// Copyright (c) 2006-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:
//



// INCLUDE FILES
#include "cmmdatacalltsy.h"
#include "cmmdatalinetsy.h"
#include "cmmphonetsy.h"
#include "cmmtsyreqhandlestore.h"
#include "cmmcalllist.h"
#include "CMmCommonStaticUtility.h"
#include "MmTsy_numberOfSlots.h"
#include "cmmlinelist.h"
#include "cmmmessagemanagerbase.h"
#include <ctsy/pluginapi/cmmdatapackage.h>
#include <ctsy/serviceapi/gsmerror.h>
#include "cmmcallgsmwcdmaext.h"
#include <etelmmerr.h>


// ======== MEMBER FUNCTIONS ========

CMmDataCallTsy::CMmDataCallTsy()
    {
    }

CMmDataCallTsy* CMmDataCallTsy::NewL( 
    CMmPhoneTsy* aMmPhone, CMmDataLineTsy* aMmLine,
    RMobilePhone::TMobileService aMode, 
    TDes& aName, 
    CMmMessageManagerBase* aMessageManager )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::NewL. Call name: %S", &aName);

    CMmDataCallTsy* mmCall = NULL;

    //check input parameters
    if ( NULL != aMmPhone && NULL != aMmLine &&
         RMobilePhone::ECircuitDataService == aMode )
        {
        mmCall = new( ELeave ) CMmDataCallTsy;
        CleanupClosePushL( *mmCall );
        mmCall->iMmPhone = aMmPhone;
        mmCall->iMmLine = aMmLine;
        mmCall->iCallName = aName;
        mmCall->iCallMode = aMode;
        mmCall->iMessageManager = aMessageManager;
        mmCall->ConstructL( aMode );        
        CleanupStack::Pop( mmCall );
        }

    return mmCall;
    }

CMmDataCallTsy::~CMmDataCallTsy()
    {
TFLOGSTRING3("TSY: CMmDataCallTsy::~CMmDataCallTsy - Call deleted iCallId: %d iCallName: %S",
    iCallId, &iCallName);

    // If Dial fails, Symbian CSD agent will close the call immediately.
    // This means that TSY has not yet received call status indications, 
    // where call status changes to idle. Thus responses from modem are 
    // passed to call object. 
    // Here we need to recover dataport if it is used.
    CCallBase::SetUnowned();

    // Check if dataport is loaned!
    if ( iLoanedCommPort.iPort.Compare( KNullDesC) != 0 )
        {
        //Create package
        CCallDataPackage package;
        //Set call id and call mode
        package.SetCallIdAndMode( iCallId, iCallMode );
        //Pack commport
        package.PackData( &iLoanedCommPort );

        //Send request to the Domestic OS layer.
        if( iMessageManager )
        	{
        	TRAP_IGNORE( 
            		iMessageManager->HandleRequestL(
                		EEtelCallRecoverDataPort, &package );
            		   );
        	}
        	
        iLoanedCommPort.iCsy.Zero();
        iLoanedCommPort.iPort.Zero();
        }

    iRetDataCallCaps = NULL;
    iRetHscsdInfo = NULL;
    }
    

