--- /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();
+ }
+ }