phoneplugins/csplugin/src/cspcall.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 14 May 2010 15:51:57 +0300
changeset 30 ebdbd102c78a
parent 21 92ab7f8d0eab
child 51 f39ed5e045e0
permissions -rw-r--r--
Revision: 201017 Kit: 201019

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


#include <etelmm.h>
#include <etel.h>
#include <centralrepository.h>
#include <settingsinternalcrkeys.h>
#include <ccpdefs.h>
#include <gsmerror.h>
#include <etelsat.h>
#include <cccpcallparameters.h>

#include "cspcall.h"
#include "cspetelcallrequester.h"
#include "cspetelcalleventmonitor.h"
#include "cspcallinfomonitor.h"
#include "cspetelcallstatusmonitor.h"
#include "cspetelcallcapsmonitor.h"
#include "csptransferprovider.h"
#include "cspforwardprovider.h"
#include "csplogger.h"
#include "csppanic.pan"
#include "cspconsts.h"
#include "cspaudiohandler.h"
#include "mcspcommoninfo.h"
#include "mcspsecuritysettingobserver.h"
#include "tcspskypeidparser.h"
#include "cspuuimonitor.h"
#include "cspuuimessagesender.h"

const TInt KTimesToSplitValue = 16;


// ---------------------------------------------------------------------------
// CSPCall::~CSPCall
// ---------------------------------------------------------------------------
//
CSPCall::~CSPCall()
    {
    CSPLOGSTRING(CSPOBJECT, "CSPCall::~CSPCall <");

    delete iParams;
    iCommonInfo.IndicateHangupComplete( *this );
    
    if ( iAudioHandler 
         && iAudioStatus == ECSPCallAudioStatusActive )
        {
        iAudioStatus = ECSPCallAudioStatusInactive;
        iAudioHandler->Stop();
        }
    
    delete iUserToUserInformation;    
    delete iRequester;    
    delete iCallEventMonitor;
    delete iCallStatusMonitor;
    delete iCallCapsMonitor; 
    delete iCallInfoMonitor;
    delete iForwardProvider;
    delete iTransferProvider;
    delete iUUIMonitor;
    delete iUUIMessageSender;
    delete iSkypeId;

    iObservers.Close();        
    if ( iCall.SubSessionHandle() )
        {
        iCall.Close();
        }
    
    CSPLOGSTRING(CSPOBJECT, "CSPCall::~CSPCall >");
    }

// ---------------------------------------------------------------------------
// CSPCall::SetAudioHandler
// ---------------------------------------------------------------------------
//
void CSPCall::SetAudioHandler( CSPAudioHandler* aHandler )
    {
    CSPLOGSTRING2(CSPINT, "CSPCall::SetAudioHandler handler: %x", aHandler);
    iAudioHandler = aHandler;
    }

// ---------------------------------------------------------------------------
// CSPCall::SecuritySettingChanged
// ---------------------------------------------------------------------------
//
void CSPCall::SecuritySettingChanged( TInt aValue )
    {
    switch ( aValue )
        {
        case MCSPSecuritySettingObserver::ESecureCall:         
            {
            CSPLOGSTRING(CSPINT, 
                    "CSPCall::SecuritySettingChanged Sending 'secure call' event");
            NotifyCallEventOccurred( MCCPCallObserver::ECCPSecureCall );
            break; 
            }            
        case MCSPSecuritySettingObserver::ENotSecureCall:                     
            {
            CSPLOGSTRING(CSPINT, 
                    "CSPCall::SecuritySettingChanged Sending 'not secure call' event");
            NotifyCallEventOccurred( MCCPCallObserver::ECCPNotSecureCall );
            break;  
            }
        case MCSPSecuritySettingObserver::ESecureNotSpecified:                     
            {
            CSPLOGSTRING(CSPINT, 
                    "CSPCall::SecuritySettingChanged Sending SecureNotSpecified");
            NotifyCallEventOccurred( MCCPCallObserver::ECCPSecureNotSpecified );
            break;  
            }

        default: 
            {
            CSPLOGSTRING(CSPERROR, "CSPCall::SecuritySettingChanged, \
                unknown event");            
            break;  
            }
        }
    }

