diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/common_tsy/commontsy/src/mmtsy/cmmdatacalltsy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telephonyserverplugins/common_tsy/commontsy/src/mmtsy/cmmdatacalltsy.cpp Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,3236 @@ +// 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 +#include +#include "cmmcallgsmwcdmaext.h" +#include + + +// ======== 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(dataPtr) ); + break; + // Notify Call Status Change + case EMobileCallNotifyMobileCallStatusChange: + ret = NotifyMobileCallStatusChange( + reinterpret_cast(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( 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( + 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(dataPtr), + reinterpret_cast( + dataPtr2) ); + break; + // High Speed Circuit Switched Data (HCSCD) + // Set Dynamic HSCSD Call Parameters + case EMobileCallSetDynamicHscsdParams: + ret = SetDynamicHscsdParams( aTsyReqHandle, + reinterpret_cast(dataPtr), + reinterpret_cast(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(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( 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(); + 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( + 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( + 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( + 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( + const_cast( 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( + 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; + } + + 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(const_cast (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(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 ( 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( 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( 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( + 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( + 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( + const_cast( 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( + 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