// 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 "cmmfaxcalltsy.h"
#include "cmmfaxlinetsy.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 "CMmFaxExtInterface.h" 
#include "cmmcallgsmwcdmaext.h"

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

CMmFaxCallTsy::CMmFaxCallTsy()
    {
    }

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

    CMmFaxCallTsy* mmCall = NULL;

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

    return mmCall;
    }

CMmFaxCallTsy::~CMmFaxCallTsy()
    {
    TFLOGSTRING3("TSY: CMmFaxCallTsy::~CMmFaxCallTsy. 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 assert that call object recovers dataport
    // if it is loaned.
    CCallBase::SetUnowned();

    // delete Internal Fax call extension object.
    if ( iMmFaxExt )
        {
        delete iMmFaxExt;
        }
    iMmFaxExt = NULL;

    // 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();;
        }
        
    // If this is iLastIncomingFaxCall, set iLastIncomingFaxCall
    // of CMmFaxLineTsy to NULL
    if ( this == (reinterpret_cast<CMmFaxLineTsy*>(iMmLine))->iLastIncomingFaxCall )
    	{
        reinterpret_cast<CMmFaxLineTsy*>(iMmLine)->ResetLastIncomingCall();
    	}
    }


// ---------------------------------------------------------------------------
// CMmFaxCallTsy::InitExtensionModulesL
// Initialises extension modules for CMmFaxCallTsy
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
void CMmFaxCallTsy::InitExtensionModulesL(
    RMobilePhone::TMobileService aMode )
    {
    CMmCallTsy::InitExtensionModulesL( aMode );

    // Create internal fax call object if this is fax call
    // TODO: what to do when this is faxmodem fax call??
    if ( aMode == RMobilePhone::EFaxService )
        {
        // Internal Fax call extension object creation.
        iMmFaxExt = CMmFaxExtInterface::NewL( this );
        }
    else
        {
        iMmFaxExt = NULL;
        }
    }

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

    iCallCaps.iFlags = RCall::KCapsFax | 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;

    //dataport params
    iLoanedCommPort.iCsy.Zero();
    iLoanedCommPort.iPort.Zero();;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::OpenNewObjectByNameL