// ---------------------------------------------------------------------------
// CSPCall::RemoteAlertingToneStatusChanged
// Sends EarlyMediaStarted event to observer if network has started to 
// play remote alerting tone. There is only one known use case: Network
// starts playing alerting tone during connecting state. 
//
// This RemoteAlertingToneStatusChanged is called for every call, 
// so it is calls responsibility to determine if the 
// observer should be notified.
// ---------------------------------------------------------------------------
//
void CSPCall::RemoteAlertingToneStatusChanged(
    RMmCustomAPI::TRemoteAlertingToneStatus aNewStatus )
    {
    CSPLOGSTRING2(CSPINT, 
        "CSPCall::RemoteAlertingToneStatusChanged new status: %d", aNewStatus );
    
    if ( aNewStatus == RMmCustomAPI::EUiStopTone ||
         aNewStatus == RMmCustomAPI::EUiNoTone ) // NW tells us to stop playing 
        {
        // Connecting is only state where network starts playing the tone.
        if ( iCallState == MCCPCallObserver::ECCPStateConnecting )
            {
            NotifyCallEventOccurred( 
                MCCPCallObserver::ECCCSPEarlyMediaStarted );
            }
        }
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyCallStateChangedETel
// Notifies observers about state changes
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyCallStateChangedETel( RMobileCall::TMobileCallStatus aState ) 
    {
    CSPLOGSTRING3(CSPINT, 
                  "CSPCall::NotifyCallStateChangedETel < state: %d this: %x", 
                  aState, this );
    switch ( aState )
        {
        /*
        Cannot receive any mapping call statuses from ETel to following
        optional states:
        
        ECCPStateForwarding   MO call is being forwarded at receiver end
        ECCPStateQueued       Call is queued locally.
        
        The commented observer calls are for CS specific call states.
        */
        
        // Indicates that the call is idle or unknown.
        case RMobileCall::EStatusIdle:
        case RMobileCall::EStatusUnknown:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Idle");

            // If audio still active
            if ( iAudioStatus == ECSPCallAudioStatusActive 
                 && iAudioHandler
                 && iParams->CallType() == CCPCall::ECallTypeCSVoice )
                {
                iAudioStatus = ECSPCallAudioStatusInactive;
                iAudioHandler->Stop();
                }
                
            // Notify error in case not going through disconnecting
            if ( iCallState != MCCPCallObserver::ECCPStateDisconnecting 
                     && !iTerminationErrorNotified )
                {
                CheckAndNotifyTerminationError();
                }
            
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateIdle );
            iCommonInfo.IndicateHangupComplete( *this );
            break;
            }
        // The call is dialling.
        case RMobileCall::EStatusDialling:
            CSPLOGSTRING(CSPINT, "CSPCall callstate Dialling");
            {
            if ( iAudioHandler && iParams->CallType() == CCPCall:: ECallTypeCSVoice )
                {
                iAudioStatus = ECSPCallAudioStatusActive;
                iAudioHandler->Start();
                }
                
            iDontReportTerm = EFalse;
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateDialling );
            break;
            }            
        //Indicates that the MT call is ringing but not answered yet by 
        // the local user
        case RMobileCall::EStatusRinging:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Ringing");
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateRinging );
            break;
            }
        // Indicates that the local user has answered the MT call but
        // the network has not acknowledged the call connection yet. 
        case RMobileCall::EStatusAnswering:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Answering");

            if ( !iMobileOriginated
                && iAudioHandler 
                && iAudioStatus == ECSPCallAudioStatusInactive
                && iParams->CallType() == CCPCall::ECallTypeCSVoice )
                {
                iAudioStatus = ECSPCallAudioStatusActive;
                iAudioHandler->Start();
                }

            NotifyCallStateChanged( MCCPCallObserver::ECCPStateAnswering );
            break;
            }
        // MO Call: the network notifies to the MS that the remote party
        // is now ringing. 
        case RMobileCall::EStatusConnecting:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETelConnecting");
            RMmCustomAPI::TRemoteAlertingToneStatus tone = 
                iCommonInfo.GetRemoteAlertingToneStatus();
            if ( tone == RMmCustomAPI::EUiNoTone ||
                 tone == RMmCustomAPI::EUiStopTone )
                {
                NotifyCallStateChangedWithInband( MCCPCallObserver::ECCPStateConnecting );
                }
            else
                {
                NotifyCallStateChanged( MCCPCallObserver::ECCPStateConnecting );
                }
            break;
            }
        // Indicates that call is connected and active.
        case RMobileCall::EStatusConnected:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Connected");

            iDontReportTerm = ETrue;
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateConnected );
            break;
            }
        // Indicates that call is disconnecting. (Same as RCall::HangingUp)
        case RMobileCall::EStatusDisconnecting:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Disconnecting");

            if ( !iTerminationErrorNotified )
                {
                CheckAndNotifyTerminationError();
                }
            
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateDisconnecting );                
            break;
            }
        // Indicates that the call is disconnecting with inband data
        // (to enable the network to send an audio tone), signifying
        // that the call is not to be released until user terminates call
        case RMobileCall::EStatusDisconnectingWithInband:
            {
            CSPLOGSTRING(CSPINT, 
                "CSPCall::NotifyCallStateChangedETel DisconnectingWithInband");

            if ( !iTerminationErrorNotified )
                {
                CheckAndNotifyTerminationError();
                }
            
            NotifyCallStateChangedWithInband( 
                                MCCPCallObserver::ECCPStateDisconnecting );
            break;
            }
        // Indicates that the call is connected but on hold.  
        case RMobileCall::EStatusHold:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Hold");
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateHold );
            break;
            }
        case RMobileCall::EStatusTransferring:
            {
            CSPLOGSTRING(CSPINT, "CSPCall::NotifyCallStateChangedETel Transferring");
            NotifyCallStateChanged( MCCPCallObserver::ECCPStateTransferring );
            break;
            }
            
        // Indicates that call is undergoing temporary channel loss
        // and it may or may not be reconnected.  
        case RMobileCall::EStatusReconnectPending: // fall through 
        //Indicates that the call is the non-active half of an alternating
        // call. This call is waiting for its active half or the remote
        // end to switch alternating call mode.
        case RMobileCall::EStatusWaitingAlternatingCallSwitch: // fall through
        case RMobileCall::EStatusTransferAlerting:
            {
            CSPLOGSTRING2(CSPINT, 
                    "CSPCall::NotifyCallStateChangedETel no special handling for state %d",
                    aState);            
            break;
            }

        default:
            {
            CSPLOGSTRING(CSPERROR, 
                    "CSPCall::NotifyCallStateChangedETel callstate UNKNOWN");
            break;
            }
        }
    CSPLOGSTRING(CSPREQIN, "CSPCall::NotifyCallStateChangedETel >");
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyCallEventOccurred
// Notifies observers about call events
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyCallEventOccurred( 
    MCCPCallObserver::TCCPCallEvent aEvent )
    {
    CSPLOGSTRING2(CSPINT, 
            "CSPCall::NotifyCallEventOccurred < event: %d", aEvent);
    
    TInt obsCount = iObservers.Count();
    for ( TInt i = 0; i < obsCount; i++ )
        {
        CSPLOGSTRING2(CSPINT, "CSPCall::NotifyCallEventOccurred obs=%d",i);
        MCCPCallObserver *obs = iObservers[i];
        if ( obs )
            {
            obs->CallEventOccurred( aEvent, this );
            }
            
        CSPLOGSTRING2(CSPINT, "CSPCall::NotifyCallEventOccurred ok obs=%d",i);
        }
        
    CSPLOGSTRING2(CSPINT, "CSPCall::NotifyCallEventOccurred > event: %d", aEvent);
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyTransferCallEventOccurred
// Forward notification of transfer event to it's provider
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyTransferCallEventOccurred( 
    MCCPTransferObserver::TCCPTransferEvent aEvent ) 
    {
    CSPLOGSTRING2(CSPINT, "CSPCall::NotifyTransferCallEventOccurred %d", aEvent);
    // forward the method call to CSPTransferProvider object
    iTransferProvider->TransferEventOccurred( aEvent );
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyForwardEventOccurred
// Notifies observers about call events
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyForwardEventOccurred( 
    MCCPForwardObserver::TCCPForwardEvent aEvent )
    {
    CSPLOGSTRING2(CSPINT, "CSPCall::NotifyForwardEventOccurred %d", aEvent);
    iForwardProvider->NotifyForwardEventOccurred( aEvent );    
    }

// ---------------------------------------------------------------------------
// CSPCall::CallName
// Get call name
// ---------------------------------------------------------------------------
//
void CSPCall::CallName( TName& aCallName )
    {
    CSPLOGSTRING(CSPINT, "CSPCall::CallName");
    aCallName.Zero();
    aCallName.Append( iCallName );
    }

// ---------------------------------------------------------------------------
// CSPCall::DialRequestFailed
// Handles situations when dial fails
// ---------------------------------------------------------------------------
//
void CSPCall::DialRequestFailed( TInt aErrorCode )
    {
    CSPLOGSTRING(CSPERROR, "CSPCall::DialRequestFailed");
    iDialCompletionCode = aErrorCode;
    
    // If state has not changed 
    // ( e.g. in case of dial could not be initiated by network problem)
    if ( iCallStatusMonitor->State() == 
                   RMobileCall::RMobileCall::EStatusUnknown )
        {
        NotifyErrorOccurred( iRequester->MapError( aErrorCode ) );              
        
        // Force release since otherwise call remains unreleased
        CSPLOGSTRING(CSPERROR, "CSPCall::DialRequestFailed() Force Idle");
        NotifyCallStateChanged( MCCPCallObserver::ECCPStateIdle );
        }
    
    // If dial request has completed after notifying disconnecting state
    else if ( iCallState == MCCPCallObserver::ECCPStateDisconnecting
             && !iTerminationErrorNotified )
        {
        CheckAndNotifyTerminationError();
        }
    }

// ---------------------------------------------------------------------------
// CSPCall::EmergencyDialRequestFailed
// Handles situations when emergency dial fails
// ---------------------------------------------------------------------------
//
void CSPCall::EmergencyDialRequestFailed( TInt /*aErrorCode*/ )
    {
    CSPLOGSTRING(CSPERROR, "CSPCall::EmergencyDialRequestFailed");
    
    // Always same error code for CCE
    NotifyErrorOccurred( ECCPEmergencyFailed );
    
    // Mark that exit code will not be used
    iTerminationErrorNotified = ETrue;
    }
    
// ---------------------------------------------------------------------------
// CSPCall::NotifyErrorOccurred
// Notifies observers about errors
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyErrorOccurred( TCCPError aError )
    {
    CSPLOGSTRING2(CSPERROR, "CSPCall::NotifyErrorOccurred err %d", aError );

    TInt obsCount = iObservers.Count();
    for ( TInt i = 0; i < obsCount; i++ )
        {
        MCCPCallObserver *obs = iObservers[i];
        if ( obs )
            {
            obs->ErrorOccurred( aError, this );
            }
        }
    }
    
// ---------------------------------------------------------------------------
// CSPCall::CallCapsChanged
// Notifies observers about new capabilities.
// ---------------------------------------------------------------------------
//
void CSPCall::CallCapsChanged( const TUint32 aCapsFlags )
    {
    CSPLOGSTRING2(CSPERROR, "CSPCall::CallCapsChanged %b", aCapsFlags );
    iCapsFlags = aCapsFlags;
    TInt obsCount = iObservers.Count();
    for ( TInt i = 0; i < obsCount; i++ )
        {
        MCCPCallObserver *obs = iObservers[i];
        if ( obs )
            {
            obs->CallCapsChanged( aCapsFlags, this );
            }
        }
    }

// ---------------------------------------------------------------------------
// From class MCCPCSCall
// CSPCall::GetMobileCallInfo
// ---------------------------------------------------------------------------
//
TInt CSPCall::GetMobileCallInfo( TDes8& aCallInfo ) const
    {
    CSPLOGSTRING(CSPINT, "CSPCall::GetMobileCallInfo");
    return iCall.GetMobileCallInfo( aCallInfo );
    }

// ---------------------------------------------------------------------------
// From class MCCPCSCall
// CSPCall::GetMobileDataCallCaps
// ---------------------------------------------------------------------------
//
TInt CSPCall::GetMobileDataCallCaps( TDes8& /*aCaps*/ ) const
    {
    CSPLOGSTRING(CSPERROR, 
            "CSPCall::GetMobileDataCallCaps ERROR, Not supported");
    return KErrNotSupported;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Dial
// ---------------------------------------------------------------------------
//
TInt CSPCall::Dial()
    {
    CSPLOGSTRING( CSPREQIN, "CSPCall::Dial" );
    // Parameters not given, must create empty descriptor.
    TBuf8<1> params;
    return Dial(params);
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::RemoteParty
// ---------------------------------------------------------------------------
//
const TDesC& CSPCall::RemoteParty() const
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::RemoteParty");
    return iRemotePartyNumber;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::RemotePartyName
// ---------------------------------------------------------------------------
//
const TDesC& CSPCall::RemotePartyName()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::RemotePartyName");
    return iRemotePartyName;
    }
  
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::DialledParty
// ---------------------------------------------------------------------------
//  
const TDesC& CSPCall::DialledParty() const 
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::DialledParty %S", &iRemotePartyNumber);
    return iRemotePartyNumber;
    }
    
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Answer
// ---------------------------------------------------------------------------
//
TInt CSPCall::Answer()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Answer <");
    TInt ret( KErrNone );
    
    if ( iCallState == MCCPCallObserver::ECCPStateRinging 
         || iCallState == MCCPCallObserver::ECCPStateQueued )
        {    
        if( iMobileOriginated )
            {
            ret = KErrGeneral;
            }
        else if( iCallState != MCCPCallObserver::ECCPStateRinging && 
            iCallState != MCCPCallObserver::ECCPStateQueued )
            {
            ret = KErrAccessDenied;
            }
        else
            {
            ret = iCommonInfo.IndicateAnswerRequest( *this );
            }
        }
    else
        {
        // Not correct state for answer
        ret = KErrNotReady;
        }
    
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Answer > ret %d", ret);
    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCallCommandHandling
// CSPCall::PerformAnswerRequest
// ---------------------------------------------------------------------------
//
TInt CSPCall::PerformAnswerRequest()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::PerformAnswerRequest");
    
    TInt ret = iRequester->MakeRequest( CSPEtelCallRequester::ERequestTypeAnswer );
    CSPLOGSTRING3(CSPINT, 
            "CSPCall::Answer request performed, call state %d ret: %d", iCallState, ret);

    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Reject
// ---------------------------------------------------------------------------
//
TInt CSPCall::Reject()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Reject <");
    TInt ret;
    if ( iCallState == MCCPCallObserver::ECCPStateRinging
         || iCallState == MCCPCallObserver::ECCPStateQueued
         || iCallState == MCCPCallObserver::ECCPStateAnswering )
        {        
        CSPLOGSTRING( CSPREQIN, "CSPCall::Reject 2" );
        ret = HangUp();
        }
    else
        {
        ret = KErrNotReady;
        }
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Reject > ret: %d", ret );
    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Queue
// ---------------------------------------------------------------------------
//
TInt CSPCall::Queue()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Queue");
    TBool callWaitingState;
    iDontReportTerm = ETrue;
    
    TRAPD( res, iCommonInfo.GetCallWaitingL( *iParams, callWaitingState ) );
    if( res == KErrNone )
        {
        if ( callWaitingState )
            {
            CSPLOGSTRING(CSPREQIN, "CSPCall::Queue Call Waiting On");
            iCallState = MCCPCallObserver::ECCPStateQueued;
            
            // Notify Queued state
            TInt obsCount = iObservers.Count ( );
            for (TInt i = 0; i < obsCount; i++ )
                {
                MCCPCallObserver *obs = iObservers[i];
                if ( obs )
                    {
                    obs->CallStateChanged ( iCallState, this );
                    }
                }
            CSPLOGSTRING(CSPOBJECT, "CSPCall::Queue ok");

            return KErrNone;
            }
        else
            {
            CSPLOGSTRING(CSPREQIN, "CSPCall::Queue Call Waiting Off");
            }
        }
    else
        {
        CSPLOGSTRING2(CSPERROR, 
                      "CSPCall::Queue Error %d with CR. Call Waiting Off", 
                      res);
        }
    
    return KErrNotSupported;
    }
    
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Ringing
// ---------------------------------------------------------------------------
//
TInt CSPCall::Ringing()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Ringing");
    iDontReportTerm = ETrue;
    
    // Ringing state is accepted because MT-call goes to ringing
    // state in the beginning based on ETel state maching.
    if ( iCallState == MCCPCallObserver::ECCPStateIdle ||
         iCallState == MCCPCallObserver::ECCPStateRinging ) 
        {
        NotifyRingingState();
        return KErrNone;
        }
    else if ( iCallState == MCCPCallObserver::ECCPStateAnswering )
        {
        // Do nothing if already in Answering state (autoanswer).   
        return KErrNone; 
        }
        
    return KErrNotReady;
    }
    
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::HangUp
// ---------------------------------------------------------------------------
//
TInt CSPCall::HangUp()
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::HangUp this: %x", this);
    TInt ret( KErrNone );
    
    CSPEtelCallRequester::TRequestType req = iRequester->Request();
    if ( req == CSPEtelCallRequester::ERequestTypeDial || 
         ( req == CSPEtelCallRequester::ERequestTypeDialEmergency ) )
        {
        CSPLOGSTRING(CSPREQIN, "CSPCall::HangUp 1: Cancel ongoing dial");
        ret = iRequester->DialCancel();
        CSPLOGSTRING(CSPREQIN, "CSPCall::HangUp Canceled");
        }
    else if ( req == CSPEtelCallRequester::ERequestTypeHangup )
        {
        CSPLOGSTRING(CSPREQIN, "CSPCall::HangUp 2");
        ret = KErrAlreadyExists;
        }
    else if ( req == CSPEtelCallRequester::ERequestTypeNone 
              && iCallState != MCCPCallObserver::ECCPStateIdle )
        {
        CSPLOGSTRING(CSPREQIN, "CSPCall::HangUp 3");
        ret = iRequester->MakeRequest( CSPEtelCallRequester::ERequestTypeHangup );
        iCommonInfo.IndicateActiveHangup( *this );
        }
    else if ( req == CSPEtelCallRequester::ERequestTypeNone )
        {
        CSPLOGSTRING(CSPREQIN, "CSPCall::HangUp 4");
        ret = KErrAlreadyExists;
        }
    else
        {
        CSPLOGSTRING(CSPREQIN, "CSPCall::HangUp 5");
        // Request pending, must be canceled
        iRequester->Cancel();
        ret = iRequester->MakeRequest( CSPEtelCallRequester::ERequestTypeHangup );
        iCommonInfo.IndicateActiveHangup( *this );
        }
        
    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Cancel
