diff -r 000000000000 -r c8caa15ef882 simpleengine/siputils/src/simplerequest.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simpleengine/siputils/src/simplerequest.cpp Tue Feb 02 01:05:17 2010 +0200 @@ -0,0 +1,1056 @@ +/* +* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: sip request +* +*/ + + + + +// INCLUDE FILES + +// sip api +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// simple +#include "simplesipconnection.h" +#include "simplerefreshtimer.h" +#include "simpleerrors.h" +#include "simplecommon.h" + +#ifdef _DEBUG +#include "simpledebugutils.h" +#endif + +// time limits in seconds +const TInt KRefreshLimit = 1200; // limit when KRefreshBefore is used +const TInt KRefreshBefore = 600; // how much before expiration a refresh is done +const TInt KRetryBefore = 300; // how much before expiration a retry is done +const TInt KMinorDelay = 5; // garbage collection and retry delay +const TInt KDeleteDelay = 1; // delay before deleting a subscription request +const TInt KMinorExpiry = 65; // default expiration time for re-try + + +// ================= MEMBER FUNCTIONS ======================= +// + +// ----------------------------------------------------------------------------- +// CSimpleRequest::CSimpleRequest +// ----------------------------------------------------------------------------- + +CSimpleRequest::CSimpleRequest( + MSimpleSipConnCallback& aEngine, + MSimpleEngineRequest& aReq, + TSimpleSipReqType aType, + TUint aExpires ) + : iEngine(aEngine), iReq(aReq), + iTrans(NULL), iSipRefresh(NULL), iType(aType), + iDialog(NULL), iStatus(KErrNone), + iState(ESimpleInit), iRetryAfter(0), + iReason(KErrNone), iExpires(aExpires), + iPendingState(ENoPending), iData(NULL), + iGivenETag( EFalse ), iSubscriptionState(MSimpleEngineRequest::ESimpleStateNone), + iRespCount(0) + {} + +CSimpleRequest::~CSimpleRequest() + { + StopExpiryTimer(); + StopRefreshTimer(); + delete iSipRefresh; + delete iRefreshTimer; + delete iExpiryTimer; + delete iETag; + delete iDialog; + delete iTrans; + delete iData; + delete iRecipientId; + delete iRequestContentType; + } + +// ---------------------------------------------------------- +// CSimpleRequest::NewL +// ---------------------------------------------------------- +// +CSimpleRequest* CSimpleRequest::NewL( + MSimpleSipConnCallback& aEngine, + MSimpleEngineRequest& aReq, + TSimpleSipReqType aType, + TUint aExpires ) + { + CSimpleRequest* self = new (ELeave) CSimpleRequest( + aEngine, + aReq, + aType, + aExpires ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: NewL this=%d" ), (TInt)self ); +#endif + return self; + } + +// ---------------------------------------------------------- +// CSimpleRequest::ConstructL +// ---------------------------------------------------------- +// +void CSimpleRequest::ConstructL( ) + { + iExpiryTimer = new (ELeave) CSimpleExpiryTimer( iEngine, *this ); + iRefreshTimer = new (ELeave) CSimpleRefreshTimer( iEngine, *this ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Destroy +// ----------------------------------------------------------------------------- +void CSimpleRequest::Destroy() + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: DESTROY this=%d"), (TInt)this ); +#endif + iLink.Deque(); + delete this; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::DestroyStart +// ----------------------------------------------------------------------------- +void CSimpleRequest::DestroyStart() + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: DestroyStart this=%d"), (TInt)this ); +#endif + SetReqState( ESimpleDeleting ); + // Yield control to active scheduler before deleting a request. The request may have + // called multiple callback methods, so it's safer to break the call. + StartExpiryTimer( KDeleteDelay ); + StopRefreshTimer(); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Request +// ----------------------------------------------------------------------------- +MSimpleEngineRequest& CSimpleRequest::Request() + { + return iReq; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Transaction +// ----------------------------------------------------------------------------- +CSIPClientTransaction* CSimpleRequest::Transaction() + { + return iTrans; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetTransaction +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetTransaction( CSIPClientTransaction* aTrans ) + { + delete iTrans; + iTrans = aTrans; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Refresh +// ----------------------------------------------------------------------------- +CSIPRefresh* CSimpleRequest::Refresh() + { + return iSipRefresh; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Match +// ----------------------------------------------------------------------------- +TBool CSimpleRequest::Match( CSIPClientTransaction& aTrans ) + { + CSIPClientTransaction* tr = Transaction(); + return ( tr && aTrans == *tr ? ETrue : EFalse ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Match +// ----------------------------------------------------------------------------- +TBool CSimpleRequest::Match( TSimpleSipReqType aType ) const + { + return ( aType == iType ? ETrue : EFalse ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Match +// ----------------------------------------------------------------------------- +TBool CSimpleRequest::Match( const CSIPDialog& aDialog ) const + { + return aDialog.IsAssociated( *iDialog ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Match +// ----------------------------------------------------------------------------- +TBool CSimpleRequest::Match( MSimpleEngineRequest& aReq ) const + { + if ( aReq.OpId() == iReq.OpId() ) + { + return ETrue; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Complete +// ----------------------------------------------------------------------------- +void CSimpleRequest::Complete( TInt aStatus ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: Complete %d this=%d"),aStatus, (TInt)this ); +#endif + + if ( iState == ESimpleDeleting ) + { + // Tell to other DLL that this can be deleted now. + iReq.Complete( aStatus ); + return; + } + if (( aStatus == KErrDisconnected ) || + ( aStatus == KErrTimedOut && iType != EReqPublish )) + { + // This is a serious network problem + SetRetryAfter( 0 ); + StopExpiryTimer(); + StopRefreshTimer(); + SetReqState( ESimpleFailed ); + iReq.Complete( aStatus ); + return; + } + + if ( iType == EReqRegister ) + { + // stop expiry timer + StopExpiryTimer(); + // Complete the client request + iReq.Complete( aStatus ); + } + else if ( iType == EReqPublish ) + { + DoCompletePublication( aStatus ); + } + else if ( EReqSendIM == iType ) + { + iReq.Complete( aStatus ); + return; + } + else if ( EReqReceiveIM == iType ) + { + TRAP_IGNORE( iReq.SetResponseDataL( Data() ) ) + TRAP_IGNORE( iReq.SetRecipientL( RecipientL() ) ) + iReq.Complete( aStatus ); + return; + } + else if ( iType == EReqSubscribe || iType == EReqSubscribeList || iType == EReqSubscribeWinfo ) + { + if ( Request().ResponseMethod( ) == MSimpleEngineRequest::ENotify ) + { + DoCompleteNotification( aStatus ); + } + else + { + DoCompleteSubscription( aStatus ); + } + } + // EReqListEvents will go to CompleteEvent method. + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::CompleteEvent +// ----------------------------------------------------------------------------- +void CSimpleRequest::CompleteEvent( ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: CompleteEvent this=%d"),(TInt)this ); +#endif + iReq.Complete( KErrNone ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetRefreshTime +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetRefreshTime( TUint aTime ) + { + iRefreshTime = aTime; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::RefreshTime +// ----------------------------------------------------------------------------- +TUint CSimpleRequest::RefreshTime( ) const + { + return iRefreshTime; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::StartRefreshTimer +// ----------------------------------------------------------------------------- +void CSimpleRequest::StartRefreshTimer( TUint aTime ) + { + + // Refresh a little bit earlier, KRefreshBefore sec + // If expiration time is greater than 1200 seconds, + // the interval is set to 600 seconds lower than expiration time. + // Otherwise, interval is set to half of the expiration time. + + if ( aTime ) + { + // special time used for error recovery + iRefreshTimer->Start( aTime ); + return; + } + + // This time is for garbage collection + TUint myTime = iRefreshTime + KMinorDelay; + + if ( iReq.IsRefresh() ) + { + // This time is for regular PUBLISH refresh + if ( iRefreshTime > KRefreshLimit ) + { + myTime = iRefreshTime - KRefreshBefore; + } + else + { + myTime = iRefreshTime / 2 ; + } + } + + iRefreshTimer->Start( myTime ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::StopRefreshTimer +// ----------------------------------------------------------------------------- +void CSimpleRequest::StopRefreshTimer() + { + if ( iRefreshTimer ) + { + iRefreshTimer->Cancel(); + } + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::StartExpiryTimer +// ----------------------------------------------------------------------------- +void CSimpleRequest::StartExpiryTimer( TUint aTime ) + { + iExpiryTimer->Start( aTime ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::StopExpiryTimer +// ----------------------------------------------------------------------------- +void CSimpleRequest::StopExpiryTimer() + { + if ( iExpiryTimer ) + { + iExpiryTimer->Cancel(); + } + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::RetryTime +// ----------------------------------------------------------------------------- +TUint CSimpleRequest::RetryTime() + { + // Retry (refresh) time in error recovery retry. + + // If retry-after SIP header value is present then use it. + + // If retry-after is not available: + // A quarter of expires value (=half of the current time until expires), + // maximum 300 seconds. + + // This time policy is in line with SIP stack and presence refreshment policy. + // Too long time interval is checked outside this method, + + TUint myTime(0); + + if ( iRetryAfter ) + { + // Retry-after header value + myTime = iRetryAfter; + } + else if ( iRefreshTime > KRefreshLimit ) + { + myTime = KRetryBefore; + } + else + { + myTime = iRefreshTime / 4 ; + } + // Minun value is few seconds. + return ( myTime > KMinorDelay ? myTime : KMinorDelay ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::RetryExpiryTime +// ----------------------------------------------------------------------------- +TInt CSimpleRequest::RetryExpiryTime() + { + // Expiry for retry in error cases, should be calculated at the same time as + // retry time above. + TInt myTime(0); + + if ( iRefreshTime > KRefreshLimit ) + { + myTime = KRefreshBefore; + } + else + { + myTime = iRefreshTime / 2 ; + } + + return ( myTime > KMinorExpiry ? myTime : KMinorExpiry ); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetETag +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetETag( HBufC8* aTag ) + { + // ownership is transferred + delete iETag; + iETag = aTag; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::ETag +// ----------------------------------------------------------------------------- +TPtrC8 CSimpleRequest::ETag() const + { + return iETag ? iETag->Des(): TPtrC8(); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Status +// ----------------------------------------------------------------------------- +TUint CSimpleRequest::Status() const + { + return iStatus; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetStatus +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetStatus( TUint aVal ) + { + iStatus = aVal; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Dialog +// ----------------------------------------------------------------------------- +CSIPSubscribeDialogAssoc* CSimpleRequest::Dialog( ) + { + return iDialog; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetDialog +// ----------------------------------------------------------------------------- + void CSimpleRequest::SetDialog( CSIPSubscribeDialogAssoc* aDialog ) + { + delete iDialog; + iDialog = NULL; + iDialog = aDialog; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::ReqState +// ----------------------------------------------------------------------------- +CSimpleRequest::TSimpleReqState CSimpleRequest::ReqState() const + { + return iState; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetReqState +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetReqState( CSimpleRequest::TSimpleReqState aState ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: SetReqState %d->%d this=%d"), + iState, aState,(TInt)this ); +#endif + iState = aState; + if ( aState == ESimpleFailed || aState == ESimpleComplete || aState == ESimpleDeleting ) + { + iSubscriptionState = MSimpleEngineRequest::ESimpleStateTerminated; + } + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetThrottleTime +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetThrottleTime( TUint aSeconds ) + { + TTime myTime; + myTime.HomeTime(); + myTime += TTimeIntervalSeconds( aSeconds ); + iThrottleTime = myTime; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::ThrottleTime +// ----------------------------------------------------------------------------- +TTime CSimpleRequest::ThrottleTime( ) + { + return iThrottleTime; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::RetryAfter +// ----------------------------------------------------------------------------- +TUint CSimpleRequest::RetryAfter( ) + { + return iRetryAfter; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetRetryAfter +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetRetryAfter( TUint aVal ) + { + iRetryAfter = aVal; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetReason +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetReason( TInt aVal ) + { + iReason = aVal; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Reason +// ----------------------------------------------------------------------------- +TInt CSimpleRequest::Reason( ) + { + return iReason; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::PlusErrNotify +// ----------------------------------------------------------------------------- +void CSimpleRequest::PlusErrCount( ) + { + ++iErrNotify; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::ResetErrNotify +// ----------------------------------------------------------------------------- +void CSimpleRequest::ResetErrCount( ) + { + iErrNotify = 0; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::ErrNotify +// ----------------------------------------------------------------------------- +TInt CSimpleRequest::ErrCount( ) + { + return iErrNotify; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::PendingState +// ----------------------------------------------------------------------------- +CSimpleRequest::TSimplePendingSubState CSimpleRequest::PendingState( ) + { + return iPendingState; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::AddPendingState +// ----------------------------------------------------------------------------- +void CSimpleRequest::AddPendingState( CSimpleRequest::TSimplePendingSubState aVal ) + { + if (( aVal == EPendingModify && iPendingState == EPendingRefresh ) || + ( aVal == EPendingRefresh && iPendingState == EPendingModify )) + { + SetPendingState( EPendingModifyAndRefresh ); + } + else if ( aVal == EPendingModify && iPendingState == ENoPending ) + { + SetPendingState( EPendingModify ); + } + else if ( aVal == EPendingRefresh && iPendingState == ENoPending ) + { + SetPendingState( EPendingRefresh ); + } + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetPendingState +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetPendingState( CSimpleRequest::TSimplePendingSubState aVal ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: iPendingState=%d"), aVal ); +#endif + iPendingState = aVal; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::Data +// ----------------------------------------------------------------------------- +TPtrC8 CSimpleRequest::Data() const + { + return iData ? iData->Des() : TPtrC8(); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetRecipientL +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetRecipientL( const TDesC8& aRecipientId ) + { + delete iRecipientId; + iRecipientId = NULL; + iRecipientId = aRecipientId.AllocL(); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::RecipientL +// ----------------------------------------------------------------------------- +TPtrC8 CSimpleRequest::RecipientL() const + { + return iRecipientId ? iRecipientId->Des() : TPtrC8(); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetDataL +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetDataL( const TDesC8& aData ) + { + delete iData; + iData = NULL; + iData = aData.AllocL(); + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::GivenETag +// ----------------------------------------------------------------------------- +TBool CSimpleRequest::GivenETag() const + { + return iGivenETag; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::SetGivenETag +// ----------------------------------------------------------------------------- +void CSimpleRequest::SetGivenETag( TBool aVal ) + { + iGivenETag = aVal; + } + +// ---------------------------------------------------------- +// CSimpleRequest::RequestContentType +// ---------------------------------------------------------- +// +TPtrC8 CSimpleRequest::RequestContentType() + { + return iRequestContentType ? iRequestContentType->Des() : TPtrC8(); + } + +// ---------------------------------------------------------- +// CSimpleRequest::SetRequestContentTypeL +// ---------------------------------------------------------- +// +void CSimpleRequest::SetRequestContentTypeL( const TDesC8& aData ) + { + delete iRequestContentType; + iRequestContentType = NULL; + iRequestContentType = aData.AllocL(); + } + +// ---------------------------------------------------------- +// CSimpleRequest::SipSubscriptionState +// ---------------------------------------------------------- +// +MSimpleEngineRequest::TSimpleSipSubscriptionState CSimpleRequest::SipSubscriptionState() + { + return iSubscriptionState; + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::DoCompleteSubscription +// ----------------------------------------------------------------------------- +void CSimpleRequest::DoCompleteSubscription( TInt aStatus ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: DoCompleteSubscription %d"), aStatus); +#endif + + // This is a part of the the state machine for subscriptions. + // Mainly those cases that call API callback + + TSimpleReqState orig = iState; + + // Stop expiry timer always except a stop request is a special case, because of then + // both 200 and Notify are required, or an error code alone. + if ( orig != ESimpleStopping ) + { + StopExpiryTimer(); + } + // Stop refresh timer used for garbage collection + if ( orig != ESimpleRunningInit ) + { + StopRefreshTimer(); + } + + if ( orig == ESimpleRunningInit ) + { + if ( aStatus == KErrNone || aStatus == KSimpleErrPending ) + { + if ( iExpires ) + { + // OK response [ expires != 0 ] + if ( aStatus == KSimpleErrPending ) + { + iSubscriptionState = MSimpleEngineRequest::ESimpleStatePending; + } + SetReqState( ESimpleActiveSubs ); + } + else + { + // OK response [ expires == 0 ] + SetReqState( ESimpleComplete ); + } + } + else + { + // error + SetReqState( ESimpleFailed ); + } + // Complete API callback always in ESimpleRunningInit + iReq.Complete( aStatus ); + } + else if ( orig == ESimpleActiveSubs ) + { + // This happens if refresh has failed without response notify + TUint retryTime = RetryTime(); + // If too long interval in the retry-after header then return an error + if ( retryTime > KRetryBefore ) + { + SetReqState( ESimpleFailed ); + iReq.Complete( KErrCompletion ); + return; + } + SetReqState( ESimpleReTry ); + StartRefreshTimer( retryTime ); + } + else if ( orig == ESimpleStopping ) + { + // Stop expiry timer always except a stop request is a special case, because of then + // both 200 and Notify are required, or an error code alone. + ++iRespCount; + if (( aStatus != KErrNone && aStatus != KSimpleErrPending ) || + ( iRespCount == 2 ) ) + { + SetReqState( ESimpleComplete ); + StopExpiryTimer(); + } + iReq.Complete( aStatus ); + } + else if ( orig == ESimpleDialogReCre && aStatus == KErrNone ) + { + // OK resp + SetReqState( ESimpleActiveSubs ); + } + else + { + // expires or stop / callback + // error / callback + // Expires or stop /callbc, respectively + SetReqState( ESimpleFailed ); + iReq.Complete( aStatus ); + } + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::DoCompleteNotification +// ----------------------------------------------------------------------------- +void CSimpleRequest::DoCompleteNotification( TInt aStatus ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: DoCompleteNotification %d"), aStatus); +#endif + + // This is a part of the the state machine for subscriptions. + // Mainly those cases that call API callback + + TSimpleReqState orig = iState; + + if ( aStatus == KErrNone || aStatus == KSimpleErrPending ) + { + if ( KSimpleErrPending == aStatus ) + { + iSubscriptionState = MSimpleEngineRequest::ESimpleStatePending; + } + else + { + iSubscriptionState = MSimpleEngineRequest::ESimpleStateActive; + } + + if ( orig == ESimpleStopping && aStatus != KErrNone ) + { + // A stop request is a special case, because of then + // both 200 and Notify are required, or an error code alone. + ++iRespCount; + if ( iRespCount == 2 ) + { + SetReqState( ESimpleComplete ); + StopExpiryTimer(); + } + } + + // Notification without error does not change the state, + // just pass the notification thru to the API + iReq.Complete( aStatus ); + return; + } + + if ( orig == ESimpleActiveSubs ) + { + // Ensure that Dialog refreshing will be stopped now. + SetDialog( NULL ); + if ( iReq.IsRefresh() && aStatus == KSimpleErrTemporary ) + { + // terminated [ refresh ] + StopRefreshTimer(); + TUint retryTime = RetryTime(); + // If too long interval in the retry-after header then return an error + if ( retryTime > KRetryBefore ) + { + SetReqState( ESimpleFailed ); + iReq.Complete( KErrCompletion ); + return; + } + // Do not send the notification to the client API now, but + // go to retry-state and retry later dialog re-creation. + SetReqState( ESimpleReTry ); + StartRefreshTimer( retryTime ); + } + else + { + // Expires[ no refresh ] + // error [ no refresh ] + // Timer may stop the request if not refresh. + SetReqState( (aStatus==KErrTimedOut || aStatus==KErrCompletion) ? + ESimpleComplete : ESimpleFailed ); + // Complete API callback + iReq.Complete( aStatus ); + } + } + else + { + iReq.Complete( aStatus ); + } + } + +// ----------------------------------------------------------------------------- +// CSimpleRequest::DoCompletePublication +// ----------------------------------------------------------------------------- +void CSimpleRequest::DoCompletePublication( TInt aStatus ) + { +#ifdef _DEBUG + TSimpleLogger::Log(_L("SimpleRequest: DoCompletePublication %d"), aStatus); +#endif + + // This is a part of the the state machine for publications. + // Mainly those cases that call API callback + + // SIP error code 412, RFC3903 + const TUint KMySip412 = 412; + + TSimpleReqState orig = iState; + TSimplePendingSubState nextSub = ENoPending; + + // Set ETag that's received from network or reset + // when an error has taken a place. If it fails, it is not very serious, + // and it is very rare OOM situation. + TRAP_IGNORE( iReq.SetETagL( ETag() )); + + // Stop refresh timer and start only when needed. + if ( orig != ESimplePending ) + { + StopRefreshTimer(); + } + + if ( orig == ESimpleRunningInit ) + { + // stop expiry timer + StopExpiryTimer(); + if ( aStatus == KErrNone ) + { + // OK response + SetReqState( ESimpleActive ); + // Ensure API callback when terminated + StartRefreshTimer(); + } + else + { + // error + SetReqState( ESimpleFailed ); + } + // Complete API callback always in ESimpleRunningInit + iReq.Complete( aStatus ); + } + else if ( orig == ESimpleRunning ) + { + TBool isModify = Request().RequestType() == MSimpleEngineRequest::EPublishModify ? ETrue : EFalse; + // Handle pending/running modifify request situation first + if ( isModify ) + { + SetReqState( ESimpleActive ); + // Check SIP status and decide whether publication is terminated or + // the modify request failed only. + if ( PendingState() != ENoPending ) + { + // The previous refresh request is completed and the next one is the + // pending modify request. + if ( aStatus ) + { + // error[ callback ] + // terminate the publication + // stop expiry timer + StopExpiryTimer(); + iReq.Complete( KErrCompletion ); + SetReqState( ESimpleFailed ); + } + else + { + StartRefreshTimer(); + // Send modification request + TInt errx = iEngine.DoSendPendingPublish( *this ); + if ( errx ) + { + // Modify request failed only + // stop expiry timer + StopExpiryTimer(); + iReq.Complete( errx ); + SetReqState( ESimpleActive ); + } + else + { + // Just wait modify response, do not complete API request. + // Do not stop or restart expiry timer + } + } + } // pending + else + { + // This is the actual modify request response. + TUint sipStatus = Status(); + // check if not 412, see RFC3903 + if ( ( !aStatus || aStatus == KSimpleErrTemporary ) && sipStatus != KMySip412 ) + { + // Modify failed only + StartRefreshTimer(); + // Complete modification in API callback + iReq.Complete( aStatus ); + SetReqState( ESimpleActive ); + } + else + { + // The whole publication is terminated + iReq.Complete( KErrCompletion ); + SetReqState( ESimpleFailed ); + } + // stop expiry timer + StopExpiryTimer(); + } // not pending + } // modify + else + { + // stop expiry timer + StopExpiryTimer(); + // re-freshing publication + if ( aStatus == KErrNone ) + { + StartRefreshTimer(); + SetReqState( ESimpleActive ); + // Complete the request for ETag observers only + iReq.SetResponseMethod( MSimpleEngineRequest::EStatusETag ); + } + else + { + // error, no recovery + SetReqState( ESimpleFailed ); + iReq.Complete( aStatus ); + } + } + } + else if ( orig == ESimpleStopping ) + { + // stop expiry timer + StopExpiryTimer(); + // Any kind of response is OK for stopping, + // either timeout or OK response except with given ETag the real SIP response + // is sent to the client. + SetReqState( ESimpleComplete ); + TInt retVal = GivenETag() ? aStatus : KErrNone; + iReq.Complete( retVal ); + } + else if ( orig == ESimplePending && + ( iPendingState==EPendingModify || iPendingState==EPendingModifyAndRefresh ) && + aStatus != KErrCompletion ) + { + // Check if just modify terminates or the entire publication is terminated + // stop expiry timer + StopExpiryTimer(); + // Modify failed, automatic refresh continues + // Complete modification in API callback + iReq.Complete( aStatus ); + SetReqState( ESimpleActive ); + if ( iPendingState == EPendingModifyAndRefresh && aStatus ) + { + // The publication may still be alive but automatic refresh is pending + SetReqState( ESimplePending ); + nextSub = EPendingRefresh; + } + } + else // odds and ends like time-out + { + // stop expiry timer + StopExpiryTimer(); + SetReqState( ESimpleFailed ); + iReq.Complete( aStatus ); + } + // Reset the request body data + delete iData; + iData = NULL; + // Reset pendig modify request + SetPendingState( nextSub ); + }