diff -r f742655b05bf -r d38647835c2e sipvoipprovider/svptransfer/src/svptransferstatecontext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sipvoipprovider/svptransfer/src/svptransferstatecontext.cpp Wed Sep 01 12:29:57 2010 +0100 @@ -0,0 +1,1475 @@ +/* +* Copyright (c) 2006-2010 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: Transfer state context class for state machine +* +*/ + +#include // TMceTransactionDataContainer +#include // CMceRefer, CMceOutRefer +#include // CMceEvent +#include +#include +#include +#include + +#include "svpsessionbase.h" +#include "svptransferstatecontext.h" +#include "svptransferstatebase.h" +#include "svptransferidlestate.h" +#include "svptransferpendingstate.h" +#include "svptransferacceptedstate.h" +#include "svptransferterminatingstate.h" +#include "svptransferterminatedstate.h" +#include "svptransferobserver.h" +#include "svplogger.h" +#include "svpuriparser.h" +#include "svpconsts.h" +#include "svpholdcontext.h" +#include "svpholdcontroller.h" +#include "svpcleanupresetanddestroy.h" + + +// --------------------------------------------------------------------------- +// C++ default constructor can NOT contain any code, that might leave. +// --------------------------------------------------------------------------- +// +CSVPTransferStateContext::CSVPTransferStateContext( + CMceSession* aMceSession, + CSVPSessionBase* aSVPSession, + TMceTransactionDataContainer& aContainer, + MSVPTransferObserver& aObserver ) : + iMceSession( aMceSession ), + iSVPSession( aSVPSession ), + iTargetSession( NULL ), + iContainer( aContainer ), + iTransferObserver( aObserver ), + iStates( NULL ), + iCurrentState( NULL ), + iMceRefer( NULL ), + iMceEvent( NULL ), + iAttended( EFalse ), + iIncomingReferTo ( NULL ), + iIncomingReferredBy ( NULL ), + iIncomingReplaces (NULL) + { + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::ConstructL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::ConstructL() + { + SVPDEBUG1( "CSVPTransferStateContext::ConstructL In" ) + + // Create the transfer states in the state array. + InitializeStateArrayL(); + + // Initialize idle state to current state. Note, that it is not + // applied yet. + SetCurrentStateL( KSVPTransferIdleStateIndex ); + + SVPDEBUG1( "CSVPTransferStateContext::ConstructL Out" ) + } + +// ----------------------------------------------------------------------------- +// CSVPTransferStateContext::NewL +// ----------------------------------------------------------------------------- +CSVPTransferStateContext* CSVPTransferStateContext::NewL( + CMceSession* aMceSession, + CSVPSessionBase* aSVPSession, + TMceTransactionDataContainer& aContainer, + MSVPTransferObserver& aObserver ) + { + CSVPTransferStateContext* self = new ( ELeave ) CSVPTransferStateContext( + aMceSession, + aSVPSession, + aContainer, + aObserver ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::~CSVPTransferStateContext +// --------------------------------------------------------------------------- +// +CSVPTransferStateContext::~CSVPTransferStateContext() + { + SVPDEBUG1( "CSVPTransferStateContext::~CSVPTransferStateContext In" ) + + if ( iStates ) + { + iStates->ResetAndDestroy(); + iStates->Close(); + delete iStates; + } + + delete iMceEvent; + delete iMceRefer; + delete iIncomingReferTo; + delete iIncomingReferredBy; + delete iIncomingReplaces; + + SVPDEBUG1( "CSVPTransferStateContext::~CSVPTransferStateContext Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetCurrentStateL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetCurrentStateL( + TSVPTransferStateIndex aStateIndex ) + { + // Check, if the transition is valid + if ( !IsStateTransitionAccepted( aStateIndex ) ) + { + SVPDEBUG2( "CSVPTransferStateContext::SetCurrentStateL: STATE ERROR stateindex: %i", aStateIndex ) + User::Leave( KSVPErrTransferStateError ); + } + else + { + iCurrentState = ( *iStates )[ aStateIndex ]; + iCurrentState->Enter( *this ); + } + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CurrentState +// --------------------------------------------------------------------------- +// +TSVPTransferStateIndex CSVPTransferStateContext::CurrentState() const + { + return iStates->Find( iCurrentState ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::ApplyCurrentStateL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::ApplyCurrentStateL() + { + iCurrentState->ApplyL( *this ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::TransferObserver +// --------------------------------------------------------------------------- +// +MSVPTransferObserver& CSVPTransferStateContext::TransferObserver() + { + return iTransferObserver; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetMceSessionObject +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetMceSessionObject( CMceSession* aSession ) + { + iMceSession = aSession; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::MceSessionObject +// --------------------------------------------------------------------------- +// +CMceSession* CSVPTransferStateContext::MceSessionObject() + { + return iMceSession; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetMceRefer +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetMceRefer( CMceRefer* aRefer ) + { + if ( iMceRefer != aRefer ) + { + delete iMceRefer; + iMceRefer = aRefer; + } + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::MceRefer +// --------------------------------------------------------------------------- +// +CMceRefer* CSVPTransferStateContext::MceRefer() + { + return iMceRefer; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetAttended +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetAttended( const TBool aAttended ) + { + iAttended = aAttended; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::IsAttended +// --------------------------------------------------------------------------- +// +TBool CSVPTransferStateContext::IsAttended() + { + return iAttended; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckIsSessionRemoteHold +// --------------------------------------------------------------------------- +// +TBool CSVPTransferStateContext::CheckIsSessionRemoteHold() + { + SVPDEBUG1( "CSVPTransferStateContext::CheckIsSessionRemoteHold In" ) + + TBool ret = EFalse; + + if ( iSVPSession->HasHoldController() && + MCCPCallObserver::ECCPStateDisconnecting != iSVPSession->State() ) + { + SVPDEBUG1("CSVPTransferStateContext::CheckIsSessionRemoteHold, Check hold state" ) + + if ( ESVPOnHold == iSVPSession->HoldController().HoldState() && + ESVPRemoteHold == iSVPSession->HoldController().HoldRequest() ) + { + // Session is remote holded -> Snom/EyeBeam as unattended transferer case. + SVPDEBUG1( "CSVPTransferStateContext:CheckIsSessionRemoteHold, transferer is Snom, EyeBeam or similar" ) + ret = ETrue; + } + } + + SVPDEBUG2("CSVPTransferStateContext::CheckIsSessionRemoteHold Out return: %d",ret ) + return ret; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetTransferDataL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetTransferDataL( + CDesC8Array* aUserAgentHeaders, TInt aSecureStatus ) + { + SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL In" ) + + if ( aUserAgentHeaders ) + { + if ( iIncomingReplaces && IsAttended() ) + { + SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL: Add replaces header" ) + // fetch "replaces:" string + HBufC* replacesStringHeap16 = IncomingReplaces().AllocLC(); // CS: 1 + + // Copy incoming replaces to 8-bit buffer + HBufC8* replacesStringHeap8 = + HBufC8::NewLC( replacesStringHeap16->Length() + + KSVPReplacesColonTxt().Length() ); // CS: 2 + + replacesStringHeap8->Des().Copy( *replacesStringHeap16 ); + CleanupStack::Pop( 1 ); + CleanupStack::PushL( replacesStringHeap8 ); // ReAlloc possible + + // add replaces header + replacesStringHeap8->Des().Insert( 0, KSVPReplacesColonTxt ); + CleanupStack::Pop( 1 ); + CleanupStack::PushL( replacesStringHeap8 ); // ReAlloc possible + SVPDEBUG2( "CSVPTransferStateContext::SetTransferDataL - length: %d", replacesStringHeap8->Length() ) + + // Finally add collected Replaces string to header + aUserAgentHeaders->AppendL( *replacesStringHeap8 ); + CleanupStack::PopAndDestroy( replacesStringHeap8 ); // CS: 1 + CleanupStack::PopAndDestroy( replacesStringHeap16 ); // CS: 0 + } + + if ( iIncomingReferredBy ) + { + SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL: Add referredBy header" ) + TBuf8 referredByString; + referredByString.Append( KSVPReferredBy ); + // add IncomingReferredBy + referredByString.Append( IncomingReferredBy() ); + // Finally add collected Referred-By string to header + aUserAgentHeaders->AppendL( referredByString ); + } + } + + // Update transfer target address according preferred securesetting. + UpdateTransferTargetL( aSecureStatus ); + + SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::IsIncoming +// --------------------------------------------------------------------------- +// +TBool CSVPTransferStateContext::IsIncoming() + { + return ( NULL != iIncomingReferTo ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetIncomingReferToL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetIncomingReferToL( const TDesC8& aReferTo ) + { + SVPDEBUG1("CSVPTransferStateContext::SetIncomingReferToL In" ) + + ResetIncomingReferTo(); + + // modify aReferTo + HBufC8* referTo = CompleteReferToL( aReferTo ); + CleanupStack::PushL( referTo ); + + // at this point referto must contains legal sip uri + RemoveExtraParameters( referTo ); + + // Check length - moSession construct limitation + // sip: or sips: prefix will be added later, so 95 is maximum + if ( referTo->Length() < ( KSVPMaxUriLength - KSVPSipPrefixLength ) ) + { + // Copy and convert the "refer to" -parameter. + iIncomingReferTo = HBufC::NewL( referTo->Length() ); + TPtr temp = iIncomingReferTo->Des(); + temp.Copy( *referTo ); + } + else + { + SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferToL: referTo too long, Leave" ) + User::Leave( KErrArgument ); + } + + CleanupStack::PopAndDestroy( referTo ); + + SVPDEBUG2( "CSVPTransferStateContext::SetIncomingReferToL lenght: %d", + iIncomingReferTo->Length()) + SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferToL Out" ) + } + +// ----------------------------------------------------------------------------- +// CSVPSessionBase::SetIncomingReferredByL +// ----------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetIncomingReferredByL( const TDesC8& aReferredBy ) + { + SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferredByL In" ) + + ResetIncomingReferredBy(); + + // modify aReferredBy + HBufC8* referredBy = CompleteReferredByL( aReferredBy ); + CleanupStack::PushL( referredBy ); + + // Copy and convert the "Referred By" -parameter. + iIncomingReferredBy = HBufC::NewL( referredBy->Length() ); + TPtr temp = iIncomingReferredBy->Des(); + temp.Copy( *referredBy ); + CleanupStack::PopAndDestroy( referredBy ); + + SVPDEBUG2( "CSVPTransferStateContext::SetIncomingReferredByL lenght: %d", + iIncomingReferredBy->Length() ) + SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferredByL Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetIncomingReplacesL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetIncomingReplacesL( const TDesC8& aString ) + { + SVPDEBUG1("CSVPTransferStateContext::SetIncomingReplacesL In" ) + + ResetIncomingReplaces(); + + // modify Replaces + HBufC8* string = CompleteReplacesL( aString ); + CleanupStack::PushL( string ); + + // Copy and convert the "Replaces" -parameter. + iIncomingReplaces = HBufC::NewL( string->Length() ); + TPtr temp = iIncomingReplaces->Des(); + temp.Copy( *string ); + CleanupStack::PopAndDestroy( string ); + + SVPDEBUG2( "CSVPTransferStateContext::SetIncomingReplacesL lenght: %d", + iIncomingReplaces->Length() ) + SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReplacesL Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CompleteReplacesL +// --------------------------------------------------------------------------- +// +HBufC8* CSVPTransferStateContext::CompleteReplacesL( const TDesC8& aString ) + { + SVPDEBUG1( "CSVPTransferStateContext::CompleteReplacesL In" ) + + // Copy the parameter to a new buffer. + HBufC8* string = aString.AllocLC(); + // If "?Replaces=" found attended transfer case + TInt position = CheckReplacesTxt( *string ); + SVPDEBUG2( " CheckReplacesTxt returns = %d", position ); + + if ( KErrNotFound != position ) + { + TakeReplacesTxt( string, position ); + CleanupStack::Pop( 1 ); // string, ReAlloc possible + CleanupStack::PushL( string ); + } + // Check "?X-Sipx-Authidentity=" and remove text after it if exists + position = CheckAuthidentity( *string ); + + if ( KErrNotFound != position ) + { + // "?X-Sipx-Authidentity=" found + CutStringFromPosition( string, position ); + CleanupStack::Pop( 1 ); // string, ReAlloc possible + CleanupStack::PushL( string ); + } + + // Check ">" and remove text after it if exists + position = CheckRightBracket( *string ); + SVPDEBUG2(" CheckRightBracket returns = %d" , position ) + + if ( KErrNotFound != position ) + { + // ">" found + CutStringFromPosition( string, position ); + CleanupStack::Pop( 1 ); // string, ReAlloc possible + CleanupStack::PushL( string ); + } + + HBufC8* temp = EscapeUtils::EscapeDecodeL( *string ); + CleanupStack::PopAndDestroy( string ); + + SVPDEBUG1( "CSVPTransferStateContext::CompleteReplacesL Out" ) + return temp; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CompleteReferToL +// --------------------------------------------------------------------------- +// +HBufC8* CSVPTransferStateContext::CompleteReferToL( const TDesC8& aUri ) + { + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL In" ) + + // Copy the parameter to a new buffer. + HBufC8* uri = aUri.AllocLC(); + + // Check "<" and remove it and text before it if exists + TInt position = CheckLeftBracket( *uri ); + + if ( KErrNotFound != position ) + { + RemoveLeftBracket( uri, position ); + CleanupStack::Pop( 1 ); // uri, ReAlloc possible + CleanupStack::PushL( uri ); + } + + // Check ";user=phone" and remove if exists + position = CheckUserEqualsPhone( *uri ); + + if ( KErrNotFound != position ) + { + // ";user=phone" found + RemoveUserEqualsPhone( uri, position ); + CleanupStack::Pop( 1 ); // uri, ReAlloc possible + CleanupStack::PushL( uri ); + } + + // Check ">" and remove text after it if exists + position = CheckRightBracket( *uri ); + + if ( KErrNotFound != position ) + { + // ">" found + CutStringFromPosition( uri, position ); + CleanupStack::Pop( 1 ); // uri, ReAlloc possible + CleanupStack::PushL( uri ); + } + + // Check "KSVPQuesReplacesTxt" and remove text after it if exists + // If it is found -> attended transfer case + position = CheckReplacesTxt( *uri ); + + if ( KErrNotFound != position ) + { + // Found -> attended case. + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL ?Replaces= found -> attended transfer" ) + SetAttended( ETrue ); + SetIncomingReplacesL( aUri ); + CutStringFromPosition( uri, position ); + } + else + { + // Not found -> unattended case. + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL ?Replaces= not found -> unattended transfer" ) + SetAttended( EFalse ); + } + + // Check "?X-Sipx-Authidentity=" and remove text after it if exists + position = CheckAuthidentity( *uri ); + + if ( KErrNotFound != position ) + { + // "?X-Sipx-Authidentity=" found + CutStringFromPosition( uri, position ); + CleanupStack::Pop( 1 ); // uri, ReAlloc possible + CleanupStack::PushL( uri ); + } + + // Check "sip:" and remove it if exists + if ( KErrNone == uri->Find( KSVPSipPrefix ) ) + { + // sip: is in the beginning of the string + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL remove sip:" ) + uri->Des().Delete( 0, KSVPSipPrefixLength ); + } + + // Check "sips:" and remove it if exists + if ( KErrNone == uri->Find( KSVPSipsPrefix ) ) + { + // sips: is in the beginning of the string + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL remove sips:" ) + uri->Des().Delete( 0, KSVPSipsPrefixLength ); + } + + // Check ":" and remove text after it if exists, + // some server might add this after transfer target address + position = uri->Find( KSVPCln ); + + if ( KErrNotFound != position ) + { + // ":" found + SVPDEBUG2( "CSVPTransferStateContext::CompleteReferToL remove text after %d ", position ) + uri->Des().Delete( position, uri->Length() - position ); + } + + CleanupStack::Pop( 1 ); // uri, ReAlloc possible + + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL Out" ) + return uri; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CompleteReferredByL +// --------------------------------------------------------------------------- +// +HBufC8* CSVPTransferStateContext::CompleteReferredByL( + const TDesC8& aReferredBy ) + { + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferredByL In" ) + + // Copy the parameter to a new buffer. + HBufC8* referredBy = aReferredBy.AllocLC(); + + // Check "Referred-By:" and remove it + TInt position = CheckReferredByTxt( *referredBy ); + + if ( KErrNotFound != position ) + { + // "Referred-By:" found. + RemoveReferredByTxt( referredBy, position ); + } + + CleanupStack::Pop( 1 ); // referredBy, ReAlloc possible + + SVPDEBUG1( "CSVPTransferStateContext::CompleteReferredByL Out" ) + return referredBy; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckUserEqualsPhone +// --------------------------------------------------------------------------- +// +TInt CSVPTransferStateContext::CheckUserEqualsPhone( const TDesC8& aUri ) const + { + SVPDEBUG1( "CSVPTransferStateContext::CheckUserEqualsPhone" ) + + return ( aUri.FindF( KSVPUserEqualsPhone ) ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::RemoveUserEqualsPhone +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::RemoveUserEqualsPhone( + HBufC8*& aUri, TInt aPosition ) const + { + SVPDEBUG2( "CSVPTransferStateContext::RemoveUserEqualsPhone posit = %d", aPosition ) + + aUri->Des().Delete( aPosition, KSVPUserEqualsPhoneLenght ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::RemoveExtraParameters +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::RemoveExtraParameters( HBufC8*& aUri ) const + { + SVPDEBUG1( "CSVPTransferStateContext::RemoveExtraParameters In" ) + + // remove all extra parameters from given address + TInt index = aUri->Locate( KSVPSemiColonMark ); + TInt bracketLocation = KErrNotFound; + + SVPDEBUG3( "CSVPTransferStateContext::RemoveExtraParameters index = %d, length = %d", + index, aUri->Length() ) + + if ( KErrNotFound != index ) + { + // Delete ";" and text after it + aUri->Des().Delete( index, aUri->Length() ); + } + + // Check "<" and remove it and text before it if exists + bracketLocation = CheckLeftBracket( *aUri ); + + if ( KErrNotFound != bracketLocation ) + { + RemoveLeftBracket( aUri, bracketLocation ); + } + + // Check ">" and remove text after it if exists + bracketLocation = CheckRightBracket( *aUri ); + + if ( KErrNotFound != bracketLocation ) + { + CutStringFromPosition( aUri, bracketLocation ); + } + + SVPDEBUG1( "CSVPTransferStateContext::RemoveExtraParameters Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckReplacesTxt +// --------------------------------------------------------------------------- +// +TInt CSVPTransferStateContext::CheckReplacesTxt( const TDesC8& aUri ) const + { + SVPDEBUG1( "CSVPTransferStateContext::CheckReplacesTxt" ) + + return ( aUri.FindF( KSVPQuesReplacesTxt ) ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CutStringFromPosition +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::CutStringFromPosition( + HBufC8*& aUri, TInt aPosition ) const + { + SVPDEBUG2( "CSVPTransferStateContext::CutStringFromPosition posit = %d", aPosition ) + aUri->Des().Delete( aPosition, aUri->Length() - aPosition ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckReferredByTxt +// --------------------------------------------------------------------------- +// +TInt CSVPTransferStateContext::CheckReferredByTxt( + const TDesC8& aReferredBy ) const + { + SVPDEBUG1( "CSVPTransferStateContext::CheckReferredByTxt" ) + + return ( aReferredBy.FindF( KSVPReferredBy ) ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::RemoveReferredByTxt +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::RemoveReferredByTxt( + HBufC8*& aReferredBy, TInt aPosition ) const + { + SVPDEBUG2( "CSVPTransferStateContext::RemoveReferredByTxt posit = %d", aPosition ) + + aReferredBy->Des().Delete( aPosition, KSVPReferredByLength + 1 ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::TakeReplacesTxt +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::TakeReplacesTxt( + HBufC8*& aString, TInt aPosition ) const + { + SVPDEBUG2( "CSVPTransferStateContext::TakeReplacesTxt posit = %d", aPosition ) + + aString->Des().Delete( 0, aPosition + KSVPQuesReplacesTxtLength ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckLeftBracket +// --------------------------------------------------------------------------- +// +TInt CSVPTransferStateContext::CheckLeftBracket( const TDesC8& aUri ) const + { + SVPDEBUG1( "CSVPTransferStateContext::CheckLeftBracket" ) + + // Return position of "<" or KErrNotFound + return ( aUri.Find( KSVPLeftBracketMark ) ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::RemoveLeftBracket +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::RemoveLeftBracket( + HBufC8*& aUri, TInt aPosition ) const + { + SVPDEBUG2( "CSVPTransferStateContext::RemoveLeftBracket posit = %d", aPosition ) + + aUri->Des().Delete( 0, aPosition + KSVPSingleBracketLength ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckRightBracket +// --------------------------------------------------------------------------- +// +TInt CSVPTransferStateContext::CheckRightBracket( const TDesC8& aUri ) const + { + SVPDEBUG1( "CSVPTransferStateContext::CheckRightBracket" ) + + return ( aUri.Find( KSVPRightBracketMark ) ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CheckAuthidentity +// --------------------------------------------------------------------------- +// +TInt CSVPTransferStateContext::CheckAuthidentity( const TDesC8& aUri ) const + { + SVPDEBUG1( "CSVPTransferStateContext::CheckAuthidentity" ) + TInt returnValue = aUri.Find( KSVPAuthidentity ); + SVPDEBUG2( "CSVPTransferStateContext::CheckAuthidentity return: %d", returnValue ) + if ( returnValue == KErrNotFound ) + { + returnValue = aUri.Find( KSVPAuthidentity2 ); + SVPDEBUG2( "CSVPTransferStateContext::CheckAuthidentity second return: %d", returnValue ) + } + if ( returnValue == KErrNotFound ) + { + returnValue = aUri.Find( KSVPAuthidentity3 ); + SVPDEBUG2( "CSVPTransferStateContext::CheckAuthidentity third return: %d", returnValue ) + } + return returnValue; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::IncomingReferTo +// --------------------------------------------------------------------------- +// +const TDesC& CSVPTransferStateContext::IncomingReferTo() + { + SVPDEBUG1( "CSVPTransferStateContext::IncomingReferTo" ) + + return *iIncomingReferTo; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::UpdateTransferTargetL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::UpdateTransferTargetL( TInt aSecureStatus ) + { + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL In" ) + + if ( iIncomingReferTo ) + { + if ( KSVPStatusNonSecure == aSecureStatus ) + { + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add SIP uri" ) + + // Check "sips:" and remove it if exists + if ( KErrNone == iIncomingReferTo->Des().FindF( KSVPSipsPrefix2 ) ) + { + // sips: is in the beginning of the string, position 0 + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL remove sips:" ) + iIncomingReferTo->Des().Delete( 0, KSVPSipsPrefixLength ); + } + + // Add "sip:" prefix in the beginning of the string, if it's missing. + if ( KErrNotFound == iIncomingReferTo->Des().FindF( KSVPSipPrefix2 ) ) + { + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add sip:" ) + iIncomingReferTo = iIncomingReferTo->ReAllocL( + iIncomingReferTo->Length() + KSVPSipPrefixLength ); + iIncomingReferTo->Des().Insert( 0, KSVPSipPrefix2 ); + } + } + else + { + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add SIPS" ) + + // Check "sip:" and remove it if exists + if ( KErrNone == iIncomingReferTo->Des().FindF( KSVPSipPrefix2 ) ) + { + // sip: is in the beginning of the string + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL remove sip:" ) + iIncomingReferTo->Des().Delete( 0, KSVPSipPrefixLength ); + } + + // Add "sips:" prefix in the beginning of the string, if it's missing. + if ( KErrNotFound == iIncomingReferTo->Des().FindF( KSVPSipsPrefix2 ) ) + { + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add sips:" ) + iIncomingReferTo = iIncomingReferTo->ReAllocL( + iIncomingReferTo->Length() + KSVPSipsPrefixLength ); + iIncomingReferTo->Des().Insert( 0, KSVPSipsPrefix2 ); + } + } + } + else + { + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL IncomingReferTo Not OK" ) + } + + SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::ResetIncomingReferTo +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::ResetIncomingReferTo() + { + SVPDEBUG1( "CSVPTransferStateContext::ResetIncomingReferTo" ) + + if ( iIncomingReferTo ) + { + delete iIncomingReferTo; + iIncomingReferTo = NULL; + } + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::ResetIncomingReferredBy +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::ResetIncomingReferredBy() + { + SVPDEBUG1( "CSVPTransferStateContext::ResetIncomingReferredBy" ) + + if ( iIncomingReferredBy ) + { + delete iIncomingReferredBy; + iIncomingReferredBy = NULL; + } + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::IncomingReferredBy +// --------------------------------------------------------------------------- +// +const TDesC& CSVPTransferStateContext::IncomingReferredBy() + { + SVPDEBUG1( "CSVPTransferStateContext::IncomingReferredBy" ) + + return *iIncomingReferredBy; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::IncomingReplaces +// --------------------------------------------------------------------------- +// +const TDesC& CSVPTransferStateContext::IncomingReplaces() + { + SVPDEBUG1( "CSVPTransferStateContext::IncomingReplaces" ) + + return *iIncomingReplaces; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::ResetIncomingReplaces +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::ResetIncomingReplaces() + { + SVPDEBUG1( "CSVPTransferStateContext::ResetIncomingReplaces" ) + + if ( iIncomingReplaces ) + { + delete iIncomingReplaces; + iIncomingReplaces = NULL; + } + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetTransferParmsL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetTransferParmsL( + CSVPSessionBase* aTargetSession, const TDesC& aTarget, + const TBool aAttendedTransfer ) + { + SVPDEBUG1( "CSVPTransferStateContext::SetTransferParmsL In" ) + + // No target session as default. + iTargetSession = NULL; + + // Delete possible old refer + delete iMceRefer; + iMceRefer = NULL; + + // Set attended/unattended transfer + SetAttended( aAttendedTransfer ); + + // Create mce out refer using given target parameter or call + if ( aTarget.Length() > 0 ) + { + CreateMceOutReferL( aTarget ); + } + else + { + CreateMceOutReferL( aTargetSession ); + } + + SVPDEBUG1( "CSVPTransferStateContext::SetTransferParmsL Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CreateMceOutReferL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::CreateMceOutReferL( const TDesC& aTarget ) + { + // Create mce out refer using target string (unattended). + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) In" ) + + // Copy 'refer to' argument + HBufC8* target = HBufC8::NewLC( aTarget.Length() ); + target->Des().Copy( aTarget ); + + // Parse target with uri parser, use session recipient as domain source + CSVPUriParser* uriParser = CSVPUriParser::NewLC(); + HBufC8* referto = NULL; + RPointerArray< CRCSEProfileEntry > entryArray; + CleanupResetAndDestroy< RPointerArray >::PushL( entryArray ); + CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC(); + + // Get VoIP profile by service id + reg->FindByServiceIdL( iSVPSession->Parameters().ServiceId(), entryArray ); + __ASSERT_ALWAYS( entryArray.Count(), User::Leave( KErrArgument ) ); + CRCSEProfileEntry* entry = entryArray[0]; + uriParser->SetUserEqualsPhoneRequiredL( + CRCSEProfileEntry::EOn == entry->iUserPhoneUriParameter ); + + CleanupStack::PopAndDestroy( reg ); + CleanupStack::PopAndDestroy( &entryArray ); + + HBufC8* recipient = NULL; + const CMceSession& session = iSVPSession->Session(); + __ASSERT_ALWAYS( &session, User::Leave( KErrArgument ) ); + + TBool isCLIROn = iSVPSession->IsCLIROnL(); + + if ( ( iSVPSession->IsMobileOriginated() && !isCLIROn ) + || ( !iSVPSession->IsMobileOriginated() && isCLIROn ) ) + { + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget), orig" ) + const TDesC8& orig = session.Originator(); + __ASSERT_ALWAYS( &orig, User::Leave( KErrArgument ) ); + recipient = HBufC8::NewLC( orig.Length() ); + recipient->Des().Copy( orig ); + } + else + { + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget), recip" ) + const TDesC8& recip = session.Recipient(); + __ASSERT_ALWAYS( &recip, User::Leave( KErrArgument ) ); + recipient = HBufC8::NewLC( recip.Length() ); + recipient->Des().Copy( recip ); + } + + // remove all extra parameters from recipient address + RemoveExtraParameters( recipient ); + + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) recipient->Length() = %d", + recipient->Length() ) + + if ( iSVPSession->SecureMandatory() || iSVPSession->SecurePreferred() ) + { + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) SIPS URI..." ) + referto = uriParser->CompleteSecureSipUriL( *target, *recipient ); + } + else + { + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) SIP URI..." ) + referto = uriParser->CompleteSipUriL( *target, *recipient ); + } + + CleanupStack::PushL( referto ); + + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) 1 referto->Length() = %d", + referto->Length() ) + + // remove all extra parameters from referto + RemoveExtraParameters( referto ); + + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) 2 referto->Length() = %d", + referto->Length() ) + + // Create the refer + delete iMceRefer; + iMceRefer = NULL; + iMceRefer = CMceOutRefer::NewL( *iMceSession, *referto, CMceRefer::ENoSuppression ); + CleanupStack::PopAndDestroy( referto ); + + CleanupStack::PopAndDestroy( recipient ); + CleanupStack::PopAndDestroy( uriParser ); + CleanupStack::PopAndDestroy( target ); + + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::CreateMceOutReferL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::CreateMceOutReferL( CSVPSessionBase* aTargetSession ) + { + // Create mce out refer using session (attended). + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) In" ) + + // Store target session + iTargetSession = aTargetSession; + + // Construct the refer-to string + HBufC8* referto = HBufC8::NewLC( KSVPTempStringlength ); + TPtr8 refptr = referto->Des(); + + if ( iTargetSession ) + { + // Set refer-to for the attended transfer using the target session, + // that can not be the same as the owner session of the + // transfer controller. + if ( iSVPSession != iTargetSession ) + { + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) TargetSession = 0x%x", &iTargetSession ) + + HBufC8* recipient = NULL; + const CMceSession& session = iTargetSession->Session(); + __ASSERT_ALWAYS( &session, User::Leave( KErrArgument ) ); + + if ( iTargetSession->IsMobileOriginated() ) + { + const TDesC8& recip = session.Recipient(); + __ASSERT_ALWAYS( &recip, User::Leave( KErrArgument ) ); + recipient = HBufC8::NewLC( recip.Length() ); + recipient->Des().Copy( recip ); + } + else + { + const TDesC8& orig = session.Originator(); + __ASSERT_ALWAYS( &orig, User::Leave( KErrArgument ) ); + recipient = HBufC8::NewLC( orig.Length() ); + recipient->Des().Copy( orig ); + } + + // remove all extra parameters from recipient address + RemoveExtraParameters( recipient ); + + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) recipient->Length() = %d", + recipient->Length() ) + + // Set the refer-to address (recipient) + refptr.Append( recipient->Des() ); + CleanupStack::PopAndDestroy( recipient ); + + // Gather up the rest of the refer-to data (replaces etc.) + // from the target session (sessionbase) member variables. + TBuf8 tmp( KNullDesC8 ); + tmp.Append( KSVPQuesReplacesTxt ); // Set CallId + + if ( iTargetSession->CallId() ) + { + // Set "replaces" callid string starting from next char + // the of KSVPCallId_replaces -text + TDesC8* callid = iTargetSession->CallId(); + TInt index = callid->Find( KSVPCallId_replaces ); + + if ( KErrNotFound != index ) + { + // Check and encode the possible @ char of the callid + // to "%40" format. This kind of callid e.g. in Cisco 7960. + TInt index2 = callid->Find( KSVPAt ); + + if ( KErrNotFound != index2 ) + { + HBufC8* tmpCallId = HBufC8::NewLC( callid->Length() ); + tmpCallId->Des().Append( callid->Mid( index + + KSVPCallId_replaces().Length() ) ); + CSVPUriParser::EscapeEncodeSipUriL( tmpCallId, + EscapeUtils::EEscapeUrlEncoded ); + tmp.Append( *tmpCallId ); + CleanupStack::Pop( 1 ); // tmpCallId, ReAlloc possible + delete tmpCallId; + } + else + { + // Normal copy from the correct position + tmp.Append( callid->Mid( index + + KSVPCallId_replaces().Length() ) ); + } + } + } + else + { + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - missing CallId %i", KSVPErrTransferReferTo ) + User::Leave( KSVPErrTransferReferTo ); + } + + // To-header + if ( iTargetSession->ToHeader() ) + { + tmp.Append( KSVPTo_tag ); + + // Set "to" tag string starting from next char + // of the KSVPTo_tag_replaces -text + TDesC8* toHdr = iTargetSession->ToHeader(); + TInt index = toHdr->Find( KSVP_tag ); + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) toHdr index = %d", index ) + + if ( KErrNotFound != index ) + { + tmp.Append( toHdr->Mid( index + KSVPTagLength ) ); + } + } + else + { + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - missing ToHeader %i", KSVPErrTransferReferTo ) + User::Leave( KSVPErrTransferReferTo ); + } + + // From-header + if ( iTargetSession->FromHeader() ) + { + tmp.Append( KSVPFrom_tag ); + + // Set "from" tag string starting from next char of + // the KSVPTo_tag_replaces -text + TDesC8* fromHdr = iTargetSession->FromHeader(); + TInt index = fromHdr->Find( KSVP_tag ); + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) fromHdr index = %d", index ) + + if ( KErrNotFound != index ) + { + tmp.Append( fromHdr->Mid( index + KSVPTagLength ) ); + } + } + else + { + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - missing FromHeader %i", KSVPErrTransferReferTo ) + User::Leave( KSVPErrTransferReferTo ); + } + + refptr.Append( tmp ); + } // if ( iSVPSession != iTargetSession ) + else + { + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - the same target session %i", KSVPErrTransferReferTo ) + User::Leave( KSVPErrTransferReferTo ); + } + + // Create the refer + iMceRefer = CMceOutRefer::NewL( *iMceSession, + *referto, CMceRefer::ENoSuppression ); + } // if (iTargetSession) + else + { + SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - no target session %i", KSVPErrTransferReferTo ) + User::Leave( KSVPErrTransferReferTo ); + } + + CleanupStack::PopAndDestroy( referto ); + + SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::ExecuteReferL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::ExecuteReferL() + { + SVPDEBUG1( "CSVPTransferStateContext::ExecuteReferL In" ) + + delete iMceEvent; + iMceEvent = NULL; + + // Create headers for refer call. + CDesC8Array* headers = SetupHeadersL(); + CleanupStack::PushL( headers ); + + // Refer with headers, passes ownership. + iMceEvent = static_cast< CMceOutRefer* >(MceRefer())->ReferL( headers ); + CleanupStack::Pop( headers ); + + // Execution of the refer. Pass ownership of the arguments. Generates + // event to the MMceReferObserver. New MceOutEvent is created and events + // of that then through MMceEventObserver interface. + iSVPSession->StartTimerL( KSVPReferExpirationTime, + KSVPReferTimerExpired );// Start refer timer + + SVPDEBUG1( "CSVPTransferStateContext::ExecuteReferL Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetMceEvent +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::SetMceEvent( CMceEvent* aEvent ) + { + SVPDEBUG1( "CSVPTransferStateContext::SetMceEvent In" ) + + if ( iMceEvent != aEvent ) + { + delete iMceEvent; + iMceEvent = aEvent; + SVPDEBUG1( "CSVPTransferStateContext::SetMceEvent Updated" ) + } + + SVPDEBUG1( "CSVPTransferStateContext::SetMceEvent Out" ) + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::MceEvent +// --------------------------------------------------------------------------- +// +CMceEvent* CSVPTransferStateContext::MceEvent() + { + return iMceEvent; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::StopReferTimer +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::StopReferTimer() + { + SVPDEBUG1( "CSVPTransferStateContext::StopReferTimer" ) + + iSVPSession->StopTimer( KSVPReferTimerExpired ); + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::SetupHeadersL +// --------------------------------------------------------------------------- +// +CDesC8Array* CSVPTransferStateContext::SetupHeadersL() + { + SVPDEBUG1( "CSVPTransferStateContext::SetupHeadersL In" ) + + CDesC8ArrayFlat* headers = new( ELeave ) CDesC8ArrayFlat( + KSVPHeaderArrayGranularity ); + CleanupStack::PushL( headers ); + + // Set "referred by" value - that is this end of the session. + TBuf8 tempRefBy; + tempRefBy.Append( KSVPReferredBy ); + + if ( iSVPSession->IsMobileOriginated() ) + { + TDesC8* fromHdr = iSVPSession->FromHeader(); + if ( fromHdr ) + { + TInt indexLeft = fromHdr->Find( KSVPLeftBracketMark ); + TInt indexRight = fromHdr->Find( KSVPRightBracketMark ); + SVPDEBUG3( "CSVPTransferStateContext::SetupHeadersL: indexLeft = %d, indexRight = %d", indexLeft, indexRight ); + + tempRefBy.Append( fromHdr->Mid( indexLeft, + indexRight - indexLeft + KSVPSingleBracketLength ) ); + } + } + else + { + TDesC8* toHdr = iSVPSession->ToHeader(); + if ( toHdr ) + { + TInt indexLeft = toHdr->Find( KSVPLeftBracketMark ); + TInt indexRight = toHdr->Find( KSVPRightBracketMark ); + SVPDEBUG3( "CSVPTransferStateContext::SetupHeadersL: indexLeft = %d, indexRight = %d", indexLeft, indexRight ) + + tempRefBy.Append( toHdr->Mid( indexLeft, + indexRight - indexLeft + KSVPSingleBracketLength ) ); + } + } + + headers->AppendL( tempRefBy ); + CleanupStack::Pop( headers ); + + SVPDEBUG1( "CSVPTransferStateContext::SetupHeadersL Out" ) + return headers; + } + +// --------------------------------------------------------------------------- +// CSVPTransferStateContext::InitializeStateArrayL +// --------------------------------------------------------------------------- +// +void CSVPTransferStateContext::InitializeStateArrayL() + { + // Create the array of the transfer states. + iStates = new ( ELeave ) RPointerArray + ( KSVPTransferStateArraySize ); + + // Transfer state classes are created here: + // Idle state + CSVPTransferStateBase* state = CSVPTransferIdleState::NewLC(); + User::LeaveIfError( iStates->Insert( + state, KSVPTransferIdleStateIndex ) ); + CleanupStack::Pop( state ); + + // Pending state + state = CSVPTransferPendingState::NewLC(); + User::LeaveIfError( iStates->Insert( + state, KSVPTransferPendingStateIndex ) ); + CleanupStack::Pop( state ); + + // Accepted state + state = CSVPTransferAcceptedState::NewLC(); + User::LeaveIfError( iStates->Insert( + state, KSVPTransferAcceptedStateIndex ) ); + CleanupStack::Pop( state ); + + // Terminating state + state = CSVPTransferTerminatingState::NewLC(); + User::LeaveIfError( iStates->Insert( + state, KSVPTransferTerminatingStateIndex ) ); + CleanupStack::Pop( state ); + + // Terminated state + state = CSVPTransferTerminatedState::NewLC(); + User::LeaveIfError( iStates->Insert( + state, KSVPTransferTerminatedStateIndex ) ); + CleanupStack::Pop( state ); + } + +// ----------------------------------------------------------------------------- +// CSVPTransferStateContext::IsStateTransitionAccepted +// ----------------------------------------------------------------------------- +// +TBool CSVPTransferStateContext::IsStateTransitionAccepted( + const TSVPTransferStateIndex aNewState ) + { + TSVPTransferStateIndex current = CurrentState(); + + SVPDEBUG2( "CSVPTransferStateContext::IsStateTransitionAccepted: current = %d", current ) + SVPDEBUG2( "CSVPTransferStateContext::IsStateTransitionAccepted: newstate = %d", aNewState ) + + switch( current ) + { + case KErrNotFound: + { + // Only idle state can be the first one. + if ( KSVPTransferIdleStateIndex == aNewState ) + { + return ETrue; + } + else + { + return EFalse; + } + } + + case KSVPTransferIdleStateIndex: + { + if ( KSVPTransferPendingStateIndex == aNewState || + KSVPTransferTerminatingStateIndex == aNewState ) + { + return ETrue; + } + else + { + return EFalse; + } + } + + case KSVPTransferPendingStateIndex: + { + if ( KSVPTransferAcceptedStateIndex == aNewState || + KSVPTransferTerminatingStateIndex == aNewState ) + { + return ETrue; + } + else + { + return EFalse; + } + } + + case KSVPTransferAcceptedStateIndex: + { + // If in accepted state, new transition is valid (return true). + // No transition actually occurs because + // state "changes" from accepted to accepted. + // This ignores sequent icoming NOTIFY's after REFER has been sent. + if ( KSVPTransferTerminatingStateIndex == aNewState || + KSVPTransferAcceptedStateIndex == aNewState) + { + return ETrue; + } + else + { + return EFalse; + } + } + + case KSVPTransferTerminatingStateIndex: + { + // From terminating state, transition to terminated is accepted. + if ( KSVPTransferTerminatingStateIndex == aNewState || + KSVPTransferTerminatedStateIndex == aNewState ) + { + return ETrue; + } + else + { + return EFalse; + } + } + + case KSVPTransferTerminatedStateIndex: + { + // From terminated state, transition to idle is accepted. + if ( KSVPTransferIdleStateIndex == aNewState ) + { + return ETrue; + } + else + { + return EFalse; + } + } + + default: + { + // Should not come here, since all the states are handled + SVPDEBUG1( "CSVPTransferStateContext::IsStateTransitionAccepted - Error" ) + return EFalse; + } + // No breaks in switch case due returns. + } + } +