convergedcallengine/cce/src/cccecall.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:15:03 +0100
branchRCL_3
changeset 20 987c9837762f
parent 19 7d48bed6ce0c
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006-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:  Base class of call object
*
*/


//  INCLUDE FILES
#include "cccecall.h"
#include <exterror.h>                // GSM error codes
#include <gsmerror.h>
#include <etelmm.h>
#include <ccpdefs.h>

#include <featmgr.h>

#include "mccptransferprovider.h"
#include "mccpcall.h"
#include "mccecallobserver.h"
#include "ccce.h"
#include "cccelogger.h"
#include "ccceutility.h"
#include "cccedurationtimer.h"
#include "mccpcscall.h"
#include "cccecallcontainer.h"
#include "cccetransfercontroller.h"
#include "ccceconferencecall.h"
#include "mccpforwardprovider.h"
#include "cccecallobserverasynchroniser.h"
#include "tccecallindex.h"

// ======== MEMBER FUNCTIONS ========
// ---------------------------------------------------------------------------
// Constructor
// ---------------------------------------------------------------------------
//
CCCECall::CCCECall( CCCECallContainer& aCallContainer, TInt aCallId ) :
    iCallId( aCallId ),
    iCallContainer( aCallContainer ),
    iCallIndex( KInvalidCallIndex )
    {
    Reset();
    }

// ---------------------------------------------------------------------------
// Construct object
// ---------------------------------------------------------------------------
//
void CCCECall::ConstructL()
    {
    FeatureManager::InitializeLibL();
    iCCEDurationTimer = CCCEDurationTimer::NewL();
    iObserver = CCCECallObserverAsynchroniser::NewL();
    }
    