// ---------------------------------------------------------------------------
//
TInt CSPCall::Cancel()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Cancel");
    return HangUp();
    }
        
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Hold
// ---------------------------------------------------------------------------
//
TInt CSPCall::Hold()
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Hold this: %x", this);
    TInt ret;
        
    if ( iCallState == MCCPCallObserver::ECCPStateConnected )
        {
        CSPLOGSTRING(CSPREQOUT, "CSPCall::Hold make request");

        // Set call on hold
        ret = iRequester->MakeRequest( 
                    CSPEtelCallRequester::ERequestTypeHold );
        if ( ret != KErrNone )
            {
            CSPLOGSTRING2(CSPERROR, 
                "CSPCall::Hold ERROR: %d", ret);
            }
        }
    else if ( iCallState == MCCPCallObserver::ECCPStateHold )
        {
        CSPLOGSTRING(CSPERROR, "CSPCall::Hold : already held");
        ret = KErrAlreadyExists;
        }
    else
        {
        CSPLOGSTRING(CSPERROR, "CSPCall::Hold not allowed");
        ret = KErrNotReady;
        }

    return ret;
    } 

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Resume
// ---------------------------------------------------------------------------
//
TInt CSPCall::Resume()
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Resume this: %x", this);
    TInt ret;
        
    if ( iCallState == MCCPCallObserver::ECCPStateHold )
        {
        CSPLOGSTRING(CSPREQOUT, "CSPCall::Resume request");
        
        ret = iRequester->MakeRequest( 
            CSPEtelCallRequester::ERequestTypeResume );
        if ( KErrNone != ret )
            {
            CSPLOGSTRING2(CSPERROR, "CSPCall::Resume ERROR %d", ret);
            }
        }
    else if ( iCallState == MCCPCallObserver::ECCPStateConnected )
        {
        CSPLOGSTRING(CSPERROR, "CSPCall::Resume already connected" );
        ret = KErrAlreadyExists;
        }
    else
        {
        CSPLOGSTRING(CSPERROR, "CSPCall::Resume not held state" );
        ret = KErrNotReady;
        }
    
    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Swap