// ---------------------------------------------------------------------------
// CMmDataCallTsy::InitInternalAttributes
// Initialises miscellaneous internal attributes.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::InitInternalAttributes()
    {
    CMmCallTsy::InitInternalAttributes();

    //set call capabilities
    iCallCaps.iFlags =
        RCall::KCapsData | RCall::KCapsDial | RCall::KCapsConnect;

    // Boolean that indicates if this call object is finished data call.
    // Required as Symbian CSD agent in situation where first data call
    // fails due wrong number and it then opens second data call, which
    // dials correct number. Call status notifications go to wrong call
    // object (the first one) and causes problems for clients.
    iIsFinishedDataCall = EFalse;

    //data call params
    iRetDataCallCaps = NULL;
    iLoanedCommPort.iCsy.Zero();
    iLoanedCommPort.iPort.Zero();
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::DoExtFuncL
// DoExtFuncL is called by the Etel server when it has an "extended", i.e. 
// non-core ETel request for the TSY. To process a request handle, request  
// type and request data are passed to the TSY. 
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::DoExtFuncL(
    const TTsyReqHandle aTsyReqHandle,
    const TInt aIpc,
    const TDataPackage& aPackage )
    {
TFLOGSTRING3("TSY: CMmDataCallTsy::DoExtFuncL - IPC: %d Handle: %d",
    aIpc, aTsyReqHandle);

    TInt ret( KErrNone );

    TAny* dataPtr = aPackage.Ptr1();
    TAny* dataPtr2 = aPackage.Ptr2();

    // The request data has to extracted from TDataPackage and the TAny* 
    // pointers have to be "cast" to the expected request data type

    // NOTE! Do not put any Cancel methods here.
    switch ( aIpc )
        {
      // Call Status
        // Get Call Status
        case EMobileCallGetMobileCallStatus:
            ret = GetMobileCallStatus( aTsyReqHandle,
                reinterpret_cast<RMobileCall::TMobileCallStatus*>(dataPtr) );
            break;
        // Notify Call Status Change
        case EMobileCallNotifyMobileCallStatusChange:
            ret = NotifyMobileCallStatusChange(
                reinterpret_cast<RMobileCall::TMobileCallStatus*>(dataPtr) );
            break;
        // Transfer One Call to Remote Party of Another Call
        case EMobileCallTransfer:
            ret = TransferL( aTsyReqHandle );
            break;
        // Notify Call Event
        case EMobileCallNotifyCallEvent:
            ret = NotifyCallEvent(
                reinterpret_cast<RMobileCall::TMobileCallEvent*>( dataPtr) );
            break;
        // Call Control
        // Get Call Capabilities
        case EMobileCallGetMobileCallCaps: 
             ret = GetMobileCallCaps( aTsyReqHandle, aPackage.Des1n() );
			 break;

	    //Notify Call Capabilities Change
        case EMobileCallNotifyMobileCallCapsChange:
             ret =  NotifyMobileCallCapsChange(aPackage.Des1n());
             break;
       
	    // Call Information
        // Get Mobile Call Information
        case EMobileCallGetMobileCallInfo:
            ret = GetMobileCallInfo( aTsyReqHandle, aPackage.Des1n() );
            break;
        // Notify Change of Remote Party Information
        case EMobileCallNotifyRemotePartyInfoChange:
            ret = NotifyRemotePartyInfoChange(
            reinterpret_cast<RMobileCall::TMobileCallRemotePartyInfoV1Pckg*>(
                    aPackage.Des1n()) );
            break;
        // Data Call Capabilities
        // Get Data Call Capabilities
        case EMobileCallGetMobileDataCallCaps: 
            ret = GetMobileDataCallCaps( aTsyReqHandle, aPackage.Des1n() );
            break;
        // Notify Change of Data Call Capabilities
        case EMobileCallNotifyMobileDataCallCapsChange:
            ret = NotifyMobileDataCallCapsChange( aTsyReqHandle,
                aPackage.Des1n() );
            break;
        // Data Call RLP Parameters
        // Get Data Call RLP Range
        case EMobileCallGetMobileDataCallRLPRange:
            ret = GetMobileDataCallRLPRange( aTsyReqHandle, 
                reinterpret_cast<TInt*>(dataPtr),
                reinterpret_cast<RMobileCall::TMobileDataRLPRangesV1Pckg*>(
                    dataPtr2) );
            break;
        // High Speed Circuit Switched Data (HCSCD)
        // Set Dynamic HSCSD Call Parameters
        case EMobileCallSetDynamicHscsdParams:
            ret = SetDynamicHscsdParams( aTsyReqHandle, 
                reinterpret_cast<RMobileCall::TMobileCallAiur*>(dataPtr),
                reinterpret_cast<TInt*>(dataPtr2) );
            break;
        // Get Current HSCSD Call Information
        case EMobileCallGetCurrentHscsdInfo:
            ret = GetCurrentHscsdInfo( aTsyReqHandle, aPackage.Des1n() );
            break;
        // Notify Change of HSCSD Call Information
        case EMobileCallNotifyHscsdInfoChange:
            ret = NotifyHscsdInfoChange( aTsyReqHandle, aPackage.Des1n() );
            break;
        // Order to notify if privacy is confirmed
        case EMobileCallNotifyPrivacyConfirmation:
            ret = NotifyPrivacyConfirmation(
              reinterpret_cast<RMobilePhone::TMobilePhonePrivacy*>(dataPtr) );
            break;
        // Dial a call ( DialNoFdnCheck )
        case EMobileCallDialNoFdnCheck:
    		ret = DialNoFdnCheck( aTsyReqHandle, aPackage.Des1n(), 
    		    aPackage.Des2u() ); 
    		break;            
        // Unsupported features
        case EMobileCallDialEmergencyCall:
        case EMobileCallHold:
        case EMobileCallResume:
        case EMobileCallSwap:
        case EMobileCallGoOneToOne:

        case EMobileCallSwitchAlternatingCall:
        case EMobileCallNotifyAlternatingCallSwitch:
        case EMobileCallSetPrivacy:
        case EMobileCallSetTrafficChannel:
        case EMobileCallNotifyTrafficChannelConfirmation:
        case EMobileCallGetUUSCaps:
        case EMobileCallNotifyUUSCapsChange:
        case EMobileCallActivateUUS:
        case EMobileCallSendUUI:
        case EMobileCallReceiveUUI:
        case EMobileCallHangupWithUUI:
        case EMobileCallAnswerWithUUI:
        case EMobileCallNotifyVoiceFallback:
        case EMobileCallDeflect:
        case EMobileCallActivateCCBS:
        case EMobileCallRejectCCBS:
        default:
            ret = KErrNotSupported;
            break;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::ReqModeL
// ReqModeL is called from the ETel server's CTelObject::ReqAnalyserL in order 
// to check the type of request it has.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
CTelObject::TReqMode CMmDataCallTsy::ReqModeL(
    const TInt aIpc )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::ReqModeL - IPC: %d", aIpc);

    CTelObject::TReqMode ret( 0 ); // default return value
    
    switch ( aIpc )
        {
        // No Flow Control
        // All disabled
        // TSYs wishing to implement their own buffering algorithm will
        // place all requests in this category.
        // This category will also be used by the RecoverDataPort request
        // that must be passed to the TSY to indicate that it may use
        // the communications port after a loan.

        // Get methods that do not use Licencee specific TSY  and return 
        // immediately. Flow control not required.
        case EEtelCallGetInfo:
        case EEtelCallGetStatus:
        case EEtelCallGetCaps:
        case EEtelCallGetBearerServiceInfo:
        case EEtelCallGetOwnershipStatus:
        case EEtelCallGetCallParams:
        case EEtelCallGetCallDuration:
        case EEtelCallGetFaxSettings:
        case EMobileCallGetMobileCallStatus:
        case EMobileCallGetMobileCallInfo:
        case EMobileCallGetMobileDataCallCaps:
        case EMobileCallGetMobileCallCaps:
        case EMobileCallGetCurrentHscsdInfo:
        case EMobileCallGetMobileDataCallRLPRange:
        case EMobileCallGetUUSCaps:
        case EMobileCallActivateUUS:
        case EMobileCallSendUUI:
        case EMobileCallReceiveUUI:
        case EMobileCallHangupWithUUI:
        case EMobileCallAnswerWithUUI:
        // Other methods that do not use Licencee specific TSY and return 
        // immediately.
        // Flow control not required.
        case EEtelCallAcquireOwnership:
        case EEtelCallTransferOwnership:
        case EEtelCallSetFaxSettings:
        // Methods that can propably take a long time and cannot therefore be 
        // flow controlled. Solution: All these methods must check req handle 
        // table before handling the request. In case that the request table 
        // indicates that same method has been called and has not been 
        // completed, the method should return KErrServerBusy.
        case EMobileCallTransfer:
        // This is also included here due to the fact that Emergency call
        // should never be blocked by flow control. KErrServerBusy returned
        // when already already dialing.
        case EMobileCallDialEmergencyCall:
        // HangUp cannot be flow controlled. Client should for example be able
        // to terminate a call while another call is e.g. in Dialling state.
        case EEtelCallHangUp:
        // Answer was mixed with Hangup. Therefore this is also No flow 
        // control type
        case EEtelCallAnswer:
        // dial is not flow controlled as compeltion may take a while and that
        // blocks for example PS data activation in 3G while dialing.
        case EEtelCallDial:
        case EMobileCallDialNoFdnCheck:        
            break;
        // Flow Controlled Services
        // KReqModeFlowControlObeyed
        // Commands that change the state of the phone, e.g. clearing the
        // AoC counter; are commands that the TSY should only deal with
        // one at a time.
        
        //Voice call related methods that should be handled one at the time.
        case EEtelCallConnect:
        case EMobileCallHold:
        case EMobileCallResume:
        case EMobileCallSwap:
        case EMobileCallDeflect:
        case EMobileCallGoOneToOne:
        //Data call related methods that should be handled one at the time.
        case EEtelCallLoanDataPort:
        case EEtelCallRecoverDataPort:
        case EMobileCallSwitchAlternatingCall:
        case EMobileCallSetDynamicHscsdParams:
        case EMobileCallSetPrivacy:
        case EMobileCallSetTrafficChannel:
            ret = KReqModeFlowControlObeyed;
            break;
        // ReqModePostImmediately
        // Requests that notify a client about a change of state, where
        // the TSY needs to distinguish between different clients.
            //ret=KReqModeRePostImmediately;

        // KReqModeMultipleCompletionEnabled
        // (a) commands that may take some time, but which the TSY can
        //     handle more than one of concurrently, or 
        // (b) notifications that the TSY does not wish to be re-posted
        //     immediately, so the server does no buffering.
            //ret=KReqModeMultipleCompletionEnabled;

        // KReqModeMultipleCompletionEnabled | KReqModeFlowControlObeyed
        // A command that may take some time and which the TSY can only
        // deal with one at a time.
            //ret = KReqModeMultipleCompletionEnabled |
            //      KReqModeFlowControlObeyed;
            //break;

        // Notifications
        // KReqModeMultipleCompletionEnabled | ReqModePostImmediately
        // Requests that notify a client about a change of state.
        // Since these requests do not require the issuing of any modem
        // commands, they do not have to obey flow control.
        // The TSY never gets more than one of these outstanding per 
        // CTelObject
        case EEtelCallNotifyHookChange:        
        case EEtelCallNotifyStatusChange:
        case EEtelCallNotifyDurationChange: 
        case EEtelCallCapsChangeNotification:
        case EMobileCallNotifyCallEvent:
        case EMobileCallNotifyMobileCallStatusChange:
        case EMobileCallNotifyRemotePartyInfoChange:
        case EMobileCallNotifyPrivacyConfirmation:
        case EMobileCallNotifyTrafficChannelConfirmation:
        case EMobileCallNotifyHscsdInfoChange:
        case EMobileCallNotifyMobileDataCallCapsChange:
        case EMobileCallNotifyAlternatingCallSwitch:
        case EMobileCallNotifyMobileCallCapsChange:
        case EMobileCallNotifyVoiceFallback:
        case EMobileCallNotifyUUSCapsChange:
            ret = KReqModeMultipleCompletionEnabled |
                KReqModeRePostImmediately;
            break;
        // Cancel Requests
        // It is not necessary to include the Cancel methods in ReqModeL.
        // The ETel server never calls ReqModeL with a Cancel IPC.

        // Other variations of return values are unusable

        // Default: Call CCallBase's ReqModeL.
        default:
            //Direct the request to the CCallBase
            ret = CCallBase::ReqModeL( aIpc );
            break;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::NumberOfSlotsL
// NumberOfSlotsL is called by the server when it is registering a new 
// NOTIFICATION. It enables the TSY to tell the server how many buffer slots 
// to allocate for "repost immediately" notifications that may trigger before 
// clients collect them.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::NumberOfSlotsL(
    const TInt aIpc )
    {
    // There is a buffer in the ETel server for each type of NOTIFICATION and
    // the size of the buffer is determined by the TSY. When the ETel server
    // discovers that a request is "repost immediately" it will ask the TSY
    // how big a buffer it wants by calling CTelObject::NumberOfSlotsL( ).
    //
    // It is up to the TSY developer's judgement how many buffer slots this
    // method returns for each notification. If there is a danger that
    // a particular notification could trigger frequently and in rapid
    // succession (e.g. call group change notification) then at least 10 or
    // 20 slots may be required. For a notification that triggers rarely,
    // perhaps 1 or 2 slots is enough.
    //
    // So if the ETel server has stored a few occurrences of a particular
    // notification, when a client subsequently calls that notification
    // request, the ETel server will complete the client's request with
    // the saved data.

    TInt numberOfSlots( 1 );

    switch ( aIpc ) 
        {
        case EEtelCallNotifyHookChange:
            numberOfSlots = KMmCallHookChangeSlots;
            break;
        case EEtelCallNotifyStatusChange:
            numberOfSlots = KMmCallStatusChangeSlots;
            break;
        case EEtelCallNotifyDurationChange: 
            numberOfSlots = KMmCallDurationChangeSlots;
            break;
        case EEtelCallCapsChangeNotification:
            numberOfSlots = KMmCallCapsChangeSlots;
            break;
        case EMobileCallNotifyCallEvent:
            numberOfSlots = KMmCallCallEventSlots;
            break;
        case EMobileCallNotifyMobileCallStatusChange:
            numberOfSlots = KMmCallMobileCallStatusChangeSlots;
            break;
        case EMobileCallNotifyRemotePartyInfoChange:
            numberOfSlots = KMmCallRemotePartyInfoChangeSlots;
            break;
        case EMobileCallNotifyPrivacyConfirmation:
            numberOfSlots = KMmCallPrivacyConfirmationSlots;
            break;
        case EMobileCallNotifyTrafficChannelConfirmation:
            numberOfSlots = KMmCallTrafficChannelConfirmationSlots;
            break;
        case EMobileCallNotifyHscsdInfoChange:
            numberOfSlots = KMmCallHscsdInfoChangeSlots;
            break;
        case EMobileCallNotifyMobileDataCallCapsChange:
            numberOfSlots = KMmCallMobileDataCallCapsChangeSlots;
            break;
        case EMobileCallNotifyAlternatingCallSwitch:
            numberOfSlots = KMmCallAlternatingCallSwitchSlots;
            break;
        case EMobileCallNotifyMobileCallCapsChange:
            numberOfSlots = KMmCallMobileCallCapsChangeSlots;
            break;
        case EMobileCallNotifyVoiceFallback:
            numberOfSlots = KMmCallVoiceFallbackSlots;
            break;
        case EMobileCallNotifyUUSCapsChange:
            numberOfSlots = KMmCallUUSCapsChangeSlots;
            break;
        default:
            // Unknown or invalid Call IPC
            User::Leave( KErrNotSupported );
            break;
        }

    return numberOfSlots;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CancelService
// CancelService is called by the ETel server when it is "cleaning-up" any 
// still outstanding asynchronous requests before closing a client's 
// sub-session. This will happen if a client closes its R-class handle without 
// cancelling outstanding asynchronous requests. Only Mobile API requests are 
// handled here.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::CancelService(
    const TInt aIpc,
    const TTsyReqHandle aTsyReqHandle )
    {
    TFLOGSTRING3("TSY: CMmDataCallTsy::CancelService - IPC: %d, Req handle: %d",
        aIpc, aTsyReqHandle); 

    TInt ret( KErrNone );

    //When the clients close their sub-sessions (eg. by calling RPhone::Close)
    //they may not have cancelled all their outstanding asynchronous requests
    //before closing.  It is up to the ETel server to clean up in this
    //situation, so the server will find the list of outstanding requests
    //related to that sub-session object and pass these outstanding IPC req
    //numbers, one at a time, to the CancelService function in the TSY.
    switch ( aIpc )
        {
        //TSY has started a request and it is not possible to then cancel this
        //request. The best thing for the TSY to do in this case is to proceed
        //as though the Cancel never happened. The server's call to the TSY
        //cancel function will return synchronously. The TSY then continues to
        //wait for the original acknowledgement and when it receives it,
        //the TSY will complete the original request.
        case EMobileCallSetDynamicHscsdParams:
        case EMobileCallHold:
        case EMobileCallResume:
        case EMobileCallSwap:
        case EMobileCallGoOneToOne:
        case EMobileCallDeflect:
        case EMobileCallTransfer:
        case EMobileCallNotifyTrafficChannelConfirmation:
            break;
        //Cancel methods that are not supported
        case EMobileCallDialEmergencyCall:
        case EMobileCallSwitchAlternatingCall:
        case EMobileCallNotifyAlternatingCallSwitch:
        case EMobileCallGetMobileDataCallRLPRange:
        case EMobileCallNotifyVoiceFallback:
        case EMobileCallNotifyUUSCapsChange:
        case EMobileCallActivateUUS:
        case EMobileCallSendUUI:
        case EMobileCallReceiveUUI:
        case EMobileCallHangupWithUUI:
        case EMobileCallAnswerWithUUI:
            ret = KErrNotSupported;
            break;
        //Notification Cancels, no special requirements.
        case EMobileCallNotifyMobileDataCallCapsChange:
            ret = NotifyMobileDataCallCapsChangeCancel( aTsyReqHandle );
            break;
        case EMobileCallNotifyHscsdInfoChange:
            ret = NotifyHscsdInfoChangeCancel( aTsyReqHandle );
            break;
        case EMobileCallNotifyMobileCallCapsChange:
            ret = NotifyMobileCallCapsChangeCancel( aTsyReqHandle );
            break;
        case EMobileCallNotifyMobileCallStatusChange:
            ret = NotifyMobileCallStatusChangeCancel( aTsyReqHandle );
            break;
        case EMobileCallNotifyCallEvent:
            ret = NotifyCallEventCancel( aTsyReqHandle );
            break;
        case EMobileCallNotifyRemotePartyInfoChange:
            ret = NotifyRemotePartyInfoChangeCancel( aTsyReqHandle );
            break;
        case EMobileCallNotifyPrivacyConfirmation:
            ret = NotifyPrivacyConfirmationCancel( aTsyReqHandle );
            break;
        //Default case
        default:
            //call CCallBase
            ret = CCallBase::CancelService( aIpc, aTsyReqHandle );
            break;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteNotifyStatusChange
// Complete notification when status changes. If the new status requires, this
// method will ask call protocol extension to update it's status and 
// capabilities and line owning this call to update it's status.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteNotifyStatusChange(
    TInt aResult,
    CMmDataPackage* aDataPackage )
    {
    if ( iGhostCall ) 
        {
        HandleGhostCallStatusChange( aResult, aDataPackage );
        }
    else
        {
        TInt callIndex( 0 ); 
        TInt extendedError(
            CMmCommonStaticUtility::ExtendedErrorCode( aResult ) );
        TInt ret( KErrNone );
        TBool timerStarted( EFalse );
        TBool statusChanged ( EFalse );
        TBool mobileStatusChanged ( EFalse );
        CMmDataCallTsy* mmCall = NULL; 
        RMobileCall::TMobileCallStatus callStatus( RMobileCall::EStatusIdle );
        CCallDataPackage* callDataPackage = 
            reinterpret_cast<CCallDataPackage*>( aDataPackage );

        callDataPackage->UnPackData( callStatus );

        TFLOGSTRING2("TSY: CMmDataCallTsy::CompleteNotifyStatusChange - \
            aResult: %d", aResult );
        TFLOGSTRING3("TSY: CMmDataCallTsy::CompleteNotifyStatusChange - \
            Call status: %d, Call name: %S", callStatus, &iCallName);

        switch( callStatus )
            {
            case RMobileCall::EStatusIdle:
                // stop the call duration timer
                timerStarted = iCallTimer->Stop();
                // Check air time timer only if call was in active state
                // (call timer was started)
                if ( timerStarted )
                    {
                    iMmPhone->AirTimeTimerCheckStop();
                    UpdateLifeTimer();                    
                    }

                iCallStatus = RCall::EStatusIdle;
                iMobileCallStatus = RMobileCall::EStatusIdle;

                SetUnowned();
                ClearCallStatus();
				RecoverDataPort(0);
                statusChanged = ETrue;

                if ( KErrNone != aResult )
                    {
                    if ( KErrGsmReleaseByUser == aResult || 
                         KErrGsmBusyUserRequest == aResult )
                        {
                        // aResult must be KErrNone to indicate the client
                        // that HangUp has successfully completed 
                        CompleteHangUp( KErrNone );
                        if ( this != iMmPhone->WaitingCallForData() )
                            {
                            CompleteAnswerIncomingCall( 
                                KErrGsmBusyUserRequest );
                            }
                        }
                    else
                        {
                        // Set last exit code
                        iLastExitCode = aResult;
                        CompleteHangUp( aResult );
                        if ( this != iMmPhone->WaitingCallForData() )
                            {
                            CompleteAnswerIncomingCall( aResult );
                            }
                        }
                    CompleteDial( aResult );
                    CompleteDialNoFdn( aResult );
                    }
                // Try to complete Dial and HangUp; If completes happens from
                // here, something has gone wrong. Done to prevent TSY from
                // hanging.
                else
                    {
                    iLastExitCode = KErrGeneral;
                    TInt errorValue = CMmCommonStaticUtility::EpocErrorCode( 
                        KErrNotReady, KErrNotFound );
                    CompleteDial( errorValue );
                    CompleteDialNoFdn( errorValue );
                    CompleteHangUp( errorValue );
                    if ( this != iMmPhone->WaitingCallForData() )
                        {
                        CompleteAnswerIncomingCall( errorValue );
                        }
                    }
                // save last id. Required by Conference call implementation
                SetPreviousCallId( iCallId );
                // reset call id
                iCallId = -1;

                // reset caps. 
                iCallCaps.iFlags |=
                    RCall::KCapsDial | RCall::KCapsConnect;
                iCallCaps.iFlags &= ~( RCall::KCapsAnswer );

                // Check if KCapsHangup or dataport caps still exists
                // If it does, remove and complete notification.
                if ( ( RCall::KCapsHangUp ==
                        ( iCallCaps.iFlags & RCall::KCapsHangUp ) ) ||
                    ( RCall::KCapsLoanDataPort ==
                        ( iCallCaps.iFlags & RCall::KCapsLoanDataPort ) ) ||
                    ( RCall::KCapsRecoverDataPort ==
                        ( iCallCaps.iFlags & RCall::KCapsRecoverDataPort) ) )
                    {
                    iCallCaps.iFlags &= ~(
                        RCall::KCapsHangUp |
                        RCall::KCapsLoanDataPort |
                        RCall::KCapsRecoverDataPort );
                    CompleteNotifyCapsChange();
                    }

                // Call Transfer handling
                if ( ServiceRequested( EMultimodeCallTransfer ) )
                    {
                    // Complete Transfer 
                    CompleteTransfer( KErrNone );
                    }
                break;
                // End of case KCallStatusIdle
            case RMobileCall::EStatusDialling:
#ifdef REQHANDLE_TIMER
                iTsyReqHandleStore->StopTimeout( EMultimodeCallDial );
                iTsyReqHandleStore->StopTimeout( 
                    EMultimodeCallDialNoFdnCheck ); 
#endif
                iCallStatus = RCall::EStatusDialling;
                iMobileCallStatus = RMobileCall::EStatusDialling;
                statusChanged = ETrue;
                if ( iDialCancelFlag != CMmCallTsy::EDialCancelNotCalled )
                    {
                    TTsyReqHandle dialCancelHandle = 
                        iTsyReqHandleStore->GetTsyReqHandle( 
                            EMultimodeCallDial );
                    TTsyReqHandle dialCancelHandleNoFdn = 
                        iTsyReqHandleStore->GetTsyReqHandle( 
                        EMultimodeCallDialNoFdnCheck );                   

                    if ( 0 < dialCancelHandle )
                        {
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteNotifyStatusChange. - HangUp - EMultimodeCallDial");                        
                        HangUp( dialCancelHandle );
                        } 
                    else if ( 0 < dialCancelHandleNoFdn )
                        {
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteNotifyStatusChange. - HangUp - EMultimodeCallDialNoFdnCheck");
                        HangUp( dialCancelHandleNoFdn );
                        } 
                    else
                        {
                        iDialCancelFlag = CMmCallTsy::EDialCancelNotCalled;
                        }
                    }
                break;
            case RMobileCall::EStatusConnecting:
                iCallStatus = RCall::EStatusConnecting;
                iMobileCallStatus = RMobileCall::EStatusConnecting;
                statusChanged = ETrue;
                break;
            case RMobileCall::EStatusRinging:
                iCallStatus = RCall::EStatusRinging;
                iMobileCallStatus = RMobileCall::EStatusRinging;
                statusChanged = ETrue;

                // Set caps. 
                iCallCaps.iFlags &= ~(
                    RCall::KCapsDial | RCall::KCapsConnect );
                   
                iCallCaps.iFlags |= RCall::KCapsHangUp;
                if ( ( NULL == iMmPhone->CallList()->GetMmCallByStatus(
                        RMobileCall::EStatusConnected ) ) &&
                     ( NULL == iMmPhone->CallList()->GetMmCallByStatus(
                            RMobileCall::EStatusHold ) ) )                            
                    {
                    iCallCaps.iFlags |= RCall::KCapsAnswer;
                    }
                //complete caps change notification
                CompleteNotifyCapsChange();

                // Check if the call is for Call Back functionality.
                // E.g. client has dialled server, which calls back to 
                // save user the data call charging.
                TFLOGSTRING("TSY: CMmDataCallTsy::Check for waiting call");
                if ( this == iMmPhone->WaitingCallForData() )
                    {
                    // Client has already tried to answer the incoming 
                    // call, so do it now
                    CallComingForWaitingCall();
                    }
                break;
            case RMobileCall::EStatusAnswering:
                // Set caps
                iCallCaps.iFlags |= RCall::KCapsHangUp;
                iCallCaps.iFlags &= ~(
                    RCall::KCapsDial |
                    RCall::KCapsAnswer );


                iCallStatus = RCall::EStatusAnswering;
                iMobileCallStatus = RMobileCall::EStatusAnswering;
                statusChanged = ETrue;
                break;
            case RMobileCall::EStatusConnected:
                if ( KErrMMEtelCallForbidden == aResult )
                    {
                    CMmCallList* callList = iMmPhone->CallList();
                    
                    for( TInt i=0; i< callList->GetNumberOfObjects();i++)
                        {
                        CMmDataCallTsy* call = 
                        reinterpret_cast<CMmDataCallTsy*>(
                            iMmPhone->CallList()->GetMmCallByIndex( i ) );
                    
                        // if there is call with status Answering, complete
                        // it with CALL_CAUSE_NOT_ALLOWED    
                        if( RCall::EStatusAnswering == call->Status() )
                            {
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteNotifyStatusChange Answering not allowed!");                                
                            TInt errorValue = 
                                CMmCommonStaticUtility::EpocErrorCode( 
                                   KErrAccessDenied, KErrMMEtelCallForbidden );
                            call->CompleteAnswerIncomingCall( errorValue );
                            }
                        }
                    }
                // check previous status. If status is answering
                if ( RCall::EStatusAnswering == iCallStatus )
                    {
                	// don't start timers if error occurred
                	if ( KErrNone == aResult )
                		{
                    	//Start call duration monitoring
                    	iCallTimer->Start(); 
                    	//Check if start the air time duration monitoring
                    	iMmPhone->AirTimeTimerCheckStart();
                		}

                    }
                // If it was connecting and dial cancel has not been activated
                else if ( ( iCallStatus == RCall::EStatusConnecting ||
                    iCallStatus == RCall::EStatusDialling ) &&
                    CMmCallTsy::EDialCancelNotCalled == iDialCancelFlag )
                    {
                    // Start call duration monitoring
                    iCallTimer->Start(); 
                    // start air time duration monitoring
                    iMmPhone->AirTimeTimerCheckStart();
                    }

                // Don't update status if it has not changed.
                if ( RCall::EStatusConnected != iCallStatus ||
                     RMobileCall::EStatusConnected != iMobileCallStatus )
                    {
                    iCallStatus = RCall::EStatusConnected;
                    iMobileCallStatus = RMobileCall::EStatusConnected;
                    statusChanged = ETrue;
                    }
                break;
            case RMobileCall::EStatusDisconnecting:
                // When call is released, this call object becomes "used".
                // Thus set iIsFinishedDataCall to ETrue. 
                iIsFinishedDataCall = ETrue;

                // Core status
                iCallStatus = RCall::EStatusHangingUp; 
                statusChanged = ETrue;
                // Mobile status
                iMobileCallStatus = RMobileCall::EStatusDisconnecting;
                mobileStatusChanged = ETrue;

                if ( iCallDirection == RMobileCall::EMobileTerminated )
                    {
                    // CompleteDial in case remote user is busy
                    CompleteDial( aResult );
                    CompleteDialNoFdn( aResult );
                    }

                // Set last exit code
                if ( KErrGsmReleaseByUser == aResult ||
                    KErrGsmBusyUserRequest == aResult ||
                    KErrGsmCCNormalUnspecified == extendedError ||
                    KErrNone == aResult )
                    {
                    iLastExitCode = KErrNone;
                    }
                else
                    {
                    // set last exit code
                    iLastExitCode = aResult;
                    }

                // reset caps.
                if ( RCall::KCapsLoanDataPort == 
                    ( iCallCaps.iFlags & RCall::KCapsLoanDataPort ) )
                    {
                    iCallCaps.iFlags &= ~( RCall::KCapsLoanDataPort );
                    CompleteNotifyCapsChange();
                    }
                break;
            case RMobileCall::EStatusDisconnectingWithInband:
                // When call is released, this call object becomes "used".
                // Thus set iIsFinishedDataCall to ETrue. 
                iIsFinishedDataCall = ETrue;
                // Core status
                iCallStatus = RCall::EStatusHangingUp; 
                statusChanged = ETrue;
                // Mobile status
                iMobileCallStatus = 
                    RMobileCall::EStatusDisconnectingWithInband;
                mobileStatusChanged = ETrue;
                // CompleteDial in case remote user is busy
                CompleteDial( aResult );
                CompleteDialNoFdn( aResult );
                // Set last exit code
                if ( KErrGsmReleaseByUser == aResult ||
                    KErrGsmBusyUserRequest == aResult ||
                    KErrGsmCCNormalUnspecified == extendedError ||
                    KErrNone == aResult )
                    {
                    iLastExitCode = KErrNone;
                    }
                else
                    {
                    // set last exit code
                    iLastExitCode = aResult;
                    }

                //reset caps.
                if ( RCall::KCapsLoanDataPort == 
                     ( iCallCaps.iFlags & RCall::KCapsLoanDataPort ) )
                    {
                    iCallCaps.iFlags &= ~( RCall::KCapsLoanDataPort );
                    CompleteNotifyCapsChange();
                    }
                break;
            case RMobileCall::EStatusHold:
            case RMobileCall::EStatusUnknown:
            case RMobileCall::EStatusReconnectPending:
            case RMobileCall::EStatusWaitingAlternatingCallSwitch:
            case RMobileCall::EStatusTransferring:
            case RMobileCall::EStatusTransferAlerting:
            default:
                // nothing to do
                break;
            }

        //reset req handle. Returns the deleted req handle
        TTsyReqHandle reqHandle = iTsyReqHandleStore->GetTsyReqHandle(
            EMultimodeCallNotifyStatusChange );

        if ( ( EMultimodeCallReqHandleUnknown != reqHandle ) 
                                                        && statusChanged )
            {
            *iRetStatus = iCallStatus;
            //reset req handle. 
            iTsyReqHandleStore->ResetTsyReqHandle(
                EMultimodeCallNotifyStatusChange );

            ReqCompleted( reqHandle, ret );
            }

        // reset req handle. Returns the deleted req handle
        reqHandle = iTsyReqHandleStore->GetTsyReqHandle(
            EMultimodeCallNotifyMobileCallStatusChange );

        if ( ( EMultimodeCallReqHandleUnknown != reqHandle ) 
                && (statusChanged || mobileStatusChanged) )
            {
            *iRetMobileCallStatus = iMobileCallStatus;
            // reset req handle. 
            iTsyReqHandleStore->ResetTsyReqHandle( 
                EMultimodeCallNotifyMobileCallStatusChange );
            ReqCompleted( reqHandle, ret );
            }

        // Update also line's status
        if ( statusChanged || mobileStatusChanged )
            {
            iMmLine->CompleteNotifyStatusChange();
            }

        // Inform extension dll about the current status. Enables dynamic 
        // capability updates. Must be done before Notifying caps change 
        if ( KErrNone == iMmCallExtInterface-> 
            CompleteNotifyStatusChange( iMobileCallStatus ) )
            { 
            CompleteNotifyMobileCallCapsChange( KErrNone );
            CompleteNotifyMobileDataCallCapsChange();
            }

        mmCall = reinterpret_cast<CMmDataCallTsy*>(
            iMmPhone->CallList()->GetMmCallByIndex( callIndex ) );
        while ( mmCall ) 
            { 
            if ( RMobileCall::EStatusIdle != mmCall->MobileCallStatus() && 
                 this != mmCall )
                { 
                if ( KErrNone ==
                    mmCall->ActiveCallExtension()-> 
                    CompleteNotifyStatusChange( mmCall->MobileCallStatus() ) )
                    { 
                    mmCall->CompleteNotifyMobileCallCapsChange( KErrNone );
                    mmCall->CompleteNotifyMobileDataCallCapsChange();
                    }
                } 
            callIndex++;
            mmCall = reinterpret_cast<CMmDataCallTsy*>(
                iMmPhone->CallList()->GetMmCallByIndex( callIndex ) );
            }
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::Dial
// This CORE API method dials to the given number.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::Dial(
    const TTsyReqHandle aTsyReqHandle,
    const TDesC8* aCallParams,
    TDesC* aTelNumber )
    {
TFLOGSTRING3("TSY: CMmDataCallTsy::Dial - Req handle: %d, Call name: %S",
    aTsyReqHandle, &iCallName);

	if( aCallParams->Length()!= 0)
		{
		if(sizeof(RCall::TCallParams) > aCallParams->Length())
			{
			TFLOGSTRING ("TSY: CMmDataCallTsy::Dial bad size argument");
			// Complete the request with appropiate error        
			return KErrArgument;
			}
		}
	CMmCallList* callList = iMmPhone->CallList();
	TBool dialFlag( EFalse );
	
	for(TInt i=0; i< callList->GetNumberOfObjects();i++)
		{		
		CMmCallTsy* call = callList->GetMmCallByIndex( i );
		if( call->GetDialFlag() )
			{
			dialFlag = ETrue;
			i= callList->GetNumberOfObjects();
			}
		}
	
	if(!dialFlag )
		{
TFLOGSTRING("TSY: CMmDataCallTsy::Dial ONGOING" );		
		SetDialFlag( ETrue );
		TTsyReqHandle dialHandle = 
			iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallDial );
    
		// reset exit code
		iLastExitCode = KErrNone;
	
		// reset finished data call flag
		iIsFinishedDataCall = EFalse;
	
		if ( ERfsStateInfoInactive == iMmPhone->GetRfStateInfo() )  
			{
			TFLOGSTRING("TSY: Offline mode ON, Dial request is not allowed" );
			TInt ret = CMmCommonStaticUtility::EpocErrorCode(
				KErrGeneral, KErrGsmOfflineOpNotAllowed );
	
			// Complete the request with appropiate error
			ReqCompleted ( aTsyReqHandle, ret ); 
			}
	
		// check that status is Idle
		else if ( RMobileCall::EStatusIdle != iMobileCallStatus )
			{
			// The request cannot be forwarded since this call object
			// is still in use.
			// Complete request with status value informing the client
			// about the situation.
			TFLOGSTRING("TSY: CMmDataCallTsy::Dial - KErrNotReady");
			ReqCompleted( aTsyReqHandle, KErrNotReady );
			}
		else if ( 0 < dialHandle )
			{
			// The request is already in processing because of previous request
			// Complete request with status value informing the client about 
			// the situation.
			TFLOGSTRING("TSY: CMmDataCallTsy::Dial - KErrServerBusy");
			ReqCompleted( aTsyReqHandle, KErrServerBusy );
			}
		else
			{
		   
			TInt ret( KErrNone );
			TInt trapError( KErrNone );
			TCallOwnership ownerShip = EOwnedFalse;
	
			if(aCallParams->Length() >0)
				{
				RCall::TCallParamsPckg* paramsPckg = reinterpret_cast<RCall::TCallParamsPckg*>(
					const_cast<TDesC8*>( aCallParams ) );
				RCall::TCallParams& params = ( *paramsPckg )();
	
				// save call params
				iCallParams.iSpeakerControl = params.iSpeakerControl;
				iCallParams.iSpeakerVolume = params.iSpeakerVolume;
				iCallParams.iInterval = params.iInterval;
				iCallParams.iWaitForDialTone = params.iWaitForDialTone;
				}
			else
				{
				iCallParams.iSpeakerControl = RCall::EMonitorSpeakerControlAlwaysOff;
				iCallParams.iSpeakerVolume = RCall::EMonitorSpeakerVolumeOff;
				iCallParams.iInterval = 0;
				iCallParams.iWaitForDialTone = RCall::EDialToneWait;
				}
		  
			// set call direction
			iCallDirection = RMobileCall::EMobileOriginated;
	
			// Check if there already is an active or connecting call
			TInt numberOfObjects = iMmPhone->CallList()->
				GetNumberOfObjects();
			for ( TInt i = 0; i < numberOfObjects; i++ )
				{
				CMmDataCallTsy* mmCall = reinterpret_cast<CMmDataCallTsy*>(
					iMmPhone->CallList()->GetMmCallByIndex( i ) );
				if ( !( RMobileCall::EStatusUnknown == 
							mmCall->MobileCallStatus() ||
						RMobileCall::EStatusIdle == 
							mmCall->MobileCallStatus() ||
						RMobileCall::EStatusDisconnecting == 
							mmCall->MobileCallStatus() ||
						RMobileCall::EStatusDisconnectingWithInband == 
							mmCall->MobileCallStatus() ) )
					{
					ret = KErrEtelCallAlreadyActive;
					break;
					}
				}
	
			// Return value can also be priorityclient! 
			ownerShip = CheckOwnership( aTsyReqHandle );
	
			if ( KErrNone == ret && ( EOwnedUnowned == ownerShip || 
				 EOwnedPriorityClient == ownerShip ) ) 
				{
				SetOwnership( aTsyReqHandle );
	
				if ( KErrNone == ret )
					{
					TFLOGSTRING("TSY: CMmDataCallTsy::Dial - DialDataCall");
					TRAP( trapError,
						ret = iMmCallExtInterface->DialDataCallL(
							iCallMode, aCallParams, aTelNumber );
						);
					if ( KErrNone != trapError )
						{
						//error handling. DialDataCall() leaved.
						ret = trapError;
						}
					// If dial succeeded, continue
					if ( KErrNone == ret )
						{
						RPhone::TStatus modemStatus;
						modemStatus.iModemDetected = RPhone::EDetectedPresent;
						modemStatus.iMode = RPhone::EModeEstablishingLink;
						iMmPhone->CompleteNotifyModemDetected( modemStatus );
	
						//update core status
						iCallCaps.iFlags &= ~(
							RCall::KCapsDial | RCall::KCapsConnect );
						iCallCaps.iFlags |= RCall::KCapsHangUp;
						//complete core caps change
						CompleteNotifyCapsChange();
						}
					}
				}
	
			if ( KErrNone != ret )
				{
				ReqCompleted( aTsyReqHandle, ret );
				ClearCallStatus();
				}
			else
				{
#ifdef REQHANDLE_TIMER
				// set timer for the request
				SetTypeOfResponse( EMultimodeCallDial, aTsyReqHandle );
#else
				// set timer
				iTsyReqHandleStore->SetTsyReqHandle(
					EMultimodeCallDial, aTsyReqHandle );
#endif
				}
			}
	
		return KErrNone;
		}
    else
       	return KErrServerBusy;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteDial
// Completes a Dial request.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteDial(
    TInt aResult )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::CompleteDial - Result: %d", aResult ); 
TFLOGSTRING3("TSY: CMmDataCallTsy::CompleteDial - Call Id: %d, Call name: %S",
    iCallId, &iCallName);
    
    // Set dial flag to false
    SetDialFlag( EFalse );
    
    // reset req handle. Returns the deleted req handle
    TTsyReqHandle reqHandle = iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallDial );

    if ( EMultimodeCallReqHandleUnknown != reqHandle )
        {
        if ( aResult != KErrNone )
            {
            // The creation has failed.
            iLastExitCode = aResult;
            ClearCallStatus();

            //Dial has failed, update core status - dial possible again
            iCallCaps.iFlags |= RCall::KCapsDial;
            iCallCaps.iFlags &= ~( RCall::KCapsHangUp );

            //complete caps change notification
            CompleteNotifyCapsChange();
            }

        ReqCompleted( reqHandle, aResult );

        }

    // Set also new call caps to enable dataport loaning!
    if ( RCall::EStatusConnected == iCallStatus &&
         KErrNone == aResult )
        {
        iCallCaps.iFlags |= RCall::KCapsLoanDataPort;
        iMmCallExtInterface->AddGSMCallCaps(
            RCall::KCapsLoanDataPort );

        //complete caps change notification
        CompleteNotifyCapsChange();
        CompleteNotifyMobileCallCapsChange( KErrNone );
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::AnswerIncomingCall
// This CORE API method is used for answering to an incoming call.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::AnswerIncomingCall(
    const TTsyReqHandle aTsyReqHandle,
    const TDesC8* )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::AnswerIncomingCall. \n\t\t\t Handle: %d",
    aTsyReqHandle); 

    TTsyReqHandle answerCallHandle = 
        iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallAnswer );

    if ( 0 < answerCallHandle )
        {
        //The request is already in processing because of previous request
        //Complete request with status value informing the client about 
        //the situation.
        ReqCompleted( aTsyReqHandle, KErrServerBusy );
        }
    else
        {
        TInt ret( KErrNone );
        //call object is under use again
        iIsFinishedDataCall = EFalse;
        //reset exit code
        iLastExitCode = KErrNone;

        if ( EOwnedUnowned == CheckOwnership( aTsyReqHandle ) )
            {
            // If Answering is allowed (KCapsAnswer is set) or
            // if automatic answer is to be enabled (call status idle)
            if ( iCallCaps.iFlags & RCall::KCapsAnswer ||
                RCall::EStatusIdle == iCallStatus )
                {
                SetOwnership( aTsyReqHandle );

                if ( KErrNone == ret )
                    {
                    //Answer incoming call
                    TRAPD( trapError,
                        ret = iMmCallExtInterface->
                                  AnswerIncomingDataCallL( iCallId );
                        );

                    if ( KErrNone != trapError )
                        {
                        //error handling. Object cannot be created.
                        ret = trapError;
                        }

                    if ( KErrNone == ret )
                        {
                        //Remove answering, dialing and connecting 
                        //capabilities
                        iCallCaps.iFlags |= RCall::KCapsHangUp;
                        iCallCaps.iFlags &= ~( RCall::KCapsAnswer | 
                            RCall::KCapsDial | RCall::KCapsConnect );
                        CompleteNotifyCapsChange();
                        }
                    }
                }
            else
                {
                ret = KErrNotReady;
                }
            }
        else if ( EOwnedTrue == CheckOwnership( aTsyReqHandle ) ||
            EOwnedPriorityClient == CheckOwnership( aTsyReqHandle ) )
            {
            // SOS architechture Call Back functionality tries to answer 
            // incoming call even before the current MO call is fully 
            // released. So, save pointer to this CMmDataCallTsy object 
            // into CMmPhoneTsy.
            iMmPhone->SetWaitingCallForData( this );
            //Remove answering, dialing and connecting capabilities.
            iCallCaps.iFlags |= RCall::KCapsHangUp;
            iCallCaps.iFlags &= ~(
                RCall::KCapsAnswer | RCall::KCapsDial | RCall::KCapsConnect );
            CompleteNotifyCapsChange();
            }
        // Else return error
        else
            {
            ret = KErrEtelNotCallOwner;
            }

        //error handling
        if ( KErrNone != ret )
            {
            ReqCompleted( aTsyReqHandle, ret );
            ClearCallStatus();
            }
        else
            {
#ifdef REQHANDLE_TIMER
            //set timer for the request
            SetTypeOfResponse( EMultimodeCallAnswer, aTsyReqHandle );
#else
            //timer set
            iTsyReqHandleStore->SetTsyReqHandle(
                EMultimodeCallAnswer, aTsyReqHandle );
#endif
            }
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::AnswerIncomingCallCancel
// TSY has started a request and it is not possible to then cancel this 
// request. The best thing for the TSY to do in this case is to call
// HangUp method to do this and set a flag so that we can know that
// AnswerIncomingCallCancel handling is going on.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::AnswerIncomingCallCancel(
    const TTsyReqHandle aTsyReqHandle )
    {
TFLOGSTRING3("TSY: CMmDataCallTsy::AnswerIncomingCallCancel. Req handle: %d, Call name: %S",
    aTsyReqHandle, &iCallName);

    TInt ret( KErrNone );

    if( iAnswerCancelFlag )
        {
        ret = KErrServerBusy;
        }
    else
        {
        iAnswerCancelFlag = ETrue;

        if ( 0 < iCallId )
            {
            HangUp( aTsyReqHandle );
            }
        else 
            {
TFLOGSTRING2("TSY: CMmDataCallTsy::AnswerIncomingCallCancel -- iCallStatus = %d", 
    iCallStatus);       
            if ( RCall::EStatusUnknown == iCallStatus )
                {               
                // Cancel automatic answering

                //Create package
                CCallDataPackage package;
                //Set call id and call mode
                package.SetCallIdAndMode( iCallId, iCallMode );
                // This is needed, messhandler tries to get two pointers. 
                // Without this second pointer is NULL and crashes
                TBool autoStChangeDisable( EFalse );
                TInt hangUpCause( KErrGsmReleaseByUser );
                //Pack call parameters and mobile call info
                package.PackData( &hangUpCause, &autoStChangeDisable );

                //Send request to the Domestic OS layer.
                TRAPD( leaveError,
                    ret = iMessageManager->HandleRequestL( 
                         EEtelCallHangUp, &package );
                    );

                //send failure
                if ( KErrNone != ret || KErrNone != leaveError )
                    {
                    ReqCompleted( aTsyReqHandle, ret );
                    }
                }
            CompleteAnswerIncomingCall( KErrCancel );
            }
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteAnswerIncomingCall
// Completes answer request to client.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteAnswerIncomingCall(
    TInt aResult )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::CompleteAnswerIncomingCall - Result: %d",
    aResult ); 
TFLOGSTRING3("TSY: CMmDataCallTsy::CompleteAnswerIncomingCall - Call Id: %d, Call name: %S",
    iCallId, &iCallName);

    //reset req handle. Returns the deleted req handle
    TTsyReqHandle reqHandle =
        iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallAnswer );

    if ( EMultimodeCallReqHandleUnknown != reqHandle )
        {
        if ( KErrNone != aResult )
            {
            TInt extendedError(
                CMmCommonStaticUtility::ExtendedErrorCode( aResult ) );

            if ( KErrGsmCCNormalUnspecified == extendedError )
                {
                //Call MT released while answer request was ongoing
                //Set Symbian error value to disconnected.
                aResult = CMmCommonStaticUtility::EpocErrorCode( 
                    KErrGeneral, KErrDisconnected );
                }
            else
                {
                iCallCaps.iFlags |= RCall::KCapsAnswer | RCall::KCapsDial;
                iCallCaps.iFlags &= ~( RCall::KCapsHangUp );

                CompleteNotifyCapsChange();
                }

            iLastExitCode = aResult;

            ClearCallStatus();
            }

        ReqCompleted( reqHandle, aResult );

        }

    // Set also new call caps to enable dataport loaning!
    if ( RCall::EStatusConnected == iCallStatus &&
         KErrNone == aResult )
        {
        iCallCaps.iFlags |= RCall::KCapsLoanDataPort;
        iMmCallExtInterface->AddGSMCallCaps(
            RCall::KCapsLoanDataPort );

        //complete caps change notification
        CompleteNotifyCapsChange();
        CompleteNotifyMobileCallCapsChange( KErrNone );
        }
      
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::HangUp
// This CORE API method disconnects the call. Used with normal voice calls, 
// emergency calls as well as data calls. DialCancel also uses this method.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::HangUp(
    const TTsyReqHandle aTsyReqHandle )
    {
TFLOGSTRING3("TSY: CMmDataCallTsy::HangUp - Req. handle: %d, Call name: %S",
    aTsyReqHandle, &iCallName);

    TInt hangUpCause( KErrNone );
    TInt ret( KErrNone );

    TTsyReqHandle hangUpHandle = 
        iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallHangUp );
    TTsyReqHandle dialHandle = 
        iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallDial );
    TTsyReqHandle dialHandleNoFdnCheck = 
        iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallDialNoFdnCheck );        
            
    if ( 0 < hangUpHandle || iHangUpFlag )
        {
        //The request is already in processing because of previous request
        //Complete request with status value informing the client about 
        //the situation.
TFLOGSTRING("TSY: CMmDataCallTsy::HangUp - KErrServerBusy");
        ReqCompleted( aTsyReqHandle, KErrServerBusy );
        }
    else if ( RCall::EStatusIdle == iCallStatus &&
        EMultimodeCallReqHandleUnknown == dialHandle )
        {
        //Call object is already in idle state. Complete HangUp request with
        //error.
TFLOGSTRING("TSY: CMmDataCallTsy::HangUp - KErrNotReady");        
        ReqCompleted( aTsyReqHandle, KErrNotReady );
        }
    else
        {
        // If this was not called by DialCancel or AnswerIncomingCallCancel
        if ( CMmCallTsy::EDialCancelNotCalled == iDialCancelFlag &&
            !iAnswerCancelFlag )
            {
#ifdef REQHANDLE_TIMER
            //set timer for the request
            SetTypeOfResponse( EMultimodeCallHangUp, aTsyReqHandle );
#else
            //save HangUp request handle, set timer
            iTsyReqHandleStore->SetTsyReqHandle(
                EMultimodeCallHangUp, aTsyReqHandle );
#endif
            }

        //decide the hangup cause
        if ( RCall::EStatusRinging == iCallStatus )
            {
            iLastExitCode = KErrGsmCallRejected;
            hangUpCause = KErrGsmBusyUserRequest;
            }
        else
            {
            hangUpCause = KErrGsmReleaseByUser;
            }

        // Call handling
        //If the call is ringing e.g. MT call, we do not have ownership
        //yet. So let the client reject the call without checking 
        //ownership.
        if ( RCall::EStatusRinging == iCallStatus )
            {
            TFLOGSTRING("TSY: CMmDataCallTsy::HangUp - Reject incoming call");
            }
        //Phone Application is the first client that is started, it 
        //will always be the priority client and thus able to hangup calls
        //Owner of the call is also able to hangup the call.
        else if ( ( CCallBase::CheckPriorityClient( aTsyReqHandle ) ) ||
            ( CheckOwnership( aTsyReqHandle ) != EOwnedFalse ) )
            {
            ret = KErrNone;
            }
        // If call is not owned, complete with error
        else if ( CCallBase::EOwnedTrue != 
            CheckOwnership( aTsyReqHandle ) )
            {
            iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallHangUp );
            ret = KErrEtelNotCallOwner;
            ReqCompleted( aTsyReqHandle, KErrEtelNotCallOwner );
            }    

        if ( KErrNone == ret )
            {
            //Create package
            CCallDataPackage package;
            //Set call id and call mode
            package.SetCallIdAndMode( iCallId, iCallMode );

            // This is needed, messhandler tries to get two pointers. Without 
            // this second pointer is NULL and crashes
            TBool autoStChangeDisable = EFalse;
            //Pack call parameters and mobile call info
            package.PackData( &hangUpCause, &autoStChangeDisable );
            //Send request to the Domestic OS layer.
            TRAPD( leaveError,
                ret = iMessageManager->HandleRequestL( 
                                            EEtelCallHangUp, &package );
                );

            //send failure
            if ( KErrNone != ret || KErrNone != leaveError )
                {
                iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallHangUp );
                ReqCompleted( aTsyReqHandle, ret );
                }
            else
                {
                //update core status - hangup not possible now.
                //remove also dataport caps
                iCallCaps.iFlags &= ~(
                    RCall::KCapsHangUp | RCall::KCapsLoanDataPort );

                iMmCallExtInterface->RemoveGSMCallCaps(
                    RCall::KCapsHangUp | RCall::KCapsLoanDataPort );

                //complete core caps change
                CompleteNotifyCapsChange();
                CompleteNotifyMobileCallCapsChange( KErrNone );
                //set HangUp flag to ongoing     
                iHangUpFlag = ETrue;
                }
            }
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteHangUp
// Completes call hangup (both normal and emergency calls). If the cause value 
// is different than the sent one, the call release requset has failed. In 
// this case the causeValue describes the fail cause. Otherwise the call  
// releasing has succeeded.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteHangUp(
    TInt aResult )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::CompleteHangUp.\n  \t\t\t Result: %d",
    aResult ); 
