sipvoipprovider/svptransfer/src/svptransfercontroller.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:57 +0100
branchRCL_3
changeset 22 d38647835c2e
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Transfer controller class, transfer is controlled through 
*                this class
*
*/

#include <mceinrefer.h>                     // CMceInRefer
#include <mceinevent.h>                     // CMceEvent, CMceInEvent
#include <mcetransactiondatacontainer.h>    // TMceTransactionDataContainer

#include "svptransfercontroller.h"
#include "svptransferstatecontext.h"
#include "svplogger.h"
#include "svpsessionbase.h"             // CSVPSessionBase
#include "svpsipconsts.h"
#include "svpconsts.h"

// ---------------------------------------------------------------------------
// CSVPTransferController::CSVPTransferController
// ---------------------------------------------------------------------------
//
CSVPTransferController::CSVPTransferController() :
    iTransferContext (NULL),
    iCCPTransferObserver (NULL),
    iAccepted( EFalse )
    {
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::ConstructL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::ConstructL( 
                                CMceSession* aMceSession,
                                CSVPSessionBase* aSVPSession,
                                TMceTransactionDataContainer& aContainer, 
                                MSVPTransferObserver& aObserver )
    {
    // Transfer state context
    iTransferContext = CSVPTransferStateContext::NewL( 
                                aMceSession, aSVPSession, 
                                aContainer, aObserver );
    }
    

// ---------------------------------------------------------------------------
// CSVPTransferController::NewL
// ---------------------------------------------------------------------------
//
CSVPTransferController* CSVPTransferController::NewL( 
                            CMceSession* aMceSession,
                            CSVPSessionBase* aSVPSession,
                            TMceTransactionDataContainer& aContainer, 
                            MSVPTransferObserver& aObserver )
    {
    CSVPTransferController* self = CSVPTransferController::NewLC( 
                                        aMceSession, 
                                        aSVPSession,
                                        aContainer,
                                        aObserver );
    CleanupStack::Pop( self );
    return self;
    }


// ---------------------------------------------------------------------------
// CSVPTransferController::NewLC
// ---------------------------------------------------------------------------
//
CSVPTransferController* CSVPTransferController::NewLC( 
                            CMceSession* aMceSession,
                            CSVPSessionBase* aSVPSession,
                            TMceTransactionDataContainer& aContainer, 
                            MSVPTransferObserver& aObserver )
    {
    CSVPTransferController* self = new( ELeave ) CSVPTransferController;
    CleanupStack::PushL( self );
    self->ConstructL( aMceSession, aSVPSession, aContainer, aObserver );
    return self;
    }
    

// ---------------------------------------------------------------------------
// CSVPTransferController::~CSVPTransferController
// ---------------------------------------------------------------------------
//
CSVPTransferController::~CSVPTransferController()
    {
    delete iTransferContext;
    }
    

// ---------------------------------------------------------------------------
// Handle mce event observer notify events. 
// The state of the event has changed.
// ---------------------------------------------------------------------------
//
void CSVPTransferController::HandleEventStateChangedL( 
                            CMceEvent& /* aEvent */,
                            TInt aStatusCode )
    {
    if ( KSVPOKVal == aStatusCode )
        {
        if ( iTransferContext->IsAttended() )
            {
            SVPDEBUG1( "CSVPTransferController::HandleEventStateChangedL: KSVPOKVal & attended" );
            if ( KSVPTransferAcceptedStateIndex == iTransferContext->CurrentState())
                {
                // F25 OK received - already acccepted 
                // leave for not to create new session later
                SVPDEBUG1( "CSVPTransferController::HandleEventStateChangedL: transfer in progress");
                User::Leave( KSVPErrTransferInProgress );
                }

            // F18 OK received as response for "trying"
            // Set and apply the next state - accepted
            iTransferContext->SetCurrentStateL( KSVPTransferAcceptedStateIndex );
            iTransferContext->ApplyCurrentStateL();
            SVPDEBUG1( "CSVPTransferController::HandleEventStateChangedL:ApplyCurrentStateL done" );
            }
        else    // unattended transfer
            {
            SVPDEBUG1( "CSVPTransferController::HandleEventStateChangedL: KSVPOKVal unattended" );
            if ( iTransferContext->CheckIsSessionRemoteHold() &&
                 KSVPTransferAcceptedStateIndex == iTransferContext->CurrentState() )
                {
                // Transferer has put transferee on hold before sending refer
                SVPDEBUG1( "CSVPTransferController::HandleEventStateChangedL: Snom or similar as transferer" );
                SendNotifyL( aStatusCode ); // 200 OK
                }
            }
        }
    else
        {
        SVPDEBUG2("CSVPTransferController::HandleEventStateChangedL: aStatusCode = %d",
              aStatusCode);
        }
    SVPDEBUG1("CSVPTransferController::HandleEventStateChangedL: Out");    
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::NotifyReceivedL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::NotifyReceivedL( 
                            CMceEvent& aEvent,
                            TMceTransactionDataContainer* aContainer )
    {
    SVPDEBUG1("CSVPTransferController::NotifyReceivedL: In");    
    
    // check data container and match the event to the active refer event
    if ( aContainer && iTransferContext->MceEvent() == &aEvent )
        {                  
        TInt statusCode = aContainer->GetStatusCode();        
        HBufC8* content = aContainer->GetContent();
        
        SVPDEBUG2( "CSVPTransferController::NotifyReceivedL:\
            statusCode: %d", statusCode );
        SVPDEBUG2( "CSVPTransferController::NotifyReceivedL:\
            aContainer->GetContent()->Length(): %d", content->Length() );

        if ( !content->Find( TPtrC8( KSVPNotifyTrying ) ) )
            {
            if ( iTransferContext->IsAttended() )
                {                
                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, Attended case:\
                    SIP/2.0 100 Trying" );

                // Attended transfer (F17) NOTIFY , transferee is trying establish new session.
                // Check if 202 Accepted already received
                if ( iAccepted )
                    {
                    // Stop the refer timer
                    iTransferContext->StopReferTimer( );
                    // Set and apply the next state - accepted
                    iTransferContext->SetCurrentStateL( 
                                    KSVPTransferAcceptedStateIndex );
                    iTransferContext->ApplyCurrentStateL();
                    }
                }
            else
                {
                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, UnAttended case:\
                    SIP/2.0 100 Trying" );

                // Check if 202 Accepted already received
                if ( iAccepted )
                    { 
                    // Stop the refer timer
                    iTransferContext->StopReferTimer( );

                    SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, Unattended: is accepted" );
                        
                    // Unattended transfer: F7 NOTIFY, display "transferred" note
                    if( iCCPTransferObserver )
                        {
                        SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, send local transfer" );
                        iCCPTransferObserver->TransferEventOccurred( 
                                MCCPTransferObserver::ECCPLocalTransfer );
                        }                

                    // Set and apply the next state - accepted
                    iTransferContext->SetCurrentStateL( 
                            KSVPTransferAcceptedStateIndex );
                    iTransferContext->ApplyCurrentStateL();                
                
                    iTransferContext->SetCurrentStateL( 
                                            KSVPTransferTerminatingStateIndex );
                    iTransferContext->ApplyCurrentStateL();
                    // Unattended transfer is ok, hangup the session
                    iTransferContext->TransferObserver().TransferNotification( 
                                                          ESVPTransferOKHangUp );
                    }
                }
            }
        else if ( !content->Find( TPtrC8( KSVPNotifyOK ) ) || 
                  !content->Find( TPtrC8( KSVPNotifyOk2 ) ) )
            {
            if ( iTransferContext->IsAttended() )
                {
                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, Attended case:\
                    SIP/2.0 200 OK" );

                // Attended transfer (F24) 200 OK
                if( iCCPTransferObserver )
                    {
                    SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, send local transfer" );
                    iCCPTransferObserver->TransferEventOccurred( 
                                MCCPTransferObserver::ECCPLocalTransfer );  
                    }

                // Set and apply the next state - terminating
                iTransferContext->SetCurrentStateL( 
                                        KSVPTransferTerminatingStateIndex );
                iTransferContext->ApplyCurrentStateL();

                // Attended transfer is ok, hangup the session
                iTransferContext->TransferObserver().TransferNotification(
                                                      ESVPTransferOKHangUp );
                }
            else
                {
                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, UnAttended: SIP/2.0 200 OK" );                    
                }
            }
        else if ( ( !content->Find( TPtrC8( KSVPNotifyRinging ) ) || 
                    !content->Find( TPtrC8( KSVPNotifyRinging183 ) ) ) &&
                    !iTransferContext->IsAttended())
            {
            // Polycom send Ringing instead of Trying in unattended case.
            SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, UnAttended and Ringing" );

            // Check if 202 Accepted already received
            if ( iAccepted )
                { 
                // Stop the refer timer
                iTransferContext->StopReferTimer( );

                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, Unattended: Polycom case" );
                    
                // Unattended transfer: display "transferred" note
                if( iCCPTransferObserver )
                    {
                    SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, send local transfer" );
                    iCCPTransferObserver->TransferEventOccurred( 
                            MCCPTransferObserver::ECCPLocalTransfer );
                    }                

                // Set and apply the next state - accepted
                iTransferContext->SetCurrentStateL( 
                        KSVPTransferAcceptedStateIndex );
                iTransferContext->ApplyCurrentStateL();                
            
                iTransferContext->SetCurrentStateL( 
                                        KSVPTransferTerminatingStateIndex );
                iTransferContext->ApplyCurrentStateL();
                // Unattended transfer is ok, hangup the session
                iTransferContext->TransferObserver().TransferNotification( 
                                                      ESVPTransferOKHangUp );
                }
            }
        else if ( !content->Find( TPtrC8( KSVPNotifyServiceUnavailable ) ) )
            {
            // Notify that comes after the accepted refer, if
            // the (wrong) address of the refer cannot be reached.
            if ( KSVPTransferAcceptedStateIndex == iTransferContext->CurrentState() )
                {
                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, 503 -> ECCPTransferFailed");

                // Set and apply the next state - terminating
                iTransferContext->SetCurrentStateL( 
                                        KSVPTransferTerminatingStateIndex );
                iTransferContext->ApplyCurrentStateL();

                // Transfer fails, notify client.
                iTransferContext->TransferObserver().TransferNotification(
                                                      ESVPTransferDecline );
                }
            else
                {
                SVPDEBUG1( "CSVPTransferController::NotifyReceivedL, 503.");
                }
            }
        else
            {
            SVPDEBUG1("CSVPTransferController::NotifyReceivedL:\
                Unhandled container content");
            }
        
        // Ownership transferred here   
        delete content;
        }
        
    SVPDEBUG1("CSVPTransferController::NotifyReceivedL: Out");    
    }
    
    
// ---------------------------------------------------------------------------
// CSVPTransferController::HandleReferStateChangeL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::HandleReferStateChangeL( CMceRefer& aRefer,
				                                TInt aStatusCode )
    {
    SVPDEBUG1("CSVPTransferController::HandleReferStateChangeL() In");    

    if ( iTransferContext->MceRefer() == &aRefer )
        {                          
        if ( KSVPAcceptedVal == aStatusCode )
            {
            // Accepted unattended F6, Attended F16
            SVPDEBUG2( "CSVPTransferController::HandleReferStateChangeL: Accept: %i",
			             KSVPAcceptedVal );

            // Display "transferring" note
            if( iCCPTransferObserver )
                {
                SVPDEBUG1( "CSVPTransferController::HandleReferStateChangeL, send remote transferring" );
                iCCPTransferObserver->TransferEventOccurred( 
                        MCCPTransferObserver::ECCPRemoteTransferring ); 
                }
            // Continue acceptance when also notify F7 / F17 "trying" received
            iAccepted = ETrue;
            }
        else if ( ( KSVPBadRequestVal <= aStatusCode && 
                    KSVPRequestPendingVal >= aStatusCode ) ||
                    KSVPDeclineVal == aStatusCode ||
                    KSVPServerInternalErrorVal == aStatusCode ||
                    KSVPPreconditionFailureVal == aStatusCode )
            {
            // Decline, Request Failure 4xx or Server Failure 5xx
            SVPDEBUG2( "CSVPTransferController::HandleReferStateChangeL: Code: %i", aStatusCode );
            // Stop the refer timer
            iTransferContext->StopReferTimer( );

            // Set and apply the next state - terminating
            iTransferContext->SetCurrentStateL( 
                                      KSVPTransferTerminatingStateIndex );
            iTransferContext->ApplyCurrentStateL();            

            // Notify the observer about the decline.
            iTransferContext->TransferObserver().TransferNotification( 
                                                    ESVPTransferDecline );
            }
            
        else
            {
            // Not handled
            SVPDEBUG2( "CSVPTransferController::HandleReferStateChangeL: \
                Unknown StatusCode: %i", aStatusCode );
            }
        }    
    else
        {
        // Unknown refer - not handled
        SVPDEBUG1( "CSVPTransferController::HandleReferStateChangeL: \
            Unknown refer");
        }    

    SVPDEBUG1("CSVPTransferController::HandleReferStateChangeL() Out");            
    }
        
            
// ---------------------------------------------------------------------------
// CSVPTransferController::IncomingReferL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::IncomingReferL( CMceInRefer* aRefer,
        const TDesC8& aReferTo, TMceTransactionDataContainer* aContainer )
    {
    SVPDEBUG1( "CSVPTransferController::IncomingReferL In" )
    
    // Is new incoming refer handling possible
    if ( KSVPTransferIdleStateIndex == iTransferContext->CurrentState() )
        {
        SVPDEBUG1( "CSVPTransferController::IncomingReferL: allowed" )
        
        iTransferContext->SetMceRefer( static_cast<CMceRefer*>( aRefer ) );
        iTransferContext->SetIncomingReferToL( aReferTo );
        CDesC8Array* headers = aContainer->GetHeaders();// get headers
        
        if ( headers )
            {
            TBool found = EFalse;
            
            for( TInt i = 0; i < headers->MdcaCount() && !found; i++ )
                {
                TPtrC8 tmpHeader = headers->MdcaPoint( i );
                
                if ( KErrNotFound != tmpHeader.FindF( KSVPReferredBy ) )
                    {
                    SVPDEBUG1( "KSVPReferredBy found" )
                    found = ETrue;
                    iTransferContext->SetIncomingReferredByL( tmpHeader );
                    }
                }
            }
        
        delete headers;
        headers = NULL;
        }
    
    else if ( KSVPTransferPendingStateIndex == iTransferContext->CurrentState() )
        {
        SVPDEBUG1( "CSVPTransferController::IncomingReferL: not allowed \
            -> ignore" )
        User::Leave( KSVPErrTransferInProgress );
        }
    
    else
        {
        SVPDEBUG1( "CSVPTransferController::IncomingReferL: not allowed" )
        User::Leave( KSVPErrTransferStateError );
        }
    
    if ( iTransferContext->IsAttended() )
        {
        SVPDEBUG1( "CSVPTransferController::IncomingReferL: Attended case, send accept" )
        
        // send trying notification and wait respond for it
        CMceInEvent* inEvent = NULL;
        
        TRAPD( acceptError, inEvent = static_cast<CMceInRefer*>(
                iTransferContext->MceRefer() )->AcceptL() );
        
        if ( KErrNone == acceptError )
            {
            // Apply state, changes to next state (pending)
            SVPDEBUG1( "CSVPTransferController::IncomingReferL: pending state" )
            iTransferContext->SetMceEvent( static_cast<CMceEvent*>( inEvent ) );
            iTransferContext->ApplyCurrentStateL();
            }
        else
            {
            // Set and apply the next state - terminating
            SVPDEBUG2("CSVPTransferController::IncomingReferL: acc fails = %d", acceptError )
            iTransferContext->SetCurrentStateL( KSVPTransferTerminatingStateIndex );
            iTransferContext->ApplyCurrentStateL();
            }
        }
    else
        {
        // Apply state, changes to next state (pending)
        SVPDEBUG1( "CSVPTransferController::IncomingReferL: UnAttended case pending" )
        iTransferContext->ApplyCurrentStateL();
        }
    
    SVPDEBUG1( "CSVPTransferController::IncomingReferL Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::IsMceRefer
// ---------------------------------------------------------------------------
//
TBool CSVPTransferController::IsMceRefer( CMceRefer& aRefer )
    {
    return ( iTransferContext->MceRefer() == &aRefer );
    }
    
// ---------------------------------------------------------------------------
// CSVPTransferController::IsAttended
// ---------------------------------------------------------------------------
//
TBool CSVPTransferController::IsAttended( )
    {
    return ( iTransferContext->IsAttended() );
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::SetTransferDataL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::SetTransferDataL( CDesC8Array* aUserAgentHeaders,
                                               TInt aSecureStatus )
    {
    SVPDEBUG1("  CSVPTransferController::SetTransferDataL" );
    iTransferContext->SetTransferDataL( aUserAgentHeaders, aSecureStatus );
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::SetMceSessionObject
// ---------------------------------------------------------------------------
//
void CSVPTransferController::SetMceSessionObject( CMceSession* aSession )
    {
    iTransferContext->SetMceSessionObject( aSession );
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::SendNotifyL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::SendNotifyL( TInt aStatusCode )
    {
    SVPDEBUG2("CSVPTransferController::SendNotifyL() code = %d", aStatusCode);

    CMceInEvent* inEvent = static_cast< CMceInEvent* > (
                                            iTransferContext->MceEvent());   
    if (inEvent)
        {
        HBufC8* contentType = KSVPMessageSipfrag().AllocLC(); //message/sipfrag
        HBufC8* content = NULL; 
    
        if (KSVPOKVal == aStatusCode )
            {
            content = KSVPNotifyOK().AllocLC(); // "SIP/2.0 200 OK"
            }
        else if ( KSVPNotFoundVal == aStatusCode ||
                  KSVPBusyHereVal == aStatusCode ||
                  KSVPDeclineVal == aStatusCode )
            {
            content = KSVPNotifyServiceUnavailable().AllocLC(); // "503"
            }
        else
            {
            SVPDEBUG2("CSVPTransferController::SendNotifyL unknown aStatusCode = %d", aStatusCode);
            content = KSVPNotifyServiceUnavailable().AllocLC(); // "503"
            }

        CDesC8Array* headers = NULL;
        headers = new( ELeave ) CDesC8ArrayFlat( KSVPContactArrayGranularity );
        CleanupStack::PushL( headers );
        headers->AppendL( KSVPSubsStateTerminated );

        // Notify is sent to transferer (unattended  msg F15, attended msg F24)
        TRAPD( errNotify, inEvent->TerminateL( headers, contentType, content ) );

        if ( KErrNone == errNotify )
            {
            SVPDEBUG1("CSVPTransferController::SendNotifyL, notify sending OK");
            CleanupStack::Pop( 3, contentType );    // headers, content, contentType
            }
        else
            {
            // error handling
            SVPDEBUG2("CSVPTransferController::SendNotifyL: errNotify = %d", errNotify );
            CleanupStack::PopAndDestroy( 3, contentType );    // headers, content, contentType
            }
        }
        
    if ( iTransferContext->IsAttended() )
        {
        SVPDEBUG1("CSVPTransferController::SendNotifyL() Attended done");
        }
    else
        {
        SVPDEBUG1("CSVPTransferController::SendNotifyL() UnAttended to terminating state");
        // Finish unattended incoming transfer sequence
        // Set and apply the next state - terminating
        iTransferContext->SetCurrentStateL( KSVPTransferTerminatingStateIndex );
        iTransferContext->ApplyCurrentStateL();
        }

    SVPDEBUG1("CSVPTransferController::SendNotifyL() Out");
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::IsIncomingTransfer
// ---------------------------------------------------------------------------
//
TBool CSVPTransferController::IsIncomingTransfer()
    {
    SVPDEBUG2("CSVPTransferController::IsIncomingTransfer = %d",
                iTransferContext->IsIncoming() );
    return iTransferContext->IsIncoming();
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::TerminateTransfer
// ---------------------------------------------------------------------------
//
void CSVPTransferController::TerminateTransfer()
    {
    SVPDEBUG1("CSVPTransferController::TerminateTransfer" )
    TRAP_IGNORE( TerminateTransferL() );
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::TerminateTransferL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::TerminateTransferL()
    {
    iTransferContext->SetCurrentStateL( KSVPTransferTerminatingStateIndex );
    iTransferContext->ApplyCurrentStateL();
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::AttendedTransfer
// ---------------------------------------------------------------------------
//
TInt CSVPTransferController::AttendedTransfer( MCCPCall& aTransferTargetCall )
    {  
    SVPDEBUG1( "CSVPTransferController::AttendedTransfer call IN" );
    TRAPD( transError, TransferL( &aTransferTargetCall, KNullDesC, ETrue ));
    SVPDEBUG2( "CSVPTransferController::AttendedTransfer A return: %d", transError );
    return transError;
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::AttendedTransfer
// ---------------------------------------------------------------------------
//
TInt CSVPTransferController::AttendedTransfer( const TDesC& aTransferTarget )
    {  
    SVPDEBUG1( "CSVPTransferController::AttendedTransfer target IN" );
    TRAPD( transError, TransferL( NULL, aTransferTarget, ETrue ));
    SVPDEBUG2( "CSVPTransferController::AttendedTransfer B return: %d", transError );
    return transError;
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::UnattendedTransfer
// ---------------------------------------------------------------------------
//
TInt CSVPTransferController::UnattendedTransfer( const TDesC& aTransferTarget )
    {  
    SVPDEBUG1( "CSVPTransferController::UnattendedTransfer IN" );
    TRAPD( transError, TransferL( NULL, aTransferTarget, EFalse ));
    SVPDEBUG2( "CSVPTransferController::UnattendedTransfer return: %d", transError );
    return transError;
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::AcceptTransfer
// ---------------------------------------------------------------------------
//
TInt CSVPTransferController::AcceptTransfer( const TBool aAccept )
    {
    SVPDEBUG2("CSVPTransferController::AcceptTransfer() IN aAccept = \
        %d", aAccept);
    TInt acceptError = KErrNone;
    TInt stateError = KErrNone;
    TInt currentState = iTransferContext->CurrentState();
    CMceInEvent* inEvent(NULL);
    
    // Is state "pending"
    if ( KSVPTransferPendingStateIndex == currentState )
        {
        if ( aAccept )
            {
            TRAP( acceptError, ( inEvent = static_cast< CMceInRefer* > (iTransferContext->MceRefer())->AcceptL()));
            SVPDEBUG2("CSVPTransferController::AcceptTransfer()\
                 AcceptL = %d", acceptError);
            }
        else
            {
            SVPDEBUG1("CSVPTransferController::AcceptTransfer() reject");
            TRAP( acceptError, ( static_cast< CMceInRefer* > (iTransferContext->MceRefer())->RejectL()) );
            }
            
        if ( KErrNone == acceptError )
            {
            if ( aAccept )
                {
                // Set the received event
                iTransferContext->SetMceEvent(static_cast< CMceEvent* >(inEvent));
                
                // Set and apply the next state - accepted
                TRAP( acceptError,
                    iTransferContext->SetCurrentStateL( 
                                            KSVPTransferAcceptedStateIndex );
                    iTransferContext->ApplyCurrentStateL();
                    );
                }
            else
                {
                // Set and apply the next state - terminating
                TRAP( acceptError,
                    iTransferContext->SetCurrentStateL( 
                                            KSVPTransferTerminatingStateIndex );
                    iTransferContext->ApplyCurrentStateL();        
                    );
                }
            }
        else
            {
            SVPDEBUG2("CSVPTransferController::AcceptTransfer()\
                 fails = %d", acceptError);
            // Set and apply the next state - terminating
            TRAP( stateError,
                iTransferContext->SetCurrentStateL( 
                                        KSVPTransferTerminatingStateIndex );
                iTransferContext->ApplyCurrentStateL();
                );
            SVPDEBUG2("CSVPTransferController::AcceptTransfer()\
                 stateError = %d", stateError);
            }
        }
    else
        {
        SVPDEBUG2("CSVPTransferController::AcceptTransfer()\
             current state is not pending: %d", currentState);       
        acceptError = KSVPErrTransferStateError;
        }

    SVPDEBUG2("CSVPTransferController::AcceptTransfer()\
         OUT acceptError = %d", acceptError);    
    return acceptError;
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::TransferTarget
// ---------------------------------------------------------------------------
//
const TDesC& CSVPTransferController::TransferTarget() const
    {   
    return iTransferContext->IncomingReferTo();
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::AddObserverL
// ---------------------------------------------------------------------------
//    
void CSVPTransferController::AddObserverL( 
                                    const MCCPTransferObserver& aObserver )
    {
    SVPDEBUG1("CSVPTransferController::AddObserverL() In");
    // set transfer observer
    // only one observer used at a time, replaces current one
    iCCPTransferObserver = const_cast<MCCPTransferObserver*>(&aObserver);

    SVPDEBUG1("CSVPTransferController::AddObserverL() Out");
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::RemoveObserver
// ---------------------------------------------------------------------------
//
TInt CSVPTransferController::RemoveObserver( 
                                    const MCCPTransferObserver& aObserver )
    {
    SVPDEBUG1("CSVPTransferController::RemoveObserver");
    TInt err = KErrNone;
    if ( iCCPTransferObserver == const_cast<MCCPTransferObserver*>
                (&aObserver) )
        {
        iCCPTransferObserver = NULL;
        }
    else
        {
        err = KErrNotFound;
        }
    return err;
    }

// ---------------------------------------------------------------------------
// CSVPTransferController::TransferL
// ---------------------------------------------------------------------------
//
void CSVPTransferController::TransferL( MCCPCall* aCall, 
                                        const TDesC& aTarget,
                                        const TBool aAttendedTransfer )
    {
    SVPDEBUG1("CSVPTransferController::TransferL() In");

    // Transfer possible.
    if ( KSVPTransferIdleStateIndex == iTransferContext->CurrentState() )
        {
        iAccepted = EFalse;
        
        // Set transfer parameters
        iTransferContext->SetTransferParmsL( 
                            static_cast< CSVPSessionBase* >(aCall),
                            aTarget,
                            aAttendedTransfer );

        // Apply state, execute the refer and change to next state (pending).
        iTransferContext->ApplyCurrentStateL();
        }
    else
        {
        SVPDEBUG1( "CSVPTransferController::TransferL: Error - transfer in progress" );
        iTransferContext->TransferObserver().TransferFailed( KErrInUse );
        TerminateTransferL();
        }

    SVPDEBUG1("CSVPTransferController::TransferL() OUT");
    }