// Creates new Fax object and returns a pointer to it.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
CTelObject* CMmFaxCallTsy::OpenNewObjectByNameL(    
    const TDesC& aName )
    {
    CTelObject* telObject = NULL;

    // iMmFaxExt is non null if fax calls are supported
    if ( iMmFaxExt )
        {
        telObject = iMmFaxExt->OpenNewObjectByNameL(aName);
        }
    else
        {
        //Not supported
        User::Leave( KErrNotSupported );
        }

    return telObject;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::DoExtFuncL(
    const TTsyReqHandle aTsyReqHandle,
    const TInt aIpc,
    const TDataPackage& aPackage )
    {
    TFLOGSTRING3("TSY: CMmFaxCallTsy::DoExtFuncL. IPC:%d Handle:%d", aIpc, 
        aTsyReqHandle);

    TInt ret( KErrNone );

    TAny* dataPtr = aPackage.Ptr1();

    // 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;
        // 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;
        // Order to notify if privacy is confirmed
        case EMobileCallNotifyPrivacyConfirmation:
            ret = NotifyPrivacyConfirmation(
              reinterpret_cast<RMobilePhone::TMobilePhonePrivacy*>(
                dataPtr ) );
            break;
        // Unsupported features
        case EMobileCallDialEmergencyCall:
        case EMobileCallHold:
        case EMobileCallResume:
        case EMobileCallSwap:
        case EMobileCallGoOneToOne:
        case EMobileCallGetMobileDataCallCaps: 
        case EMobileCallNotifyMobileDataCallCapsChange: 
        case EMobileCallGetMobileDataCallRLPRange:
        case EMobileCallSetDynamicHscsdParams:
        case EMobileCallGetCurrentHscsdInfo:
        case EMobileCallNotifyHscsdInfoChange:
        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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::ReqModeL(
    const TInt aIpc )
    {
    TFLOGSTRING2("TSY: CMmFaxCallTsy::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 DOS 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 DOS 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:
            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 at all
        //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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::CancelService(
    const TInt aIpc,
    const TTsyReqHandle aTsyReqHandle )
    {
    TFLOGSTRING3("TSY: CMmFaxCallTsy::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 EMobileCallHold:
        case EMobileCallResume:
        case EMobileCallSwap:
        case EMobileCallGoOneToOne:
        case EMobileCallDeflect:
        case EMobileCallTransfer:
        case EMobileCallNotifyTrafficChannelConfirmation:
            break;
        //Cancel methods that are not supported
        case EMobileCallDialEmergencyCall:

        case EMobileCallSetDynamicHscsdParams:
        case EMobileCallNotifyMobileDataCallCapsChange:
        case EMobileCallNotifyHscsdInfoChange:

        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 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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::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 );
        CMmFaxCallTsy* mmCall = NULL; 
        RMobileCall::TMobileCallStatus callStatus( RMobileCall::EStatusIdle );
        CCallDataPackage* callDataPackage = 
            reinterpret_cast<CCallDataPackage*>(aDataPackage);

        callDataPackage->UnPackData( callStatus );

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

        switch( callStatus )
            {
            case RMobileCall::EStatusIdle:
                //reset caps. 
                iCallCaps.iFlags &= ~(
                    RCall::KCapsHangUp | RCall::KCapsAnswer );
                iCallCaps.iFlags |= RCall::KCapsDial;

                //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();
                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 );
                    }
                // 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 );
                    CompleteHangUp( errorValue );
                    if ( this != iMmPhone->WaitingCallForData() )
                        {
                        CompleteAnswerIncomingCall( errorValue );
                        }
                    }
                //save last id. Required by Conference call implementation
                SetPreviousCallId( iCallId );
                //reset call id
                iCallId = -1;

                //Check if call capability KCapsHangup still exists
                //If it does, remove it and return the KCapsDial capability.
                //If call mode is data, then return also KCapsConnect 
                //capability
                if ( RCall::KCapsHangUp == 
                    ( iCallCaps.iFlags & RCall::KCapsHangUp ) )
                    {
                    // Remove KCapsHangUp if it exists
                    iCallCaps.iFlags &= ~( RCall::KCapsHangUp );
                    // return the KCapsDial capability.
                    iCallCaps.iFlags |= RCall::KCapsDial;

                    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 );
                #endif
                iCallStatus = RCall::EStatusDialling;
                iMobileCallStatus = RMobileCall::EStatusDialling;
                statusChanged = ETrue;
                if ( iDialCancelFlag != CMmCallTsy::EDialCancelNotCalled )
                    {
                    TTsyReqHandle dialCancelHandle = iTsyReqHandleStore->
                        GetTsyReqHandle( EMultimodeCallDial );

                    if ( 0 < dialCancelHandle )
                        {
                        HangUp( dialCancelHandle );
                        } 
                    else
                        {
                        iDialCancelFlag = CMmCallTsy::EDialCancelNotCalled;
                        }
                    }
                break;
            case RMobileCall::EStatusConnecting:
                iCallStatus = RCall::EStatusConnecting;
                iMobileCallStatus = RMobileCall::EStatusConnecting;
                statusChanged = ETrue;
                break;
            case RMobileCall::EStatusRinging:
                // If mode is fax call, there is a chance that call mode is 
                //already ringing
                if (RCall::EStatusRinging != iCallStatus ||
                    RMobileCall::EStatusRinging != iMobileCallStatus)
                    {
                    iCallStatus = RCall::EStatusRinging;
                    iMobileCallStatus = RMobileCall::EStatusRinging;
                    statusChanged = ETrue;
                    }
                break;
            case RMobileCall::EStatusAnswering:
                iCallStatus = RCall::EStatusAnswering;
                iMobileCallStatus = RMobileCall::EStatusAnswering;
                statusChanged = ETrue;

                CompleteAnswerIncomingCall( aResult );
                break;
            case RMobileCall::EStatusConnected:
                //check previous status. If status is answering
                if ( RCall::EStatusAnswering == iCallStatus )
                    {
                    //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 );

                    //Set last exit code
                    if ( KErrGsmReleaseByUser == aResult ||
                        KErrGsmBusyUserRequest == aResult ||
                        KErrGsmCCNormalUnspecified == extendedError ||
                        KErrNone == aResult )
                        {
                        iLastExitCode = KErrNone;
                        }
                    else
                        {
                        //set last exit code
                        iLastExitCode = aResult;
                        }
                    }
                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 );

                //Set last exit code
                if ( KErrGsmReleaseByUser == aResult ||
                    KErrGsmBusyUserRequest == aResult ||
                    KErrGsmCCNormalUnspecified == extendedError ||
                    KErrNone == aResult )
                    {
                    iLastExitCode = KErrNone;
                    }
                else
                    {
                    //set last exit code
                    iLastExitCode = aResult;
                    }
                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 );
            }

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

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::Dial
// This CORE API method dials to the given number.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::Dial(
    const TTsyReqHandle aTsyReqHandle,
    const TDesC8* aCallParams,
    TDesC* aTelNumber )
    {
    TFLOGSTRING3("TSY: CMmFaxCallTsy::Dial. 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 )
	{
	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: CMmFaxCallTsy::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: CMmFaxCallTsy::Dial - KErrServerBusy");
        ReqCompleted( aTsyReqHandle, KErrServerBusy );
        }
    else
        {
        TInt ret( KErrNone );

        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;

        // if fax extension is loaded do a fax call, otherwise return not supported
        if (iMmFaxExt)
            {
            // Check if there already is an active or connecting call
            TInt numberOfObjects = iMmPhone->CallList()->
                GetNumberOfObjects();
            for ( TInt i = 0; i < numberOfObjects; i++ )
                {
                CMmCallTsy* mmCall = iMmPhone->CallList()->
                    GetMmCallByIndex( i );
                if ( !( RMobileCall::EStatusUnknown == 
                            mmCall->MobileCallStatus() ||
                        RMobileCall::EStatusIdle == 
                            mmCall->MobileCallStatus() ||
                        RMobileCall::EStatusDisconnecting == 
                            mmCall->MobileCallStatus() ||
                        RMobileCall::EStatusDisconnectingWithInband == 
                            mmCall->MobileCallStatus() ) )
                    {
                    ret = KErrEtelCallAlreadyActive;
                    break;
                    }
                }

            if ( KErrNone == ret )
                {
                ret = iMmFaxExt->Dial(aTsyReqHandle, aTelNumber);
                }
            }
        else
            {
            ret = KErrNotSupported;
            }

        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;
    }

	
// ---------------------------------------------------------------------------
// CMmFaxCallTsy::DialCancel
// This CORE API method cancels an outstanding dial request.Calls HangUp 
// method to do this and set a flag so that we can know that DialCancel 
// handling is going on.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::DialCancel(
    const TTsyReqHandle aTsyReqHandle )
    {
    TFLOGSTRING3("TSY: CMmFaxCallTsy::DialCancel. Req handle: %d, Call name: %S", 
        aTsyReqHandle, &iCallName);

    TInt ret( KErrGeneral );

    if (iMmFaxExt)
        {
        iMmFaxExt->DialCancel();
        // ingnore dialcancel for internal fax call
        return KErrNone;
        }

    ret = CMmCallTsy::DialCancel( aTsyReqHandle );

    return ret;
    }

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

    TTsyReqHandle iAnswerCallHandle = iTsyReqHandleStore->
        GetTsyReqHandle( EMultimodeCallAnswer );

    if ( 0 < iAnswerCallHandle )
        {
        //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 ( iMmFaxExt )
            {
            // internal fax call...
            ret = iMmFaxExt->AnswerIncomingCall( aTsyReqHandle );
            }
        else
            {
            // FaxModemMode should send the ATA command itself,
            // not call answer from TSY!
            // fax receive case comes here...
            ret = KErrNotSupported;
            }

        //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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 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 
// AnswerIncomingCall() acknowledgemnt and when it receives it, the TSY will 
// complete the original AnswerIncomingCall request.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::AnswerIncomingCallCancel(
    const TTsyReqHandle )
    {
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::HangUp(
    const TTsyReqHandle aTsyReqHandle )
    {
    TFLOGSTRING3("TSY: CMmFaxCallTsy::HangUp. Req handle: %d, Call name: %S", 
        aTsyReqHandle, &iCallName);

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

    TTsyReqHandle hangUpHandle = iTsyReqHandleStore->
        GetTsyReqHandle( EMultimodeCallHangUp );
    TTsyReqHandle dialHandle = iTsyReqHandleStore->
        GetTsyReqHandle( EMultimodeCallDial );
            
    if ( 0 < hangUpHandle )
        {
        //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 if ( RCall::EStatusIdle == iCallStatus && 
        EMultimodeCallReqHandleUnknown == dialHandle )
        {
        //Call object is already in idle state.
        //Complete HangUp request with error.
        ReqCompleted( aTsyReqHandle, KErrNotReady );
        }
    else
        {
        //if this was not called by DialCancel
        if ( CMmCallTsy::EDialCancelNotCalled == iDialCancelFlag ) 
            {
#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: CMmFaxCallTsy::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 ) )
            {
            if ( iMmFaxExt != NULL )
                {
                // internal fax hangup handling
                iMmFaxExt->HangUp();
                }
            }
        // 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 )
            {
            //in case of memory error
            if ( KErrNone != trapError )
                {
                // Object cannot be created.
                ret = trapError;
                }
            else
                {
                //Create package
                CCallDataPackage package;
                //Set call id and call mode
                package.SetCallIdAndMode( iCallId, iCallMode );
                
                TBool autoStChangeDisable = EFalse;
                //Pack call parameters and mobile call info
                package.PackData( &hangUpCause, &autoStChangeDisable );
                //Send request to the Domestic OS layer.
                TRAP(trapError,
                    ret = iMessageManager->HandleRequestL(
                        EEtelCallHangUp,  &package );
                    );
                }

            //send failure
            if ( KErrNone != ret || KErrNone != trapError )
                {
                iTsyReqHandleStore->ResetTsyReqHandle( EMultimodeCallHangUp );

                //in case of memory error
                if ( KErrNone != trapError )
                    {
                    // Object cannot be created.
                    ret = trapError;
                    }

                ReqCompleted( aTsyReqHandle, ret );
                }
            else
                {
                //update core status - hangup not possible now.
                //remove also dataport caps
                iCallCaps.iFlags &= ~(
                    RCall::KCapsHangUp |
                    RCall::KCapsLoanDataPort | 
                    RCall::KCapsRecoverDataPort );
                //complete core caps change
                CompleteNotifyCapsChange();
                }
            }
        }

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::GetOwnershipStatus
// Get call ownership status.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::TransferOwnership
// Transfers the call ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::AcquireOwnership
// Acquire the call ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::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 )
            {
            // Object cannot be created.
            ReqCompleted( aTsyReqHandle, trapError );
            }
        else if ( NULL != entry )
            {
            iList->iAcquireList.AddLast( *entry );
            }
        }

    return KErrNone;
    }

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

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::RelinquishOwnership
// Relinquish the call ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::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;
    }

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

#ifdef REQHANDLE_TIMER
// ---------------------------------------------------------------------------
// CMmFaxCallTsy::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 CMmFaxCallTsy::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 DOS in a specified time.
    TInt timeOut( 0 );

    //example switch
    switch ( aReqHandleType )
        {
        case EMultimodeCallDial:
            timeOut = KMmCallDialTimeOut;
            break;
        case EMultimodeCallAnswer:
            timeOut = KMmCallAnswerTimeOut;
            break;
        case EMultimodeCallHangUp:
            timeOut = KMmCallHangUpTimeOut;
            break;
        case EMultimodeCallTransfer: 
            timeOut = KMmCallTransferTimeOut;
            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:

        case EMultimodeCallSetDynamicHscsdParams:  

        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 );
        }
    }