TFLOGSTRING3("TSY: CMmDataCallTsy::CompleteHangUp - Call Id: %d, Call name: %S", 
    iCallId, &iCallName);

    TInt ret( KErrNone );

    // Complete for HangUp request
    // (not to DialCancel or AnswerIncomingCallCancel)
    if ( CMmCallTsy::EDialCancelNotCalled == iDialCancelFlag &&
         !iAnswerCancelFlag )
        {
        //reset req handle. Returns the deleted req handle
        TTsyReqHandle reqHandle =
            iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallHangUp );

        if ( EMultimodeCallReqHandleUnknown != reqHandle )
            {
            //if hangup request failed
            if ( KErrNone != aResult )
                {
                //Hangup failed, it should be still possible to carry out
                iCallCaps.iFlags |= RCall::KCapsHangUp;
                iMmCallExtInterface->AddGSMCallCaps(
                    RCall::KCapsHangUp );

                //Call status is not idle. HangUp request failed, complete 
                //HangUp request with error.
                if ( RCall::EStatusIdle != iCallStatus )
                	{
                    // ignore KErrGsmReleaseByUser, which means that the call ended
                    // because the local user released the call, and must be treated
                    // as a normal return code from the LTSY
                    ret = ( (aResult == KErrGsmReleaseByUser) ? KErrNone : aResult );
                	}
                }
            else
                {
                //Dial hangup has succeeded, update core status - 
                //dial possible again
                iCallCaps.iFlags |= RCall::KCapsDial;

                if ( KErrGsmCallRejected != iLastExitCode )
                    {
                    iLastExitCode = KErrNone;
                    }

                //Bring back also the connecting capability
                iCallCaps.iFlags |= RCall::KCapsConnect;
                //If client refuses to answer, remove the answering capability
                iCallCaps.iFlags &= ~( RCall::KCapsAnswer );
                }
            ReqCompleted( reqHandle, ret );

            //complete caps change notification
            CompleteNotifyCapsChange();
            CompleteNotifyMobileCallCapsChange( KErrNone );

            //Change modem state to idle
            RPhone::TStatus modemStatus;
            modemStatus.iModemDetected = RPhone::EDetectedPresent;
            modemStatus.iMode = RPhone::EModeIdle;
            iMmPhone->CompleteNotifyModemDetected( modemStatus );
            // Reset call extension attributes
            iMmCallExtInterface->ResetInternalAttributes();
            }
        }
    // Complete for DialCancel or AnswerIncomingCallCancel, success
    else if ( KErrNone == aResult ) 
        { 
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp - EMultimodeCallDial");           
        // Find out if this is cancelling of Dial
        TTsyReqHandle cancelHandle =
            iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallDial ); 

        if ( NULL == cancelHandle ) 
            { 
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp - EMultimodeCallDialNoFdnCheck");                
	        // Find out if this is cancelling of DialNoFdnCheck
	        cancelHandle = iTsyReqHandleStore->
            ResetTsyReqHandle( EMultimodeCallDialNoFdnCheck );
        
            if ( NULL == cancelHandle )
                { 
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp - EMultimodeCallAnswer");                
                // Find out if this is cancelling of AnswerIncomingCall
                cancelHandle = iTsyReqHandleStore->ResetTsyReqHandle(
                    EMultimodeCallAnswer );
                }
        	}
        
        if ( 0 < cancelHandle ) 
            { 
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp with KErrCancel");
             
            // Complete with error value KErrCancel
            ReqCompleted( cancelHandle, KErrCancel );

            // Cancel has succeeded, update core status -
            // dial possible again
            iCallCaps.iFlags |= RCall::KCapsDial;
            // Bring back also the connecting capability
            iCallCaps.iFlags |= RCall::KCapsConnect;
            // If client refuses to answer, remove the answering capability
            iCallCaps.iFlags &= ~( RCall::KCapsAnswer );
            // Complete caps change notification
            CompleteNotifyCapsChange();

            // Change modem state to idle
            RPhone::TStatus modemStatus;
            modemStatus.iModemDetected = RPhone::EDetectedPresent;
            modemStatus.iMode = RPhone::EModeIdle;
            iMmPhone->CompleteNotifyModemDetected( modemStatus );
            // Reset call extension attributes
            iMmCallExtInterface->ResetInternalAttributes();
            }
        } 
    // Cancel failed and the request succeeded (connected)
    else if ( RCall::EStatusConnected == iCallStatus ) 
        { 
        // Find out if this is cancelling of Dial
        TTsyReqHandle cancelHandle =
            iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallDial ); 

        if ( NULL == cancelHandle ) 
            { 
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp - cancelling of EMultimodeCallDialNoFdnCheck");     
            // Find out if this is cancelling of DialNoFdnCheck
            TTsyReqHandle cancelHandle =
                iTsyReqHandleStore->ResetTsyReqHandle( 
                    EMultimodeCallDialNoFdnCheck ); 
            
            if ( NULL == cancelHandle )
                {
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp - cancelling of AnswerIncomingCall");                     
                // Find out if this is cancelling of AnswerIncomingCall
                cancelHandle = iTsyReqHandleStore->ResetTsyReqHandle( 
                    EMultimodeCallAnswer );
                }
            }


        // Cancel to Dial or AnswerIncomingCall
        if ( 0 < cancelHandle ) 
            { 
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteHangUp - with KErrNone");             
            // Complete with success (KErrNone)
            ReqCompleted( cancelHandle, KErrNone ); 

            // Succeeded, update core status - hangup possible again
            iCallCaps.iFlags |= RCall::KCapsHangUp;
            // Complete caps change notification
            CompleteNotifyCapsChange();
            } 
        } 

    // Reset cancel flags
    iDialCancelFlag = CMmCallTsy::EDialCancelNotCalled;
    iAnswerCancelFlag = EFalse;
    // reset the HangUp flag
    iHangUpFlag = EFalse;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::GetOwnershipStatus