// ---------------------------------------------------------------------------
//
TInt CSPCall::Swap()
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Swap this: %x", this);
    TInt ret;
    if ( iCallState == MCCPCallObserver::ECCPStateConnected
         || iCallState == MCCPCallObserver::ECCPStateHold )
        {    
        ret = iRequester->MakeRequest( CSPEtelCallRequester::ERequestTypeSwap );
        if ( ret )
            {
            CSPLOGSTRING2( CSPERROR, "CSPCall::Swap Error %d", ret );
            }
        }
    else
        {
        ret = KErrNotReady;
        }
    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::IsMobileOriginated
// ---------------------------------------------------------------------------
//
TBool CSPCall::IsMobileOriginated() const
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::IsMobileOriginated");
    return iMobileOriginated;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::State
// ---------------------------------------------------------------------------
//
MCCPCallObserver::TCCPCallState CSPCall::State() const
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::State %d", iCallState);
    return iCallState;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Uid
// ---------------------------------------------------------------------------
//
TUid CSPCall::Uid() const
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Uid %d", KCSPImplementationUid);
    return KCSPImplementationUid;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Caps
// ---------------------------------------------------------------------------
//
MCCPCallObserver::TCCPCallControlCaps CSPCall::Caps( ) const
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Caps %b", iCapsFlags );
    return (MCCPCallObserver::TCCPCallControlCaps) iCapsFlags;
    }
 
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::SetParameters
// ---------------------------------------------------------------------------
//
void CSPCall::SetParameters( const CCCPCallParameters& /*aNewParams*/ )
    {
    CSPLOGSTRING(CSPOBJECT, "CSPCall::SetParameters ERROR Can't set params");
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Parameters
// ---------------------------------------------------------------------------
//
const CCCPCallParameters& CSPCall::Parameters() const
    {
    CSPLOGSTRING(CSPINT, "CSPCall::Parameters");
    return *iParams;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::TransferProvider
// ---------------------------------------------------------------------------
//
MCCPTransferProvider* CSPCall::TransferProviderL(const MCCPTransferObserver& 
                                                            aObserver )
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::TransferProvider");
    iTransferProvider->AddObserverL( aObserver );
    return iTransferProvider;
    }
    
// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::ForwardProvider
// ---------------------------------------------------------------------------
//
MCCPForwardProvider* CSPCall::ForwardProviderL( 
        const MCCPForwardObserver& aObserver )
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::ForwardProvider");
    iForwardProvider->AddObserverL( aObserver );
    return iForwardProvider;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::AddObserverL
// ---------------------------------------------------------------------------
//
void CSPCall::AddObserverL( const MCCPCallObserver& aObserver )
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::AddObserverL %x", &aObserver);
    if ( iObservers.Find( &aObserver ) == KErrNotFound )
        {
        iObservers.AppendL( &aObserver );
        }
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// Removes observer.
// ---------------------------------------------------------------------------
//
TInt CSPCall::RemoveObserver( const MCCPCallObserver& aObserver )
    {
    CSPLOGSTRING2(CSPREQIN, "CSPCall::RemoveObserver %x", &aObserver);
    
    TInt found = iObservers.Find( &aObserver );
    if ( found != KErrNotFound )
        {
        iObservers.Remove( found );
        return KErrNone;
        }
        
    return found;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::IsCallForwarded
// ---------------------------------------------------------------------------
//
TBool CSPCall::IsCallForwarded( ) const
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::IsCallForwarded <");
    TBool ret( EFalse );
    TInt err( KErrNone );
    RMobileCall::TMobileCallInfoV3 callInfo;
    RMobileCall::TMobileCallInfoV3Pckg pck( callInfo );
    err = iCall.GetMobileCallInfo( pck );
    if (err == KErrNone )
        {
        ret = callInfo.iForwarded;
        }
    
    CSPLOGSTRING2(CSPREQIN, 
            "CSPCall::IsCallForwarded > forwarder: %d", ret );
    
    return ret;
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::IsSecured
// ---------------------------------------------------------------------------
//
TBool CSPCall::IsSecured( ) const
    {    
    CSPLOGSTRING(CSPREQIN, "CSPCall::IsSecured");
    return iCommonInfo.NetworkSecurityStatus();
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::SecureSpecified
// ---------------------------------------------------------------------------
//
TBool CSPCall::SecureSpecified( ) const
    {    
    CSPLOGSTRING(CSPREQIN, "CSPCall::SecureSpecified");
    return iCommonInfo.SecureSpecified();
    }

// ---------------------------------------------------------------------------
// From class MCCPCall
// CSPCall::Tone
// ---------------------------------------------------------------------------
//
TCCPTone CSPCall::Tone() const
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Tone <");
    TCCPTone tone( ECCPNoSoundSequence );

    if ( iCallState == MCCPCallObserver::ECCPStateConnecting )
        {
        RMmCustomAPI::TRemoteAlertingToneStatus ts = iCommonInfo.GetRemoteAlertingToneStatus();
        
        if (ts == RMmCustomAPI::EUiRbtTone )
            {
            tone = ECCPRemoteAlerting;
            }
        else if ( ts == RMmCustomAPI::EUiStopTone )
            {
            tone = ECCPNoSoundSequence;
            }
        else            
            {
            // No tone
            tone = ECCPNoSoundSequence;
            }
        }
    else
        {
        // Handle disconnecting tones      
        TInt callDisconnectingError = ExitCodeError();
        CSPLOGSTRING2(CSPINT, "CSPCall::Tone exit code err: %d", callDisconnectingError);

        switch( callDisconnectingError )
            {
            case KErrNone:
                // GSM: DIAL TONE (optional) - not used in Nokia phones 
                CSPLOGSTRING(CSPERROR, "CSPCall::Tone: No sound");
                break;
            case KErrGsmCCUserBusy:
                // GSM: SUBSCRIBER BUSY
                tone = ECCPToneUserBusy;
                CSPLOGSTRING(CSPINT, "CSPCall::Tone: Subscriber Busy");
                break;
                // Fall through
            case KErrGsmCCNumberChanged:
            case KErrGsmCCResponseToStatusEnquiry:
            case KErrGsmCCNormalUnspecified:
                // GSM: NONE, Nokia phones: radio path not available
                tone = ECCPToneRadioPathNotAvailable;
                CSPLOGSTRING(CSPINT, "CSPCall::Tone: RadioPathNotAvailable");
                break;      
            case KErrGsmCCNoChannelAvailable:
            case KErrGsmCCTemporaryFailure:
            case KErrGsmCCSwitchingEquipmentCongestion:
            case KErrGsmCCRequestedChannelNotAvailable:
            case KErrGsmCCQualityOfServiceNotAvailable:
            case KErrGsmCCBearerCapabilityNotCurrentlyAvailable:
                // GSM: CONGESTION
                tone = ECCPToneCongestion;
                CSPLOGSTRING(CSPINT, "CSPCall::Tone: Congestion");
                break;
            case KErrGsmCCUnassignedNumber:
            case KErrGsmCCNoRouteToDestination:
            case KErrGsmCCChannelUnacceptable:
            case KErrGsmCCOperatorDeterminedBarring:
            case KErrGsmCCUserNotResponding:
            case KErrGsmCCUserAlertingNoAnswer:
            case KErrGsmCCCallRejected:
            case KErrGsmCCNonSelectedUserClearing:
            case KErrGsmCCDestinationOutOfOrder:
            case KErrGsmCCInvalidNumberFormat:
            case KErrGsmCCFacilityRejected:
            case KErrGsmCCNetworkOutOfOrder:
            case KErrGsmCCAccessInformationDiscarded:
            case KErrGsmCCResourceNotAvailable:
            case KErrGsmCCRequestedFacilityNotSubscribed:
            case KErrGsmCCIncomingCallsBarredInCug:
            case KErrGsmCCBearerCapabilityNotAuthorised:
            case KErrGsmCCServiceNotAvailable:
            case KErrGsmCCBearerServiceNotImplemented:
            case KErrGsmCCChannelTypeNotImplemented:
            case KErrGsmCCAcmGreaterThanAcmMax:
            case KErrGsmCCRequestedFacilityNotImplemented:
            case KErrGsmCCOnlyRestrictedDigitalInformationBCAvailable:
            case KErrGsmCCServiceNotImplemented:
            case KErrGsmCCInvalidCallReferenceValue:
            case KErrGsmCCChannelDoesNotExist:
            case KErrGsmCCSuspendedCallExistsButCallIdentityDoesNotWork:
            case KErrGsmCCCallIdentityInUse:
            case KErrGsmCCNoCallSuspended:
            case KErrGsmCCRequestedCallIdentityAlreadyCleared:
            case KErrGsmCCUserNotInCug:
            case KErrGsmCCIncompatibleDestination:
            case KErrGsmCCInvalidTransitNetworkSelection:
            case KErrGsmCCIncompatibleSegmentedMessage:
            case KErrGsmCCSemanticallyIncorrectMessage:
            case KErrGsmCCInvalidMandatoryInformation:
            case KErrGsmCCNonExistentMessageType:
            case KErrGsmCCIncompatibleMessageInProtocolState:
            case KErrGsmCCNonExistentInformationElement:
            case KErrGsmCCConditionalIEError:
            case KErrGsmCCIncompatibleMessageInCallState:
            case KErrGsmCCRecoveryOnTimerExpiry:
            case KErrGsmCCUnspecifiedProtocolError:
            case KErrGsmCCUnspecifiedInterworkingError:
                // GSM: SPECIAL INFORMATION
                tone = ECCPToneSpecialInformation;
                CSPLOGSTRING(CSPINT, "CSPCall::Tone: Special Information");
                break;
            default:
                CSPLOGSTRING(CSPERROR, "CSPCall::Tone: ERROR not found");
                break;
            }
         }
    
    CSPLOGSTRING2(CSPREQIN, "CSPCall::Tone > tone: %d", tone);
    return tone;
    }
    
// ---------------------------------------------------------------------------
// From class MCCPCSCall
// CSPCall::NoFdnCheck
// ---------------------------------------------------------------------------
//
void CSPCall::NoFDNCheck( )
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::NoFDNCheck");
    iFdnCheck = EFalse;
    }
    
// ---------------------------------------------------------------------------
// CSPCall::LogDialedNumber
// ---------------------------------------------------------------------------
//
TBool CSPCall::LogDialedNumber() const
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::LogDialedNumber true");
    return ETrue;
    }
    
