realtimenetprots/sipfw/SIP/sipapi/src/SipDialogImplementation.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/sipapi/src/SipDialogImplementation.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,1371 @@
+// Copyright (c) 2007-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:
+// Name          : SipDialogImplementation.cpp
+// Part of       : SIPAPI
+// Version       : SIP/6.0
+//
+
+
+
+#include <uri8.h>
+#include "siperr.h"
+#include "SipAssert.h"
+#include "SipDialogImplementation.h"
+#include "SipDialogAssocImplementation.h"
+#include "sipinvitedialogassoc.h"
+#include "sipsubscribedialogassoc.h"
+#include "sipdialogstate.h"
+#include "sipmessageelements.h"
+#include "siprequestelements.h"
+#include "sipresponseelements.h"
+#include "SipConnectionImplementation.h"
+#include "sipclientconnection.h"
+#include "sipinviteclienttransaction.h"
+#include "sipservertransaction.h"
+#include "sipregistrationcontext.h"
+#include "siprefresh.h"
+#include "sipaddress.h"
+#include "sipfromheader.h"
+#include "siptoheader.h"
+#include "sipcontactheader.h"
+#include "sipcallidheader.h"
+#include "sip.h"
+#include "SipImplementation.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+
+#ifdef CPPUNIT_TEST
+#include "TestCleanupStack.h"
+#endif
+
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::NewLC
+// -----------------------------------------------------------------------------
+//
+CSIPDialogImplementation* CSIPDialogImplementation::NewLC(
+						CSIPConnectionImplementation& aConnImplementation,
+						const MSIPRegistrationContext* aContext)
+	{
+	CSIPDialog* dialog = aContext ?
+		CSIPDialog::NewL(aConnImplementation, *aContext) :
+		CSIPDialog::NewL(aConnImplementation);	
+
+    CSIPDialogImplementation* self = &dialog->Implementation();
+    CleanupStack::PushL(self);
+    return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPDialogImplementation* CSIPDialogImplementation::NewL(
+						CSIPDialog* aDialog,
+						CSIPConnectionImplementation& aConnImplementation)
+    {
+    CSIPDialogImplementation* self =
+    	new (ELeave) CSIPDialogImplementation(aConnImplementation);
+    CleanupStack::PushL(self);
+    self->ConstructL(aDialog);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPDialogImplementation* CSIPDialogImplementation::NewL(
+							CSIPDialog* aDialog,
+							CSIPConnectionImplementation& aConnImplementation,
+                            const MSIPRegistrationContext& aContext)
+    {
+    CSIPDialogImplementation* self =
+    	new (ELeave) CSIPDialogImplementation(aConnImplementation, aContext);
+    CleanupStack::PushL(self);
+    self->ConstructL(aDialog);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CSIPDialogImplementation
+// -----------------------------------------------------------------------------
+//
+CSIPDialogImplementation::CSIPDialogImplementation(
+						CSIPConnectionImplementation& aConnImplementation) :
+    iConnection(&aConnImplementation)
+#ifdef CPPUNIT_TEST
+    , iDialogAssocs(1)
+#endif	
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CSIPDialogImplementation
+// -----------------------------------------------------------------------------
+//
+CSIPDialogImplementation::CSIPDialogImplementation(
+						CSIPConnectionImplementation& aConnImplementation,
+                       	const MSIPRegistrationContext& aContext) :
+    iConnection(&aConnImplementation),
+    iRegistration(&aContext)
+#ifdef CPPUNIT_TEST
+    , iDialogAssocs(1)
+#endif
+	, iStringPoolOpened(EFalse)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::ConstructL(CSIPDialog* aDialog)
+    {
+    CheckConnectionL();
+    iConnection->AddDialogL(*this);
+    iState = iConnection->InitialDialogStateL();
+    iDialog = aDialog;
+
+    SIPStrings::OpenL();
+    iStringPoolOpened = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::~CSIPDialogImplementation
+// -----------------------------------------------------------------------------
+//
+CSIPDialogImplementation::~CSIPDialogImplementation()
+    {
+    if (iConnection)
+        {        
+        iConnection->RemoveDialog(*this);
+        }
+
+    iDialogAssocs.Reset();
+
+	delete iDialog;
+    delete iFrom;
+    delete iTo;
+    delete iRemoteUri;
+    delete iContact;
+    delete iCallID;
+
+	if (iStringPoolOpened)
+		{
+    	SIPStrings::Close();
+		}
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::State
+// -----------------------------------------------------------------------------
+//
+CSIPDialog::TState CSIPDialogImplementation::State() const
+    {
+    __TEST_INVARIANT;
+    return iState ? iState->State() : CSIPDialog::ETerminated;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ChangeState
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::ChangeState(const CDialogState* aNewState)
+	{
+    __TEST_INVARIANT;
+
+	iState = aNewState;
+
+    __TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ConnectionLost
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::ConnectionLost()
+    {
+    __TEST_INVARIANT;
+
+    if (iState)
+        {        
+        iState->ConnectionLost(*this);
+        }
+    
+    for (TInt i = 0; i < iDialogAssocs.Count(); ++i)
+        {
+        iDialogAssocs[i]->Implementation().ConnectionLost();
+        }
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SIPDialogAssociations
+// -----------------------------------------------------------------------------
+//
+const RPointerArray<CSIPDialogAssocBase>&
+CSIPDialogImplementation::SIPDialogAssociations() const
+    {
+    __TEST_INVARIANT;
+    return iDialogAssocs;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::RegistrationContext
+// -----------------------------------------------------------------------------
+//
+const MSIPRegistrationContext*
+CSIPDialogImplementation::RegistrationContext() const
+    {
+    __TEST_INVARIANT;
+    return iRegistration;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::IsAssociated
+// -----------------------------------------------------------------------------
+//
+TBool
+CSIPDialogImplementation::IsAssociated(const CSIPDialogAssocBase& aAssoc) const
+    {
+    __TEST_INVARIANT;
+
+    for (TInt i = 0; i < iDialogAssocs.Count(); ++i)
+        {
+        if (iDialogAssocs[i] == &aAssoc)
+            {
+            return ETrue;
+            }
+        }
+
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::Connection
+// -----------------------------------------------------------------------------
+//
+CSIPConnection* CSIPDialogImplementation::Connection()
+    {    
+    return GetConnection();
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::Connection
+// -----------------------------------------------------------------------------
+//
+const CSIPConnection* CSIPDialogImplementation::Connection() const
+    {
+    return GetConnection();
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::GetConnection
+// -----------------------------------------------------------------------------
+//
+CSIPConnection* CSIPDialogImplementation::GetConnection() const
+	{
+	__TEST_INVARIANT;
+
+	CSIPConnection* conn = NULL;
+    if (iConnection)
+    	{
+    	TRAP_IGNORE((conn = &iConnection->SIPConnectionL()))
+    	}
+    return conn;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FromHeader
+// -----------------------------------------------------------------------------
+//
+const CSIPFromHeader& CSIPDialogImplementation::FromHeader() const
+    {
+    __TEST_INVARIANT;
+    return *iFrom;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ToHeader
+// -----------------------------------------------------------------------------
+//
+const CSIPToHeader& CSIPDialogImplementation::ToHeader() const
+    {
+    __TEST_INVARIANT;
+    return *iTo;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::RemoteURI
+// -----------------------------------------------------------------------------
+//
+const CUri8& CSIPDialogImplementation::RemoteURI() const
+    {
+    __ASSERT_DEBUG(iRemoteUri,
+    	User::Panic(_L("CSIPDlgImp:RemoteURI"), KErrNotFound));
+    return *iRemoteUri;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CallIdL
+// If Call-ID doesn't exist yet, application has asked it too early.
+// -----------------------------------------------------------------------------
+//
+const CSIPCallIDHeader& CSIPDialogImplementation::CallIdL() const
+	{
+	__ASSERT_ALWAYS(iCallID, User::Leave(KErrSIPInvalidDialogState));
+	return *iCallID;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::StoreCallIdL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::StoreCallIdL()
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(iDialogId != 0, KErrNotFound);	
+	CheckConnectionL();
+
+    CSIPCallIDHeader* tmp = iConnection->ClientConnectionL().CallIDL(iDialogId);
+	delete iCallID;
+	iCallID = tmp;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CopyCallIdL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::CopyCallIdL(
+    const CSIPDialogImplementation& aDialog)
+	{
+	__TEST_INVARIANT;	
+
+	CSIPCallIDHeader* tmp = 
+	    static_cast<CSIPCallIDHeader*>(aDialog.CallIdL().CloneL());
+	delete iCallID;
+	iCallID = tmp;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::operator==
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::operator==(
+						const CSIPDialogImplementation& aDialog) const
+    {
+    __TEST_INVARIANT;
+    return this == &aDialog ||
+    	   (iDialogId && aDialog.iDialogId && (iDialogId == aDialog.iDialogId));
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ReuseInitialRequestData
+// -----------------------------------------------------------------------------
+//
+TInt CSIPDialogImplementation::ReuseInitialRequestData()
+    {
+    TInt err = KErrSIPInvalidDialogState;
+    
+    if (iState && iState->State() == CSIPDialog::ETerminated &&
+        iConnection && iConnection->SIP() && iConnection->ClientConnection())
+        {
+        TUint32 originalRequestId = iInitialRequestId;
+        iInitialRequestId = 0;
+        const CDialogState* originalState = iState;
+        iState = iConnection->SIP()->Implementation().InitialDialogState();
+        err = iConnection->ClientConnection()->ResetDialogState(iDialogId);
+        if (err != KErrNone)
+            {
+            // Rollback to the original state
+            iInitialRequestId = originalRequestId;
+            iState = originalState;
+            }
+        else
+            {
+            iTo->DeleteParam(SIPStrings::StringF(SipStrConsts::ETag));
+            }
+        }       
+    
+    return err;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::Dialog
+// Don't use invariant here.
+// -----------------------------------------------------------------------------
+//
+CSIPDialog& CSIPDialogImplementation::Dialog()
+	{
+	__ASSERT_DEBUG(iDialog, User::Panic(_L("CSIPDlgImp:Dialog"), KErrNotFound));
+	return *iDialog;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::IncomingResponseL
+// -----------------------------------------------------------------------------
+//
+TBool
+CSIPDialogImplementation::IncomingResponseL(CSIPResponseElements* aElements,
+				                            TUint32 aRequestId,
+		                                    TUint32 aDialogId,
+		                                    CConnectionCallback& aCallback)
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_LEAVE(aElements != NULL, KErrArgument);
+
+    if (iState)
+        {
+        return iState->IncomingResponseL(*this,
+                                         aElements,
+		                                 aRequestId,
+                                         aDialogId,
+                                         aCallback);
+        }
+    delete aElements;
+    return EFalse;    
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::IncomingResponseL
+// -----------------------------------------------------------------------------
+//
+TBool
+CSIPDialogImplementation::IncomingResponseL(CSIPResponseElements* aElements,
+				                            TUint32 aRequestId,
+		                                    TUint32 aRefreshId,
+							                TUint32 aDialogId,
+		                                    CConnectionCallback& aCallback)                                   
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_LEAVE(aElements != NULL, KErrArgument);
+
+    if (iState)
+        {
+        return iState->IncomingResponseL(*this,
+                                         aElements,
+		                                 aRequestId,
+                                         aRefreshId,
+                                         aDialogId,
+                                         aCallback);
+        }
+    delete aElements;
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::IncomingRequest
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::IncomingRequestL(
+									CSIPServerTransaction* aTransaction,
+                                   	CConnectionCallback& aCallback)                                  
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_LEAVE(aTransaction != NULL, KErrArgument);
+
+    if (iState)
+        {
+        return iState->IncomingRequestL(*this, aTransaction, aCallback);
+        }
+    delete aTransaction;
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ErrorOccured
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::ErrorOccured(TInt aError,
+				                             TUint32 aRequestId,
+				                             CConnectionCallback& aCallback)
+    {
+    __TEST_INVARIANT;
+    return iState &&
+    	   iState->ErrorOccured(*this, aError, aRequestId, aCallback);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ErrorOccured
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::ErrorOccured(TInt aError,             
+				                             TUint32 aRefreshId,
+				                             TUint32 aRequestId,
+				                             CConnectionCallback& aCallback)
+    {
+    __TEST_INVARIANT;
+    return iState &&
+    	iState->ErrorOccured(*this, aError, aRefreshId, aRequestId, aCallback);        
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::DialogId
+// Don't use invariant here.
+// -----------------------------------------------------------------------------
+//
+TUint32 CSIPDialogImplementation::DialogId() const
+    {    
+    return iDialogId;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SetDialogId
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::SetDialogId(TUint32 aDialogId)
+    {
+    __TEST_INVARIANT;
+
+    iDialogId = aDialogId;
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FindTransaction
+// -----------------------------------------------------------------------------
+//
+CSIPTransactionBase*
+CSIPDialogImplementation::FindTransaction(TUint32 aRequestId) const
+    {
+    __TEST_INVARIANT;
+
+    CSIPTransactionBase* ta = NULL;
+    for (TInt i = 0; i < iDialogAssocs.Count() && !ta; ++i)
+        {
+        ta = iDialogAssocs[i]->Implementation().FindTransaction(aRequestId);
+        }
+
+    return ta;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FindTransactionAndAssoc
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::FindTransactionAndAssoc(TUint32 aRequestId,
+                                    CSIPTransactionBase** aTransaction,
+                                    CSIPDialogAssocBase** aAssoc) const
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_RETURN_VALUE(aTransaction && aAssoc, EFalse);
+
+    CSIPTransactionBase* ta = NULL;
+    for (TInt i = 0; i < iDialogAssocs.Count(); ++i)
+        {
+        ta = iDialogAssocs[i]->Implementation().FindTransaction(aRequestId);
+        if (ta)
+            {
+            *aTransaction = ta;
+            *aAssoc = iDialogAssocs[i];
+            return ETrue;
+            }
+        }
+
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FindAssocAndRefreshL
+// Search with aRequestId. If not found, search with aRefreshId.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::FindAssocAndRefreshL(TUint32 aRequestId,
+                                  TUint32 aRefreshId,
+                                  CSIPDialogAssocBase** aAssoc,
+                                  CSIPRefresh** aRefresh,
+                                  CSIPTransactionBase** aTransaction) const
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_RETURN_VALUE(aAssoc && aRefresh && aTransaction, EFalse);
+
+    if (FindTransactionAndAssoc(aRequestId, aTransaction, aAssoc))
+        {
+        *aRefresh =
+            static_cast<CSIPClientTransaction*>(*aTransaction)->Refresh();
+
+        //Refresh must exist now
+        __ASSERT_DEBUG(*aRefresh,
+		    User::Panic(_L("CSIPDlgImp:FindAssocAndRfr"), KErrNotFound));
+        if (*aRefresh)
+            {
+            return ETrue;
+            }
+        }
+
+	if (FindAssocAndRefresh(aRefreshId, aAssoc, aRefresh))
+		{
+		CSIPTransactionBase* ta = (*aRefresh)->Transaction();
+		if (ta)
+			{
+			CSIPTransactionBase::TState state = ta->StateL();
+			//If transaction has received a final response, it is the initial
+			//transaction creating the refresh. Ignore EConfirmed state, as only
+			//INVITE _server_ transaction has it.
+			if (state != CSIPTransactionBase::ECompleted &&
+				state != CSIPTransactionBase::ETerminated)
+				{
+				*aTransaction = ta;
+				}
+			}
+		return ETrue;
+		}
+	return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FindAssocAndRefresh
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::FindAssocAndRefresh(TUint32 aRefreshId,
+                                      CSIPDialogAssocBase** aAssoc,
+                                      CSIPRefresh** aRefresh) const
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_RETURN_VALUE(aAssoc && aRefresh, EFalse);
+	
+    CSIPRefresh* refresh = NULL;
+    for (TInt i = 0; i < iDialogAssocs.Count(); ++i)
+        {
+        refresh = iDialogAssocs[i]->FindRefresh(aRefreshId);
+        if (refresh)
+            {
+            *aAssoc = iDialogAssocs[i];
+            *aRefresh = refresh;
+            return ETrue;
+            }
+        }
+
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FindRefresh
+// -----------------------------------------------------------------------------
+//  
+CSIPRefresh* CSIPDialogImplementation::FindRefresh(
+    TUint32 aRequestId,
+    TUint32 aRefreshId) const
+    {
+    CSIPDialogAssocBase* dummyAssoc = NULL;
+    CSIPRefresh* refresh = NULL;
+    CSIPTransactionBase* dummyTransaction;
+    if (FindTransactionAndAssoc(aRequestId, &dummyTransaction, &dummyAssoc))
+        {
+        return static_cast<CSIPClientTransaction*>(dummyTransaction)->Refresh();
+        }
+    FindAssocAndRefresh(aRefreshId,&dummyAssoc,&refresh);
+    return refresh;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendNonTargetRefreshRequestL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction* CSIPDialogImplementation::SendNonTargetRefreshRequestL(
+										CSIPDialogAssocImplementation& aAssoc,
+                                        RStringF aMethod,
+                                        CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;
+    return StateL().SendNonTargetRefreshRequestL(*this,
+                                                 aAssoc,
+                                                 aMethod,
+                                                 aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendInviteL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendInviteL(CSIPInviteDialogAssoc& aAssoc,
+                        			  CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;    
+    return StateL().SendInviteL(*this, aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendPrackL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendPrackL(CSIPInviteDialogAssoc& aAssoc,
+                       				 CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;    
+    return StateL().SendPrackL(aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendUpdateL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendUpdateL(CSIPInviteDialogAssoc& aAssoc,
+                        			  CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;
+    return StateL().SendUpdateL(aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendAckL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::SendAckL(CSIPInviteDialogAssoc& aAssoc,
+			                       const CSIPClientTransaction& aTransaction,
+			                       CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;
+
+    StateL().SendAckL(aAssoc, aTransaction, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendSubscribeL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendSubscribeL(CSIPSubscribeDialogAssoc& aAssoc,
+			                             CSIPMessageElements* aElements,
+			                             CSIPRefresh* aRefresh) const
+    {
+    __TEST_INVARIANT;
+    return StateL().SendSubscribeL(*this, aAssoc, aElements, aRefresh);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::UpdateL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::UpdateL(CSIPSubscribeDialogAssoc& aAssoc,
+			                      CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;
+    return StateL().UpdateL(*this, aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendUnsubscribeL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendUnsubscribeL(CSIPSubscribeDialogAssoc& aAssoc,
+                             			   CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;
+    return StateL().SendUnsubscribeL(aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendByeL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendByeL(CSIPInviteDialogAssoc& aAssoc,
+                     			   CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;    
+    return StateL().SendByeL(aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendCancelL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendCancelL(TUint32 aRequestId) const
+    {
+    __TEST_INVARIANT;
+
+    CSIPTransactionBase* dummyTa = NULL;
+    CSIPDialogAssocBase* assoc = NULL;
+	__ASSERT_ALWAYS(FindTransactionAndAssoc(aRequestId, &dummyTa, &assoc),
+					User::Leave(KErrSIPInvalidTransactionState));
+	__ASSERT_ALWAYS(assoc->Type() == SIPStrings::StringF(SipStrConsts::EInvite),
+					User::Leave(KErrSIPInvalidTransactionState));
+    return static_cast<CSIPInviteDialogAssoc*>
+    	(assoc)->DoSendCancelL(aRequestId);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendNotifyL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendNotifyL(CSIPNotifyDialogAssoc& aAssoc,
+                        			  CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;    
+    return StateL().SendNotifyL(aAssoc, aElements);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendReferL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendReferL(CSIPReferDialogAssoc& aAssoc,
+                       				 CSIPMessageElements* aElements) const
+   	{
+   	__TEST_INVARIANT;    
+    return StateL().SendReferL(*this, aAssoc, aElements);
+   	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendResponseL
+// -----------------------------------------------------------------------------
+//
+void
+CSIPDialogImplementation::SendResponseL(const CSIPResponseElements& aElements,
+							            TUint32 aRequestId,
+			                            TBool aAffectsDialogState,
+			                            TBool aTargetRefresh)
+    {
+    __TEST_INVARIANT;
+
+    StateL().SendResponseL(*this,
+                           aElements,
+                           aRequestId,
+                           aAffectsDialogState,
+                           aTargetRefresh);
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendRequestInDialogL
+// CSIPClientConnection checks that connection is active.
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction* CSIPDialogImplementation::SendRequestInDialogL(
+                                        CSIPDialogAssocImplementation& aAssoc,
+                                        RStringF aMethod,
+                                        CSIPMessageElements* aElements) const
+    {
+    __TEST_INVARIANT;
+    CheckConnectionL();
+
+	CSIPClientTransaction* ta = CreateClientTransactionL(aMethod, aAssoc, NULL);
+    CleanupStack::PushL(ta);
+
+    TUint32 requestId(0);
+    TUint32 dummyRefreshId(0); // Not used for non-refreshed requests
+    iConnection->ClientConnectionL().SendRequestWithinDialogL(iDialogId,
+							  requestId,
+							  dummyRefreshId,
+                              aMethod,
+							  aElements,
+                              CSIPTransactionBase::IsTargetRefresh(aMethod));
+	CleanupStack::Pop(ta);
+    ta->SetRequestId(requestId);
+
+    delete aElements;
+    return ta;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CreateClientTransactionL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::CreateClientTransactionL(RStringF aType,                                     
+                                     CSIPDialogAssocImplementation& aAssoc,                                     
+                                     CSIPRefresh* aRefresh) const
+    {
+    __TEST_INVARIANT;
+
+    if (aType == SIPStrings::StringF(SipStrConsts::EInvite))
+        {
+        __SIP_ASSERT_LEAVE(!aRefresh, KErrArgument);
+        return CSIPInviteClientTransaction::NewL(aAssoc);
+        }
+
+    return CSIPClientTransaction::NewL(aType, aAssoc, aRefresh);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::AddAssocL
+// Needs aType as aAssoc.Type can't be used as aAssoc::iImplementation is NULL
+// (CSIPDialogAssocImplementation::NewL hasn't returned yet). No invariant here.
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::AddAssocL(CSIPDialogAssocBase& aAssoc,
+										 RStringF aType)
+    {
+    __ASSERT_ALWAYS(iDialogAssocs.Find(&aAssoc) == KErrNotFound &&
+        			(aType != SIPStrings::StringF(SipStrConsts::EInvite) ||
+         			!HasInviteAssoc()), User::Leave(KErrAlreadyExists));    
+    iDialogAssocs.AppendL(&aAssoc);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::RemoveAssoc
+// CDeleteMgr isn't used, as it'd be in CSIP, which is not always accessible as
+// CSIPConnection and/or CSIP may've been deleted. Don't use invariant here.
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::RemoveAssoc(const CSIPDialogAssocBase& aAssoc)
+    {
+    //Returns KErrNotFound e.g. if CSIPDialogAssocImplementation::ConstructL
+    //runs out of memory.
+    TInt pos = iDialogAssocs.Find(&aAssoc);
+    if (pos != KErrNotFound)
+        {
+	    iDialogAssocs.Remove(pos);
+
+	    if (iDialogAssocs.Count() == 0)
+	        {
+	        delete this;
+	        }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::HasInviteAssoc
+// Don't use invariant here.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::HasInviteAssoc() const
+    {
+    for (TInt i = 0; i < iDialogAssocs.Count(); ++i)
+        {
+        if (iDialogAssocs[i]->Type() ==
+        	SIPStrings::StringF(SipStrConsts::EInvite))
+            {
+            return ETrue;
+            }
+        }
+
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ConnectionDeleted
+// As CSIPClientConnection is deleted, SIP client terminates all dialogs. So
+// TerminateDialog is not called here. Clear iState, as CSIPDialogImplementation
+// won't get noticed, when the CSIP owning the dialog states, is deleted.
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::ConnectionDeleted()
+    {
+    __TEST_INVARIANT;
+
+    iState = NULL;
+    iConnection = NULL;
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CheckConnectionL
+// Don't use invariant here.
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::CheckConnectionL() const
+    {
+    __ASSERT_ALWAYS(iConnection, User::Leave(KErrSIPResourceNotAvailable));
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::StateL
+// -----------------------------------------------------------------------------
+//
+const CDialogState& CSIPDialogImplementation::StateL() const
+    {
+    __TEST_INVARIANT;
+    __ASSERT_ALWAYS(iState != NULL, User::Leave(KErrSIPResourceNotAvailable));
+    return *iState;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::UpdateState
+// -----------------------------------------------------------------------------
+//
+void
+CSIPDialogImplementation::UpdateState(const CSIPClientTransaction& aTransaction,
+			                          const CDialogState& aEarly,
+			                          const CDialogState& aConfirmed,
+			                          const CDialogState& aTerminated)
+    {
+    __TEST_INVARIANT;
+
+    const CSIPResponseElements* elem = aTransaction.ResponseElements();
+    __SIP_ASSERT_RETURN(elem != NULL, KErrArgument);
+
+	TUint status = elem->StatusCode();
+    if (aTransaction.AffectsDialogState())
+        {
+        if (status >= 300)
+            {
+            ChangeState(&aTerminated);
+            }
+        else if (status >= 200)
+            {
+            ChangeState(&aConfirmed);
+            }
+        else
+            {
+            if (status > 100 && State() == CSIPDialog::EInit)
+                {
+                ChangeState(&aEarly);
+                }
+            }
+        }
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::CheckNoTransactionExistsL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::CheckNoTransactionExistsL() const
+    {
+    __TEST_INVARIANT;    
+    __ASSERT_ALWAYS(!iInitialRequestId, User::Leave(KErrSIPInvalidDialogState));
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::InitialTransactionStarted
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::InitialTransactionStarted(TUint32 aRequestId)
+    {
+    __TEST_INVARIANT;
+    __SIP_ASSERT_RETURN(aRequestId, KErrArgument);
+    __SIP_ASSERT_RETURN(!iInitialRequestId, KErrAlreadyExists);
+
+	iInitialRequestId = aRequestId;
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::InitialTransactionStarted
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::InitialTransactionStarted(
+											CSIPTransactionBase& aTransaction)
+    {
+    __TEST_INVARIANT;
+
+    InitialTransactionStarted(aTransaction.RequestId());
+    aTransaction.SetAffectsDialogState();
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::DoesNotifyConfirmDialog
+// -----------------------------------------------------------------------------
+//
+TBool CSIPDialogImplementation::DoesNotifyConfirmDialog() const
+	{
+	__TEST_INVARIANT;
+
+	if (iInitialRequestId)
+		{
+		CSIPTransactionBase* ta = FindTransaction(iInitialRequestId);
+		return (ta &&
+				(ta->Type() == SIPStrings::StringF(SipStrConsts::ESubscribe) ||
+				 ta->Type() == SIPStrings::StringF(SipStrConsts::ERefer)) &&
+				ta->IsSIPClientTransaction());
+		}
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ChangeRefreshesToActive
+// Adding a virtual function CSIPDialogAssocBase::ChangeRefreshToActive breaks
+// BC, so an ugly way like this is used.
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::ChangeRefreshesToActive() const
+	{
+	__TEST_INVARIANT;
+
+    for (TInt i = 0; i < iDialogAssocs.Count(); ++i)
+        {
+        if (iDialogAssocs[i]->Type() ==
+        	SIPStrings::StringF(SipStrConsts::ESubscribe))
+        	{
+        	const CSIPRefresh* rfr = static_cast<CSIPSubscribeDialogAssoc*>
+        		(iDialogAssocs[i])->SIPRefresh();
+			if (rfr && rfr->State() == CSIPRefresh::EInactive)
+				{
+				//Get a modifiable pointer to the refresh
+				CSIPRefresh* refresh =
+					iDialogAssocs[i]->FindRefresh(rfr->RefreshId());
+				__SIP_ASSERT_RETURN(refresh != NULL, KErrNotFound);
+				refresh->ChangeState(CSIPRefresh::EActive);
+				}
+        	}
+        }
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::UpdateRemoteTargetL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::UpdateRemoteTargetL(RStringF aMethod,
+									 const CSIPMessageElements& aElements)
+	{
+	__TEST_INVARIANT;
+
+	if (CSIPTransactionBase::IsTargetRefresh(aMethod))
+		{
+		CUri8* uri = GetUriFromContactL(aElements);
+		if (uri)
+			{
+			delete iRemoteUri;
+			iRemoteUri = uri;
+			}
+		}
+	__TEST_INVARIANT;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SetHeadersL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::SetHeadersL(CSIPFromHeader* aFrom,
+			                               CSIPToHeader* aTo,
+			                               CUri8* aRemoteUri,
+			                               CSIPContactHeader* aContact)
+    {
+    __SIP_ASSERT_LEAVE(aRemoteUri, KErrArgument);
+    __SIP_ASSERT_LEAVE(!iFrom && !iTo && !iRemoteUri && !iContact,
+                       KErrAlreadyExists);
+   	if (!aFrom)
+        {
+        __SIP_ASSERT_LEAVE(iRegistration != NULL, KErrNotFound);
+        iFrom =
+            iConnection->ClientConnectionL().AorL(iRegistration->ContextId());
+        iFrom->DeleteParam(SIPStrings::StringF(SipStrConsts::ETag));
+        }
+
+	if (aTo)
+		{
+		iTo = aTo;
+		}
+	else
+		{
+		iTo = CSIPToHeader::DecodeL(aRemoteUri->Uri().UriDes());
+		}
+
+    if (aFrom)
+        {
+        iFrom = aFrom;
+        }
+
+	iRemoteUri = aRemoteUri;
+    iContact = aContact;
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::InitialTransactionReceivedL
+// Request must have exactly one Contact header. Dialog subsystem hasn't checked
+// that as request came outside dialog. iRemoteUri is set with the Contact URI.
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::InitialTransactionReceivedL(
+										CSIPServerTransaction& aTransaction)
+    {
+    __SIP_ASSERT_LEAVE(!iFrom && !iTo && !iRemoteUri, KErrAlreadyExists);
+
+	const CSIPRequestElements* elem = aTransaction.RequestElements();
+    __SIP_ASSERT_LEAVE(elem != NULL, KErrArgument);
+
+	//From includes the remote tag, if remote filled it
+	iFrom = CSIPFromHeader::NewL(*elem->FromHeader());
+    iTo = CSIPToHeader::NewL(*elem->ToHeader());
+	iRemoteUri = GetUriFromContactL(elem->MessageElements());
+	InitialTransactionStarted(aTransaction);
+
+	if (!iRemoteUri)
+		{
+		CSIPResponseElements* resp = CSIPResponseElements::NewLC(400,
+        	SIPStrings::StringF(SipStrConsts::EPhraseBadRequest));
+        aTransaction.SendResponseL(resp);
+        CleanupStack::Pop(resp);
+        User::Leave(KErrSIPMalformedMessage);
+		}
+
+    __TEST_INVARIANT;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::SendDialogCreatingRequestL
+// -----------------------------------------------------------------------------
+//
+CSIPClientTransaction*
+CSIPDialogImplementation::SendDialogCreatingRequestL(
+									   CSIPDialogAssocImplementation& aAssoc,
+									   CSIPMessageElements* aElements,
+									   CSIPRefresh* aRefresh)
+	{
+	__TEST_INVARIANT;
+	CheckConnectionL();
+
+	CSIPClientTransaction* ta =
+		CreateClientTransactionL(aAssoc.Type(), aAssoc, aRefresh);
+    CleanupStack::PushL(ta);
+
+    TUint32 requestId(0);
+	TUint32 refreshId(0);
+	iConnection->ClientConnectionL().SendRequestAndCreateDialogL(requestId,
+                         refreshId,
+					     iDialogId,
+						 aAssoc.Type(),
+						 *iRemoteUri,
+						 iFrom,
+						 aElements,
+                     	 iTo,
+                     	 RegistrationId(),
+                     	 (aRefresh != NULL));
+	ta->SetRequestId(requestId);
+	InitialTransactionStarted(*ta);
+	StoreCallIdL();
+	FillLocalTagL(ETrue);
+	CleanupStack::Pop(ta);
+
+	if (aRefresh)
+        {
+        aRefresh->SetRefreshIdIfEmpty(refreshId);
+        }
+	delete aElements;
+
+    //Contact can now be freed
+    delete iContact;
+    iContact = NULL;
+
+	return ta;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::ContactHeader
+// -----------------------------------------------------------------------------
+//
+const CSIPContactHeader* CSIPDialogImplementation::ContactHeader() const
+	{
+	__TEST_INVARIANT;
+	return iContact;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::GetUriFromContactL
+// Don't use invariant here.
+// -----------------------------------------------------------------------------
+//
+CUri8* CSIPDialogImplementation::GetUriFromContactL(
+								const CSIPMessageElements& aElements) const
+	{
+	CUri8* uri = NULL;
+	
+	RStringF contact = SIPStrings::StringF(SipStrConsts::EContactHeader);
+	if (aElements.UserHeaderCount(contact) == 1)
+		{
+		RPointerArray<CSIPHeaderBase> headers = aElements.UserHeadersL(contact);
+		CleanupClosePushL(headers);
+
+		CSIPContactHeader* contactHeader =
+			static_cast<CSIPContactHeader*>(headers[0]);
+
+		const CSIPAddress* addr = contactHeader->SIPAddress();
+		if (addr)
+			{
+			uri = CUri8::NewL(addr->Uri8().Uri());
+			}
+	    CleanupStack::PopAndDestroy(); //headers
+		}
+	return uri;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FillLocalTagL
+// -----------------------------------------------------------------------------
+//
+void CSIPDialogImplementation::FillLocalTagL(TBool aClientInitiatedDialog) const
+	{
+	__TEST_INVARIANT;
+	__SIP_ASSERT_LEAVE(iDialogId != 0, KErrNotFound);
+
+	RStringF tag = SIPStrings::StringF(SipStrConsts::ETag);
+	CSIPFromToHeaderBase* header = iFrom;
+	if (!aClientInitiatedDialog)
+		{		
+		header = iTo;
+		}
+
+	if (!header->HasParam(tag))
+		{
+		CheckConnectionL();
+		RStringF localTag =
+			iConnection->ClientConnectionL().LocalTagL(iDialogId);
+		CleanupClosePushL(localTag);
+		header->SetParamL(tag, localTag);
+		CleanupStack::PopAndDestroy(); //localTag
+		}	
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::FillRemoteTagL
+// -----------------------------------------------------------------------------
+//
+void
+CSIPDialogImplementation::FillRemoteTagL(const CSIPToHeader& aToHeader) const
+	{
+	__TEST_INVARIANT;
+
+	RStringF tag = SIPStrings::StringF(SipStrConsts::ETag);
+	if (aToHeader.HasParam(tag))
+		{
+		iTo->SetParamL(tag, aToHeader.ParamValue(tag));
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::RegistrationId
+// -----------------------------------------------------------------------------
+//
+TUint32 CSIPDialogImplementation::RegistrationId() const
+    {
+    return (iRegistration ? iRegistration->ContextId() : 0);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPDialogImplementation::__DbgTestInvariant
+// iState is NULL if CSIP has been deleted.
+// Don't check iRemoteUri, as 400 response is sent when missing iRemoteUri from
+// an incoming request that creates a dialog.
+// -----------------------------------------------------------------------------
+//
+
+void CSIPDialogImplementation::__DbgTestInvariant() const
+	{
+	if (!iDialog || !iFrom || !iTo)
+		{
+		User::Invariant();
+		}
+	}