// Get call ownership status.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::GetOwnershipStatus(
    const TTsyReqHandle aTsyReqHandle,
    RCall::TOwnershipStatus* aOwnershipStatus )
    {
    TCallOwnership ownerShip = CheckOwnership( aTsyReqHandle );
    
    switch ( ownerShip )
        {
        case EOwnedUnowned:
            *aOwnershipStatus = RCall::EOwnershipUnowned;
            break;
        case EOwnedTrue:
            *aOwnershipStatus = RCall::EOwnershipOwnedByThisClient;
            break;
        case EOwnedFalse:
            *aOwnershipStatus = RCall::EOwnershipOwnedByAnotherClient;
            break;
        case EOwnedPriorityClient:
            if ( CCallBase::CheckPriorityClient( aTsyReqHandle ) )
                {
                *aOwnershipStatus = RCall::EOwnershipOwnedByThisClient;
                }
            else
                {
                *aOwnershipStatus = RCall::EOwnershipOwnedByAnotherClient;
                }
            break;
        default:
            //all possible values are switched, nothing to do here...
            break;
        }

    ReqCompleted( aTsyReqHandle, KErrNone );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::TransferOwnership
// Transfers the call ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::TransferOwnership(
    const TTsyReqHandle aTsyReqHandle )
    {
    // If call is not owned, complete with error
    if ( CCallBase::EOwnedTrue != CheckOwnership( aTsyReqHandle ) )
        {
        ReqCompleted( aTsyReqHandle, KErrEtelNotCallOwner );
        }
    // If list is empty, complete with error
    else if ( iList->iAcquireList.IsEmpty() )
        {
        ReqCompleted( aTsyReqHandle, KErrEtelNoClientInterestedInThisCall );
        }
    else
        {
        CAcquireEntry* entry = iList->iAcquireList.First();
        if ( entry )
            {
            SetOwnership( entry->iTsyReqHandle );
            ReqCompleted( entry->iTsyReqHandle, KErrNone );
            iList->Remove( entry );
            ReqCompleted( aTsyReqHandle, KErrNone );
            }
        else 
            {
            ReqCompleted( aTsyReqHandle, KErrGeneral );
            }
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::AcquireOwnership
// Acquire the call ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::AcquireOwnership(
    const TTsyReqHandle aTsyReqHandle )
    {
    TInt trapError;
    // Check if the call is unowned?
    if ( CheckOwnership( aTsyReqHandle ) == CCallBase::EOwnedUnowned )
        {
        // It is, return with error
        ReqCompleted( aTsyReqHandle, KErrEtelCallNotActive );
        }
    else 
        {
        CAcquireEntry* entry = NULL;
        // Call is owned, add this req handle to acquire list
// coverity [resource_leak]
// TRAP macro releases memory while exception caught and trapError != KErrNone
        TRAP( trapError, ( entry = CAcquireEntry::NewL( aTsyReqHandle ) ) );
        if ( trapError != KErrNone )
            {
            //error handling. Object cannot be created.
            ReqCompleted( aTsyReqHandle, trapError );
            }
        else if ( NULL != entry )
            {
            iList->iAcquireList.AddLast( *entry );
            }
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::AcquireOwnershipCancel
// Cancel the call ownership acquire.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::AcquireOwnershipCancel(
    const TTsyReqHandle aTsyReqHandle )
    {
    CAcquireEntry* entry = iList->FindByTsyReqHandle( aTsyReqHandle );
    if ( NULL != entry )
        {
        iList->Remove( entry );
        ReqCompleted( aTsyReqHandle, KErrCancel );
        }
    else
        {
        ReqCompleted( aTsyReqHandle, KErrNotFound );
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::RelinquishOwnership
// Relinquish the call ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::RelinquishOwnership()
    {
    if ( iList->iAcquireList.IsEmpty() ) 
        {
        SetUnowned();
        if ( RCall::EStatusConnected != iCallStatus )
            {
            RelinquishOwnershipCompleted( KErrNone );
            }
        }
    else
        {
        CAcquireEntry* entry = iList->iAcquireList.First();
        if ( entry ) 
            {
            SetOwnership( entry->iTsyReqHandle );
            ReqCompleted( entry->iTsyReqHandle, KErrNone );
            iList->Remove( entry );
            }
        RelinquishOwnershipCompleted( KErrNone );
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::RegisterNotification
// RegisterNotification is called when the server recognises that this 
// notification is being posted for the first time on this sub-session object. 
// It enables the TSY to "turn on" any regular notification messages that it 
// may receive from DOS. Currently does not really do anything but returns 
// KErrNone to ETel server in case of known notification request type. 
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::RegisterNotification(
    const TInt aIpc )
    {
    TInt ret( KErrNone );

    switch ( aIpc )
        {
        case EEtelCallNotifyHookChange:        
        case EEtelCallNotifyStatusChange:
        case EEtelCallNotifyDurationChange: 
        case EEtelCallCapsChangeNotification:
        case EMobileCallNotifyCallEvent:
        case EMobileCallNotifyMobileCallStatusChange:
        case EMobileCallNotifyRemotePartyInfoChange:
        case EMobileCallNotifyPrivacyConfirmation:
        case EMobileCallNotifyTrafficChannelConfirmation:
        case EMobileCallNotifyHscsdInfoChange:
        case EMobileCallNotifyMobileDataCallCapsChange:
        case EMobileCallNotifyAlternatingCallSwitch:
        case EMobileCallNotifyMobileCallCapsChange:
        case EMobileCallNotifyVoiceFallback:
        case EMobileCallNotifyUUSCapsChange:
            ret = KErrNone;
            break;
        default:
            // Unknown or invalid IPC
            ret = KErrNotSupported;
            break;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::DeregisterNotification
// DeregisterNotification is called when the server recognises that this 
// notification will not be posted again because the last client to have a 
// handle on this sub-session object has just closed the handle. It enables 
// the TSY to "turn off" any regular notification messages that it may receive  
// from DOS. Currently does not really do anything but returns KErrNone to  
// ETel server in case of known notification request type. 
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::DeregisterNotification(
    const TInt aIpc )
    {
    TInt ret ( KErrNone );

    switch ( aIpc )
        {
        case EEtelCallNotifyHookChange:        
        case EEtelCallNotifyStatusChange:
        case EEtelCallNotifyDurationChange: 
        case EEtelCallCapsChangeNotification:
        case EMobileCallNotifyCallEvent:
        case EMobileCallNotifyMobileCallStatusChange:
        case EMobileCallNotifyRemotePartyInfoChange:
        case EMobileCallNotifyPrivacyConfirmation:
        case EMobileCallNotifyTrafficChannelConfirmation:
        case EMobileCallNotifyHscsdInfoChange:
        case EMobileCallNotifyMobileDataCallCapsChange:
        case EMobileCallNotifyAlternatingCallSwitch:
        case EMobileCallNotifyMobileCallCapsChange:
        case EMobileCallNotifyVoiceFallback:
        case EMobileCallNotifyUUSCapsChange:
            ret = KErrNone;
            break;
        default:
            // Unknown or invalid IPC
            ret = KErrNotSupported;
            break;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::ClearCallStatus
// Clears internal call status.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::ClearCallStatus()
    {
    SetUnowned();
    CMmCallTsy::ClearCallStatus();
    }

#ifdef REQHANDLE_TIMER

// ---------------------------------------------------------------------------
// CMmDataCallTsy::SetTypeOfResponse
// Sets the type of response for a given Handle. Automatic mode includes an 
// automatic response in case of non response from the Domestic OS Layer in a 
// specified time.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::SetTypeOfResponse(
    const TInt aReqHandleType,
    const TTsyReqHandle aTsyReqHandle )
    {
    //Sets the type of response for a given Handle. Automatic mode includes an 
    //automatic response in case of non response from the Licencee specific
    //TSY in a specified time.
    TInt timeOut( 0 );

    //example switch
    switch ( aReqHandleType )
        {
        case EMultimodeCallDial:
        case EMultimodeCallDialNoFdnCheck:
            timeOut = KMmCallDialTimeOut;
            break;
        case EMultimodeCallAnswer:
            // If call mode is data and client is expecting call back from
            // server, set timeout value to KMmCallAnswerCallBackTimeOut
            if ( this == iMmPhone->WaitingCallForData() )
                {
                timeOut = KMmCallAnswerCallBackTimeOut;
                }
            else
                {
                timeOut = KMmCallAnswerTimeOut;
                }
            break;
        case EMultimodeCallHangUp:
            timeOut = KMmCallHangUpTimeOut;
            break;
        case EMultimodeCallTransfer:
            timeOut = KMmCallTransferTimeOut;
            break;
        case EMultimodeCallSetDynamicHscsdParams:
            timeOut = KMmCallSetDynamicHscsdParamsTimeOut;
            break;
        //Can't use timer:
        // - all notifications
            //case EMultimodeCallNotifyStatusChange: 
            //case EMultimodeCallNotifyDurationChange:
            //case EMultimodeCallCapsChangeNotification:
            //case EMultimodeCallNotifyMobileCallStatusChange: 
            //case EMultimodeCallNotifyCallEvent:
            //case EMultimodeCallNotifyRemotePartyInfoChange:
            //case EMultimodeCallNotifyMobileCallCapsChange:
            //case EMultimodeCallNotifyDataCallCapsChange:
            //case EMultimodeCallNotifyHscsdInfoChange:
            //case EMultimodeCallNotifyPrivacyConfirmation:

        case EMultimodeMobileCallHold:
        case EMultimodeMobileCallResume:
        case EMultimodeMobileCallSwap:
        case EMultimodeMobileCallDeflectCall:
        case EMultimodeMobileCallDialEmergencyCall:
        case EMultimodeCallGoOneToOne:
        default:
            //does not use timer
            iTsyReqHandleStore->SetTsyReqHandle( 
                aReqHandleType, 
                aTsyReqHandle );
            break;
        }

    if ( timeOut > 0 )
        {
        //the timeout parameter is given in seconds.
        iTsyReqHandleStore->SetTsyReqHandle(
            aReqHandleType, aTsyReqHandle, timeOut );
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::Complete
// Completes the request due timer expiration.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::Complete(
    TInt aReqHandleType,
    TInt aError )
    {
    //All possible TSY req handle types are listed in the
    //switch case below. 
    switch( aReqHandleType )
        {
        //cases handled with automatic completion
        case EMultimodeCallSetDynamicHscsdParams:
            CompleteSetDynamicHscsdParams( aError );
            break;

        //Can't use timer:
        // - all notifications
            //case EMultimodeCallNotifyStatusChange: 
            //case EMultimodeCallNotifyDurationChange:
            //case EMultimodeCallCapsChangeNotification:
            //case EMultimodeCallNotifyMobileCallStatusChange: 
            //case EMultimodeCallNotifyCallEvent:
            //case EMultimodeCallNotifyRemotePartyInfoChange:
            //case EMultimodeCallNotifyMobileCallCapsChange:
            //case EMultimodeCallNotifyDataCallCapsChange:
            //case EMultimodeCallNotifyHscsdInfoChange:
            //case EMultimodeCallNotifyPrivacyConfirmation:

        case EMultimodeCallDial:
        case EMultimodeCallDialNoFdnCheck:
        case EMultimodeCallAnswer:
        case EMultimodeCallHangUp:
        case EMultimodeMobileCallHold:
        case EMultimodeMobileCallResume:
        case EMultimodeMobileCallSwap:
        case EMultimodeMobileCallDeflectCall:
        case EMultimodeMobileCallDialEmergencyCall:
        case EMultimodeCallTransfer: 
        case EMultimodeCallGoOneToOne:
        default:
            CMmCallTsy::Complete( aReqHandleType, aError );
            break;
        }
    }
#endif

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CallComingForWaitingCall
// Starts to answer an incoming call.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CallComingForWaitingCall()
    {
    //Incoming call detected, which is directed to this call object
    //which should be waiting for incoming call
    TFLOGSTRING("TSY: CMmDataCallTsy::CallComingForWaitingCall");

    TInt ret( KErrNone );

    TFLOGSTRING("TSY: CMmDataCallTsy::AnswerIncomingCall - Data call");
    //Answer incoming call
    TRAPD( trapError,
        ret = iMmCallExtInterface->AnswerIncomingDataCallL( iCallId );
        );

    if ( KErrNone != trapError )
        {
        //error handling. Object cannot be created.
        ret = trapError;
        }

    if ( KErrNone == ret )
        {
        // SOS architechture Call Back functionality tries to answer 
        // incoming call even before the current MO call is fully 
        // released. This is done by dialup agent (CsdAgx/CsdAgt), 
        // which does not wait for the previous call to get 
        // disconnected. As the call is now answered, NULL the pointer
        // to this CMmDataCallTsy object from CMmPhoneTsy.
        iMmPhone->SetWaitingCallForData( NULL );
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::IsFinishedData
// Returns boolean that indicates if call object is already been used in
// data calls. This means that call has been already released or disconnected.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TBool CMmDataCallTsy::IsFinishedData() const
    {
    return iIsFinishedDataCall;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::LoanDataPort
// This CORE API method loans dataport to client.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::LoanDataPort(
    const TTsyReqHandle aTsyReqHandle,
    RCall::TCommPort* aCommPort )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::LoanDataPort - Client taking control: %S",
    &iCallName );

    TInt ret( KErrNone );

    // Check if the port is loaned!
    if ( iLoanedCommPort.iPort.Compare( KNullDesC) == 0 )
        {
        // Check ownership
        TCallOwnership ownerShip = CheckOwnership( aTsyReqHandle );
        // If not yet owned, take ownership.
        if ( EOwnedUnowned == ownerShip || EOwnedPriorityClient == ownerShip )
            {
            SetOwnership( aTsyReqHandle );
            }
        // Else check if this req handle already owns the call.
        else if ( CCallBase::EOwnedTrue != ownerShip )
            {
            ret = KErrEtelNotCallOwner;
            }

        // If port can be loaned, request access to dataport
        if ( ret == KErrNone )
            {
            //Create package
            CCallDataPackage package;
            //Set call id and call mode
            package.SetCallIdAndMode( iCallId, iCallMode );
            //Pack commport
            package.PackData( aCommPort );

            //Send request to the Domestic OS layer.
            TRAPD( trapError,
                ret = iMessageManager->HandleRequestL(
                    EEtelCallLoanDataPort, &package );
                );

            if ( KErrNone != trapError )
                {
                //error handling, leaved.
                ret = trapError;               
                }

            if ( KErrNone == ret )
                {
                iLoanedCommPort.iCsy.Copy( aCommPort->iCsy );
                iLoanedCommPort.iPort.Copy( aCommPort->iPort );

                // If dataport was available, changed new call caps and 
                // complete notification!
                iCallCaps.iFlags |=
                    RCall::KCapsData |
                    RCall::KCapsHangUp |
                    RCall::KCapsRecoverDataPort;
                iCallCaps.iFlags &= ~( RCall::KCapsLoanDataPort );

                iMmCallExtInterface->AddGSMCallCaps(
                    RCall::KCapsRecoverDataPort );
                iMmCallExtInterface->RemoveGSMCallCaps(
                    RCall::KCapsLoanDataPort );

                CompleteNotifyCapsChange();
                CompleteNotifyMobileCallCapsChange( KErrNone );
                }
            else
            	{
            	SetUnowned();
            	}
            }
        }
    else
        {
        ret = KErrEtelPortAlreadyLoaned;
        }

    // Complete request if result is KErrNone.
    // Return possible error to CCallBase base class because it sets
    // iLoanDataport to TRUE if KErrNone is returned. This may cause
    // serious problems when the data call object is closed and data port
    // is not really loaned. ETel completes request in case where error is
    // returned.
    if ( KErrNone == ret )    
        {
        ReqCompleted( aTsyReqHandle, KErrNone );
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::LoanDataPortCancel
// Cancels dataport loaning to client. LoanDataPort always
// completes immediately, this is never used.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::LoanDataPortCancel(
    const TTsyReqHandle )
    {
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::RecoverDataPort
// This CORE API method recovers dataport from client.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::RecoverDataPort(
    const TTsyReqHandle aTsyReqHandle )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::RecoverDataPort - Client returning control: %S",
    &iCallName );

    TInt ret( KErrNone );

    // Check if the port is loaned!
    if ( iLoanedCommPort.iPort.Compare( KNullDesC) != 0 )
        {
        //Create package
        CCallDataPackage package;
        //Set call id and call mode
        package.SetCallIdAndMode( iCallId, iCallMode );
        //Pack commport
        package.PackData( &iLoanedCommPort );

        //Send request to the Domestic OS layer.
        TRAPD( trapError,
            ret = iMessageManager->HandleRequestL(
                EEtelCallRecoverDataPort, &package );
            );

        if ( KErrNone != trapError )
            {
            //error handling, leaved.
            ret = trapError;
            }

        iLoanedCommPort.iCsy.Zero();
        iLoanedCommPort.iPort.Zero();

        // Set new call caps!
        iCallCaps.iFlags |= RCall::KCapsLoanDataPort;
        iCallCaps.iFlags &= ~( RCall::KCapsRecoverDataPort );

        iMmCallExtInterface->AddGSMCallCaps(
            RCall::KCapsLoanDataPort );
        iMmCallExtInterface->RemoveGSMCallCaps(
            RCall::KCapsRecoverDataPort );
        }
    else
        {
        ret = KErrEtelPortNotLoanedToClient;
        }

    if(0 != aTsyReqHandle)
        {
        ReqCompleted( aTsyReqHandle, ret );
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::RecoverDataPortAndRelinquishOwnership
// Recovers dataport from client and relinquishes ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::RecoverDataPortAndRelinquishOwnership()
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::RecoverDataPortAndRelinquishOwnership - \
    Client returning control: %S", &iCallName );

    TInt ret( KErrNone );

    // Check if the port is loaned!
    if ( iLoanedCommPort.iPort.Compare( KNullDesC) != 0 )
        {
        //Create package
        CCallDataPackage package;
        //Set call id and call mode
        package.SetCallIdAndMode( iCallId, iCallMode );
        //Pack commport
        package.PackData( &iLoanedCommPort );

        //Send request to the Domestic OS layer.
        TRAPD( trapError,
            ret = iMessageManager->HandleRequestL(
                EEtelCallRecoverDataPort, &package );
            );

        if ( KErrNone != trapError )
            {
            //error handling, leaved.
            ret = trapError;
            }

        iLoanedCommPort.iCsy.Zero();
        iLoanedCommPort.iPort.Zero();

        if ( iList->iAcquireList.IsEmpty() )
            {
            SetUnowned();
            
            if ( KErrNone == ret )
                {
                // Call owner is closing data call handle. Call 
                // RecoverDataPortAndRelinquishOwnershipCompleted method.
                RecoverDataPortAndRelinquishOwnershipCompleted( KErrNone );
                }            
            }
        else
            {
            CAcquireEntry* entry = iList->iAcquireList.First();
            if ( entry )
                {
                SetOwnership( entry->iTsyReqHandle );
                ReqCompleted( entry->iTsyReqHandle, KErrNone );
                iList->Remove( entry );
                }
            // Set new call caps!
            iCallCaps.iFlags |= RCall::KCapsLoanDataPort;
            iCallCaps.iFlags &= ~( RCall::KCapsRecoverDataPort );

            iMmCallExtInterface->AddGSMCallCaps(
                RCall::KCapsLoanDataPort );
            iMmCallExtInterface->RemoveGSMCallCaps(
                RCall::KCapsRecoverDataPort );
            }
        }
    else
        {
        ret = KErrEtelPortNotLoanedToClient;
        }

    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::Connect
// Set correct data call attributes, depending on parameter extension.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::Connect(
    const TTsyReqHandle aTsyReqHandle,
    const TDesC8* aCallParams )
    {
TFLOGSTRING("TSY: CMmDataCallTsy::Connect");      
    if ( CheckOwnership( aTsyReqHandle ) == CCallBase::EOwnedUnowned )
        {
        SetOwnership( aTsyReqHandle );
        }
    TDes8* callParams = reinterpret_cast<TDes8*>(const_cast<TDesC8*> (aCallParams));
    if(callParams->MaxLength() == 0)
    	{
    	// default parameters...
        iCallParams.iSpeakerControl = RCall::EMonitorSpeakerControlAlwaysOff;
        iCallParams.iSpeakerVolume = RCall::EMonitorSpeakerVolumeOff;
        iCallParams.iInterval = 0;
        iCallParams.iWaitForDialTone = RCall::EDialToneWait;
        ReqCompleted( aTsyReqHandle, KErrNone );

        return KErrNone;
    	}
    if(callParams->MaxLength() == sizeof(RCall::TCallParams))
    	{
    	// only RCall parameters
        RCall::TCallParamsPckg* paramsPckg = 
            reinterpret_cast<RCall::TCallParamsPckg*>(callParams);
        RCall::TCallParams& params = ( *paramsPckg )();

        iCallParams.iSpeakerControl = params.iSpeakerControl;
        iCallParams.iSpeakerVolume = params.iSpeakerVolume;
        iCallParams.iInterval = params.iInterval;
        iCallParams.iWaitForDialTone = params.iWaitForDialTone;
        ReqCompleted( aTsyReqHandle, KErrNone );

        return KErrNone;
    	}
    if(sizeof(RMobileCall::TMobileCallParamsV1) > aCallParams->Length())
       	{
        TFLOGSTRING ("TSY: CMmDataCallTsy::Connect bad size argument");
        // Complete the request with appropiate error        
        return KErrArgument;
    	}
    RMobileCall::TMobileCallParamsV1Pckg* paramsPckgV1 = 
        reinterpret_cast<RMobileCall::TMobileCallParamsV1Pckg*> ( callParams );
    RMobileCall::TMobileCallParamsV1& paramsV1 = ( *paramsPckgV1 )();

        if ( CheckOwnership( aTsyReqHandle ) == CCallBase::EOwnedUnowned )
            {
            SetOwnership( aTsyReqHandle );
            }
        

        iCallParams.iSpeakerControl = paramsV1.iSpeakerControl;
        iCallParams.iSpeakerVolume = paramsV1.iSpeakerVolume;
        iCallParams.iInterval = paramsV1.iInterval;
        iCallParams.iWaitForDialTone = paramsV1.iWaitForDialTone;

        if ( ( paramsV1.ExtensionId() == KETelExtMultimodeV1 ) ||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileDataCallParamsV1 ) ||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileDataCallParamsV2 ) ||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileDataCallParamsV8 ) ||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV1 )||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV2 )||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV7 )||
            ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV8 ))
            {
            iCallParams.iIdRestrict = paramsV1.iIdRestrict;
            iCallParams.iCug = paramsV1.iCug;
            iCallParams.iAutoRedial = paramsV1.iAutoRedial;
            }

        if ( ( paramsV1.ExtensionId() ==
                RMobileCall::KETelMobileDataCallParamsV1 ) ||
             ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileDataCallParamsV2 ) ||
             ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileDataCallParamsV8 ) ||
             ( paramsV1.ExtensionId() ==
                RMobileCall::KETelMobileHscsdCallParamsV1 )||
             ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV2 )||
             ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV7 )||
             ( paramsV1.ExtensionId() == 
                RMobileCall::KETelMobileHscsdCallParamsV8 ))
            {
            iMmCallExtInterface->Connect( aCallParams );
            }

        ReqCompleted( aTsyReqHandle, KErrNone );

    
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::ConnectChancel
// Cancels connecting of a (data) call (Not Supported).
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::ConnectCancel(
    const TTsyReqHandle )
    {
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::GetMobileDataCallCaps
// Get data call caps.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::GetMobileDataCallCaps(
    const TTsyReqHandle aTsyReqHandle,
    TDes8* aCaps )
    {
    TInt ret( KErrArgument );   
    
    if ( sizeof ( RMobileCall::TMobileCallDataCapsV1 ) <= aCaps->MaxLength() )
        {
        RMobileCall::TMobileCallDataCapsV1Pckg* callDataCapsV1Pckg = 
            reinterpret_cast<RMobileCall::TMobileCallDataCapsV1Pckg*>( aCaps );
        RMobileCall::TMobileCallDataCapsV1& callDataCapsV1 = 
            ( *callDataCapsV1Pckg )();
        
        if ( KETelExtMultimodeV1 == callDataCapsV1.ExtensionId() )
            {
            // The call will only have data capabilities if this call has been 
            // opened from the phone's data line.
            ret = KErrNone;
            iMmCallExtInterface->GetMobileDataCallCapsV1( callDataCapsV1 );
            }
        }

    ReqCompleted( aTsyReqHandle, ret );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::NotifyMobileDataCallCapsChange
// Notifies change of the data call capabilities.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::NotifyMobileDataCallCapsChange(
    const TTsyReqHandle,
    TDes8* aCaps )
    {
    TInt ret( KErrArgument );   
    
    if ( sizeof ( RMobileCall::TMobileCallDataCapsV1 ) <= aCaps->MaxLength() )
        {
        RMobileCall::TMobileCallDataCapsV1Pckg* callDataCapsV1Pckg = 
            reinterpret_cast<RMobileCall::TMobileCallDataCapsV1Pckg*>( aCaps );
        RMobileCall::TMobileCallDataCapsV1& callDataCapsV1 = 
            ( *callDataCapsV1Pckg )();  
        
        if ( KETelExtMultimodeV1 == callDataCapsV1.ExtensionId() )
            {
            ret = KErrNone;
            iRetDataCallCaps = aCaps;
            iReqHandleType = EMultimodeCallNotifyDataCallCapsChange;
            }
        }    
    
    return ret;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::NotifyMobileDataCallCapsChangeCancel
// Cancels MobileDataCallCaps change notifications.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::NotifyMobileDataCallCapsChangeCancel(
    const TTsyReqHandle aTsyReqHandle )
    {
    iRetDataCallCaps = NULL;
    iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallNotifyDataCallCapsChange );
    ReqCompleted( aTsyReqHandle, KErrCancel );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteNotifyMobileDataCallCapsChange
// Complete a NotifyMobileDataCallCapsChange request.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteNotifyMobileDataCallCapsChange()
    {
    //reset req handle. Returns the deleted req handle
    TTsyReqHandle reqHandle = iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallNotifyDataCallCapsChange );

    if ( EMultimodeCallReqHandleUnknown != reqHandle )
        {
        RMobileCall::TMobileCallDataCapsV1Pckg* callDataCapsV1Pckg = 
            reinterpret_cast<RMobileCall::TMobileCallDataCapsV1Pckg*>( 
                iRetDataCallCaps );
        RMobileCall::TMobileCallDataCapsV1& callDataCapsV1 = 
            ( *callDataCapsV1Pckg )();
                        
        iMmCallExtInterface->GetMobileDataCallCapsV1( callDataCapsV1 );
        
        iRetDataCallCaps = NULL;

        ReqCompleted( reqHandle, KErrNone );
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::GetBearerServiceInfo
// Get bearer service info.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::GetBearerServiceInfo(
    const TTsyReqHandle aTsyReqHandle,
    RCall::TBearerService* aBearerService )
    {
    // If the call is not connected, the request will return KErrNotFound.
    TInt ret( KErrNotFound );
    // Reset info variables. Info is also unknown for voice call.
    aBearerService->iBearerCaps =
        RCall::KBearerCapsCompressionNone | RCall::KBearerCapsProtocolUnknown;
    aBearerService->iBearerSpeed = RCall::EBearerDataUnknown;

    if ( RCall::EStatusConnected == iCallStatus )
        {
        ret = iMmCallExtInterface->GetBearerServiceInfo( aBearerService );
        }

    ReqCompleted( aTsyReqHandle, ret );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::SetDynamicHscsdParams
// Set HSCSD dynamic data parameters.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::SetDynamicHscsdParams(
    const TTsyReqHandle aTsyReqHandle,
    RMobileCall::TMobileCallAiur* aAiur,
    TInt* aRxTimeslots )
    {
    TInt ret( KErrNone );
    // HSCSD parameters can be set only if this call has been opened
    // from the phone's data line.
TFLOGSTRING3("TSY: CMmDataCallTsy::SetDynamicHscsdParams.\n  \t\t\t Air Intrf: %d\n  \t\t\t RX slots: %d", 
    *aAiur, *aRxTimeslots);

    iReqHandleType = EMultimodeCallSetDynamicHscsdParams;

    TRAP_IGNORE( 
        ret = iMmCallExtInterface->SetDynamicHscsdParamsL(
            aAiur, aRxTimeslots );
        );

    // If not a data call or extension returned error.
    if ( KErrNone != ret )
        {
        ReqCompleted( aTsyReqHandle, KErrNotFound );
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::SetDynamicHscsdParamsCancel
// Cancel SetDynamicHscsdParams request.
// Not possible, as SetDynamicHscsdParams request is completed immediately.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::SetDynamicHscsdParamsCancel(
    const TTsyReqHandle ) const
    {
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteSetDynamicHscsdParams
// Complete a SetDynamicHscsdParams request.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteSetDynamicHscsdParams(
    TInt aErrorCode )
    {
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteSetDynamicHscsdParams");    
    //reset req handle. Returns the deleted req handle
    TTsyReqHandle reqHandle = iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallSetDynamicHscsdParams );

    if ( EMultimodeCallReqHandleUnknown != reqHandle )
        {
        ReqCompleted( reqHandle, aErrorCode );
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::GetCurrentHscsdInfo
// Get current HSCSD info.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::GetCurrentHscsdInfo(
    const TTsyReqHandle aTsyReqHandle,
    TDes8* aHSCSDInfo )
    {
TFLOGSTRING("TSY: CMmDataCallTsy::GetCurrentHscsdInfo");        
    TInt ret( KErrNone );
    // HSCSD info can be read only if this call has been opened from the 
    // phone's data line and call is connected.
    // Connected here means that TSY gas has received CONNECT: XXXX from modem
    // When CONNECT: XXXX has been received, TSY has completed clients request
    // which can be dial or answer.
    // Thus those req handles should be unknown, otherwise the call is not yet
    // connected. 
    if ( ( EMultimodeCallReqHandleUnknown ==
            iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallDial ) ) &&
        ( EMultimodeCallReqHandleUnknown ==
            iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallAnswer ) ) &&
        ( EMultimodeCallReqHandleUnknown ==
            iTsyReqHandleStore->GetTsyReqHandle( EMultimodeCallDialNoFdnCheck ) ) )
        {
        ret = iMmCallExtInterface->GetCurrentHscsdInfo( aHSCSDInfo );
        }
    else
        {
        RMobileCall::TMobileCallHscsdInfoV1Pckg* hscsdInfoPckg = 
            reinterpret_cast<RMobileCall::TMobileCallHscsdInfoV1Pckg*>(
                aHSCSDInfo );
        RMobileCall::TMobileCallHscsdInfoV1& hscsdInfo = (*hscsdInfoPckg)();

        hscsdInfo.iAiur = RMobileCall::EAiurBpsUnspecified;
        hscsdInfo.iRxTimeSlots = 0;
        hscsdInfo.iTxTimeSlots = 0;
        hscsdInfo.iCodings = RMobileCall::ETchCodingUnspecified;

        ret = KErrEtelCallNotActive;
        }

    ReqCompleted( aTsyReqHandle, ret );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::NotifyHscsdInfoChange
