This release addresses the following issues:
1. The crash bug fix when receiving file
2. Now the sending is based on MSRP messages, there is no longer file receiving or sending. Client sends data as MSRP was designed.
3. Soma MSRP stack was created so that the client told the correct session-id, Symbian stack generated it by itself. This is not allowed, it was changed so that clients tell the session-id (same as used in SIP INVITE).
4. Unnecessary division of data to chunks removed when there is no need to interrupt sending. The message is sent in as few chunks as possible.
5. Stack can now receive files and chunks with ?unlimited? size. Old stack wrote the incoming data to memory and did not utilize disk space until the end of chunk was reached (large chunks from another client crashed it).
6. Now when writing the incoming data to file, it will take into account the byte-range header values. So, this complies with the RFC4975 requirements that stack must be able to handle chunks that come in any sequence.
7. Some buffering changes to outgoing/incoming data.
8. The outgoing data is now checked that it does not contain the created transaction-id before sending the data.
9. MSRP success reports are now implemented and tested against servers.
10. Progress report system fixed so progress is now visible on client (all the way to 100%).
11. Message Cancel receiving / Cancel sending now corrected and made to work as rfc4975 requires. (termination from sender and error code from receiver when cancelling).
12. Bug correction related to messages received not belonging to any session, old stack implementation did send error response, but after response was written it did give the buffer to client anyway. Now corrected.
// 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();
}
}