// ---------------------------------------------------------------------------
// Default Symbian constructor (object is left into cleanupstack)
// ---------------------------------------------------------------------------
//
CCCECall* CCCECall::NewLC( CCCECallContainer& aCallContainer, TInt aCallId )
    {
    CCCECall* self = new( ELeave ) CCCECall( aCallContainer, aCallId );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// Destructor
// ---------------------------------------------------------------------------
//
CCCECall::~CCCECall()
    {
    Reset();
    delete iCCEDurationTimer;
    delete iObserver;
    delete iCallParameters;
	FeatureManager::UnInitializeLib();
    }

// ---------------------------------------------------------------------------
// SetObserver( MCCECallObserver& aObserver )
// ---------------------------------------------------------------------------
//
void CCCECall::SetObserver( const MCCECallObserver& aObserver )
    {
    CCELOGSTRING2("id:%d CCCECall::SetObserver()", iCallId);
    
    iObserver->SetMCCECallObserver( const_cast<MCCECallObserver*>( &aObserver ));
    
    if (iCCEDurationTimer)
        {
        iCCEDurationTimer->SetObserver( iObserver );
        }
    }

// ---------------------------------------------------------------------------
// SetConvergedCall( MCCPCall* aCall )
// ---------------------------------------------------------------------------
//
void CCCECall::SetConvergedCallL( MCCPCall* aCall, 
                                 TUid aImplementationUid,
                                 TBool aTransferred )
    {
    CCELOGSTRING2("id:%d CCCECall::SetConvergedCall():IN", iCallId);
       
    iCall = aCall;
    iImplementationUid = aImplementationUid;
    
    delete iCallParameters;
    iCallParameters = NULL;
    iCallParameters = aCall->Parameters().CloneL();
    
    
    // This object is now in use

    CCELOGSTRING3("id:%d CCCECall::SetConvergedCall: CallId = %d", iCallId, iCallId);
    // Reserve call id for this call
    // If this is transferred call then call id has been already reserved
    if( !aTransferred )
        {
        iCallContainer.ReserveCallInfoCallId( iCallId );    
        }
    
    CCELOGSTRING2("id:%d CCCECall::SetConvergedCall: CallId reserved", iCallId);
    
    // Set call direction
    if( aCall->IsMobileOriginated() ) 
        {
        CCELOGSTRING2("id:%d CCCECall::SetConvergedCall:Mobile originated call", iCallId);
        iCallDirection = CCPCall::EMobileOriginated;
        }
    else
        {
        CCELOGSTRING2("id:%d CCCECall::SetConvergedCall():Mobile terminated call", iCallId);
        
        if ( !aTransferred )
            {
            iCallState  = CCPCall::EStateRinging;
            }
        iCallDirection = CCPCall::EMobileTerminated;
        aCall->AddObserverL(*this);
        }

    TRAP_IGNORE( iTransferProvider = iCall->TransferProviderL(*this) );
    
    TRAP_IGNORE( iForwardProvider = iCall->ForwardProviderL(*this) );

    CCELOGSTRING2("id:%d CCCECall::SetConvergedCall():OUT", iCallId);
    }

// ---------------------------------------------------------------------------
// Returns implementationuid
// ---------------------------------------------------------------------------
//
const TUid CCCECall::ImplementationUid() const
    {
    return iImplementationUid;
    }

// ---------------------------------------------------------------------------
// From base class MCCECallInfo
// Returns direction of the call
// ---------------------------------------------------------------------------
//
CCPCall::TCallDirection CCCECall::Direction() const
    {
    return iCallDirection;
    }

// ---------------------------------------------------------------------------
// From base class MCCECallInfo
// Returns the type of the call
// ---------------------------------------------------------------------------
//
CCPCall::TCallType CCCECall::CallType() const
    {
    if ( iCallParameters )
        {
        return iCallParameters->CallType();
        }
    return CCPCall::ECallTypeCSVoice;
    }

// ---------------------------------------------------------------------------
// From base class MCCECallInfo, MCCECall
// Returns the index of the call
// ---------------------------------------------------------------------------
//
TInt CCCECall::CallIndex() const
    {
    return iCallIndex;
    }

// ---------------------------------------------------------------------------
// ServiceId
// ---------------------------------------------------------------------------
//
TUint32 CCCECall::ServiceId() const 
    {
    if( iCall )
        {
        return iCall->Parameters().ServiceId(); 
        }
    return 0;
    }

// ---------------------------------------------------------------------------
// Return ETrue if this call object is in use
// ---------------------------------------------------------------------------
//
TBool CCCECall::IsInUse() const
    {
    CCELOGSTRING3("id:%d CCCECall::IsInUse() %d", iCallId, ( iCall != NULL ) );
    return ( iCall != NULL );
    }

// ---------------------------------------------------------------------------
// Return ETrue if this calls secure status can be specified
// ---------------------------------------------------------------------------
//
TBool CCCECall::SecureSpecified() const
    {
    return iCall->SecureSpecified();
    }

// ---------------------------------------------------------------------------
// Return ETrue if this call object is secured
// ---------------------------------------------------------------------------
//
TBool CCCECall::IsSecured() const
    {
    return iCall->IsSecured();
    }

// ---------------------------------------------------------------------------
// Return if call is an emergency call or not.
// ---------------------------------------------------------------------------
//
TBool CCCECall::IsEmergency() const
    {
    return EFalse;
    }

// ---------------------------------------------------------------------------
// CCCECall::RemoteParty
// ---------------------------------------------------------------------------
//
const TDesC& CCCECall::RemoteParty() const
    {
    if( iCall )
        {
        return iCall->RemoteParty();
        }

    return KNullDesC;
    }

// ---------------------------------------------------------------------------
// CCCECall::RemotePartyName
// ---------------------------------------------------------------------------
//
const TDesC& CCCECall::RemotePartyName() const
    {
    if( iCall )
        {
        return iCall->RemotePartyName();
        }

    return KNullDesC;
    }

// ---------------------------------------------------------------------------
// CCCECall::DialledParty
// ---------------------------------------------------------------------------
//
const TDesC& CCCECall::DialledParty() const
    {
    if( iCall )
        {
        return  iCall->DialledParty();
        }

    return KNullDesC;
    }

// ---------------------------------------------------------------------------
// Return current active request
// ---------------------------------------------------------------------------
//
CCCECall::TCallRequest CCCECall::Request() const
    {
    return iActiveRequest;
    }
    
// ---------------------------------------------------------------------------
// Returns reference to converged call provider call object
// ---------------------------------------------------------------------------
//
MCCPCall& CCCECall::GetCCPCall() const
    {
    return *iCall;
    }

// ---------------------------------------------------------------------------
// CallId()
// Returns ID of the call
// ---------------------------------------------------------------------------
//
TInt CCCECall::CallId() const
    {
    return iCallId;
    }

// ---------------------------------------------------------------------------
// From class MCCECall.
// Hold()
// ---------------------------------------------------------------------------
//
TInt CCCECall::Hold()
    {
    CCELOGSTRING2( "id:%d CCCECall::Hold() ", iCallId);
    TInt error = KErrNone;
    
    if( iCallState != CCPCall::EStateConnected )
        {
        if( iCallState == CCPCall::EStateHold )
            {
            error = KErrAlreadyExists;
            }
        else
            {
            error = KErrNotReady;
            }
        }
    else
        {
        iActiveRequest = ECCEHold;
        error = iCall->Hold();
        }

    return error;
    }

// ---------------------------------------------------------------------------
// From class MCCECall.
// Resume()
// ---------------------------------------------------------------------------
//
TInt CCCECall::Resume()
    {
    CCELOGSTRING2( "id:%d CCCECall::Resume()", iCallId );
    TInt error = KErrNone;
    
    if( iCallState != CCPCall::EStateHold )
        {
        if( iCallState == CCPCall::EStateConnected )
            {
            error = KErrAlreadyExists;
            }
        else
            {
            error = KErrNotReady;
            }
        }
    else
        {
        iActiveRequest = ECCEResume;
        error = iCall->Resume();
        }

    return error;
    }

// ---------------------------------------------------------------------------
// From class MCCECall.
// HangUp()
// ---------------------------------------------------------------------------
//
TInt CCCECall::HangUp()
    {
    CCELOGSTRING3("id:%d CCCECall::HangUp() callstate = %d", iCallId, iCallState);

    TInt error = KErrNone;

    // Inform that currently ongoing request is canceled
    if( iActiveRequest != ECCENone &&
        iActiveRequest != ECCEReleaseActive &&
        iActiveRequest != ECCEReleaseHeld &&
        iActiveRequest != ECCEReleaseOutgoing &&
        iActiveRequest != ECCETerminateDisconnected )
        {
        RequestComplete( ECCPErrorCancel );
        }
    
    switch(iCallState)
        {
        case CCPCall::EStateDialling:
            CCELOGSTRING2("id:%d CCCECall::HangUp(): DialCancel: Cancel", iCallId);
            iActiveRequest = ECCEReleaseOutgoing;

            error = iCall->Cancel();

            RequestComplete( ECCPErrorNone );
            CallStateChanged( MCCPCallObserver::ECCPStateIdle, EFalse );
            break;
            
        case CCPCall::EStateConnecting:
            CCELOGSTRING2("id:%d CCCECall::HangUp(): DialCancel: HangUp", iCallId);
            iActiveRequest = ECCEReleaseOutgoing;
            NotifyCallStatusChange( 
                    CCPCall::EStateDisconnecting, ETrue, CCECallEnums::ENoNotify );
            error = iCall->HangUp();
            break;

        case CCPCall::EStateAnswering:
        case CCPCall::EStateRinging:
        case CCPCall::EStateQueued:
            CCELOGSTRING2("id:%d CCCECall::HangUpL: Reject", iCallId);
            iActiveRequest = ECCERejectIncoming;
            // Set exitcode to rejected to avoid 
            // missed call notification
            iExitCode = ECCPErrorRejected;
            NotifyCallStatusChange( 
                    CCPCall::EStateDisconnecting, ETrue, CCECallEnums::ENoNotify );
            error = iCall->Reject();
            break;
            
        case CCPCall::EStateDisconnecting: 
            if( ECCETerminateDisconnected != iActiveRequest &&
                ECCEReleaseOutgoing != iActiveRequest )
                {
                RequestComplete( ECCPErrorNone );
                iActiveRequest = ECCETerminateDisconnected;
                error = iCall->HangUp();
                }
            else 
                {
                error = KErrGeneral;  
                }   
            break;
            
        case CCPCall::EStateIdle:
            error = KErrAlreadyExists;
            break;
            
        case CCPCall::EStateHold:
            iActiveRequest = ECCEReleaseHeld;
            iCCEDurationTimer->Stop();
            NotifyCallStatusChange( 
                    CCPCall::EStateDisconnecting, ETrue, CCECallEnums::ENoNotify );
            error = iCall->HangUp();
            break;
            
        case CCPCall::EStateConnected:
            iActiveRequest = ECCEReleaseActive;
            iCCEDurationTimer->Stop();
            NotifyCallStatusChange( 
                    CCPCall::EStateDisconnecting, ETrue, CCECallEnums::ENoNotify );
            error = iCall->HangUp();
            break;
            
        default:
            CCCEUtility::Panic( ECCEPanicInvalidState ); 
            break;
        }
        


    // If hangup was completed successfully, change
    // call status to disconnecting. This must be done
    // because if hangup was caused by replace -command
    // and in that case AnswerIncomingCall is called right
    // after hangup. If call is not changed to disconnecting
    // state, ResumeAutomaticallyHeldCall would try to
    // resume this call and it causes error.
    return error;
    }

// ---------------------------------------------------------------------------
// Swap()
// ---------------------------------------------------------------------------
//
TInt CCCECall::Swap()
    {
    CCELOGSTRING2( "id:%d CCCECall::Swap()", iCallId );
    
    TInt error = KErrNone;

    // if there is other CSProvider call use swap instead of Hold
    if ( ( iImplementationUid == KCSProviderUid || 
           iImplementationUid == KVCCProviderUid ) && 
         ( IsCsPlugin() ) && 
           1 < iCallContainer.CountCsCalls( iImplementationUid ) )
        {
        error = iCall->Swap();
        }
    else if( iCallState == CCPCall::EStateConnected )
        {
        // Swapping starts - 1.phase
        error = HoldNoNotify();
        }
    else
        {
        error = KErrNotReady;
        
        iActiveRequest = ECCENone;
        }

    if( !error )
        {
        // Everything went ok
        iActiveRequest = ECCESwap;
        }

    return error;
    }

// ---------------------------------------------------------------------------
// NotifyRequestComplete( TInt aRequest, TCCPError aError )
// ---------------------------------------------------------------------------
//
void CCCECall::NotifyRequestComplete( TInt aRequest, TCCPError aError )
    {
    CCELOGSTRING4("id:%d CCCECall::NotifyRequestComplete: aRequest = %d, aError = %d", 
        iCallId, aRequest, aError );

    // Notify observer, if NoNotify is NOT set
    if ( aRequest == iDoNotReportRequest )
        {
        iDoNotReportRequest = KErrNotFound;
        }
    else
        {
        if( iObserver )
            {
            iObserver->ErrorOccurred( aError );
            }
        else
            {
            CCELOGSTRING( "CCCECall::NotifyRequestComplete: observer was NOT set!" );
            }
        }
    }

// ---------------------------------------------------------------------------
// GetMobileCallInfo( TDes8& aCallInfo ) const
// TODO: We should use our own packet instead of TMobileCallInfoV3Pckg
// ---------------------------------------------------------------------------
//
void CCCECall::GetMobileCallInfo( TDes8& aCallInfo ) const
    {
    CCELOGSTRING3("id:%d CCCECall::GetMobileCallInfo() Call = %d", iCallId, iCallId);
    
    RMobileCall::TMobileCallInfoV3Pckg& pckg =
        reinterpret_cast<RMobileCall::TMobileCallInfoV3Pckg&>( aCallInfo );

    // Check for call object needed, due call info can be fetched
    // also if dial fails.
    if ( iCall )
        {
        RMobileCall::TMobileCallStatus state = RMobileCall::EStatusUnknown;

        switch(iCallState)
            {
            case CCPCall::EStateIdle:
                state = RMobileCall::EStatusIdle;
                break;
            case CCPCall::EStateRinging:
                state = RMobileCall::EStatusRinging;
                break;
            case CCPCall::EStateConnecting:
                state = RMobileCall::EStatusConnecting;
                break;
            case CCPCall::EStateConnected:
                state = RMobileCall::EStatusConnected;
                break;
            case CCPCall::EStateDisconnecting:
                state = RMobileCall::EStatusDisconnecting;
                break;
            case CCPCall::EStateHold:
                state = RMobileCall::EStatusHold;
                break;
            case CCPCall::EStateTransferring:
                state = RMobileCall::EStatusTransferring;
                break;
            case CCPCall::EStateForwarding:
                state = RMobileCall::EStatusConnecting;
                break;
            case CCPCall::EStateQueued:
                state = RMobileCall::EStatusRinging;
                break;
            case CCPCall::EStateAnswering:
                state = RMobileCall::EStatusAnswering;
                break;
            case CCPCall::EStateDialling:
                state = RMobileCall::EStatusDialling;
                break;
            default:
                state = RMobileCall::EStatusUnknown;
                break;
            }
        
        if( IsCsPlugin() )
            {
            TInt error = 
                static_cast<MCCPCSCall*>(iCall)->GetMobileCallInfo(aCallInfo);
            
            pckg().iCallId = iCallId+1;
            pckg().iStatus = state;
            pckg().iDuration = iCCEDurationTimer->NumberOfBeats();
            return;
            }

        TInt err = KErrNone;
        switch( iExitCode )
            {
            case ECCPErrorNone:
                break;
            /**
            General: KErrNotFound
            */
            case ECCPErrorNotFound:
                err = KErrNotFound;
                break;
            /**
            General: KErrGeneral 
            */
            case ECCPErrorGeneral:
                err = KErrGeneral;
                break;

            /**
            General: KErrCancel
            */
            case ECCPErrorCancel:
                err = KErrCancel;
                break;

            /** 
            General: KErrNoMemory */
            case ECCPErrorNoMemory:
                err = KErrNoMemory;
                break;

            /** 
            General: KErrNotSupported */
            case ECCPErrorNotSupported:
                err = KErrNotSupported;
                break;
                
            /**
            General: KErrInUse
            */
            case ECCPErrorAlreadyInUse:
                err = KErrInUse;
                break;

            /**
            No corresponding cs/sip error identified yet.
            */
            case ECCPErrorNotReady:
                err = KErrNotReady;
                break;

            /** 
            KErrGsmCCFacilityRejected
            KErrGsmCallServerFail
            KErrGsm0707NotFound
            */
            case ECCPErrorRejected:
            case ECCPErrorCCFacilityRejected:
                err = KErrGsmCCFacilityRejected;
                break;

            /** 
            KErrGsmCCUnassignedNumber 
            SIP: 404 Not found
            */
            case ECCPErrorNotReached:
                err = KErrGsmCCUnassignedNumber;
                break;

            /** KErrGsmCCNumberChanged
            SIP: 301 Moved permanently/410 Gone
            */
            case ECCPErrorMovedPermanently:
                err = KErrGsmCCNumberChanged;
                break;
            /**
            KErrGsmCCInvalidNumberFormat
            SIP: BadUri
            */
            case ECCPErrorInvalidURI:
                err = KErrGsmCCInvalidNumberFormat;
                break;

            /** 
            KErrGsmCCNetworkOutOfOrder
            SIP: 502 Bad gateway
            (redial logic needs)
            */
            case ECCPErrorNetworkOutOfOrder:
                err = KErrGsmCCNetworkOutOfOrder;
                break;

            /** 
            KErrGsmCCUserBusy
            SIP: 486 Busy here
            */
            case ECCPErrorBusy:
                err = KErrGsmCCUserBusy;
                break;

            /** 
            KErrGsmCCUserNotResponding
            SIP: 480 Temporarily unavailable
            */
            case ECCPErrorNotResponding:
            case ECCPErrorCCUserNotResponding:
                err = KErrGsmCCUserNotResponding;
                break;

            /** 
            KErrGsmCCTemporaryFailure
            SIP: 500 Internal server error
            KErrGsmCCSwitchingEquipmentCongestion
            SIP: 503 Service unavailable
            KErrGsmCCRequestedChannelNotAvailable
            */
            case ECCPErrorNetworkBusy:
                err = KErrGsmCCTemporaryFailure;
                break;

            /** 
            KErrGsmCCNoRouteToDestination
            SIP: 404 Not Found
            SIP: 404 Not found / Timeout
            SIP: 503 Service unavailable
            */
            case ECCPErrorConnectionErrorRedial:
            case ECCPErrorCCNoRouteToDestination:
                err = KErrGsmCCNoRouteToDestination;
                break;

            /**
            KErrArgument
            */
            case ECCPErrorInvalidPhoneNumber:
                err = KErrArgument;
                break;

            /**
            KErrGsmNoService
            */
            case ECCPErrorNoService:
                err = KErrGsmNoService;
                break;

            /**
            KErrGsmNoNumber
            */
            case ECCPErrorInvalidPhoneNumberCancelRedial:
                err = KErrGsmNoNumber;
                break;

            /**
            KErrGsmReleaseByUser
            */
            case ECCPErrorReleaseByUserForCancelRedial:
                err = KErrGsmReleaseByUser;
                break;

            /**
            KErrGsmCCRequestedFacilityNotImplemented
            */
            case ECCPErrorServiceSettingError:
                err = KErrGsmCCRequestedFacilityNotImplemented;
                break;

            /**
            KErrGsm0707SimNotInserted
            KErrGsm0707SIMPuk1Required
            KErrGsm0707SimPin1Required
            KErrGsm0707SimPin2Required
            KErrGsm0707SimFailure
            KErrGsm0707PhoneToSimLockRequired
            KErrGsm0707SimWrong
            */
            case ECCPErrorAuthenticationFailed:
                err = KErrGsm0707SimNotInserted;
                break;

            /**
            KErrGsmOfflineOpNotAllowed
            */
            case ECCPErrorNotAllowedInOfflineMode:
                err = KErrGsmOfflineOpNotAllowed;
                break;

            /**
            KErrMMEtelCallForbidden
            KErrGsmCallInProgress
            KErrGsmNumberBarred
            KErrGsmNotAllowed
            KErrEtelCallNotActive
            KErrEtelCallAlreadyActive
            SIP: 403 Forbidden
            */
            case ECCPErrorNotAllowed:
                err = KErrGsmNotAllowed;
                break;

            /**
            KErrTimedOut
            */
            case ECCPErrorTimedOut:
                err = KErrTimedOut;
                break;

            /**
            KErrGsmInvalidFdn
            */
            case ECCPErrorInvalidFDN:
                err = KErrGsmInvalidFdn;
                break;

            /**
            KErrGsmCCChannelUnacceptable
            */
            case ECCPErrorUnacceptableChannel:
                err = KErrGsmCCChannelUnacceptable;
                break;

            /**
            KErrGsmCCAccessInformationDiscarded
            */
            case ECCPErrorAccessInformationDiscarded:
                err = KErrGsmCCAccessInformationDiscarded;
                break;

            /**
            KErrGsmCCQualityOfServiceNotAvailable
            */
            case ECCPErrorQualityOfServiceNotAvailable:
                err = KErrGsmCCQualityOfServiceNotAvailable;
                break;

            /**
            KErrGsmCCInvalidCallReferenceValue
            */
            case ECCPErrorInvalidCallReferenceValue:
                err = KErrGsmCCInvalidCallReferenceValue;
                break;

            /**
            KErrGsmCCInvalidTransitNetworkSelection
            KErrGsmCCSemanticallyIncorrectMessage
            KErrGsmCCConditionalIEError
            SIP: 400 Bad request
            KErrGsmCCUnspecifiedProtocolError
            SIP: 400 Bad request
            SIP: 400 Bad request
            */
            case ECCPErrorConnectionError:
            case ECCPErrorCCInvalidTransitNetworkSelection:
                err = KErrGsmCCInvalidTransitNetworkSelection;
                break;

            /**
            KErrGsmCCIncompatibleDestination
            SIP: 400 Bad request
            */
            case ECCPErrorBadRequest:
            case ECCPErrorCCIncompatibleDestination:
                err = KErrGsmCCIncompatibleDestination;
                break;

            /**
            KErrGsmCCOperatorDeterminedBarring
            SIP: 403 Forbidden
            */
            case ECCPErrorNumberBarred:
                err = KErrGsmCCOperatorDeterminedBarring;
                break;

            /**
            KErrGsmCCNormalUnspecified
            400 Bad request
            */
            case ECCPErrorNoAnswerForVideo:
                err = KErrGsmCCNormalUnspecified;
                break;

            /**
            KErrPhoneEngineNoWcdmaNetwork
            */
            case ECCPErrorVideoCallNotSupportedByNetwork:
            //  err = KErrPhoneEngineNoWcdmaNetwork;
                break;

            /**
            KErrPhoneEngineVideoCallNotAllowedDuringRestore
            */
            case ECCPErrorVideoCallNotAllowedDuringRestore:
            //  err = KErrPhoneEngineVideoCallNotAllowedDuringRestore;
                break;
                
            /**
            KErrPhoneEngineVideoCallSetupFailed
            */
            case ECCPErrorVideoCallSetupFailed:
            //  err = KErrPhoneEngineVideoCallSetupFailed;
                break;

            /**
            KErrDiagnosticInfoBarredWithCUG
            */
            case ECCPErrorCUGOutgoingCallsBarred:
    //            err = KErrDiagnosticInfoBarredWithCUG;
                break;

            /**
            KErrDiagnosticInfoBarredNoCUG
            */
            case ECCPErrorCUGNotSelected:
     //           err = KErrDiagnosticInfoBarredNoCUG;
                break;

            /**
            KErrDiagnosticInfoBarredUnknownCUG
            */
            case ECCPErrorCUGIndexUnknown:
     //           err = KErrDiagnosticInfoBarredUnknownCUG;
                break;

            /**
            KErrDiagnosticInfoBarredIncompatibleCUG
            */
            case ECCPErrorCUGIndexIncompatible:
    //            err = KErrDiagnosticInfoBarredIncompatibleCUG;
                break;

            /**
            KErrDiagnosticInfoBarredFailureCUG
            */
            case ECCPErrorCUGCallsFailure:
     //           err = KErrDiagnosticInfoBarredFailureCUG;
                break;

            /**
            KErrDiagnosticInfoBarredClirNotSubscribed
            */
            case ECCPErrorCLIRNotSubscribed:
     //           err = KErrDiagnosticInfoBarredClirNotSubscribed;
                break;

            /**
            KErrDiagnosticInfoBarredCCBSPossible
            */
            case ECCPErrorCCBSPossible:
      //          err = KErrDiagnosticInfoBarredCCBSPossible;
                break;

            /**
            KErrDiagnosticInfoBarredCCBSNotPossible
            */
            case ECCPErrorCCBSNotPossible:
      //          err = KErrDiagnosticInfoBarredCCBSNotPossible;
                break;

            /**
            Secure call failed.
            */
            case ECCPSecureCallFailed:
                err = KErrGsmCCChannelUnacceptable;
                break;

            /**
            Emergency call failed.
            */
            case ECCPEmergencyFailed:
                err = KErrGsmCCAcmGreaterThanAcmMax;
                break;

            /**
            Transfer failed.
            */
            case ECCPTransferFailed:
            /**
            Local hold failed.
            */
            case ECCPLocalHoldFail:
            /**
            Local resume failed.
            */
            case ECCPLocalResumeFail:
                err = KErrGsmCCNormalUnspecified;
                break;

            /**
            When none of other errors map and received a 3XX response. 
            */
            case ECCPRedirection:
                err = KErrGsmCCUnassignedNumber;
                break;

            /**
            When none of other errors map and received a 4XX response. 
            */
            case ECCPRequestFailure:
                err = KErrGsmCCUnassignedNumber;
                break;

            /**
            When none of other errors map and received a 5XX response. 

            */
            case ECCPServerFailure:
                err = KErrGsmCallServerFail;
                break;

            /** 
            When none of other errors map and received a 6XX response. 
            */
            case ECCPGlobalFailure:
                err = KErrGsmCCUnspecifiedProtocolError;
                break;

            /** Rtp detection media error. */
            case ECCPErrorMedia:
                err = KErrGsmCCUnspecifiedProtocolError; // TODO
                break;

            /**
            KErrGsmCCServiceNotImplemented
            SIP 488 Not Acceptable Here 
            SIP 606 Not Acceptable 
            */
            case ECCPErrorNotAcceptable:
            case ECCPErrorCCServiceNotImplemented:
                err = KErrGsmCCServiceNotImplemented;
                break;
            
            /* Access denied error */
            case ECCPErrorAccessDenied:
                err = KErrAccessDenied;
                break;


            /**
            KErrGsmCCDestinationOutOfOrder
            */
            case ECCPErrorCCDestinationOutOfOrder:                
                err = KErrGsmCCDestinationOutOfOrder;
                break;

            /**
            KErrGsmCCResourceNotAvailable
            */
            case ECCPErrorCCResourceNotAvailable:
                err = KErrGsmCCResourceNotAvailable;
                break;

            /** 
            KErrGsmCCIncompatibleMessageInCallState;
            */
            case ECCPErrorCCIncompatibleMessageInCallState:
                err = KErrGsmCCIncompatibleMessageInCallState;
                break;

            /** 
            KErrGsmCCIncompatibleMessageInProtocolState;
            */
            case ECCPErrorCCIncompatibleMessageInProtocolState:
                err = KErrGsmCCIncompatibleMessageInProtocolState;
                break;


            /** 
            KErrGsmCCNormalCallClearing;
            */
            case ECCPErrorCCNormalCallClearing:
                err = KErrGsmCCNormalCallClearing;
                break;


            /** 
            KErrGsmCCUserAlertingNoAnswer;
            */
            case ECCPErrorCCUserAlertingNoAnswer:
                err = KErrGsmCCUserAlertingNoAnswer;
                break;

            /** 
            KErrGsmCCCallRejected;
            */
            case ECCPErrorCCCallRejected:
                err = KErrGsmCCCallRejected;
                break;


            /** 
            KErrGsmCCPreemption;
            */
            case ECCPErrorCCPreemption:
                err = KErrGsmCCPreemption;
                break;

            /** 
            KErrGsmCCResponseToStatusEnquiry;
            */
            case ECCPErrorCCResponseToStatusEnquiry:
                err = KErrGsmCCResponseToStatusEnquiry;
                break;


            /** 
            KErrGsmCCInvalidMandatoryInformation;
            */
            case ECCPErrorCCInvalidMandatoryInformation:
                err = KErrGsmCCInvalidMandatoryInformation;
                break;


            /** 
            KErrGsmCCNonExistentMessageType;
            */
            case ECCPErrorCCNonExistentMessageType:
                err = KErrGsmCCNonExistentMessageType;
                break;


            /** 
            KErrGsmCCNonExistentInformationElement;
            */
            case ECCPErrorCCNonExistentInformationElement:
                err = KErrGsmCCNonExistentInformationElement;
                break;


            /** 
            KErrGsmCCNoChannelAvailable;
            */
            case ECCPErrorCCNoChannelAvailable:
                err = KErrGsmCCNoChannelAvailable;
                break;


            /** 
            KErrGsmCCRequestedFacilityNotSubscribed;
            */
            case ECCPErrorCCRequestedFacilityNotSubscribed:
                err = KErrGsmCCRequestedFacilityNotSubscribed;
                break;


            /** 
            KErrGsmCCIncomingCallsBarredInCug;
            */
            case ECCPErrorCCIncomingCallsBarredInCug:
                err = KErrGsmCCIncomingCallsBarredInCug;
                break;


            /** 
            KErrGsmCCBearerCapabilityNotAuthorised;
            */
            case ECCPErrorCCBearerCapabilityNotAuthorised:
                err = KErrGsmCCBearerCapabilityNotAuthorised;
                break;


            /** 
            KErrGsmCCBearerCapabilityNotCurrentlyAvailable;
            */
            case ECCPErrorCCBearerCapabilityNotCurrentlyAvailable:
                err = KErrGsmCCBearerCapabilityNotCurrentlyAvailable;
                break;


            /** 
            KErrGsmCCServiceNotAvailable;
            */
            case ECCPErrorCCServiceNotAvailable:
                err = KErrGsmCCServiceNotAvailable;
                break;


            /** 
            KErrGsmCCBearerServiceNotImplemented;
            */
            case ECCPErrorCCBearerServiceNotImplemented:
                err = KErrGsmCCBearerServiceNotImplemented;
                break;


            /** 
            KErrGsmCCOnlyRestrictedDigitalInformationBCAvailable;
            */
            case ECCPErrorCCOnlyRestrictedDigitalInformationBCAvailable:
                err = KErrGsmCCOnlyRestrictedDigitalInformationBCAvailable;
                break;

            /** 
            KErrGsmCCUnspecifiedInterworkingError;
            */
            case ECCPErrorCCUnspecifiedInterworkingError:
                err = KErrGsmCCUnspecifiedInterworkingError;
                break;


            /** User not in Gug */
            case ECCPErrorUserNotInCug: // TODO
            default:
                CCELOGSTRING3("id:%d CCCECall::GetMobileCallInfo() Unhandled iExitCode %d",
                    iCallId, iExitCode);
                break;
            }

        pckg().iValid =   RMobileCall::KCallDuration
                        | RMobileCall::KCallId
                        | RMobileCall::KCallRemoteParty
                        | RMobileCall::KCallDialledParty
                        | RMobileCall::KCallExitCode
                        | RMobileCall::KCallEmergency
                        | RMobileCall::KCallSecurity;

        pckg().iService = RMobilePhone::EVoiceService;
        pckg().iStatus = state;
        pckg().iCallId = iCallId+1;
        pckg().iExitCode = err;
        pckg().iEmergency = EFalse;
        pckg().iForwarded = iCall->IsCallForwarded();
        pckg().iDuration = iCCEDurationTimer->NumberOfBeats();
        pckg().iStartTime = iCCEDurationTimer->StartTime();
        
        pckg().iRemoteParty.iDirection = 
            (RMobileCall::TMobileCallDirection)iCallDirection;
        pckg().iRemoteParty.iRemoteNumber.iTelNumber = 
                iCall->RemoteParty().Left( RMobilePhone::KMaxMobileTelNumberSize );
                
        const TDesC& remoteParty = pckg().iRemoteParty.iRemoteNumber.iTelNumber;  

        if ( CCPCall::EMobileTerminated == iCallDirection )
            {
            if ( remoteParty == KNullDesC )
                {
                pckg().iRemoteParty.iRemoteIdStatus = 
                    RMobileCall::ERemoteIdentitySuppressed;
                }
            else
                {
                pckg().iRemoteParty.iRemoteIdStatus = 
                    RMobileCall::ERemoteIdentityAvailable;
                }

            pckg().iForwarded = EFalse;
            
            pckg().iValid |= RMobileCall::KCallForwarded;
            }
        else
            {
            pckg().iRemoteParty.iRemoteIdStatus = 
                RMobileCall::ERemoteIdentityUnknown;
            }

        pckg().iDialledParty.iTelNumber = remoteParty;
        pckg().iCallName = KNullDesC;      

        // InfoV3
        if ( iCallState == CCPCall::EStateConnected )
            { 
            if ( iCall->IsSecured())
                {
                // Because ETel does not support VoIP, GSM ciphering is reported
                pckg().iSecurity = RMobilePhone::ECipheringGSM;
                }
            }
       else
            {
            pckg().iSecurity = RMobilePhone::ECipheringOff;
            }
        }
    else
        {
        CCELOGSTRING2("id:%d CCCECall::GetMobileCallInfo: Not found", iCallId);
        }
    }

// ---------------------------------------------------------------------------
// From class MCCECall.
// 
// ---------------------------------------------------------------------------
//
CCPCall::TCallState CCCECall::State() const
    {
    CCELOGSTRING3( "id:%d CCCECall::State() = %d", iCallId, iCallState );
    return iCallState;
    }
    
// ---------------------------------------------------------------------------
// TCCPTone Tone() const
//
// ---------------------------------------------------------------------------
//
TCCPTone CCCECall::Tone() const
    {
    TCCPTone tone = iCall->Tone();  
    CCELOGSTRING3( "id:%d CCCECall::Tone() = %d", iCallId, (TInt)tone );
    return tone;
    
    }
// ---------------------------------------------------------------------------
// CallDuration() const
// ---------------------------------------------------------------------------
//
TTimeIntervalSeconds CCCECall::CallDuration() const
    {
    return iCCEDurationTimer->NumberOfBeats();
    }


// ---------------------------------------------------------------------------
// StartTime() const
// ---------------------------------------------------------------------------
//
TDateTime CCCECall::StartTime() const
    {
    return iCCEDurationTimer->StartTime();
    }

// ---------------------------------------------------------------------------
// Caps() const
// ---------------------------------------------------------------------------
//
MCCECallObserver::TCCECallControlCaps CCCECall::Caps() const
    {
    CCELOGSTRING3( "id:%d CCCECall::Caps(): caps = %d", iCallId, iCall->Caps() );
    
    return (MCCECallObserver::TCCECallControlCaps)iCall->Caps();
    }

// ---------------------------------------------------------------------------
// SetParameters()
// ---------------------------------------------------------------------------
//
void CCCECall::SetParameters( const CCCECallParameters& aNewParams )
    {
    delete iCallParameters;
    iCallParameters = NULL;
    TRAP_IGNORE(iCallParameters = aNewParams.CloneL());
    }

// ---------------------------------------------------------------------------
// Parameters() const
// ---------------------------------------------------------------------------
//
const CCCPCallParameters& CCCECall::Parameters() const
    {
    if ( FeatureManager::FeatureSupported( KFeatureIdFfVoiceCallContinuity ) )
        {
        return iCall->Parameters();
        }
    return *iCallParameters;
    }

// ---------------------------------------------------------------------------
// Get transfer target
// ---------------------------------------------------------------------------
//
const TDesC& CCCECall::TransferTarget() const
    {
    // nothing here yet
    return KNullDesC;
    }

// ---------------------------------------------------------------------------
// AttendedTransfer()
// ---------------------------------------------------------------------------
//
TInt CCCECall::AttendedTransfer( const TDesC& /*aTransferTarget*/ )
    {
    CCELOGSTRING2( "id:%d CCCECall::AttendedTransfer()", iCallId );
    TInt error = KErrNone;
      
    if ( iTransferProvider )
        {
        CCCECall* toCall = iCallContainer.GetCall( 
                CCPCall::EStateConnected, this );
        
        // On cs world it is possible to transfer call to connecting
        // call
        if( !toCall )
            {
            toCall = iCallContainer.GetCall( 
                    CCPCall::EStateConnecting, this );
            
            TBool condition( EFalse );
            
            if ( FeatureManager::FeatureSupported( 
                    KFeatureIdFfVoiceCallContinuity ) )
                {
                if ( toCall && 
                     toCall->Parameters().CallType() != 
                         CCPCall::ECallTypeCSVoice )
                    {
                    condition = ETrue;
                    }
                }
            else 
                {
                if ( toCall && toCall->ImplementationUid() != KCSProviderUid )
                    {
                    condition = ETrue;
                    }
                }            
            if ( condition )    
            
                {
                toCall = NULL;
                }
            }
            
        if( toCall )
            {
            error = iTransferProvider->AttendedTransfer( toCall->GetCCPCall() );      
            
            if ( error == KErrNone )
                {
                iActiveRequest = ECCETransfer;
                }
            }    
        else
            {
            error = KErrNotReady;
            }
        }
    else
        {
        error = KErrNotSupported;
        }

    return error;
    }
    
// ---------------------------------------------------------------------------
// UnattendedTransfer( const TDesC& /*aTarget*/ )
// ---------------------------------------------------------------------------
//
TInt CCCECall::UnattendedTransfer( const TDesC& aTarget )
    {
    CCELOGSTRING2("id:%d CCCECall::UnattendedTransfer():IN", iCallId);
    TInt error = KErrNone;
   
    if( iTransferProvider )
        {
        error = iTransferProvider->UnattendedTransfer( aTarget );
        
        if ( error == KErrNone )
            {
            iActiveRequest = ECCEUnattendedTransfer;
            }
        }
    else
        {
        error = KErrNotSupported;
        }

    CCELOGSTRING2("id:%d CCCECall::UnattendedTransfer():OUT", iCallId);
    return error;
    }
    
// ---------------------------------------------------------------------------
// AcceptTransfer( TBool /*aAccept*/ )
// ---------------------------------------------------------------------------
//
TInt CCCECall::AcceptTransfer( const TBool aAccept )
    {
    CCELOGSTRING3("id:%d CCCECall::AcceptTransfer():IN aAccept=%d", iCallId,aAccept);
    TInt error = KErrNone;
   
    if( iTransferController &&
        iTransferProvider )
        {
        if( CCPCall::EStateConnected == iCallState ||
            CCPCall::EStateHold == iCallState )
            {
            iTransferProvider->AcceptTransfer( aAccept );
            if( aAccept )
                {
                iTransferController->SetTransferAccepted( aAccept );    
                }
            else
                {
                iTransferController->ReleaseTransferCall();    
                }
            }
        else
            {
            iTransferController->ReleaseTransferCall();    
            }   
        }
     else
        {
        error = KErrNotSupported;
        }
    CCELOGSTRING2("id:%d CCCECall::AcceptTransfer():OUT", iCallId);
    return error;
    }
    
// ---------------------------------------------------------------------------
// ForwardCallToAddressChoices()
// ---------------------------------------------------------------------------
//
const CDesC8Array& CCCECall::GetForwardAddressChoicesL()
    {
    CCELOGSTRING2("id:%d CCCECall::GetForwardAddressChoicesL()", iCallId);
    const CDesC8Array* array = NULL;
    
    if( iForwardProvider )
        {
        array = &iForwardProvider->GetForwardAddressChoicesL();
        }
    else
        {
        User::Leave( KErrNotSupported );
        }
        
    return *array;
    }
    
// ---------------------------------------------------------------------------
// ForwardCallToAddress( TInt /*aIndex*/ )
// ---------------------------------------------------------------------------
//    
void CCCECall::ForwardToAddressL( TInt aIndex )
    {
    CCELOGSTRING2("id:%d CCCECall::ForwardCallToAddress()", iCallId);
    if( iForwardProvider )
        {
        iForwardProvider->ForwardToAddressL( aIndex );
        }
    else
        {
        User::Leave( KErrNotSupported );
        }
    }

// ---------------------------------------------------------------------------
// From class MCCECall.
// Check if other call needs to placed on hold
// If no, continue call
// ---------------------------------------------------------------------------
//
TInt CCCECall::Dial( const TDesC8& aCallParams )
    {
    CCELOGSTRING2( "id:%d CCCECall::Dial()", iCallId );
    TInt error = KErrNone;

    if( iCallState != CCPCall::EStateIdle )
        {
        return KErrNotReady;
        }
    
    iCallParams = &aCallParams;
    iActiveRequest = ECCEDial;
    
    // If this is unattended transfer dial
    if( iTransferController &&
        iCall == iTransferController->TransferCall() )      
        {
        CCELOGSTRING2( "id:%d CCCECall::Dial(): TransferDial", iCallId);
        // Must wait that original call is disconnected before transfer
        // dial can be done
        if( MCCPCallObserver::ECCPStateDisconnecting == 
            iTransferController->OriginatorCall()->State() )
            {
            error = DoPendingRequest();
            }
        else
            {
            iTransferController->SetTransferDialPending( ETrue );
            }
        }
    else
        {
        
        CCCECall* call = iCallContainer.GetCall( 
                CCPCall::EStateConnected, this);
            
        if(call)
            {
            if( 0 == iCallContainer.ConferenceCall().EnumerateCalls() )
                {
                if( (iCallContainer.GetCall( 
                        CCPCall::EStateHold, this))  && (ECCENone != iActiveRequest))
                    {
                    CCELOGSTRING2( "id:%d CCCECall::Dial() failed. Too many calls. ", iCallId);
                    error = KErrInUse;
                    }
                else
                    {
                    error = call->HoldNoNotify();
                    }                                     
                }
            else
                {
                error = iCallContainer.ConferenceCall().Swap();
                }
            }
        else
            {
            // Continue dial if no other connected calls exist
            error = DoPendingRequest();
            }
        }
    return error;
    }
    
// ---------------------------------------------------------------------------
// From class MCCECSCall.
// NoFDNCheck()
// ---------------------------------------------------------------------------
//
void CCCECall::NoFDNCheck()
    {
    if ( IsCsPlugin() )    
        {
        static_cast<MCCPCSCall*>(iCall)->NoFDNCheck();
        }
    }
    
// ---------------------------------------------------------------------------
// From class MCCECall.
// Answer()
// ---------------------------------------------------------------------------
//
TInt CCCECall::Answer()
    {
    CCELOGSTRING2( "id:%d CCCECall::Answer()", iCallId );
    TInt error = KErrNone;
    iActiveRequest = ECCEAnswer;

    CCCECall* call = iCallContainer.GetCall( 
            CCPCall::EStateConnected, this);
        
    if(call)
        {
        if( 0 == iCallContainer.ConferenceCall().EnumerateCalls() )
            {
            if( (iCallContainer.GetCall(  
                    CCPCall::EStateHold, this))  && (ECCENone != iActiveRequest))
                {
                CCELOGSTRING2( "id:%d CCCECall::Answer() failed. Too many calls. "
                    , iCallId);
                error = KErrInUse;
                iActiveRequest = ECCENone; 
                }
            else
                {
                error = call->HoldNoNotify();
                }                                     
            }
        else
            {
            error = iCallContainer.ConferenceCall().Swap();
            }
        }
    else
        {
        // Continue answering if no other connected calls exist
        error = DoPendingRequest();
        }

    return error;
    }

// ---------------------------------------------------------------------------
// DoPendingRequest()
// This does the pending request. It can be called from cccecallcontainer
// ---------------------------------------------------------------------------
//
TInt CCCECall::DoPendingRequest()
    {
    CCELOGSTRING2( "id:%d CCCECall::DoPendingRequest()", iCallId );
    TInt error = KErrNone;
    
    if( iActiveRequest == ECCEDial )
        {
        CCELOGSTRING2("id:%d CCCECall::DoDial", iCallId);

        if ( IsCsPlugin() )
            {
            error = static_cast<MCCPCSCall*>(iCall)->Dial(*iCallParams);
            }
        else if( iCall )
            {
            error = iCall->Dial();
            }
        }
    else if( iActiveRequest == ECCEAnswer ||
             iActiveRequest == ECCEReplaceActive )
        {
        CCELOGSTRING2("id:%d CCCECall::DoAnswer", iCallId);
        error = iCall->Answer();
        }
    else
        {
        error = KErrNotFound;
        }
        
    return error;
    }

// ---------------------------------------------------------------------------
// DialEmergencyCall( const TDesC16& /*aNumber*/ )
// ---------------------------------------------------------------------------
//
void CCCECall::DialEmergencyCall( const TDesC16& /*aNumber*/ )
    {
    CCELOGSTRING2("id:%d CCCECall::DialEmergencyCall()", iCallId);
    }

// ---------------------------------------------------------------------------
// From class MCCECall.
// Close call object
// ---------------------------------------------------------------------------
//
TInt CCCECall::Release()
    {
    CCELOGSTRING2( "id:%d CCCECall::Release()", iCallId );
    
    if( CCPCall::EStateIdle != iCallState )
        {
        iCallContainer.HandleCallStatusChange( 
                CCPCall::EStateIdle, 
            this, CCECallEnums::ENotifySynchronously );    
        }
     
    // Stop duration timer if it is not yet stopped.
    iCCEDurationTimer->Stop();
    // Reset timer observer
    iCCEDurationTimer->SetObserver( NULL );
     
    // Delete converged call
    // Release call id
    iCallContainer.ReleaseCallInfoCallId( iCallId );

    if( iCall )
        {
        iCallContainer.ReleaseCall(*iCall);    
        }
    
    Reset();

    return KErrNone;
    }
    
// ---------------------------------------------------------------------------
// Request is to an ringing/waiting state call.
// Active call if found is hang-up
// When active call goes to idle incoming call is answered
// ---------------------------------------------------------------------------
//
TInt CCCECall::ReplaceActive()
    {
    CCELOGSTRING2( "id:%d CCCECall::ReplaceActive()", iCallId );
    TInt error = KErrNone;
    iActiveRequest = ECCEReplaceActive;
    CCCECall* callConnected = iCallContainer.GetCall( 
            CCPCall::EStateConnected, this);
        
    if ( callConnected )
        { 
        if ( !iCallContainer.ConferenceCall().IsPartOfConference( *callConnected ) )
            {    
            error = callConnected->GetCCPCall().HangUp();                                             
            }
        else if ( iCallContainer.ConferenceCall().State() == 
            MCCPConferenceCallObserver::ECCPConferenceActive )
            {
            error = iCallContainer.ConferenceCall().HangUp();
            }
            
        if ( KErrNone != error )
            {
            iActiveRequest = ECCENone;
            }
        }
    else
        {
        // Continue answering if no other connected calls exist
        error = DoPendingRequest();
        }

    return error;
    }
    
// ---------------------------------------------------------------------------
// Hold call but do not notify observer when completed
// ---------------------------------------------------------------------------
//
TInt CCCECall::HoldNoNotify()
    {
    CCELOGSTRING2( "id:%d CCCECall::HoldNoNotifyL()", iCallId );
    
    return iCall->Hold();
    }


// ---------------------------------------------------------------------------
// Resume call but do not notify observer when completed
// ---------------------------------------------------------------------------
//
TInt CCCECall::ResumeNoNotify()
    {
    CCELOGSTRING2( "id:%d CCCECall::ResumeNoNotifyL()", iCallId );
    
    return iCall->Resume();
    }

// ---------------------------------------------------------------------------
// HandleTransfer()
// Notifies phoneengine about received transfer request from remote end
// ---------------------------------------------------------------------------
//
void CCCECall::HandleTransfer(const TBool aAttented, 
    CCCETransferController& aTransferController )
    {
    iTransferController = &aTransferController;
    if( iObserver )
        {
        iObserver->HandleTransfer( aAttented,
            iTransferProvider->TransferTarget() );
        }
    else
        {
        CCELOGSTRING( "CCCECall::HandleTransfer: observer was NOT set!" );
        }
    }

// ---------------------------------------------------------------------------
// SetTransferController()
// 
// ---------------------------------------------------------------------------
//
void CCCECall::SetTransferController( 
    CCCETransferController* aTransferController )
    {
    iTransferController = aTransferController;
    }

// ---------------------------------------------------------------------------
// Sets call index 
// ---------------------------------------------------------------------------
//
void CCCECall::SetNewCallIndex()
    {
    if ( iCallIndex == KInvalidCallIndex )
        {
        TCCECallIndex callIndex( iCallContainer );
        iCallIndex = callIndex.CurrentCallIndex();
        }
    }
    
// ---------------------------------------------------------------------------
// Reset call object to initial state 
// ---------------------------------------------------------------------------
//
void CCCECall::Reset()
    {
    CCELOGSTRING2( "id:%d  CCCECall::Reset()", iCallId );
    
    iActiveRequest = ECCENone;
    
    // only one observer at the moment. Clear it.
    if (iObserver)
        {
        iObserver->SetMCCECallObserver(NULL);
        }
     
   
    // This object is no longer in use.
    iExitCode = ECCPErrorNone;
    
    iCallDirection = CCPCall::EDirectionUnknown;
    iCallState    = CCPCall::EStateIdle;

    iImplementationUid.iUid = 0;
    
    iCall = NULL;
    delete iCallParameters;
    iCallParameters = NULL;
    iCallParams = NULL;
       
    iDoNotReportRequest = KErrNotFound;

    iTransferProvider = NULL;
    iTransferController = NULL;
    
    if( iCCEDurationTimer )
        {
        iCCEDurationTimer->Reset();     
        }
    }

// ---------------------------------------------------------------------------
// GetMobileDataCallCaps( TDes8& /*aCaps*/ ) const
// ---------------------------------------------------------------------------
//
TInt CCCECall::GetMobileDataCallCaps( TDes8& aCaps ) const
    {
    CCELOGSTRING2("id:%d CCCECall::GetMobileDataCallCaps()", iCallId);
    
    if ( IsCsPlugin() )
        {
        return static_cast<MCCPCSCall*>(iCall)->GetMobileDataCallCaps(aCaps);
        }
    else
        return KErrNotSupported;
    }


// ---------------------------------------------------------------------------
// LogDialedNumber()
// ---------------------------------------------------------------------------
//    
TBool CCCECall::LogDialedNumber() const
    {
    // CS related 
    CCELOGSTRING2("id:%d CCCECall::LogDialedNumber()", iCallId);
    
    if ( IsCsPlugin() )
        {
        return static_cast<MCCPCSCall*>(iCall)->LogDialedNumber();
        }
    // for other than CS always return true
    return ETrue;
    }

// ---------------------------------------------------------------------------
// SwitchAlternatingCall()
// ---------------------------------------------------------------------------
//    
TInt CCCECall::SwitchAlternatingCall()
    {
    CCELOGSTRING2("id:%d CCCECall::SwitchAlternatingCall()", iCallId);
    if ( IsCsPlugin() )
        {
        static_cast<MCCPCSCall*>(iCall)->SwitchAlternatingCall();
        return KErrNone;
        }
    else
        return KErrNotSupported;
    }

// ---------------------------------------------------------------------------
// ErrorOccured( TCCPCallError aError )
// ---------------------------------------------------------------------------
//
void CCCECall::ErrorOccurred( TCCPError aError, MCCPCall* /*aCall*/ ) 
    {
    if( !iCall )
        {
        CCELOGSTRING2("id:%d CCCECall::ErrorOccurred()::Call not active", iCallId);
        return;
        }
        
    CCELOGSTRING3("id:%d CCCECall::ErrorOccurred: Error = %d", 
        iCallId, aError );

    iExitCode = aError;
    iCallContainer.ErrorOccurred( this, aError );
    
     // Complete request to observer
    if ( ECCENone != iActiveRequest )
        {
        RequestComplete( aError );
        }
    else
        {
        if( iObserver )
            {
            iObserver->ErrorOccurred(aError);
            }
        else
            {
            CCELOGSTRING( "CCCECall::ErrorOccurred: observer was NOT set!" );
            }
        }
    
    }

// ---------------------------------------------------------------------------
// RequestComplete( TInt aError )
// ---------------------------------------------------------------------------
//
void CCCECall::RequestComplete( TCCPError aError )
    {
    CCELOGSTRING4("id:%d CCCECall::RequestComplete: Request = %d, Error = %d",iCallId
        ,iActiveRequest, aError );

    // Complete request to observer
    if ( ECCENone != iActiveRequest )
        {
        NotifyRequestComplete( iActiveRequest, aError );
        }
    else
        {
        CCELOGSTRING2("id:%d CCCECall::RequestComplete: No active request.", iCallId);
        }

    // Reset active request
    iActiveRequest = ECCENone;
    }

// ---------------------------------------------------------------------------
// CallEventOccurred( TCCPCallEvent aEvent )
// ---------------------------------------------------------------------------
//
void CCCECall::CallEventOccurred( TCCPCallEvent aEvent, MCCPCall* /*aCall*/ ) 
    {
    if( !iCall )
        {
        CCELOGSTRING2("id:%d CCCECall::CallEventOccurred()::Call not active", iCallId);
        return;
        }


    if( !iObserver->GetMCCECallObserver() ) 
        {
        CCELOGSTRING( "CCCECall::CallEventOccurred: observer was NOT set!" );
        return;
        }


    CCELOGSTRING4("id:%d CCCECall::CallEventOccurred() Event = %d CallId = %d", 
        iCallId, aEvent, iCallId );

    switch ( aEvent )
        {
        /** Call has been placed on hold as a result of a local action. */
        case ECCPLocalHold:
            iObserver->CallEventOccurred( MCCECallObserver::ELocalHold );
            break;
        /** Call has been placed on hold by the remote connected party. */
        case ECCPRemoteHold:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteHold );
            break;
        /** Call has been resumed as a result of a local action. */
        case ECCPLocalResume:
            iObserver->CallEventOccurred( MCCECallObserver::ELocalResume );
            break;
        /** Call has been resumed by the remote connected party. */
        case ECCPRemoteResume:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteResume );
            break;
        /** Outgoing call has been barred by the local party. */
        case ECCPLocalBarred:
            iObserver->CallEventOccurred( MCCECallObserver::ELocalBarred );
            break;
        /** Outgoing call has been barred by the remote party. */
        case ECCPRemoteBarred:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteBarred );
            break;
        /** Call is waiting at the remote end. */
        case ECCPRemoteWaiting:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteWaiting );
            break;
        /** Call has been terminated by the remote party. */
        case ECCPRemoteTerminated:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteTerminated);
            break;
        /** Call is in queue */
        case ECCPQueued:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteWaiting );
            break;
        /** VoIP specific */
        case ECCCSPEarlyMediaStarted:
            iObserver->CallEventOccurred( MCCECallObserver::EVoIPEventEarlyMediaStarted );
            break;
        /** Call is secure */
        case ECCPSecureCall:
            iObserver->CallEventOccurred( MCCECallObserver::ESecureSession );
            break;
        /** Call is not secure */
        case ECCPNotSecureCall:
            iObserver->CallEventOccurred( MCCECallObserver::ENotSecureSession );
            break;
        /** Secure call signaling is not possible */
        case ECCPNotSecureSessionWithSips:
            iObserver->CallEventOccurred( MCCECallObserver::EVoIPEventNotSecureSessionWithSips );
            break;
        /** Call has been added to remote conference call at remote end */
        case ECCPRemoteConferenceCreate:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteConferenceCreate );
            break;
        /** CS call specific event */
        case ECCPCSDataPortLoaned:
            iObserver->CallEventOccurred( MCCECallObserver::ECCECSDataPortLoaned );
            break;
        /** CS call specific event */
        case ECCPCSDataPortRecovered:
            iObserver->CallEventOccurred( MCCECallObserver::ECCECSDataPortRecovered );
            break;
        /** Remote party info target meaning has changed */
        case ECCPNotifyRemotePartyInfoChange:
        	{
            //Ho occurred, call type has changed
            if ( FeatureManager::FeatureSupported( KFeatureIdFfVoiceCallContinuity ) )
                {
                CCELOGSTRING( "CCCECall::CallEventOccurred: ECCPNotifyRemotePartyInfoChange!" );
                delete iCallParameters;
                iCallParameters = NULL;
                
                TRAP_IGNORE( iCallParameters = iCall->Parameters().CloneL() );
                }           
            iCallContainer.AirTimeDurationSwap(
                                     iCall->Parameters().CallType() );
            iObserver->CallEventOccurred( MCCECallObserver::ECCENotifyRemotePartyInfoChange );
        	}
			break;
        /** Call secure status cannot be determined */
        case ECCPSecureNotSpecified:
            iObserver->CallEventOccurred( MCCECallObserver::ECCESecureNotSpecified );
            break;
        default:
            CCELOGSTRING3("id:%d CCCECall::SessionEventOccurred: Unhandled event = %d", iCallId,
                aEvent );
            break;
        }
    }