// Notifies change of the HSCSD info.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::NotifyHscsdInfoChange(
    const TTsyReqHandle,
    TDes8* aHSCSDInfo )
    {
    // HSCSD info can be read only if this call has been opened
    // from the phone's data line.
    // Save request handle and ptr to aHSCSDInfo.
    iRetHscsdInfo = aHSCSDInfo;
    iReqHandleType = EMultimodeCallNotifyHscsdInfoChange;

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::NotifyHscsdInfoChangeCancel
//  Cancels HSCSD info change notifications.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::NotifyHscsdInfoChangeCancel(
    const TTsyReqHandle aTsyReqHandle )
    {
    TInt ret( KErrNone );

    iRetHscsdInfo = NULL;
    iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallNotifyHscsdInfoChange );
    ret = KErrCancel;

    ReqCompleted( aTsyReqHandle, ret );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteNotifyHscsdInfoChange
// Complete a NotifyHscsdInfoChange request.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteNotifyHscsdInfoChange()
    {
TFLOGSTRING("TSY: CMmDataCallTsy::CompleteNotifyHscsdInfoChange");       
    //reset req handle. Returns the deleted req handle
    TTsyReqHandle reqHandle = iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallNotifyHscsdInfoChange );

    if ( EMultimodeCallReqHandleUnknown != reqHandle )
        {
        TInt ret = iMmCallExtInterface->GetCurrentHscsdInfo( iRetHscsdInfo );
        iRetHscsdInfo = NULL;
        ReqCompleted( reqHandle, ret );
        }
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::GetMobileDataCallRLPRange
// Get Data Call RLP Range.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::GetMobileDataCallRLPRange(
    const TTsyReqHandle aTsyReqHandle,
    TInt*,
    TDes8* )
    {
    ReqCompleted( aTsyReqHandle, KErrNotSupported );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::DialNoFdnCheck
// This CORE API method dials to the given number.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmDataCallTsy::DialNoFdnCheck(
    const TTsyReqHandle aTsyReqHandle,
    const TDesC8* aCallParams,
    TDesC* aTelNumber )
    {
TFLOGSTRING3("TSY: CMmDataCallTsy::DialNoFdnCheck - Req handle: %d, Call name: %S",
    aTsyReqHandle, &iCallName);

	CMmCallList* callList = iMmPhone->CallList();
	TBool dialFlag( EFalse );
	
	for(TInt i=0; i< callList->GetNumberOfObjects();i++)
		{		
		CMmCallTsy* call = callList->GetMmCallByIndex( i );
		if( call->GetDialFlag() )
			{
			dialFlag = ETrue;
			i= callList->GetNumberOfObjects();
			}
		}
	
	if( !dialFlag )
		{
TFLOGSTRING("TSY: CMmDataCallTsy::DialNoFdnCheck ONGOING" );		
    		
    	SetDialFlag( ETrue );
    		
        TTsyReqHandle dialHandle = iTsyReqHandleStore->GetTsyReqHandle(
        		EMultimodeCallDialNoFdnCheck );
        
        // reset exit code
        iLastExitCode = KErrNone;
    
        // reset finished data call flag
        iIsFinishedDataCall = EFalse;
    
        if ( ERfsStateInfoInactive == iMmPhone->GetRfStateInfo() )  
            {
TFLOGSTRING("TSY: CMmDataCallTsy - DialNoFdnCheck - Offline mode ON, Dial request is not allowed" );
            TInt ret = CMmCommonStaticUtility::EpocErrorCode(
                KErrGeneral, KErrGsmOfflineOpNotAllowed );
            SetDialFlag( EFalse );
TFLOGSTRING("TSY: CMmDataCallTsy::DialNoFdnCheck - RF inactive -> dial-flag false" );        
            // Complete the request with appropiate error
            ReqCompleted ( aTsyReqHandle, ret ); 
            }

        // check that status is Idle
        else if ( RMobileCall::EStatusIdle != iMobileCallStatus )
            {
            // Request cannot be forwarded since this call object
            // is still in use.
            // Complete request with status value informing the client
            // about the situation.
TFLOGSTRING("TSY: CMmDataCallTsy::DialNoFdnCheck - KErrNotReady");
            ReqCompleted( aTsyReqHandle, KErrNotReady );
            }
        else if ( 0 < dialHandle )
            {
            // Request is already in processing because of previous request
            // Complete request with status value informing the client about 
            // the situation.
TFLOGSTRING("TSY: CMmDataCallTsy::DialNoFdnCheck - KErrServerBusy");
            ReqCompleted( aTsyReqHandle, KErrServerBusy );
            }
        else
            {
            TInt ret( KErrNone );
            TInt trapError( KErrNone );
            TCallOwnership ownerShip = EOwnedFalse;
    
            RMobileCall::TMobileCallParamsV1Pckg* paramsPckgV1 = 
                reinterpret_cast<RMobileCall::TMobileCallParamsV1Pckg*>(
                    const_cast<TDesC8*>( aCallParams ) );
            RMobileCall::TMobileCallParamsV1& paramsV1 = ( *paramsPckgV1 )();
    
            // save call params
            iCallParams.iSpeakerControl = paramsV1.iSpeakerControl;
            iCallParams.iSpeakerVolume = paramsV1.iSpeakerVolume;
            iCallParams.iInterval = paramsV1.iInterval;
            iCallParams.iWaitForDialTone = paramsV1.iWaitForDialTone;
    
            // set call direction
            iCallDirection = RMobileCall::EMobileOriginated;
    
            // Check if there already is an active or connecting call
            TInt numberOfObjects = iMmPhone->CallList()->
                GetNumberOfObjects();
            for ( TInt i = 0; i < numberOfObjects; i++ )
                {
                CMmDataCallTsy* mmCall = reinterpret_cast<CMmDataCallTsy*>(
                    iMmPhone->CallList()->GetMmCallByIndex( i ) );
                if ( !( RMobileCall::EStatusUnknown == 
                            mmCall->MobileCallStatus() ||
                        RMobileCall::EStatusIdle == 
                            mmCall->MobileCallStatus() ||
                        RMobileCall::EStatusDisconnecting == 
                            mmCall->MobileCallStatus() ||
                        RMobileCall::EStatusDisconnectingWithInband == 
                            mmCall->MobileCallStatus() ) )
                    {
                    ret = KErrEtelCallAlreadyActive;
                    break;
                    }
                }
    
            // Return value can also be priorityclient! 
            ownerShip = CheckOwnership( aTsyReqHandle );
    
            if ( KErrNone == ret && ( EOwnedUnowned == ownerShip || 
                 EOwnedPriorityClient == ownerShip ) ) 
                {
                SetOwnership( aTsyReqHandle );
    
                if ( KErrNone == ret )
                    {
                    SetDialTypeId( KMultimodeCallTypeIDNoFdnCheck );
                    
TFLOGSTRING("TSY: CMmDataCallTsy::DialNoFdnCheck - DialDataCall");
                    TRAP( trapError,
                        ret = iMmCallExtInterface->DialDataCallL(
                            iCallMode, aCallParams, aTelNumber );
                        );
                    if ( KErrNone != trapError )
                        {
                        //error handling. DialDataCall() leaved.
                        ret = trapError;
                        }
                    // If dial succeeded, continue
                    if ( KErrNone == ret )
                        {
                        RPhone::TStatus modemStatus;
                        modemStatus.iModemDetected = RPhone::EDetectedPresent;
                        modemStatus.iMode = RPhone::EModeEstablishingLink;
                        iMmPhone->CompleteNotifyModemDetected( modemStatus );
    
                        //update core status
                        iCallCaps.iFlags &= ~(
                            RCall::KCapsDial | RCall::KCapsConnect );
                        iCallCaps.iFlags |= RCall::KCapsHangUp;
                        //complete core caps change
                        CompleteNotifyCapsChange();
                        }
                    }
                }
    
            if ( KErrNone != ret )
                {
                ReqCompleted( aTsyReqHandle, ret );
                ClearCallStatus();
                }
            else
                {
#ifdef REQHANDLE_TIMER
                // set timer for the request
                SetTypeOfResponse( EMultimodeCallDialNoFdnCheck,
                		aTsyReqHandle );
#else
                // set timer
                iTsyReqHandleStore->SetTsyReqHandle(
                    EMultimodeCallDialNoFdnCheck, aTsyReqHandle );
#endif
                }
            }
    
        return KErrNone;
        } 
    else
        {
        return KErrServerBusy;
        }  	
    }

