simpleengine/siputils/src/simplesipconnectionobserver.cpp
changeset 0 c8caa15ef882
child 17 2669f8761a99
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simpleengine/siputils/src/simplesipconnectionobserver.cpp	Tue Feb 02 01:05:17 2010 +0200
@@ -0,0 +1,909 @@
+/*
+* 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 connection
+*
+*/
+
+
+
+
+
+#include <sipconnectionobserver.h>
+#include <sipmessageelements.h>
+#include <sipresponseelements.h>
+#include <sipregistrationbinding.h>
+#include <sipconnection.h>
+#include <siprefresh.h>
+#include <sipdialog.h>
+#include <sipdialogassocbase.h>
+#include <sipsubscribedialogassoc.h>
+#include <sipstrings.h>
+#include <sipstrconsts.h>
+#include <sipclienttransaction.h>
+#include <sipservertransaction.h>
+#include <siprequestelements.h>
+
+#include <sipretryafterheader.h>
+#include <sipextensionheader.h>
+#include <sipcontenttypeheader.h>
+
+#include <siperr.h>
+#include <sipaddress.h>
+#include <sipfromheader.h>
+
+#include "simplecommon.h"
+#include "simplesipconnectionobserver.h"
+#include "simplesipconncallback.h"
+#include "simplerequest.h"
+#include "simpleerrors.h"
+
+#ifdef _DEBUG
+#include "simpledebugutils.h"
+#endif
+
+// SIP response Call/Transaction does not exists
+const TUint  KSimple481 = 481;
+
+_LIT8 ( KSimpleBoundary, "boundary" );
+_LIT8 ( KSimpleStart, "start");
+_LIT8 ( KAt, "@" );
+
+#ifdef _DEBUG
+#include "simpledebugutils.h"
+#ifdef __LOCAL_MODE
+//  INTERNAL TEST SUITE
+#include "simplelocalmodeutils.h"
+#endif
+#endif
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::CSimpleSipConnectionObserver
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CSimpleSipConnectionObserver::CSimpleSipConnectionObserver(
+    MSimpleSipConnCallback& aCallback )
+    : iCallback( aCallback )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::~CSimpleSipConnectionObserver
+// -----------------------------------------------------------------------------
+//
+CSimpleSipConnectionObserver::~CSimpleSipConnectionObserver()
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: DESTRUCTOR this=%d"), (TInt)this);
+#ifdef __LOCAL_MODE
+    /**
+     * INTERNAL TEST SUITE
+     */
+    delete iLocalModeUtils;
+#endif        
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::NewL
+// -----------------------------------------------------------------------------
+//
+CSimpleSipConnectionObserver* CSimpleSipConnectionObserver::NewL(
+    MSimpleSipConnCallback& aCallback )
+    {
+    CSimpleSipConnectionObserver* self = new (ELeave) CSimpleSipConnectionObserver( aCallback );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: NewL this=%d"), (TInt)self);
+#endif
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ConstructL()
+    {
+#ifdef _DEBUG
+#ifdef __LOCAL_MODE
+    /**
+     * INTERNAL TEST SUITE
+     */
+    iLocalModeUtils = CSimpleLocalModeUtils::NewL( );
+    iLocalModeUtils->SubscribeNetworkStateL( this );
+#endif
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ConnectionStateChanged
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ConnectionStateChanged(
+    CSIPConnection::TState aState )
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ConnectionStateChanged state=%d sip=%d"), aState );
+#endif  
+    ConnectionStateChanged2( aState, KErrNone );
+    }
+    
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ProfileStateChanged
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ProfileStateChanged(
+    CSIPConnection::TState aState, TInt aSipError )
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ProfileStateChanged state=%d sip=%d"), aState );
+#endif
+      ConnectionStateChanged2( aState, aSipError );      
+    }     
+    
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ProfileUpdated
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ProfileUpdated()
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ProfileUpdated"));
+#endif
+    iCallback.ConnectionChanged();
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ConnectionStateChanged2
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ConnectionStateChanged2(
+    CSIPConnection::TState aState, TInt aSipError )
+    {
+    TInt retErr = aSipError ? ConvertSipCode( aSipError, EFalse, EFalse ) : KErrNone;
+    switch ( aState )
+      {
+      // Here is a logic, how to tell active state upward after waiting both
+      // connection and profile to be ok.
+      case CSIPConnection::EInit:
+          iCallback.ConnectionStateChange( ESimpleSipIdle, retErr );
+          break;
+      case CSIPConnection::EActive:                      
+         iCallback.ConnectionStateChange( ESimpleSipActive, retErr );
+          break;
+      case CSIPConnection::ESuspended:
+          iCallback.ConnectionStateChange( ESimpleSipSuspend, retErr);
+          break;
+      case CSIPConnection::EInactive:
+          iCallback.ConnectionStateChange( ESimpleSipInactive, retErr );
+          break;
+      case CSIPConnection::EUnavailable:
+          iCallback.ConnectionStateChange( ESimpleSipUnavailable, retErr );
+          break;
+      default:
+          break;
+      }; 
+    }    
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::IncomingResponse
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::IncomingResponse (
+    CSIPClientTransaction& /*aTransaction*/,
+    CSIPRegistrationBinding& /*aRegistration*/)
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: IncomingResponse" ));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ErrorOccured
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ErrorOccured (
+    TInt aError,
+    CSIPClientTransaction& /*aTransaction*/,
+    CSIPRegistrationBinding& /*aRegistration*/)
+    {
+    iError = aError;
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ErrorOccured 1 err=%d"), aError );
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ErrorOccured
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ErrorOccured (
+    TInt aError,
+    CSIPRegistrationBinding& /*aRegistration*/)
+    {
+    iError = aError;
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ErrorOccured 2 err=%d" ), aError);
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ErrorOccured
+// This is mainly for Publish errors, no dialog.
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ErrorOccured (
+    TInt aError,
+    CSIPTransactionBase& aTransaction )
+    {
+    iError = aError;
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ErrorOccured 3 err=%d" ), aError);
+#endif
+    if ( aTransaction.IsSIPClientTransaction() )
+        {
+        CSIPTransactionBase::TState sipState = CSIPTransactionBase::ETrying;
+        TRAP_IGNORE( sipState = aTransaction.StateL() );
+        CSimpleRequest* r = iCallback.GetRequest(
+            STATIC_CAST( CSIPClientTransaction&, aTransaction) );
+        if ( r && sipState == CSIPTransactionBase::ETerminated )
+            {
+            TInt retCode = aError == KErrSIPForbidden ? KErrAccessDenied : KErrCommsBreak;
+            r->SetStatus( 0 );
+            // update response method
+            r->Request().SetResponseMethod( MSimpleEngineRequest::EUnknownResponse );
+            r->Complete( retCode );
+            }
+        else
+            {
+            // nothing to do
+            }
+        }
+    else
+        {
+        // nothing to do
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ErrorOccured
+// Dialog refresh has failed, a transaction has been deleted.
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ErrorOccured (
+    TInt aError,
+    CSIPDialogAssocBase& aDialogAssoc )
+    {
+    // This is called when SUBSCRIBE refresh fails with
+    // an error response from a remote server.
+    iError = aError;
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ErrorOccured 4 err=%d" ), aError );
+#endif
+
+    TInt retCode = aError == KErrSIPForbidden ? KErrAccessDenied : KErrCommsBreak;
+    TUint status(0);
+    TUint myRefresh(0);
+
+    CSIPSubscribeDialogAssoc& myDialogA = STATIC_CAST( CSIPSubscribeDialogAssoc&, aDialogAssoc );
+    const CSIPDialog& myDialog = myDialogA.Dialog();
+    CSimpleRequest* r = iCallback.GetdDialogRequest( myDialog );
+    if ( !r )
+        {
+        // request not found
+        return;
+        }
+
+    if ( aError == KErrSIPTerminatedWithResponse )
+        {
+        // It's subscription's response with data
+        const CSIPRefresh* refresh = myDialogA.SIPRefresh();
+        if ( refresh  )
+            {
+            // This instance is not the initial transaction but
+            // the refresh transaction instance.
+            // Ownership is not transferred. May be NULL.
+            const CSIPClientTransaction* trans = refresh->SIPTransaction();
+            if ( trans )
+                {
+                // ownership isn't transferred.
+                // Elems must exist with KErrSIPTerminatedWithResponse
+                const CSIPResponseElements* elems = trans->ResponseElements();
+               // Get retry-after header value
+                myRefresh = GetRetryAfter( elems );
+                // Get SIP Status
+                status = elems->StatusCode();
+                if ( status >= KSimpleOK )
+                    {
+                    retCode = ConvertSipCode( status, myRefresh ? ETrue: EFalse, EFalse );
+                    }
+                }
+            }
+        }
+
+    // Update the request entity and complete it.
+    r->SetRetryAfter( myRefresh );
+    r->SetStatus( status );
+    r->Request().SetResponseMethod( MSimpleEngineRequest::EUnknownResponse );
+    r->Complete( retCode );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ErrorOccured
+// Sending of either request or response failed, dialog specific.
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ErrorOccured (
+    TInt aError,
+    CSIPTransactionBase& aTransaction,
+    CSIPDialogAssocBase& /*aDialogAssoc*/)
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ErrorOccured 5 err=%d" ), aError);
+#endif
+
+    TInt retCode = aError == KErrSIPForbidden ? KErrAccessDenied : KErrCommsBreak;
+    TUint status = 0;
+
+    if ( aTransaction.IsSIPClientTransaction() )
+        {
+        // This is an initial SUBSCRIBE transaction that has failed.
+        CSimpleRequest* r2 = iCallback.GetRequest(
+            STATIC_CAST( CSIPClientTransaction&, aTransaction )); 
+        if ( !r2 )
+            {
+            // request not found
+            return;
+            }                               
+        // This instance is the initial transaction.
+        CSIPClientTransaction& trans = STATIC_CAST( CSIPClientTransaction&, aTransaction );
+        // ownership isn't transferred.
+        const CSIPResponseElements* elems = trans.ResponseElements();
+        if ( elems )
+            {
+            status = elems->StatusCode();
+            }
+        // convert SIP status code
+        if ( status >= KSimpleOK )
+            {
+            retCode = ConvertSipCode( status, EFalse, EFalse );
+            }
+        r2->SetStatus( status );
+        // update response method
+        r2->Request().SetResponseMethod( MSimpleEngineRequest::EUnknownResponse );
+        r2->Complete( retCode );
+        }
+    else
+        {
+        // Server transactions are not handled.
+        // An error in responding to NOTIFY request comes here.
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::ErrorOccured
+// This is not really needed because of engine does not use standalone CSIPRefesh
+// requests.
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::ErrorOccured (
+    TInt /*aError*/,
+    CSIPRefresh& /*aRefresh*/)
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: ErrorOccured 6" ));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// A SIP request outside a dialog has been received from the network.
+// CSimpleSipConnectionObserver::IncomingRequest
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::IncomingRequest(
+    CSIPServerTransaction* aTransaction )
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(
+        _L("CSimpleSipConnectionObserver::IncomingRequest" ) );
+#endif
+    
+    TRAP_IGNORE( DoIncomingRequestL( aTransaction ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::IncomingRequest
+// Dialog specific request from server..
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::IncomingRequest (
+    CSIPServerTransaction* aTransaction,
+    CSIPDialog& aDialog )
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: IncomingRequest (dialog)" ));
+#endif
+
+    TRAP_IGNORE( DoIncomingRequestL( aTransaction, aDialog ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::IncomingResponse
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::IncomingResponse(
+    CSIPClientTransaction& aTransaction)
+    {
+#ifdef _DEBUG
+    TInt status = aTransaction.ResponseElements()->StatusCode();
+    TSimpleLogger::Log(_L("SipConnectionObserver: IncomingResponse status=%d" ), status);
+#endif
+
+    DoIncomingResponse( aTransaction );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::IncomingResponse
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::IncomingResponse(
+    CSIPClientTransaction& aTransaction,
+    CSIPDialogAssocBase& aDialogAssoc)
+    {
+#ifdef _DEBUG
+    TInt status( KErrNone );
+    status = aTransaction.ResponseElements()->StatusCode();
+    TSimpleLogger::Log(_L("SipConnectionObserver: IncomingResponse (dialog) status=%d"), status);
+#endif
+
+    DoIncomingResponse( aTransaction, aDialogAssoc );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::IncomingResponse
+// Invite not supported by SIMPLE
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::IncomingResponse (
+    CSIPClientTransaction& /*aTransaction*/,
+    CSIPInviteDialogAssoc* /*aDialogAssoc*/)
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: IncomingResponse (invite)" ));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::InviteCompleted
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::InviteCompleted (
+    CSIPClientTransaction& /*aTransaction*/)
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: InviteCompleted" ));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::InviteCanceled
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::InviteCanceled (
+    CSIPServerTransaction& /*aTransaction*/)
+    {
+#ifdef _DEBUG
+    TSimpleLogger::Log(_L("SipConnectionObserver: InviteCanceled" ));
+#endif
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::DoHandleSrvrReqContentL
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::DoHandleSrvrReqContentL(
+    const CSIPMessageElements& aElems,
+    MSimpleEngineRequest& aR )
+    {
+    RStringF boundary = SIPStrings::Pool().OpenFStringL( KSimpleBoundary );
+    CleanupClosePushL( boundary );
+    RStringF start = SIPStrings::Pool().OpenFStringL( KSimpleStart );
+    CleanupClosePushL( start );
+    RStringF value;
+
+    // ownership of typeHeader is not transferred and it may be NULL.
+    const CSIPContentTypeHeader* typeHeader = aElems.ContentType();
+    if ( typeHeader )
+        {
+        // buffer ownership is transferred
+        HBufC8* buffer = typeHeader->ToTextValueL();
+        aR.SetResponseContentType( buffer );
+        aR.SetResponseDataL( aElems.Content() );
+        // set boundary
+        if ( typeHeader->HasParam( boundary ) )
+            {
+            value = typeHeader->ParamValue( boundary );
+            aR.SetResponseBoundaryL( value.DesC() );
+            }
+        // set start-content-id
+        if ( typeHeader->HasParam( start ) )
+            {
+            value = typeHeader->ParamValue( start );
+            aR.SetResponseStartL( value.DesC() );
+            }
+#ifdef _DEBUG
+        RFs myFs;
+        (void)myFs.Connect();
+        TSimpleLogger::Dump( aR.ResponseData(), myFs, 1 );
+        myFs.Close();
+#endif
+        }
+    CleanupStack::PopAndDestroy( &start );
+    CleanupStack::PopAndDestroy( &boundary );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::DoIncomingRequestL
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::DoIncomingRequestL(
+    CSIPServerTransaction* aTransaction )
+    {
+    const CSIPRequestElements* elems = aTransaction->RequestElements();
+    const CSIPContentTypeHeader* contentType = elems->MessageElements().
+        ContentType();
+    
+    if( KSimpleMediaType() == contentType->MediaType() &&
+        KSimpleMediaSubType() == contentType->MediaSubtype() )
+        {
+        const CSIPFromHeader* fromHeader = elems->FromHeader();
+        const TDesC8& content = elems->MessageElements().Content();
+        const TDesC8& user = fromHeader->SIPAddress().Uri8().Uri().
+            Extract( EUriUserinfo );
+        const TDesC8& host = fromHeader->SIPAddress().Uri8().Uri().
+            Extract( EUriHost );
+        
+        CleanupStack::PushL( aTransaction ); // CS: 1
+        
+        HBufC8* from = HBufC8::NewLC( user.Length() + KAt().Length() +
+            host.Length() ); // CS: 1
+        from->Des().Copy( user );
+        from->Des().Append( KAt() );
+        from->Des().Append( host );
+        
+        CSIPResponseElements* respElem = CSIPResponseElements::NewLC( // CS: 3
+            KSimpleOK, SIPStrings::StringF( SipStrConsts::EPhraseOk ) );
+        
+        // Use the transaction to send 200 OK
+        aTransaction->SendResponseL( respElem );
+        
+        CleanupStack::Pop( respElem );     // CS: 2
+
+        iCallback.HandleReceivedMessage( *from, content );
+        CleanupStack::PopAndDestroy( from ); // CS: 1
+        CleanupStack::Pop( aTransaction ); // CS: 0
+        }
+    
+    // We no longer need aTransaction. Just delete it.
+    delete aTransaction;
+    aTransaction = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::DoIncomingRequestL
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::DoIncomingRequestL (
+    CSIPServerTransaction* aTransaction,
+    CSIPDialog& aDialog )
+    {
+    // Ownership of aTransaction is transferred.
+    CleanupStack::PushL( aTransaction );
+
+    const CSIPRequestElements* reqE = aTransaction->RequestElements();
+    TPtrC8 method = reqE->Method().DesC();
+
+    // search the right request
+    CSimpleRequest* req = iCallback.GetdDialogRequest( aDialog );
+    if ( ! req )
+        {
+#ifdef _DEBUG
+        TSimpleLogger::Log(_L("SipConnectionObserver: IncomingRequest ERROR **" ));
+#endif
+
+        // This is unknown response, send response 481 in order to unsubscribe the dialog.
+        // See RFC3265
+        CSIPResponseElements* resE = CSIPResponseElements::NewLC( KSimple481,
+        SIPStrings::StringF( SipStrConsts::EPhraseCallTransactionDoesNotExist ) );
+        aTransaction->SendResponseL( resE );
+        // resE ownership is transferred
+        CleanupStack::Pop( resE );
+        CleanupStack::PopAndDestroy( aTransaction );
+        return;
+        }
+
+    // send a response to PA in NOTIFY
+    if ( aTransaction->ResponseAllowed()  )
+        {
+        if ( !method.CompareF( KSimpleNOTIFY ))
+            {
+            CSIPResponseElements* resE = CSIPResponseElements::NewLC( KSimpleOK,
+            SIPStrings::StringF( SipStrConsts::EPhraseOk ) );
+            aTransaction->SendResponseL( resE );
+            // resE ownership is transferred
+            CleanupStack::Pop( resE );
+#ifdef _DEBUG
+            TSimpleLogger::Log(_L("SipConnectionObserver: response sent *" ));
+#endif
+            }
+        }
+
+    // Fill the data of the request
+    const CSIPMessageElements& elems = reqE->MessageElements();
+    TRAPD( err, DoHandleSrvrReqContentL( elems, req->Request() ));
+    // Update expires when necessary
+    if ( !err )
+        {
+        // This completes the client request when needed
+        TRAP( err, iCallback.HandleDialogRequestL( elems, *req, method ));
+        }
+
+    CleanupStack::PopAndDestroy( aTransaction );
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::DoIncomingResponse
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::DoIncomingResponse(
+    CSIPClientTransaction& aTransaction)
+    {
+    const CSIPResponseElements* elems = aTransaction.ResponseElements();
+    // elems ownership is not transferred
+    TUint status = elems->StatusCode();
+
+    if ( status >= KSimpleOK )
+        {
+        // Final response received
+
+        // Search the right request
+        CSimpleRequest* req = iCallback.GetRequest( aTransaction );
+        
+        if ( req )
+            {
+            if( req->Match( CSimpleRequest::EReqSendIM ) )
+                {
+                TBool isModify = MSimpleEngineRequest::ESendIM ==
+                    req->Request().RequestType() ? ETrue : EFalse;
+                
+                // Get retry-after header value
+                TUint myRefresh = GetRetryAfter( elems );
+                req->SetRetryAfter( myRefresh );
+                
+                TInt retCode = ConvertSipCode( status, myRefresh ?
+                    ETrue: EFalse, isModify );
+                req->SetStatus( status );
+                req->Request().SetResponseMethod(
+                    MSimpleEngineRequest::EStatus );
+                TInt err( KErrNone );
+                
+                //  Complete the client request and change the request state
+                req->Complete( err ? err : retCode );
+                }
+            else if ( req->Match( CSimpleRequest::EReqPublish ) )
+                {
+                TBool isModify = req->Request().RequestType() ==
+                    MSimpleEngineRequest::EPublishModify ? ETrue : EFalse;
+                
+                // Get retry-after header value
+                TUint myRefresh = GetRetryAfter( elems );
+                req->SetRetryAfter( myRefresh );
+                
+                TInt retCode = ConvertSipCode( status, myRefresh ?
+                    ETrue: EFalse, isModify );
+                req->SetStatus( status );
+                req->Request().SetResponseMethod(
+                    MSimpleEngineRequest::EStatus );
+
+                // Make response to a client when necessary, i.e. response to
+                // the first PUBLISH.
+                // This handles STOP publish also, since it's
+                // actually a new publish request with expires=0 and ETag.
+                const CSIPMessageElements& mElems = elems->MessageElements();
+                TInt err( KErrNone );
+                TRAP( err, iCallback.HandlePublishRespL( mElems, req ) );
+                //  Complete the client request and change the request state
+                req->Complete( err ? err : retCode );
+                }
+            else
+                {
+                // This is unknown response
+                #ifdef _DEBUG
+                    TSimpleLogger::Log( _L("SipConnectionObserver: IncomingResponse IGNORED") );
+                #endif
+                }
+            }
+        else
+            {
+            // Request not found
+            #ifdef _DEBUG
+                TSimpleLogger::Log( _L("SipConnectionObserver: IncomingResponse IGNORED") );
+            #endif
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSimpleSipConnectionObserver::DoIncomingResponse
+// -----------------------------------------------------------------------------
+//
+void CSimpleSipConnectionObserver::DoIncomingResponse(
+    CSIPClientTransaction& aTransaction,
+    CSIPDialogAssocBase& /*aDialogAssoc*/)
+    {
+    // ownership of elems is not transferred.
+    const CSIPResponseElements* elems = aTransaction.ResponseElements();
+    if ( !elems )
+        {
+        return;
+        }
+    // elems ownership is not transferred
+    TUint status = elems->StatusCode();          
+
+    if ( status >= KSimpleOK )
+        {
+        // Final response received
+
+        // search the right request
+        CSimpleRequest* req = iCallback.GetRequest( aTransaction );
+        if ( ! req )
+            {
+#ifdef _DEBUG
+           TSimpleLogger::Log(_L("SipConnectionObserver: Unknown response **" ));
+#endif
+            // This is unknown response
+            return;
+            }
+
+        req->SetStatus( status );
+
+        // update response method
+        req->Request().SetResponseMethod( MSimpleEngineRequest::EStatus );
+        req->Complete( ConvertSipCode( status, EFalse, EFalse ) );
+
+        }
+    }
+
+// ----------------------------------------------------------
+// CSimpleSipConnectionObserver::ConvertSipCode
+// ----------------------------------------------------------
+//
+TInt CSimpleSipConnectionObserver::ConvertSipCode(
+    TUint aSip, TBool aRetryAfter, TBool aPublishModify )
+    {
+    // The SIP status codes are converted to engine error codes
+    if ( aSip < KSimpleOK )
+        {
+        return KErrNone;
+        }
+    if ( aPublishModify )
+        {
+        return ConvertSipModifyCode( aSip );
+        }
+    switch ( aSip )
+        {
+        case KSimpleOK: // 200
+            return KErrNone;
+        case KSimpleAccepted: // 202
+            return KSimpleErrPending;
+        case 404:  // Not Found
+            return KSimpleErrNotFound;
+        case 401: //  Unauthorized
+        case 407: //  Proxy Authentication Required
+            return KSimpleErrAuthorization;
+        case 302: // Moved Temporarily
+        case 408: // Request Timeout
+        case 412: // Conditional Request Failed, RFC3903
+        case 480: // Temporarily Unavailable
+        case 481: // Call/Transaction Does Not Exist
+        case 482: // Loop Detected
+        case 483: // Too Many Hops
+        case 486: // Busy Here
+        case 487: // Request Terminated (BYE/CANCEL) ** should not happen
+        case 491: // Request Pending
+        case 503: // Service Unavailable
+        case 504: // Server Time-out
+            return KSimpleErrTemporary;
+        case 413: // Request Entity Too Large
+            if ( aRetryAfter )
+                {
+                return KSimpleErrTemporary;
+                }
+            else
+                {
+                return KSimpleErrPermanent;
+                }
+        default:
+            return KSimpleErrPermanent;
+        }
+    }
+
+// ----------------------------------------------------------
+// CSimpleSipConnectionObserver::ConvertSipModifyCode
+// ----------------------------------------------------------
+//
+TInt CSimpleSipConnectionObserver::ConvertSipModifyCode( 
+    TUint aSip )
+    {
+    // The SIP status codes are converted to engine error codes
+    if ( aSip < KSimpleOK )
+        {
+        return KErrNone;
+        }
+    switch ( aSip )
+        {
+        case KSimpleOK: // 200
+            return KErrNone;
+        case KSimpleAccepted: // 202
+            return KSimpleErrPending;
+        case 404:  // Not Found
+            return KSimpleErrNotFound;
+        case 401: //  Unauthorized
+        case 407: //  Proxy Authentication Required
+            return KSimpleErrAuthorization;
+        case 400: // Bad request
+        case 408: // Request Time Out
+        case 415: // Unsupported media type
+        case 508: // Server Timed-Out
+            return KSimpleErrTemporary;
+        default:
+            return KSimpleErrPermanent;
+        }
+    }
+// ----------------------------------------------------------
+// CSimpleSipConnectionObserver::GetRetryAfter
+// ----------------------------------------------------------
+//
+TUint CSimpleSipConnectionObserver::GetRetryAfter( const CSIPResponseElements* aElems )
+    {
+    TUint ret(0);
+
+    // aElems must exist
+    const CSIPMessageElements& mes = aElems->MessageElements();
+
+    // Scan user headers
+    const RPointerArray<CSIPHeaderBase>& userHs = mes.UserHeaders();
+    for ( TInt i = 0; i < userHs.Count(); i++ )
+        {
+        const CSIPHeaderBase* header = userHs[ i ];
+        if ( header->Name() == SIPStrings::StringF( SipStrConsts::ERetryAfterHeader ))
+            {
+            CSIPRetryAfterHeader* retryH = (CSIPRetryAfterHeader*)header;
+            ret = retryH->RetryAfter();
+            }
+        else
+            {
+            // We ignore other than Retry-After header
+            }
+        }
+
+    return ret;
+    }