// ---------------------------------------------------------------------------
// CallCapsChanged( TUint32 aCapsFlags )
// ---------------------------------------------------------------------------
//
void CCCECall::CallCapsChanged( TUint32 aCapsFlags, MCCPCall* /*aCall*/ ) 
    {
    CCELOGSTRING2("id:%d CCCECall::CallCapsChanged()", iCallId);
    if( !iCall )
        {
        CCELOGSTRING2("id:%d CCCECall::CallCapsChanged()::Call not active", iCallId);
        return;
        }
        
    if( iObserver )
        {
        iObserver->CallCapsChanged( (MCCECallObserver::TCCECallControlCaps)aCapsFlags );
        }
    else
        {
        CCELOGSTRING( "CCCECall::CallCapsChanged: observer was NOT set!" );
        }
    }

// ---------------------------------------------------------------------------
// TransferEventOccurred()
// ---------------------------------------------------------------------------
//
void CCCECall::TransferEventOccurred( TCCPTransferEvent aEvent )
    {
    CCELOGSTRING2("id:%d CCCECall::TransferEventOccurred()", iCallId);
    
    if( !iObserver->GetMCCECallObserver() )
        {
        CCELOGSTRING( "CCCECall::TransferEventOccurred: observer was NOT set!" );
        return;
        }
    
    switch ( aEvent )
        {
       /** Call has been transferred to another remote party as a result 
        of a local action. This is the result of transfer being succesfully 
        completed */
        case ECCPLocalTransfer:
            iObserver->CallEventOccurred( MCCECallObserver::ELocalTransfer );
            break;
       /** Outgoing call is transfering. The transfer request has now been 
        accepted by the current call recipient. */
        case ECCPRemoteTransferring:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteTransferring );
            break;
       /** Outgoing transfer call is alerting. Current call recipinet has sent
        connection request to transfer target*/
        case ECCPRemoteTransferAlerting:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteTransferAlerting );
            break;

        default:
            CCELOGSTRING3("id:%d CCCECall::TransferEventOccurred: Unhandled event = %d", iCallId,
                aEvent );
            break;
        }
    }

