--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/simpleengine/siputils/src/simplesipconnection.cpp Tue Feb 02 01:05:17 2010 +0200
@@ -0,0 +1,2702 @@
+/*
+* Copyright (c) 2006-2009 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 connection
+*
+*/
+
+
+
+
+// INCLUDE FILES
+
+#ifdef _DEBUG
+#include <f32file.h>
+#endif
+
+#include <badesca.h>
+
+// sip api
+#include <sip.h>
+#include <sipconnection.h>
+#include <sipconnectionobserver.h>
+#include <sipresponseelements.h>
+#include <siprequestelements.h>
+#include <sipclienttransaction.h>
+#include <siprefresh.h>
+#include <sipmessageelements.h>
+#include <sipsubscribedialogassoc.h>
+#include <sipregistrationcontext.h>
+
+// sip codec api
+#include <sipfromheader.h>
+#include <siptoheader.h>
+#include <sipexpiresheader.h>
+#include <sipeventheader.h>
+#include <sipcontenttypeheader.h>
+#include <sipaddress.h>
+#include <sipstrings.h>
+#include <sipstrconsts.h>
+#include <sipextensionheader.h>
+#include <sipsubscriptionstateheader.h>
+#include <sipsupportedheader.h>
+#include <sipacceptheader.h>
+
+#include <cvimpstsettingsstore.h>
+
+// own simple
+#include "simplesipconnection.h"
+#include "simplesipconnectionobserver.h"
+#include "simplesipprofileobserver.h"
+#include "simplerefreshtimer.h"
+#include "msimpleenginerequest.h"
+#include "simpleerrors.h"
+
+#ifdef _DEBUG
+#include "simpledebugutils.h"
+#ifdef __LOCAL_MODE
+// INTERNAL TEST SUITE
+#include "simplelocalmodeutils.h"
+#endif
+#endif
+
+_LIT8 ( KSimpleWINFO, "winfo");
+_LIT8 ( KSimplePRESENCE_LOW, "presence");
+_LIT8 ( KSimpleEventlist, "eventlist");
+_LIT8 ( KSimpleId, "id");
+_LIT8 ( KSimpleAnonymous, "\"Anonymous\" <sip:anonymous@anonymous.invalid>");
+_LIT8 ( KSimpleDeactivated, "deactivated" );
+_LIT8 ( KSimpleProbation, "probation" );
+_LIT8 ( KSimpleRejected, "rejected" );
+_LIT8 ( KSimpleTimeout, "timeout" );
+_LIT8 ( KSimpleGiveup, "giveup" );
+_LIT8 ( KSimpleNoresource, "Noresource" );
+_LIT8 ( KSipPrefix, "sip:" );
+
+// ================= MEMBER FUNCTIONS =======================
+//
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::CSimpleSipConnection
+// ----------------------------------------------------------
+//
+CSimpleSipConnection::CSimpleSipConnection()
+: iSip(NULL), iSipConnection(NULL), iConnectionObserver(NULL),
+ iSipState( ESimpleSipInactive ),
+ iRequestList(CSimpleRequest::LinkOffset()),
+ iCurrentNbrSubs( 0 )
+ {
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::~CSimpleSipConnection
+// ----------------------------------------------------------
+//
+EXPORT_C CSimpleSipConnection::~CSimpleSipConnection()
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DESTRUCTOR this=%d" ), (TInt)this );
+ iFs.Close();
+#endif
+ delete iSipConnection;
+ delete iProfileObserver;
+ delete iConnectionObserver;
+ delete iSip;
+ DeleteRequests();
+ DeleteRequests( CSimpleRequest::EReqReceiveIM );
+ SIPStrings::Close();
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::NewL
+// ----------------------------------------------------------
+//
+EXPORT_C CSimpleSipConnection* CSimpleSipConnection::NewL()
+ {
+ CSimpleSipConnection* self = new (ELeave) CSimpleSipConnection;
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::ConstructL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::ConstructL()
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(
+ _L("SipConnection: ConstructL 20-01-07 this=%d" ), (TInt)this );
+#endif
+
+ iConnectionObserver = CSimpleSipConnectionObserver::NewL( *this);
+ SIPStrings::OpenL();
+ // read static cenrep settings
+ iSettings.ReadCentRepSettings();
+
+#ifdef _DEBUG
+ // read ini file for debug version settings
+ (void)iFs.Connect();
+ TRAP_IGNORE(iSettings.ReadIniFileL( iFs ));
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DispatchReqL
+// ----------------------------------------------------------
+//
+EXPORT_C void CSimpleSipConnection::DispatchReqL( MSimpleEngineRequest& aReq )
+ {
+ MSimpleEngineRequest::TSimpleRequest type = aReq.RequestType();
+
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DispatchReqL type=%d this=%d" ),
+ type, (TInt)this );
+#endif
+
+ switch ( type )
+ {
+ case MSimpleEngineRequest::ERegister:
+ aReq.SetRefreshTime( 0 );
+ RegisterL( aReq );
+ break;
+ case MSimpleEngineRequest::ESendIM:
+ aReq.SetRefreshTime( 0 );
+ SendInstantMessageL( aReq );
+ break;
+ case MSimpleEngineRequest::EReceiveIM:
+ aReq.SetRefreshTime( 0 );
+ RequestInstantMessageReceivingL( aReq );
+ break;
+ case MSimpleEngineRequest::EStartPublish:
+ aReq.SetRefreshTime( iSettings.ExpiryPuhlish() );
+ StartPublishL( aReq );
+ break;
+ case MSimpleEngineRequest::EPublishModify:
+ ModifyPublishL( aReq );
+ break;
+ case MSimpleEngineRequest::ESubscribe:
+ aReq.SetRefreshTime( iSettings.ExpiryWatcher() );
+ SubscribeL( aReq);
+ break;
+ case MSimpleEngineRequest::ESubscribeStop:
+ aReq.SetRefreshTime( 0 );
+ StopSubscribeL( aReq );
+ break;
+ case MSimpleEngineRequest::ESubscribeGet:
+ aReq.SetRefreshTime( 0 );
+ SubscribeL( aReq );
+ break;
+ case MSimpleEngineRequest::ESubscribeWinfo:
+ aReq.SetRefreshTime( iSettings.ExpiryWinfo() );
+ SubscribeWinfoL( aReq );
+ break;
+ case MSimpleEngineRequest::ESubscribeLista:
+ aReq.SetRefreshTime( iSettings.ExpiryWatcher() );
+ SubscribeListL( aReq );
+ break;
+ case MSimpleEngineRequest::EStopPublish:
+ aReq.SetRefreshTime( 0 );
+ StopPublishL( aReq );
+ break;
+ case MSimpleEngineRequest::EListenEvents:
+ aReq.SetRefreshTime( 0 );
+ ListenStatusL( aReq );
+ break;
+ case MSimpleEngineRequest::EDestroy:
+ DeleteRequest( aReq );
+ break;
+ case MSimpleEngineRequest::EDestroyStart:
+ DeleteRequestStart( aReq );
+ break;
+ default:
+ User::Leave( KErrNotSupported );
+ break;
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SIPStatus
+// ----------------------------------------------------------
+//
+EXPORT_C TUint CSimpleSipConnection::SIPStatus(
+ TInt aOpId, TInt& aRetryAfter )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: SIPStatus this=%d" ), (TInt)this);
+#endif
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ aRetryAfter = 0;
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ MSimpleEngineRequest& mr = req->Request();
+ if ( mr.OpId( ) == aOpId )
+ {
+ aRetryAfter = req->RetryAfter();
+ return req->Status();
+ }
+ }
+ return 0;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SIPState
+// ----------------------------------------------------------
+//
+EXPORT_C TSimpleSipState CSimpleSipConnection::SIPState( )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: SIPState returns %d this=%d" ),
+ iSipState, (TInt)this );
+#endif
+ return iSipState;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::CurrentSIPIdentityL
+// ----------------------------------------------------------
+//
+EXPORT_C TPtrC8 CSimpleSipConnection::CurrentSIPIdentityL()
+ {
+ return iProfileObserver->GiveUserAorL();
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SipSubscriptionState
+// ----------------------------------------------------------
+//
+EXPORT_C MSimpleEngineRequest::TSimpleSipSubscriptionState CSimpleSipConnection::SipSubscriptionState(
+ MSimpleEngineRequest& aReq )
+ {
+ MSimpleEngineRequest::TSimpleSipSubscriptionState retVal = MSimpleEngineRequest::ESimpleStateNone;
+
+ CSimpleRequest* r = GetCliRequest( aReq );
+ if ( r )
+ {
+ retVal = r->SipSubscriptionState();
+ }
+ else
+ {
+ }
+
+ return retVal;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::RegisterL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::RegisterL( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: RegisterL" ));
+#endif
+ // Check if already registered
+ switch ( iSipState )
+ {
+ case ESimpleSipInactive:
+ {
+ if ( !aReq.Aux() )
+ {
+ // Default profile used
+ RegisterDefaultL( aReq );
+ }
+ else
+ {
+ RegisterAnyL( aReq );
+ }
+ }
+ break;
+ case ESimpleSipActive:
+ case ESimpleSipSuspend:
+ // The sip connection is already registered,
+ // return the callback.
+ aReq.Complete( KErrNone );
+ break;
+ case ESimpleSipIdle:
+ {
+ // already initiated, just wait
+ // Save the request to wait a response
+ CSimpleRequest* simpleR = CSimpleRequest::NewL(
+ *this, aReq, CSimpleRequest::EReqRegister, aReq.RefreshTime());
+ iRequestList.AddLast( *simpleR );
+ }
+ break;
+ case ESimpleSipUnavailable:
+ default:
+ User::Leave( KErrNotFound );
+ break;
+ }; //lint !e960
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::ListenStatusL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::ListenStatusL( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: ListenStatusL" ));
+#endif
+ // Save the request to wait a response
+ CSimpleRequest* simpleR = CSimpleRequest::NewL(
+ *this, aReq, CSimpleRequest::EReqListenEvents, aReq.RefreshTime() );
+ iRequestList.AddLast( *simpleR );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::RequestInstantMessageReceivingL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::RequestInstantMessageReceivingL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log( _L(
+ "CSimpleSipConnection::RequestInstantMessageReceivingL - Start" ) );
+#endif
+
+ // Create the request
+ CSimpleRequest* request = CSimpleRequest::NewL( *this,
+ aReq, CSimpleRequest::EReqReceiveIM, aReq.RefreshTime() );
+
+ // Save the request into queue
+ iRequestList.AddLast( *request );
+
+#ifdef _DEBUG
+ TSimpleLogger::Log( _L(
+ "CSimpleSipConnection::RequestInstantMessageReceivingL - End" ) );
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SendInstantMessageL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::SendInstantMessageL( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(
+ _L( "CSimpleSipConnection::SendInstantMessageL - Start" ) );
+#endif
+
+ // Create the request
+ CSimpleRequest* request = CSimpleRequest::NewL( *this, aReq,
+ CSimpleRequest::EReqSendIM, aReq.RefreshTime() );
+ CleanupStack::PushL( request ); // CS: 1
+
+ request->SetDataL( aReq.RequestData() );
+ request->SetRequestContentTypeL( aReq.RequestContentType() );
+ request->SetRefreshTime( aReq.RefreshTime() );
+
+ if ( ESimpleSipActive == iSipState )
+ {
+ // Set request state
+ request->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ const TDesC8& aContent = request->Data();
+
+ if ( !iSipConnection || ESimpleSipActive != iSipState ||
+ !iProfileObserver )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ MSIPRegistrationContext* regContext = iProfileObserver->
+ ProfileContext();
+
+ if ( !regContext )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ // Check CLIENT-OBJ-DATA-LIMIT
+ TUint myLimit = iSettings.ObjLimit();
+
+ if ( myLimit && ( TUint )aContent.Size() > myLimit )
+ {
+ // This is too big mesasge, an error is returned
+ User::Leave( KSimpleErrSettingsLimit );
+ }
+
+ // Get request URI from a request
+ TUriParser8 parser;
+ HBufC8* temp = HBufC8::NewLC( KSipPrefix().Length() +
+ aReq.Recipient().Length() ); // CS: 2
+ temp->Des().Copy( KSipPrefix() );
+ temp->Des().Append( aReq.Recipient() );
+ User::LeaveIfError( parser.Parse( *temp ));
+ CUri8* uri = CUri8::NewL( parser );
+
+ // Start to fill header, Remote URI
+ CSIPRequestElements* elems = CSIPRequestElements::NewL( uri );
+ CleanupStack::PushL( elems ); // CS: 3
+
+ TUriParser8 parser3;
+ User::LeaveIfError( parser3.Parse( iProfileObserver->
+ GiveUserAorL() ));
+ uri = CUri8::NewL( parser3 );
+ CSIPAddress* sipAddress = CSIPAddress::NewL( uri );
+
+ // From Header
+ CSIPFromHeader* fromH = CSIPFromHeader::NewL( sipAddress );
+ elems->SetFromHeaderL( fromH ); // fromH, ownership given to elems
+
+ uri = CUri8::NewL( parser );
+ CSIPAddress* addr = CSIPAddress::NewL( uri );
+ // To Header
+ CSIPToHeader* toHeader = CSIPToHeader::NewL( addr );
+ elems->SetToHeaderL( toHeader );
+
+ CSIPMessageElements& mesElems = elems->MessageElements();
+
+ // Add Expires Header
+ if ( aReq.RefreshTime() )
+ {
+ RPointerArray<CSIPHeaderBase> headers;
+ CleanupClosePushL( headers ); // CS: 4
+
+ CSIPExpiresHeader* exprH = new (ELeave) CSIPExpiresHeader(
+ aReq.RefreshTime() );
+ CleanupStack::PushL( exprH ); // CS: 5
+ User::LeaveIfError( headers.Append( exprH ) );
+ CleanupStack::Pop( exprH ); // CS: 4
+
+ mesElems.SetUserHeadersL( headers );
+ // headers ownership given to mesElems
+ CleanupStack::Pop( &headers ); // CS: 3
+ }
+
+ // Set content type and content
+ HBufC8* buffer = aContent.AllocLC(); // CS: 4
+ CSIPContentTypeHeader* contTypeH = CSIPContentTypeHeader::NewL(
+ KSimpleMediaType, KSimpleMediaSubType );
+ CleanupStack::Pop( buffer ); // CS: 3
+ mesElems.SetContentL( buffer, contTypeH );
+ // buffer ownership given to mesElems
+ // contTypeH ownership given to mesElems
+
+ // Set method
+ elems->SetMethodL( SIPStrings::StringF( SipStrConsts::EMessage ) );
+
+ CleanupStack::Pop( elems ); // CS: 2
+ // Send the request transaction
+ // elems, ownership given
+ CSIPClientTransaction* sipTrans = iSipConnection->SendRequestL( elems,
+ *regContext );
+
+ // Save SIP client transaction
+ request->SetTransaction( sipTrans );
+
+ CleanupStack::PopAndDestroy( temp ); // CS: 1
+
+ // Start refresh timer, it's used for garbage collection too.
+ request->StartRefreshTimer();
+ }
+ else if ( iSipState == ESimpleSipSuspend )
+ {
+ request->SetReqState( CSimpleRequest::ESimplePendingInit );
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ // Save the request into queue
+ iRequestList.AddLast( *request );
+ CleanupStack::Pop( request ); // CS: 0
+
+ // Update SOURCE-THROTTLE-PUBLISH time
+ if ( iSettings.Throttle() )
+ {
+ request->SetThrottleTime( iSettings.Throttle() );
+ }
+
+ // Start timer to detect infinite wait situation
+ request->StartExpiryTimer( iSettings.ExpiryApi() );
+
+#ifdef _DEBUG
+ TSimpleLogger::Log(
+ _L( "CSimpleSipConnection::SendInstantMessageL - End" ) );
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::StartPublishL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::StartPublishL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: StartPublishL" ));
+ TSimpleLogger::Dump( aReq.RequestData(), iFs, 0 );
+#endif
+
+ // create the request
+ CSimpleRequest* r = CSimpleRequest::NewL( *this,
+ aReq, CSimpleRequest::EReqPublish, aReq.RefreshTime() );
+ CleanupStack::PushL( r );
+ r->SetDataL( aReq.RequestData() );
+ r->SetRequestContentTypeL( aReq.RequestContentType() );
+
+ // Set ETag if given
+ if ( aReq.ETag().Length() )
+ {
+ HBufC8* etagBuf = aReq.ETag().AllocL();
+ // Ownership is transferred
+ r->SetETag( etagBuf );
+ }
+
+ // save refresh time
+ r->SetRefreshTime( aReq.RefreshTime() );
+
+ if ( iSipState == ESimpleSipActive )
+ {
+ // set request state
+ r->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ // Do the SIP Publish transaction
+ CSIPClientTransaction* sipTrans = DoPublishL(
+ iProfileObserver->GiveUserAorL(),
+ aReq.RefreshTime(),
+ r->Data(),
+ r->ETag(), r->RequestContentType() );
+ // Save SIP client transaction
+ r->SetTransaction( sipTrans );
+
+ // Start re-fresh timer, it's used for garbage collection too.
+ // expires [ no refresh ]
+ r->StartRefreshTimer();
+ }
+ else if ( iSipState == ESimpleSipSuspend )
+ {
+ r->SetReqState( CSimpleRequest::ESimplePendingInit );
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ // Save the request into queue
+ iRequestList.AddLast( *r );
+ CleanupStack::Pop( r );
+
+ // update SOURCE-THROTTLE-PUBLISH time
+ if ( iSettings.Throttle() )
+ {
+ r->SetThrottleTime( iSettings.Throttle() );
+ }
+
+ // Start timer to detect infinite wait situation
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::ModifyPublishL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::ModifyPublishL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: ModifyPublishL" ));
+ TSimpleLogger::Dump( aReq.RequestData(), iFs, 0 );
+#endif
+
+ // Get initial SIP transaction in order to get ETag value.
+ CSimpleRequest* r = GetCliRequest( aReq );
+ if ( !r || r->ETag().Length() == 0 )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ // Check the request state is valid
+ CSimpleRequest::TSimpleReqState myState = r->ReqState();
+ if ( myState != CSimpleRequest::ESimpleActive &&
+ myState != CSimpleRequest::ESimplePending &&
+ myState != CSimpleRequest::ESimpleRunning )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ // initialize SIP status
+ r->SetStatus( 0 );
+
+ // check SOURCE-THROTTLE-PUBLISH
+ TTime myTime;
+ myTime.HomeTime();
+ if ( iSettings.Throttle() && myTime < r->ThrottleTime() )
+ {
+ // Leave if not enough time elapsed since last publish
+ // for this publication.
+ User::Leave( KSimpleErrSettingsLimit );
+ }
+
+ // send PUBLISH modify transaction if network is available
+ if ( iSipState == ESimpleSipActive &&
+ myState != CSimpleRequest::ESimpleRunning )
+ {
+ // set state
+ r->SetReqState( CSimpleRequest::ESimpleRunning );
+ r->SetDataL( aReq.RequestData() );
+ r->SetRequestContentTypeL( aReq.RequestContentType() );
+
+ CSIPClientTransaction* sipTrans = DoPublishL(
+ iProfileObserver->GiveUserAorL(),
+ aReq.RefreshTime(),
+ r->Data(),
+ r->ETag(), r->RequestContentType() );
+
+ // save latest client transaction
+ r->SetTransaction( sipTrans );
+
+ // Re-fresh timer is started in ok response, not yet here.
+
+ // update SOURCE-THROTTLE-PUBLISH time
+ if ( iSettings.Throttle() )
+ {
+ r->SetThrottleTime( iSettings.Throttle() );
+ }
+ }
+ else if ( iSipState == ESimpleSipActive &&
+ myState == CSimpleRequest::ESimpleRunning )
+ {
+ // not to send the ETag only.
+ r->AddPendingState( CSimpleRequest::EPendingModify );
+ r->SetDataL( aReq.RequestData() );
+ }
+ else if ( iSipState == ESimpleSipSuspend )
+ {
+ // set state
+ r->SetReqState( CSimpleRequest::ESimplePending );
+ // not to send the ETag only.
+ r->AddPendingState( CSimpleRequest::EPendingModify );
+ r->SetDataL( aReq.RequestData() );
+ }
+ else
+ {
+ // very rare situation
+ User::Leave( KErrNotReady );
+ }
+
+ // start expiry timer to detect infinite wait situation
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+
+#ifdef _DEBUG
+ TBuf<100> myETag;
+ myETag.Copy( r->ETag() );
+ TSimpleLogger::Log(_L("SipConnection: ModifyPublishL ETag=%S" ), &myETag );
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::StartToRefreshL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::StartToRefreshL( CSimpleRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: StartToRefresh"));
+#endif
+
+ // This refreshes PUBLISH request or makes garbage collection for
+ // subscription without refresh.
+
+ // There are two cases: normal re-publish
+ // or expiration of publication
+
+ if ( aReq.Match( CSimpleRequest::EReqPublish ) )
+ {
+ // refresh[ network ]
+ // time to retry
+ // expires[ no refresh ]
+ // expires
+ DoRefreshPublishL( aReq );
+ }
+ else if ( aReq.Match( CSimpleRequest::EReqSubscribe ) ||
+ aReq.Match( CSimpleRequest::EReqSubscribeList ) ||
+ aReq.Match( CSimpleRequest::EReqSubscribeWinfo ))
+ {
+ DoRefreshSubscribe( aReq );
+ }
+ else
+ {
+ // No other cases
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::StopPublishL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::StopPublishL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: StopPublishL" ));
+#endif
+
+ CSIPClientTransaction* sipTrans = NULL;
+
+ TBool stopETagScratch (EFalse);
+
+ // Get SIP transaction in order to get ETag value.
+ CSimpleRequest* r = GetCliRequest( aReq );
+ if ( !r && aReq.ETag().Length() == 0 )
+ {
+ User::Leave( KErrNotFound );
+ }
+ else if ( !r )
+ {
+ // create the request
+ r = CSimpleRequest::NewL( *this,
+ aReq, CSimpleRequest::EReqPublish, aReq.RefreshTime() );
+ CleanupStack::PushL( r );
+ stopETagScratch = ETrue;
+ }
+
+ // Set ETag if given
+ if ( aReq.ETag().Length() )
+ {
+ HBufC8* etagBuf = aReq.ETag().AllocL();
+ // Ownership is transferred
+ r->SetETag( etagBuf );
+ r->SetGivenETag( ETrue );
+ }
+
+ // initialize SIP status
+ r->SetStatus( 0 );
+
+ // refresh timer not needed
+ r->StopRefreshTimer();
+
+ // set state
+ r->SetReqState( CSimpleRequest::ESimpleStopping );
+
+ // Check if the transaction is pending or running
+ if ( r->ETag().Length() == 0 )
+ {
+ r->SetReqState( CSimpleRequest::ESimpleComplete );
+ r->Complete( KErrNone );
+ return;
+ }
+
+ // send PUBLISH transaction
+ TRAPD( errx, sipTrans = DoPublishL(
+ iProfileObserver->GiveUserAorL(),
+ 0, // 0 epiry headers value
+ KNullDesC8, // request data
+ r->ETag(), r->RequestContentType() ));
+ if ( errx )
+ {
+ // In error case complete the request immediately
+ r->Complete( errx );
+ return;
+ }
+
+ // save latest client transaction
+ r->SetTransaction( sipTrans );
+
+ // start expiry timer to detect infinite wait situation
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+
+ if ( stopETagScratch )
+ {
+ // Save the request into queue
+ iRequestList.AddLast( *r );
+ CleanupStack::Pop( r );
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SubscribeL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::SubscribeL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: SubscribeL" ));
+#endif
+
+ CSIPSubscribeDialogAssoc* subsDialog = NULL;
+
+ // create the request
+ CSimpleRequest* r = CSimpleRequest::NewL( *this,
+ aReq, CSimpleRequest::EReqSubscribe, aReq.RefreshTime() );
+ CleanupStack::PushL( r );
+
+ if ( iSipState == ESimpleSipActive )
+ {
+ r->SetDataL( aReq.RequestData() );
+ r->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ CSIPClientTransaction* sipTrans = DoSubscribeL(
+ aReq.RemoteURI(),
+ aReq.RefreshTime(),
+ r->Data(),
+ subsDialog,
+ aReq.IsRefresh(),
+ ESubsRegular,
+ aReq.Aux() ? ETrue : EFalse );
+ // save SIP Dialog and SIP client transaction
+ r->SetDialog( subsDialog );
+ r->SetTransaction( sipTrans );
+ }
+ else if ( iSipState == ESimpleSipSuspend )
+ {
+ r->SetReqState( CSimpleRequest::ESimplePendingInit );
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ CleanupStack::Pop( r );
+ iRequestList.AddLast( *r );
+
+ // start timer to detect infinite wait situation
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+
+ if ( !aReq.IsRefresh() )
+ {
+ // Start refresh timer for garbage colletion for
+ // subscription not needing refresh.
+ TUint myTime = ( aReq.RefreshTime() > iSettings.ExpiryApi() ?
+ aReq.RefreshTime() : iSettings.ExpiryApi() );
+ r->SetRefreshTime( myTime );
+ r->StartRefreshTimer();
+ }
+ // increase subscription counter
+ IncreaseNbrSubs();
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SubscribeListL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::SubscribeListL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: SubscribeListL" ));
+#endif
+
+ CSIPSubscribeDialogAssoc* subsDialog = NULL;
+
+ // create the request
+ CSimpleRequest* r = CSimpleRequest::NewL( *this,
+ aReq, CSimpleRequest::EReqSubscribeList, aReq.RefreshTime() );
+ CleanupStack::PushL( r );
+
+ if ( iSipState == ESimpleSipActive )
+ {
+ r->SetDataL( aReq.RequestData() );
+ r->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ CSIPClientTransaction* sipTrans = DoSubscribeL(
+ aReq.RemoteURI(),
+ aReq.RefreshTime(),
+ r->Data(),
+ subsDialog,
+ aReq.IsRefresh(),
+ ESubsList,
+ aReq.Aux() ? ETrue : EFalse );
+ // save SIP Dialog and SIP client transaction
+ r->SetDialog( subsDialog );
+ r->SetTransaction( sipTrans );
+ }
+ else if ( iSipState == ESimpleSipUnavailable || iSipState == ESimpleSipIdle )
+ {
+ User::Leave( KErrNotReady );
+ }
+ else
+ {
+ r->SetReqState( CSimpleRequest::ESimplePendingInit );
+ }
+
+ CleanupStack::Pop( r );
+ iRequestList.AddLast( *r );
+
+ // Start timer to detect infinite wait situation
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+
+ if ( !aReq.IsRefresh() )
+ {
+ // Start refresh timer for garbage colletion for
+ // subscription not needing refresh.
+ TUint myTime = ( aReq.RefreshTime() > iSettings.ExpiryApi() ?
+ aReq.RefreshTime() : iSettings.ExpiryApi() );
+ r->SetRefreshTime( myTime );
+ r->StartRefreshTimer();
+ }
+ // increase subscription counter
+ IncreaseNbrSubs();
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SubscribeWinfoL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::SubscribeWinfoL(
+ MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: SubscribeWinfoL" ));
+#endif
+ // get request-URI from SIP profiles
+ TPtrC8 aor = iProfileObserver->GiveUserAorL();
+ aReq.SetRemoteURIL( aor );
+
+ CSIPSubscribeDialogAssoc* subsDialog = NULL;
+
+ // create the request
+ CSimpleRequest* r = CSimpleRequest::NewL( *this,
+ aReq, CSimpleRequest::EReqSubscribeWinfo, aReq.RefreshTime() );
+ CleanupStack::PushL( r );
+
+ if ( iSipState == ESimpleSipActive )
+ {
+ r->SetDataL( aReq.RequestData() );
+ r->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ CSIPClientTransaction* sipTrans = DoSubscribeL(
+ aReq.RemoteURI(),
+ aReq.RefreshTime(),
+ r->Data(),
+ subsDialog,
+ ETrue,
+ ESubsWinfo,
+ EFalse );
+ // save SIP Dialog and SIP client transaction
+ r->SetDialog( subsDialog );
+ r->SetTransaction( sipTrans );
+ }
+ else if ( iSipState == ESimpleSipUnavailable || iSipState == ESimpleSipIdle )
+ {
+ User::Leave( KErrNotReady );
+ }
+ else
+ {
+ r->SetReqState( CSimpleRequest::ESimplePendingInit );
+ }
+
+ CleanupStack::Pop( r );
+ iRequestList.AddLast( *r );
+
+ // Start timer to detect infinite wait situation
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::StopSubscribeL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::StopSubscribeL(
+ MSimpleEngineRequest& aReq )
+ {
+
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: StopSubscribeL" ));
+#endif
+
+ // Get SIP transaction
+ CSimpleRequest* r = GetCliRequest( aReq );
+ if ( !r )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ CSIPSubscribeDialogAssoc* dialog = r->Dialog();
+ if ( !dialog )
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ if ( r->ReqState() == CSimpleRequest::ESimpleReTry ||
+ r->ReqState() == CSimpleRequest::ESimplePendingInit ||
+ r->ReqState() == CSimpleRequest::ESimplePending )
+ {
+ // There is not active SIP dialog,
+ // therefore real stopping is not needed.
+ r->SetReqState( CSimpleRequest::ESimpleStopping );
+ r->Request().SetResponseMethod( MSimpleEngineRequest::EUnknownResponse );
+ r->Complete( KErrCompletion );
+ return;
+ }
+ else if ( r->ReqState() == CSimpleRequest::ESimpleDeleting )
+ {
+ // there is no active subscription
+ User::Leave( KErrNotFound );
+ }
+
+ // modify the old request entity
+ r->SetTransaction( NULL );
+
+ // create new unsubscribe transaction in the dialog
+ // Add accepted header
+ CSIPMessageElements* mesElems = CSIPMessageElements::NewLC();
+ RPointerArray<CSIPHeaderBase> headers;
+ CleanupClosePushL( headers );
+ // Accept header with application/pidf+xml is
+ // added for reqular subscription and list subscription
+ CSIPAcceptHeader* acceH = NULL;
+ TInt popCount(0);
+
+ if ( r->Match( CSimpleRequest::EReqSubscribe ) ||
+ r->Match( CSimpleRequest::EReqSubscribeList ))
+ {
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleApplicationType, KSimplePidfSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+ ++popCount;
+ }
+ if ( r->Match( CSimpleRequest::EReqSubscribeList ))
+ {
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleApplicationType, KSimpleListSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+ ++popCount;
+
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleMultiType, KSimpleMultipartSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+ ++popCount;
+
+ // add supported header with value eventlist
+ RPointerArray<CSIPSupportedHeader> suppHs =
+ CSIPSupportedHeader::DecodeL( KSimpleEventlist);
+ for( TInt count=0; count < suppHs.Count(); count++ )
+ {
+ User::LeaveIfError( headers.Append( suppHs[count] ));
+ }
+ suppHs.Close();
+ }
+ if ( r->Match( CSimpleRequest::EReqSubscribeWinfo ))
+ {
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleApplicationType, KSimpleWinfoSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+ ++popCount;
+ }
+
+ // ---------------------------------------------------------
+#ifdef _DEBUG
+#ifdef __LOCAL_MODE
+ /**
+ * INTERNAL TEST SUITE
+ */
+ CSimpleLocalModeUtils::AddTestHeaderL( headers );
+#endif
+#endif
+ // ---------------------------------------------------------
+
+ // add content
+ mesElems->SetUserHeadersL( headers );
+
+ // Pop AccessHeaders
+ CleanupStack::Pop( popCount );
+ CleanupStack::PopAndDestroy( &headers );
+
+ // Send SUBSCRIBE message
+ CSIPClientTransaction* sipTrans = dialog->SendUnsubscribeL( mesElems );
+ CleanupStack::Pop( mesElems );
+
+ // save client transaction
+ r->SetTransaction( sipTrans );
+
+ // Start timer to detect infinite wait situation
+ r->SetReqState( CSimpleRequest::ESimpleStopping );
+ r->StartExpiryTimer( iSettings.ExpiryApi() );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::IncomingRequest
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::IncomingRequest( TUint32 /*aIapId*/,
+ CSIPServerTransaction* /*aTransaction*/)
+ {
+ // Nothing to do.
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: IncomingRequest" ));
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::TimedOut
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::TimedOut( CSIPServerTransaction& /*aTransaction*/)
+ {
+ // Nothing to do.
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: TimeOut" ));
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::ConnectionStateChange
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::ConnectionStateChange(
+ TSimpleSipState aState, TInt aSipError )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: ConnectionStateChange %d->%d"),
+ iSipState, aState);
+#endif
+
+ // re-try to get connection
+ TSimpleSipState oldState = iSipState;
+
+ RecognizeSipState( aState );
+
+ // Complete status event
+ if ( oldState != iSipState )
+ {
+ CompleteStatusRequest();
+ }
+
+ // Profile observer gives active event and then the connection can be started to create.
+ if ( oldState == ESimpleSipIdle && aState == ESimpleSipActive )
+ {
+ TRAPD( err, iSipConnection = iProfileObserver->GiveConnectionL() );
+ if ( !err )
+ {
+ SetSipState( ESimpleSipActive );
+ // complete client requests
+ CompleteRegisterRequests( KErrNone );
+ }
+ else if ( err != KErrNotReady )
+ {
+ // error callback to SimpleEngine
+ SetSipState( ESimpleSipInactive );
+ CompleteRegisterRequests( err );
+ }
+ else
+ {
+ // KErrNotReady is a normal error indicating
+ // pending initialization.
+ }
+ }
+ else if ( iSipState == ESimpleSipUnavailable )
+ {
+ iCurrentNbrSubs = 0;
+ // Complete all pending register requests with an error code
+ TInt retErr = aSipError ? aSipError : KErrDisconnected;
+ CompleteRegisterRequests( retErr );
+ // Complete all active subscriptions and publications and
+ // call API callbacks. KErrDisconnected has a special handling
+ // in CSimpleRequest::Complete().
+ CompleteRegularRequests( KErrDisconnected );
+ }
+ else if ( iSipState == ESimpleSipInactive )
+ {
+ iCurrentNbrSubs = 0;
+ // Complete all pending register requests with an error code
+ TInt retErr = aSipError ? aSipError : KErrDisconnected;
+ CompleteRegisterRequests( retErr );
+ // All the dialogs and transactions are lost.
+ // Registeration is done automatically when state is active again.
+ // Complete all active subscriptions and publications and
+ // call API callbacks now. KErrDisconnected has a special handling
+ // in CSimpleRequest::Complete().
+ CompleteRegularRequests( KErrDisconnected );
+ }
+ else if ( iSipState == ESimpleSipSuspend )
+ {
+ // Wait till the active state
+ }
+ else if ( oldState == ESimpleSipSuspend && iSipState == ESimpleSipActive )
+ {
+ // Scan all the pending requests and start to proceed them
+ HandlePendings();
+ }
+ else
+ {
+ // nothing to do
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::HandleReceivedMessage
+// ----------------------------------------------------------
+//
+TInt CSimpleSipConnection::HandleReceivedMessage( const TDesC8& aFrom,
+ const TDesC8& aContent )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log( _L("CSimpleSipConnection::HandleReceivedMessage") );
+#endif
+ TInt error( KErrNone );
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+
+ if ( req->Match( CSimpleRequest::EReqReceiveIM ) )
+ {
+ TRAP( error, DoHandleReceivedMessageL( aFrom, aContent, *req ) )
+ }
+ }
+
+ // KErrNoMemory is returned here if error occurred when allocating
+ // memory for heap descriptors in DoHandleReceivedMessageL
+ return error;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::ConnectionChanged
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::ConnectionChanged()
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: ConnectionChanged"));
+ if( iSipConnection )
+ {
+ TSimpleLogger::Log(_L("SipConnection: ConnectionChanged : old conn state %d (internal:%d)"), iSipConnection->State(), iSipState );
+ TSimpleLogger::Log(_L("SipConnection: ConnectionChanged : old IAP %d"), iSipConnection->IapId() );
+ }
+#endif
+
+ iCurrentNbrSubs = 0;
+ CSIPConnection* conn = NULL;
+ TRAPD( err, conn = iProfileObserver->GiveConnectionL() );
+ if( !err )
+ {
+ delete iSipConnection;
+ iSipConnection = conn;
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: ConnectionChanged : new conn state %d"), iSipConnection->State() );
+ TSimpleLogger::Log(_L("SipConnection: ConnectionChanged : new IAP %d"), iSipConnection->IapId() );
+#endif
+ }
+#ifdef _DEBUG
+ else
+ {
+ TSimpleLogger::Log(_L("SipConnection: ConnectionChanged : Get SIP connection error %d"), err );
+ }
+#endif
+
+ if( iSipConnection )
+ {
+ if( iSipState != iSipConnection->State() )
+ {
+ iConnectionObserver->ConnectionStateChanged( iSipConnection->State() );
+ }
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::StartToCheckExpiryL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::StartToCheckExpiryL( CSimpleRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: StartToCheckExpiryL"));
+#endif
+
+ // This is expired
+ aReq.Complete( KErrTimedOut );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::GetRequest
+// ----------------------------------------------------------
+//
+CSimpleRequest* CSimpleSipConnection::GetRequest(
+ CSIPClientTransaction& aTrans )
+ {
+ // Search the correspoding request element
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ if ( req->Match( aTrans ))
+ {
+ return req;
+ }
+ }
+
+ return (CSimpleRequest*)NULL;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::GetCliRequest
+// ----------------------------------------------------------
+//
+CSimpleRequest* CSimpleSipConnection::GetCliRequest(
+ MSimpleEngineRequest& aReq )
+ {
+ // Search the correspoding request element
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ if ( req->Match( aReq ))
+ {
+ return req;
+ }
+ }
+
+ return (CSimpleRequest*)NULL;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::GetdDialogRequest
+// ----------------------------------------------------------
+//
+CSimpleRequest* CSimpleSipConnection::GetdDialogRequest( const CSIPDialog& aDialog )
+ {
+ // Search the correspoding request element
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ if ( req->Match( aDialog ))
+ {
+ return req;
+ }
+ }
+
+ return (CSimpleRequest*)NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::DeleteRequests
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::DeleteRequests()
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DeleteRequests" ));
+#endif
+ // Delete all buffered transaction requests
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+
+ // open request EReqReceiveIM should not be deleted
+ // will be deleted only when im message received
+ // or destructor is called.
+ if ( !req->Match( CSimpleRequest::EReqReceiveIM ) )
+ {
+ req->Destroy();
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::DeleteRequests
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::DeleteRequests(
+ CSimpleRequest::TSimpleSipReqType aRequestType )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DeleteRequests type=%d" ),
+ aRequestType );
+#endif
+ // Delete buffered transaction requests match to the aRequestType
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+
+ if ( req->Match( aRequestType ) )
+ {
+ req->Destroy();
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::DeleteRequest
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::DeleteRequest( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DeleteRequest" ));
+#endif
+
+ CSimpleRequest* r = CSimpleSipConnection::GetCliRequest( aReq );
+ if ( r )
+ {
+ if ( r->Match( CSimpleRequest::EReqSubscribe ) ||
+ r->Match( CSimpleRequest::EReqSubscribeList ) )
+ {
+ DecreaseNbrSubs();
+ }
+ r->Destroy();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::DeleteRequestStart
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::DeleteRequestStart( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DeleteRequestStart" ));
+#endif
+
+ CSimpleRequest* r = CSimpleSipConnection::GetCliRequest( aReq );
+ if ( r )
+ {
+ if ( r->Match( CSimpleRequest::EReqSubscribe ) ||
+ r->Match( CSimpleRequest::EReqSubscribeList ))
+ {
+ DecreaseNbrSubs();
+ }
+ r->DestroyStart();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::CompleteRegisterRequests
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::CompleteRegisterRequests( TInt aStatus )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: CompleteRegisterRequests %d" ), aStatus);
+#endif
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ if ( req->Match( CSimpleRequest::EReqRegister ))
+ {
+ req->Complete( aStatus );
+ // Open request can be deletetd after completion.
+ req->Destroy();
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::CompleteRegularRequests
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::CompleteRegularRequests( TInt aStatus )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: CompleteRegularRequests %d" ), aStatus);
+#endif
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ if ( req->Match( CSimpleRequest::EReqPublish ) ||
+ req->Match( CSimpleRequest::EReqSubscribe ) ||
+ req->Match( CSimpleRequest::EReqSubscribeList ) ||
+ req->Match( CSimpleRequest::EReqSubscribeWinfo ))
+ {
+ req->SetReason( KErrNone );
+ req->Request().SetResponseMethod( MSimpleEngineRequest::EUnknownResponse );
+ req->Complete( aStatus );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnection::CompleteStatusRequest
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::CompleteStatusRequest( )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: CompleteStatusRequest" ) );
+#endif
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+ if ( req->Match( CSimpleRequest::EReqListenEvents ))
+ {
+ req->CompleteEvent( );
+ return;
+ }
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoPublishL
+// ----------------------------------------------------------
+//
+CSIPClientTransaction* CSimpleSipConnection::DoPublishL(
+ const TDesC8& aRemoteURI, TInt aExpiry,
+ const TDesC8& aContent, const TDesC8& aSipIfMatch,
+ const TDesC8& aContentType )
+ {
+#ifdef _DEBUG
+ TBuf<100> testBuf;
+ testBuf.Copy( aSipIfMatch );
+ TSimpleLogger::Log(_L("SipConnection: DoPublishL expiry=%d sip-if-match=%S" ),
+ aExpiry, &testBuf);
+#endif
+
+ TBool multi( EFalse );
+
+ if ( aContent.Length() &&
+ aContentType.CompareF( KSimpleDocumentType ))
+ {
+ // content exists and not pidf+xml (not refresh)
+ multi = ETrue;
+ }
+
+ if ( !iSipConnection || iSipState != ESimpleSipActive || !iProfileObserver )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ MSIPRegistrationContext* regContext = iProfileObserver->ProfileContext();
+ if ( !regContext )
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ // Check CLIENT-OBJ-DATA-LIMIT
+ TUint myLimit = iSettings.ObjLimit();
+ // Breakpoint:
+ if ( myLimit && (TUint)aContent.Size() > myLimit )
+ {
+ // This is too big mesasge, an error is returned
+ User::Leave( KSimpleErrSettingsLimit );
+ }
+
+ // get request uri from a request
+ TUriParser8 parser;
+ User::LeaveIfError( parser.Parse( aRemoteURI ));
+ CUri8* uri = CUri8::NewLC( parser );
+
+ // Start to fill headres, Remote URI
+ CSIPRequestElements* elems = CSIPRequestElements::NewL(uri);
+ CleanupStack::Pop( uri); // ownership given to elems
+ CleanupStack::PushL( elems );
+ // To header not needed when remote uri set
+
+ uri = CUri8::NewLC( parser );
+ CSIPAddress* sipAddress = CSIPAddress::NewL( uri );
+ CleanupStack::Pop( uri ); // ownership given to sipAddress
+ CleanupStack::PushL( sipAddress );
+
+ // From header
+ CSIPFromHeader* fromH = CSIPFromHeader::NewL( sipAddress );
+ CleanupStack::Pop( sipAddress ); // ownership given to FromHeader
+ CleanupStack::PushL( fromH );
+ elems->SetFromHeaderL( fromH );
+ CleanupStack::Pop( fromH ); // fromH, ownership given to elems
+
+ // start to add other headers
+ RPointerArray<CSIPHeaderBase> headers;
+ CleanupClosePushL(headers);
+
+ // Expires header
+ CSIPExpiresHeader* exprH = new (ELeave) CSIPExpiresHeader(aExpiry);
+ CleanupStack::PushL( exprH );
+ User::LeaveIfError( headers.Append( exprH ));
+ CleanupStack::Pop( exprH ); // exprH
+
+ // Event header
+ CSIPEventHeader* eventH = CSIPEventHeader::NewLC( KSimplePRESENCE_LOW );
+ User::LeaveIfError( headers.Append( eventH ));
+ CleanupStack::Pop( eventH ); // eventH
+
+ // create SIP-ETAG header with CSIPExtensionHeader
+ if ( aSipIfMatch.Length() )
+ {
+ CSIPExtensionHeader* etagH = CSIPExtensionHeader::NewLC(
+ KSimpleSipIfMatch, aSipIfMatch );
+ User::LeaveIfError( headers.Append( etagH ));
+ CleanupStack::Pop( etagH ); // etagH
+ }
+
+ // ---------------------------------------------------------
+#ifdef _DEBUG
+#ifdef __LOCAL_MODE
+ /**
+ * INTERNAL TEST SUITE
+ */
+ CSimpleLocalModeUtils::AddTestHeaderL( headers );
+#endif
+#endif
+ // ---------------------------------------------------------
+
+ CSIPMessageElements& mesElems = elems->MessageElements();
+ mesElems.SetUserHeadersL( headers );
+ CleanupStack::PopAndDestroy( &headers );
+
+ // set Content type and content
+
+ CSIPContentTypeHeader* contTypeH = NULL;
+ if ( aContent.Length() ) //lint !e830
+ {
+ if ( multi )
+ {
+ // Set CID and Boundary parameters as well
+ // ***************************************
+ /*
+ HBufC8* contentTypeB = HBufC8::NewLC(
+ NSimpleDocument::NSimpleMulti::KContentTypeSize +
+ NSimpleDocument::KSimpleBoundarySize ); // << contentTypeB
+ TPtr8 typeAppend( contentTypeB->Des() );
+ TBuf8<10> temppi;
+ temppi.Copy( NSimpleDocument::KSimpleBoundary );
+ typeAppend.Format( NSimpleDocument::NSimpleMulti::KContentType, &temppi );
+ */
+
+ TBuf8<200> temppi;
+ temppi.Copy( NSimpleDocument::NSimpleMulti::KContentTypeFullValue );
+
+ contTypeH = CSIPContentTypeHeader::DecodeL( temppi );
+ // CleanupStack::PopAndDestroy( contentTypeB ); // >> contentTypeB
+ CleanupStack::PushL( contTypeH ); // << contTypeH
+ }
+ else
+ {
+ contTypeH = CSIPContentTypeHeader::NewLC(
+ KSimpleApplicationType, KSimplePidfSubType ); // // << contTypeH
+ }
+
+ // copy content from a request parameter
+ HBufC8* buffer = aContent.AllocLC();
+ mesElems.SetContentL( buffer, contTypeH ); // >> contTypeH
+ // buffer ownership given to mesElems
+ CleanupStack::Pop( buffer );
+ // contTypeH ownership given to mesElems
+ CleanupStack::Pop( contTypeH );
+ }
+ else
+ {
+ // No need to insert content, there wasn't any.
+ }
+
+ // set method
+ RStringF method = SIPStrings::Pool().OpenFStringL( KSimplePUBLISH );
+ CleanupClosePushL( method );
+ elems->SetMethodL( method );
+
+ // Send the request transaction
+ CSIPClientTransaction* sipTrans = iSipConnection->SendRequestL( elems, *regContext );
+ // PopAndDestroy calls method.Close()
+ CleanupStack::PopAndDestroy( &method );
+ CleanupStack::Pop( elems ); // elems, ownership given
+ return sipTrans;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::HandlePublishRespL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::HandlePublishRespL(
+ const CSIPMessageElements& aMesElems, CSimpleRequest* aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: HandlePublishRespL" ));
+#endif
+ TBool ETagReceived(EFalse);
+ RStringF extensionName = SIPStrings::Pool().OpenFStringL( KSimpleETag );
+ CleanupClosePushL( extensionName );
+ const RPointerArray<CSIPHeaderBase>& userHs = aMesElems.UserHeaders();
+ for ( TInt i = 0; i < userHs.Count(); i++ )
+ {
+ const CSIPHeaderBase* header = userHs[ i ];
+ if ( header->Name() == extensionName )
+ {
+ HBufC8* hValue = header->ToTextValueL();
+ // hValue ownership is transferred
+ aReq->SetETag( hValue );
+ // store etag to vimpstsettingstore
+ StoreETagL( *hValue );
+ ETagReceived = ETrue;
+ }
+ else if ( header->Name() == SIPStrings::StringF( SipStrConsts::EExpiresHeader))
+ {
+ // Save the new refresh time.
+ // Start the timer later in CSimplerequest::Complete()
+ CSIPExpiresHeader* eH = (CSIPExpiresHeader*)header;
+ TUint expires = eH->Value();
+ aReq->SetRefreshTime( expires );
+ }
+ else
+ {
+ // We igonre other than Expires and ETag headers
+ }
+ }
+ if ( !ETagReceived || !aReq->RefreshTime() )
+ {
+ // Remove old ETag if nore received or if the expires header was 0 in our request.
+ aReq->SetETag( NULL );
+ //TPtrC8 nullETag = nullETag.Alloc( KNullDesC8 );
+ TBufC8<1> nullETag( KNullDesC8 );
+ HBufC8* buf;
+ buf = nullETag.Alloc();
+ StoreETagL( *buf );
+ delete buf;
+ }
+ // PopAndDestroy calls extensionName.Close()
+ CleanupStack::PopAndDestroy( &extensionName );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::HandleDialogRequestL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::HandleDialogRequestL(
+ const CSIPMessageElements& aMesElems, CSimpleRequest& aReq,
+ const TDesC8& aMethod )
+ {
+#ifdef _DEBUG
+ TBuf<20> myBuf;
+ myBuf.Copy( aMethod );
+ TSimpleLogger::Log(_L("SipConnection: HandleDialogRequestL %S" ), &myBuf);
+ CSIPRefresh* sipR = aReq.Refresh();
+ if ( sipR )
+ {
+ TSimpleLogger::Log(_L("SIPREFRESH STATE = %d" ), sipR->State() );
+ }
+#endif
+
+ _LIT8( KMyActive, "active");
+ _LIT8( KMyPending, "pending");
+
+ if ( aMethod.CompareF( KSimpleNOTIFY ))
+ {
+ // Only NOTIFY is handled.
+ return;
+ }
+
+ aReq.Request().SetResponseMethod( MSimpleEngineRequest::ENotify );
+ aReq.SetReason( KErrNone );
+
+ // Start to search subscription-state header
+ const RPointerArray<CSIPHeaderBase>& userHs = aMesElems.UserHeaders();
+ for ( TInt i = 0; i < userHs.Count(); i++ )
+ {
+ const CSIPHeaderBase* header = userHs[ i ];
+ if ( header->Name() == SIPStrings::StringF( SipStrConsts::ESubscriptionStateHeader))
+ {
+ CSIPSubscriptionStateHeader* stateH =
+ (CSIPSubscriptionStateHeader*)header;
+ TPtrC8 p = stateH->SubStateValue();
+#ifdef _DEBUG
+ myBuf.Copy( p);
+ TSimpleLogger::Log(_L("SipConnection: Subscription-State = %S" ), &myBuf);
+#endif
+ if ( !p.CompareF( KMyActive ))
+ {
+ // "active" Notification received
+ aReq.ResetErrCount();
+ aReq.Complete( KErrNone );
+ }
+ else if ( !p.CompareF( KMyPending ))
+ {
+ // "pending" Notification received
+ aReq.ResetErrCount();
+ aReq.Complete( KSimpleErrPending );
+ }
+ else // KMyTerminated
+ {
+ // "terminated"
+
+ aReq.PlusErrCount();
+
+ // Get the value of reason parameter if any exists.
+ RStringF value;
+ value = stateH->ParamValue( SIPStrings::StringF(
+ SipStrConsts::EReason ));
+ DoSetResponseReason( value.DesC(), aReq );
+
+ // Get retry-after parameter
+ TInt retryAfter = stateH->RetryAfterParameter();
+ if ( retryAfter < 0 )
+ {
+ retryAfter = 0;
+ }
+ aReq.SetRetryAfter( retryAfter );
+
+ // Retry in certain situations and do not send
+ // the final error to the client yet.
+
+ // Detect an error loop if server always returns "terminated"
+ // Certain errors are serious, and no reason to retry.
+ if ( aReq.ErrCount() > 1 ||
+ IsPermanentReason( aReq.Reason() ) ||
+ !(aReq.Request().IsRefresh()) ||
+ aReq.ReqState() != CSimpleRequest::ESimpleActiveSubs )
+ {
+ // Complete the client request.
+ // KErrCompletion has a special handling in a client observer.
+ // Set the reason code too.
+ DoSetResponseReason2( aReq.Reason(), aReq.Request() );
+ aReq.Complete( KErrCompletion );
+ }
+ else // ESimpleActiveSubs, no fatal error
+ {
+ // terminated[ refresh ]
+ // Retry later
+ // Notice that permanent reason is handled above
+ // also for ESimpleActiveSubs
+ //
+ DoSetResponseReason2( aReq.Reason(), aReq.Request() );
+ // CSimpleRequest::Complete handles this case even when re-tried
+ // without API callback..
+ aReq.Complete( KSimpleErrTemporary );
+ }
+ }
+ // No need to scan rest of the SIP headers
+ return;
+ }
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoSubscribeL
+// ----------------------------------------------------------
+//
+CSIPClientTransaction* CSimpleSipConnection::DoSubscribeL(
+ const TDesC8& aRemoteURI, TInt aExpiry,
+ const TDesC8& aContent,
+ CSIPSubscribeDialogAssoc*& aSubsDialog,
+ TBool aRefresh,
+ TSimpleSubsType aType,
+ TBool aAnonymous )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DoSubscribeL expiry=%d" ), aExpiry);
+#endif
+
+ // array grow granularity
+ const TInt KMyGran = 10;
+
+ if ( !iSipConnection || iSipState != ESimpleSipActive )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DoSubscribeL LEAVES **" ));
+#endif
+ User::Leave( KErrNotReady );
+ }
+
+ TUint myLimit = iSettings.MaxSubscriptions();
+ // Breakpoint:
+ if ( myLimit && iCurrentNbrSubs >= myLimit && aType != ESubsWinfo )
+ {
+ User::Leave( KSimpleErrSettingsLimit );
+ }
+
+ // get request (remote) uri from a request
+ TUriParser8 parser;
+ User::LeaveIfError( parser.Parse( aRemoteURI ));
+ CUri8* uri = CUri8::NewLC( parser );
+
+ // Event header
+ CSIPEventHeader* eventH = NULL;
+ if ( aType == ESubsRegular || aType == ESubsList )
+ {
+ eventH = CSIPEventHeader::NewLC( KSimplePRESENCE_LOW );
+ }
+ else // if ( aType == ESubsWinfo )
+ {
+ eventH = CSIPEventHeader::NewLC( KSimplePRESENCE_LOW );
+ CDesC8ArrayFlat* flat = new (ELeave) CDesC8ArrayFlat( KMyGran );
+ CleanupStack::PushL( flat );
+ flat->AppendL( KSimpleWINFO );
+ eventH->SetEventTemplatesL( *flat );
+ CleanupStack::PopAndDestroy( flat );
+ }
+
+ // From header
+ // Create is if anonymous request, otherwise use SIP Profile AOR
+ CSIPFromHeader* fromH = NULL;
+
+ if ( aAnonymous )
+ {
+ // Generate From header
+ fromH = CSIPFromHeader::DecodeL( KSimpleAnonymous );
+ }
+ CleanupStack::PushL( fromH );
+
+ // Subscribe Dialog
+ CSIPSubscribeDialogAssoc* sda = CSIPSubscribeDialogAssoc::NewL(
+ *iSipConnection, uri, *iProfileObserver->ProfileContext(),
+ eventH, fromH );
+
+ CleanupStack::Pop( fromH );
+ CleanupStack::Pop( eventH );
+ CleanupStack::Pop( uri );
+ CleanupStack::PushL( sda );
+
+ // start to add other headers
+ CSIPMessageElements* mesElems = CSIPMessageElements::NewLC();
+ RPointerArray<CSIPHeaderBase> headers;
+ CleanupClosePushL( headers );
+
+ // Expires header
+ CSIPExpiresHeader* exprH = new (ELeave) CSIPExpiresHeader(aExpiry);
+ CleanupStack::PushL( exprH );
+ User::LeaveIfError( headers.Append( exprH ));
+
+ // Accept header with application/pidf+xml is
+ // added for reqular subscription and list subscription
+ CSIPAcceptHeader* acceH = NULL;
+ if ( aType != ESubsWinfo )
+ {
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleApplicationType, KSimplePidfSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+
+ // notice: allow multipart/related always!
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleMultiType, KSimpleMultipartSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+ }
+
+ if ( aType == ESubsList )
+ {
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleApplicationType, KSimpleListSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+
+ // add supported header with value eventlist
+ RPointerArray<CSIPSupportedHeader> suppHs =
+ CSIPSupportedHeader::DecodeL( KSimpleEventlist);
+ for( TInt count=0; count < suppHs.Count(); count++ )
+ {
+ User::LeaveIfError( headers.Append( suppHs[count] ));
+ }
+ suppHs.Close();
+ }
+
+ if ( aType == ESubsWinfo )
+ {
+ acceH = CSIPAcceptHeader::NewLC(
+ KSimpleApplicationType, KSimpleWinfoSubType );
+ User::LeaveIfError( headers.Append( acceH ));
+ }
+
+ // For anonymous request add Privacy and P-Preferred-Identity headers
+ CSIPExtensionHeader* privacyH = NULL;
+ CSIPExtensionHeader* pPIH = NULL;
+ HBufC8* myBuffer = NULL;
+ if ( aAnonymous )
+ {
+ privacyH = CSIPExtensionHeader::NewLC(
+ KSimplePrivacy, KSimpleId );
+ User::LeaveIfError( headers.Append( privacyH ));
+ TInt aorLength = iProfileObserver->GiveUserAorL().Length();
+ myBuffer = HBufC8::NewLC( aorLength + 2 ); // room for brackets
+ *myBuffer = _L8("<");
+ myBuffer->Des().Append( iProfileObserver->GiveUserAorL() );
+ myBuffer->Des().Append( _L8(">"));
+ pPIH = CSIPExtensionHeader::NewLC(
+ KSimplePIdentity, myBuffer->Des() );
+ User::LeaveIfError( headers.Append( pPIH ));
+ }
+
+ // ---------------------------------------------------------
+
+#ifdef _DEBUG
+#ifdef __LOCAL_MODE
+ /**
+ * INTERNAL TEST SUITE
+ */
+ CSimpleLocalModeUtils::AddTestHeaderL(headers);
+#endif
+#endif
+ // ---------------------------------------------------------
+
+ // add content and create refresh entity
+ mesElems->SetUserHeadersL( headers );
+ // ownership of elements is given to mesElems
+ if ( aAnonymous )
+ {
+ CleanupStack::Pop( pPIH );
+ CleanupStack::PopAndDestroy( myBuffer );
+ CleanupStack::Pop( privacyH );
+ }
+ if ( aType == ESubsList )
+ {
+ CleanupStack::Pop( 3 ); // 3 * acceH
+ }
+ else if ( aType == ESubsRegular )
+ {
+ CleanupStack::Pop( 2 ); // 2 * acceH
+ }
+ else // ESubsWinfo
+ {
+ CleanupStack::Pop( 1 ); // 1 * acceH
+ }
+ CleanupStack::Pop( exprH );
+ CleanupStack::PopAndDestroy( &headers );
+
+ // set Content type and content
+ if ( aContent.Length() )
+ {
+ CSIPContentTypeHeader* contTypeH = CSIPContentTypeHeader::NewLC(
+ KSimpleApplicationType, KSimpleSubscribeSubType );
+ // copy content from a request parameter
+ HBufC8* buffer = aContent.AllocLC();
+ mesElems->SetContentL( buffer, contTypeH );
+ // buffer ownership given to mesElems
+ CleanupStack::Pop( buffer );
+ // contTypeH ownership given to mesElems
+ CleanupStack::Pop( contTypeH );
+ }
+
+ CSIPRefresh* refresh = NULL;
+ if ( aExpiry && aRefresh )
+ {
+ refresh = CSIPRefresh::NewLC();
+ }
+ // Refresh gets its value from expires header.
+ CSIPClientTransaction* sipTrans = sda->SendSubscribeL( mesElems, refresh );
+ if ( refresh )
+ {
+ CleanupStack::Pop( refresh );
+ }
+ CleanupStack::Pop( mesElems );
+ // CSIPSubscribeDialogAssoc must not be deleted until it is ubsubscribed
+ CleanupStack::Pop( sda );
+ aSubsDialog = sda;
+
+ return sipTrans;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::RegisterDefaultL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::RegisterDefaultL( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: RegisterDefaultL" ));
+#endif
+ iProfileObserver->RegisterDefaultProfileL();
+ SetSipState( ESimpleSipIdle );
+ TRAPD( err, iSipConnection = iProfileObserver->GiveConnectionL() );
+ if ( !err )
+ {
+ SetSipState( ESimpleSipActive );
+ aReq.Complete( KErrNone );
+ }
+ else if ( err != KErrNotReady )
+ {
+ // KErrNotReady is a normal error indicating
+ // pending initialization
+ User::Leave( err );
+ }
+ else
+ {
+ // KErrNotReady situation
+ }
+ // Save the request to wait a response
+ CSimpleRequest* simpleR = CSimpleRequest::NewL(
+ *this, aReq, CSimpleRequest::EReqRegister, aReq.RefreshTime() );
+ iRequestList.AddLast( *simpleR );
+ // Start timer to detect infinite wait situation
+ simpleR->StartExpiryTimer( iSettings.ExpiryApi() );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::RegisterAnyL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::RegisterAnyL( MSimpleEngineRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: RegisterAnyL" ));
+#endif
+
+ iSettings.ReadOTASettingsL( aReq.Aux() );
+
+ TInt32 uniqueId = iSettings.SipProfileId();
+ TUid uniqueUid;
+ uniqueUid.iUid = uniqueId;
+
+ if ( !iSip && !iProfileObserver )
+ {
+ iSip = CSIP::NewL( uniqueUid, *this );
+
+ iProfileObserver = CSimpleSipProfileObserver::NewL(
+ iSip, *iConnectionObserver);
+ }
+
+ iProfileObserver->RegisterGivenProfileL( iSettings.SipProfileId() );
+ SetSipState( ESimpleSipIdle );
+ TRAPD( err, iSipConnection = iProfileObserver->GiveConnectionL() );
+ if ( !err )
+ {
+ SetSipState( ESimpleSipActive );
+ aReq.Complete( KErrNone );
+ }
+ else if ( err != KErrNotReady )
+ {
+ // KErrNotReady is a normal error indicating
+ // pending initialization
+ User::Leave( err );
+ }
+ else
+ {
+ // KErrNotReady situation
+ }
+ // Save the request to wait a response
+ CSimpleRequest* simpleR = CSimpleRequest::NewL(
+ *this, aReq, CSimpleRequest::EReqRegister, aReq.RefreshTime() );
+ iRequestList.AddLast( *simpleR );
+ // Start timer to detect infinite wait situation
+ simpleR->StartExpiryTimer( iSettings.ExpiryApi() );
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::SetSipState
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::SetSipState( TSimpleSipState aState )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: SetSipState %d this=%d" ), aState, (TInt)this );
+#endif
+ iSipState = aState;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoSetResponseReason
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DoSetResponseReason(
+ const TDesC8& aReason, CSimpleRequest& aR )
+ {
+ if ( aReason.Length() == 0 )
+ {
+ aR.SetReason( KErrNone );
+ }
+ else if ( !aReason.CompareF( KSimpleRejected ))
+ {
+ aR.SetReason( KSimpleErrRejected );
+ }
+ else if ( !aReason.CompareF( KSimpleTimeout ))
+ {
+ aR.SetReason( KSimpleErrTimeout );
+ }
+ else if ( !aReason.CompareF( KSimpleDeactivated ))
+ {
+ aR.SetReason( KSimpleErrDeactivated );
+ }
+ else if ( !aReason.CompareF( KSimpleProbation ))
+ {
+ aR.SetReason( KSimpleErrProbation );
+ }
+ else if ( !aReason.CompareF( KSimpleNoresource ))
+ {
+ aR.SetReason( KSimpleErrNoresource );
+ }
+ else if ( !aReason.CompareF( KSimpleGiveup ))
+ {
+ aR.SetReason( KSimpleErrGiveup);
+ }
+ else
+ {
+ aR.SetReason( KErrNone );
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoSetResponseReason2
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DoSetResponseReason2(
+ TInt aReason, MSimpleEngineRequest& aR )
+ {
+ switch ( aReason )
+ {
+ case KSimpleErrRejected:
+ aR.SetResponseReason( MSimpleEngineRequest::ERejected );
+ break;
+ case KSimpleErrTimeout:
+ aR.SetResponseReason( MSimpleEngineRequest::ETimeout );
+ break;
+ case KSimpleErrDeactivated:
+ aR.SetResponseReason( MSimpleEngineRequest::EDeactivated );
+ break;
+ case KSimpleErrProbation:
+ aR.SetResponseReason( MSimpleEngineRequest::EProbation );
+ break;
+ case KSimpleErrNoresource:
+ aR.SetResponseReason( MSimpleEngineRequest::ENoresource );
+ break;
+ case KSimpleErrGiveup:
+ aR.SetResponseReason( MSimpleEngineRequest::EGiveup );
+ break;
+ default:
+ aR.SetResponseReason( MSimpleEngineRequest::ENoReason );
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::IsPermanentReason
+// ----------------------------------------------------------
+//
+TBool CSimpleSipConnection::IsPermanentReason( TInt aReason )
+ {
+ switch ( aReason )
+ {
+ case KSimpleErrPending:
+ case KSimpleErrDeactivated:
+ case KSimpleErrProbation:
+ case KSimpleErrTimeout:
+ case KSimpleErrGiveup:
+ case KSimpleErrTemporary:
+ return EFalse;
+ default:
+ return ETrue;
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::IncreaseNbrSubs
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::IncreaseNbrSubs()
+ {
+ ++iCurrentNbrSubs;
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: ++iCurrentNbrSubs %d" ),
+ iCurrentNbrSubs );
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DecreaseNbrSubs
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DecreaseNbrSubs()
+ {
+ if ( iCurrentNbrSubs )
+ {
+ --iCurrentNbrSubs;
+ }
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: --iCurrentNbrSubs %d" ),
+ iCurrentNbrSubs );
+#endif
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoRefreshPublishL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DoRefreshPublishL( CSimpleRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DoRefreshPublishL"));
+#endif
+
+ CSimpleRequest::TSimpleReqState orig = aReq.ReqState();
+
+ // First, handle
+ // expires [ no refresh ]
+ if ( !aReq.Request().IsRefresh() && orig==CSimpleRequest::ESimpleActive )
+ {
+ aReq.SetStatus( 0 );
+ aReq.Complete( KErrTimedOut );
+ return;
+ }
+ if ( orig == CSimpleRequest::ESimpleRunningInit )
+ {
+ // This might happen with short expiry time when there is no response
+ // from a network.
+ aReq.SetStatus( 0 );
+ aReq.Complete( KErrTimedOut );
+ return;
+ }
+ else if ( orig == CSimpleRequest::ESimplePending )
+ {
+ // If refresh is already once set to pending,then this publication is terminated (expired)
+ if ( aReq.PendingState() == CSimpleRequest::EPendingRefresh ||
+ aReq.PendingState() == CSimpleRequest::EPendingModifyAndRefresh )
+ {
+ // special error code that terminates the whole publication.
+ aReq.Complete( KErrCompletion );
+ return;
+ }
+
+ }
+ else if ( orig != CSimpleRequest::ESimpleActive )
+ {
+ // special error code that terminates the whole publication.
+ aReq.Complete( KErrCompletion );
+ return;
+ }
+
+ if ( iSipState == ESimpleSipActive )
+ {
+ // set request state
+ aReq.SetReqState( CSimpleRequest::ESimpleRunning );
+ TInt errx = DoSendPendingPublish( aReq );
+ if ( errx )
+ {
+ // Error changes the state and calls API callback when needed
+ aReq.Complete( errx );
+ }
+ else
+ {
+ // start refresh timer to detect expiry of publication
+ aReq.StartRefreshTimer( aReq.RetryExpiryTime() );
+ // Do not start expiry timer
+ }
+ }
+ else if ( iSipState == ESimpleSipSuspend )
+ {
+ // no network available
+ // refresh [ no network ]
+ // start refresh timer to detect expiry of publication
+ aReq.StartRefreshTimer( aReq.RetryExpiryTime() );
+ // Do not start expiry timer
+ aReq.SetReqState( CSimpleRequest::ESimplePending );
+ aReq.AddPendingState( CSimpleRequest::EPendingRefresh );
+ }
+ else
+ {
+ User::Leave( KErrNotReady );
+ }
+
+ // DO NOT update SOURCE-THROTTLE-PUBLISH time
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoRefreshSubscribe
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DoRefreshSubscribe( CSimpleRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DoRefreshSubscribe"));
+#endif
+
+ if ( !aReq.Request().IsRefresh() )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: Refresh EXPIRED **"));
+#endif
+ // This is expired and no need to refresh
+ aReq.Complete( KErrTimedOut );
+ }
+
+ aReq.StartExpiryTimer( aReq.RetryExpiryTime() );
+
+ if ( iSipState != ESimpleSipActive )
+ {
+ if ( aReq.ReqState() == CSimpleRequest::ESimpleReTry )
+ {
+ // time to retry [ no network ]
+ aReq.SetReqState( CSimpleRequest::ESimplePending );
+ // expiry timer i already runnig
+ }
+ }
+ else
+ {
+ if ( aReq.ReqState() == CSimpleRequest::ESimplePending ||
+ aReq.ReqState() == CSimpleRequest::ESimpleReTry )
+ {
+ // time to retry / SIP req
+ // recreate a dialog
+ aReq.SetReqState( CSimpleRequest::ESimpleDialogReCre );
+ TRAPD( errx, DoCreateDialogL( aReq ) );
+ if ( errx )
+ {
+ // error
+ // This will call API callback
+ // Original error has been SIP error
+ aReq.SetReqState( CSimpleRequest::ESimpleFailed );
+ aReq.Complete( KSimpleErrTemporary );
+ }
+ else
+ {
+ // waiting OK resp
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoCreateDialogL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DoCreateDialogL( CSimpleRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DoCreateDialogL"));
+#endif
+
+ CSIPSubscribeDialogAssoc* subsDialog = NULL;
+ CSIPClientTransaction* sipTrans = NULL;
+
+ // Check whether regular subscription or WINFO subscription is needed.
+ MSimpleEngineRequest::TSimpleRequest reqType= aReq.Request().RequestType();
+ TSimpleSubsType subsType = ESubsRegular;
+ if ( reqType == MSimpleEngineRequest::ESubscribeLista )
+ {
+ subsType = ESubsList;
+ }
+ else if ( reqType == MSimpleEngineRequest::ESubscribeWinfo )
+ {
+ subsType = ESubsWinfo;
+ }
+
+ // send SIP request
+ sipTrans = DoSubscribeL(
+ aReq.Request().RemoteURI(),
+ aReq.Request().RefreshTime(),
+ aReq.Data(),
+ subsDialog,
+ aReq.Request().IsRefresh(),
+ subsType,
+ aReq.Request().Aux() ? ETrue : EFalse );
+
+ // save SIP Dialog and SIP client transaction
+ aReq.SetDialog( subsDialog );
+ aReq.SetTransaction( sipTrans );
+
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoSendPendingPublish
+// ----------------------------------------------------------
+//
+TInt CSimpleSipConnection::DoSendPendingPublish(
+ CSimpleRequest& aReq )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log(_L("SipConnection: DoSendPendingPublish" ));
+#endif
+
+ // Do the SIP Publish transaction
+ TBool sendData = aReq.PendingState() == CSimpleRequest::EPendingModify ||
+ aReq.PendingState() == CSimpleRequest::EPendingModifyAndRefresh ?
+ ETrue : EFalse;
+ TPtrC8 myData = sendData ? aReq.Data() : TPtrC8();
+ CSIPClientTransaction* sipTrans = NULL;
+ TRAPD( errx, sipTrans = DoPublishL(
+ iProfileObserver->GiveUserAorL(),
+ aReq.Request().RefreshTime(),
+ myData,
+ aReq.ETag(), aReq.RequestContentType() ));
+ if ( errx )
+ {
+ return errx;
+ }
+ // Save SIP client transaction
+ aReq.SetTransaction( sipTrans );
+
+ aReq.SetPendingState( CSimpleRequest::ENoPending );
+
+ // Do not update SOURCE-THROTTLE-PUBLISH time
+
+ // Expiry timer is already running
+
+ return KErrNone;
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::HandlePendings
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::HandlePendings( )
+ {
+ TInt errx( KErrNone );
+ TDblQueIter<CSimpleRequest> rIter( iRequestList );
+ rIter.SetToFirst();
+
+ while ( rIter )
+ {
+ CSimpleRequest* req = rIter;
+ rIter++; //lint !e1757
+
+ if ( req->Match( CSimpleRequest::EReqSubscribe ) ||
+ req->Match( CSimpleRequest::EReqSubscribeList ) ||
+ req->Match( CSimpleRequest::EReqSubscribeWinfo ))
+ {
+ // Subscritions
+ // Set new request state
+ if ( req->ReqState() == CSimpleRequest::ESimplePendingInit )
+ {
+ req->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ }
+ else if ( req->ReqState() == CSimpleRequest::ESimplePending )
+ {
+ req->SetReqState( CSimpleRequest::ESimpleDialogReCre );
+ }
+ else
+ {
+ // other states do not need network recovery
+ break;
+ }
+
+ // create new dialog
+ TRAP( errx, DoCreateDialogL( *req ) );
+ if ( errx )
+ {
+ // error
+ // This will call API callback
+ req->SetReqState( CSimpleRequest::ESimpleFailed );
+ req->Complete( errx );
+ }
+ else
+ {
+ // Start to wait response from SIP stack.
+ // Expiry timer is already runnig to detect infinite wait situation
+ }
+ }
+ else if ( req->Match( CSimpleRequest::EReqPublish ) )
+ {
+ // Publications
+ if ( req->ReqState() == CSimpleRequest::ESimplePendingInit )
+ {
+ req->SetReqState( CSimpleRequest::ESimpleRunningInit );
+ }
+ else if ( req->ReqState() == CSimpleRequest::ESimplePending )
+ {
+ req->SetReqState( CSimpleRequest::ESimpleRunning );
+ }
+ else
+ {
+ // other states do not need network recovery
+ break;
+ }
+ // retry publication
+ if ( DoSendPendingPublish( *req ) )
+ {
+ // error
+ // This will call API callback
+ req->SetReqState( CSimpleRequest::ESimpleFailed );
+ req->Complete( errx );
+ }
+ else
+ {
+ // Start to wait response from SIP stack.
+ // Expiry timer is already runnig to detect infinite wait situation
+ }
+ }
+ } // while
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::RecognizeSipState
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::RecognizeSipState(
+ TSimpleSipState aState )
+ {
+ if ( aState == ESimpleSipActive )
+ {
+ // Check that both SIP Profile and SIP connection are ready.
+ // iProfileObserver is created in ConstructL.
+ if ( iProfileObserver->IsProfileActive() &&
+ iSipConnection &&
+ iSipConnection->State() == CSIPConnection::EActive )
+ {
+ SetSipState( aState );
+ }
+ }
+ else
+ {
+ SetSipState( aState );
+ }
+ }
+
+// ----------------------------------------------------------
+// CSimpleSipConnection::DoHandleReceivedMessageL
+// ----------------------------------------------------------
+//
+void CSimpleSipConnection::DoHandleReceivedMessageL( const TDesC8& aFrom,
+ const TDesC8& aContent, CSimpleRequest& aRequest )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log( _L(
+ "CSimpleSipConnection::DoHandleReceivedMessageL - Start" ) );
+#endif
+ aRequest.SetReason( KErrNone );
+ aRequest.SetRecipientL( aFrom );
+ aRequest.SetDataL( aContent );
+ aRequest.Complete( KErrNone );
+ // Open request can be deleted after completion.
+ aRequest.Destroy();
+#ifdef _DEBUG
+ TSimpleLogger::Log( _L(
+ "CSimpleSipConnection::DoHandleReceivedMessageL - End" ) );
+#endif
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleRequest::SetServiceId
+// -----------------------------------------------------------------------------
+EXPORT_C void CSimpleSipConnection::SetServiceId( TInt32 aServiceId )
+ {
+#ifdef _DEBUG
+ TSimpleLogger::Log( _L(
+ "CSimpleSipConnection::SetServiceId old serviceId = %d, new serviceId = %d" ),
+ iServiceId, aServiceId );
+#endif
+ iServiceId = aServiceId;
+ }
+
+// -----------------------------------------------------------------------------
+// CSimpleRequest::StoreETag
+// -----------------------------------------------------------------------------
+void CSimpleSipConnection::StoreETagL( HBufC8& aETag )
+ {
+#ifdef _DEBUG
+ TBuf<255> printDocumentId;
+ printDocumentId.Copy( aETag );
+ TSimpleLogger::Log(_L("CSimpleSipConnection: StoreETag ETag = %S, serviceId = %d" ),
+ &printDocumentId, iServiceId );
+#endif
+ MVIMPSTSettingsStore* settings = CVIMPSTSettingsStore::NewLC();
+
+ // Store ETag to uiservicetabsettings
+ User::LeaveIfError( settings->SetL(
+ iServiceId, EServicePresenceSessionIdentifier, aETag ) );
+
+ CleanupStack::PopAndDestroy(); //settings
+ }
+