callcontinuity/vcc/src/cvccperformer.cpp
branchRCL_3
changeset 22 d38647835c2e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/callcontinuity/vcc/src/cvccperformer.cpp	Wed Sep 01 12:29:57 2010 +0100
@@ -0,0 +1,988 @@
+/*
+* Copyright (c) 2008 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:   CCP reference plug-in implementation.
+*
+*/
+
+#include <mccpcall.h>
+#include <mccpcallobserver.h>
+#include "ccpdefs.h" 
+#include <mccpforwardprovider.h>
+
+#include "vccdefinitions.h"
+#include "cvccperformer.h"
+#include "vcchotrigger.h"
+#include "vccsettingsreader.h"
+#include "cvcctransferprovider.h"
+
+//state machine
+#include "tvccstateinit.h"
+#include "tvccstatecalling.h"
+#include "tvccstatefailing.h"
+#include "tvccstatereleasing.h"
+#include "rubydebug.h"
+
+_LIT( KSVPSipPrefix, "sip:" );
+// -----------------------------------------------------------------------------
+// 
+// -----------------------------------------------------------------------------
+//
+CVccPerformer::CVccPerformer(RPointerArray<CConvergedCallProvider>& aProviders,
+							 TVccState& aState, CVccHoTrigger& aVccHoTrigger,
+							 TBool aCsOriginated ) :
+    iProviders(aProviders),
+    iCurrentState(&aState),
+    iVccHoTrigger( aVccHoTrigger ),
+    iCsOriginated( aCsOriginated),
+    iTransferProvider( NULL ),
+    iRemotePartiesSet( EFalse )
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::CVccPerformer" );
+    }
+
+// -----------------------------------------------------------------------------
+// Default C++ destructor.
+// -----------------------------------------------------------------------------
+//
+CVccPerformer::~CVccPerformer()
+    {
+    RUBY_DEBUG0( "CVccPerformer::~CVccPerformer() - ENTER" );
+	delete iVccPsp;
+	delete iTransferProvider;
+    RUBY_DEBUG0( "CVccPerformer::~CVccPerformer() - EXIT" );
+    }
+// -----------------------------------------------------------------------------
+// Call creating comes here. In MT case observer is null and CCE will call
+// SetObserver later on for us
+// -----------------------------------------------------------------------------
+//
+CVccPerformer* CVccPerformer::NewL(
+						RPointerArray<CConvergedCallProvider>& aProviders, 
+						TVccState& aState,
+						CVccHoTrigger& aVccHoTrigger,
+						TBool aCsOriginated)
+    {
+    RUBY_DEBUG_BLOCKL( "CVccPerformer::NewL" );
+    CVccPerformer* self = new( ELeave ) CVccPerformer(aProviders, 
+    													aState, 
+    													aVccHoTrigger,
+    													aCsOriginated);
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop(self);
+
+    return self;
+    }
+// -----------------------------------------------------------------------------
+// 
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::ConstructL()
+    {
+    RUBY_DEBUG_BLOCKL( "CVccPerformer::ConstructL" );
+        
+    iVccPsp = CVccEngPsProperty::NewL();
+    }
+
+// -----------------------------------------------------------------------------
+// User has answered the incoming call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Answer()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Answer" );
+ 	return iCurrentState->Answer(*iPrimaryCall);
+    }
+    
+// -----------------------------------------------------------------------------
+// User has rejected the incoming call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Reject()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Reject" );
+  	return iCurrentState->Reject(*iPrimaryCall);
+    }
+    
+// -----------------------------------------------------------------------------
+// Queue incoming call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Queue()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Queue" );
+ 	return iCurrentState->Queue(*iPrimaryCall);
+    }
+    
+// -----------------------------------------------------------------------------
+// Dial a new call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Dial()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Dial" );
+ 	return iCurrentState->Dial(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// MT call user ringing now
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Ringing()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Ringing" );
+	return iCurrentState->Ringing(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// End current call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::HangUp()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::HangUp" );
+    return iCurrentState->HangUp(*this, *iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Cancel ongoing request
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Cancel()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Cancel" );
+  	return iCurrentState->Cancel(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Hold call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Hold()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Hold" );
+    return iCurrentState->Hold(*iPrimaryCall); 
+    }
+
+// -----------------------------------------------------------------------------
+// Resume held call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Resume()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Resume" );
+ 	return iCurrentState->Resume(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Swap hold/resume states
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Swap()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Swap" );
+    return iCurrentState->Swap(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Get call recipient
+// -----------------------------------------------------------------------------
+//
+const TDesC& CVccPerformer::RemoteParty() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::RemoteParty" );
+    
+    return iOrigRemoteParty;
+    }
+
+// -----------------------------------------------------------------------------
+// RemotePartyName
+// -----------------------------------------------------------------------------
+//
+const TDesC& CVccPerformer::RemotePartyName()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::RemotePartyName" );
+    return iOrigRemotePartyName;
+    //return iCurrentState->RemoteParty(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Get call recipient
+// -----------------------------------------------------------------------------
+//
+const TDesC& CVccPerformer::DialledParty() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::DialledParty" );
+    return iCurrentState->DialledParty(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Is call forwarded or not
+// -----------------------------------------------------------------------------
+//
+TBool CVccPerformer::IsCallForwarded() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::IsCallForwarded " );
+ 	return iCurrentState->IsCallForwarded(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Is call mobile originated or not
+// -----------------------------------------------------------------------------
+//
+TBool CVccPerformer::IsMobileOriginated() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::IsMobileOriginated" );
+ 	return iCurrentState->IsMobileOriginated(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Get current call state
+// -----------------------------------------------------------------------------
+//
+MCCPCallObserver::TCCPCallState CVccPerformer::State() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::State " );
+ 	return iCurrentState->State(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Get plug-in UID
+// -----------------------------------------------------------------------------
+//
+TUid CVccPerformer::Uid() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Uid " );
+  
+    return TUid::Uid( KVccCallProviderPlugId );
+    }
+
+// -----------------------------------------------------------------------------
+// get call capabilities
+// -----------------------------------------------------------------------------
+//
+MCCPCallObserver::TCCPCallControlCaps CVccPerformer::Caps() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::CVccPerformer" );
+ 	return iCurrentState->Caps(*iPrimaryCall);
+    }
+
+
+// -----------------------------------------------------------------------------
+// SecureSpecified()
+// -----------------------------------------------------------------------------
+//
+TBool CVccPerformer::SecureSpecified() const
+    {
+    return iCurrentState->SecureSpecified( *iPrimaryCall );
+    }
+// -----------------------------------------------------------------------------
+// Is call secured
+// -----------------------------------------------------------------------------
+//
+TBool CVccPerformer::IsSecured() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::IsSecured" );
+    return iCurrentState->IsSecured(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Set parameters
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::SetParameters( const CCCPCallParameters& aNewParams )
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::SetParameters " );
+    iCurrentState->SetParameters(aNewParams);
+    }
+
+// -----------------------------------------------------------------------------
+// Get parameters
+// -----------------------------------------------------------------------------
+//
+const CCCPCallParameters& CVccPerformer::Parameters() const
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::Parameters" );
+    return iCurrentState->Parameters(*iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Return used tone.
+// -----------------------------------------------------------------------------
+//
+TCCPTone CVccPerformer::Tone() const
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::Tone " );
+	return iCurrentState->Tone(*iPrimaryCall);
+	}
+  
+// -----------------------------------------------------------------------------
+// Get forward call enabling methods for the call
+// -----------------------------------------------------------------------------
+//
+MCCPForwardProvider* CVccPerformer::ForwardProviderL
+                                        ( const MCCPForwardObserver& aObserver )
+    {
+    RUBY_DEBUG_BLOCKL( "CVccPerformer::ForwardProviderL " );
+ 	return iPrimaryCall->ForwardProviderL(aObserver);
+    }
+
+// -----------------------------------------------------------------------------
+// Get transfer call enabling methods for the call
+// -----------------------------------------------------------------------------
+//
+MCCPTransferProvider* CVccPerformer::TransferProviderL
+                                        ( const MCCPTransferObserver& aObserver )
+    {
+    RUBY_DEBUG_BLOCKL( "CVccPerformer::TransferProviderL " );
+	if ( !iTransferProvider )
+          {    
+          iTransferProvider = CVccTransferProvider::NewL(this);
+          iTransferProvider->AddObserverL( aObserver );
+          }
+      
+    return iTransferProvider;
+    }
+
+// -----------------------------------------------------------------------------
+// Add observer.
+// the CCE will call that in the MT call case, to put the observer for a call in place
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::AddObserverL( const MCCPCallObserver& aObserver )
+    {
+    RUBY_DEBUG_BLOCKL( "CVccPerformer::AddObserverL " );
+ 	iCallObs = const_cast<MCCPCallObserver*>( &aObserver );
+ 	iCurrentState->AddObserverL(*this, *iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// remove observer.
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::RemoveObserver(const MCCPCallObserver& aObserver )
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::RemoveObserver " );
+	return iCurrentState->RemoveObserver(aObserver, *iPrimaryCall);
+    }
+
+// -----------------------------------------------------------------------------
+// Dial from MCCPCSCall
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::Dial( const TDesC8& aCallParams )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::Dial" );
+	return iCurrentState->Dial(aCallParams, 
+	                        *static_cast<MCCPCSCall*>(iPrimaryCall));
+	}
+
+// -----------------------------------------------------------------------------
+// NoFDNCheck from MCCPCSCall
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::NoFDNCheck()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::NoFDNCheck " );
+	iCurrentState->NoFDNCheck(*static_cast<MCCPCSCall*>(iPrimaryCall));
+	}
+
+// -----------------------------------------------------------------------------
+// GetMobileCallInfo from MCCPCSCall
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::GetMobileCallInfo( TDes8& aCallInfo ) const
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::GetMobileCallInfo " );
+	return iCurrentState->GetMobileCallInfo(aCallInfo,
+	                          *static_cast<MCCPCSCall*>(iPrimaryCall));
+	}
+	
+// -----------------------------------------------------------------------------
+// SwitchAlternatingCall from MCCPCSCall
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::SwitchAlternatingCall()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::SwitchAlternatingCall " );
+	return iCurrentState->SwitchAlternatingCall(
+	                         *static_cast<MCCPCSCall*>(iPrimaryCall));
+	}
+
+// -----------------------------------------------------------------------------
+// GetMobileDataCallCaps from MCCPCSCall
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::GetMobileDataCallCaps( TDes8& aCaps ) const
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::GetMobileDataCallCaps " );
+	return iCurrentState->GetMobileDataCallCaps(aCaps,
+	                          *static_cast<MCCPCSCall*>(iPrimaryCall));
+	}
+
+// -----------------------------------------------------------------------------
+// LogDialedNumber from MCCPCSCall
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::LogDialedNumber() const
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::LogDialedNumber " );
+	return iCurrentState->LogDialedNumber(
+	                          *static_cast<MCCPCSCall*>(iPrimaryCall) );
+	}
+	
+// -----------------------------------------------------------------------------
+// MCCPCallObserver:: ErrorOccurred
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::ErrorOccurred(const TCCPError aError, MCCPCall* aCall )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::TCCPError ");	
+	iCurrentState->ErrorOccurred(*this, aError, aCall );
+	}
+	
+// -----------------------------------------------------------------------------
+// MCCPCallObserver:: CallStateChanged
+// -----------------------------------------------------------------------------
+//	
+void CVccPerformer::CallStateChanged( 
+                                   const MCCPCallObserver::TCCPCallState aState, 
+                                   MCCPCall* aCall  )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::CallStateChanged ");
+	iCurrentState->CallStateChanged( *this, aState, aCall );		
+	}
+
+// -----------------------------------------------------------------------------
+// MCCPCallObserver:: CallStateChangedWithInband
+// -----------------------------------------------------------------------------
+//	
+void CVccPerformer::CallStateChangedWithInband( 
+                                   const MCCPCallObserver::TCCPCallState aState,
+                                   MCCPCall* aCall )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::CallStateChanged ");
+	iCurrentState->CallStateChangedWithInband( *this, aState, aCall );
+	}
+
+// -----------------------------------------------------------------------------
+// MCCPCallObserver::CallEventOccurred
+// -----------------------------------------------------------------------------
+//	
+void CVccPerformer::CallEventOccurred( 
+                                   const MCCPCallObserver::TCCPCallEvent aEvent, 
+                                   MCCPCall* aCall  )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::CallEventOccurred ");
+	iCurrentState->CallEventOccurred(*this, aEvent, aCall);
+	}
+	
+// -----------------------------------------------------------------------------
+// MCCPCallObserver::CallCapsChanged
+// -----------------------------------------------------------------------------
+//	
+void CVccPerformer::CallCapsChanged(const TUint32 aCapsFlags, MCCPCall* aCall )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::CallCapsChanged");
+	iCurrentState->CallCapsChanged(*this, aCapsFlags, aCall );
+	}
+
+// -----------------------------------------------------------------------------
+//  Get CallObserver()
+// -----------------------------------------------------------------------------
+//
+MCCPCallObserver* CVccPerformer::CallObserver()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::CallObserver " );
+  	return iCallObs;
+    }
+
+// -----------------------------------------------------------------------------
+//  Creates actual implementation
+// -----------------------------------------------------------------------------
+//
+MCCPCall* CVccPerformer::CreatePrimaryCallL( 
+                                 const CCCPCallParameters& aParameters,
+                                 const TDesC& aRecipient,
+                                 const MCCPCallObserver& aObserver )
+	{
+    RUBY_DEBUG_BLOCKL( "CVccPerformer::CreatePrimaryCallL" );
+
+    iPrimaryCall = NULL;
+    TInt index = KErrNotFound;
+    if (aParameters.CallType() != CCPCall::ECallTypePS )
+	    {
+	    index = VoipProviderIndex( EFalse );
+	    }
+    else
+ 	    {
+ 	    index = VoipProviderIndex( ETrue );
+ 	    }
+    if( index != KErrNotFound )
+        {
+        iPrimaryCall = iProviders[ index ]->NewCallL(aParameters, aRecipient, *this);
+        }
+            
+	if( !iPrimaryCall )
+	    {
+	    User::Leave( KErrNotFound );
+	    }
+    iCallObs = const_cast< MCCPCallObserver* >( &aObserver ); 
+    
+    SetRemoteParties();
+    
+	return this;
+	}
+	
+// -----------------------------------------------------------------------------
+//  saves incoming call and returns itself
+// -----------------------------------------------------------------------------
+//
+MCCPCall* CVccPerformer::IncomingCall( MCCPCall* aCall )
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::IncomingCall" );
+    iPrimaryCall = aCall;
+    SetRemoteParties();
+    
+    return this;
+     }
+
+// -----------------------------------------------------------------------------
+//  saves 3rd party mo call and returns itself
+// -----------------------------------------------------------------------------
+//
+MCCPCall* CVccPerformer::MoCall( MCCPCall* aCall )
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::MoCall" );
+    iPrimaryCall = aCall;
+    return this;
+     }
+
+// -----------------------------------------------------------------------------
+//  Returns actual call implementation
+// -----------------------------------------------------------------------------
+//	
+MCCPCall* CVccPerformer::PrimaryCall()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::PrimaryCall" );
+	return iPrimaryCall;	
+	}
+	
+// -----------------------------------------------------------------------------
+//  Returns actual CS provider implementation
+// -----------------------------------------------------------------------------
+//
+CConvergedCallProvider& CVccPerformer::CsProvider()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::CsProvider" );
+	return *iProviders[ VoipProviderIndex( EFalse ) ];
+	            
+	}
+	
+// -----------------------------------------------------------------------------
+//  Returns actual PS provider implementation
+// -----------------------------------------------------------------------------
+//
+CConvergedCallProvider& CVccPerformer::PsProvider()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::PsProvider" );
+	return *iProviders[ VoipProviderIndex( ETrue ) ];
+	}
+
+// -----------------------------------------------------------------------------
+//  Updates the actual call
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::SetCall(MCCPCall* aCall)
+    {
+    TRAP_IGNORE( SetCallL( aCall) );
+    }
+
+
+// -----------------------------------------------------------------------------
+//  Updates the actual call
+// -----------------------------------------------------------------------------
+//
+void CVccPerformer::SetCallL(MCCPCall* aCall)
+	{
+	__ASSERT_DEBUG(aCall == iSecondaryCall, User::Leave(KErrArgument));
+    RUBY_DEBUG_BLOCK( "CVccPerformer::SetCall" );
+    
+    //inform through phone engine to phone about call bubble update needs
+    MCCPCallObserver::TCCPCallEvent event = 
+                              MCCPCallObserver::ECCPNotifyRemotePartyInfoChange;
+    iCallObs->CallEventOccurred( event, this );
+    
+    //both secure call and not secure call events result in same 
+    //securestatuschanged message in phone engine.
+        
+        
+    MCCPCall* temp = iPrimaryCall;
+	iPrimaryCall = aCall;
+	iSecondaryCall = temp; //taking old call pointer
+	if (iTransferProvider)
+	    {
+	    iTransferProvider->UpdateL();
+	    }
+
+	MCCPCallObserver::TCCPCallEvent event2;
+	//if( iPrimaryCall->IsSecured() )
+	//    {
+	//    event2 = MCCPCallObserver::ECCPSecureCall;
+	//    }
+	//else
+	//    {
+	    event2 = MCCPCallObserver::ECCPNotSecureCall;
+	//    }
+    iCallObs->CallEventOccurred( event2, this );
+        
+	}
+	
+// -----------------------------------------------------------------------------
+//  Releases ongoing call
+// -----------------------------------------------------------------------------
+//
+TInt CVccPerformer::ReleaseCall(MCCPCall& /*aCall*/)
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::ReleaseCall" );
+	TInt err = KErrNotFound;
+	err = iCurrentState->ReleaseCall(*iPrimaryCall, iProviders);
+	iPrimaryCall = NULL;
+	return err;
+	}
+	
+// -----------------------------------------------------------------------------
+//  Suppressor calls this when HO is done
+// -----------------------------------------------------------------------------
+//    
+void CVccPerformer::HandoverReady()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::HandoverReady" );    
+	iSecondaryCall = NULL;
+    ActivateTrigger( ETrue );
+    //get new service id for voip call and set it to parameters
+    //this is used later for loading correct CTI plugins
+    TInt VoIPServiceId(KErrNotFound);
+    TRAP_IGNORE( VoIPServiceId = VccSettingsReader::VoIPServiceIdL() );
+    RUBY_DEBUG1( "CVccPerformer::HandoverReady() -- new Service Id: %d", VoIPServiceId );
+    CCCPCallParameters* params = NULL;
+    TRAP_IGNORE( params = iPrimaryCall->Parameters().CloneL() );
+    params->SetServiceId( VoIPServiceId );
+    iPrimaryCall->SetParameters( *params );
+    //inform through phone engine to phone about call bubble update needs
+    MCCPCallObserver::TCCPCallEvent event = 
+                              MCCPCallObserver::ECCPNotifyRemotePartyInfoChange;
+    iCallObs->CallEventOccurred( event, this );
+    
+    RUBY_DEBUG0("Let HoTrigger know about changed domain");
+
+    if( params->CallType() == CCPCall::ECallTypeCSVoice )
+          {
+          RUBY_DEBUG0("New domain is CS");
+          iVccHoTrigger.SetCurrentDomainType( CVccHoTrigger::ECallDomainTypeCS );
+          }
+      else
+          {
+          RUBY_DEBUG0("New domain is PS");
+          iVccHoTrigger.SetCurrentDomainType( CVccHoTrigger::ECallDomainTypePS );
+          }
+    
+    delete params;
+    }
+
+// -----------------------------------------------------------------------------
+//  Creates a new call to be handled
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::CreateSecondaryCallL(
+                               const CCCPCallParameters& aParameters,
+					      	   const TDesC& aRecipient,
+					      	   const MCCPCallObserver& aObserver)
+	{
+	RUBY_DEBUG_BLOCKL( "CVccPerformer::CreateLocalSecondaryCallL" );
+	iSecondaryCall = NULL;
+	TInt index = KErrNotFound;
+	if (aParameters.CallType() != CCPCall::ECallTypePS )
+	    {
+	    index = VoipProviderIndex( EFalse );
+	    }
+	else
+	    {
+	    index = VoipProviderIndex( ETrue );
+	    }
+	if( index != KErrNotFound )
+	    {
+	    iSecondaryCall = iProviders[ index ]->NewCallL(aParameters, 
+	                                                   aRecipient, 
+	                                                   aObserver);
+	    }
+	            
+	if( !iSecondaryCall )
+	    {
+	    User::Leave( KErrNotFound );
+	    }
+	}
+
+// -----------------------------------------------------------------------------
+//  Creates a new call to be handled
+// -----------------------------------------------------------------------------
+// 
+MCCPCall* CVccPerformer::SecondaryCall()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::SecondaryCall" );
+	return iSecondaryCall;
+	}
+	
+// -----------------------------------------------------------------------------
+//  Updates the state with the next one
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::SetState(TVccState& aState)
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::SetState" );
+	iCurrentState = &aState;
+	}
+
+// -----------------------------------------------------------------------------
+//  Returns the state name
+// -----------------------------------------------------------------------------
+// 
+TUint CVccPerformer::StateName() const
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::StateName" );
+	return iCurrentState->Name();
+	}
+
+// -----------------------------------------------------------------------------
+//  Returns the Notifier
+// -----------------------------------------------------------------------------
+// 
+CVccEngPsProperty& CVccPerformer::Notifier()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::Notifier" );
+	return *iVccPsp;
+	}
+
+// -----------------------------------------------------------------------------
+//  Starts Handover procedure
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::SwitchL( const TInt aValue )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::DoHandover" );
+	//there must be an actuall call implementation created
+	__ASSERT_DEBUG(iPrimaryCall != NULL, User::Leave(KErrArgument));
+    
+	//dont change remote party after/during handover
+	iRemotePartiesSet = ETrue;
+	// check which call is active and do handover for that call. other calls
+	// are dropped.
+	if( iPrimaryCall->State() == MCCPCallObserver::ECCPStateConnected )
+		{
+        switch ( iPrimaryCall->Parameters().CallType() )
+            {
+            case CCPCall::ECallTypeCSVoice:
+                {
+                // CS call active
+                if ( aValue == EVccAutomaticStartCsToPsHoRequest || 
+                     aValue == EVccManualStartCsToPsHoRequest ||
+                     aValue == EVccAutomaticStartCsToPsHoRequestIfSingleCall )
+                    {
+                    // HO direction OK
+                    RUBY_DEBUG0( "- CS to PS HO OK" );
+            		iCurrentState->SwitchL(*this);
+                    }
+                break;
+                }
+            case CCPCall::ECallTypePS:
+                {
+                // PS call active
+                if ( aValue == EVccAutomaticStartPsToCsHoRequest || 
+                     aValue == EVccManualStartPsToCsHoRequest ||
+                     aValue == EVccAutomaticStartPsToCsHoRequestIfSingleCall )
+                    {
+                    // HO direction OK
+                    RUBY_DEBUG0( "- PS to CS HO OK" );
+					iCurrentState->SwitchL(*this);
+                    }
+                break;
+                }
+            }        
+		}
+	}
+
+// -----------------------------------------------------------------------------
+//  Activates trigger when call becomes active
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::ActivateTrigger( TBool aActivation )
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::ActivateTrigger" );
+	//Dont activate trigger if ho not allowed
+	if( aActivation )
+		{
+		// Trigger is started only if call type is CS or PS
+		CCPCall::TCallType type = iPrimaryCall->Parameters().CallType(); 
+		if ( type == CCPCall::ECallTypeCSVoice || 
+		     type == CCPCall::ECallTypePS )
+		    {
+		    //call became active, start trigger for automatic HOs
+		    //inform trigger about the original domain so it can check
+		    //possible HO restrictions
+		    iVccHoTrigger.Start( *this, iCsOriginated );
+		    }
+		}
+	else
+		{
+		//call is not active anymore, stop trigger
+		iVccHoTrigger.Stop( *this );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+//  Updates PS key using trigger
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::AllowHo( TBool aAllow )
+    {
+    TRAP_IGNORE( AllowHoL( aAllow) );
+    }
+
+// -----------------------------------------------------------------------------
+//  Updates PS key using trigger
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::AllowHoL( TBool aAllow )
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::AllowHoL" );
+    if( aAllow )
+        {
+        //HO is allowed, item can be in in call options menu
+        iVccHoTrigger.HoAllowed();
+        }
+    else
+        {
+        //HO is not allowed (f.ex. remote hold) and UI item needs to be removed
+        iVccHoTrigger.HoNotAllowedL();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+//  Checks call state and starts trigger if connected
+//  Conference call doesnt notify state Connected after conference ended
+//  Only one call can be in Connected state
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::ConferenceEnded()
+	{
+	RUBY_DEBUG_BLOCK( "CVccPerformer::ConferenceEnded" );
+	if( iPrimaryCall->State() == MCCPCallObserver::ECCPStateConnected )
+		{
+		ActivateTrigger( ETrue );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// Release secondary call leg, if needed, before calling destructor
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::ReleaseSecondaryCallLeg()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::ReleaseSecondaryCallLeg" );
+    if ( iSecondaryCall )
+        {
+        TInt err = iCurrentState->ReleaseCall(*iSecondaryCall, iProviders);
+        if( err != KErrNone )
+            {
+            RUBY_DEBUG0("CVccPerformer::ReleaseSecondaryCallLeg:" );
+            RUBY_DEBUG1("Error releasing secondary call leg: %d", err );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// Save original RemoteParty and RemotePartyName
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::SetRemoteParties()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::SetRemoteParties" );
+    if( !iRemotePartiesSet )
+        {
+        iOrigRemoteParty = iPrimaryCall->RemoteParty();
+        iOrigRemotePartyName = iPrimaryCall->RemotePartyName();
+        ParseRemoteParty();
+        }
+    } 
+
+// -----------------------------------------------------------------------------
+// Return ps/cs provider index
+// -----------------------------------------------------------------------------
+// 
+TInt CVccPerformer::VoipProviderIndex( TBool aVoipIndexWanted )
+    {
+    TInt index = KErrNotFound;
+    CSInfo info;
+    if( aVoipIndexWanted )
+        {
+        for( TInt i = 0; i < iProviders.Count(); i++ )
+            {
+            if( !iProviders[ i ]->GetCSInfo( info ) )
+                {
+                index = i;
+                break;
+                }
+            }
+        }
+    else
+        {
+        for( TInt i = 0; i < iProviders.Count(); i++ )
+            {
+            if( iProviders[ i ]->GetCSInfo( info ) )
+                {
+                index = i;
+                break;
+                }
+            }
+        }
+    return index;
+    }
+
+// -----------------------------------------------------------------------------
+// Parse remoteparty number if call is VoIP call
+// -----------------------------------------------------------------------------
+// 
+void CVccPerformer::ParseRemoteParty()
+    {
+    RUBY_DEBUG_BLOCK( "CVccPerformer::ParseRemoteParty" );
+    TInt position = 0;
+        
+     // seek '@' sign (returns KErrNotFound if none)
+    position = iOrigRemoteParty.Locate('@');
+        
+     // if found
+     if(position != KErrNotFound)
+           {
+           TInt length = iOrigRemoteParty.Length();
+            // remove the domain part from sip uri
+           iOrigRemoteParty.Delete(position, length - position);
+           //and delete 'sip:' prefix if found
+           if ( iOrigRemoteParty.Find( KSVPSipPrefix ) != KErrNotFound )
+               {
+               RUBY_DEBUG0("SIP: prefix found, delete it");
+               iOrigRemoteParty.Delete(0, 4);
+               }
+           }
+
+    }