// ---------------------------------------------------------------------------
// From class MCCPCSCall
// CSPCall::Dial
// ---------------------------------------------------------------------------
//
TInt CSPCall::Dial( const TDesC8& /*aCallParams*/ )
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::Dial");
    return iCommonInfo.IndicateDialRequest( *this );
    }

// ---------------------------------------------------------------------------
// From class MCCPCallCommandHandling
// CSPCall::PerformDialRequest
// ---------------------------------------------------------------------------
//
TInt CSPCall::PerformDialRequest()
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::PerformDialRequest");
    iDialCompletionCode = KErrNone;
    iTerminationErrorNotified = EFalse;
    
    // Send the User to User Information.
    if( iUserToUserInformation->Length() )
        {
        iUUIMessageSender->SendUUIMessage( *iUserToUserInformation );
        }
    
    return DialFdnCond( iFdnCheck );
    }
    
// ---------------------------------------------------------------------------
// CSPCall::CSPCall
// ---------------------------------------------------------------------------
//
CSPCall::CSPCall( RMobileLine& aLine, 
                  TBool aMobileOriginated,
                  const TDesC& aName,
                  MCSPCommonInfo& aCommonInfo,
                  TBool aIsEmergencyCall ) : 
                    iLine( aLine ),
                    iMobileOriginated( aMobileOriginated ),
                    iName( aName ), 
                    iCommonInfo( aCommonInfo ),
                    iTerminationErrorNotified( EFalse ),
                    iIsEmergencyCall( aIsEmergencyCall),
                    iFdnCheck(ETrue),
                    iAudioStatus( ECSPCallAudioStatusInactive ) 
                    
    {
    CSPLOGSTRING(CSPOBJECT, "CSPCall::CSPCall");
    }

