sipvoipprovider/svptransfer/src/svptransferstatecontext.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 09 Jun 2010 09:31:04 +0300
branchRCL_3
changeset 16 df4dfb214df5
parent 11 6134b5029079
child 20 65a3ef1d5bd0
permissions -rw-r--r--
Revision: 201021 Kit: 2010123

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

#include <mcetransactiondatacontainer.h> // TMceTransactionDataContainer 
#include <mceoutrefer.h>                 // CMceRefer, CMceOutRefer
#include <mceoutevent.h>                 // CMceEvent
#include <escapeutils.h>
#include <mcesession.h>
#include <crcseprofileentry.h>
#include <crcseprofileregistry.h>

#include "svpsessionbase.h"
#include "svptransferstatecontext.h"
#include "svptransferstatebase.h"
#include "svptransferidlestate.h"
#include "svptransferpendingstate.h"
#include "svptransferacceptedstate.h"
#include "svptransferterminatingstate.h"
#include "svptransferterminatedstate.h" 
#include "svptransferobserver.h"
#include "svplogger.h"          
#include "svpuriparser.h"
#include "svpconsts.h"
#include "svpholdcontext.h"
#include "svpholdcontroller.h"
#include "svpcleanupresetanddestroy.h"


// ---------------------------------------------------------------------------
// C++ default constructor can NOT contain any code, that might leave.
// ---------------------------------------------------------------------------
//
CSVPTransferStateContext::CSVPTransferStateContext( 
                                CMceSession* aMceSession,                                
                                CSVPSessionBase* aSVPSession,                                
                                TMceTransactionDataContainer& aContainer, 
                                MSVPTransferObserver& aObserver ) :
        iMceSession( aMceSession ),
        iSVPSession( aSVPSession ),        
        iTargetSession( NULL ),
        iContainer( aContainer ),
        iTransferObserver( aObserver ),
        iStates( NULL ),
        iCurrentState( NULL ),
        iMceRefer( NULL ),        
        iMceEvent( NULL ),
        iAttended( EFalse ),
        iIncomingReferTo ( NULL ),
        iIncomingReferredBy ( NULL ),
        iIncomingReplaces (NULL)
    {
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::ConstructL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::ConstructL() 
    {
    SVPDEBUG1( "CSVPTransferStateContext::ConstructL In" )
    
    // Create the transfer states in the state array.
    InitializeStateArrayL();  
           
    // Initialize idle state to current state. Note, that it is not
    // applied yet.
    SetCurrentStateL( KSVPTransferIdleStateIndex );
    
    SVPDEBUG1( "CSVPTransferStateContext::ConstructL Out" )
    }

// -----------------------------------------------------------------------------
// CSVPTransferStateContext::NewL
// -----------------------------------------------------------------------------
CSVPTransferStateContext* CSVPTransferStateContext::NewL( 
                                CMceSession* aMceSession,
                                CSVPSessionBase* aSVPSession,
                                TMceTransactionDataContainer& aContainer, 
                                MSVPTransferObserver& aObserver )
    {    
    CSVPTransferStateContext* self = new ( ELeave ) CSVPTransferStateContext(
                                                        aMceSession,
                                                        aSVPSession,
                                                        aContainer, 
                                                        aObserver );
    
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }
    
// ---------------------------------------------------------------------------
// CSVPTransferStateContext::~CSVPTransferStateContext
// ---------------------------------------------------------------------------
//
CSVPTransferStateContext::~CSVPTransferStateContext()
    {
    SVPDEBUG1( "CSVPTransferStateContext::~CSVPTransferStateContext In" )
    
    if ( iStates )
        {
        iStates->ResetAndDestroy();
        iStates->Close();
        delete iStates;
        }
    
    delete iMceEvent;
    delete iMceRefer;
    delete iIncomingReferTo;
    delete iIncomingReferredBy;
    delete iIncomingReplaces;
    
    SVPDEBUG1( "CSVPTransferStateContext::~CSVPTransferStateContext Out" )        
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetCurrentStateL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetCurrentStateL(
        TSVPTransferStateIndex aStateIndex )
    {
    // Check, if the transition is valid
    if ( !IsStateTransitionAccepted( aStateIndex ) )
        {
        SVPDEBUG2( "CSVPTransferStateContext::SetCurrentStateL: STATE ERROR stateindex: %i", aStateIndex )
        User::Leave( KSVPErrTransferStateError );
        }
    else
        {
        iCurrentState = ( *iStates )[ aStateIndex ];
        iCurrentState->Enter( *this );
        }
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CurrentState
// ---------------------------------------------------------------------------
//
TSVPTransferStateIndex CSVPTransferStateContext::CurrentState() const
    {
    return iStates->Find( iCurrentState );    
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::ApplyCurrentStateL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::ApplyCurrentStateL()
   {
   iCurrentState->ApplyL( *this );
   }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::TransferObserver
// ---------------------------------------------------------------------------
//
MSVPTransferObserver& CSVPTransferStateContext::TransferObserver()
    {
    return iTransferObserver;    
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetMceSessionObject
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetMceSessionObject( CMceSession* aSession )
    {
    iMceSession = aSession;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::MceSessionObject
// ---------------------------------------------------------------------------
//
CMceSession* CSVPTransferStateContext::MceSessionObject()
    {
    return iMceSession;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetMceRefer
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetMceRefer( CMceRefer* aRefer )
    {
    if ( iMceRefer != aRefer )
        {
        delete iMceRefer;
        iMceRefer = aRefer;
        }
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::MceRefer
// ---------------------------------------------------------------------------
//
CMceRefer* CSVPTransferStateContext::MceRefer()
    {
    return iMceRefer;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetAttended
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetAttended( const TBool aAttended )
    {
    iAttended = aAttended;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::IsAttended
// ---------------------------------------------------------------------------
//
TBool CSVPTransferStateContext::IsAttended()
    {
    return iAttended;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckIsSessionRemoteHold
// ---------------------------------------------------------------------------
//
TBool CSVPTransferStateContext::CheckIsSessionRemoteHold()
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckIsSessionRemoteHold In" )
    
    TBool ret = EFalse;
    
    if ( iSVPSession->HasHoldController() &&
         MCCPCallObserver::ECCPStateDisconnecting != iSVPSession->State() )
        {
        SVPDEBUG1("CSVPTransferStateContext::CheckIsSessionRemoteHold, Check hold state" )
        
        if ( ESVPOnHold == iSVPSession->HoldController().HoldState() &&
             ESVPRemoteHold == iSVPSession->HoldController().HoldRequest() )
            {
            // Session is remote holded -> Snom/EyeBeam as unattended transferer case.
            SVPDEBUG1( "CSVPTransferStateContext:CheckIsSessionRemoteHold, transferer is Snom, EyeBeam or similar" )
            ret = ETrue;
            }
        }
    
    SVPDEBUG2("CSVPTransferStateContext::CheckIsSessionRemoteHold Out return: %d",ret )
    return ret;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetTransferDataL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetTransferDataL(
        CDesC8Array* aUserAgentHeaders, TInt aSecureStatus )
    {
    SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL In" )
    
    if ( aUserAgentHeaders )
        {
        if ( iIncomingReplaces && IsAttended() )
            {
            SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL: Add replaces header" )
            // fetch "replaces:" string
            HBufC* replacesStringHeap16 = IncomingReplaces().AllocLC(); // CS: 1
            
            // Copy incoming replaces to 8-bit buffer
            HBufC8* replacesStringHeap8 =
                    HBufC8::NewLC( replacesStringHeap16->Length() +
                                   KSVPReplacesColonTxt().Length() ); // CS: 2
            
            replacesStringHeap8->Des().Copy( *replacesStringHeap16 );
            CleanupStack::Pop( 1 );
            CleanupStack::PushL( replacesStringHeap8 ); // ReAlloc possible
            
            // add replaces header
            replacesStringHeap8->Des().Insert( 0, KSVPReplacesColonTxt );
            CleanupStack::Pop( 1 );
            CleanupStack::PushL( replacesStringHeap8 ); // ReAlloc possible
            SVPDEBUG2( "CSVPTransferStateContext::SetTransferDataL - length: %d", replacesStringHeap8->Length() )
            
            // Finally add collected Replaces string to header
            aUserAgentHeaders->AppendL( *replacesStringHeap8 );
            CleanupStack::PopAndDestroy( replacesStringHeap8 );      // CS: 1
            CleanupStack::PopAndDestroy( replacesStringHeap16 );     // CS: 0
            }
        
        if ( iIncomingReferredBy )
            {
            SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL: Add referredBy header" )
            TBuf8<KSVPTempStringlength> referredByString;
            referredByString.Append( KSVPReferredBy );
            // add IncomingReferredBy
            referredByString.Append( IncomingReferredBy() );
            // Finally add collected Referred-By string to header
            aUserAgentHeaders->AppendL( referredByString );
            }
        }
    
    // Update transfer target address according preferred securesetting.
    UpdateTransferTargetL( aSecureStatus );
    
    SVPDEBUG1( "CSVPTransferStateContext::SetTransferDataL Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::IsIncoming
// ---------------------------------------------------------------------------
//
TBool CSVPTransferStateContext::IsIncoming()
    {
    return ( NULL != iIncomingReferTo );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetIncomingReferToL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetIncomingReferToL( const TDesC8& aReferTo )
    {
    SVPDEBUG1("CSVPTransferStateContext::SetIncomingReferToL In" )
    
    ResetIncomingReferTo();
    
    // modify aReferTo
    HBufC8* referTo = CompleteReferToL( aReferTo );
    CleanupStack::PushL( referTo );

    // at this point referto must contains legal sip uri
    RemoveExtraParameters( referTo );
    
    // Check length - moSession construct limitation
    // sip: or sips: prefix will be added later, so 95 is maximum
    if ( referTo->Length() < ( KSVPMaxUriLength - KSVPSipPrefixLength ) )
        {
        // Copy and convert the "refer to" -parameter.
        iIncomingReferTo = HBufC::NewL( referTo->Length() );
        TPtr temp = iIncomingReferTo->Des();
        temp.Copy( *referTo );
        }
    else
        {
        SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferToL: referTo too long, Leave" )
        User::Leave( KErrArgument );
        }
    
    CleanupStack::PopAndDestroy( referTo );
    
   SVPDEBUG2( "CSVPTransferStateContext::SetIncomingReferToL lenght: %d",
            iIncomingReferTo->Length())
    SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferToL Out" )
    }

// -----------------------------------------------------------------------------
// CSVPSessionBase::SetIncomingReferredByL
// -----------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetIncomingReferredByL( const TDesC8& aReferredBy )
    {
    SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferredByL In" )
    
    ResetIncomingReferredBy();
    
    // modify aReferredBy
    HBufC8* referredBy = CompleteReferredByL( aReferredBy );
    CleanupStack::PushL( referredBy );
    
    // Copy and convert the "Referred By" -parameter.    
    iIncomingReferredBy = HBufC::NewL( referredBy->Length() );
    TPtr temp = iIncomingReferredBy->Des();
    temp.Copy( *referredBy );
    CleanupStack::PopAndDestroy( referredBy );
    
    SVPDEBUG2( "CSVPTransferStateContext::SetIncomingReferredByL lenght: %d",
            iIncomingReferredBy->Length() )
    SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReferredByL Out" )
    }    

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetIncomingReplacesL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetIncomingReplacesL( const TDesC8& aString )
    { 
    SVPDEBUG1("CSVPTransferStateContext::SetIncomingReplacesL In" )
    
    ResetIncomingReplaces();
    
    // modify Replaces
    HBufC8* string = CompleteReplacesL( aString );
    CleanupStack::PushL( string );
    
    // Copy and convert the "Replaces" -parameter.    
    iIncomingReplaces = HBufC::NewL( string->Length() );
    TPtr temp = iIncomingReplaces->Des();
    temp.Copy( *string );
    CleanupStack::PopAndDestroy( string );
    
    SVPDEBUG2( "CSVPTransferStateContext::SetIncomingReplacesL lenght: %d",
            iIncomingReplaces->Length() )
    SVPDEBUG1( "CSVPTransferStateContext::SetIncomingReplacesL Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CompleteReplacesL
// ---------------------------------------------------------------------------
//
HBufC8* CSVPTransferStateContext::CompleteReplacesL( const TDesC8& aString )
    {
    SVPDEBUG1( "CSVPTransferStateContext::CompleteReplacesL In" )
    
    // Copy the parameter to a new buffer.
    HBufC8* string = aString.AllocLC();
    // If "?Replaces=" found attended transfer case
    TInt position = CheckReplacesTxt( *string );
    SVPDEBUG2( "    CheckReplacesTxt returns = %d", position );
    
    if ( KErrNotFound != position )
        {
        TakeReplacesTxt( string, position );
        CleanupStack::Pop( 1 ); // string, ReAlloc possible
        CleanupStack::PushL( string );
        }
    
    // Check ">" and remove text after it if exists
    position = CheckRightBracket( *string );
    SVPDEBUG2("    CheckRightBracket returns = %d" , position )
    
    if ( KErrNotFound != position )
        {
        // ">" found
        CutStringFromPosition( string, position );
        CleanupStack::Pop( 1 ); // string, ReAlloc possible
        CleanupStack::PushL( string );
        }
    
    HBufC8* temp = EscapeUtils::EscapeDecodeL( *string );
    CleanupStack::PopAndDestroy( string );
    
    SVPDEBUG1( "CSVPTransferStateContext::CompleteReplacesL Out" )
    return temp;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CompleteReferToL
// ---------------------------------------------------------------------------
//
HBufC8* CSVPTransferStateContext::CompleteReferToL( const TDesC8& aUri )
    {
    SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL In" )
    
    // Copy the parameter to a new buffer.
    HBufC8* uri = aUri.AllocLC();
    
    // Check "<" and remove it and text before it if exists
    TInt position = CheckLeftBracket( *uri );
    
    if ( KErrNotFound != position )
        {
        RemoveLeftBracket( uri, position );
        CleanupStack::Pop( 1 ); // uri, ReAlloc possible
        CleanupStack::PushL( uri );
        }
    
    // Check ";user=phone" and remove if exists
    position = CheckUserEqualsPhone( *uri );
    
    if ( KErrNotFound != position )
        {
        // ";user=phone" found
        RemoveUserEqualsPhone( uri, position );
        CleanupStack::Pop( 1 ); // uri, ReAlloc possible
        CleanupStack::PushL( uri );
        }
    
    // Check ">" and remove text after it if exists
    position = CheckRightBracket( *uri );
    
    if ( KErrNotFound != position )
        {
        // ">" found
        CutStringFromPosition( uri, position );
        CleanupStack::Pop( 1 ); // uri, ReAlloc possible
        CleanupStack::PushL( uri );
        }
    
    // Check "KSVPQuesReplacesTxt" and remove text after it if exists
    // If it is found -> attended transfer case
    position = CheckReplacesTxt( *uri );
    
    if ( KErrNotFound != position )
        {
        // Found -> attended case.
        SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL ?Replaces= found -> attended transfer" )
        SetAttended( ETrue );
        SetIncomingReplacesL( aUri );
        CutStringFromPosition( uri, position );
        }
    else
        {
        // Not found -> unattended case.
        SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL ?Replaces= not found -> unattended transfer" )
        SetAttended( EFalse );
        }

    // Check "?X-Sipx-Authidentity=" and remove text after it if exists
    position = CheckAuthidentity( *uri );

    if ( KErrNotFound != position )
        {
        // "?X-Sipx-Authidentity=" found
        CutStringFromPosition( uri, position );
        CleanupStack::Pop( 1 ); // uri, ReAlloc possible
        CleanupStack::PushL( uri );
        }

    // Check "sip:" and remove it if exists
    if ( KErrNone == uri->Find( KSVPSipPrefix ) )
        {
        // sip: is in the beginning of the string
        SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL remove sip:" )
        uri->Des().Delete( 0, KSVPSipPrefixLength );
        }

    // Check "sips:" and remove it if exists
    if ( KErrNone == uri->Find( KSVPSipsPrefix ) )
        {
        // sips: is in the beginning of the string
        SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL remove sips:" )
        uri->Des().Delete( 0, KSVPSipsPrefixLength );
        }

    // Check ":" and remove text after it if exists,
    // some server might add this after transfer target address
    position = uri->Find( KSVPCln );

    if ( KErrNotFound != position )
        {
        // ":" found
        SVPDEBUG2( "CSVPTransferStateContext::CompleteReferToL remove text after %d ", position )
        uri->Des().Delete( position, uri->Length() - position );
        }

    CleanupStack::Pop( 1 ); // uri, ReAlloc possible
    
    SVPDEBUG1( "CSVPTransferStateContext::CompleteReferToL Out" )
    return uri;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CompleteReferredByL
// ---------------------------------------------------------------------------
//
HBufC8* CSVPTransferStateContext::CompleteReferredByL(
        const TDesC8& aReferredBy )
    {
    SVPDEBUG1( "CSVPTransferStateContext::CompleteReferredByL In" )
    
    // Copy the parameter to a new buffer.
    HBufC8* referredBy = aReferredBy.AllocLC();
    
    // Check "Referred-By:" and remove it
    TInt position = CheckReferredByTxt( *referredBy );
    
    if ( KErrNotFound != position )
        {
        // "Referred-By:" found.
        RemoveReferredByTxt( referredBy, position );
        }
    
    CleanupStack::Pop( 1 ); // referredBy, ReAlloc possible
    
    SVPDEBUG1( "CSVPTransferStateContext::CompleteReferredByL Out" )
    return referredBy;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckUserEqualsPhone
// ---------------------------------------------------------------------------
//
TInt CSVPTransferStateContext::CheckUserEqualsPhone( const TDesC8& aUri ) const
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckUserEqualsPhone" )
    
    return ( aUri.FindF( KSVPUserEqualsPhone ) );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::RemoveUserEqualsPhone
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::RemoveUserEqualsPhone(
        HBufC8*& aUri, TInt aPosition ) const
    {
    SVPDEBUG2( "CSVPTransferStateContext::RemoveUserEqualsPhone posit = %d", aPosition )
    
    aUri->Des().Delete( aPosition, KSVPUserEqualsPhoneLenght );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::RemoveExtraParameters
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::RemoveExtraParameters( HBufC8*& aUri ) const 
    {
    SVPDEBUG1( "CSVPTransferStateContext::RemoveExtraParameters In" )
    
    // remove all extra parameters from given address
    TInt index = aUri->Locate( KSVPSemiColonMark );
    TInt bracketLocation = KErrNotFound;
    
    SVPDEBUG3( "CSVPTransferStateContext::RemoveExtraParameters index = %d, length = %d",
        index, aUri->Length() )
    
    if ( KErrNotFound != index )
        {
        // Delete ";" and text after it
        aUri->Des().Delete( index, aUri->Length() );
        }
    
    // Check "<" and remove it and text before it if exists
    bracketLocation = CheckLeftBracket( *aUri );
    
    if ( KErrNotFound != bracketLocation )
        {
        RemoveLeftBracket( aUri, bracketLocation );
        }
    
    // Check ">" and remove text after it if exists
    bracketLocation = CheckRightBracket( *aUri );
    
    if ( KErrNotFound != bracketLocation )
        {
        CutStringFromPosition( aUri, bracketLocation );
        }
    
    SVPDEBUG1( "CSVPTransferStateContext::RemoveExtraParameters Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckReplacesTxt
// ---------------------------------------------------------------------------
//
TInt CSVPTransferStateContext::CheckReplacesTxt( const TDesC8& aUri ) const
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckReplacesTxt" )
    
    return ( aUri.FindF( KSVPQuesReplacesTxt ) );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CutStringFromPosition
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::CutStringFromPosition(
        HBufC8*& aUri, TInt aPosition ) const
    {
    SVPDEBUG2( "CSVPTransferStateContext::CutStringFromPosition posit = %d", aPosition )
    aUri->Des().Delete( aPosition, aUri->Length() - aPosition );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckReferredByTxt
// ---------------------------------------------------------------------------
//
TInt CSVPTransferStateContext::CheckReferredByTxt(
        const TDesC8& aReferredBy ) const
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckReferredByTxt" )
    
    return ( aReferredBy.FindF( KSVPReferredBy ) );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::RemoveReferredByTxt
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::RemoveReferredByTxt(
        HBufC8*& aReferredBy, TInt aPosition ) const
    {
    SVPDEBUG2( "CSVPTransferStateContext::RemoveReferredByTxt posit = %d", aPosition )
    
    aReferredBy->Des().Delete( aPosition, KSVPReferredByLength + 1 );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::TakeReplacesTxt
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::TakeReplacesTxt(
        HBufC8*& aString, TInt aPosition ) const
    {
    SVPDEBUG2( "CSVPTransferStateContext::TakeReplacesTxt posit = %d", aPosition )
    
    aString->Des().Delete( 0, aPosition + KSVPQuesReplacesTxtLength );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckLeftBracket
// ---------------------------------------------------------------------------
//
TInt CSVPTransferStateContext::CheckLeftBracket( const TDesC8& aUri ) const
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckLeftBracket" )
    
    // Return position of "<" or KErrNotFound
    return ( aUri.Find( KSVPLeftBracketMark ) );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::RemoveLeftBracket
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::RemoveLeftBracket(
        HBufC8*& aUri, TInt aPosition ) const
    {
    SVPDEBUG2( "CSVPTransferStateContext::RemoveLeftBracket posit = %d", aPosition )
    
    aUri->Des().Delete( 0, aPosition + KSVPSingleBracketLength );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckRightBracket
// ---------------------------------------------------------------------------
//
TInt CSVPTransferStateContext::CheckRightBracket( const TDesC8& aUri ) const
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckRightBracket" )
    
    return ( aUri.Find( KSVPRightBracketMark ) );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CheckAuthidentity  
// ---------------------------------------------------------------------------
//
TInt CSVPTransferStateContext::CheckAuthidentity( const TDesC8& aUri ) const
    {
    SVPDEBUG1( "CSVPTransferStateContext::CheckAuthidentity" )
    TInt returnValue = aUri.Find( KSVPAuthidentity );
    SVPDEBUG2( "CSVPTransferStateContext::CheckAuthidentity return: %d", returnValue )
    if ( returnValue == KErrNotFound )
        {
        returnValue = aUri.Find( KSVPAuthidentity2 );
        SVPDEBUG2( "CSVPTransferStateContext::CheckAuthidentity second return: %d", returnValue )
        }
    return returnValue;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::IncomingReferTo
// ---------------------------------------------------------------------------
//
const TDesC& CSVPTransferStateContext::IncomingReferTo()
    {
    SVPDEBUG1( "CSVPTransferStateContext::IncomingReferTo" )
    
    return *iIncomingReferTo;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::UpdateTransferTargetL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::UpdateTransferTargetL( TInt aSecureStatus )
    {
    SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL In" )
    
    if ( iIncomingReferTo )
        {
        if ( KSVPStatusNonSecure == aSecureStatus )
            {
            SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add SIP uri" )
            
            // Check "sips:" and remove it if exists
            if ( KErrNone == iIncomingReferTo->Des().FindF( KSVPSipsPrefix2 ) )
                {
                // sips: is in the beginning of the string, position 0
                SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL remove sips:" )
                iIncomingReferTo->Des().Delete( 0, KSVPSipsPrefixLength );
                }
            
            // Add "sip:" prefix in the beginning of the string, if it's missing.
            if ( KErrNotFound == iIncomingReferTo->Des().FindF( KSVPSipPrefix2 ) )
                {
                SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add sip:" )
                iIncomingReferTo = iIncomingReferTo->ReAllocL(
                        iIncomingReferTo->Length() + KSVPSipPrefixLength );
                iIncomingReferTo->Des().Insert( 0, KSVPSipPrefix2 );
                }
            }
        else
            {
            SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add SIPS" )
            
            // Check "sip:" and remove it if exists
            if ( KErrNone == iIncomingReferTo->Des().FindF( KSVPSipPrefix2 ) )
                {
                // sip: is in the beginning of the string
                SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL remove sip:" )
                iIncomingReferTo->Des().Delete( 0, KSVPSipPrefixLength );
                }
            
            // Add "sips:" prefix in the beginning of the string, if it's missing.
            if ( KErrNotFound == iIncomingReferTo->Des().FindF( KSVPSipsPrefix2 ) )
                {
                SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL add sips:" )
                iIncomingReferTo = iIncomingReferTo->ReAllocL(
                        iIncomingReferTo->Length() + KSVPSipsPrefixLength );
                iIncomingReferTo->Des().Insert( 0, KSVPSipsPrefix2 );
                }
            }
        }
    else
        {
        SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL IncomingReferTo Not OK" )
        }
    
    SVPDEBUG1( "CSVPTransferStateContext::UpdateTransferTargetL Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::ResetIncomingReferTo
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::ResetIncomingReferTo()
    {
    SVPDEBUG1( "CSVPTransferStateContext::ResetIncomingReferTo" )    
    
    if ( iIncomingReferTo )
        {
        delete iIncomingReferTo;
        iIncomingReferTo = NULL;
        }
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::ResetIncomingReferredBy
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::ResetIncomingReferredBy()
    {
    SVPDEBUG1( "CSVPTransferStateContext::ResetIncomingReferredBy" )
    
    if ( iIncomingReferredBy )
        {
        delete iIncomingReferredBy;
        iIncomingReferredBy = NULL;
        }
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::IncomingReferredBy
// ---------------------------------------------------------------------------
//
const TDesC& CSVPTransferStateContext::IncomingReferredBy()
    {
    SVPDEBUG1( "CSVPTransferStateContext::IncomingReferredBy" )
    
    return *iIncomingReferredBy;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::IncomingReplaces
// ---------------------------------------------------------------------------
//
const TDesC& CSVPTransferStateContext::IncomingReplaces()
    {
    SVPDEBUG1( "CSVPTransferStateContext::IncomingReplaces" )
    
    return *iIncomingReplaces;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::ResetIncomingReplaces
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::ResetIncomingReplaces()
    {
    SVPDEBUG1( "CSVPTransferStateContext::ResetIncomingReplaces" )
    
    if ( iIncomingReplaces )
        {
        delete iIncomingReplaces;
        iIncomingReplaces = NULL;
        }
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetTransferParmsL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetTransferParmsL(
        CSVPSessionBase* aTargetSession, const TDesC& aTarget,
        const TBool aAttendedTransfer )
    {
    SVPDEBUG1( "CSVPTransferStateContext::SetTransferParmsL In" )
    
    // No target session as default. 
    iTargetSession = NULL;
    
    // Delete possible old refer 
    delete iMceRefer;
    iMceRefer = NULL;
    
    // Set attended/unattended transfer
    SetAttended( aAttendedTransfer );
    
    // Create mce out refer using given target parameter or call
    if ( aTarget.Length() > 0 )
        {
        CreateMceOutReferL( aTarget );
        }
    else
        {
        CreateMceOutReferL( aTargetSession );
        }
    
    SVPDEBUG1( "CSVPTransferStateContext::SetTransferParmsL Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CreateMceOutReferL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::CreateMceOutReferL( const TDesC& aTarget )
    {
    // Create mce out refer using target string (unattended).   
    SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) In" )
    
    // Copy 'refer to' argument
    HBufC8* target = HBufC8::NewLC( aTarget.Length() );
    target->Des().Copy( aTarget );
    
    // Parse target with uri parser, use session recipient as domain source 
    CSVPUriParser* uriParser = CSVPUriParser::NewLC();
    HBufC8* referto = NULL;
    RPointerArray< CRCSEProfileEntry > entryArray;
    CleanupResetAndDestroy< RPointerArray<CRCSEProfileEntry> >::PushL( entryArray );
    CRCSEProfileRegistry* reg = CRCSEProfileRegistry::NewLC();
    
    // Get VoIP profile by service id
    reg->FindByServiceIdL( iSVPSession->Parameters().ServiceId(), entryArray );
    __ASSERT_ALWAYS( entryArray.Count(), User::Leave( KErrArgument ) );
    CRCSEProfileEntry* entry = entryArray[0];
    uriParser->SetUserEqualsPhoneRequiredL(
            CRCSEProfileEntry::EOn == entry->iUserPhoneUriParameter );
    
    CleanupStack::PopAndDestroy( reg );
    CleanupStack::PopAndDestroy( &entryArray );

    HBufC8* recipient = NULL;
    const CMceSession& session = iSVPSession->Session();
    __ASSERT_ALWAYS( &session, User::Leave( KErrArgument ) );
    
    TBool isCLIROn = iSVPSession->IsCLIROnL();
    
    if ( ( iSVPSession->IsMobileOriginated() && !isCLIROn ) 
            || ( !iSVPSession->IsMobileOriginated() && isCLIROn ) )
        {
        SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget), orig" )
        const TDesC8& orig = session.Originator(); 
        __ASSERT_ALWAYS( &orig, User::Leave( KErrArgument ) );
        recipient = HBufC8::NewLC( orig.Length() );
        recipient->Des().Copy( orig );
        }
    else
        {
        SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget), recip" )
        const TDesC8& recip = session.Recipient(); 
        __ASSERT_ALWAYS( &recip, User::Leave( KErrArgument ) );
        recipient = HBufC8::NewLC( recip.Length() );
        recipient->Des().Copy( recip );    
        }

    // remove all extra parameters from recipient address
    RemoveExtraParameters( recipient );
    
    SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) recipient->Length() = %d",
               recipient->Length() )
    
    if ( iSVPSession->SecureMandatory() || iSVPSession->SecurePreferred() )
        {
        SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) SIPS URI..." )
        referto = uriParser->CompleteSecureSipUriL( *target, *recipient );
        }
    else
        {
        SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) SIP URI..." )
        referto = uriParser->CompleteSipUriL( *target, *recipient );
        }
    
    CleanupStack::PushL( referto );
    
    SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) 1 referto->Length() = %d",
               referto->Length() )
    
    // remove all extra parameters from referto
    RemoveExtraParameters( referto );

    SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) 2 referto->Length() = %d",
               referto->Length() )
    
    // Create the refer
    delete iMceRefer;
    iMceRefer = NULL;
    iMceRefer = CMceOutRefer::NewL( *iMceSession, *referto, CMceRefer::ENoSuppression );
    CleanupStack::PopAndDestroy( referto );
    
    CleanupStack::PopAndDestroy( recipient );
    CleanupStack::PopAndDestroy( uriParser );
    CleanupStack::PopAndDestroy( target );
    
    SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTarget) Out" )
	}

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::CreateMceOutReferL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::CreateMceOutReferL( CSVPSessionBase* aTargetSession )
    {
    // Create mce out refer using session (attended).   
    SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) In" )    
    
    // Store target session 
    iTargetSession = aTargetSession;
    
    // Construct the refer-to string
    HBufC8* referto = HBufC8::NewLC( KSVPTempStringlength );
    TPtr8 refptr = referto->Des();
    
    if ( iTargetSession )
        {
        // Set refer-to for the attended transfer using the target session,
        // that can not be the same as the owner session of the 
        // transfer controller.
        if ( iSVPSession != iTargetSession )
            {
            SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) TargetSession = 0x%x", &iTargetSession )
            
            HBufC8* recipient = NULL;
            const CMceSession& session = iTargetSession->Session();
            __ASSERT_ALWAYS( &session, User::Leave( KErrArgument ) );
            
            if ( iTargetSession->IsMobileOriginated() ) 
                {
                const TDesC8& recip = session.Recipient();
                __ASSERT_ALWAYS( &recip, User::Leave( KErrArgument ) );
                recipient = HBufC8::NewLC( recip.Length() );
                recipient->Des().Copy( recip );
                }
            else
                {
                const TDesC8& orig = session.Originator();
                __ASSERT_ALWAYS( &orig, User::Leave( KErrArgument ) );
                recipient = HBufC8::NewLC( orig.Length() );
                recipient->Des().Copy( orig );    
                }
            
            // remove all extra parameters from recipient address
            RemoveExtraParameters( recipient );
            
            SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) recipient->Length() = %d",
               recipient->Length() )
            
            // Set the refer-to address (recipient)
            refptr.Append( recipient->Des() );
            CleanupStack::PopAndDestroy( recipient );
            
            // Gather up the rest of the refer-to data (replaces etc.)  
            // from the target session (sessionbase) member variables.
            TBuf8<KSVPTempStringlength> tmp( KNullDesC8 );
            tmp.Append( KSVPQuesReplacesTxt ); // Set CallId
            
            if ( iTargetSession->CallId() )
                {
                // Set "replaces" callid string starting from next char 
                // the of KSVPCallId_replaces -text
                TDesC8* callid = iTargetSession->CallId();
                TInt index = callid->Find( KSVPCallId_replaces );
                
                if ( KErrNotFound != index )
                    {
                    // Check and encode the possible @ char of the callid 
                    // to "%40" format. This kind of callid e.g. in Cisco 7960.
                    TInt index2 = callid->Find( KSVPAt );
                    
                    if ( KErrNotFound != index2 )
                	    {
                	    HBufC8* tmpCallId = HBufC8::NewLC( callid->Length() );
                	    tmpCallId->Des().Append( callid->Mid( index +
                	            KSVPCallId_replaces().Length() ) );
                	    CSVPUriParser::EscapeEncodeSipUriL( tmpCallId,
                                EscapeUtils::EEscapeUrlEncoded );
                        tmp.Append( *tmpCallId );
                        CleanupStack::Pop( 1 ); // tmpCallId, ReAlloc possible
                        delete tmpCallId;
                        }
                    else
                        {
                        // Normal copy from the correct position
                        tmp.Append( callid->Mid( index +
                                KSVPCallId_replaces().Length() ) );
                        }
                    }
                }
            else
                {
                SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - missing CallId %i", KSVPErrTransferReferTo )
                User::Leave( KSVPErrTransferReferTo );
                }
            
            // To-header                    
            if ( iTargetSession->ToHeader() )
                {
                tmp.Append( KSVPTo_tag );
                
                // Set "to" tag string starting from next char 
                // of the KSVPTo_tag_replaces -text
                TDesC8* toHdr = iTargetSession->ToHeader();
                TInt index = toHdr->Find( KSVP_tag );
                SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) toHdr index = %d", index )
                
                if ( KErrNotFound != index )
                    {
                    tmp.Append( toHdr->Mid( index + KSVPTagLength ) );
                    }
                }
            else
                {
                SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - missing ToHeader %i", KSVPErrTransferReferTo )        
                User::Leave( KSVPErrTransferReferTo );
                }
            
            // From-header
            if ( iTargetSession->FromHeader() )
                {                    
                tmp.Append( KSVPFrom_tag );                    
                
                // Set "from" tag string starting from next char of 
                // the KSVPTo_tag_replaces -text
                TDesC8* fromHdr = iTargetSession->FromHeader();
                TInt index = fromHdr->Find( KSVP_tag );
                SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) fromHdr index = %d", index )
                
                if ( KErrNotFound != index )
                    {
                    tmp.Append( fromHdr->Mid( index + KSVPTagLength ) );
                    }
                }
            else
                {
                SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - missing FromHeader %i", KSVPErrTransferReferTo )
                User::Leave( KSVPErrTransferReferTo );
                }
            
            refptr.Append( tmp );
            } // if ( iSVPSession != iTargetSession )
        else
            {
            SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - the same target session %i", KSVPErrTransferReferTo )
            User::Leave( KSVPErrTransferReferTo );
            }
        
        // Create the refer
        iMceRefer = CMceOutRefer::NewL( *iMceSession,
                *referto, CMceRefer::ENoSuppression );
        } // if (iTargetSession)
    else
        {
        SVPDEBUG2( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) error - no target session %i", KSVPErrTransferReferTo )        
        User::Leave( KSVPErrTransferReferTo );
        }
    
    CleanupStack::PopAndDestroy( referto );    	
    
    SVPDEBUG1( "CSVPTransferStateContext::CreateMceOutReferL(aTargetSession) Out" )        
	}

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::ExecuteReferL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::ExecuteReferL()
    {
    SVPDEBUG1( "CSVPTransferStateContext::ExecuteReferL In" )
    
    delete iMceEvent;
    iMceEvent = NULL;
    
    // Create headers for refer call.
    CDesC8Array* headers = SetupHeadersL();
    CleanupStack::PushL( headers );
    
    // Refer with headers, passes ownership.
    iMceEvent = static_cast< CMceOutRefer* >(MceRefer())->ReferL( headers );          
    CleanupStack::Pop( headers );
    
    // Execution of the refer. Pass ownership of the arguments. Generates 
    // event to the MMceReferObserver. New MceOutEvent is created and events 
    // of that then through MMceEventObserver interface.
    iSVPSession->StartTimerL( KSVPReferExpirationTime,
            KSVPReferTimerExpired  );// Start refer timer
    
    SVPDEBUG1( "CSVPTransferStateContext::ExecuteReferL Out" )
	}

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetMceEvent
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::SetMceEvent( CMceEvent* aEvent )
    {
    SVPDEBUG1( "CSVPTransferStateContext::SetMceEvent In" )
    
    if ( iMceEvent != aEvent )
        {
        delete iMceEvent;
        iMceEvent = aEvent;
        SVPDEBUG1( "CSVPTransferStateContext::SetMceEvent Updated" )
        }
    
    SVPDEBUG1( "CSVPTransferStateContext::SetMceEvent Out" )
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::MceEvent
// ---------------------------------------------------------------------------
//
CMceEvent* CSVPTransferStateContext::MceEvent()
    {
    return iMceEvent;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::StopReferTimer
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::StopReferTimer()
    {
    SVPDEBUG1( "CSVPTransferStateContext::StopReferTimer" )
    
    iSVPSession->StopTimer( KSVPReferTimerExpired );
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::SetupHeadersL
// ---------------------------------------------------------------------------
//
CDesC8Array* CSVPTransferStateContext::SetupHeadersL()
    {
    SVPDEBUG1( "CSVPTransferStateContext::SetupHeadersL In" )
    
    CDesC8ArrayFlat* headers = new( ELeave ) CDesC8ArrayFlat(
            KSVPHeaderArrayGranularity );
    CleanupStack::PushL( headers );
    
    // Set "referred by" value - that is this end of the session.
    TBuf8<KSVPTempStringlength> tempRefBy;
    tempRefBy.Append( KSVPReferredBy );
    
    if ( iSVPSession->IsMobileOriginated() )
        {
        TDesC8* fromHdr = iSVPSession->FromHeader();
        if ( fromHdr )
            {
            TInt indexLeft = fromHdr->Find( KSVPLeftBracketMark );
            TInt indexRight = fromHdr->Find( KSVPRightBracketMark );
            SVPDEBUG3( "CSVPTransferStateContext::SetupHeadersL: indexLeft = %d, indexRight =  %d", indexLeft, indexRight );

            tempRefBy.Append( fromHdr->Mid( indexLeft,
                    indexRight - indexLeft + KSVPSingleBracketLength ) );
            }
        }
    else
        {
        TDesC8* toHdr = iSVPSession->ToHeader();
        if ( toHdr )
            {
            TInt indexLeft = toHdr->Find( KSVPLeftBracketMark );
            TInt indexRight = toHdr->Find( KSVPRightBracketMark );
            SVPDEBUG3( "CSVPTransferStateContext::SetupHeadersL: indexLeft = %d, indexRight =  %d", indexLeft, indexRight )

            tempRefBy.Append( toHdr->Mid( indexLeft,
                    indexRight - indexLeft + KSVPSingleBracketLength ) );
            }
        }
    
    headers->AppendL( tempRefBy );
    CleanupStack::Pop( headers );
    
    SVPDEBUG1( "CSVPTransferStateContext::SetupHeadersL Out" )
    return headers;
    }

// ---------------------------------------------------------------------------
// CSVPTransferStateContext::InitializeStateArrayL
// ---------------------------------------------------------------------------
//
void CSVPTransferStateContext::InitializeStateArrayL()
    {
    // Create the array of the transfer states.
    iStates = new ( ELeave ) RPointerArray<CSVPTransferStateBase>
            ( KSVPTransferStateArraySize );
    
    // Transfer state classes are created here:
    // Idle state
    CSVPTransferStateBase* state = CSVPTransferIdleState::NewLC();
    User::LeaveIfError( iStates->Insert(
            state, KSVPTransferIdleStateIndex ) );
    CleanupStack::Pop( state );
    
    // Pending state
    state = CSVPTransferPendingState::NewLC();
    User::LeaveIfError( iStates->Insert(
            state, KSVPTransferPendingStateIndex ) );
    CleanupStack::Pop( state );
    
    // Accepted state
    state = CSVPTransferAcceptedState::NewLC();
    User::LeaveIfError( iStates->Insert(
            state, KSVPTransferAcceptedStateIndex ) );
    CleanupStack::Pop( state );
    
    // Terminating state
    state = CSVPTransferTerminatingState::NewLC();
    User::LeaveIfError( iStates->Insert(
            state, KSVPTransferTerminatingStateIndex ) );
    CleanupStack::Pop( state );
    
    // Terminated state
    state = CSVPTransferTerminatedState::NewLC();
    User::LeaveIfError( iStates->Insert(
            state, KSVPTransferTerminatedStateIndex ) );
    CleanupStack::Pop( state );
    }

// -----------------------------------------------------------------------------
// CSVPTransferStateContext::IsStateTransitionAccepted
// -----------------------------------------------------------------------------
//
TBool CSVPTransferStateContext::IsStateTransitionAccepted(
        const TSVPTransferStateIndex aNewState )
	{
	TSVPTransferStateIndex current = CurrentState();
	
    SVPDEBUG2( "CSVPTransferStateContext::IsStateTransitionAccepted: current  = %d", current )
    SVPDEBUG2( "CSVPTransferStateContext::IsStateTransitionAccepted: newstate = %d", aNewState )
    
    switch( current )
        {
        case KErrNotFound:
            {
            // Only idle state can be the first one.
            if ( KSVPTransferIdleStateIndex  == aNewState )
                {
                return ETrue;
                }
            else
                {
                return EFalse;
                }
            }
        
        case KSVPTransferIdleStateIndex:
            {
            if ( KSVPTransferPendingStateIndex == aNewState ||
                 KSVPTransferTerminatingStateIndex == aNewState )
                {
                return ETrue;
                }
            else
                {
                return EFalse;
                }
            }
        
        case KSVPTransferPendingStateIndex:
            {
            if ( KSVPTransferAcceptedStateIndex == aNewState ||
                 KSVPTransferTerminatingStateIndex == aNewState )
                {
                return ETrue;
                }
            else
                {
                return EFalse;
                }
            }
        
        case KSVPTransferAcceptedStateIndex:
            {
            // If in accepted state, new transition is valid (return true).
            // No transition actually occurs because
            // state "changes" from accepted to accepted.
            // This ignores sequent icoming NOTIFY's after REFER has been sent.
            if ( KSVPTransferTerminatingStateIndex == aNewState ||
                    KSVPTransferAcceptedStateIndex == aNewState)
                {
                return ETrue;
                }
            else
                {
                return EFalse;
                }
            }
        
        case KSVPTransferTerminatingStateIndex:
            {
            // From terminating state, transition to terminated is accepted.
            if ( KSVPTransferTerminatingStateIndex == aNewState ||
                 KSVPTransferTerminatedStateIndex == aNewState )
                {
                return ETrue;
                }
            else
                {
                return EFalse;
                }
            }
        
        case KSVPTransferTerminatedStateIndex:
            {
            // From terminated state, transition to idle is accepted.
            if ( KSVPTransferIdleStateIndex == aNewState )
                {
                return ETrue;
                }
            else
                {
                return EFalse;
                }
            }
        
        default:
            {
            // Should not come here, since all the states are handled
            SVPDEBUG1( "CSVPTransferStateContext::IsStateTransitionAccepted - Error" )
            return EFalse;
            }
        // No breaks in switch case due returns.  
        }
	}