// ---------------------------------------------------------------------------
// ForwardEventOccurred()
// ---------------------------------------------------------------------------
//
void CCCECall::ForwardEventOccurred( 
    const MCCPForwardObserver::TCCPForwardEvent aEvent )
    {
    CCELOGSTRING2("id:%d CCCECall::ForwardEventOccurred()", iCallId);

    if( !iObserver->GetMCCECallObserver() )
        {
        CCELOGSTRING( "CCCECall::ForwardEventOccurred: observer was NOT set!" );
        return;
        }
    
    switch ( aEvent )
        {
        /** Call is being forwarded by the remote party. */
        /** MovedTemporarily is handled as forwarding */
        case ECCPRemoteForwarding:
        case ECCPMovedTemporarily:
            iObserver->CallEventOccurred( MCCECallObserver::ERemoteForwarding );
            break;
        /** Multiple call forward choices are available */
        case ECCPMultipleChoices:
            iObserver->CallEventOccurred( MCCECallObserver::EVoIPEventMultipleChoices );
            break;
        /** Call moved permanently */
        case ECCPMovedPermanentlyEvent:
            iObserver->CallEventOccurred( MCCECallObserver::EVoIPEventMovedPermanently );
            break;
        /** Call is forwarded */
        case ECCPForwarded:
        default:
            CCELOGSTRING3("id:%d CCCECall::ForwardEventOccurred: Unhandled event = %d", iCallId,
                aEvent );
            break;
        }
    }