// ---------------------------------------------------------------------------
// CMmDataCallTsy::CompleteDialNoFdn
// Completes a Dial request.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::CompleteDialNoFdn(
    TInt aResult )
    {
TFLOGSTRING2("TSY: CMmDataCallTsy::CompleteDialNoFdn - Result: %d", aResult ); 
TFLOGSTRING3("TSY: CMmDataCallTsy::CompleteDialNoFdn - Call Id: %d, Call name: %S",
    iCallId, &iCallName);
    
    // Set dial flag to false
    SetDialFlag( EFalse );
    
    // reset req handle. Returns the deleted req handle
    TTsyReqHandle reqHandle = iTsyReqHandleStore->ResetTsyReqHandle(
        EMultimodeCallDialNoFdnCheck );

    if ( EMultimodeCallReqHandleUnknown != reqHandle )
        {
        if ( aResult != KErrNone )
            {
            // The creation has failed.
            iLastExitCode = aResult;
            ClearCallStatus();

            //Dial has failed, update core status - dial possible again
            iCallCaps.iFlags |= RCall::KCapsDial;
            iCallCaps.iFlags &= ~( RCall::KCapsHangUp );

            //complete caps change notification
            CompleteNotifyCapsChange();
            }
TFLOGSTRING2("TSY: CMmDataCallTsy::CompleteDialNoFdn before ReqComplete %d", aResult );
        ReqCompleted( reqHandle, aResult );

TFLOGSTRING("TSY: CMmDataCallTsy::CompleteDialNoFdn - set dialtype to none ");
	    //Set dial type to none 
	    SetDialTypeId( KMultimodeCallTypeDialNone );
        }

    // Set also new call caps to enable dataport loaning!
    if ( RCall::EStatusConnected == iCallStatus &&
         KErrNone == aResult )
        {
        iCallCaps.iFlags |= RCall::KCapsLoanDataPort;
        iMmCallExtInterface->AddGSMCallCaps(
            RCall::KCapsLoanDataPort );

        //complete caps change notification
        CompleteNotifyCapsChange();
        CompleteNotifyMobileCallCapsChange( KErrNone );
        }
    }

#ifdef TF_LOGGING_ENABLED
// ---------------------------------------------------------------------------
// CMmCallTsy::ReqCompleted
// Overloads CTelObject::ReqCompleted for logging purposes. It prints the 
// aTsyReqHandle and aError variable in the log file and then calls 
// CTelObject::ReqCompleted.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmDataCallTsy::ReqCompleted(
    const TTsyReqHandle aTsyReqHandle,
    const TInt aError )
    {
    //Overloads CTelObject::ReqCompleted for logging purposes. It 
    //prints the aTsyReqHandle and aError variable in the log file and then 
    //calls CTelObject::ReqCompleted.
TFLOGSTRING3("TSY: CMmDataCallTsy::Request Completed. Handle:%d Error:%d", aTsyReqHandle, aError); 

    CTelObject::ReqCompleted(aTsyReqHandle,aError);
    }
#endif

//  End of File  