#endif

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

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::LoanDataPort
// This CORE API method loans dataport to client.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::LoanDataPort(
    const TTsyReqHandle aTsyReqHandle,
    RCall::TCommPort* aCommPort )
    {
TFLOGSTRING2("TSY: CMmFaxCallTsy::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
        {
        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;    
    }

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

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::RecoverDataPort
// This CORE API method recovers dataport from client.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::RecoverDataPort(
    const TTsyReqHandle aTsyReqHandle )
    {
TFLOGSTRING2("TSY: CMmFaxCallTsy::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;
        }

    ReqCompleted( aTsyReqHandle, ret );

    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::RecoverDataPortAndRelinquishOwnership
// Recovers dataport from client and relinquishes ownership.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::RecoverDataPortAndRelinquishOwnership()
    {
TFLOGSTRING2("TSY: CMmFaxCallTsy::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 fax 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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::Connect
// Set correct data call attributes, depending on parameter extension.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::Connect(
    const TTsyReqHandle aTsyReqHandle,
    const TDesC8* aCallParams )
    {
    TInt ret(KErrArgument);
    
    if(sizeof(RMobileCall::TMobileCallParamsV1) <= aCallParams->Length())
       	{
       	ret = KErrNone;
       	
        if ( CheckOwnership( aTsyReqHandle ) == CCallBase::EOwnedUnowned )
            {
            SetOwnership( aTsyReqHandle );
            }

        RMobileCall::TMobileCallParamsV1Pckg* paramsPckgV1 = 
            reinterpret_cast<RMobileCall::TMobileCallParamsV1Pckg*>(
                const_cast<TDesC8*>( aCallParams ) );
        RMobileCall::TMobileCallParamsV1& paramsV1 = ( *paramsPckgV1 )();

        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 ret;
    }

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

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::GetBearerServiceInfo
// Get bearer service info.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::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;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::GetFaxSettings
// This CORE API method is used for getting fax settings.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::GetFaxSettings(
    const TTsyReqHandle aTsyReqHandle,
    RCall::TFaxSessionSettings* aSettings )
    {
    TInt errorCode ( KErrNotSupported );

    if ( iMmFaxExt )
        {
        // if fax is supported, handle this request
        errorCode = iMmFaxExt->GetFaxSettings( aSettings );
        }

    ReqCompleted( aTsyReqHandle, errorCode );
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CMmFaxCallTsy::SetFaxSettings
// This CORE API method is used for set fax settings.
// (other items were commented in a header).
// ---------------------------------------------------------------------------
//
TInt CMmFaxCallTsy::SetFaxSettings(
    const TTsyReqHandle aTsyReqHandle,
    const RCall::TFaxSessionSettings* aSettings )
    {
    TInt errorCode(KErrNotSupported);

    if ( iMmFaxExt )
        {
        // if fax is supported, handle this request
        errorCode = iMmFaxExt->SetFaxSettings( aSettings );
        }

    ReqCompleted( aTsyReqHandle, errorCode );

    return KErrNone;
    }

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

    return KErrNone;
    }


//  End of File  