// ---------------------------------------------------------------------------
// CallStateChanged( TCCPCallState aState )
// ---------------------------------------------------------------------------
//
void CCCECall::CallStateChanged( TCCPCallState aState, MCCPCall* /*aCall*/ ) 
    {
    CCELOGSTRING3("id:%d CCCECall::CallStateChanged() State = %d", 
        iCallId, aState );
    
    CallStateChanged( aState, EFalse );
    }

// ---------------------------------------------------------------------------
// CallStateChangedWithInband( TCCPCallState aState )
// ---------------------------------------------------------------------------
//
void CCCECall::CallStateChangedWithInband( TCCPCallState aState, 
                                           MCCPCall* /*aCall*/ ) 
    {
    CCELOGSTRING3("id:%d CCCECall::CallStateChangedWithInband() State = %d", 
       iCallId , aState );
        
    CallStateChanged( aState, ETrue );
    }

// ---------------------------------------------------------------------------
// CallStateChanged( TCCPCSCallState aState )
// ---------------------------------------------------------------------------
//
void CCCECall::CallStateChanged( TCCPCallState aState, TBool aInband )
    {
    if( !iCall )
        {
        CCELOGSTRING2("id:%d CCCECall::CallStateChanged()::Call not active", iCallId);
        return;
        }
        
    TInt notify = EFalse;
    CCPCall::TCallState state( CCPCall::EStateIdle);
        
    switch ( aState )
        {
        case ECCPStateQueued:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Queued", iCallId);
            // Call index becomes available when call gets to dialling or ringing/queued state.
            // Idle call does not have call index.
            SetNewCallIndex();
            if ( iCallDirection == CCPCall::EMobileTerminated )
                {
                state = CCPCall::EStateQueued;
                notify = ETrue;
                }
            break;
        
        case ECCPStateDialling:
            // Call index becomes available when call gets to dialling or ringing/queued state.
            // Idle call does not have call index.
            SetNewCallIndex();

            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Dialling", iCallId);
            state = CCPCall::EStateDialling;
            notify = ETrue;
                
            break;   
            
        case ECCPStateAnswering:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Answering", iCallId);
            state = CCPCall::EStateAnswering;
            notify = ETrue;
                
            break;    
   
        case ECCPStateConnecting:
        case ECCPStateRinging:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Connecting/Ringing", iCallId);
            if ( iCallDirection == CCPCall::EMobileTerminated )
                {
                state = CCPCall::EStateRinging;
                // Call index becomes available when call gets to dialling or incoming state.
                // Idle call does not have call index.
                SetNewCallIndex();
                }
            else
                {
                if ( ECCEDial == iActiveRequest )
                    {
                    RequestComplete( ECCPErrorNone );
                    }
                    
                state = CCPCall::EStateConnecting;
                }
            notify = ETrue;
            break;

        case ECCPStateConnected:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Connected", iCallId);
            // Start call duration timer
            iCCEDurationTimer->Start();

            // We are either dialling or answering
            if ( ECCEAnswer == iActiveRequest ||
                 ECCEResume == iActiveRequest ||
                 ECCEDial == iActiveRequest ||
                 ECCEReplaceActive == iActiveRequest ) 
                {
                RequestComplete( ECCPErrorNone );
                }
                
            state = CCPCall::EStateConnected;
            notify = ETrue;
            break;

        case ECCPStateDisconnecting:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Disconnecting", iCallId);
            // Stop duration timer
            iCCEDurationTimer->Stop();

            if ( ECCETransfer == iActiveRequest )
                {
                RequestComplete( ECCPErrorNone );
                }

            state = CCPCall::EStateDisconnecting;
            notify = ETrue;
            break;

        case ECCPStateIdle:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Disconnected/Idle", iCallId);
            // Stop duration timer
            iCCEDurationTimer->Stop();

            // Remove call from conference before it is notified elsewhere
            if( iCallContainer.ConferenceCall().IsPartOfConference(*this) )
                {
                MCCPConferenceCallObserver& confObserver = iCallContainer.ConferenceCall(); 
                confObserver.ConferenceCallEventOccurred(
                     MCCPConferenceCallObserver::ECCPConferenceCallRemoved, iCall );
                }

            if ( ECCENone != iActiveRequest )
                {
                RequestComplete( ECCPErrorNone );
                }

            state = CCPCall::EStateIdle;
            iCallIndex = KInvalidCallIndex; // Call index not valid anymore in idle state
            notify = ETrue;
           
            if( !iObserver->GetMCCECallObserver() )
                {
                notify = EFalse;
                Release();
                
                }
            break;

        case ECCPStateHold:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Hold", iCallId);
            state = CCPCall::EStateHold;
            if ( ECCEHold == iActiveRequest )
                {
                RequestComplete( ECCPErrorNone );
                }
                
            notify = ETrue;
            break;

        case ECCPStateForwarding:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Forwarding", iCallId);
            // Notify observer
            // Forwarding state is notified to upstairs but is not set
            // to calls internal state
            if( iObserver )
                {
                if (aInband)
                    {
                    iObserver->CallStateChangedWithInband(CCPCall::EStateForwarding);  
                    }
                else
                    {
                    iObserver->CallStateChanged(CCPCall::EStateForwarding);   
                    }
                
                }
            break;

        case ECCPStateTransferring:
            CCELOGSTRING2("id:%d CCCECall::CallStateChanged: Transferring", iCallId);
            // Notify observer
            // Transferring state is notified to upstairs but is not set
            // to calls internal state
           if( iObserver )
                {
                if (aInband)
                    {
                    iObserver->CallStateChangedWithInband(CCPCall::EStateTransferring)  ;
                    }
                else
                    {
                    iObserver->CallStateChanged(CCPCall::EStateTransferring); 
                    }
                
                }
                
            break;

        default:
            CCELOGSTRING3("id:%d CCCECall::CallStateChanged: Unhandled state = %d", iCallId,
                aState );
            break;
        }
        
    if( notify )
        {
        NotifyCallStatusChange( state, aInband, CCECallEnums::ENotifyAsynchronously );
        }
    }
    