// ---------------------------------------------------------------------------
// CSPCall::ConstructL
// Constructing CSPCall in 2nd phase
// ---------------------------------------------------------------------------
//    
void CSPCall::ConstructL( const CCCECallParameters& aParams )
    {
    CSPLOGSTRING(CSPOBJECT, "CSPCall::ConstructL <");

    // Create cloned copy of call parameters 
    iParams = static_cast<CCCECallParameters*>( aParams.CloneL() );
    
    // Open call handle  
    OpenCallHandleL(); 

    // Update call info 
    UpdateCallInfo(); 
    
    // Update call state from ETel 
    UpdateCallState(); 
    
    // Create call handlers for call related requests 
    // and for monitoring call related events 
    CreateCallHandlersL(); 
        
    CSPLOGSTRING(CSPOBJECT, "CSPCall::ConstructL >");
    }

// ---------------------------------------------------------------------------
// CSPCall::OpenCallHandleL
// Open call handle, calls either OpenNewCallL or OpenExistingCallL depending 
// of the call direction and if the call is a client call       
// ---------------------------------------------------------------------------
//    
void CSPCall::OpenCallHandleL()
    {
    CSPLOGSTRING(CSPINT, "CSPCall::OpenCallHandleL <");
    
    if ( iMobileOriginated )
        {
        // There is no existing call on line, open new call 
        OpenNewCall();
        }
    else
        {
        // Mobile terminated call on line, open existing call 
        OpenExistingCallL( iName ); 
        }

    CSPLOGSTRING(CSPINT, "CSPCall::OpenCallHandleL >");
    }

// ---------------------------------------------------------------------------
// CSPCall::UpdateCallInfoL
// Update call info including remote party name and number data  
// ---------------------------------------------------------------------------
//    
void CSPCall::UpdateCallInfo()
    {
    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallInfo <");
    RMobileCall::TMobileCallInfoV7 callInfo;
    RMobileCall::TMobileCallInfoV7Pckg pck( callInfo );
    TInt err = iCall.GetMobileCallInfo( pck );
    
    UpdateCallInfoImpl( callInfo );

    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallInfo >");
    }

// ---------------------------------------------------------------------------
// CSPCall::UpdateCallInfoImpl
// Implementation for UpdateCallInfo().
// ---------------------------------------------------------------------------
//    
void CSPCall::UpdateCallInfoImpl( RMobileCall::TMobileCallInfoV7 aCallInfo )
    {
    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallInfoImpl <");

    if ( iMobileOriginated )
        {
        // Call wasn't added by ETel monitor, update info accordingly
        UpdateCallNameNumberInfo( aCallInfo, EFalse ); 
        }
    else
        {
        // Call was added by ETel monitor, update info accordingly
        UpdateCallNameNumberInfo( aCallInfo, ETrue );
        }
    

    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallInfoImpl >");
    }

// ---------------------------------------------------------------------------
// CSPCall::UpdateCallOrigin
// Set call origin to CCCECallParameters.
// ---------------------------------------------------------------------------
//    
void CSPCall::UpdateCallOrigin( RMobileCall::TMobileCallInfoV7 aCallInfo )
    {
    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallOrigin <");

    if ( RMobileCall::EOriginatorSIM == aCallInfo.iCallParamOrigin )
        {
        iParams->SetOrigin(CCCECallParameters::ECCECallOriginSAT);
        iParams->SetAlphaId(aCallInfo.iAlphaId);
        }

    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallOrigin >");
    }



// ---------------------------------------------------------------------------
// CSPCall::UpdateCallStateL
//   
// ---------------------------------------------------------------------------
//    
int CSPCall::UpdateCallState()
    {
    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallState <");
    TInt err( KErrNone ); 
    
    // Update call state from ETel
    RMobileCall::TMobileCallStatus etelState;
    err = iCall.GetMobileCallStatus( etelState );
    if ( KErrNone == err )
        {
        iCallState = CCPStateFromETelState( etelState );
        }
    CSPLOGSTRING2(CSPINT, "CSPCall::UpdateCallState > res %d", err);
    
    return err; 
    }

// ---------------------------------------------------------------------------
// CSPCall::CreateCallHandlersL
// Create call handlers for call related requests and call monitoring  
// ---------------------------------------------------------------------------
//    
void CSPCall::CreateCallHandlersL()
    {
    CSPLOGSTRING(CSPINT, "CSPCall::CreateCallHandlersL <");

    iRequester = CSPEtelCallRequester::NewL( *this, iCall );

    iCallEventMonitor = CSPEtelCallEventMonitor::NewL( *this, iCall );
    iCallEventMonitor->StartMonitoring();
    iCallStatusMonitor = CSPEtelCallStatusMonitor::NewL( *this, iCall );
    iCallStatusMonitor->StartMonitoring();
    
    iCallCapsMonitor = CSPEtelCallCapsMonitor::NewL( *this, iCall );
    iCallCapsMonitor->StartMonitoring();
    iCapsFlags = iCallCapsMonitor->FetchCallControlCapsL();
    
    iCallInfoMonitor = CSPCallInfoMonitor::NewL( *this, iCall );
    iCallInfoMonitor->StartMonitoring();
    
    // Start UUI monitor and create message sender 
    iSkypeId = TCSPSkypeIdParser::CreateSkypeIdBufferL();
    iUUIMonitor = CSPUUIMonitor::NewL( iCall,*this );
    iUUIMonitor->StartMonitor();
    iUUIMessageSender = CSPUUIMessageSender::NewL( iCall );
    iUserToUserInformation = iParams->UUSId().AllocL();
    
    // Transfer provider
    iTransferProvider = CSPTransferProvider::NewL( iCall, *this, iCommonInfo );

    // Forward provider
    iForwardProvider = CSPForwardProvider::NewL();
    
    CSPLOGSTRING(CSPINT, "CSPCall::CreateCallHandlersL >");
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyRingingState
// Gets to ringing state
// ---------------------------------------------------------------------------
//     
void CSPCall::NotifyRingingState( )
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::NotifyRingingState");
    iCallState = MCCPCallObserver::ECCPStateRinging;

    TInt obsCount = iObservers.Count ( );
    for (TInt i = 0; i < obsCount; i++ )
        {
        MCCPCallObserver *obs = iObservers[i];
        if ( obs )
            {
            obs->CallStateChanged ( iCallState, this );
            }
        }
    }

