diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/simtsy/src/CSimVoiceCall.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telephonyserverplugins/simtsy/src/CSimVoiceCall.cpp Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,1171 @@ +// Copyright (c) 2001-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: +// This file contains the implementation of the Simulator TSY Voice Call functionality. +// The Call classes process the Call-based requests made by ETel clients +// and passed down to the TSY by the ETel Server. +// +// + +/** + @file +*/ + +#include + +#include "CSimVoiceCall.h" +#include "CSimPhone.h" +#include "CSimDtmf.h" +#include "Simlog.h" +#include "CSimTsyMode.h" + +CSimVoiceCall* CSimVoiceCall::NewL(CSimLine* aLine,const TDesC& aName, CSimPhone* aPhone) +/** +* Standard two phase constructor. +* +* @param aLine pointer to the Line object. +* @param aName name of the call to be constructed +* @return CSimVoiceCall pointer to the voice call object created +* @leave Leaves if no memory or object is not created for any reason +*/ + { + CSimVoiceCall* voiceCall=new(ELeave) CSimVoiceCall(aLine,aName,aPhone); + TCleanupItem newCallVoiceClose(CloseCall,voiceCall); + CleanupStack::PushL(newCallVoiceClose); + voiceCall->ConstructL(); + CleanupStack::Pop(); + return voiceCall; + } + +CSimVoiceCall::CSimVoiceCall(CSimLine* aLine,const TDesC& aName, CSimPhone* aPhone) + : CSimCall(aLine,aName,aPhone) +/** +* Trivial constructor. Calls CSimCall to initialise its members +*/ + { + } + +void CSimVoiceCall::ConstructL() +/** +* Second phase of 2-Phase Constructor +* Retrieves all the pausing duration tags from the config file +* +* @param aName name of the voice call to be constructed +*/ + { + LOGVOICE1("Starting to parse Voice Call config parameters..."); + iCaps=Caps(); + iDiallingPause=iLine->CfgFile()->ItemValue(KDiallingPauseDuration,KDefaultDiallingPauseDuration); + iConnectingPause=iLine->CfgFile()->ItemValue(KConnectingPauseDuration,KDefaultConnectingPauseDuration); + iDisconnectingPause=iLine->CfgFile()->ItemValue(KDisconnectingPauseDuration,KDefaultDisconnectingPauseDuration); + iAnswerIncomingPause=iLine->CfgFile()->ItemValue(KAnswerIncomingPauseDuration,KDefaultAnswerIncomingPauseDuration); + iRemoteHangupPause=iLine->CfgFile()->ItemValue(KRemoteHangupPauseDuration,KDefaultRemoteHangupPauseDuration); + + iTimer=CSimTimer::NewL(iLine->iPhone); + CSimCall::ConstructL(); + + //If present read in remote party info tag + TPtrC8 callingname, remotenumber; + TInt delay=0; + const CTestConfigItem* item=NULL; + item=iLine->CfgFile()->Item(KNotifyRemotePartyInfo); + TInt ret; + if (item) + { + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,delay); + if(ret!=KErrNone) + { + LOGPARSERR("delay",ret,0,&KNotifyRemotePartyInfo); + } + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,callingname); + if(ret!=KErrNone) + { + LOGPARSERR("callingname",ret,1,&KNotifyRemotePartyInfo); + } + ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,remotenumber); + if(ret!=KErrNone) + { + LOGPARSERR("remotenumber",ret,2,&KNotifyRemotePartyInfo); + } + + iNotifyRemotePartyInfoTimer->iDelay = delay; + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EDirectionUnknown; + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iCallingName.Copy(callingname); + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iTelNumber.Copy(remotenumber); + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iTypeOfNumber = RMobilePhone::EInternationalNumber; + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iNumberPlan = RMobilePhone::EIsdnNumberPlan; + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus = RMobileCall::ERemoteIdentityAvailable; + } + else + { + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus = RMobileCall::ERemoteIdentityUnknown; + } + + LOGVOICE1("...Finished parsing Voice Call config parameters..."); + } + +CSimVoiceCall::~CSimVoiceCall() +/** +* Destroy all the objects constructed. +* CSimTimer and CSimSysAgent objects are destroyed here +*/ + { + delete iTimer; + if(iAnswerIncomingCall.iNotifyPending) + iLine->ResetAutoAnswerCallObject(this); + } + +TInt CSimVoiceCall::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc,const TDataPackage& aPackage) +/** +* ExtFunc is called by the server when it has a "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 +* +* @param aTsyReqHandle +* @param aIpc IPc number representing the request +* @param aPackage data for the request +* @return KErrNone +*/ + { + TAny* dataPtr=aPackage.Ptr1(); + + // The request data has to extracted from TDataPackage and the TAny* pointers have to + // be "cast" to the expected request data type + + switch (aIpc) + { + // + // No Flow Control NOR Multiple Completion + // + case EMobileCallGetMobileCallCaps: + return GetMobileCallCaps(aTsyReqHandle,aPackage.Des1n()); + + case EMobileCallGetMobileCallStatus: + return GetMobileCallStatus(aTsyReqHandle, + REINTERPRET_CAST(RMobileCall::TMobileCallStatus*,dataPtr)); + + case EMobileCallGetMobileCallInfo: + return GetMobileCallInfo(aTsyReqHandle,aPackage.Des1n()); + + case EMobileCallDialEmergencyCall: + return DialEmergencyCall(aTsyReqHandle,aPackage.Des1u()); + + case EMobileCallHold: + return Hold(aTsyReqHandle); + + case EMobileCallResume: + return Resume(aTsyReqHandle); + + case EMobileCallSwap: + return Swap(aTsyReqHandle); + + case EMobileCallDialISV: + return DialISV(aTsyReqHandle, aPackage.Des1n(), aPackage.Des2u()); + + case EMobileCallAnswerISV: + TInt retVal; + TRAPD(errVal, retVal=AnswerIncomingCallISVL(aTsyReqHandle, aPackage.Des1n())); + if (errVal != KErrNone) + { + return errVal; + } + else + { + return retVal; + } + + // + // Multiple Completion Services with Immediate Server Repost + // (Usually Notifications) + // + case EMobileCallNotifyMobileCallStatusChange: + return NotifyMobileCallStatusChange(aTsyReqHandle, + REINTERPRET_CAST(RMobileCall::TMobileCallStatus*, dataPtr)); + + case EMobileCallNotifyMobileCallCapsChange: + return NotifyMobileCallCapsChange(aTsyReqHandle, aPackage.Des1n()); + + case EMobileCallNotifyRemotePartyInfoChange: + return NotifyRemotePartyInfoChange(aTsyReqHandle, aPackage.Des1n()); + + default: + break; + } + return KErrNotSupported; + } + +TInt CSimVoiceCall::CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle) +/** + * Cancel an outstanding request. + * @param aIpc The IPC number of the request that must be cancelled. Note: this is not the + * IPC number of the cancel request itself. + * @param aTsyReqHandle The TSY Request Handle of the request to be cancelled. + */ + { + switch(aIpc) + { + case EMobileCallNotifyMobileCallStatusChange: + return NotifyMobileCallStatusChangeCancel(aTsyReqHandle); + + case EMobileCallNotifyMobileCallCapsChange: + return NotifyMobileCallCapsChangeCancel(aTsyReqHandle); + + case EMobileCallDialEmergencyCall: + return DialEmergencyCallCancel(aTsyReqHandle); + + case EMobileCallHold: + return HoldCancel(aTsyReqHandle); + + case EMobileCallResume: + return ResumeCancel(aTsyReqHandle); + + case EMobileCallSwap: + return SwapCancel(aTsyReqHandle); + + case EMobileCallNotifyRemotePartyInfoChange: + return NotifyRemotePartyInfoChangeCancel(); + + case EMobileCallDialISV: + return DialISVCancel(aTsyReqHandle); + + case EMobileCallAnswerISV: + return AnswerIncomingCallISVCancel(aTsyReqHandle); + default: + break; + } + + return CCallBase::CancelService(aIpc,aTsyReqHandle); + } + +TInt CSimVoiceCall::DialEmergencyCall(const TTsyReqHandle aTsyReqHandle,TDesC* aTelNumber) +/** +* Process a client's emergency call request. +* +* @param aTsyReqHandle +* @param aTelNumber The telephone number to dial +* @return KErrNone +*/ + { + return Dial(aTsyReqHandle,NULL,aTelNumber); + } + +TInt CSimVoiceCall::DialEmergencyCallCancel(const TTsyReqHandle aTsyReqHandle) +/** +* Cancels an emergency call request. +* +* @param aTsyReqHandle +* @return KErrNone if successfully cancelled +*/ + { + return DialCancel(aTsyReqHandle); + } + +TInt CSimVoiceCall::Dial(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* /*aTelNumber*/) +/** +* Process a client's dial request. +* +* @param aTsyReqHandle +* @param aCallParams the call parameters +* @param aTelNumber The telephone number to dial +* @return KErrNone +*/ + { + LOGVOICE1(">>CSimVoiceCall::Dial"); + // Note: The telephone number and call parameters should be validated against config file + // values here. + + //see where the dial request has orignated from + if(aCallParams) + { + RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast(const_cast(aCallParams)); + RCall::TCallParams& callparams=(*callparamsPckg)(); + + if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) + { + LOGVOICE1("<>CSimVoiceCall::DialCancel"); + switch(iState) + { + case RMobileCall::EStatusIdle: + SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. + break; + + case RMobileCall::EStatusDialling: + case RMobileCall::EStatusConnecting: + iTimer->DoCancel(); + // Can ignore for cancel + TInt err; + err = KErrNone; + TRAP(err, (void)ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse)); + if (err != KErrNone) + { + ReqCompleted(iDialRequestHandle, err); + } + else + { + ReqCompleted(iDialRequestHandle, KErrCancel); + } + break; + + case RMobileCall::EStatusConnected: + SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. + break; + + default: + break; + } + LOGVOICE1("<>CSimVoiceCall::DialISV"); + // Note: The telephone number and call parameters should be validated against config file + // values here. + + //see where the dial request has orignated from + if(aCallParams) + { + RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast(const_cast(aCallParams)); + RCall::TCallParams& callparams=(*callparamsPckg)(); + + if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) + { + LOGVOICE1("<>CSimVoiceCall::DialISVCancel"); + switch(iState) + { + case RMobileCall::EStatusIdle: + SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. + break; + + case RMobileCall::EStatusDialling: + case RMobileCall::EStatusConnecting: + iTimer->DoCancel(); + // Can ignore for cancel + TInt err; + err = KErrNone; + TRAP(err, (void)ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse)); + if (err != KErrNone) + { + ReqCompleted(iDialRequestHandle, err); + } + else + { + ReqCompleted(iDialRequestHandle, KErrCancel); + } + break; + + case RMobileCall::EStatusConnected: + SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. + break; + + default: + break; + } + LOGVOICE1("<>CSimVoiceCall::AnswerIncomingCall 0x%08x, state %d entry ",this,iState); + + //see where the answer request has orignated from + if(aCallParams) + { + RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast(const_cast(aCallParams)); + RCall::TCallParams& callparams=(*callparamsPckg)(); + + if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) + { + LOGVOICE1("<SetAutoAnswerCallObject(this); + if(ret!=KErrNone) + { + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + + iAnswerIncomingCall.iNotifyPending=ETrue; + iAnswerIncomingCall.iNotifyHandle=aTsyReqHandle; + + if(iState==RMobileCall::EStatusRinging) + ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); + else if(iLine->iState==RMobileCall::EStatusRinging) + { + TRAPD(errVal, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse)); + if (errVal != KErrNone) + { + ret = errVal; + } + + if(ret==KErrNone) + ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); + } + LOGVOICE3("<>CSimVoiceCall::AnswerIncomingCallCancel"); + if(iAnswerIncomingCall.iNotifyPending) + { + iAnswerIncomingCall.iNotifyPending=EFalse; + iLine->ResetAutoAnswerCallObject(this); + ReqCompleted(iAnswerIncomingCall.iNotifyHandle,KErrCancel); + } + LOGVOICE1("<>CSimVoiceCall::AnswerIncomingCallISV 0x%08x, state %d entry ",this,iState); + + //see where the answer request has orignated from + if(aCallParams) + { + RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast(const_cast(aCallParams)); + RCall::TCallParams& callparams=(*callparamsPckg)(); + + if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) + { + LOGVOICE1("<SetAutoAnswerCallObject(this); + if(ret!=KErrNone) + { + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + + iAnswerIncomingCall.iNotifyPending=ETrue; + iAnswerIncomingCall.iNotifyHandle=aTsyReqHandle; + + if(iState==RMobileCall::EStatusRinging) + ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); + else if(iLine->iState==RMobileCall::EStatusRinging) + { + TRAPD(leaveValue, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse)); + if (leaveValue != KErrNone) + { + return leaveValue; + } + + if (ret == KErrNone) + { + ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); + } + } + LOGVOICE3("<>CSimVoiceCall::AnswerIncomingCallISVCancel"); + if(iAnswerIncomingCall.iNotifyPending) + { + iAnswerIncomingCall.iNotifyPending=EFalse; + iLine->ResetAutoAnswerCallObject(this); + ReqCompleted(iAnswerIncomingCall.iNotifyHandle,KErrCancel); + } + LOGVOICE1("<>CSimVoiceCall::HangUp"); + iHangUpRequestHandle=aTsyReqHandle; + TInt ret=ActionEvent(ECallEventHangUp,KErrNone); + if(ret!=KErrNone) + ReqCompleted(aTsyReqHandle,ret); + LOGVOICE1("<>CSimVoiceCall::HangUpCancel"); + switch(iState) + { + case RMobileCall::EStatusIdle: + SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. + break; + + case RMobileCall::EStatusDisconnecting: + iTimer->DoCancel(); + // Can ignore for cancel + TInt err; + err = KErrNone; + TRAP(err, (void)ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse)); + if (err != KErrNone) + { + ReqCompleted(iHangUpRequestHandle, err); + } + else + { + ReqCompleted(iHangUpRequestHandle, KErrCancel); + } + break; + + default: + break; + } + LOGVOICE1("<>CSimVoiceCall::ActionEvent 0x%08x %d",this,iState); + + switch(aEvent) + { + case ECallEventDial: + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventDial]"); + if(iState==RMobileCall::EStatusIdle) + { + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusDialling,EFalse,EFalse)); + if(ret==KErrNone) + iTimer->Start(iDiallingPause,this); + } + else + return KErrEtelCallAlreadyActive; + break; + + case ECallEventHangUp: + { + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventHangUp]"); + switch(iState) + { + case RMobileCall::EStatusDialling: + case RMobileCall::EStatusRinging: + case RMobileCall::EStatusAnswering: + case RMobileCall::EStatusConnecting: + case RMobileCall::EStatusConnected: + case RMobileCall::EStatusHold: + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusDisconnecting,EFalse,EFalse)); + if(ret==KErrNone) + iTimer->Start(iDisconnectingPause,this); + if(iSimDtmf) + { + iSimDtmf->CallClosureCallback(); + iSimDtmf=NULL; + } + break; + default: + return KErrEtelCallNotActive; + } + } + break; + + case ECallEventIncomingCall: + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventIncomingCall]"); + if(iState==RMobileCall::EStatusIdle) + { + if(iAnswerIncomingCall.iNotifyPending) + { + TRAP(ret, ret=ProcessAnswerIncomingCallL()); + } + else + { + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse)); + if(ret!=KErrNone) + return ret; + } + } + else + return KErrEtelCallAlreadyActive; + break; + + case ECallEventAnswerIncoming: + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventAnswerIncoming]"); + if(iState==RMobileCall::EStatusRinging) + { + TRAP(ret, ret=ProcessAnswerIncomingCallL()); + if(ret!=KErrNone) + { + return ret; + } + } + else + SimPanic(EIllegalStateInconsistancy); // This is checked before calling ActionEvent + break; + + case ECallEventRemoteHangup: + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventRemoteHangup]"); + if(iState==RMobileCall::EStatusConnected) + { + TRAP(ret, ret=ProcessRemoteHangupL()); + if(ret!=KErrNone) + { + return ret; + } + } + else + SimPanic(EIllegalStateInconsistancy); // This is checked before calling ActionEvent + break; + + case ECallEventTimeOut: + { + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventTimeOut]"); + switch(iState) + { + case RMobileCall::EStatusDialling: + LOGVOICE1(">>CSimVoiceCall::State = [EStatusDialling]"); + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnecting,EFalse,EFalse)); + if(ret==KErrNone) + iTimer->Start(iConnectingPause,this); + return ret; + + case RMobileCall::EStatusConnecting: + LOGVOICE1(">>CSimVoiceCall::State = [EStatusConnecting]"); + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse)); + UpdateRemotePartyInfoDirection(RMobileCall::EStatusConnecting); + ReqCompleted(iDialRequestHandle,ret); + return ret; + + case RMobileCall::EStatusDisconnecting: + LOGVOICE1(">>CSimVoiceCall::State = [EStatusDisconnecting]"); + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse)); + ReqCompleted(iHangUpRequestHandle,ret); + return ret; + + case RMobileCall::EStatusAnswering: + LOGVOICE1(">>CSimVoiceCall::State = [EStatusAnswering]"); + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse)); + UpdateRemotePartyInfoDirection(RMobileCall::EStatusAnswering); + ReqCompleted(iAnswerIncomingCall.iNotifyHandle,ret); + return ret; + + default: + break; + } + } + break; + case ECallEventHold: + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventHold]"); + __ASSERT_ALWAYS(iState==RMobileCall::EStatusConnected,SimPanic(EIllegalStateInconsistancy)); + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusHold,aOtherArgument == ECallEventSwap,EFalse)); + if (ret == KErrNone) + ReqCompleted(iHoldResumeRequestHandle,ret); + break; + + case ECallEventResume: + LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventResume]"); + __ASSERT_ALWAYS(iState==RMobileCall::EStatusHold,SimPanic(EIllegalStateInconsistancy)); + TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,aOtherArgument == ECallEventSwap,EFalse)); + if (ret == KErrNone) + ReqCompleted(iHoldResumeRequestHandle,ret); + break; + + case ECallEventConnectContinue: + SimPanic(EIllegalVoiceCallEvent); // All other events not legal for voice call. + break; + default: + SimPanic(EIllegalVoiceCallEvent); // All other events not legal for voice call. + break; + } + + return ret; + } + + +void CSimVoiceCall::TimerCallBack(TInt /*aId*/) +/** +* Timer callback function. When the timer goes off, it will call back into this +* function for further processing. +*/ + { + LOGVOICE1(">>CSimVoiceCall::TimerCallBack"); + TInt ret=ActionEvent(ECallEventTimeOut,KErrNone); + __ASSERT_ALWAYS(ret==KErrNone,SimPanic(ETimeOutEventActionFailed)); + LOGVOICE1("<>CSimVoiceCall::ProcessAnswerIncomingCall %d",iState,this); + TInt ret=ChangeStateL(RMobileCall::EStatusAnswering,EFalse,EFalse); + if(ret!=KErrNone) + return ret; + iTimer->Start(iAnswerIncomingPause,this); + iAnswerIncomingCall.iNotifyPending=EFalse; + iLine->ResetAutoAnswerCallObject(this); + LOGVOICE1("<>CSimVoiceCall::ProcessRemoteHangupL %d",iState,this); + TInt ret=ChangeStateL(RMobileCall::EStatusDisconnecting,EFalse,EFalse); + if(ret!=KErrNone) + return ret; + iTimer->Start(iRemoteHangupPause,this); + iLine->ResetRemoteHangupCallObject(this); + LOGVOICE1("<iCalls->Count(); + + while(singleCall && iiCalls->At(i) != this && (iLine->iCalls->At(i)->iState == RMobileCall::EStatusConnected || iLine->iCalls->At(i)->iState == RMobileCall::EStatusHold)) + singleCall = EFalse; + i++; + } + + if (singleCall) + caps |= RMobileCall::KCapsHold; + // Swap capability is applicable to single and multiple call + // scenarios + caps |= RMobileCall::KCapsSwap; + } + else if(iState==RMobileCall::EStatusHold) + { + caps |= RCall::KCapsHangUp; + + TBool otherConnected = EFalse; + TInt count= iLine->iCalls->Count(); + TInt i=0; + while (!otherConnected && iiCalls->At(i) != this && (iLine->iCalls->At(i)->iState == RMobileCall::EStatusConnected || iLine->iCalls->At(i)->iState == RMobileCall::EStatusHold)) + otherConnected = ETrue; + i++; + } + if(otherConnected) + { + caps |= RMobileCall::KCapsSwap; + } + else + { + caps |= RMobileCall::KCapsResume; + caps |= RMobileCall::KCapsSwap; + } + } + else if (iState==RMobileCall::EStatusRinging) + { + if((iLine->IsAnswerCallObjectSpare())) + caps |= RCall::KCapsAnswer; + } + } + else + { + if(iLine->iState==RMobileCall::EStatusIdle || iLine->iState==RMobileCall::EStatusHold) + { + caps |= RCall::KCapsDial; + if((iLine->IsAnswerCallObjectSpare())) + caps |= RCall::KCapsAnswer; + } + else if (iLine->iState==RMobileCall::EStatusRinging) + { + if((iLine->IsAnswerCallObjectSpare())) + caps |= RCall::KCapsAnswer; + } + } + return caps; + } + +void CSimVoiceCall::UpdateRemotePartyInfoDirection(RMobileCall::TMobileCallStatus aPreviousStatus) +/** +Update the direction of the call for the remote party info member +*/ + { + if(iNotifyRemotePartyInfoTimer && iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus != RMobileCall::ERemoteIdentityUnknown) + { + if(aPreviousStatus == RMobileCall::EStatusAnswering) + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EMobileTerminated; + else + iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EMobileOriginated; + } + }