sipvoipprovider/src/svpcontroller.cpp
changeset 0 a4daefaec16c
child 8 7117cbf1600a
--- /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" )
+    }
+