// ---------------------------------------------------------------------------
// CSPCall::CCPStateFromETelState
// Simple mapping between state enumerations.
// ---------------------------------------------------------------------------
//     
MCCPCallObserver::TCCPCallState CSPCall::CCPStateFromETelState( 
    RMobileCall::TMobileCallStatus aEtelState ) 
    {
    MCCPCallObserver::TCCPCallState ret = MCCPCallObserver::ECCPStateIdle;
    switch ( aEtelState )
        {
        case RMobileCall::EStatusUnknown:
            {
            CSPLOGSTRING( CSPREQIN, 
                "CSPCall::State > RMobileCall::Unknown" );
            ret = MCCPCallObserver::ECCPStateIdle;
            break;
            }
        case RMobileCall::EStatusIdle:
            {
            CSPLOGSTRING( CSPREQIN, 
                "CSPCall::State > RMobileCall::EStatusIdle" );
            ret = MCCPCallObserver::ECCPStateIdle;
            break;
            }
        case RMobileCall::EStatusRinging:
            {
            CSPLOGSTRING( CSPREQIN, 
                "CSPCall::State > RMobileCall::EStatusRinging" );
            ret = MCCPCallObserver::ECCPStateRinging;
            break;
            }
        // Map the following to connecting status
        case RMobileCall::EStatusDialling:                
            {
            CSPLOGSTRING( CSPREQIN, "CSPCall::State > \
                RMobileCall::EStatusDialling" );
            ret = MCCPCallObserver::ECCPStateDialling;
            break;
            }
        case RMobileCall::EStatusConnecting:
            {
            CSPLOGSTRING( CSPREQIN, "CSPCall::State > \
                RMobileCall::Connecting" );
            ret = MCCPCallObserver::ECCPStateConnecting;
            break;
            }
        case RMobileCall::EStatusAnswering:
            {
            CSPLOGSTRING( CSPREQIN, "CSPCall::State > \
                RMobileCall::Answering" );
            ret = MCCPCallObserver::ECCPStateAnswering;
            break;                
            }
        // Call is connected and active.
        case RMobileCall::EStatusConnected:
            {
            CSPLOGSTRING( CSPREQIN, 
            "CSPCall::State > RMobileCall::EStatusConnected" );
            ret = MCCPCallObserver::ECCPStateConnected;
            break;
            }
        case RMobileCall::EStatusDisconnectingWithInband:
        case RMobileCall::EStatusDisconnecting:
            {
            CSPLOGSTRING( CSPREQIN, 
                 "CSPCall::State > RMobileCall::EStatusDisconnecting/Inband?");
            ret = MCCPCallObserver::ECCPStateDisconnecting;
            break;
            }
        case RMobileCall::EStatusReconnectPending:
            {
            CSPLOGSTRING( CSPREQIN, 
            "CSPCall::State > RMobileCall::EStatusHangingUp" );
            ret = MCCPCallObserver::ECCPStateDisconnecting;
            break;
            }
        case RMobileCall::EStatusHold:
            {
            CSPLOGSTRING( CSPREQIN, 
            "CSPCall::State > RMobileCall::EStatusHold" );
            ret = MCCPCallObserver::ECCPStateHold;
            break;
            }
        case RMobileCall::EStatusWaitingAlternatingCallSwitch: 
            {
            // This state is not used in real life.
            CSPLOGSTRING( CSPREQIN, 
            "CSPCall::State > RMobileCall::EStatusWaitingAlternatingCallSwitch" );
            ret = MCCPCallObserver::ECCPStateConnected;
            break;
            }
        case RMobileCall::EStatusTransferring: 
            {
            CSPLOGSTRING( CSPREQIN, 
            "CSPCall::State > RMobileCall::EStatusHold" );
            ret = MCCPCallObserver::ECCPStateTransferring;
            break;
            }
        case RMobileCall::EStatusTransferAlerting: 
            {
            CSPLOGSTRING( CSPREQIN, 
            "CSPCall::State > RMobileCall::EStatusHold" );
            ret = MCCPCallObserver::ECCPStateTransferring;
            break;
            }            
        default:
            {
            CSPLOGSTRING( CSPREQIN, 
                "CSPCall::CCPStateFromETelState unhandled state ");
            }
        }

    CSPLOGSTRING3(CSPINT, 
        "CSPCall::CCPStateFromETelState ETel: %d CCP: %d", aEtelState, ret);
    return ret;
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyCallStateChanged
// Notifies observers about state changes
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyCallStateChanged( MCCPCallObserver::TCCPCallState aState ) 
    {
    CSPLOGSTRING3(CSPINT, 
            "CSPCall::NotifyCallStateChanged < state: %d this: %x", 
            aState, this );
                           
    iCallState = aState;    
    TBool notifyObservers( ETrue ); 

    if ( !iMobileOriginated && MCCPCallObserver::ECCPStateRinging == aState )
        {
        CSPLOGSTRING2(CSPINT, "CSPCall::No notify on ringing MT", aState);        
        notifyObservers = EFalse; 
        }
    
    if ( notifyObservers )
        {
        TInt obsCount = iObservers.Count();
        for ( TInt i = 0; i < obsCount; i++ )
            {
            MCCPCallObserver *obs = iObservers[i];
            if ( obs )
                {            
                obs->CallStateChanged( aState, this );
                }
            }
        }
        
    CSPLOGSTRING3(CSPINT, 
            "CSPCall::NotifyCallStateChanged > state: %d this: %x", 
            aState, this );
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyCallStateChangedWithInband
// Notifies observers about state changes
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyCallStateChangedWithInband( 
        MCCPCallObserver::TCCPCallState aState ) 
    {
    CSPLOGSTRING3(CSPINT, 
        "CSPCall::NotifyCallStateChangedWithInBand < state: %d this: %x", 
        aState, this );
    
    iCallState = aState;
   
    if ( !iMobileOriginated && MCCPCallObserver::ECCPStateRinging == aState )
        {
        CSPLOGSTRING2(CSPINT, "CSPCall::No notify on ringing MT", aState);
        }
    else
        {        
        TInt obsCount = iObservers.Count();
        for ( TInt i = 0; i < obsCount; i++ )
            {            
            MCCPCallObserver *obs = iObservers[i];
            if ( obs )
                {
                obs->CallStateChangedWithInband( aState, this );
                }
            }
        }
    CSPLOGSTRING3(CSPINT, 
            "CSPCall::NotifyCallStateChangedWithInband > state: %d this: %x", 
            aState, this);
    }

// ---------------------------------------------------------------------------
// CSPCall::ReadRepositoryL
// Reads the given information from Central Repository.
// ---------------------------------------------------------------------------
//
void CSPCall::ReadRepositoryL( TUid aUid, TUint aKey, TInt& aVal)
    {
    CSPLOGSTRING(CSPINT, "CSPCall::ReadRepositoryL");
    
    CRepository* cr = CRepository::NewL( aUid );
    TInt err = cr->Get( aKey, aVal );
    delete cr;
    User::LeaveIfError( err );
    }

// ---------------------------------------------------------------------------
// CSPCall::CheckAndNotifyTerminationError
// Reads error code from ETel.
// ---------------------------------------------------------------------------
//
void CSPCall::CheckAndNotifyTerminationError()
    {
    CSPLOGSTRING2(CSPINT, 
        "CSPCall::CheckAndNotifyTerminationError dial completion code: %d", 
        iDialCompletionCode);
    
    // Emergency error handling is separated into CSPEtelCallRequester
    if ( !iIsEmergencyCall )
        {
        TInt termErr = ExitCodeError();
        CSPLOGSTRING2(CSPINT, 
                "CSPCall::CheckAndNotifyTerminationError exit code error: %d", 
                termErr);
        
        if ( termErr == KErrNone )
            {
            // Handle KErrGsmCCUnassignedNumber correctly
            // because the value is not stored in exit code.
            termErr = iDialCompletionCode;
            CSPLOGSTRING(CSPINT, 
                    "CSPCall::CheckAndNotifyTerminationError use dial completion code");
            }
            
        if ( termErr == KErrGsmRRPreEmptiveRelease )
            {
            // Error KErrGsmRRPreEmptiveRelease occurs when there is active call 
            // and user make emergency call, can be ignored.
            CSPLOGSTRING3( 
                CSPERROR, 
                "CSPCall::CheckAndNotifyTerminationError preemptive release, ignore: %d",
                termErr,
                this );
            }
        else if ( iDontReportTerm 
                && (  termErr == KErrGsmCCNormalUnspecified 
                   || termErr == KErrGsmCCCallRejected ) )
            {
            // Not an error, since this happens on normal 
            // call termination situation after connected call.
            CSPLOGSTRING3(CSPERROR, 
                    "CSPCall::CheckAndNotifyTerminationError DISCARD this: %x err: %d", 
                    this, 
                    termErr);    
            }        
        else if ( termErr )
            {
            TCCPError ccpErr(ECCPErrorNone);

            // Only a couple of error codes can have diagnostic information. 
            // aDiagnostic ought to be undefined in other situatios,
            // but at least in this way we can really guarantee it.
            if ( termErr == KErrGsmCCFacilityRejected ||
                 termErr == KErrGsmCCRequestedFacilityNotSubscribed ||
                 termErr == KErrGsmCCIncomingCallsBarredInCug ||
                 termErr == KErrGsmCCRequestedFacilityNotImplemented ||
                 termErr == KErrGsmCCUserNotInCug )
                {
                TName name;
                CallName( name );        
                TInt diagErr = iCommonInfo.GetDiagnosticError( name );
                ccpErr = iRequester->MapError( diagErr );
    
                // Finally use exit code if diagnostic did not contain
                // any useful information.
                if ( ccpErr == ECCPRequestFailure )
                    {
                    ccpErr = iRequester->MapError( termErr );
                    }
                }
            else
                {
                ccpErr = iRequester->MapError( termErr );
                }
            
            NotifyErrorOccurred( ccpErr );
            iTerminationErrorNotified = ETrue;
            }
        }    
    }

// ---------------------------------------------------------------------------
// CSPCall::ExitCodeError
// Reads error code from ETel call info's iExitCode.
// ---------------------------------------------------------------------------
//
TInt CSPCall::ExitCodeError() const
    {
    CSPLOGSTRING2(CSPINT, "CSPCall::ExitCodeError < this: %x", 
                    this );
    TInt callError;
    RMobileCall::TMobileCallInfoV3 callInfo;
    RMobileCall::TMobileCallInfoV3Pckg pck( callInfo );
    TInt getErr = iCall.GetMobileCallInfo( pck );
    // Is there value in higher 16 bits
    if ( KErrNone == getErr && (callInfo.iExitCode & 0xFFFF0000) ) 
        {
        CSPLOGSTRING2(CSPINT, "CSPCall::ExitCodeError callInfo.iExitCode %d", 
            callInfo.iExitCode );
        callError = ( callInfo.iExitCode >> KTimesToSplitValue ); 
        
        if ( callError > KErrEtelGsmBase ) 
            // Not in valid exteded range
            {
            // Ignore invalid extented code
            if ( ( callInfo.iExitCode & 0x0000FFFF ) == KErrNone ) 
                // core error is zero
                {
                callError = KErrNone;
                }
            else
                {
                callError = ( ( callInfo.iExitCode & 0x0000FFFF ) 
                    | 0xFFFF0000 ); 
                }
            }
        }
    // Higher and lower 16 bits are zero
    else if ( !( callInfo.iExitCode & 0xFFFFFFFF ) ) 
        {
        callError = KErrNone;
        }
    else 
        {
        // No extended error, expand value to full range
        callError = ( callInfo.iExitCode | 0xFFFF0000 );
        }
        
    CSPLOGSTRING2(CSPINT, "CSPCall::ExitCodeError > err: %d", callError);
        
    return callError;
    }

// ---------------------------------------------------------------------------
// CSPCall::UUSMessageReceived
// ---------------------------------------------------------------------------
//
 void CSPCall::UUSMessageReceived( TDesC& aMessage )
    {      
    CSPLOGSTRING(CSPREQIN, "CSPCall::UUSMessageReceived");
    TCSPSkypeIdParser parser;
           
    TPtr ptr = iSkypeId->Des();
    ptr.Zero();
    const TInt error( parser.Parse( aMessage, ptr ) );
    
    if ( !error ) 
        {
        iRemotePartyName = ptr;
        NotifyCallEventOccurred( MCCPCallObserver::ECCPNotifyRemotePartyInfoChange );            
        }
    CSPLOGSTRING2(CSPINT, "CSPCall::UUSMessageReceived  err: %d",  error );        
    }

// ---------------------------------------------------------------------------
// CSPCall::NotifyRemotePartyInfoChanged
// ---------------------------------------------------------------------------
//
void CSPCall::NotifyRemotePartyInfoChanged(const TDesC& aRemoteParty) 
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::NotifyRemotePartyInfoChanged");
    iRemotePartyName = aRemoteParty;
    NotifyCallEventOccurred( MCCPCallObserver::ECCPNotifyRemotePartyInfoChange );
    }

// ---------------------------------------------------------------------------
// CSPCall::DontReportTerminationError
// ---------------------------------------------------------------------------
//
void CSPCall::DontReportTerminationError() 
    {
    CSPLOGSTRING(CSPREQIN, "CSPCall::DontReportTerminationError");
    iDontReportTerm = ETrue;
    }

// ---------------------------------------------------------------------------
// CSPCall::UpdateCallNameNumberInfo
// Update call info including remote party name and number data  
// ---------------------------------------------------------------------------
//    
void CSPCall::UpdateCallNameNumberInfo(
        RMobileCall::TMobileCallInfoV3& aCallInfo, 
        TBool aCallAddedByMonitor )
    {
    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallNameNumberInfo <");

    iCallName.Zero();
    iRemotePartyNumber.Zero();
    iRemotePartyName.Zero();
    
    if ( aCallAddedByMonitor )        
        {
        CSPLOGSTRING(CSPINT, 
                "CSPCall::UpdateCallNameNumberInfo call added by monitor");

        // If call was created by ETel line status or incoming call monitor
        // the call name is already known, only remote party info is fetched from 
        // call info 
        iCallName.Append( iName );
        iRemotePartyName.Append( aCallInfo.iRemoteParty.iCallingName );
        iRemotePartyNumber.Append( aCallInfo.iRemoteParty.iRemoteNumber.iTelNumber );
        }
    else 
        {
        CSPLOGSTRING(CSPINT, 
                "CSPCall::UpdateCallNameNumberInfo call added by plugin owner");
        
        // The call was not created by monitor and the remote number is already known, 
        // fetch only call name from call info  
        iCallName.Append( aCallInfo.iCallName );
        iRemotePartyNumber.Append( iName ); 
        }
    
    CSPLOGSTRING2(CSPINT, 
            "CSPCall::UpdateCallNameNumberInfo iCallName: %S", &iCallName );
    CSPLOGSTRING2(CSPINT, 
            "CSPCall::UpdateCallNameNumberInfo iRemotePartyNumber: %S", &iRemotePartyNumber );
    CSPLOGSTRING2(CSPINT, 
            "CSPCall::UpdateCallNameNumberInfo iRemotePartyName: %S", &iRemotePartyName );

    CSPLOGSTRING(CSPINT, "CSPCall::UpdateCallNameNumberInfo >");
    }

// ---------------------------------------------------------------------------
// CSPCall::OpenNewCall
// Open new call 
// ---------------------------------------------------------------------------
//    
void CSPCall::OpenNewCall()
    {
    CSPLOGSTRING(CSPINT, "CSPCall::OpenNewCall <");

    // Open new call 
    __ASSERT_ALWAYS( iCall.OpenNewCall( iLine ) == KErrNone, 
            Panic( ECSPPanicNoEtel ) );

    CSPLOGSTRING(CSPINT, "CSPCall::OpenNewCall >");
    }

// ---------------------------------------------------------------------------
// CSPCall::OpenExistingCallL
// Open existing call  
// ---------------------------------------------------------------------------
//    
void CSPCall::OpenExistingCallL( const TDesC& aName )
    {
    CSPLOGSTRING2(CSPINT, 
            "CSPCall::OpenExistingCallL < aName: %S", &aName);
    
    // Open existing call with given name from current line 
    TInt err = iCall.OpenExistingCall( iLine, aName ); 
    
    if ( KErrNone != err  )
        {
        CSPLOGSTRING2(CSPERROR,
            "CSPCall::OpenCallHandleL OpenExistingCall error: %d, leaving", err);    
        User::Leave( err );
        }

    CSPLOGSTRING(CSPINT, "CSPCall::OpenExistingCallL >");
    }

// End of File