--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sipvoipprovider/src/svpcontroller.cpp Mon Jan 18 20:12:36 2010 +0200
@@ -0,0 +1,3510 @@
+/*
+* Copyright (c) 2006-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: Handles all common logic for SVP and handles sessions.
+*
+*/
+
+#include <mcevideostream.h>
+#include <mceaudiocodec.h>
+#include <mcemediasink.h>
+#include <mcemediasource.h>
+#include <mceevent.h>
+#include <mcesession.h>
+#include <mceinrefer.h>
+#include <mcesecuresession.h>
+#include <mcertpsource.h>
+#include <mccpdtmfobserver.h>
+#include <sipstrings.h>
+#include <sipstrconsts.h>
+
+#include <crcseprofileentry.h>
+#include <crcseprofileregistry.h>
+
+#include <wlantrafficstreamparameters.h> // CWlanMgmtClient
+#include <ccpdefs.h>
+
+#include "svpcontroller.h"
+#include "svpmosession.h"
+#include "svpmtsession.h"
+#include "svplogger.h"
+#include "svptimer.h"
+#include "svputility.h"
+#include "svpholdcontext.h"
+#include "svpholdcontroller.h"
+#include "svpcleanupresetanddestroy.h"
+#include "svpaudioutility.h"
+#include "svpsipconsts.h"
+#include "svpemergencyiapprovider.h"
+#include "svprtpobserver.h"
+#include "svpsettings.h"
+
+// ---------------------------------------------------------------------------
+// CSVPController::CSVPController
+// ---------------------------------------------------------------------------
+//
+CSVPController::CSVPController() : iSessionUpdateOngoing( EFalse )
+ {
+
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::ConstructL()
+ {
+ SVPDEBUG1( "CSVPController::ConstructL In" )
+
+ iIncomingReferCallIndex = KErrNotFound;
+ iHoldCallIndex = KErrNotFound;
+ iSuppServices = CSVPSupplementaryServices::NewL();
+ iSVPUtility = CSVPUtility::NewL();
+ iRtpObserver = CSVPRtpObserver::NewL();
+#ifndef __WINS__
+ iWlanMgmt = CWlanMgmtClient::NewL();
+#endif // __WINS__
+
+ SVPDEBUG1( "CSVPController::ConstructL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::NewL
+// ---------------------------------------------------------------------------
+//
+CSVPController* CSVPController::NewL()
+ {
+ CSVPController* self = new ( ELeave ) CSVPController();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::~CSVPController
+// ---------------------------------------------------------------------------
+//
+CSVPController::~CSVPController()
+ {
+ SVPDEBUG1( "CSVPController::~CSVPController In" )
+
+#ifndef __WINS__
+ delete iWlanMgmt;
+#endif // __WINS__
+
+ delete iSVPUtility;
+
+ // clean array that contains SVP sessions.
+ iSessionArray.ResetAndDestroy();
+ iSessionArray.Close();
+
+ // SVP emergency session
+ delete iEmergencySession;
+
+ iEmergencyProfileIds.Close();
+ iEmergencyIapIds.Close();
+
+ delete iSuppServices;
+ delete iMceManager;
+ delete iRtpObserver;
+
+ delete iDtmfString;
+
+ SVPDEBUG1( "CSVPController::~CSVPController Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::InitializeL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::InitializeL( const TUint32 aServiceId,
+ const MCCPObserver& aMonitor,
+ const MCCPSsObserver& aSsObserver )
+ {
+
+ SVPDEBUG2( "CSVPController::InitializeL serviceId = %d", aServiceId )
+
+ SVPDEBUG2( "CSVPController::InitializeL iCCPMonitor: 0x%x", iCCPMonitor )
+
+ //Find callprovider plugin uid that should be used when registering to MCE
+ TInt ccpUid = SvpSettings::IntPropertyL( aServiceId,
+ EPropertyCallProviderPluginId );
+ SVPDEBUG2( "CSVPController::InitializeL callproviderpluginuid=%d", ccpUid )
+
+ // See CConvergedCallProvider API documentation. If already called,
+ // leave with KErrAlreadyExists.
+ __ASSERT_ALWAYS( !iCCPMonitor, User::Leave( KErrAlreadyExists ) );
+ __ASSERT_ALWAYS( !iCCPSsObserver, User::Leave( KErrAlreadyExists ) );
+ __ASSERT_ALWAYS( iSVPUtility, User::Leave( KErrNotReady ) );
+ __ASSERT_ALWAYS( iRtpObserver, User::Leave( KErrNotReady ) );
+
+ // save CCP monitor
+ iCCPMonitor = const_cast< MCCPObserver* >( &aMonitor );
+
+ // save CCP Supplementary Services observer
+ iCCPSsObserver = const_cast< MCCPSsObserver* >( &aSsObserver );
+
+ // get terminal type and wlan mac address, needed for user agent header
+ iSVPUtility->GetTerminalTypeL( iTerminalType );
+ iSVPUtility->GetWlanMACAddressL( iWlanMacAddress );
+
+ TUid uid = { ccpUid };
+ // create Mce Manager, establishes connection to Mce server
+ iMceManager = CMceManager::NewL( uid, &iContainer );
+
+ // set observers for asynchronous events
+ iMceManager->SetSessionObserver( this );
+ iMceManager->SetInSessionObserver( this );
+ iMceManager->SetInReferObserver( this );
+ iMceManager->SetReferObserver( this );
+ iMceManager->SetMediaObserver( this );
+ iMceManager->SetEventObserver( this );
+ iMceManager->SetDtmfObserver( this );
+ iMceManager->SetRtpObserver( iRtpObserver );
+
+ iTrafficStreamCreated = EFalse;
+
+ SVPDEBUG1( "CSVPController::InitializeL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::InitializeL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::InitializeL( const MCCPObserver& aMonitor,
+ const MCCPSsObserver& aSsObserver )
+ {
+ SVPDEBUG2( "CSVPController::InitializeL iCCPMonitor: 0x%x", iCCPMonitor )
+ SVPDEBUG2( "CSVPController::InitializeL iCCPSsObserver: 0x%x", iCCPSsObserver )
+
+ // See CConvergedCallProvider API documentation. If already called,
+ // leave with KErrAlreadyExists.
+ __ASSERT_ALWAYS( !iCCPMonitor, User::Leave( KErrAlreadyExists ) );
+ __ASSERT_ALWAYS( !iCCPSsObserver, User::Leave( KErrAlreadyExists ) );
+ __ASSERT_ALWAYS( iSVPUtility, User::Leave( KErrNotReady ) );
+ __ASSERT_ALWAYS( iRtpObserver, User::Leave( KErrNotReady ) );
+
+ // save CCP monitor
+ iCCPMonitor = const_cast< MCCPObserver* >( &aMonitor );
+
+ // save CCP Supplementary Services observer
+ iCCPSsObserver = const_cast< MCCPSsObserver* >( &aSsObserver );
+
+ // get terminal type and wlan mac address, needed for user agent header
+ iSVPUtility->GetTerminalTypeL( iTerminalType );
+ iSVPUtility->GetWlanMACAddressL( iWlanMacAddress );
+
+ // create Mce Manager, establishes connection to Mce server
+ iMceManager = CMceManager::NewL( KSVPImplementationUid, &iContainer );
+
+ // set observers for asynchronous events
+ iMceManager->SetSessionObserver( this );
+ iMceManager->SetInSessionObserver( this );
+ iMceManager->SetInReferObserver( this );
+ iMceManager->SetReferObserver( this );
+ iMceManager->SetMediaObserver( this );
+ iMceManager->SetEventObserver( this );
+ iMceManager->SetDtmfObserver( this );
+ iMceManager->SetRtpObserver( iRtpObserver );
+
+ iTrafficStreamCreated = EFalse;
+
+ SVPDEBUG1( "CSVPController::InitializeL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::NewCallL
+// ---------------------------------------------------------------------------
+//
+MCCPCall* CSVPController::NewCallL(
+ const CCCPCallParameters& aParameters,
+ const TDesC& aRecipient,
+ const MCCPCallObserver& aObserver )
+ {
+ SVPDEBUG1( "CSVPController::NewCallL In" )
+
+ __ASSERT_ALWAYS( &aParameters, User::Leave( KErrArgument ) );
+ __ASSERT_ALWAYS( &aRecipient, User::Leave( KErrArgument ) );
+ __ASSERT_ALWAYS( &aObserver, User::Leave( KErrArgument ) );
+
+#ifndef __WINS__
+ // Preliminary Call Admission Control implementation, run only if no stream yet open
+ if ( !iTrafficStreamCreated )
+ {
+ SVPDEBUG1( "CSVPController::NewCallL - Creating WLAN traffic stream.." )
+
+ TRequestStatus requestStatus;
+ TUint streamId = 0;
+ TWlanTrafficStreamParameters streamParams( KSVPWlanTrafficStreamParamUserPriority );
+ TWlanTrafficStreamStatus streamStatus = EWlanTrafficStreamStatusActive;
+
+ // Disabling WLAN traffic stream automation and get stream status
+ iWlanMgmt->CreateTrafficStream( requestStatus, streamParams, streamId, streamStatus );
+ User::WaitForRequest( requestStatus );
+
+ // Save traffic stream ID, needed for stream deletion
+ iTrafficStreamId = streamId;
+
+ if ( EWlanTrafficStreamStatusInactiveNoBandwidth == streamStatus )
+ {
+ SVPDEBUG1( "CSVPController::NewCallL - No bandwidth in traffic stream, leaving with ECCPErrorNetworkBusy" )
+
+ // Enabling WLAN traffic stream automation back by deleting used stream
+ iWlanMgmt->DeleteTrafficStream( requestStatus, iTrafficStreamId );
+ User::WaitForRequest( requestStatus );
+
+ TCCPError err = ECCPErrorNetworkBusy;
+ User::Leave( err );
+ }
+ SVPDEBUG1( "CSVPController::NewCallL - WLAN traffic stream created, continuing with NewCallL" )
+
+ iTrafficStreamCreated = ETrue;
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::NewCallL - WLAN traffic stream already created, continuing with NewCallL" )
+ ;
+ }
+#endif // __WINS__
+
+ SVPDEBUG2( "CSVPController::NewCallL aRecipient length = %d", aRecipient.Length() )
+ SVPDEBUG2( "CSVPController::NewCallL aRecipient = %S", &aRecipient )
+ SVPDEBUG2( "CSVPController::NewCallL Serviceid = %d", aParameters.ServiceId() )
+
+ // Prepare and remove possible DTMF suffix
+ HBufC* parsedRecipient = NULL;
+ parsedRecipient = ParseRecipientDtmfSuffixL( aRecipient );
+
+ // "convert" recpient to 8-bit format
+ HBufC8* recipient = HBufC8::NewLC( parsedRecipient->Length() ); // CS:1
+ TPtr8 temp = recipient->Des();
+ temp.Copy( *parsedRecipient );
+
+ // Pointer to parsedRecipient no longer needed
+ delete parsedRecipient;
+ parsedRecipient = NULL;
+
+ // fetch SIP profile ID from VoIP profiles
+ RPointerArray< CRCSEProfileEntry > entryArray;
+ CleanupResetAndDestroy<
+ RPointerArray<CRCSEProfileEntry> >::PushL( entryArray ); //CS:2
+
+ CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC(); // CS:3
+
+ // take service id to local variable
+ TUint32 serviceId = aParameters.ServiceId();
+
+ // Get VoIP profile by service id
+ reg->FindByServiceIdL( serviceId, entryArray );
+ __ASSERT_ALWAYS( entryArray.Count(), User::Leave( KErrArgument ) );
+
+ // Take first entry from array
+ CRCSEProfileEntry* entry = entryArray[0];
+
+ // create new session
+ MCCPCall* moSessionTemp = CreateNewSessionL( *recipient,
+ *entry,
+ aParameters,
+ aObserver );
+
+ CleanupStack::PopAndDestroy( 2, &entryArray ); // CS:1
+ CleanupStack::PopAndDestroy( recipient ); // CS:0
+
+ SVPDEBUG1( "CSVPController::NewCallL Out" )
+ return moSessionTemp;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CreateNewSessionL
+// ---------------------------------------------------------------------------
+//
+MCCPCall* CSVPController::CreateNewSessionL(
+ TDesC8& aRecipient,
+ CRCSEProfileEntry& aVoipProfile,
+ const CCCPCallParameters& aParameters,
+ const MCCPCallObserver& aObserver )
+ {
+ SVPDEBUG1( "CSVPController::CreateNewSessionL In" )
+
+ // array for provisioned data
+ CDesC8ArrayFlat* userAgentHeaders = new( ELeave ) CDesC8ArrayFlat( 4 );
+ CleanupStack::PushL( userAgentHeaders ); // CS:1
+
+ // variable for storing security status
+ TUint32 securityStatus( 0 );
+
+ // set provisioning data
+ SVPDEBUG1( "CSVPController::CreateNewSessionL Set provisioning data..." )
+ iSVPUtility->SetProvisioningDataL( aVoipProfile,
+ *userAgentHeaders,
+ securityStatus,
+ iTerminalType,
+ iWlanMacAddress );
+
+ SVPDEBUG2( "CSVPController::CreateNewSessionL Security status: %d", securityStatus )
+ SVPDEBUG2( "CSVPController::CreateNewSessionL UAHeaders count: %d", userAgentHeaders->Count() )
+
+ // Creates a SVP Mo session
+ CSVPMoSession* moSessionTemp = CSVPMoSession::NewL( *iMceManager,
+ aRecipient,
+ aVoipProfile,
+ aParameters,
+ iContainer,
+ *this,
+ *iSVPUtility,
+ *iRtpObserver,
+ securityStatus,
+ userAgentHeaders );
+ CleanupStack::Pop( userAgentHeaders ); // CS:0, to member data
+ CleanupStack::PushL( moSessionTemp ); // CS:1
+
+ FinalizeSessionCreationL( moSessionTemp );
+
+ // set CCP session observer to SVP session
+ moSessionTemp->AddObserverL( aObserver );
+ // set CCP supplementary services events observer to SVP session
+ moSessionTemp->SetSsObserver( *iCCPSsObserver );
+
+ CleanupStack::Pop( moSessionTemp ); // CS:0
+
+ // session pointer is passed to CCP
+ SVPDEBUG1( "CSVPController::CreateNewSessionL Out" )
+ return moSessionTemp;
+ }
+
+// ---------------------------------------------------------------------------
+// Releases call
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ReleaseCall( MCCPCall& aCall )
+ {
+ SVPDEBUG1( "CSVPController::ReleaseCall In" )
+
+ TInt response = KErrNotFound;
+
+ // To ensure correct value
+ iIncomingReferCallIndex = KErrNotFound;
+ iSessionUpdateOngoing = EFalse;
+
+ for ( TInt i = 0; i < iSessionArray.Count(); i++ )
+ {
+ if ( iSessionArray[i] == &aCall )
+ {
+ if ( iDtmfStringSending )
+ {
+ SVPDEBUG1( "CSVPController::ReleaseCall - Abort DTMF Sending" )
+
+ // send abort event
+ iSessionArray[i]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfSequenceAbort,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+
+ SVPDEBUG1( "CSVPController::ReleaseCall - Complete DTMF" )
+
+ // send sequence completed event
+ iSessionArray[i]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfStringSendingCompleted,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+
+ // sequence complete, clear flags
+ iDtmfStringSending = EFalse;
+ iFirstDtmfSent = EFalse;
+
+ delete iDtmfString;
+ iDtmfString = NULL;
+ }
+ iSessionArray[i]->Release();
+ response = KErrNone;
+ }
+ }
+
+#ifndef __WINS__
+ // Preliminary Call Admission Control implementation, delete only if created in NewCallL
+ if ( iTrafficStreamCreated )
+ {
+ SVPDEBUG1( "CSVPController::ReleaseCall - Deleting WLAN traffic stream" )
+
+ TRequestStatus requestStatus;
+
+ // Enabling WLAN traffic stream automation back by deleting used stream
+ iWlanMgmt->DeleteTrafficStream( requestStatus, iTrafficStreamId );
+ User::WaitForRequest( requestStatus );
+
+ iTrafficStreamCreated = EFalse;
+
+ SVPDEBUG1( "CSVPController::ReleaseCall - WLAN traffic stream deleted" )
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::ReleaseCall - No WLAN traffic stream to delete" )
+ ;
+ }
+#endif // __WINS__
+
+ SVPDEBUG1( "CSVPController::ReleaseCall Out" )
+ return response;
+ }
+
+// ---------------------------------------------------------------------------
+// Releases emergency call
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ReleaseEmergencyCall( MCCPEmergencyCall& /*aCall*/ )
+ {
+ SVPDEBUG1( "CSVPController::ReleaseEmergencyCall In" )
+
+ // To ensure correct value next time
+ iIncomingReferCallIndex = KErrNotFound;
+ iSessionUpdateOngoing = EFalse;
+
+ delete iEmergencySession;
+ iEmergencySession = NULL;
+
+ SVPDEBUG1( "CSVPController::ReleaseEmergencyCall Out" )
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// Releases conference call
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ReleaseConferenceCall( MCCPConferenceCall& /*aCall*/ )
+ {
+ SVPDEBUG1( "CSVPController::ReleaseConferenceCall In" )
+ SVPDEBUG1( "CSVPController::ReleaseConferenceCall Out" )
+ return KErrNotSupported;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::RemoveFromArray
+// ---------------------------------------------------------------------------
+//
+void CSVPController::RemoveFromArray( CSVPSessionBase& aSession )
+ {
+ SVPDEBUG1( "CSVPController::RemoveFromArray In" )
+
+ // When Sessions destructor is called object be removed from array
+ // manually after when data has been deleted.
+ SVPDEBUG2( "CSVPController::RemoveFromArray aSession: 0x%x", &aSession )
+
+ TInt index = FindSVPSession( aSession.Session() );
+ if ( KErrNotFound != index )
+ {
+ SVPDEBUG1( "CSVPController::RemoveFromArray Session found - removing" )
+ iSessionArray.Remove( index );
+ iSessionArray.Compress();
+ }
+
+ // Try also to remove it from RTCP observer. Ingore the return code, yet
+ // again this is "just in case" thing.
+ iRtpObserver->RemoveSessionFromObserving( &aSession );
+ SVPDEBUG1( "CSVPController::RemoveFromArray Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::FindSVPSession
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::FindSVPSession( const CMceSession& aSession ) const
+ {
+ SVPDEBUG1( "CSVPController::FindSVPSession In" )
+
+ TInt count = iSessionArray.Count();
+ SVPDEBUG2( "CSVPController::FindSVPSession count = %d", count )
+
+ while ( count )
+ {
+ count--;
+
+ if ( &iSessionArray[count]->Session() == &aSession )
+ {
+ SVPDEBUG2( "CSVPController::FindSVPSession Out return: %d", count )
+ return count;
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::FindSVPSession Out return: KErrNotFound" )
+ return KErrNotFound;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::Uid
+// ---------------------------------------------------------------------------
+//
+const TUid& CSVPController::Uid() const
+ {
+ SVPDEBUG1( "CSVPController::Uid" )
+ return KSVPImplementationUid;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CreateNonSecureSessionL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::CreateNonSecureSessionL( TInt aSessionIndex )
+ {
+ SVPDEBUG1( "CSVPController::CreateNonSecureSessionL In" )
+
+ // secure session failed -> create non secure Mo session
+ static_cast< CSVPMoSession* >( iSessionArray[ aSessionIndex ] )->
+ CreateNonSecureSessionL( *iMceManager );
+
+ SVPDEBUG1( "CSVPController::CreateNonSecureSessionL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CheckIfSecureFailed
+// ---------------------------------------------------------------------------
+//
+TBool CSVPController::CheckIfSecureFailed( TInt aStatusCode ) const
+ {
+ SVPDEBUG2( "CSVPController::CheckIfSecureFailed In, aStatusCode: %d", aStatusCode )
+
+ // if secure fails with the following response codes
+ // normal session is tried next
+ if ( KSVPNotAcceptableHereVal == aStatusCode ||
+ KSVPNotAcceptableVal == aStatusCode ||
+ KSVPPreconditionFailureVal == aStatusCode ||
+ KSVPMethodNotAllowedVal == aStatusCode )
+ {
+ SVPDEBUG1( "CSVPController::CheckIfSecureFailed Out ETrue" )
+ return ETrue;
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::CheckIfSecureFailed Out EFalse" )
+ return EFalse;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::SessionStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::SessionStateChanged( CMceSession& aSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged In" )
+
+ // Note, getting the status code may reset it in the container. So do it
+ // only once and be sure that it stays as it should be.
+ const TInt statusCode = aContainer->GetStatusCode();
+ SVPDEBUG2( "CSVPController::SessionStateChanged statusCode: %d", statusCode )
+
+ // check if this is emergency session
+ if ( iEmergencySession )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged, emergency session" )
+
+ if ( CMceSession::EEstablished == aSession.State() )
+ {
+ // Rest of the profiles not needed since session is established
+ iEmergencyProfileIds.Reset();
+ iEmergencyIapIds.Reset();
+ }
+
+ if ( CMceSession::EEstablished == aSession.State() &&
+ iEmergencySession->HasHoldController() &&
+ ( ( iEmergencySession->HoldController() ).HoldInProgress() ||
+ ( iEmergencySession->HoldController() ).HoldRolledBack() ) )
+ {
+ // Handle hold
+ TRAPD( error, iEmergencySession->HoldSessionStateChangedL( aSession ) )
+
+ if ( error )
+ {
+ SVPDEBUG2( "CSVPController::SessionStateChanged, emergency session error %d", error )
+ }
+ }
+ else
+ {
+ iEmergencySession->SessionStateChanged( statusCode );
+ }
+ }
+ else if ( iSessionUpdateOngoing )
+ {
+ // Non-hold session update, e.g. codec renegotiation ongoing; no actions
+ // needed until MCE session state is established.
+ SVPDEBUG1( "CSVPController::SessionStateChanged - MT Session Update" )
+
+ if ( CMceSession::EEstablished == aSession.State() )
+ {
+ // Session update done (Ack received)
+ iSessionUpdateOngoing = EFalse;
+ SVPDEBUG1( "CSVPController::SessionStateChanged - MT Session Updated" )
+ }
+ }
+ else
+ {
+ // fetch correct session
+ const TInt ind = FindSVPSession( aSession );
+
+ // KErrNone = status, status had to be error code
+ if ( KErrNotFound != ind &&
+ iSessionArray[ ind ]->SecurePreferred() &&
+ CheckIfSecureFailed( statusCode ) ||
+ CMceSession::ECancelling == aSession.State() )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged - Secure failed, trying normal session" )
+
+ // trying normal session after secure session trial failed
+ TRAPD( err, CreateNonSecureSessionL( ind ) );
+
+ if ( err )
+ {
+ iSessionArray[ ind ]->GetCCPSessionObserver().
+ ErrorOccurred( ECCPRedirection, iSessionArray[ ind ] );
+ iSessionArray[ ind ]->GetCCPSessionObserver().
+ CallStateChanged( MCCPCallObserver::ECCPStateIdle,
+ iSessionArray[ ind ]);
+ }
+ }
+ else if ( KErrNotFound != ind )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged - Session found" )
+
+ CSVPSessionBase* session = iSessionArray[ ind ];
+
+ if ( !session->CallId() &&
+ KSVPMultipleChoicesVal != statusCode &&
+ KSVPMovedPermanentlyVal != statusCode &&
+ KSVPMovedTemporarilyVal != statusCode )
+ {
+ // CallId not stored yet and not a 3XX case,
+ // check and store headers data.
+ CheckHeadersData( session, aContainer );
+ }
+
+ if ( !session->SecurePreferred() )
+ {
+ session->ReleaseTempSecure();
+ }
+
+ // Release attended transfer target session index
+ // if e.g. early stage session terminate
+ if ( CMceSession::ETerminated == aSession.State() )
+ {
+ iHoldCallIndex = KErrNotFound;
+ }
+
+ if ( CMceSession::EProceeding == aSession.State() )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged EProceeding" )
+
+ if ( KErrNotFound != iHoldCallIndex && iSessionArray.Count() > 1 )
+ {
+ SVPDEBUG3( "CSVPController::SessionStateChanged, atte trans target, ind %d, iHCInd %d",
+ ind, iHoldCallIndex )
+ CheckCallEventToBeSent( session, iSessionArray[iHoldCallIndex] );
+ ExecCbIncomingCall( session, *iSessionArray[iHoldCallIndex] );
+ iHoldCallIndex = KErrNotFound;
+ }
+ else if ( session->HasHoldController() &&
+ ( session->HoldController() ).HoldInProgress() )
+ {
+ // Do nothing here; this only prevents wrong new call
+ // callback to CCP.
+ SVPDEBUG1( "CSVPController::SessionStateChanged - HoldInProgress" )
+ }
+ else if ( session->IsEmptyReInvite() )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged - Empty re-Invite handling ongoing" )
+ }
+ else if ( !session->IsIdle() )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged - NOP" )
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged Incoming" )
+ ExecCbIncomingCall( session );
+ session->SessionStateChanged( statusCode );
+ }
+ }
+ else if ( CMceSession::EEstablished == aSession.State() &&
+ session->HasHoldController() &&
+ ( ( session->HoldController() ).HoldInProgress() ||
+ ( session->HoldController() ).HoldRolledBack() ) )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged EEstablished & HoldController" )
+
+ session->HandleSessionStateChanged( aSession );
+ }
+ else if ( ( CMceSession::EEstablished == aSession.State() ||
+ CMceSession::ETerminated == aSession.State() ) &&
+ KErrNone != statusCode &&
+ KErrNotFound != iIncomingReferCallIndex &&
+ iIncomingReferCallIndex < iSessionArray.Count() &&
+ iSessionArray[ iIncomingReferCallIndex ]->IsIncomingTransfer() )
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged transferor" )
+
+ // Transferor sends notify to original when new session connected/failed.
+ // If secure is mandatory but path unsecure, attended transfer req must be rejected
+ if ( session->SecureMandatory() &&
+ CMceSession::EControlPathUnsecure == aSession.ControlPathSecurityLevel() &&
+ iSessionArray[ iIncomingReferCallIndex ]->IsAttended() )
+ {
+ iSessionArray[ iIncomingReferCallIndex ]->SendNotify( KSVPDeclineVal );
+ }
+ else
+ {
+ iSessionArray[ iIncomingReferCallIndex ]->SendNotify( statusCode );
+ }
+
+ if ( iSessionArray[ iIncomingReferCallIndex ]->IsAttended() )
+ {
+ // remotepartyinfo and/or secure status might have been changed,
+ // proper event will be sent later on.
+ CheckCallEventToBeSent( session, iSessionArray[iIncomingReferCallIndex] );
+ }
+ iIncomingReferCallIndex = KErrNotFound;
+ session->SessionStateChanged( statusCode );
+ }
+ // 3xx Call forward handling
+ else if ( KSVPMultipleChoicesVal == statusCode ||
+ KSVPMovedPermanentlyVal == statusCode ||
+ KSVPMovedTemporarilyVal == statusCode )
+ {
+ HandleCallForward( statusCode, ind, aContainer );
+ }
+ else
+ {
+ if ( ( aSession.State() == CMceSession::EOffering ||
+ aSession.State() == CMceSession::ETerminating ||
+ aSession.State() == CMceSession::ETerminated ) &&
+ iSessionArray[ ind ]->HasHoldController() &&
+ ( ( iSessionArray[ ind ]->HoldController() ).HoldInProgress() ||
+ ( iSessionArray[ ind ]->HoldController() ).HoldRolledBack() ) )
+ {
+ // Failed hold e.g. 408 response
+ SVPDEBUG1("CSVPController::SessionStateChanged()\
+ State change: Failed && HoldController");
+ if ( 491 == statusCode )
+ {
+ SVPDEBUG1(
+ "CSVPController::SessionStateChanged - UpdateFailed()" )
+ UpdateFailed( aSession, aContainer );
+ }
+ else if ( 100 <= statusCode && 200 > statusCode ) // Provisional response
+ {
+ // NOP
+ SVPDEBUG1(
+ "CSVPController::SessionStateChanged - Provisional - NOP" )
+ }
+ else
+ {
+ iSessionArray[ ind ]->HandleSessionStateChanged( aSession );
+ session->SessionStateChanged( statusCode );
+ }
+ }
+
+ else if ( session->HasHoldController() )
+ {
+ // MCE Session Refresh; no actions by the SVP
+ SVPDEBUG1(
+ "CSVPController::SessionStateChanged - Session refresh" )
+ if ( CMceSession::ETerminating == aSession.State() ||
+ CMceSession::ETerminated == aSession.State() )
+ {
+ session->SessionStateChanged( statusCode );
+ }
+ }
+ else if ( !iFailed )
+ {
+ SVPDEBUG1(
+ "CSVPController::SessionStateChanged - Not handled -> Notify session" )
+ session->SessionStateChanged( statusCode );
+ }
+ else
+ {
+ // Failed() callback occurred before EEstablished state
+ // -> No action needed, session termination timer is set
+ }
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::SessionStateChanged else" )
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::SessionStateChanged Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::SessionConnectionStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::SessionConnectionStateChanged(
+ CMceSession& aSession,
+ TBool aActive )
+ {
+ SVPDEBUG2("CSVPController::SessionConnectionStateChanged Active ETrue, Inactive EFalse: %d", aActive )
+
+ if ( iEmergencySession )
+ {
+ iEmergencySession->SessionConnectionStateChanged( aSession, aActive );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::Failed
+// ---------------------------------------------------------------------------
+//
+#ifdef _DEBUG
+void CSVPController::Failed( CMceSession& aSession, TInt aError )
+#else
+void CSVPController::Failed( CMceSession& aSession, TInt /*aError*/ )
+#endif // _DEBUG
+ {
+ SVPDEBUG1("CSVPController::Failed In" )
+ SVPDEBUG2("CSVPController::Failed With error code: %d", aError )
+
+ TInt ind = FindSVPSession( aSession );
+
+ if ( KErrNotFound != ind )
+ {
+ SVPDEBUG1("CSVPController::Failed() Session found")
+
+ if ( &iSessionArray[ ind ]->GetCCPSessionObserver() )
+ {
+ iSessionArray[ ind ]->GetCCPSessionObserver().
+ ErrorOccurred( ECCPErrorConnectionError,
+ iSessionArray[ ind ] );
+
+ // Actually MCE session state should always
+ // be ETerminated when this method is
+ // called; but check anyway:
+ if ( CMceSession::ETerminated == aSession.State() )
+ {
+ iFailed = ETrue;
+ // start termination timer, needed for UI
+ // to handle Disconnected-bubble
+ TRAP_IGNORE( iSessionArray[ ind ]->StartTimerL(
+ KSVPTerminatingTime, KSVPTerminationTimerExpired ) );
+
+ iSessionArray[ ind ]->GetCCPSessionObserver().
+ CallStateChanged( MCCPCallObserver::ECCPStateDisconnecting,
+ iSessionArray[ ind ] );
+
+ SVPDEBUG1("CSVPController::Failed() Session terminating");
+ }
+ }
+ else
+ {
+ iCCPMonitor->ErrorOccurred( MCCPObserver::ECCPIncomingCallFailed );
+ }
+ }
+ else
+ {
+ SVPDEBUG1("CSVPController::Failed() Session not Found!!");
+ }
+
+ SVPDEBUG1("CSVPController::Failed Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::UpdateFailed
+// ---------------------------------------------------------------------------
+//
+void CSVPController::UpdateFailed(
+ CMceSession& aSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::UpdateFailed In" )
+
+ TInt ind = FindSVPSession( aSession );
+ TInt statusCode = aContainer->GetStatusCode();
+
+ SVPDEBUG2( "CSVPController::UpdateFailed statusCode: %d", statusCode )
+
+ if ( KErrNotFound != ind )
+ {
+ iSessionArray[ ind ]->UpdateFailed( aSession, statusCode );
+ }
+ iSessionUpdateOngoing = EFalse;
+ SVPDEBUG1( "CSVPController::UpdateFailed Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::EventStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::EventStateChanged(
+ CMceEvent& aEvent,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController:EventStateChanged In" )
+
+ iContainer = *aContainer;
+ TInt ind = FindSVPSession( *aEvent.AssociatedSession() );
+ TInt statusCode = iContainer.GetStatusCode();
+
+ SVPDEBUG2( "CSVPController:EventStateChanged statusCode: %d", statusCode )
+
+ if ( KErrNotFound != ind )
+ {
+ SVPDEBUG2( "CSVPController::EventStateChanged ind = %d", ind )
+ TInt err = iSessionArray[ ind ]->EventStateChanged( aEvent, statusCode );
+
+ if ( KSVPOKVal == statusCode &&
+ iSessionArray[ ind ]->IsAttended() &&
+ KErrNone == err )
+ {
+ SVPDEBUG1( "CSVPController::EventStateChanged Atte transfer cont." )
+
+ TRAP( err, CreateNewTransferSessionL( ind, ETrue ) );
+
+ if ( err )
+ {
+ SVPDEBUG2( "CSVPController::EventStateChanged: err: %d", err )
+ }
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::EventStateChanged Session not Found!!" )
+ }
+
+ SVPDEBUG1("CSVPController:EventStateChanged OUT");
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::NotifyReceived
+// ---------------------------------------------------------------------------
+//
+void CSVPController::NotifyReceived(
+ CMceEvent& aEvent,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::NotifyReceived In" )
+
+ TInt ind = FindSVPSession( *aEvent.AssociatedSession() );
+
+ if ( KErrNotFound != ind )
+ {
+ iSessionArray[ ind ]->NotifyReceived( aEvent, aContainer );
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::NotifyReceived, session not found !" )
+ }
+
+ SVPDEBUG1( "CSVPController::NotifyReceived Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::EventConnectionStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController:: EventConnectionStateChanged(
+ CMceEvent& /*aEvent*/,
+ TBool /*aActive*/ )
+ {
+ SVPDEBUG1( "CSVPController:: EventConnectionStateChanged In" )
+ SVPDEBUG1( "CSVPController:: EventConnectionStateChanged Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::Failed
+// ---------------------------------------------------------------------------
+//
+#ifdef _DEBUG
+void CSVPController::Failed( CMceEvent& /*aEvent*/, TInt aError )
+#else
+void CSVPController::Failed( CMceEvent& /*aEvent*/, TInt /*aError*/ )
+#endif // _DEBUG
+ {
+ SVPDEBUG2("CSVPController::Failed Event failure, error: %d", aError )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingSession
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingSession(
+ CMceInSession* aSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::IncomingSession In" )
+ SVPDEBUG2( "CSVPController::IncomingSession - status code: %d", aContainer->GetStatusCode() )
+
+ if ( iEmergencySession )
+ {
+ SVPDEBUG1( "CSVPController::IncomingSession - ongoing emergency call - reject incoming call" )
+ TRAP_IGNORE( aSession->RejectL( KSVPBusyHereReason, KSVPBusyHereVal ) )
+ // Ownership of aSession is changed, delete it
+ delete aSession;
+ aSession = NULL;
+ return;
+ }
+
+ // IncomingSessionHandlerL is used to handle possible leave
+ SVPDEBUG1( "CSVPController::IncomingSession IncomingSessionHandlerL" )
+ TRAPD( err, IncomingSessionHandlerL( aSession, aContainer ) );
+
+ if ( err )
+ {
+ SVPDEBUG2( "CSVPController::IncomingSession: err: %d", err )
+
+ // RejectL must be called in case SVP needs to delete session.
+ // TRAP is used because of RejectL might contain a leaver.
+ switch ( err )
+ {
+ case KErrNotSupported:
+ {
+ TRAP( err, aSession->RejectL( KSVPCallTransactDoesNotExistReason,
+ KSVPCallDoesNotExistVal ) );
+ break;
+ }
+
+ case KSVPErrWrongMinSE:
+ // NOP. Reject has been done as a result of call to
+ // IncomingSessionHandlerL.
+ break;
+
+ case KSVPErrDnDRejection:
+ {
+ // Reject call because of Do not Disturb service active.
+ TRAP( err, aSession->RejectL( KSVPBusyHereReason,
+ KSVPBusyHereVal ) );
+ break;
+ }
+
+ case KSVPErrAnonymousCallRejection:
+ {
+ // Reject call because of Anonymous Barring service active.
+ TRAP( err, aSession->RejectL( KSVPNotAcceptableHereReason,
+ KSVPNotAcceptableHereVal ) );
+ break;
+ }
+
+ case KSVPErrCodecMismatch:
+ {
+ TRAP( err, aSession->RejectL( KSVPIncompatibleMediaFormatReason,
+ KSVPNotAcceptableHereVal ) );
+ break;
+ }
+
+ default:
+ {
+ // NOP.
+ break;
+ }
+ }
+
+ if ( KErrNotFound == FindSVPSession( *aSession ) )
+ {
+ // Leave has occured before CSVPMtSession was created.
+ delete aSession;
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::IncomingSession IncomingSessionHandlerL leave occurred" )
+ // clean up session
+ TerminateSession( *aSession );
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::TerminateSession
+// ---------------------------------------------------------------------------
+//
+void CSVPController::TerminateSession( CMceInSession& aSession )
+ {
+ SVPDEBUG1( "CSVPController::TerminateSession In" )
+
+ // find correct session
+ TInt index = FindSVPSession( aSession );
+
+ if ( KErrNotFound != index )
+ {
+ CSVPSessionBase* tempBase = iSessionArray[ index ];
+ // remove session pointer from array and compress array
+ iSessionArray.Remove( index );
+ iSessionArray.Compress();
+
+ // delete session
+ delete tempBase;
+ tempBase = NULL;
+ }
+
+ SVPDEBUG1( "CSVPController::TerminateSession Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CheckMinSessionExpiresL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::CheckMinSessionExpiresL( CMceInSession& aSession,
+ CDesC8Array& aHeaders,
+ TInt aMinSE )
+ {
+ SVPDEBUG1( "CSVPController::CheckMinSessionExpiresL In" )
+
+ TInt count = aHeaders.MdcaCount();
+ TUint32 sessionExpires = 0;
+ TInt error = KErrNone;
+ while ( count-- )
+ {
+ TPtrC8 tmpHeader = aHeaders.MdcaPoint( count );
+ if ( KErrNotFound != tmpHeader.Find( KSVPSessionExpires ) )
+ {
+ // "Session-Expires:" found
+ SVPDEBUG1( "CSVPController::CheckMinSEL: 'Session-Expires:' found" )
+
+ TInt offset = tmpHeader.FindF( KSVPRefresher );
+ if ( KErrNotFound != offset )
+ {
+ tmpHeader.Set( tmpHeader.Left( offset ) );
+ }
+
+ TPtrC8 header;
+ header.Set( tmpHeader );
+ if ( header.FindF( KSVPCln ) )
+ {
+ // 5 digits should be enought for Min-SE
+ // For example: "Min-SE: 1200"
+ TLex8 expires( header.Right( 5 ) );
+ TInt digits = 0;
+ while ( !expires.Eos() )
+ {
+ if ( expires.Peek().IsDigit() )
+ {
+ digits++;
+ }
+ expires.Inc();
+ }
+ TLex8 expiresVal( header.Right( digits ) );
+ error = expiresVal.Val( sessionExpires, EDecimal );
+ SVPDEBUG2(" CSVPController::CheckMinSEL sesExp: %d", sessionExpires )
+
+ if ( error || aMinSE > sessionExpires )
+ {
+ SVPDEBUG2(" CSVPController::CheckMinSEL reject, err: %d", error )
+ CDesC8ArrayFlat* minSEHeader =
+ new ( ELeave ) CDesC8ArrayFlat( 1 );
+ CleanupStack::PushL( minSEHeader ); // CS:0
+
+ HBufC8* header = HBufC8::NewL(
+ KSVPMinExpiresLenght + digits );
+ CleanupStack::PushL( header ); // CS:1
+
+ header->Des().Copy( KSVPMinSessionExpires );
+ header->Des().AppendNum( aMinSE );
+ minSEHeader[ 0 ].AppendL( *header );
+ CleanupStack::PopAndDestroy( header ); // CS:1
+
+ aSession.RejectL( KSVPIntervalTooSmallReason,
+ KSVPSessionIntervalTooSmallVal,
+ minSEHeader );
+
+ // ownership to Mce
+ CleanupStack::Pop( minSEHeader ); // CS:0
+ User::Leave( KSVPErrWrongMinSE );
+ }
+ }
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::CheckMinSessionExpiresL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::FetchExpiresTime
+// ---------------------------------------------------------------------------
+//
+void CSVPController::FetchExpiresTime( TUint32& aExpiresTime,
+ CDesC8Array& aHeaders ) const
+ {
+ SVPDEBUG1( "CSVPController::FetchExpiresTime In" )
+
+ TBool expiresTaken = EFalse;
+ for ( TInt i = 0; i < aHeaders.MdcaCount() && !expiresTaken; i++ )
+ {
+ TPtrC8 tmpHeader = aHeaders.MdcaPoint( i );
+ if ( KErrNotFound != tmpHeader.Find( KSVPExpiresHeader ) &&
+ KErrNotFound == tmpHeader.Find( KSVPSessionExpires ) )
+ {
+ // "Expires:" found
+ SVPDEBUG1(" CSVPController::FetchExpiresTimer: 'Expires:' found")
+
+ TInt colonMark = tmpHeader.FindF( KSVPCln );
+
+ if ( colonMark )
+ {
+
+ TLex8 expires( tmpHeader.Right( 5 ) ); // three digits max
+ TInt digits = 0;
+ while ( !expires.Eos() )
+ {
+ if ( expires.Peek().IsDigit() )
+ {
+ digits++;
+ }
+ expires.Inc();
+ }
+ TLex8 expiresVal( tmpHeader.Right( digits ) );
+ TInt error = expiresVal.Val( aExpiresTime, EDecimal );
+
+ if ( error )
+ {
+ SVPDEBUG2(" CSVPController::FetchExpiresTimer, set default value\
+ Val error: %d", error );
+ // if error occurred, set default time
+ aExpiresTime = KSVPDefaultExpiresTime;
+ expiresTaken = ETrue;
+ }
+ else if ( KSVPDefaultExpiresTime < aExpiresTime )
+ {
+ aExpiresTime = KSVPDefaultExpiresTime;
+ expiresTaken = ETrue;
+ }
+ else
+ {
+ SVPDEBUG2(" CSVPController::FetchExpiresTime: %d", aExpiresTime )
+ expiresTaken = ETrue;
+ }
+ }
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::FetchExpiresTime Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingSessionHandlerL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingSessionHandlerL( CMceInSession* aSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL In" )
+
+ __ASSERT_ALWAYS( aSession, User::Leave( KErrArgument ) );
+ __ASSERT_ALWAYS( aContainer, User::Leave( KErrArgument ) );
+
+ CDesC8Array* headers = aContainer->GetHeaders();
+ __ASSERT_ALWAYS( headers, User::Leave( KErrArgument ) );
+ CleanupStack::PushL( headers ); // CS:1
+
+ IsTransferTargetCaseL( headers );
+
+ // check if Require header contains precondition and that Supported header
+ // includes option tag 100rel, providing support for PRACK's
+ iPreconditions = IsPreconditionRequired( *headers );
+
+ // Default expiration time (120 s) is set due IOP issue,
+ // otherwise incoming call would continue eternity in some cases.
+ TUint32 expireTime = KSVPDefaultExpiresTime;
+ // check if expires header is present and update expiration time
+ FetchExpiresTime( expireTime, *headers );
+
+ // mt session temp
+ CSVPMtSession* mtSessionTemp = NULL;
+
+ CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC(); // CS:2
+
+ RPointerArray< CRCSEProfileEntry > voipProfiles;
+ CleanupResetAndDestroy< RPointerArray< CRCSEProfileEntry > >::PushL(
+ voipProfiles ); // CS:3
+
+ reg->FindBySIPProfileIdL( aSession->Profile(), voipProfiles );
+
+ // Take first profile from the array
+ const TUint32 voipProfileId = voipProfiles[ 0 ]->iId;
+ const TUint32 minSE = voipProfiles[ 0 ]->iSIPMinSE;
+
+ CheckMinSessionExpiresL( *aSession, *headers, minSE );
+
+ SVPDEBUG2("CSVPController::IncomingSessionHandlerL VoIP profile id: %d",
+ voipProfileId );
+
+ // Take first profile from the array
+ const TUint32 serviceId = voipProfiles[ 0 ]->iServiceProviderId;
+
+ SVPDEBUG2("CSVPController::IncomingSessionHandlerL Service id: %d",
+ serviceId );
+
+ // create SIP and ProfileRegistry for profile handling
+ CSIP* sip = CSIP::NewLC( KSVPUid, *this ); // CS: 4
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL sip CREATED" );
+
+ CSIPProfileRegistry* sipProfileRegistry =
+ CSIPProfileRegistry::NewLC( *sip, *this ); // CS: 5
+
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL\
+ profile registry CREATED" );
+
+ // retrieve SIP profile by using sip profile id, note ownership transfer
+ CSIPProfile* profile = sipProfileRegistry->ProfileL( aSession->Profile() );
+
+ // Get keep-alive timer value
+ TUint32 iapId = 0;
+ TBool found = EFalse;
+ TInt keepAliveValue;
+
+ profile->GetParameter( KSIPAccessPointId, iapId );
+
+ TRAPD( errKeepAlive,
+ found = iSVPUtility->GetKeepAliveByIapIdL( iapId, keepAliveValue ) );
+
+ SVPDEBUG3( "CSVPController::IncomingSessionHandlerL\
+ GetKeepAliveByIapIdL: errKeepAlive = %d found = %d",
+ errKeepAlive, found );
+
+ if ( !found )
+ {
+ const TDesC8* aor;
+ profile->GetParameter( KSIPUserAor, aor );
+ TRAP( errKeepAlive, found =
+ iSVPUtility->GetKeepAliveByAORL( *aor, keepAliveValue ) );
+
+ SVPDEBUG3( "CSVPController::IncomingSessionHandlerL\
+ GetKeepAliveByAORL: errKeepAlive = %d found = %d",
+ errKeepAlive, found );
+ }
+
+ delete profile;
+ CleanupStack::PopAndDestroy( 2, sip ); // CS:3
+
+ CMceRtpSource* rtpSource = NULL;
+
+ // modify codecs and codec settings if streams found
+ if ( aSession->Streams().Count() )
+ {
+ const RPointerArray<CMceMediaStream>& streams = aSession->Streams();
+
+ SVPDEBUG2("CSVPController::IncomingSessionHandlerL Streamcount: %d",
+ streams.Count() );
+
+ // disable rtp source and speaker sink so that audio is not on
+ // before session is up signalling-wise
+ for ( TInt i = 0; i < streams.Count(); i++ )
+ {
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL disabling" );
+
+ CMceMediaStream* stream1 = streams[i];
+
+ // if stream is not audio stream -> remove
+ if ( KMceAudio != stream1->Type() )
+ {
+ aSession->RemoveStreamL( *streams[ i ] );
+ }
+ else
+ {
+ // search for RTP source
+ if ( stream1->Source() &&
+ KMceRTPSource == stream1->Source()->Type() )
+ {
+ SVPDEBUG1(
+ "CSVPController::IncomingSessionHandlerL\
+ RTPSource found" );
+
+ rtpSource = static_cast<CMceRtpSource*>(
+ stream1->Source() );
+ }
+
+ SVPAudioUtility::DisableSpeakerSinkL( stream1->Sinks() );
+ SVPAudioUtility::DisableMicSourceL( *stream1 );
+ }
+ }
+
+ // sets MMF priorities and sets codec specific settings
+ CheckStreamsL( *voipProfiles[ 0 ], *aSession, keepAliveValue );
+ if ( rtpSource )
+ {
+ iSVPUtility->UpdateJitterBufferSizeL( *rtpSource );
+ }
+
+ // create SVP Mt session
+ mtSessionTemp = CSVPMtSession::NewL( aSession,
+ iContainer,
+ serviceId,
+ voipProfileId,
+ *this,
+ *iSVPUtility,
+ *iRtpObserver,
+ keepAliveValue,
+ iPreconditions );
+
+ CleanupStack::PushL( mtSessionTemp );
+ FinalizeSessionCreationL( mtSessionTemp );
+ CleanupStack::Pop( mtSessionTemp );
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL NO streams!" );
+
+ // no streams found, handle streams like in Mo-case
+ mtSessionTemp = CSVPMtSession::NewL( aSession,
+ iContainer,
+ serviceId,
+ voipProfileId,
+ *this,
+ *iSVPUtility,
+ *iRtpObserver,
+ keepAliveValue,
+ iPreconditions );
+
+ CleanupStack::PushL( mtSessionTemp );
+ // construct audio streams
+ mtSessionTemp->ConstructAudioStreamsL();
+ FinalizeSessionCreationL( mtSessionTemp );
+ CleanupStack::Pop( mtSessionTemp );
+ }
+
+ CleanupStack::PopAndDestroy( 3, headers ); // CS:0
+
+ // set expires timer
+ if ( expireTime )
+ {
+ SVPDEBUG2( "CSVPController::IncomingSessionHandlerL expireTime: %i s.", expireTime );
+ mtSessionTemp->StartTimerL( KSVPMilliSecondCoefficient * expireTime,
+ KSVPExpiresTimeExpired );
+ }
+
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL Updating call" );
+
+ aSession->UpdateL();
+
+ SVPDEBUG2( "CSVPController::IncomingSessionHandlerL, Call state after update: %i",
+ aSession->State() );
+
+ if ( CMceSession::EProceeding == aSession->State() )
+ {
+ const TInt ind = FindSVPSession( *aSession );
+ iCCPMonitor->IncomingCall( iSessionArray[ ind ] );
+
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL - EProceeding" );
+
+ iSessionArray[ ind ]->SessionStateChanged( KErrNone );
+ }
+
+ // reset flag
+ iPreconditions = EFalse;
+
+ SVPDEBUG1( "CSVPController::IncomingSessionHandlerL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CheckStreamsL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::CheckStreamsL( CRCSEProfileEntry& aVoipProfile,
+ CMceSession& aInSession,
+ TInt aKeepAliveValue,
+ TBool aSessionUpdateOngoing)
+ {
+ SVPDEBUG1( "CSVPController::CheckStreamsL In" )
+
+ __ASSERT_ALWAYS( &aInSession, User::Leave( KErrArgument ) );
+
+ const RPointerArray< CMceMediaStream >& streamArray =
+ aInSession.Streams();
+
+ const TInt streamCount( streamArray.Count() );
+
+ SVPDEBUG3("CSVPController::CheckStreamsL aVoIPProfileId: %u streamCount: %d ",
+ aVoipProfile.iId, streamCount );
+
+ // Set codec settings, this also removes unneeded codecs.
+ for ( TInt i = 0; i < streamCount; i++ )
+ {
+ iSVPUtility->SetAudioCodecsMTL( aVoipProfile,
+ *streamArray[ i ],
+ aKeepAliveValue,
+ aSessionUpdateOngoing );
+
+ // Set the priorities for the remaining codecs. This will handle also the
+ // DTMF priorites once correct codecs are set in the streams. Also note
+ // the downlink/uplink (in/out) discrimination.
+
+ if ( KMceAudio == streamArray[i]->Type() &&
+ streamArray[i]->BoundStream() )
+ {
+ SVPDEBUG2( "CSVPController::CheckStreamsL round: %d start", i )
+
+ CMceAudioStream* stream = static_cast<CMceAudioStream*>( streamArray[i] );
+
+ TBool dtmfMode = EFalse;
+ if ( SVPAudioUtility::IsDownlinkStream( *stream ) )
+ {
+ dtmfMode = SVPAudioUtility::SetPriorityCodecValuesL( *stream,
+ static_cast<CMceAudioStream&>( stream->BoundStreamL() ) );
+ }
+ else
+ {
+ dtmfMode = SVPAudioUtility::SetPriorityCodecValuesL(
+ static_cast<CMceAudioStream&>( stream->BoundStreamL() ),
+ *stream );
+ }
+
+ iSVPUtility->SetDtmfMode( dtmfMode );
+
+ SVPDEBUG2( "CSVPController::CheckStreamsL round: %d done", i )
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::CheckStreamsL Out" )
+ }
+
+// -----------------------------------------------------------------------------
+// CSVPController::GetCallIdFromUserHeadersL
+// Extract call id from user headers
+// -----------------------------------------------------------------------------
+//
+TBool CSVPController::GetCallIdFromUserHeadersL(
+ const CDesC8Array& aUserHeaders,
+ TDes8& aCallId )
+ {
+ // All variables is used for parser.
+ TInt tmpMark1 = 0;
+ TInt tmpMark2 = 0;
+
+ TBool found = EFalse;
+
+ // Find replaces header descriptor from userheaders array.
+ for ( TInt m = 0; &aUserHeaders && m < aUserHeaders.Count() && !found; m++ )
+ {
+ TPtrC8 tmpHeader = aUserHeaders[m];
+ if ( KErrNotFound != tmpHeader.FindF( KSVPReplacesColonTxt ) )
+ {
+ SVPDEBUG1(" CSVPController::\
+ GetCallIdFromUserHeadersL: Replaces: found:");
+
+ // variables used for parse tags from replaces header.
+ tmpMark1 = tmpHeader.Locate( KSVPColonMark );
+ tmpMark2 = tmpHeader.Locate( KSVPSemiColonMark );
+ if ( KErrNotFound == tmpMark1 ||
+ KErrNotFound == tmpMark2 )
+ {
+ SVPDEBUG3("CSVPController::GetCallIdFromUserHeadersL leave \
+ tmpMark1: %d, tmpMark2: %d", tmpMark1, tmpMark2 )
+ User::Leave( KErrArgument );
+ }
+
+ // Call id is between tmpMark1 and tmpMark2 and there is a space
+ // between Replaces: -text and callid
+ if ( ( tmpHeader.Mid( tmpMark1+2, tmpMark2 - tmpMark1 - 2 ).Length() < KSVPTempStringlength ) )
+ {
+ aCallId.Copy(
+ tmpHeader.Mid( tmpMark1+2, tmpMark2 - tmpMark1 - 2 ) );
+
+ found = ETrue;
+ }
+ else
+ {
+ SVPDEBUG1(" CSVPController::\
+ GetCallIdFromUserHeadersL: Replaces: Too long, Leave");
+ User::Leave( KErrArgument );
+ }
+ }
+ }
+
+ SVPDEBUG2( "CSVPController::GetCallIdFromUserHeadersL return %d", found )
+ return found;
+ }
+
+// -----------------------------------------------------------------------------
+// CSVPController::IsTransferTargetCaseL
+// -----------------------------------------------------------------------------
+//
+void CSVPController::IsTransferTargetCaseL( CDesC8Array* aHeaders )
+ {
+ SVPDEBUG1( "CSVPController::IsTransferTargetCaseL In" )
+
+ iHoldCallIndex = KErrNotFound;
+ TBool found = EFalse;
+
+ if ( aHeaders && aHeaders->Count() )
+ {
+ // Variable to contain callID from replaces header.
+ TBuf8< KSVPTempStringlength > repCallId( KNullDesC8 );
+
+ // This is transfer session if Replaces: text is found from userheader
+ if ( GetCallIdFromUserHeadersL( *aHeaders, repCallId ) )
+ {
+ SVPDEBUG1( " CSVPController::IsTransferTargetCaseL: \
+ (attended) Transfer target case" )
+
+ if ( repCallId.Length() != 0 )
+ {
+ // Find from SVP session array a session including same CallId
+ // that parsed from replace header.
+ for ( TInt v = 0; v < iSessionArray.Count() && !found; v++ )
+ {
+ SVPDEBUG2( " CSVPController::IsTransferTargetCaseL v=%d", v )
+
+ TBuf8< KSVPTempStringlength > holdCallId( KNullDesC8 );
+ TDesC8* callid2 = iSessionArray[v]->CallId();
+
+ if ( callid2 )
+ {
+ TInt index = callid2->Find( KSVPCallId_replaces );
+ holdCallId.Append(
+ callid2->Mid( index + KSVPCallId_replaces().Length() ) );
+
+ SVPDEBUG2( "CSVPController::IsTransferTargetCaseL: SesState: %d",
+ iSessionArray[v]->State() )
+
+ if ( repCallId == holdCallId &&
+ MCCPCallObserver::ECCPStateDisconnecting !=
+ iSessionArray[v]->State() )
+ {
+ iHoldCallIndex = v;
+ }
+ }
+ }
+
+ if ( KErrNotFound == iHoldCallIndex )
+ {
+ SVPDEBUG1("CSVPController::IsTransferTargetCaseL: \
+ sessions or CallIds does not match, leave !!!" )
+ User::Leave( KErrNotSupported );
+ }
+ }
+ else
+ {
+ SVPDEBUG1("CSVPController::IsTransferTargetCaseL: \
+ Transfer session but CallId wasn't found, leave !!!" )
+ User::Leave( KErrNotSupported );
+ }
+ }
+ else
+ {
+ TSupplementaryServicesEvent restrictEvent =
+ iSuppServices->CheckRestrictionsL( *aHeaders );
+
+ if ( ESVPSSDoNotDisturb == restrictEvent )
+ {
+ User::Leave( KSVPErrDnDRejection );
+ }
+ if ( ESVPSSAnonymousBarring == restrictEvent )
+ {
+ User::Leave( KSVPErrAnonymousCallRejection );
+ }
+ SVPDEBUG1(" CSVPController::IsTransferTargetCaseL: \
+ Normal incoming case");
+ }
+ }
+
+ SVPDEBUG2( "CSVPController::IsTransferTargetCaseL Out iHoldCallIndex: %d",
+ iHoldCallIndex )
+ }
+
+// --------------------------------------------------------------------------
+// CSVPController::IsPreconditionRequired
+// Check if Require header contains precondition and that Supported header
+// includes option tag 100rel, providing support for PRACK's
+// --------------------------------------------------------------------------
+TBool CSVPController::IsPreconditionRequired( CDesC8Array& aHeaders )
+ {
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired In" )
+
+ TInt count = aHeaders.MdcaCount();
+ TBool require = EFalse;
+ TBool supported = EFalse;
+ while ( count-- )
+ {
+ TPtrC8 tmpHeader = aHeaders.MdcaPoint( count );
+ if ( KErrNotFound != tmpHeader.Find( KSVPRequire ) && !require )
+ {
+ // "Require:" found
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired 'Require-header' found" )
+
+ if ( tmpHeader.FindF( KSVPPrecondition ) )
+ {
+ // "precondition" found in Require header field
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired 'precondition' found" )
+ require = ETrue;
+ }
+ }
+ else if ( KErrNotFound != tmpHeader.Find( KSVPSupported ) && !supported )
+ {
+ // "Supported:" found
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired 'Supported-header' found" )
+
+ if ( tmpHeader.FindF( KSVP100rel ) )
+ {
+ // "100rel" found in Supported header field
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired '100rel' found" )
+ supported = ETrue;
+ }
+ }
+ }
+ if ( require && supported )
+ {
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired return ETrue" )
+ return ETrue;
+ }
+ SVPDEBUG1( "CSVPController::IsPreconditionRequired return EFalse" )
+ return EFalse;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CheckHeadersData
+// Check and store data (FromHeader, ToHeader, CallId) from the headers
+// to the SessionBase.
+// ---------------------------------------------------------------------------
+//
+void CSVPController::CheckHeadersData( CSVPSessionBase* aSVPSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::CheckHeadersData In" )
+
+ TRAPD( stringErr, SIPStrings::OpenL() );
+
+ if ( KErrNone == stringErr )
+ {
+ // get headers
+ CDesC8Array* headers = aContainer->GetHeaders();
+ RStringF fromHdr = SIPStrings::StringF(SipStrConsts::EFromHeader);
+ RStringF fromCompHdr = SIPStrings::StringF(SipStrConsts::EFromHeaderCompact);
+
+ RStringF toHdr = SIPStrings::StringF(SipStrConsts::EToHeader);
+ RStringF toCompHdr = SIPStrings::StringF(SipStrConsts::EToHeaderCompact);
+
+ RStringF callidHdr = SIPStrings::StringF(SipStrConsts::ECallIDHeader);
+ RStringF callidCompHdr = SIPStrings::StringF(SipStrConsts::ECallIDHeaderCompact);
+
+ RStringF cSeqHdr = SIPStrings::StringF(SipStrConsts::ECSeqHeader);
+
+ if ( headers )
+ {
+ TBool fromFound( EFalse );
+ TBool toFound( EFalse );
+ TBool callIdFound( EFalse );
+ TBool cSeqFound( EFalse );
+
+ for( TInt i = 0;i < headers->MdcaCount();i++ )
+ {
+ TPtrC8 tmpHeader = headers->MdcaPoint( i );
+ TInt colonMark = tmpHeader.FindF( KSVPCln );
+
+ SVPDEBUG2( "CSVPController::CheckHeadersData colonMark=%d", colonMark )
+
+ TInt fromHdrPos = tmpHeader.FindF( fromHdr.DesC() );
+ TInt fromCompHdrPos = tmpHeader.FindF( fromCompHdr.DesC() );
+
+ TInt toHdrPos = tmpHeader.FindF( toHdr.DesC() );
+ TInt toCompHdrPos = tmpHeader.FindF( toCompHdr.DesC() );
+
+ TInt callidHdrPos = tmpHeader.FindF( callidHdr.DesC() );
+ TInt callidCompHdrPos = tmpHeader.FindF( callidCompHdr.DesC() );
+
+ TInt cSeqHdrPos = tmpHeader.FindF( cSeqHdr.DesC() );
+
+ // Header name is separeted by colonmark from header body.
+ // There might be space between name and colonmark.
+
+ if ( !fromFound &&
+ ( (KErrNotFound < fromHdrPos && fromHdrPos < colonMark) ||
+ (KErrNotFound < fromCompHdrPos && fromCompHdrPos < colonMark ) ) )
+ {
+ fromFound = ETrue;
+ aSVPSession->SetFromHeader( headers->MdcaPoint( i ) );
+ }
+ else if ( !toFound &&
+ ( (KErrNotFound < toHdrPos && toHdrPos < colonMark) ||
+ (KErrNotFound < toCompHdrPos && toCompHdrPos < colonMark ) ) )
+ {
+ toFound = ETrue;
+ aSVPSession->SetToHeader( headers->MdcaPoint( i ) );
+ }
+ else if ( !callIdFound &&
+ ( (KErrNotFound < callidHdrPos && callidHdrPos < colonMark) ||
+ (KErrNotFound < callidCompHdrPos && callidCompHdrPos < colonMark ) ) )
+ {
+ callIdFound = ETrue;
+ aSVPSession->SetCallId( headers->MdcaPoint( i ) );
+ }
+ else if ( !cSeqFound &&
+ KErrNotFound < cSeqHdrPos && cSeqHdrPos < colonMark )
+ {
+ cSeqFound = ETrue;
+ aSVPSession->SetCSeqHeader( headers->MdcaPoint( i ) );
+ }
+ }
+ }
+
+ SIPStrings::Close();
+ delete headers;
+ headers = NULL;
+ }
+ else
+ {
+ SVPDEBUG2( "CSVPController::CheckHeadersData stringErr=%d", stringErr )
+ }
+
+ SVPDEBUG1( "CSVPController::CheckHeadersData Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CheckContactData
+// Check and store contact data from the headers to the MoSession
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::CheckContactData( CSVPSessionBase* aSVPSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::CheckContactData In" )
+
+ TInt count( 0 );
+ TRAPD( stringErr, SIPStrings::OpenL() );
+
+ if ( KErrNone == stringErr && aSVPSession->IsMobileOriginated() )
+ {
+ CDesC8Array* headers = aContainer->GetHeaders();
+
+ if ( headers )
+ {
+ RStringF contactHdr = SIPStrings::StringF(SipStrConsts::EContactHeader);
+ RStringF contactHdrComp = SIPStrings::StringF(SipStrConsts::EContactHeaderCompact);
+
+ CSVPMoSession* moSession = static_cast< CSVPMoSession* >( aSVPSession );
+ moSession->ResetForwardAddressChoices();
+
+ TInt ret( 0 );
+ for( TInt i( 0 ); i < headers->MdcaCount(); i++ )
+ {
+ TPtrC8 tmpHeader = headers->MdcaPoint( i );
+ TInt colonMark = tmpHeader.FindF( KSVPCln );
+ TPtrC8 left = tmpHeader.Left( colonMark ); // string until to first colon mark
+
+ if ( left.CompareF( contactHdr.DesC() ) == KErrNone ||
+ left.CompareF( contactHdrComp.DesC() ) == KErrNone )
+ {
+ SVPDEBUG1( "CSVPController::CheckContactData - Contact header found" )
+
+ // Get the remaining part of the contact header string and
+ // send it to mo session for parsing
+ TPtrC8 right = tmpHeader.Right(
+ tmpHeader.Length() - left.Length() - 1 );
+
+ TRAPD( addErr, ret = moSession->AddForwardAddressL( right ) );
+ if (KErrNone == addErr)
+ {
+ count = count + ret;
+ }
+ else
+ {
+ SVPDEBUG2( "CSVPController::CheckContactData: addErr = %d", addErr )
+ }
+ }
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::CheckContactData No headers" )
+ }
+
+ SIPStrings::Close();
+ delete headers;
+ headers = NULL;
+ }
+ else
+ {
+ SVPDEBUG2( "CSVPController::CheckContactData stringErr=%d", stringErr )
+ }
+
+ SVPDEBUG2( "CSVPController::CheckContactData Out return=%d", count )
+ return count;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingUpdate
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingUpdate(
+ CMceSession& aOrigSession,
+ CMceInSession* aUpdatedSession,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::IncomingUpdate In" )
+
+ iContainer = *aContainer;
+ const TInt sessionIndex = FindSVPSession( aOrigSession );
+
+ if ( KErrNotFound != sessionIndex )
+ {
+ SVPDEBUG1( "CSVPController::IncomingUpdate - Session found" )
+
+ // handle RE-INVITE without SDP
+ if ( !aUpdatedSession->Streams().Count() )
+ {
+ SVPDEBUG1( "CSVPController::IncomingUpdate No streams present" )
+
+ // this call sets iEmptyReInvite flag to ETrue for session,
+ // flag prevents "ghots session" to be seen on UI
+ // when empty Re-Invite is received
+ iSessionArray[ sessionIndex ]->SetEmptyReInvite();
+
+
+ #ifdef _DEBUG
+
+ TRAPD( noSdpErr, IncomingUpdateNoSdpHandlerL( sessionIndex,
+ aUpdatedSession ) );
+
+ SVPDEBUG2( "CSVPController::IncomingUpdate trapped: %d", noSdpErr )
+
+ #else // _UREL
+
+ TRAP_IGNORE( IncomingUpdateNoSdpHandlerL(
+ sessionIndex, aUpdatedSession ) )
+
+ #endif // _DEBUG
+ }
+
+ else
+ {
+ SVPDEBUG1( "CSVPController::IncomingUpdate - Normal case" )
+ IncomingNormalUpdate( sessionIndex,
+ aOrigSession, aUpdatedSession );
+ }
+
+ SVPDEBUG1( "CSVPController::IncomingUpdate - Handled" )
+ }
+ else if ( iEmergencySession &&
+ aUpdatedSession &&
+ aUpdatedSession->Streams().Count() )
+ {
+ // Handle emergency hold
+ TRAPD( error, iEmergencySession->IncomingRequestL(
+ aUpdatedSession, iContainer ) );
+
+ if ( error )
+ {
+ SVPDEBUG2( "CSVPController::IncomingUpdate, emergency error=%d",
+ error )
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::IncomingUpdate Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingNormalUpdate
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingNormalUpdate( TInt aSessionIndex,
+ CMceSession& aOrigSession,
+ CMceInSession* aUpdatedSession )
+ {
+ SVPDEBUG1( "CSVPController::IncomingNormalUpdate In" )
+
+ TInt err = iSessionArray[ aSessionIndex ]->IncomingRequest(
+ *aUpdatedSession );
+
+ if ( KErrSVPHoldNotHoldRequest == err )
+ {
+ SVPDEBUG1( "CSVPController::IncomingNormalUpdate - Not Hold/Resume" )
+
+ if ( iSessionArray[ aSessionIndex ]->HasHoldController() &&
+ KSVPHoldConnectedStateIndex != iSessionArray[ aSessionIndex ]->
+ HoldController().HoldState() )
+ {
+ // Hold is active; must update MCE streams state
+ // correspondingly
+ TRAP( err, iSessionArray[ aSessionIndex ]->HoldController().
+ RefreshHoldStateL() );
+ SVPDEBUG2( "CSVPController::IncomingNormalUpdate - Err: %d", err )
+ }
+
+ TRAP( err, UpdateSessionL( aOrigSession, *aUpdatedSession ) );
+
+ SVPDEBUG2( "CSVPController::IncomingNormalUpdate - Updated err: %d",
+ err )
+ }
+ else if ( iDtmfStringSending )
+ {
+ SVPDEBUG1( "CSVPController::IncomingNormalUpdate - Dtmf sending will be stopped" )
+ // send stop event to the previous character in string
+ // Default tone char
+ TChar dtmfToneChar( '0' );
+
+ iSessionArray[ aSessionIndex ]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfSequenceStop,
+ KErrNone,
+ dtmfToneChar );
+
+ // send sequence stop event
+ iSessionArray[ aSessionIndex ]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfStringSendingCompleted,
+ KErrNone,
+ dtmfToneChar );
+
+ // sequence complete, clear flags
+ iDtmfStringSending = EFalse;
+ iFirstDtmfSent = EFalse;
+
+ SVPDEBUG1( "CSVPController::IncomingNormalUpdate - Dtmf sending stopped" )
+ }
+ else
+ {
+ SVPDEBUG2( "CSVPController::IncomingNormalUpdate - IncomingRequest err: %d", err )
+ }
+
+ iSessionArray[ aSessionIndex ]->SetUpdatedSession( aUpdatedSession );
+
+ SVPDEBUG1( "CSVPController::IncomingNormalUpdate Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingUpdateNoSdpHandlerL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingUpdateNoSdpHandlerL( TInt aSessionIndex,
+ CMceInSession* aUpdatedSession )
+ {
+ SVPDEBUG1( "CSVPController::IncomingUpdateNoSdpHandlerL In" )
+ if ( iRtpObserver )
+ {
+ iRtpObserver->ResetSessionInObserving( iSessionArray[ aSessionIndex ] );
+ }
+ // set updated session to SVP, ownership is transferred
+ // old session is obsolete
+ iSessionArray[ aSessionIndex ]->SetUpdatedSession( aUpdatedSession );
+
+ // construct audio streams again, adding all the supported codecs
+ iSessionArray[ aSessionIndex ]->ConstructAudioStreamsL();
+
+ // finally update the session
+ aUpdatedSession->UpdateL();
+
+ SVPDEBUG1( "CSVPController::IncomingUpdateNoSdpHandlerL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::UpdateSessionL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::UpdateSessionL( CMceSession& aOrigSession,
+ CMceInSession& aUpdatedSession )
+ {
+ SVPDEBUG1( "CSVPController::UpdateSessionL In" )
+
+ __ASSERT_ALWAYS( &aOrigSession, User::Leave( KErrArgument ) );
+ __ASSERT_ALWAYS( &aUpdatedSession, User::Leave( KErrArgument ) );
+
+ CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC();
+ RPointerArray< CRCSEProfileEntry > voipProfiles;
+ CleanupResetAndDestroy< RPointerArray< CRCSEProfileEntry > >::PushL(
+ voipProfiles );
+
+ reg->FindBySIPProfileIdL( aOrigSession.Profile(), voipProfiles );
+
+ TInt keepAliveTime = 0;
+ TInt index = FindSVPSession( aOrigSession );
+ if ( KErrNotFound != index )
+ {
+ keepAliveTime = iSessionArray[ index ]->GetKeepAliveTime();
+ __ASSERT_ALWAYS( iRtpObserver, User::Leave( KErrTotalLossOfPrecision ) );
+ iRtpObserver->ResetSessionInObserving( iSessionArray[ index ] );
+ }
+
+ // flag prevents wrong handling after SessionStateChanged -callback
+ iSessionUpdateOngoing = ETrue;
+
+ // sets MMF priorities and sets codec specific settings
+ CheckStreamsL( *voipProfiles[ 0 ], aUpdatedSession, keepAliveTime,
+ iSessionUpdateOngoing );
+ CleanupStack::PopAndDestroy( 2, reg );
+
+ SVPDEBUG1( "CSVPController::UpdateSessionL - Checked" )
+
+ aUpdatedSession.UpdateL();
+ SVPDEBUG1( "CSVPController::UpdateSessionL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingRefer
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingRefer( CMceInRefer* aRefer,
+ const TDesC8& aReferTo, TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::IncomingRefer In" )
+
+ // IncomingReferHandlerL is used to handle possible leave
+ SVPDEBUG1( "CSVPController::IncomingRefer IncomingReferHandlerL" )
+ TRAPD( err, IncomingReferHandlerL( aRefer, aReferTo, aContainer ) );
+
+ if ( err )
+ {
+ SVPDEBUG2("CSVPController::IncomingRefer: err: %d", err )
+ // TRAP is used because of RejectL might leave.
+ TRAP( err, aRefer->RejectL() );
+
+ if ( err )
+ {
+ SVPDEBUG2("CSspController::IncomingRefer: RejectL err: %d", err )
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::IncomingRefer Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingReferHandlerL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingReferHandlerL( CMceInRefer* aRefer,
+ const TDesC8& aReferTo, TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::IncomingReferHandlerL In" )
+
+ __ASSERT_ALWAYS( aRefer, User::Leave( KErrArgument ) );
+
+ iContainer = *aContainer;
+ TInt sessionIndex = FindSVPSession( *aRefer->AssociatedSession() );
+
+ if ( KErrNotFound != sessionIndex )
+ {
+ SVPDEBUG2( "CSVPController::InRefHL: AssoSes OK,ind=%d",
+ sessionIndex )
+
+ iSessionArray[ sessionIndex ]->IncomingReferL(
+ aRefer, aReferTo, aContainer );
+
+ if ( iSessionArray[ sessionIndex ]->IsAttended() )
+ {
+ SVPDEBUG1( "CSVPController::InRefHL: - Attended case" )
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::InRefHL: - Unattended case" )
+ // Create a new session
+ CreateNewTransferSessionL( sessionIndex, EFalse );
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::InRefHL: Session not Found!!" )
+ User::Leave( KErrNotFound );
+ }
+
+ SVPDEBUG1( "CSVPController::IncomingReferHandlerL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CreateNewTransferSessionL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::CreateNewTransferSessionL( TInt aSessionIndex,
+ TBool aAttended )
+ {
+ SVPDEBUG1( "CSVPController::CreateNewTransferSessionL In" )
+
+ iIncomingReferCallIndex = aSessionIndex;
+ // Create a new session
+ // fetch SIP profile ID from VoIP profiles
+ RPointerArray< CRCSEProfileEntry > entryArray;
+ CleanupResetAndDestroy<
+ RPointerArray<CRCSEProfileEntry> >::PushL( entryArray ); //CS: 1
+
+ CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC(); //CS:2
+
+ const CCCPCallParameters& callParams = iSessionArray[ aSessionIndex ]->Parameters();
+ SVPDEBUG2(" CSVPController::CNTSL: iServiceId = %d", callParams.ServiceId() )
+
+ // Get VoIP profile by service id
+ reg->FindByServiceIdL( callParams.ServiceId(), entryArray );
+ // Take first entry from array
+ CRCSEProfileEntry* entry = entryArray[0];
+
+ // array for provisioned data
+ CDesC8ArrayFlat* userAgentHeaders = new( ELeave )CDesC8ArrayFlat( 4 );
+ CleanupStack::PushL( userAgentHeaders );
+
+ // variable for storing security status
+ TUint32 securityStatus = 0;
+
+ // set provisioning data
+ SVPDEBUG1( "CSVPController::CNTSL: Set provisioning data..." )
+ TRAP_IGNORE( iSVPUtility->SetProvisioningDataL(
+ *entry,
+ *userAgentHeaders,
+ securityStatus,
+ iTerminalType,
+ iWlanMacAddress ) );
+
+ // only one sip profile per voip profile
+ TInt sipProfileId = entry->iIds[ 0 ].iProfileId;
+ SVPDEBUG2( "CSVPController::CNTSL: sipProfileId=%d", sipProfileId )
+
+ if ( KSVPStatusNonSecure != securityStatus )
+ {
+ // If preferred sec is 1 or 2, we check also secure mechanism of sip profile.
+ // create SIP and ProfileRegistry for URI handling
+ CSIP* sip = CSIP::NewL( KSVPUid, *this );
+ CleanupStack::PushL( sip );
+ SVPDEBUG1( "CSVPController::CNTSL: sip CREATED" )
+
+ CSIPProfileRegistry* sipProfileRegistry =
+ CSIPProfileRegistry::NewL( *sip, *this );
+ CleanupStack::PushL( sipProfileRegistry );
+
+ SVPDEBUG1( "CSVPController::CNTSL: sipProfileRegistry CREATED" )
+
+ // retrieve SIP profile by using sip profile id
+ CSIPProfile* profile = sipProfileRegistry->ProfileL( sipProfileId );
+ CleanupStack::PushL( profile );
+
+ // set secure status to 0 if no security mechanism found from SIP profile
+ iSVPUtility->ResolveSecurityMechanismL( *profile, securityStatus );
+
+ CleanupStack::PopAndDestroy( 3, sip ); // profile, sipProfileRegistry, sip
+ }
+
+ // set transfer data
+ SVPDEBUG1( "CSVPController::CNTSL: Set transfer data..." )
+ iSessionArray[ aSessionIndex ]->SetTransferDataL(
+ userAgentHeaders, securityStatus );
+
+ SVPDEBUG3( "CSVPController::CNTSL: Header count:%d, sec status:%d",
+ userAgentHeaders->Count(), securityStatus )
+
+ CSVPMoSession* moSessionTemp = NULL;
+
+ // In attended and unattended transfer case recipient is solved here
+ SVPDEBUG1( "CSVPController::CNTSL: (Un)Attended, create new mo session" )
+ const TDesC& referTo = iSessionArray[ aSessionIndex ]->TransferTarget();
+ // "convert" recpient to 8-bit format
+ HBufC8* recipient = HBufC8::NewLC( referTo.Length() );
+ recipient->Des().Copy( referTo );
+
+ moSessionTemp = CSVPMoSession::NewL( *iMceManager,
+ *recipient,
+ *entry,
+ callParams,
+ iContainer,
+ *this,
+ *iSVPUtility,
+ *iRtpObserver,
+ securityStatus,
+ userAgentHeaders );
+
+ CleanupStack::PopAndDestroy( recipient );
+ CleanupStack::PushL( moSessionTemp );
+
+ // dtmf and rtp observervers are set
+ moSessionTemp->SetDtmfObserver( iSessionArray[ aSessionIndex ]->DtmfObserver() );
+ iRtpObserver->AddSessionForObservingL( moSessionTemp );
+
+ // created SVP session is appended to session array
+ iSessionArray.AppendL( moSessionTemp );
+ CleanupStack::Pop( moSessionTemp );
+ CleanupStack::Pop( userAgentHeaders );
+ CleanupStack::PopAndDestroy( 2, &entryArray );
+
+ // set CCP session observer to SVP session
+ SVPDEBUG1( "CSVPController::CNTSL: AddObserverL" )
+ moSessionTemp->AddObserverL( iSessionArray[ aSessionIndex ]->GetCCPSessionObserver() );
+
+ //set CCP supplementary services events observer to SVP session
+ SVPDEBUG1( "CSVPController::CNTSL: AddSsObserverL" )
+ moSessionTemp->SetSsObserver( iSessionArray[ aSessionIndex ]->GetSsObserver() );
+
+ SVPDEBUG1( "CSVPController::CNTSL: callcreated, send to CCP" )
+ ExecCbCallCreated( moSessionTemp, iSessionArray[ aSessionIndex ], aAttended );
+
+ SVPDEBUG1( "CSVPController::CreateNewTransferSessionL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::HandleForwardEvent
+// ---------------------------------------------------------------------------
+//
+void CSVPController::HandleCallForward( TInt aStatusCode,
+ TInt aSessionIndex, TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::HandleForwardEvent In" )
+ SVPDEBUG2( "CSVPController::HandleForwardEvent aStatusCode=%d", aStatusCode )
+
+ if ( !iSessionArray[ aSessionIndex ]->IsMobileOriginated() )
+ {
+ iSessionArray[ aSessionIndex ]->
+ GetCCPSessionObserver().ErrorOccurred( ECCPErrorNotReached,
+ iSessionArray[ aSessionIndex ] );
+ }
+ else
+ {
+ CSVPMoSession* session = static_cast< CSVPMoSession* >(
+ iSessionArray[ aSessionIndex ] );
+
+ switch ( aStatusCode )
+ {
+ case KSVPMultipleChoicesVal: // 300
+ case KSVPMovedPermanentlyVal: // 301
+ {
+ // Get contact headers and notify
+ TInt count = CheckContactData( session, aContainer );
+
+ if ( 0 < count )
+ {
+ session->NotifyForwardEvent( aStatusCode );
+ }
+ else
+ {
+ session->GetCCPSessionObserver().ErrorOccurred(
+ ECCPErrorNotReached,
+ session );
+ }
+ break;
+ }
+ case KSVPMovedTemporarilyVal: // 302
+ {
+ // Just notify, this call forward is handled automatically by mce
+ session->NotifyForwardEvent( aStatusCode );
+ session->GetCCPSessionObserver().
+ CallStateChanged( MCCPCallObserver::ECCPStateForwarding,
+ session );
+ break;
+ }
+ default:
+ {
+ SVPDEBUG1( "CSVPController::HandleForwardEvent: unknown code" )
+ session->GetCCPSessionObserver().ErrorOccurred(
+ ECCPErrorNotReached,
+ session );
+ }
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::HandleForwardEvent Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::StreamStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::StreamStateChanged( CMceMediaStream& aStream )
+ {
+ SVPDEBUG1("CSVPController::StreamStateChanged In" )
+
+ if ( &aStream )
+ {
+ if ( !iEmergencySession )
+ {
+ const TInt index = FindSVPSession( *aStream.Session() );
+ if ( KErrNotFound != index )
+ {
+ iSessionArray[ index ]->HandleStreamStateChange( aStream );
+ }
+
+ SVPDEBUG2( "CSVPController::StreamStateChanged index: %d", index )
+ }
+ else // Emergency session
+ {
+ iEmergencySession->StreamStateChanged( aStream );
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::StreamStateChanged, faulty arguments" )
+ }
+
+ SVPDEBUG1("CSVPController::StreamStateChanged Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::StreamStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::StreamStateChanged( CMceMediaStream& aStream,
+ CMceMediaSink& aSink )
+ {
+ SVPDEBUG1( "CSVPController::StreamStateChanged SINK In" )
+
+ if ( &aStream && &aSink )
+ {
+ SVPDEBUG2( "CSVPController::StreamStateChanged SINK Stream State: %d", aStream.State() )
+ SVPDEBUG2( "CSVPController::StreamStateChanged SINK Sink IsEnabled: %d", aSink.IsEnabled() )
+
+ if ( !iEmergencySession )
+ {
+ const TInt index = FindSVPSession( *aStream.Session() );
+
+ if ( KErrNotFound != index )
+ {
+ iSessionArray[ index ]->HandleStreamStateChange( aStream, aSink );
+ }
+
+ SVPDEBUG2( "CSVPController::StreamStateChanged SINK index: %d", index )
+ }
+ else // Emergency session
+ {
+ iEmergencySession->StreamStateChanged( aStream );
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::StreamStateChanged SINK, faulty arguments" )
+ }
+
+ SVPDEBUG1( "CSVPController::StreamStateChanged SINK Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::StreamStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::StreamStateChanged( CMceMediaStream& aStream,
+ CMceMediaSource& aSource )
+ {
+ SVPDEBUG1( "CSVPController::StreamStateChanged SOURCE In" )
+
+ if ( &aStream && &aSource )
+ {
+ SVPDEBUG2( "CSVPController::StreamStateChanged SOURCE Stream State: %d", aStream.State() )
+ SVPDEBUG2( "CSVPController::StreamStateChanged SOURCE Source IsEnabled: %d", aSource.IsEnabled() )
+
+ if ( !iEmergencySession )
+ {
+ const TInt index = FindSVPSession( *aStream.Session() );
+ if ( KErrNotFound != index )
+ {
+ iSessionArray[ index ]->HandleStreamStateChange( aStream, aSource );
+ }
+
+ SVPDEBUG2( "CSVPController::StreamStateChanged SOURCE index: %d", index )
+ }
+ else // Emergency session
+ {
+ iEmergencySession->StreamStateChanged( aStream );
+ }
+
+ }
+
+ SVPDEBUG1( "CSVPController::StreamStateChanged SOURCE Out" )
+ }
+
+
+// from ConvergedCallProvider
+// ---------------------------------------------------------------------------
+// CSVPController::NewEmergencyCallL
+// ---------------------------------------------------------------------------
+//
+MCCPEmergencyCall* CSVPController::NewEmergencyCallL(
+ const TUint32 /*aServiceId*/,
+ const TDesC& aAddress,
+ const MCCPCallObserver& aObserver )
+ {
+ SVPDEBUG1( "CSVPController::NewEmergencyCallL In" )
+
+ // Retrieve available VoIP and IAP IDs
+ if ( 0 == iEmergencyProfileIds.Count() && 0 == iEmergencyIapIds.Count() )
+ {
+ CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC(); // CS:1
+ CSIP* sip = CSIP::NewLC( KSVPUid, *this ); // CS:2
+ CSIPProfileRegistry* sipProfileRegistry = CSIPProfileRegistry::NewLC(
+ *sip, *this ); // CS:3
+
+ // Get all VoIP profile IDs into an array
+ RArray< TUint32 > voipProfileIds;
+ CleanupClosePushL( voipProfileIds ); //CS: 4
+ reg->GetAllIdsL( voipProfileIds );
+
+ // Sort the VoIP profile array so that registered profiles are first
+ for ( TInt i = 0; i < voipProfileIds.Count(); i++ )
+ {
+ TBool registered( EFalse );
+ CRCSEProfileEntry* entry = CRCSEProfileEntry::NewLC(); // CS:5
+ reg->FindL( voipProfileIds[i], *entry );
+ // There is only one (or zero) SIP profile per VoIP profile.
+ // If profileId is not found,
+ // CSVPEmergencySession::ConstructL will handle the error
+ if ( 0 < entry->iIds.Count() )
+ {
+ SVPDEBUG2( "CSVPController::NewEmergencyCallL, SIP Id count:%d",
+ entry->iIds.Count() )
+ CSIPProfile* sipProfile = sipProfileRegistry->ProfileL(
+ entry->iIds[0].iProfileId );
+ sipProfile->GetParameter( KSIPProfileRegistered, registered );
+ delete sipProfile;
+ }
+ CleanupStack::PopAndDestroy( entry ); // CS:4
+ if ( registered )
+ {
+ // Move registered VoIP profile IDs to the front
+ iEmergencyProfileIds.Insert( voipProfileIds[i], 0 );
+ }
+ else
+ {
+ iEmergencyProfileIds.Append( voipProfileIds[i] );
+ }
+ }
+
+ CleanupStack::PopAndDestroy( 4, reg );
+ // CS:0 voipProfileIds, sipProfileRegistry, sip, reg
+
+ // Request and wait for IAP IDs
+ CSVPEmergencyIapProvider* iapProvider =
+ CSVPEmergencyIapProvider::NewLC(
+ CActive::EPriorityStandard ); // CS:1
+ iapProvider->RequestIapIds( iEmergencyIapIds );
+ CleanupStack::PopAndDestroy( iapProvider ); // CS:0
+ }
+
+ SVPDEBUG2("CSVPController::NewEmergencyCallL, VoIP count:%d",
+ iEmergencyProfileIds.Count() )
+ SVPDEBUG2("CSVPController::NewEmergencyCallL, IAP count:%d",
+ iEmergencyIapIds.Count() )
+
+ // Define last try
+ TBool isLastId( EFalse );
+
+ if ( ( 0 == iEmergencyProfileIds.Count() &&
+ 1 == iEmergencyIapIds.Count() ) ||
+ ( 1 == iEmergencyProfileIds.Count() &&
+ 0 == iEmergencyIapIds.Count() )
+ )
+ {
+ isLastId = ETrue;
+ SVPDEBUG1("CSVPController::NewEmergencyCallL, last ID");
+ }
+
+ // Create session
+ CSVPEmergencySession* emergencySession = NULL;
+
+ if ( iEmergencyProfileIds.Count() )
+ {
+ // Create emergency session with VoIP ID
+ TRAPD( err, emergencySession = CSVPEmergencySession::NewL(
+ *iMceManager,
+ iEmergencyProfileIds[0],
+ aAddress,
+ aObserver,
+ *iSVPUtility,
+ isLastId ) )
+
+ if ( err )
+ {
+ // Create dummy session for session release
+ emergencySession = CSVPEmergencySession::NewL(
+ *iMceManager,
+ iEmergencyProfileIds[0],
+ aAddress,
+ aObserver,
+ *iSVPUtility,
+ isLastId,
+ ETrue );
+ }
+
+ // Update profile array
+ iEmergencyProfileIds.Remove( 0 );
+ }
+ else if ( iEmergencyIapIds.Count() )
+ {
+ // Create emergency session with IAP ID
+ TRAPD( err, emergencySession = CSVPEmergencySession::NewL(
+ *iMceManager,
+ aAddress,
+ aObserver,
+ *iSVPUtility,
+ iEmergencyIapIds[0],
+ isLastId ) )
+
+ if ( err )
+ {
+ // Create dummy session for session release
+ emergencySession = CSVPEmergencySession::NewL(
+ *iMceManager,
+ aAddress,
+ aObserver,
+ *iSVPUtility,
+ iEmergencyIapIds[0],
+ isLastId,
+ ETrue );
+ }
+
+ // Update IAP array
+ iEmergencyIapIds.Remove( 0 );
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ // save emergency session to controller
+ iEmergencySession = emergencySession;
+
+ if ( iCCPDtmfObserver )
+ {
+ SVPDEBUG1( "CSVPController::NewEmergencyCallL setting DTMFObserver" )
+ iEmergencySession->SetDtmfObserver( *iCCPDtmfObserver );
+ }
+
+ SVPDEBUG1( "CSVPController::NewEmergencyCallL Out" )
+ // return pointer to CCP emergency call object
+ return emergencySession;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::NewConferenceL
+// ---------------------------------------------------------------------------
+//
+MCCPConferenceCall* CSVPController::NewConferenceL(
+ const TUint32 /* aServiceId */,
+ const MCCPConferenceCallObserver& /*aObserver*/ )
+ {
+ return NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::AcceptTransfer
+// ---------------------------------------------------------------------------
+//
+void CSVPController::AcceptTransfer( TBool /*aAccept*/ )
+ {
+ SVPDEBUG1( "CSVPController::AcceptTransfer In" )
+ SVPDEBUG1( "CSVPController::AcceptTransfer Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ForwardCallToAddressL
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ForwardCallToAddressL( const TInt /*aIndex*/ )
+ {
+ return NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::Caps
+// ---------------------------------------------------------------------------
+//
+TUint32 CSVPController::Caps() const
+ {
+ return 0;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::DTMFProvider
+// ---------------------------------------------------------------------------
+//
+MCCPDTMFProvider* CSVPController::DTMFProviderL(
+ const MCCPDTMFObserver& aObserver )
+ {
+ SVPDEBUG1( "CSVPController::DTMFProviderL In" )
+
+ iCCPDtmfObserver = &aObserver;
+
+ TInt sessions = iSessionArray.Count();
+ while ( sessions )
+ {
+ sessions--;
+ iSessionArray[ sessions ]->SetDtmfObserver( aObserver );
+
+ SVPDEBUG2( "CSVPController::DTMFProviderL sessions: %d", sessions )
+ }
+
+ if ( iEmergencySession )
+ {
+ iEmergencySession->SetDtmfObserver( aObserver );
+ }
+
+ SVPDEBUG1( "CSVPController::DTMFProviderL Out" )
+ return this;
+ }
+
+
+// ---------------------------------------------------------------------------
+// CSVPController::ExtensionProvider
+// ---------------------------------------------------------------------------
+//
+MCCPExtensionProvider* CSVPController::ExtensionProviderL(
+ const MCCPExtensionObserver& /*aObserver*/ )
+ {
+ return NULL;
+ }
+
+// dtmf provider
+
+// ---------------------------------------------------------------------------
+// CSVPController::CancelDtmfStringSending
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::CancelDtmfStringSending()
+ {
+ SVPDEBUG1( "CSVPController::CancelDtmfStringSending In" )
+
+ TInt err( KErrNotSupported );
+ // find active session
+
+ TInt sesCount = iSessionArray.Count();
+ CSVPSessionBase* session = NULL;
+ while ( sesCount )
+ {
+ sesCount--;
+ session = iSessionArray[ sesCount ];
+
+ if ( SVPAudioUtility::DtmfActionCapableSession( *session ) )
+ {
+ err = session->CancelDtmfStringSending();
+ }
+ SVPDEBUG3( "CSVPController::CancelDtmfStringSending sesCount: %d, err: %d",
+ sesCount, err )
+ session = NULL;
+ }
+
+ if ( iEmergencySession &&
+ SVPAudioUtility::DtmfActionCapableSession( *iEmergencySession ) )
+ {
+ err = iEmergencySession->CancelDtmfStringSending();
+ }
+
+ SVPDEBUG2("CSVPController::CancelDtmfStringSending Out return=%d", err )
+ iDtmfStringSending = EFalse;
+ iFirstDtmfSent = EFalse;
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::StartDtmfTone
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::StartDtmfTone( const TChar aTone )
+ {
+ SVPDEBUG1( "CSVPController::StartDtmfTone In" )
+
+ TInt err( KErrNotSupported );
+
+ // Save DTMF tone for later use in outband dtmf start/stop events
+ iDtmfTone = aTone;
+ // Send the tone to all sessions, but check mute and hold cases where session must
+ // be in 'connected' state in order to send DTMF's. Session will then
+ // discriminate between inband and outband DTMF's.
+ TInt sesCount = iSessionArray.Count();
+ CSVPSessionBase* session = NULL;
+ while ( sesCount )
+ {
+ sesCount--;
+ session = iSessionArray[ sesCount ];
+ // Checking hold and mute status
+ if ( SVPAudioUtility::DtmfActionCapableSession( *session ) &&
+ !session->IsSessionMuted() )
+ {
+ err = session->StartDtmfTone( aTone );
+ }
+ SVPDEBUG3( "CSVPController::StartDtmfTone sesCount: %d, err: %d",
+ sesCount, err )
+ session = NULL;
+ }
+
+ if ( iEmergencySession &&
+ SVPAudioUtility::DtmfActionCapableSession( *iEmergencySession ) )
+ {
+ err = iEmergencySession->StartDtmfTone( aTone );
+ }
+
+ SVPDEBUG2("CSVPController::StartDtmfTone Out return=%d", err )
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::StopDtmfTone
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::StopDtmfTone()
+ {
+ SVPDEBUG1( "CSVPController::StopDtmfTone In" )
+
+ TInt err( KErrNotSupported );
+
+ TInt sesCount = iSessionArray.Count();
+ CSVPSessionBase* session = NULL;
+ while ( sesCount )
+ {
+ sesCount--;
+ session = iSessionArray[ sesCount ];
+
+ if ( SVPAudioUtility::DtmfActionCapableSession( *session ) )
+ {
+ err = session->StopDtmfTone();
+ }
+ SVPDEBUG3( "CSVPController::StopDtmfTone sesCount: %d, err: %d",
+ sesCount, err )
+ session = NULL;
+ }
+
+ if ( iEmergencySession &&
+ SVPAudioUtility::DtmfActionCapableSession( *iEmergencySession ) )
+ {
+ err = iEmergencySession->StopDtmfTone();
+ }
+
+ SVPDEBUG2("CSVPController::StopDtmfTone Out return=%d", err )
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::SendDtmfToneString
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::SendDtmfToneString( const TDesC& aString )
+ {
+ SVPDEBUG1( "CSVPController::SendDtmfToneString In" )
+
+ TInt err( KErrNotSupported );
+
+ delete iDtmfString;
+ iDtmfString = NULL;
+ TRAPD( errBuf, iDtmfString = HBufC::NewL( aString.Length() ) );
+ if ( KErrNone != errBuf )
+ {
+ return errBuf;
+ }
+ // Take local copy of the dtmf string to be sent
+ // This is needed for outband dtmf sequence start/stop event
+ *iDtmfString = aString;
+ iDtmfStringLex.Assign( *iDtmfString );
+
+ TInt sesCount = iSessionArray.Count();
+ CSVPSessionBase* session = NULL;
+
+ while ( sesCount )
+ {
+ sesCount--;
+ session = iSessionArray[ sesCount ];
+ // Checking hold and mute status
+ if ( SVPAudioUtility::DtmfActionCapableSession( *session ) &&
+ !session->IsSessionMuted() )
+ {
+ err = session->SendDtmfToneString( aString );
+ if ( KErrNone == err )
+ {
+ iDtmfStringSending = ETrue;
+ iFirstDtmfSent = EFalse;
+ }
+ }
+ SVPDEBUG3( "CSVPController::SendDtmfToneString sesCount: %d, err: %d",
+ sesCount, err )
+ session = NULL;
+ }
+
+ if ( iEmergencySession )
+ {
+ if ( SVPAudioUtility::DtmfActionCapableSession( *iEmergencySession ) )
+ {
+ err = iEmergencySession->SendDtmfToneString( aString );
+ }
+ iDtmfStringSending = ETrue;
+ iFirstDtmfSent = EFalse;
+ }
+
+ SVPDEBUG2("CSVPController::SendDtmfToneString Out return=%d", err )
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ContinueDtmfStringSending
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ContinueDtmfStringSending( const TBool /*aContinue*/ )
+ {
+ // SVP sessionbase used to implement this as only returning
+ // KErrNotSupported, so why not accept the situation here and just
+ // return KErrNotSupported.
+
+ SVPDEBUG1( "CSVPController::ContinueDtmfStringSending KErrNotSupported" )
+ return KErrNotSupported;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::AddObserverL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::AddObserverL( const MCCPDTMFObserver& /*aObserver*/ )
+ {
+ SVPDEBUG1( "CSVPController::AddObserverL MCCPDTMFObserver" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::RemoveObserver
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::RemoveObserver( const MCCPDTMFObserver& /*aObserver*/ )
+ {
+ SVPDEBUG1( "CSVPController::RemoveObserver MCCPDTMFObserver" )
+ return KErrNotSupported;
+ }
+
+
+// refer observer
+
+// ---------------------------------------------------------------------------
+// CSVPController::ReferStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::ReferStateChanged( CMceRefer& aRefer,
+ TMceTransactionDataContainer* aContainer )
+ {
+ SVPDEBUG1( "CSVPController::ReferStateChanged In" )
+
+ iContainer = *aContainer;
+ TInt ind = KErrNotFound;
+
+ // loop session array and check refer
+ for ( TInt s = 0; s < iSessionArray.Count() &&
+ KErrNotFound == ind; s++ )
+ {
+ if ( iSessionArray[ s ]->IsMceRefer( aRefer ) )
+ {
+ ind = s;
+ }
+ }
+
+ if ( KErrNotFound != ind )
+ {
+ SVPDEBUG2(" CSVPController::ReferStateChanged ind: %d", ind );
+ TInt statusCode = iContainer.GetStatusCode();
+
+ iSessionArray[ ind ]->ReferStateChanged( aRefer, statusCode );
+ }
+
+ SVPDEBUG1( "CSVPController::ReferStateChanged Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ReferConnectionStateChanged
+// ---------------------------------------------------------------------------
+//
+void CSVPController::ReferConnectionStateChanged( CMceRefer& /*aRefer*/,
+ TBool /*aActive*/ )
+ {
+ SVPDEBUG1( "CSVPController::ReferConnectionStateChanged" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::Failed
+// ---------------------------------------------------------------------------
+//
+#ifdef _DEBUG
+void CSVPController::Failed( CMceRefer& /*aRefer*/, TInt aError )
+#else
+void CSVPController::Failed( CMceRefer& /*aRefer*/, TInt /*aError*/ )
+#endif // _DEBUG
+ {
+ SVPDEBUG2( "CSVPController::Failed Refer failed with error: %d", aError )
+ }
+
+
+// Mce DMTF observer
+// ---------------------------------------------------------------------------
+// CSVPController::DtmfToneReceived
+// ---------------------------------------------------------------------------
+//
+void CSVPController::DtmfToneReceived( CMceSession& /*aSession*/,
+ CMceAudioStream& /*aStream*/, const TChar& /*aTone*/ )
+ {
+ // Not supported
+ SVPDEBUG1( "CSVPController:: DtmfToneReceived - Not supported" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::DtmfEventReceived
+// ---------------------------------------------------------------------------
+//
+void CSVPController::DtmfEventReceived( CMceSession& aSession,
+ CMceAudioStream& /*aStream*/,
+ CMceMediaSource& /*aSource*/,
+ TMceDtmfEvent aEvent )
+ {
+ SVPDEBUG3( "CSVPController::DtmfEventReceived In, aEvent: %d, iDtmfStringSending: %d",
+ aEvent, iDtmfStringSending )
+
+ // find what session received the event
+ const TInt index = FindSVPSession( aSession );
+
+ if ( KErrNotFound != index )
+ {
+ // match dtmf event
+ MCCPDTMFObserver::TCCPDtmfEvent dtmfEvent =
+ iSVPUtility->GetDtmfEvent( aEvent, iDtmfStringSending );
+
+ // dtmf string
+ if ( iDtmfStringSending )
+ {
+ // only start event received from mce
+ // logic below needed so that stop events can be sent
+ if ( MCCPDTMFObserver::ECCPDtmfSequenceStart == dtmfEvent )
+ {
+ if ( !iFirstDtmfSent )
+ {
+ SVPDEBUG1( "CSVPController::DtmfEventReceived FIRST SEND" )
+
+ // send start
+ iFirstDtmfSent = ETrue;
+ // call back event to application
+ iSessionArray[ index ]->
+ DtmfObserver().HandleDTMFEvent( dtmfEvent,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::DtmfEventReceived STOP TO PREVIOUS" )
+
+ // send stop event to the previous character in string
+ iSessionArray[ index ]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfSequenceStop,
+ KErrNone,
+ iDtmfStringLex.Get() );
+ SVPDEBUG1("CSVPController::DtmfEventReceived START TO CURRENT");
+ // send start event to the current character in string
+ iSessionArray[ index ]->DtmfObserver().HandleDTMFEvent(
+ dtmfEvent,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+ }
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::DtmfEventReceived STOP TO PREVIOUS AND LAST" )
+
+ // send stop event to the previous character in string
+ iSessionArray[ index ]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfSequenceStop,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+
+ SVPDEBUG1( "CSVPController::DtmfEventReceived COMPLETE" )
+
+ // send sequence stop event
+ iSessionArray[ index ]->DtmfObserver().HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfStringSendingCompleted,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+ // sequence complete, clear flags
+ iDtmfStringSending = EFalse;
+ iFirstDtmfSent = EFalse;
+
+ delete iDtmfString;
+ iDtmfString = NULL;
+ }
+ }
+ // manual dtmf
+ else
+ {
+ // call back event to application
+ iSessionArray[ index ]->DtmfObserver().HandleDTMFEvent(
+ dtmfEvent,
+ KErrNone,
+ iDtmfTone );
+ }
+ }
+
+ else if ( iEmergencySession )
+ {
+ const MCCPDTMFObserver& dtmfObs = iEmergencySession->DtmfObserver();
+ SVPDEBUG2("CSVPController::DtmfEventReceived, %d = DtmfObserver()", &dtmfObs )
+ // match dtmf event
+ MCCPDTMFObserver::TCCPDtmfEvent dtmfEvent =
+ iSVPUtility->GetDtmfEvent( aEvent, iDtmfStringSending );
+
+ // dtmf string
+ if ( iDtmfStringSending && NULL != &dtmfObs )
+ {
+ // only start event received from mce
+ // logic below needed so that stop events can be sent
+ if ( MCCPDTMFObserver::ECCPDtmfSequenceStart == dtmfEvent )
+ {
+ if ( !iFirstDtmfSent )
+ {
+ SVPDEBUG1(
+ "CSVPController::DtmfEventReceived, emergency FIRST SEND")
+
+ // send start
+ iFirstDtmfSent = ETrue;
+ // call back event to application
+ dtmfObs.HandleDTMFEvent( dtmfEvent, KErrNone, iDtmfStringLex.Peek() );
+ }
+ else
+ {
+ SVPDEBUG1("CSVPController::DtmfEventReceived,\
+ emergency STOP TO PREVIOUS")
+
+ // send stop event to the previous character in string
+ dtmfObs.HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfSequenceStop,
+ KErrNone,
+ iDtmfStringLex.Get() );
+ SVPDEBUG1("CSVPController::DtmfEventReceived,\
+ emergency START TO CURRENT")
+ // send start event to the current character in string
+ dtmfObs.HandleDTMFEvent(
+ dtmfEvent,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+ }
+ }
+ else
+ {
+ SVPDEBUG1("CSVPController::DtmfEventReceived,\
+ emergency STOP TO PREVIOUS AND LAST")
+
+ // send stop event to the previous character in string
+ dtmfObs.HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfSequenceStop,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+
+ SVPDEBUG1("CSVPController::DtmfEventReceived,\
+ emergency COMPLETE")
+
+ // send sequence stop event
+ dtmfObs.HandleDTMFEvent(
+ MCCPDTMFObserver::ECCPDtmfStringSendingCompleted,
+ KErrNone,
+ iDtmfStringLex.Peek() );
+ // sequence complete, clear flags
+ iDtmfStringSending = EFalse;
+ iFirstDtmfSent = EFalse;
+
+ delete iDtmfString;
+ iDtmfString = NULL;
+ }
+ }
+ // manual dtmf
+ else if( NULL != &dtmfObs )
+ {
+ SVPDEBUG1("CSVPController::DtmfEventReceived,\
+ manual dtmf , call back event to application")
+ dtmfObs.HandleDTMFEvent( dtmfEvent, KErrNone, iDtmfTone );
+ }
+ else
+ {
+ SVPDEBUG1("CSVPController::DtmfEventReceived, DtmfObs not set")
+ }
+ }
+
+ SVPDEBUG1( "CSVPController::DtmfEventReceived Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::DtmfErrorOccured
+// ---------------------------------------------------------------------------
+//
+ void CSVPController::DtmfErrorOccured( CMceSession& aSession,
+ CMceAudioStream& /*aStream*/,CMceMediaSource& /*aSource*/,
+ TInt aError )
+ {
+ SVPDEBUG2( "CSVPController::DtmfErrorOccured In, aError: %d", aError )
+
+ // find what session received the event
+ const TInt index = FindSVPSession( aSession );
+ if ( KErrNotFound != index )
+ {
+ // match dtmf event, unknown set as default in error case, 'tis ok?
+ const MCCPDTMFObserver::TCCPDtmfEvent dtmfEvent =
+ MCCPDTMFObserver::ECCPDtmfUnknown;
+
+ // default tone char
+ TChar dtmfToneChar('0');
+
+ // call back error
+ iSessionArray[ index ]->
+ DtmfObserver().HandleDTMFEvent( dtmfEvent,
+ aError,
+ dtmfToneChar );
+ }
+
+ SVPDEBUG1( "CSVPController::DtmfErrorOccured Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::FinalizeSessionCreationL
+// ---------------------------------------------------------------------------
+//
+void CSVPController::FinalizeSessionCreationL( CSVPSessionBase* aSession )
+ {
+ SVPDEBUG2( "CSVPController::FinalizeSessionCreationL In, aSession: 0x%x",
+ aSession )
+
+ __ASSERT_ALWAYS( aSession, User::Leave( KErrArgument ) );
+
+ if ( iCCPDtmfObserver )
+ {
+ aSession->SetDtmfObserver( *iCCPDtmfObserver );
+ }
+
+ iRtpObserver->AddSessionForObservingL( aSession );
+ iSessionArray.AppendL( aSession );
+
+ SVPDEBUG1( "CSVPController::FinalizeSessionCreationL Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ExecCbErrorOccurred
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ExecCbErrorOccurred( MCCPObserver::TCCPError aError )
+ {
+ SVPDEBUG2( "CSVPController::ExecCbErrorOccurred In, aError=%d", aError )
+
+ TInt status = KErrNotFound;
+
+ if ( iCCPMonitor )
+ {
+ status = KErrNone;
+ iCCPMonitor->ErrorOccurred( aError );
+ }
+
+ SVPDEBUG2( "CSVPController::ExecCbErrorOccurred Out return=%d", status )
+ return status;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IncomingCall
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ExecCbIncomingCall( MCCPCall* aCall )
+ {
+ SVPDEBUG2( "CSVPController::ExecCbIncomingCall In, aCall= 0x%x", aCall )
+
+ TInt status = KErrNotFound;
+
+ if ( iCCPMonitor )
+ {
+ status = KErrNone;
+ iCCPMonitor->IncomingCall( aCall );
+ }
+
+ SVPDEBUG2( "CSVPController::ExecCbIncomingCall Out return=%d", status )
+ return status;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ExecCbIncomingCall
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ExecCbIncomingCall( MCCPCall* aCall, MCCPCall& aTempCall )
+ {
+ SVPDEBUG2( "CSVPController::ExecCbIncomingCall In, aCall= 0x%x", aCall )
+ SVPDEBUG2( "CSVPController::ExecCbIncomingCall aTempCall= 0x%x", &aTempCall )
+
+ TInt status = KErrNotFound;
+
+ if ( iCCPMonitor )
+ {
+ status = KErrNone;
+ iCCPMonitor->IncomingCall( aCall, aTempCall );
+ }
+
+ SVPDEBUG2( "CSVPController::ExecCbIncomingCall Out return=%d", status )
+ return status;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ExecCbCallCreated
+// ---------------------------------------------------------------------------
+//
+TInt CSVPController::ExecCbCallCreated( MCCPCall* aNewTransferCall,
+ MCCPCall* aOriginator, TBool aAttended )
+ {
+ SVPDEBUG2( "CSVPController::ExecCbCallCreated In, aNewTransferCall= 0x%x", aNewTransferCall )
+ SVPDEBUG2( "CSVPController::ExecCbCallCreated aOriginator= 0x%x", aOriginator )
+ SVPDEBUG2( "CSVPController::ExecCbCallCreated aAttended= %d", aAttended )
+
+ TInt status = KErrNotFound;
+
+ if ( iCCPMonitor )
+ {
+ status = KErrNone;
+ iCCPMonitor->CallCreated( aNewTransferCall, aOriginator, aAttended );
+ }
+
+ SVPDEBUG2( "CSVPController::ExecCbCallCreated Out return=%d", status )
+ return status;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::ParseRecipientDtmfSuffixL
+// ---------------------------------------------------------------------------
+//
+HBufC* CSVPController::ParseRecipientDtmfSuffixL( const TDesC& aRecipient ) const
+ {
+ __ASSERT_ALWAYS( &aRecipient, User::Leave( KErrArgument ) );
+
+ SVPDEBUG2( "CSVPController::ParseRecipientDtmfSuffixL In, aRecipient=%S", &aRecipient )
+
+ HBufC* result = aRecipient.AllocLC(); // CS:1
+
+ TInt recipientLength = result->Length();
+ if ( recipientLength )
+ {
+ if ( IsValidDtmfRecipientL( *result ) )
+ {
+ TInt loopCount = 0;
+ if ( KErrNotFound != KSVPDtmfTelNumRange().Locate( result->Des()[loopCount] ) )
+ {
+ loopCount++;
+ TBool doLoop = ETrue;
+ do
+ {
+ if ( loopCount < recipientLength )
+ {
+ if ( KErrNotFound !=
+ KSVPDtmfDelimiterRange().Locate( result->Des()[loopCount] ) )
+ {
+ TInt suffixLength = recipientLength - loopCount;
+ result->Des().Delete( loopCount, suffixLength );
+ doLoop = EFalse;
+ SVPDEBUG1(
+ "CSVPController::ParseRecipientDtmfSuffixL, DTMF suffix removed" )
+ }
+ else
+ {
+ loopCount++;
+ }
+ }
+ else
+ {
+ doLoop = EFalse;
+ }
+ } while ( doLoop );
+ }
+ }
+ }
+ SVPDEBUG2( "CSVPController::ParseRecipientDtmfSuffixL Out, result=%S", result )
+ CleanupStack::Pop( result ); // CS:0
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::IsValidDtmfRecipientL
+// ---------------------------------------------------------------------------
+//
+TBool CSVPController::IsValidDtmfRecipientL( const TDesC& aRecipient ) const
+ {
+ __ASSERT_ALWAYS( &aRecipient, User::Leave( KErrArgument ) );
+
+ SVPDEBUG1( "CSVPController::IsValidDtmfRecipientL In" )
+
+ TBool result = ETrue;
+ if ( aRecipient.Length() )
+ {
+ TBool loopDo = ETrue;
+ TInt loopCount = 0;
+ do
+ {
+ if ( loopCount < aRecipient.Length() )
+ {
+ if ( KErrNotFound == KSVPDtmfAllValidChars().Locate( aRecipient[loopCount] ) )
+ {
+ result = EFalse;
+ loopDo = EFalse;
+ }
+ else
+ {
+ loopCount++;
+ }
+ }
+ else
+ {
+ loopDo = EFalse;
+ }
+ } while ( loopDo );
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::IsValidDtmfRecipientL, Invalid recipient length" )
+ result = EFalse;
+ }
+ SVPDEBUG2( "CSVPController::IsValidDtmfRecipientL Out, result=%d" , result )
+ return result;
+ }
+
+// ---------------------------------------------------------------------------
+// CSVPController::CheckCallEventToBeSent
+// ---------------------------------------------------------------------------
+//
+void CSVPController::CheckCallEventToBeSent( CSVPSessionBase* aNewSVPSession,
+ CSVPSessionBase* aOldSVPSession ) const
+ {
+ SVPDEBUG1( "CSVPController::CheckCallEventToBeSent In" )
+
+ if ( aOldSVPSession->IsSecured() != aNewSVPSession->IsSecured() )
+ {
+ // Session secure status changed, need to send proper event
+ if ( aNewSVPSession->IsSecured() )
+ {
+ SVPDEBUG1( "CSVPController::CheckCallEventToBeSent, unsecure -> secure case" )
+ aNewSVPSession->SetCallEventToBeSent( MCCPCallObserver::ECCPSecureCall );
+ }
+ else
+ {
+ SVPDEBUG1( "CSVPController::CheckCallEventToBeSent, secure -> unsecure case" )
+ aNewSVPSession->SetCallEventToBeSent( MCCPCallObserver::ECCPNotSecureCall );
+ }
+ }
+ else
+ {
+ // remoteparty will be updated anyway after attended transfer
+ SVPDEBUG1( "CSVPController::CheckCallEventToBeSent, remoteparty will be updated after attended transfer" )
+ aNewSVPSession->SetCallEventToBeSent( MCCPCallObserver::ECCPNotifyRemotePartyInfoChange );
+ }
+ SVPDEBUG1( "CSVPController::CheckCallEventToBeSent Out" )
+ }
+
+// ---------------------------------------------------------------------------
+// From class MSIPObserver
+// CSVPController::IncomingRequest
+// ---------------------------------------------------------------------------
+//
+void CSVPController::IncomingRequest(
+ TUint32 /*aIapId*/, CSIPServerTransaction* /*aTransaction*/ )
+ {
+ SVPDEBUG1( "CSVPController::IncomingRequest" )
+ }
+
+// ---------------------------------------------------------------------------
+// From class MSIPObserver
+// CSVPController::TimedOut
+// ---------------------------------------------------------------------------
+//
+void CSVPController::TimedOut(
+ CSIPServerTransaction& /*aSIPServerTransaction*/ )
+ {
+ SVPDEBUG1( "CSVPController::TimedOut" )
+ }
+
+// ---------------------------------------------------------------------------
+// From class MSIPProfileRegistryObserver
+// CSVPController::ProfileRegistryErrorOccurred
+// ---------------------------------------------------------------------------
+//
+void CSVPController::ProfileRegistryErrorOccurred(
+ TUint32 /*aSIPProfileId*/, TInt /*aError*/ )
+ {
+ SVPDEBUG1( "CSVPController::ProfileRegistryErrorOccurred" )
+ }
+
+// ---------------------------------------------------------------------------
+// From class MSIPProfileRegistryObserver
+// CSVPController::ProfileRegistryEventOccurred
+// ---------------------------------------------------------------------------
+//
+void CSVPController::ProfileRegistryEventOccurred(
+ TUint32 /*aProfileId*/, TEvent /*aEvent*/ )
+ {
+ SVPDEBUG1( "CSVPController::ProfileRegistryEventOccurred" )
+ }
+