// ---------------------------------------------------------------------------
// Notify observers about call status change
// ---------------------------------------------------------------------------
//
void CCCECall::NotifyCallStatusChange( 
    CCPCall::TCallState aCallState, 
    TBool aInband, 
    CCECallEnums::TNotifyType aNotify )
    {
    CCELOGSTRING3("id:%d CCCECall::NotifyCallStatusChange: Status = %d",iCallId, aCallState );
    
    if( (iCallState == aCallState) && ( aCallState == MCCPCallObserver::ECCPStateIdle ))
        {
        CCELOGSTRING2("id:%d CCCECall::NotifyCallStatusChange: Same status, still Idle", iCallId );
        return;
        }
    
    iCallState = aCallState;

    if( iTransferController )
        {
        iTransferController->HandleCallStateChanged( this, aCallState );
        }
   
    // Notify observer
    if( iObserver && (aNotify != CCECallEnums::ENoNotify))
        {
       if( aInband )
            {
            iObserver->CallStateChangedWithInband( aCallState );
            }
        else
            {
            iObserver->CallStateChanged( aCallState );
            }
            
        }
    else
        {
        CCELOGSTRING2("id:%d CCCECall::NotifyCallStatusChange:No observer", iCallId );
        }

    // Notify CallContainer
    iCallContainer.HandleCallStatusChange( aCallState, this, aNotify );
    }

// ---------------------------------------------------------------------------
// Tells if CS plugin is used
// ---------------------------------------------------------------------------
//
TBool CCCECall::IsCsPlugin() const
    {
    TBool isCsPlugin( EFalse );
    if ( FeatureManager::FeatureSupported( KFeatureIdFfVoiceCallContinuity ) )
        {
        if ( iCall->Parameters().CallType() != 
            CCPCall::ECallTypePS )
            {
            isCsPlugin = ETrue;
            }
        }
    else
        {
        if( iImplementationUid == KCSProviderUid )
            {
            isCsPlugin = ETrue;
            }
        }
    return isCsPlugin;
    }

// End of file