diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/multimodetsy/hayes/CALL.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telephonyserverplugins/multimodetsy/hayes/CALL.CPP Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,2763 @@ +// Copyright (c) 1997-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 +#include "CALL.H" // Header file for this source file +#include "NOTIFY.H" +#include "FAX.H" +#include "ATDIAL.H" +#include "ATANSWER.H" +#include "ATCONNCT.H" +#include "ATHANGUP.H" +#include "ATO.H" +#include "ATNOCARR.H" +#include "LINE.H" +#include "ATINIT.H" +#include "mSLOGGER.H" // for LOGTEXT untilities +#include "ATIO.H" // For CATIO class +#include "PHONE.H" +#include +#include "ATBASE.H" +#include "Matstd.h" // For AT command string constants +#include "set_cbst.h" // for CATSetCBST class +#include "et_struct.h" + +_LIT(KFaxServerName,"FaxSvr.dll"); + + +// +// CAcquireEntry class +// +CAcquireEntry* CAcquireEntry::NewL(const TTsyReqHandle aTsyReqHandle) +// +// Create new request entry +// + { + return new(ELeave) CAcquireEntry(aTsyReqHandle); + } + +CAcquireEntry::CAcquireEntry(const TTsyReqHandle aTsyReqHandle) +// +// Constructor +// + { + iTsyReqHandle=aTsyReqHandle; + } + +CAcquireEntry::~CAcquireEntry() +// +// Destructor +// + {} + +void CAcquireEntry::Deque() +// +// Deque List +// + { + iLink.Deque(); + iLink.iPrev=iLink.iNext=NULL; + } + +CAcquireOwnerList::CAcquireOwnerList() + {} + +CAcquireOwnerList::~CAcquireOwnerList() + {} + +CAcquireOwnerList* CAcquireOwnerList::NewL() +// +// Static function to create new acquire owner list +// + { + CAcquireOwnerList* self=new(ELeave) CAcquireOwnerList(); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CAcquireOwnerList::ConstructL() + { + iAcquireList.SetOffset(_FOFF(CAcquireEntry,iLink)); + } + +CAcquireEntry* CAcquireOwnerList::FindByTsyReqHandle(const TTsyReqHandle aTsyReqHandle) +// +// Searches for client interested in taking ownership of call, by its TsyReqHandle +// + { + CAcquireEntry* entry; + TDblQueIter iter(iAcquireList); + while(entry = iter++, entry!=NULL) + { + if(entry->iTsyReqHandle==aTsyReqHandle) + return entry; + } + return NULL; + } + +void CAcquireOwnerList::Remove(CAcquireEntry* aEntry) + { + aEntry->Deque(); + delete aEntry; + } + +// +// CHeartbeatRunner - periodic class to count seconds from beginning of call +// +CHeartbeatRunner* CHeartbeatRunner::NewL(CCallHayes* aCallHayes,CNotifications* aNotificationStore) + { + CHeartbeatRunner* self=new (ELeave) CHeartbeatRunner(aCallHayes,aNotificationStore); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CHeartbeatRunner::CHeartbeatRunner(CCallHayes* aCallHayes,CNotifications* aNotificationStore) + :iCallHayes(aCallHayes), iNotificationStore(aNotificationStore) + {} + +void CHeartbeatRunner::ConstructL() + { + iHeartbeat=CHeartbeat::NewL(0); // neutral priority + } + +CHeartbeatRunner::~CHeartbeatRunner() + { + if (iHeartbeat != NULL) + iHeartbeat->Cancel(); + delete iHeartbeat; + } + +void CHeartbeatRunner::Start() + { + iStartTime.UniversalTime(); + iHeartbeat->Start(ETwelveOClock,this); + } + +void CHeartbeatRunner::Stop() + { + iHeartbeat->Cancel(); + iTicks=0; + } + +TTimeIntervalSeconds CHeartbeatRunner::CallDuration() const + { + TTimeIntervalSeconds duration(iTicks); + return duration; + } + +// private functions + +void CHeartbeatRunner::Beat() + { + iTicks++; + iNotificationStore->CheckNotification(iCallHayes,ETimePeriodElapsed); + } + +void CHeartbeatRunner::Synchronize() + { + TInt ticksMissed = 0; + TTime desiredTime = iStartTime + TTimeIntervalMicroSeconds(iTicks * KCallTimerInterval); + TTime currentTime; // set current time to now + currentTime.UniversalTime(); + TTimeIntervalMicroSeconds missedTime = currentTime.MicroSecondsFrom(desiredTime); + // Calculate the ticks missed (quickly!) + TInt64 missedTimeInt = missedTime.Int64(); // convert the missed time interval to an Int64 + ticksMissed = I64INT(missedTimeInt / KCallTimerInterval); + // The following loop increments the ticks missed by the same amount, but takes much longer + // while (desiredTime < currentTime) + // { + // desiredTime = desiredTime - TTimeIntervalMicroSeconds(iTickInterval); + // ticksMissed++; + // } + iTicks = iTicks + ticksMissed; + LOGTEXT3(_L8("Heartbeat function synchronising - from %d to %d"),iTicks-ticksMissed,iTicks); + if (ticksMissed!=0) + iNotificationStore->CheckNotification(iCallHayes,ETimePeriodElapsed); + } + +// +// CCallHayes - General Call Functionality +// +void CCallHayes::CloseCall(TAny* aObj) +// +// Utility func for cleanup stack +// + { + ((CObject*)aObj)->Close(); + } + +CCallHayes::CCallHayes(CATIO* aIo,CATInit* aInit,CPhoneGlobals* aPhoneGlobals) + : iPhoneGlobals(aPhoneGlobals),iIo(aIo),iInit(aInit) + {} + +void CCallHayes::ConstructL(const TName& aName) +// +// Initialise Call Information +// + { + LOGTEXT(_L8("Entered CCallHayes::ConstructL()")); + iCallInfo.iCallName = aName; + iCallInfo.iBearerService.iBearerCaps = RCall::KBearerCapsCompressionUnknown | RCall::KBearerCapsProtocolUnknown; + iCallInfo.iBearerService.iBearerSpeed = RCall::EBearerDataUnknown; + iCallInfo.iHookStatus = RCall::EHookStatusOn; + iCallInfo.iClientPanicOccurred = ENoPanicOccurred; + // Read default call preferences from database + GetDefaultCallParams(); + iCallInfo.iLoanedToClient = EFalse; + if (iPhoneGlobals->iPhoneStatus.iLineStatus == RCall::EStatusRinging) + { + iCallInfo.iMobileStatus = RMobileCall::EStatusRinging; + } + else + { + iCallInfo.iMobileStatus = RMobileCall::EStatusIdle; + } + + iQuickInit=CATQuickInit::NewL(iIo,this,iPhoneGlobals); + iWaitForNoCarrier=CATWaitForNoCarrier::NewL(iIo,this,iPhoneGlobals); + iList=CAcquireOwnerList::NewL(); + iCallTimer = CHeartbeatRunner::NewL(this,iPhoneGlobals->iNotificationStore); + LOGTEXT2(_L8("iCallTimer = %x"),iCallTimer); + } + +CCallHayes::~CCallHayes() + { + LOGTEXT(_L8("Entered CCallHayes destructor")); + if (Owner()) + REINTERPRET_CAST(CLineHayes*,Owner())->RemoveCall(this); + iPhoneGlobals->iNotificationStore->RemoveClientFromLastEvents(this); + delete iWaitForNoCarrier; + delete iList; + delete iQuickInit; + delete iCallTimer; + } + +CTelObject::TReqMode CCallHayes::ReqModeL(const TInt aIpc) + { + TReqMode reqMode = CCallBase::ReqModeL(aIpc); + if ((reqMode & KReqModeFlowControlObeyed || aIpc==EEtelCallAnswer) && iPhoneGlobals->iPhoneStatus.iDataPortLoaned) + { + LOGTEXT2(_L8("ReqModeL Leaving with KErrInUse as data port is loaned (aIpc=%d)"),aIpc); + User::Leave(KErrInUse); + } + return reqMode; + } + +TInt CCallHayes::RegisterNotification(const TInt /*aIpc*/) + { + return KErrNone; + } +TInt CCallHayes::DeregisterNotification(const TInt /*aIpc*/) + { + return KErrNone; + } + + +void CCallHayes::Init() +// +// Only CPhoneHayes::Init() is implemented as that is called first +// + {} + + +TInt CCallHayes::NotifyCapsChange(const TTsyReqHandle aTsyReqHandle, RCall::TCaps* aCaps) + { + LOGTEXT(_L8("Call:\tCaps Change Notification lodged")); + iPhoneGlobals->iNotificationStore->RegisterNotification(ECallCaps,aTsyReqHandle,this,aCaps); + return KErrNone; + } + +TInt CCallHayes::NotifyCapsChangeCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("Call:\tCaps Change Notification cancelled")); + iPhoneGlobals->iNotificationStore->RemoveNotification(aTsyReqHandle); + return KErrNone; + } + +TInt CCallHayes::NotifyHookChange(const TTsyReqHandle aTsyReqHandle, RCall::THookStatus* aHookStatus) + { + LOGTEXT(_L8("Call:\tHook Change Notification lodged")); + iPhoneGlobals->iNotificationStore->RegisterNotification(ECallHookChange,aTsyReqHandle,this,aHookStatus); + return KErrNone; + } + +TInt CCallHayes::NotifyHookChangeCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("Call:\tHook Change Notification cancelled")); + iPhoneGlobals->iNotificationStore->RemoveNotification(aTsyReqHandle); + return KErrNone; + } + +TInt CCallHayes::NotifyStatusChange(const TTsyReqHandle aTsyReqHandle,RCall::TStatus* aStatus) + { + LOGTEXT(_L8("Call:\tStatus Change Notification lodged")); + iPhoneGlobals->iNotificationStore->RegisterNotification(ECallStatusChange,aTsyReqHandle,this,aStatus); + return KErrNone; + } + +TInt CCallHayes::NotifyStatusChangeCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("Call:\tStatus Change Notification cancelled")); + iPhoneGlobals->iNotificationStore->RemoveNotification(aTsyReqHandle); + return KErrNone; + } + +TInt CCallHayes::NotifyDurationChange(const TTsyReqHandle aTsyReqHandle,TTimeIntervalSeconds* aTime) + { + LOGTEXT(_L8("Call:\tDuration Change Notification lodged")); + iPhoneGlobals->iNotificationStore->RegisterNotification(ECallDurationChange,aTsyReqHandle,this,aTime); + return KErrNone; + } + +TInt CCallHayes::NotifyDurationChangeCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("Call:\tDuration Change Notification cancelled")); + iPhoneGlobals->iNotificationStore->RemoveNotification(aTsyReqHandle); + return KErrNone; + } + +TInt CCallHayes::GetInfo(const TTsyReqHandle aTsyReqHandle, RCall::TCallInfo* aCallInfo) + { + aCallInfo->iCallName = iCallInfo.iCallName; + aCallInfo->iStatus = GetCoreCallStatus(); + aCallInfo->iHookStatus = iCallInfo.iHookStatus; + aCallInfo->iLineName = Owner()->Name(); + GetCallDuration(aCallInfo->iDuration); + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TInt CCallHayes::GetStatus(const TTsyReqHandle aTsyReqHandle, RCall::TStatus* aCallStatus) + { + LOGTEXT(_L8("Call:\tGetStatus() called")); + *aCallStatus = GetCoreCallStatus(); + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TInt CCallHayes::TransferOwnership(const TTsyReqHandle aTsyReqHandle) +// +// Transfer call ownership +// + { + LOGTEXT(_L8("Call:\tTransferOwnership called")); + if (CheckOwnership(aTsyReqHandle)!=CCallBase::EOwnedTrue) + { + ReqCompleted(aTsyReqHandle,KErrEtelNotCallOwner); + return KErrNone; + } + + if(iList->iAcquireList.IsEmpty()) // no one interested in this call ! + { + ReqCompleted(aTsyReqHandle,KErrEtelNoClientInterestedInThisCall); + return KErrNone; + } + + CAcquireEntry* entry=iList->iAcquireList.First(); + if (entry) // someone interested in this call + { + LOGTEXT(_L8("Call:\tTransferOwnership successful")); + (void)SetOwnership(entry->iTsyReqHandle); + ReqCompleted(entry->iTsyReqHandle,KErrNone); + iList->Remove(entry); + ReqCompleted(aTsyReqHandle,KErrNone); + } + return KErrNone; + } + +TInt CCallHayes::AcquireOwnership(const TTsyReqHandle aTsyReqHandle) +// +// Acquire call Ownership (server has already checked client does not own it) +// If call is unowned and idle, this request is completed with CallNotActive. +// A call must never be owned and idle concurrently. +// + { + LOGTEXT(_L8("Call:\tAcquireOwnership called")); + if (CheckOwnership(aTsyReqHandle)==CCallBase::EOwnedUnowned) + { + LOGTEXT(_L8("Call:\tAcquireOwnership unsuccessful as call is not owned already")); + ReqCompleted(aTsyReqHandle,KErrEtelCallNotActive); + } + else + { + if(iList->iAcquireList.IsEmpty()) + // List is empty. Client is the first one to request ownership of the call. + { + CAcquireEntry* entry=NULL; + TRAPD(err,entry=CAcquireEntry::NewL(aTsyReqHandle)); + if(err==KErrNone) + iList->iAcquireList.AddLast(*entry); + else + return err; + } + else + // List is not empty. Another client has already requested to acquire ownership of the call. + // Only one client can be waiting to acquire ownership at any one time. + return KErrInUse; + } + return KErrNone; + } + +TInt CCallHayes::AcquireOwnershipCancel(const TTsyReqHandle aTsyReqHandle) +// +// Cancel Acquire call Ownership +// + { + CAcquireEntry* entry=iList->FindByTsyReqHandle(aTsyReqHandle); + __ASSERT_ALWAYS(entry!=NULL,Panic(EAcquirerNotFound)); + if (entry != NULL) + { + iList->Remove(entry); + ReqCompleted(aTsyReqHandle, KErrCancel); + } + else + { + ReqCompleted(aTsyReqHandle, KErrNotFound); + } + return KErrNone; + } + +TInt CCallHayes::GetBearerServiceInfo(const TTsyReqHandle aTsyReqHandle,RCall::TBearerService* aBearerService) + { + *aBearerService = iCallInfo.iBearerService; + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TInt CCallHayes::GetCallParams(const TTsyReqHandle aTsyReqHandle, TDes8* aParams) +// +// Call parameters are only set when connecting a call, so there have no meaning when a +// call is not in progress. +// + { + if (RMobileCall::EStatusIdle != iCallInfo.iMobileStatus && + RMobileCall::EStatusUnknown != iCallInfo.iMobileStatus ) + { + TPckg* paramsPckg = (TPckg*)aParams; + RCall::TCallParams& callparams = (*paramsPckg)(); + + // + // Configure basic TCallParams parameters + callparams.iSpeakerControl = iCallInfo.iSpeakerControl; + callparams.iSpeakerVolume = iCallInfo.iSpeakerVolume; + callparams.iInterval = iCallInfo.iInterval; + callparams.iWaitForDialTone = iCallInfo.iWaitForDialTone; + + // + // Configure additional params as required + if(callparams.ExtensionId()==RMobileCall::KETelMobileCallParamsV1) + { + // + // Configure RMobileCall::TMobileCallParamsV1 parameters + RMobileCall::TMobileCallParamsV1Pckg* pckg = (RMobileCall::TMobileCallParamsV1Pckg*)aParams; + RMobileCall::TMobileCallParamsV1& params = (*pckg)(); + params.iIdRestrict=iCallInfo.iCallParams.iIdRestrict; + params.iCug=iCallInfo.iCallParams.iCug; + params.iAutoRedial=iCallInfo.iCallParams.iAutoRedial; + } + else if(callparams.ExtensionId()==RMobileCall::KETelMobileDataCallParamsV1) + { + // + // Configure RMobileCall::TMobileDataCallParamsV1 parameters + RMobileCall::TMobileDataCallParamsV1Pckg* pckg = (RMobileCall::TMobileDataCallParamsV1Pckg*)aParams; + RMobileCall::TMobileDataCallParamsV1& params = (*pckg)(); + params.iService=iCallInfo.iCallParams.iService; + params.iSpeed=iCallInfo.iCallParams.iSpeed; + params.iProtocol=iCallInfo.iCallParams.iProtocol; + params.iQoS=iCallInfo.iCallParams.iQoS; + params.iRLPVersion=iCallInfo.iCallParams.iRLPVersion; + params.iModemToMSWindowSize=iCallInfo.iCallParams.iModemToMSWindowSize; + params.iMSToModemWindowSize=iCallInfo.iCallParams.iMSToModemWindowSize; + params.iAckTimer=iCallInfo.iCallParams.iAckTimer; + params.iRetransmissionAttempts=iCallInfo.iCallParams.iRetransmissionAttempts; + params.iResequencingPeriod=iCallInfo.iCallParams.iResequencingPeriod; + params.iV42bisReq=iCallInfo.iCallParams.iV42bisReq; + params.iV42bisCodewordsNum=iCallInfo.iCallParams.iV42bisCodewordsNum; + params.iV42bisMaxStringLength=iCallInfo.iCallParams.iV42bisMaxStringLength; + } + else if(callparams.ExtensionId()==RMobileCall::KETelMobileHscsdCallParamsV1) + { + // + // Configure RMobileCall::TMobileHscsdCallParamsV1 parameters + RMobileCall::TMobileHscsdCallParamsV1Pckg* pckg = (RMobileCall::TMobileHscsdCallParamsV1Pckg*)aParams; + RMobileCall::TMobileHscsdCallParamsV1& params = (*pckg)(); + params.iWantedAiur=iCallInfo.iCallParams.iWantedAiur; + params.iWantedRxTimeSlots=iCallInfo.iCallParams.iWantedRxTimeSlots; + params.iMaxTimeSlots=iCallInfo.iCallParams.iMaxTimeSlots; + params.iCodings=iCallInfo.iCallParams.iCodings; + params.iAsymmetry=iCallInfo.iCallParams.iAsymmetry; + params.iUserInitUpgrade=iCallInfo.iCallParams.iUserInitUpgrade; + } + + // + // Complete the clients request + ReqCompleted(aTsyReqHandle,KErrNone); + } + else + { + ReqCompleted(aTsyReqHandle,KErrUnknown); + } + return KErrNone; + } + +TInt CCallHayes::GetCallDuration(const TTsyReqHandle aTsyReqHandle, TTimeIntervalSeconds* aTime) + { + if ( RMobileCall::EStatusConnected != iCallInfo.iMobileStatus && + RMobileCall::EStatusDisconnecting != iCallInfo.iMobileStatus) + { + ReqCompleted(aTsyReqHandle,KErrEtelCallNotActive); + return KErrNone; + } + *aTime = iCallTimer->CallDuration(); + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +void CCallHayes::GetCallDuration(TTimeIntervalSeconds& aTime) const + { + aTime = iCallTimer->CallDuration(); + } + +void CCallHayes::GetDefaultCallParams() + { + iPhoneGlobals->iConfiguration->GetIntervalPref(iCallInfo.iInterval); + iPhoneGlobals->iConfiguration->GetSpeakerSettingPref(iCallInfo.iSpeakerControl); + iPhoneGlobals->iConfiguration->GetSpeakerVolumePref(iCallInfo.iSpeakerVolume); + iPhoneGlobals->iConfiguration->GetWaitForDialTonePref(iCallInfo.iWaitForDialTone); + } + +void CCallHayes::SetCallParams(const TDesC8* aParams) + { + if ((*aParams).Length()==0) + // Always returns KErrNone + GetDefaultCallParams(); + else + { + TPckg* paramsPckg = (TPckg*)aParams; + RCall::TCallParams& callparams = (*paramsPckg)(); + iCallInfo.iSpeakerControl = callparams.iSpeakerControl; + iCallInfo.iSpeakerVolume = callparams.iSpeakerVolume; + iCallInfo.iInterval = callparams.iInterval; + iCallInfo.iWaitForDialTone = callparams.iWaitForDialTone; + } + } + +TInt CCallHayes::ValidateRequest(const TTsyReqHandle aTsyReqHandle, RCall::TStatus aLineStatus) +// +// Validating a request +// + { + CCallBase::TCallOwnership owned = CheckOwnership(aTsyReqHandle); + if (owned==CCallBase::EOwnedFalse) // call owned by another client + { + return KErrEtelNotCallOwner; + } + if (iPhoneGlobals->iPhoneStatus.iLineStatus != aLineStatus) + { + if (aLineStatus==RCall::EStatusIdle) + // implies that this call is already active (assuming an owned call is + // an active call) or ringing or unknown + { + return KErrInUse; + } + else if (aLineStatus==RCall::EStatusRinging) + { + return KErrNotReady; + } + } + return KErrNone; + } + + +RCall::TStatus CCallHayes::GetCoreCallStatus() + { + RCall::TStatus coreStatus; + if (iCallInfo.iMobileStatus <= RMobileCall::EStatusDisconnecting) + //coreStatus = static_cast(iCallInfo.iMobileStatus); + coreStatus = (RCall::TStatus)iCallInfo.iMobileStatus; + else + switch (iCallInfo.iMobileStatus) + { + case RMobileCall::EStatusReconnectPending: + case RMobileCall::EStatusHold: + coreStatus = RCall::EStatusConnected; + break; + case RMobileCall::EStatusWaitingAlternatingCallSwitch: + coreStatus = RCall::EStatusIdle; + break; + default: + coreStatus = RCall::EStatusUnknown; + break; + } + return coreStatus; + } + +TInt CCallHayes::ChangeCallStatus(RMobileCall::TMobileCallStatus aCallStatus) + { + if (iCallInfo.iMobileStatus != aCallStatus) + { + iCallInfo.iMobileStatus = aCallStatus; + + if (aCallStatus == RMobileCall::EStatusIdle) + { + iCallInfo.iHookStatus = RCall::EHookStatusOn; + iPhoneGlobals->iNotificationStore->CheckNotification(this,EBecomeIdle); + } + else if (aCallStatus != RMobileCall::EStatusUnknown && aCallStatus != RMobileCall::EStatusRinging) + { + iCallInfo.iHookStatus = RCall::EHookStatusOff; + } + if (aCallStatus == RMobileCall::EStatusConnected) + { + iPhoneGlobals->iNotificationStore->CheckNotification(this,EConnected); + iIo->Cancel(); + TCommConfig aConfigPckg; + TInt ret = iPhoneGlobals->iConfiguration->PortConfig(aConfigPckg,EConfigTypeConnect); + if (ret==KErrNone) + ret = iIo->ConfigurePort(aConfigPckg); +// if (!(iIo->ReadPending())) +// iIo->Read(); + iCallInfo.iTimeCallBegan.UniversalTime(); + return ret; + } + } + return KErrNone; + } + +void CCallHayes::ChangeLineStatus(RCall::TStatus aLineStatus) + { + iPhoneGlobals->iPhoneStatus.iLineStatus = aLineStatus; + } + +void CCallHayes::SetToIdle() + { + iWaitForNoCarrier->StopWait(); + // Always returns KErrNone + (void)SetUnowned(); + iPhoneGlobals->iPhoneStatus.iMode = RPhone::EModeIdle; + ChangeLineStatus(RCall::EStatusIdle); // line status should be changed first because + // ChangeCallStatus is the function which sends + // the new event to the Notification Handler, + // and this will complete both line and call status + // notifications, taking the new statuses from the + // CLineHayes and CCallHayes objects. + // EStatusIdle always results in KErrNone return value + (void)ChangeCallStatus(RMobileCall::EStatusIdle); + StopCallTicker(); + } + +void CCallHayes::SetToIdleAndCompleteReq(TTsyReqHandle aTsyReqHandle,TInt aStatus) + { + SetToIdle(); + ReqCompleted(aTsyReqHandle, aStatus); + } + +void CCallHayes::GetCallInfo(TCallInfoIndex* aCallInfoIndex) +// +// Copied field by field since TCallInfoTSY is different to TCallInfoIndex +// + { + aCallInfoIndex->iInfo.iCallName = iCallInfo.iCallName; + aCallInfoIndex->iInfo.iStatus = GetCoreCallStatus(); + aCallInfoIndex->iInfo.iCallCapsFlags = 0; + } + +TBool CCallHayes::CheckName(const TDesC& aName) const +// +// Return TRUE if name is the same as the name of this call + { + if (iCallInfo.iCallName.CompareF(aName)) + return EFalse; + else + return ETrue; + } + +TCallInfoTSY* CCallHayes::CallInfo() + { + return &iCallInfo; + } + +void CCallHayes::StartCallTicker() const + { + iCallTimer->Start(); + } + +void CCallHayes::StopCallTicker() const + { + iCallTimer->Stop(); + } + +void CCallHayes::ResetIsForIncomingCall() + { + iIsForIncomingCall=EFalse; + } + +TBool CCallHayes::IsForIncomingCall() const + { + return iIsForIncomingCall; + } + +void CCallHayes::SetOwnedByTSY() + { + iIsOwnedByTSY=ETrue; + } + +void CCallHayes::SetUnownedByTSY() + { + iIsOwnedByTSY=EFalse; + } + +TBool CCallHayes::IsOwnedByTSY() const + { + return iIsOwnedByTSY; + } + + +// +// Functions which are supported in one line but not the other +// +TInt CCallHayes::LoanDataPort(const TTsyReqHandle,RCall::TCommPort*) + { + return KErrNotSupported; + } + +TInt CCallHayes::LoanDataPortCancel(const TTsyReqHandle) + { + return KErrNotSupported; + } + +TInt CCallHayes::RecoverDataPort(const TTsyReqHandle) + { + return KErrNotSupported; + } + +TInt CCallHayes::RecoverDataPortAndRelinquishOwnership() + { + return KErrNotSupported; + } + +TInt CCallHayes::GetFaxSettings(const TTsyReqHandle,RCall::TFaxSessionSettings*) + { + return KErrNotSupported; + } + +TInt CCallHayes::SetFaxSettings(const TTsyReqHandle,const RCall::TFaxSessionSettings*) + { + return KErrNotSupported; + } + +CTelObject* CCallHayes::OpenNewObjectByNameL(const TDesC& /*aName*/) + { + User::Leave(KErrNotSupported); + return NULL; + } + +CTelObject* CCallHayes::OpenNewObjectL(TDes& /*aNewName*/) + { + User::Leave(KErrNotSupported); + return NULL; + } + +TInt CCallHayes::CheckAndSetRegistrationParams(const TInt /*aIpc*/,const TDes8* /*aDes1*/,const TDes8* /*aDes2*/) + { + return KErrNone; + } + +TInt CCallHayes::ExtFunc(const TTsyReqHandle,const TInt, const TDataPackage&) +// +// Unsupported in this TSY +// + { + return KErrNotSupported; + } + +/* + * CCallMobile class that implements Multimode ETel Mobile Call requests + */ + +CCallMobile::CCallMobile(CATIO* aIo,CATInit* aInit,CPhoneGlobals* aPhoneGlobals) + : CCallHayes(aIo, aInit, aPhoneGlobals) + { + } + +CCallMobile::~CCallMobile() + { + } + +CTelObject::TReqMode CCallMobile::ReqModeL(const TInt aIpc) + { + // ReqModeL is called from the server's CTelObject::ReqAnalyserL + // in order to check the type of request it has + + CTelObject::TReqMode ret=0; + switch (aIpc) + { +// +// No Flow Control NOR Multiple Completion +// + case EMobileCallGetMobileCallCaps: + case EMobileCallGetMobileCallStatus: + break; + + case EMobileCallGetMobileDataCallCaps: + break; +// +// Multiple Completion Services with Immediate Server Repost +// (Usually Notifications) +// + case EMobileCallNotifyMobileCallStatusChange: + case EMobileCallNotifyMobileCallCapsChange: + + ret=KReqModeMultipleCompletionEnabled | KReqModeRePostImmediately; + break; +// +// +// + default: + ret=CCallHayes::ReqModeL(aIpc); + break; + } + + return ret; + } + + +TInt CCallMobile::NumberOfSlotsL(const TInt aIpc) + { + // 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 + + TInt numberOfSlots=1; + switch (aIpc) + { + case EMobileCallNotifyMobileCallStatusChange: + case EMobileCallNotifyMobileCallCapsChange: + LOGTEXT(_L8("CCallMobile: Registered with 5 slots")); + numberOfSlots=5; + break; + default: + numberOfSlots = CCallBase::NumberOfSlotsL(aIpc); + break; + } + return numberOfSlots; + } + + +TInt CCallMobile::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 + + 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)); +// +// 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()); + +// +// Cancels +// + case EMobileCallNotifyMobileCallStatusChangeCancel: + return NotifyMobileCallStatusChangeCancel(aTsyReqHandle); + + case EMobileCallNotifyMobileCallCapsChangeCancel: + return NotifyMobileCallCapsChangeCancel(aTsyReqHandle); + + default: + return KErrNotSupported; + } + } + +TInt CCallMobile::CancelService(const TInt aIpc, const TTsyReqHandle aTsyReqHandle) + { + // CancelService is called by the 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. + + switch (aIpc) + { + case EMobileCallNotifyMobileCallStatusChange: + return NotifyMobileCallStatusChangeCancel(aTsyReqHandle); + case EMobileCallNotifyMobileCallCapsChange: + return NotifyMobileCallCapsChangeCancel(aTsyReqHandle); + default: + return CCallBase::CancelService(aIpc,aTsyReqHandle); + } + } + +TInt CCallMobile::GetMobileCallCaps(const TTsyReqHandle aTsyReqHandle, TDes8* aCaps) + { + LOGTEXT(_L8("CCallMobile: :GetMobileCallCaps called")); + + RMobileCall::TMobileCallCapsV1Pckg *capsPckg = REINTERPRET_CAST(RMobileCall::TMobileCallCapsV1Pckg *,aCaps); + RMobileCall::TMobileCallCapsV1& caps = (*capsPckg)(); + // Always returns KErrNone + (void)CollateCurrentMobileCaps(aTsyReqHandle, &caps.iCallControlCaps); + caps.iCallEventCaps=0; // no call events are supported + + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TInt CCallMobile::GetCaps(const TTsyReqHandle aTsyReqHandle,RCall::TCaps* aCallCaps) + { + (void)CollateCurrentCoreCaps(aTsyReqHandle, reinterpret_cast(&aCallCaps->iFlags)); + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TBool CCallMobile::CollateCurrentMobileCaps(const TTsyReqHandle aTsyReqHandle, TUint32* aCallCaps) + { + CollateCoreCaps(aTsyReqHandle, aCallCaps); + if (iMobileCaps.iCallControlCaps != *aCallCaps) + { + iMobileCaps.iCallControlCaps = *aCallCaps; + return ETrue; + } + return EFalse; + } + +TBool CCallMobile::CollateCurrentCoreCaps(const TTsyReqHandle aTsyReqHandle, TUint32* aCallCaps) + { + CollateCoreCaps(aTsyReqHandle, aCallCaps); + if (iCaps.iFlags != *aCallCaps) + { + iCaps.iFlags = *aCallCaps; + return ETrue; + } + return EFalse; + } + +TInt CCallMobile::NotifyMobileCallCapsChange(const TTsyReqHandle aTsyReqHandle, TDes8* aCaps) + { + LOGTEXT(_L8("CCallMobile::NotifyMobileCallCapsChange lodged")); + iPhoneGlobals->iNotificationStore->RegisterNotification(ECallMobileCaps,aTsyReqHandle,this,aCaps); + return KErrNone; + } + +TInt CCallMobile::NotifyMobileCallCapsChangeCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("CCallMobile::NotifyMobileCallCapsChangeCancel called")); + iPhoneGlobals->iNotificationStore->RemoveNotification(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobile::GetMobileCallStatus(const TTsyReqHandle aTsyReqHandle,RMobileCall::TMobileCallStatus* aStatus) + { + LOGTEXT(_L8("CCallMobile::GetMobileCallStatus called")); + *aStatus=iCallInfo.iMobileStatus; + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TInt CCallMobile::NotifyMobileCallStatusChange(const TTsyReqHandle aTsyReqHandle,RMobileCall::TMobileCallStatus* aStatus) + { + LOGTEXT(_L8("CCallMobile::NotifyMobileCallStatusChange lodged")); + iPhoneGlobals->iNotificationStore->RegisterNotification(EMobileCallStatusChange,aTsyReqHandle,this,aStatus); + return KErrNone; + } + +TInt CCallMobile::NotifyMobileCallStatusChangeCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("CCallMobile::NotifyMobileCallStatusChangeCancel called")); + iPhoneGlobals->iNotificationStore->RemoveNotification(aTsyReqHandle); + return KErrNone; + } + +// +// CCallMobileVoice - Voice Specific Call Functionality +// + +CCallMobileVoice* CCallMobileVoice::NewL(CATIO* aATIO,CATInit* aInit,CPhoneGlobals* aPhoneGlobals,const TName& aName) + { + CCallMobileVoice* voiceCall=new(ELeave) CCallMobileVoice(aATIO,aInit,aPhoneGlobals); + TCleanupItem newCallVoiceHayesClose(CloseCall,voiceCall); + CleanupStack::PushL(newCallVoiceHayesClose); + voiceCall->ConstructL(aName); + CleanupStack::Pop(); + return voiceCall; + } + +CCallMobileVoice::CCallMobileVoice(CATIO* aATIO,CATInit* aInit,CPhoneGlobals* aPhoneGlobals) + : CCallMobile(aATIO,aInit,aPhoneGlobals) + {} + +void CCallMobileVoice::ConstructL(const TName& aName) + { + CCallHayes::ConstructL(aName); + iCallInfo.iLineOwnerName = KVoiceLineName; + iDialVoice=CATDialVoice::NewL(iIo,this,iInit,iPhoneGlobals); + iAnswerVoice=CATAnswerVoice::NewL(iIo,this,iInit,iPhoneGlobals); + iHangUpVoice=CATHangUpVoice::NewL(iIo,this,iInit,iPhoneGlobals); + } + +CCallMobileVoice::~CCallMobileVoice() +// +// Removes itself from array of calls in CLineMobileVoice +// + { + delete iDialVoice; + delete iAnswerVoice; + delete iHangUpVoice; + } + +void CCallMobileVoice::CollateCoreCaps(const TTsyReqHandle /*aTsyReqHandle*/, TUint32* aCallCaps) + { + *aCallCaps = RCall::KCapsVoice; + + // Voice calls can be manipulated by any client, not just owner so set as many caps as possible + if (iPhoneGlobals->iPhoneStatus.iModemDetected==RPhone::EDetectedPresent) + { + *aCallCaps |= (RCall::KCapsDial | RCall::KCapsConnect); + + TInt ret=KErrNone; + if (!iIsForIncomingCall) + { + if (REINTERPRET_CAST(CPhoneHayes*,Owner()->Owner())->CheckForOutstandingAnswer()) + ret=KErrEtelAnswerAlreadyOutstanding; + } + else + ret=KErrEtelAnswerAlreadyOutstanding; + + if (ret==KErrNone && (iCallInfo.iMobileStatus==RMobileCall::EStatusIdle || iCallInfo.iMobileStatus==RMobileCall::EStatusRinging)) + *aCallCaps |= RCall::KCapsAnswer; + + if (iCallInfo.iMobileStatus==RMobileCall::EStatusConnected) + *aCallCaps |= RCall::KCapsHangUp; + } + } + +TInt CCallMobileVoice::Dial(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* aTelNumber) +// +// Dial a voice call +// + { + SetCallParams(aCallParams); + LOGTEXT(_L8("VoiceCall:\tSubmitting Dial command for Voice call")); + if (iPhoneGlobals->iPhoneStatus.iLineStatus == RCall::EStatusIdle) + { + (void)SetOwnership(aTsyReqHandle); + iDialVoice->ExecuteCommand(aTsyReqHandle,aTelNumber,&iCallInfo); + return KErrNone; + } + else + { + return KErrInUse; + } + } + +TInt CCallMobileVoice::DialCancel(const TTsyReqHandle aTsyReqHandle) +/** + * Cancel the dial request if possible + */ + { + LOGTEXT(_L8("VoiceCall:\tSubmitting Cancel Dial command for Voice call")); + iDialVoice->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobileVoice::AnswerIncomingCall(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams) +/** + * If there is no waiting call, will wait for one and then answer it. If there is, it will + * answer immediately. + */ + { + CCallBase::TCallOwnership owned = CheckOwnership(aTsyReqHandle); + TInt ret=KErrNone; + if (owned==CCallBase::EOwnedFalse) // call owned by another client + { + ret=KErrEtelNotCallOwner; + } + else + { + if (!iIsForIncomingCall) + { + if (REINTERPRET_CAST(CPhoneHayes*,Owner()->Owner())->CheckForOutstandingAnswer()) + ret=KErrEtelAnswerAlreadyOutstanding; + } + else + ret=KErrEtelAnswerAlreadyOutstanding; + } + if (ret==KErrNone) + { + CLineHayes* line = STATIC_CAST(CLineHayes*,Owner()); + STATIC_CAST(CPhoneHayes*,line->Owner())->CancelOtherRingingCall(line); + line->FreePreAllocCallIfNecessary(); + SetCallParams(aCallParams); + if (iCallInfo.iMobileStatus==RMobileCall::EStatusRinging) + { + (void)SetOwnership(aTsyReqHandle); + LOGTEXT(_L8("VoiceCall:\tSubmitting Answer command")); + iAnswerVoice->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + } + else // This call is now a client-designated Incoming Call object. + { + iIsForIncomingCall=ETrue; + iAnswerTsyReqHandle = aTsyReqHandle; + } + return KErrNone; + } + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + + +TInt CCallMobileVoice::AnswerIncomingCallCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("VoiceCall:\tSubmitting Cancel Answer command")); + if (iIsForIncomingCall) + { + iIsForIncomingCall=EFalse; + ReqCompleted(aTsyReqHandle,KErrCancel); + } + else + iAnswerVoice->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +void CCallMobileVoice::AnswerImmediately() + { + (void)SetOwnership(iAnswerTsyReqHandle); + // EStatusRinging always results in KErrNone return value + (void) ChangeCallStatus(RMobileCall::EStatusRinging); + iPhoneGlobals->iNotificationStore->CheckNotification(this,ERingOccurred); + iIsForIncomingCall=EFalse; + // this must be after the check notification as CNotifications + // asks line for info about the call which Is For Incoming Call + LOGTEXT(_L8("VoiceCall:\tSubmitting Answer command")); + iAnswerVoice->ExecuteCommand(iAnswerTsyReqHandle,NULL,&iCallInfo); + } + +TInt CCallMobileVoice::Connect(const TTsyReqHandle aTsyReqHandle,const TDesC8* /*aCallParams*/) + { + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + +TInt CCallMobileVoice::ConnectCancel(const TTsyReqHandle aTsyReqHandle) + { + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + +TInt CCallMobileVoice::HangUp(const TTsyReqHandle aTsyReqHandle) + { + if (CheckOwnership(aTsyReqHandle)==CCallBase::EOwnedFalse) + { + ReqCompleted(aTsyReqHandle,KErrEtelNotCallOwner); + return KErrNone; + } + if ((iCallInfo.iMobileStatus!=RMobileCall::EStatusIdle) && + (iCallInfo.iMobileStatus!=RMobileCall::EStatusDisconnecting)) + { + LOGTEXT(_L8("VoiceCall:\tSubmitting Hang Up command")); + iHangUpVoice->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + return KErrNone; + } + else + { + // Call not in a state to be terminated - but return KErrNone + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + } + +TInt CCallMobileVoice::HangUpCancel(const TTsyReqHandle aTsyReqHandle) +// +// Cancel the hang up command. +// + { + LOGTEXT(_L8("VoiceCall:\tSubmitting Cancel Hang Up command")); + iHangUpVoice->Stop(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobileVoice::RelinquishOwnership() + { +// +// Called by server to tell TSY to either pass ownership on to another interested client +// or hang up immediately. If call is currently connecting, RelinquishOwnershipComplete +// will be called once cancelling has finished. +// + LOGTEXT(_L8("VoiceCall:\tRelinquish Ownership")); + if(iList->iAcquireList.IsEmpty()) + { + if (iDialVoice->IsPreConnectInProgress()) + { + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + return KErrNone; + } + switch(iCallInfo.iMobileStatus) + { + case RMobileCall::EStatusConnected: + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + iHangUpVoice->ExecuteCommand(0, NULL, &iCallInfo); + break; + case RMobileCall::EStatusDialling: + case RMobileCall::EStatusConnecting: + case RMobileCall::EStatusAnswering: + case RMobileCall::EStatusDisconnecting: + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + break; + default: + if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneInitialising) + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + else + RelinquishOwnershipCompleted(KErrNone); + break; + } + return KErrNone; + } + CAcquireEntry* entry=iList->iAcquireList.First(); + if (entry) + { + (void)SetOwnership(entry->iTsyReqHandle); + ReqCompleted(entry->iTsyReqHandle,KErrNone); + iList->Remove(entry); + } + RelinquishOwnershipCompleted(KErrNone); + return KErrNone; + } + +TInt CCallMobileVoice::RecoverDataPortAndRelinquishOwnership() + { + RecoverDataPortAndRelinquishOwnershipCompleted(KErrNotSupported); + return KErrNone; + } + +TInt CCallMobileVoice::LoanDataPort(const TTsyReqHandle aTsyReqHandle, RCall::TCommPort* /* aCommPort*/) + { + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + +TInt CCallMobileVoice::LoanDataPortCancel(const TTsyReqHandle aTsyReqHandle) + { + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + +TInt CCallMobileVoice::RecoverDataPort(const TTsyReqHandle aTsyReqHandle) + { + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + + +// +// +// CCallMobileData - Data Specific Call Functionality +// +// + +CCallMobileData* CCallMobileData::NewL(CATIO* aATIO,CATInit* aInit,CPhoneGlobals* aPhoneGlobals,const TName& aName) + { + CCallMobileData* dataCall=new(ELeave) CCallMobileData(aATIO,aInit,aPhoneGlobals); + TCleanupItem newCallDataHayesClose(CloseCall,dataCall); + CleanupStack::PushL(newCallDataHayesClose); + dataCall->ConstructL(aName); + CleanupStack::Pop(); + return dataCall; + } + +CCallMobileData::CCallMobileData(CATIO* aATIO,CATInit* aInit,CPhoneGlobals* aPhoneGlobals) + : CCallMobile(aATIO,aInit,aPhoneGlobals) + {} + +void CCallMobileData::ConstructL(const TName& aName) + { + CCallHayes::ConstructL(aName); + iCallInfo.iLineOwnerName = KDataLineName; + iDialData=CATDialData::NewL(iIo,this,iInit,iPhoneGlobals); + iAnswerData=CATAnswerData::NewL(iIo,this,iInit,iPhoneGlobals); + iSetCBST=CATSetCBST::NewL(iIo,this,iInit,iPhoneGlobals); + iConnectData=CATConnectData::NewL(iIo,this,iInit,iPhoneGlobals); + iHangUpData=CATHangUpData::NewL(iIo,this,iInit,iPhoneGlobals); + iATSetToOnlineDataMode=CATSetToOnlineDataMode::NewL(iIo,this,iInit,iPhoneGlobals); + } + +CCallMobileData::~CCallMobileData() +// +// Removes itself from array of calls in CLineMobileData +// + { + delete iDialData; + delete iSetCBST; + delete iAnswerData; + delete iConnectData; + delete iHangUpData; + delete iATSetToOnlineDataMode; + } + +TInt CCallMobileData::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc, + const TDataPackage& aPackage) +/** + * Process the IPC locally, otherwise delegate to our base class. + */ + { + switch (aIpc) + { + case EMobileCallGetMobileDataCallCaps: + return GetMobileDataCallCaps(aTsyReqHandle, aPackage.Des1n()); + default: + // Delegate the processing of the IPC to our base class + return CCallMobile::ExtFunc(aTsyReqHandle,aIpc,aPackage); + } + } + + +TInt CCallMobileData::GetMobileDataCallCaps(const TTsyReqHandle aTsyReqHandle, TDes8* aCaps) + { + LOGTEXT(_L8("CCallMobileData::GetMobileDataCallCaps called")); + + // + // This is a synchronous client request so this method must complete quickly. + // The call caps returned are those which were discovered during the + // intialisation of the TSY (see ATINIT.CPP). + TPckg* pckg = (TPckg*)aCaps; + RMobileCall::TMobileCallDataCapsV1& caps = (*pckg)(); + caps=iPhoneGlobals->iCallDataCaps; + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +void CCallMobileData::CollateCoreCaps(const TTsyReqHandle aTsyReqHandle, TUint32* aCallCaps) + { + *aCallCaps = RCall::KCapsData; + if (iPhoneGlobals->iPhoneStatus.iModemDetected==RPhone::EDetectedPresent) + { + CCallBase::TCallOwnership owner = CheckOwnership(aTsyReqHandle); + if (ValidateRequest(aTsyReqHandle,RCall::EStatusIdle)==KErrNone) + *aCallCaps |= (RCall::KCapsDial | RCall::KCapsConnect); + TInt ret=KErrNone; + if (owner==CCallBase::EOwnedFalse) // call owned by another client + ret=KErrEtelNotCallOwner; + else + { + if (!iIsForIncomingCall) + { + if (REINTERPRET_CAST(CPhoneHayes*,Owner()->Owner())->CheckForOutstandingAnswer()) + ret=KErrEtelAnswerAlreadyOutstanding; + } + else + ret=KErrEtelAnswerAlreadyOutstanding; + } + if (ret==KErrNone && (iCallInfo.iMobileStatus==RMobileCall::EStatusIdle || iCallInfo.iMobileStatus==RMobileCall::EStatusRinging)) + *aCallCaps |= RCall::KCapsAnswer; + if ((owner==CCallBase::EOwnedTrue || owner==CCallBase::EOwnedPriorityClient) + && iCallInfo.iMobileStatus==RMobileCall::EStatusConnected) + { + *aCallCaps |= RCall::KCapsHangUp; + if (iCallInfo.iLoanedToClient==EFalse) + *aCallCaps |= RCall::KCapsLoanDataPort; + else + *aCallCaps |= RCall::KCapsRecoverDataPort; + } + } + } + +TInt CCallMobileData::AssembleCBSTSetString(TBuf8& aTxBuffer) +/** + * This funciton assembles a +CBST= string ready to be sent to the modem using + * the values from CCallHayes::iCallInfo. + * This utility funciton is used by objects created and owned by this class. + * This has been done to reduce code size. + * @return KErrNone if and only if CBST string assembled + */ + { + TInt ret(KErrNone); // Return value of this function + + TInt speed(0); // these are the names that etsi use + TInt name(0); // these are the names that etsi use + TInt ce(0); // these are the names that etsi use + TBool speedSet(ETrue); + TBool nameSet(ETrue); + TBool ceSet(ETrue); + + switch (iCallInfo.iCallParams.iService) + { + case RMobileCall::EServiceDataCircuitAsync: + name = 0; + break; + case RMobileCall::EServiceDataCircuitAsyncRdi: + name = 4; + break; + case RMobileCall::EServiceDataCircuitSync: + name = 1; + break; + case RMobileCall::EServiceDataCircuitSyncRdi: + name = 5; + break; + case RMobileCall::EServicePADAsyncUDI: + name = 2; + break; + case RMobileCall::EServicePADAsyncRDI: + name = 6; + break; + case RMobileCall::EServicePacketAccessSyncUDI: + name = 3; + break; + case RMobileCall::EServicePacketAccessSyncRDI: + name = 7; + break; + case RMobileCall::EServiceUnspecified: // taking the default value of 0 + default: + nameSet=EFalse; + break; + } + + switch(iCallInfo.iCallParams.iQoS) + { + case RMobileCall::EQoSTransparent: + ce = 0; + break; + case RMobileCall::EQosTransparentPreferred: + ce = 2; + break; + case RMobileCall::EQoSNonTransparent: + ce = 1; + break; + case RMobileCall::EQosNonTransparentPreferred: + ce = 3; + break; + case RMobileCall::EQoSUnspecified: + default: + ceSet=EFalse; + break; + } + + switch(iCallInfo.iCallParams.iSpeed) + { + case RMobileCall::ESpeedAutobauding: + speed = 0; + break; + + case RMobileCall::ESpeed2400: + { + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV22bis) + speed = 4; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 36; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 68; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed4800: + { + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV32) + speed = 6; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 38; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 70; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed9600: + { + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV32) + speed = 7; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV34) + speed = 12; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 39; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 71; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed14400: + { + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV34) + speed = 14; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 43; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 75; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed19200: + { + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV34) + speed = 15; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 47; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 79; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed28800: + { + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV34) + speed = 16; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 48; + else if ((iCallInfo.iCallParams.iProtocol ==RMobileCall:: EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 80; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed38400: + { + if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 81; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 49; + else + speedSet=EFalse; + break; + } + case RMobileCall::ESpeed48000: + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 50; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 82; + else + speedSet=EFalse; + break; + case RMobileCall::ESpeed56000: + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV120) + speed = 51; + else if ((iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolV110) || + (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolX31FlagStuffing)) + speed = 83; + else if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolBitTransparent) + speed = 115; + else + speedSet=EFalse; + break; + case RMobileCall::ESpeed64000: + if (iCallInfo.iCallParams.iProtocol == RMobileCall::EProtocolBitTransparent) + speed = 116; + else + speedSet=EFalse; + break; + + case RMobileCall::ESpeed33600: // this baud rate is not currently used in the etsi table + case RMobileCall::ESpeedUnspecified: + default: + speedSet=EFalse; + break; + } + + // + // Try to assemble as much of the +CBST= command as we can. + // If we do not have a value we can not send the command. + // If we do not have a value then we can send a command giving only and . + // etc... + if(speedSet) + { + aTxBuffer.Zero(); // Clear tx buffer + + // Append +CBST= and the parameter + aTxBuffer.Append(KDataCallBearerServiceType); + aTxBuffer.AppendNum(speed); + + if(nameSet) + { + // Append the parameter + aTxBuffer.Append(TChar(',')); + aTxBuffer.AppendNum(name); + + if(ceSet) + { + // Append the parameter + aTxBuffer.Append(TChar(',')); + aTxBuffer.AppendNum(ce); + } + } + + // Append final \r char to AT command + aTxBuffer.Append(TChar('\r')); + } + else + { + // We have not have enough info to create a +CBST= string + ret=KErrArgument; + } + + return ret; + } + + + +TInt CCallMobileData::Dial(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* aTelNumber) +// +// Dial a data call +// + { + TInt ret(KErrNone); + + SetDataCallParams(aCallParams); + + ret=ValidateRequest(aTsyReqHandle,RCall::EStatusIdle); + if (ret==KErrNone) + { + (void)SetOwnership(aTsyReqHandle); + LOGTEXT(_L8("DataCall:\tSubmitting Dial command for Data call")); + iDialData->ExecuteCommand(aTsyReqHandle,aTelNumber,&iCallInfo); + } + else + ReqCompleted(aTsyReqHandle,ret); // An error occurred + + return KErrNone; // Real return code is returned to client thru request completion + } + + +TInt CCallMobileData::DialCancel(const TTsyReqHandle aTsyReqHandle) +// +// Cancel the dial request if possible +// + { + LOGTEXT(_L8("DataCall:\tSubmitting Cancel Dial command for Data call")); + iDialData->CancelCommand(aTsyReqHandle); + return KErrNone; + } + + +void CCallMobileData::SetDataCallParams(const TDesC8* aCallParams) +/** + * Utility function which unpacks the call parameters supplied by the client + * and saves their values in iPhoneGlobals. + * If the client did not supply parameters then default ones are used. + */ + { + if(aCallParams->Length()==0) + { + // + // Client did not supply parameters, so we use default ones + LOGTEXT(_L8("CCallMobileData::SetDataCallParams Using default parameters")); + CCallHayes::SetCallParams(aCallParams); + + // + // Ensure the speed parameter is undefined so that we prevent the + // +CBST=... command being sent to the phone when dialling a CSD data call. + iCallInfo.iCallParams.iService = RMobileCall::EServiceUnspecified; + } + else + { + // + // Use call parameters that client supplied us + LOGTEXT(_L8("CCallMobileData::SetDataCallParams Using clients parameters")); + RCall::TCallParamsPckg* paramsPckgV1 = (RCall::TCallParamsPckg*)aCallParams; + RCall::TCallParams& paramsV1 = (*paramsPckgV1)(); + + CCallHayes::SetCallParams(aCallParams); + if (paramsV1.ExtensionId()==RMobileCall::KETelMobileCallParamsV1) + { + RMobileCall::TMobileCallParamsV1Pckg* mmParamsPckgV1 = (RMobileCall::TMobileCallParamsV1Pckg*)aCallParams; + RMobileCall::TMobileCallParamsV1& mmParamsV1 = (*mmParamsPckgV1)(); + iCallInfo.iCallParams.iIdRestrict = mmParamsV1.iIdRestrict; + iCallInfo.iCallParams.iCug = mmParamsV1.iCug; + iCallInfo.iCallParams.iAutoRedial = mmParamsV1.iAutoRedial; + } + + if((paramsV1.ExtensionId()==RMobileCall::KETelMobileDataCallParamsV1) || + (paramsV1.ExtensionId()==RMobileCall::KETelMobileHscsdCallParamsV1)) + { + RMobileCall::TMobileDataCallParamsV1Pckg* dataParamsPckgV1 = (RMobileCall::TMobileDataCallParamsV1Pckg*)aCallParams; + RMobileCall::TMobileDataCallParamsV1& dataParamsV1 = (*dataParamsPckgV1)(); + iCallInfo.iCallParams.iService=dataParamsV1.iService; + iCallInfo.iCallParams.iSpeed=dataParamsV1.iSpeed; + iCallInfo.iCallParams.iProtocol=dataParamsV1.iProtocol; + iCallInfo.iCallParams.iQoS=dataParamsV1.iQoS; + iCallInfo.iCallParams.iRLPVersion=dataParamsV1.iRLPVersion; + iCallInfo.iCallParams.iModemToMSWindowSize=dataParamsV1.iModemToMSWindowSize; + iCallInfo.iCallParams.iMSToModemWindowSize=dataParamsV1.iMSToModemWindowSize; + iCallInfo.iCallParams.iAckTimer=dataParamsV1.iAckTimer; + iCallInfo.iCallParams.iRetransmissionAttempts=dataParamsV1.iRetransmissionAttempts; + iCallInfo.iCallParams.iResequencingPeriod=dataParamsV1.iResequencingPeriod; + iCallInfo.iCallParams.iV42bisReq=dataParamsV1.iV42bisReq; + iCallInfo.iCallParams.iV42bisCodewordsNum=dataParamsV1.iV42bisCodewordsNum; + iCallInfo.iCallParams.iV42bisMaxStringLength=dataParamsV1.iV42bisMaxStringLength; + } + + if (paramsV1.ExtensionId()==RMobileCall::KETelMobileHscsdCallParamsV1) + { + RMobileCall::TMobileHscsdCallParamsV1Pckg* hscsdParamsPckgV1 = (RMobileCall::TMobileHscsdCallParamsV1Pckg*)aCallParams; + RMobileCall::TMobileHscsdCallParamsV1& hscsdParamsV1 = (*hscsdParamsPckgV1)(); + iCallInfo.iCallParams.iWantedAiur = hscsdParamsV1.iWantedAiur; + iCallInfo.iCallParams.iWantedRxTimeSlots = hscsdParamsV1.iWantedRxTimeSlots; + iCallInfo.iCallParams.iMaxTimeSlots = hscsdParamsV1.iMaxTimeSlots; + iCallInfo.iCallParams.iCodings = hscsdParamsV1.iCodings; + iCallInfo.iCallParams.iAsymmetry = hscsdParamsV1.iAsymmetry; + iCallInfo.iCallParams.iUserInitUpgrade = hscsdParamsV1.iUserInitUpgrade; + } + } + } + +TInt CCallMobileData::AnswerIncomingCall(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams) +/** + * If there is no waiting call, will wait for one and then answer it. + * If there is a waiting call, will answer immediatly. + * Regardless of if there is a waiting call or not, the +CBST= command is sent immediatly. + */ + { + const CCallBase::TCallOwnership owned = CheckOwnership(aTsyReqHandle); + TInt ret=KErrNone; + if (owned==CCallBase::EOwnedFalse) // call owned by another client + { + ret=KErrEtelNotCallOwner; + } + else + { + if (!iIsForIncomingCall) + { + if (REINTERPRET_CAST(CPhoneHayes*,Owner()->Owner())->CheckForOutstandingAnswer()) + ret=KErrEtelAnswerAlreadyOutstanding; + } + else + ret=KErrEtelAnswerAlreadyOutstanding; + } + + if (ret==KErrNone) + { + CLineHayes* line = STATIC_CAST(CLineHayes*,Owner()); + STATIC_CAST(CPhoneHayes*,line->Owner())->CancelOtherRingingCall(line); + line->FreePreAllocCallIfNecessary(); + SetDataCallParams(aCallParams); + if (iCallInfo.iMobileStatus==RMobileCall::EStatusRinging) + { + (void)SetOwnership(aTsyReqHandle); + LOGTEXT(_L8("DataCall:\tSubmitting Answer command")); + + // Start the 'send CBST to phone' AT machine and pass the + // CATAnswerData object, so that the call is answered after + // the CBST is sent. + iSetCBST->ExecuteCommand(aTsyReqHandle,iAnswerData,&iCallInfo); + } + else // This call is now a client-designated Incoming Call object. + { + iIsForIncomingCall=ETrue; + iAnswerTsyReqHandle = aTsyReqHandle; + + // Start the 'send CBST to phone' AT machine. This state machine + // will not complete any client request. + iSetCBST->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + } + return KErrNone; + } + + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + + +TInt CCallMobileData::AnswerIncomingCallCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT(_L8("DataCall:\tSubmitting Cancel Answer command")); + if (iIsForIncomingCall) + { + iIsForIncomingCall=EFalse; + ReqCompleted(aTsyReqHandle,KErrCancel); + } + else + iAnswerData->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +void CCallMobileData::AnswerImmediately() + { + (void)SetOwnership(iAnswerTsyReqHandle); + // EStatusRinging always results in KErrNone return + (void) ChangeCallStatus(RMobileCall::EStatusRinging); // new 14/1/99 + iPhoneGlobals->iNotificationStore->CheckNotification(this,ERingOccurred); + iIsForIncomingCall=EFalse; // this must be after the check notification as CNotifications + // asks line for info about the call which Is For Incoming Call + LOGTEXT(_L8("DataCall:\tSubmitting Answer command")); + iAnswerData->ExecuteCommand(iAnswerTsyReqHandle,NULL,&iCallInfo); + } + +TInt CCallMobileData::Connect(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams) +// +// Connect to an already dialled call +// + { + TInt ret = ValidateRequest(aTsyReqHandle,RCall::EStatusIdle); + if (ret==KErrNone) + { + (void)SetOwnership(aTsyReqHandle); + SetCallParams(aCallParams); + LOGTEXT(_L8("DataCall:\tSubmitting Immediate Connect command")); + iConnectData->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + } + else + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + +TInt CCallMobileData::ConnectCancel(const TTsyReqHandle aTsyReqHandle) +// +// Cancel immediate connect command +// + { + LOGTEXT(_L8("DataCall:\tSubmitting Cancel Connect command")); + iConnectData->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobileData::HangUp(const TTsyReqHandle aTsyReqHandle) +// +// Terminate a data call. If someone else owns call complete with error, but if no-one owns +// it send an ATH anyway, as the connection may have failed and the user wants to ensure +// call has hung up. Call Start() instead of ExecuteCommand() because there is no need to +// initialise before doing this or to send the escape sequence - the hang up sequence drops +// DTR anyway. +// + { + if (CheckOwnership(aTsyReqHandle)==CCallBase::EOwnedFalse) + { + ReqCompleted(aTsyReqHandle,KErrEtelNotCallOwner); + return KErrNone; + } + if ((iCallInfo.iMobileStatus!=RMobileCall::EStatusIdle) && + (iCallInfo.iMobileStatus!=RMobileCall::EStatusDisconnecting)) + { + LOGTEXT(_L8("DataCall:\tSubmitting Hang Up command")); + iHangUpData->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + return KErrNone; + } + else + { + // Call not in a state to be terminated - but return KErrNone + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + } + +TInt CCallMobileData::HangUpCancel(const TTsyReqHandle aTsyReqHandle) +// +// Cancel the hang up command. +// + { + LOGTEXT(_L8("DataCall:\tSubmitting Cancel Hang Up command")); + iHangUpData->Stop(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobileData::RelinquishOwnership() +// +// Called by server to tell TSY to either pass ownership on to another interested client +// or hang up immediately. If call is currently connecting, RelinquishOwnershipComplete +// will be called once cancelling has finished. +// + { + LOGTEXT(_L8("DataCall:\tRelinquish Ownership")); + if(iList->iAcquireList.IsEmpty()) + { + if (iDialData->IsPreConnectInProgress() || + iConnectData->IsPreConnectInProgress() || + iAnswerData->IsPreConnectInProgress()) + { + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + return KErrNone; + } + switch(iCallInfo.iMobileStatus) + { + case RMobileCall::EStatusConnected: + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + //iHangUpData->ExecuteCommand(0,NULL,&iCallInfo); + iQuickInit->CancelAndHangUp(&iCallInfo,iHangUpData); + break; + case RMobileCall::EStatusDialling: + case RMobileCall::EStatusConnecting: + case RMobileCall::EStatusAnswering: + case RMobileCall::EStatusDisconnecting: + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + break; + default: + if (iPhoneGlobals->iPhoneStatus.iInitStatus==EPhoneInitialising) + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + else + RelinquishOwnershipCompleted(KErrNone); + break; + } + return KErrNone; + } + CAcquireEntry* entry=iList->iAcquireList.First(); + if (entry) + { + (void)SetOwnership(entry->iTsyReqHandle); + ReqCompleted(entry->iTsyReqHandle,KErrNone); + iList->Remove(entry); + } + RelinquishOwnershipCompleted(KErrNone); + return KErrNone; + } + +TInt CCallMobileData::RecoverDataPortAndRelinquishOwnership() +// +// Called by server to tell TSY to either pass ownership on to another interested client +// after regaining control of the port and performing a swift initialisation, +// or hang up immediately +// + { + LOGTEXT(_L8("DataPort Recover and Relinquish Ownership")); + iCallInfo.iLoanedToClient=EFalse; + iPhoneGlobals->iPhoneStatus.iDataPortLoaned = EFalse; + if(iList->iAcquireList.IsEmpty()) + { + (void)SetUnowned(); + iCallInfo.iClientPanicOccurred = EPanicOccurredDuringDataPortLoan; + iIo->Read(); + iHangUpData->ExecuteCommand(0,NULL,&iCallInfo); + return KErrNone; + } + CAcquireEntry* entry=iList->iAcquireList.First(); + if (entry) + { + (void)SetOwnership(entry->iTsyReqHandle); + ReqCompleted(entry->iTsyReqHandle,KErrNone); + iList->Remove(entry); + iQuickInit->StartQuickInit(); + } + RecoverDataPortAndRelinquishOwnershipCompleted(KErrNone); + return KErrNone; + } + +TInt CCallMobileData::LoanDataPort(const TTsyReqHandle aTsyReqHandle, RCall::TCommPort* aCommPort) +// +// Get the port info +// + { + LOGTEXT(_L8(" DataPort Loan")); + if (CheckOwnership(aTsyReqHandle)!=CCallBase::EOwnedTrue) + { + ReqCompleted(aTsyReqHandle,KErrEtelNotCallOwner); + return KErrNone; + } + if (iCallInfo.iMobileStatus != RMobileCall::EStatusConnected) + { + ReqCompleted(aTsyReqHandle,KErrEtelCallNotActive); + return KErrNone; + } + TInt ret = iPhoneGlobals->iConfiguration->ConfigModemString(TPtrC(KCDTypeNameCsyName),aCommPort->iCsy); + if (!ret) + { + ret = iPhoneGlobals->iConfiguration->ConfigModemString(TPtrC(KCDTypeNamePortName),aCommPort->iPort); + } + if (ret) + { + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + iCallInfo.iLoanedToClient = ETrue; + iPhoneGlobals->iPhoneStatus.iDataPortLoaned = ETrue; + iPhoneGlobals->iNotificationStore->CheckNotification(this,EDataPortLoaned); + iWaitForNoCarrier->StopWait(); + if (iPhoneGlobals->iPhoneStatus.iMode==RPhone::EModeOnlineCommand) + iATSetToOnlineDataMode->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + else + { + iIo->Cancel(); + TCommConfig aConfigPckg; + TInt ret = iPhoneGlobals->iConfiguration->PortConfig(aConfigPckg,EConfigTypeFull); + if (ret==KErrNone) + ret = iIo->ConfigurePort(aConfigPckg); + ReqCompleted(aTsyReqHandle,ret); + } + return KErrNone; + } + +TInt CCallMobileData::LoanDataPortCancel(const TTsyReqHandle aTsyReqHandle) + { + iATSetToOnlineDataMode->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobileData::RecoverDataPort(const TTsyReqHandle aTsyReqHandle) +// +// Take back control of data port +// Check that call had been loaned to client +// + { + if (iCallInfo.iLoanedToClient==EFalse) + { + ReqCompleted(aTsyReqHandle,KErrEtelPortNotLoanedToClient); + return KErrNone; + } + TCallOwnership owner = CheckOwnership(aTsyReqHandle); + if (owner!=CCallBase::EOwnedTrue && owner!=CCallBase::EOwnedPriorityClient) + { + ReqCompleted(aTsyReqHandle,KErrEtelNotCallOwner); + return KErrNone; + } + LOGTEXT(_L8("DataPort Recover")); + iCallInfo.iLoanedToClient=EFalse; + iPhoneGlobals->iPhoneStatus.iDataPortLoaned = EFalse; + LOGTEXT2(_L8("Comm signals : %x"),iIo->Signals()); + iIo->ResetReadAndWriteBuffers(); // in case client has left RxBuffer non-empty + LOGTEXT2(_L8("Comm signals after ResetBuffers : %x"),iIo->Signals()); + FlowControlSuspend(); // Defect fix for MPO-4ZECUN + iQuickInit->StartQuickInit(); + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +// local function needed below + +LOCAL_C void SetFaxSessionSettings(RCall::TFaxSessionSettings& aTrg, const RCall::TFaxSessionSettings& aSrc) + { + aTrg.iMode=aSrc.iMode; + aTrg.iFaxRetrieveType=aSrc.iFaxRetrieveType; + aTrg.iFaxClass=aSrc.iFaxClass; + aTrg.iFaxId=aSrc.iFaxId; + aTrg.iMaxSpeed=aSrc.iMaxSpeed; + aTrg.iMinSpeed=aSrc.iMinSpeed; + aTrg.iPreferredECM=aSrc.iPreferredECM; + aTrg.iFaxOnDemandDelay=aSrc.iFaxOnDemandDelay; + aTrg.iTxResolution=aSrc.iTxResolution; + aTrg.iTxCompression=aSrc.iTxCompression; + aTrg.iTxPages=aSrc.iTxPages; + aTrg.iRxResolution=aSrc.iRxResolution; + aTrg.iRxResolution=aSrc.iRxResolution; + } + +// +// CCallMobileFax - fax call functionality +// At construction, phone init sequence may not have yet determined phone's capabilities so +// create object anyway and check in the function calls whether fax is supported by phone +// + +CCallMobileFax* CCallMobileFax::NewL(CATIO* aATIO,CATInit* aInit,CPhoneGlobals* aPhoneGlobals,const TName& aName) + { + CCallMobileFax* faxCall=new(ELeave) CCallMobileFax(aATIO,aInit,aPhoneGlobals); + TCleanupItem newCallFaxHayesClose(CloseCall,faxCall); + CleanupStack::PushL(newCallFaxHayesClose); + faxCall->ConstructL(aName); + CleanupStack::Pop(); + return faxCall; + } + +CCallMobileFax::CCallMobileFax(CATIO* aATIO,CATInit* aInit,CPhoneGlobals* aPhoneGlobals) + : CCallMobile(aATIO,aInit,aPhoneGlobals),iFaxSession(NULL),iFax(NULL) + {} + +void CCallMobileFax::ConstructL(const TName& aName) + { + CCallHayes::ConstructL(aName); + iCallInfo.iLineOwnerName = KFaxLineName; + iDialFax=CATDialFax::NewL(iIo,this,iInit,iPhoneGlobals); + iConnectFax=CATConnectFax::NewL(iIo,this,iInit,iPhoneGlobals); + iAnswerFax=CATAnswerFax::NewL(iIo,this,iInit,iPhoneGlobals); + iHangUpFax=CATHangUpFax::NewL(iIo,this,iInit,iPhoneGlobals); + iFaxSettings.iMode = RCall::ETransmit; + iFaxSettings.iFaxRetrieveType = RCall::EFaxOnDemand; + iFaxSettings.iFaxClass = EClassAuto; + iFaxSettings.iMaxSpeed = 9600; + iFaxSettings.iMinSpeed = 2400; + iFaxSettings.iPreferredECM = EFalse; + iFaxSettings.iFaxOnDemandDelay = 20; + iFaxSettings.iTxResolution = EFaxNormal; + iFaxSettings.iTxCompression = EModifiedHuffman; + iFaxSettings.iTxPages = 0; + iFaxSettings.iRxResolution = EFaxNormal; + iFaxSettings.iRxCompression = EModifiedHuffman; + iFaxCompletion = new (ELeave) CFaxCompletion(); + iFaxProgress=CreateFaxProgressChunk(); + if(iFaxProgress==NULL) + User::Leave(KErrEtelFaxChunkNotCreated); + } + +CCallMobileFax::~CCallMobileFax() +// +// Removes itself from array of calls in CLineMobileData +// + { + __ASSERT_DEBUG(iFaxSession==NULL,Panic(EFaxServerNotNull)); + DeleteFaxProgressChunk(); // This deallocates the memory pointed to by iFaxProgress + delete iDialFax; + delete iConnectFax; + delete iAnswerFax; + delete iHangUpFax; + delete iFaxCompletion; + delete iFileHandles; + } + +void CCallMobileFax::CollateCoreCaps(const TTsyReqHandle aTsyReqHandle, TUint32* aCallCaps) + { + *aCallCaps = RCall::KCapsFax; + if (ValidateFaxClass(iFaxSettings.iFaxClass)==KErrNone + && (!(REINTERPRET_CAST(CLineMobileFax*,Owner())->iFaxOpened==TRUE && iFax==NULL)) + && iPhoneGlobals->iPhoneStatus.iModemDetected==RPhone::EDetectedPresent) + // check that fax class is OK and that no other fax call has opened a fax object + { + TCallOwnership owner = CheckOwnership(aTsyReqHandle); + if (ValidateRequest(aTsyReqHandle,RCall::EStatusIdle)==KErrNone) + *aCallCaps |= (RCall::KCapsDial | RCall::KCapsConnect); + TInt ret=KErrNone; + if (owner==CCallBase::EOwnedFalse) // call owned by another client + ret=KErrEtelNotCallOwner; + else + { + if (!iIsForIncomingCall) + { + if (REINTERPRET_CAST(CPhoneHayes*,Owner()->Owner())->CheckForOutstandingAnswer()) + ret=KErrEtelAnswerAlreadyOutstanding; + } + else + ret=KErrEtelAnswerAlreadyOutstanding; + } + if (ret==KErrNone && (iCallInfo.iMobileStatus==RMobileCall::EStatusIdle || iCallInfo.iMobileStatus==RMobileCall::EStatusRinging)) + *aCallCaps |= RCall::KCapsAnswer; + if (owner==CCallBase::EOwnedTrue && iCallInfo.iMobileStatus==RMobileCall::EStatusConnected) + { + *aCallCaps |= RCall::KCapsHangUp; + } + } + } + +TInt CCallMobileFax::OpenFax(TDesC* aTelNumber,TFaxMode aFaxMode) +// +// Open CETelFaxHayes object with desired settings +// + { + TFaxServerSessionSettings faxSettings; + faxSettings.iPhoneNumber.Copy(*aTelNumber); + faxSettings.iLogging = ETrue; + TInt ret = iPhoneGlobals->iConfiguration->ConfigModemString(TPtrC(KCDTypeNameFaxInitString),faxSettings.iFaxInitString); + if (!ret) + { + ret = iPhoneGlobals->iConfiguration->ConfigModemString(TPtrC(KCDTypeNameCsyName),faxSettings.iPortDriverName); + } + if (!ret) + { + ret = iPhoneGlobals->iConfiguration->ConfigModemString(TPtrC(KCDTypeNamePortName),faxSettings.iCommPortName); + } + if (ret) + return ret; + if(faxSettings.iFaxInitString.Length()==0) + faxSettings.iFaxInitString=KAT2Command; + faxSettings.iMode = aFaxMode; + faxSettings.iFaxClass = iFaxSettings.iFaxClass; + faxSettings.iFaxId = iFaxSettings.iFaxId; + faxSettings.iMaxSpeed = iFaxSettings.iMaxSpeed; + faxSettings.iMinSpeed = iFaxSettings.iMinSpeed; + faxSettings.iPreferredECM = iFaxSettings.iPreferredECM; + faxSettings.iFaxOnDemandDelay = iFaxSettings.iFaxOnDemandDelay; + faxSettings.iTxResolution = iFaxSettings.iTxResolution; + faxSettings.iTxCompression = iFaxSettings.iTxCompression; + faxSettings.iTxPages = iFaxSettings.iTxPages; + faxSettings.iRxResolution = iFaxSettings.iRxResolution; + faxSettings.iRxCompression = iFaxSettings.iRxCompression; + return iFaxSession->FxOpen(faxSettings,iFaxProgress); + } + +TInt CCallMobileFax::ValidateFaxClass(TFaxClass& aFaxClass) + { + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & KFaxCaps) == 0) + { + return KErrNotSupported; + } + switch (aFaxClass) + { + case EClassAuto: // TSY decides what class "AUTO" refers to! + { + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassTwoPointZero)) + aFaxClass = EClass2point0; + else if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassTwo)) + aFaxClass = EClass2; + else if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassOne)) + aFaxClass = EClass1; + break; + } + case EClass1: + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassOne)==0) + return KErrEtelWrongModemType; + break; + case EClass1point0: + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassOnePointZero)==0) + return KErrEtelWrongModemType; + break; + case EClass2: + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassTwo)==0) + return KErrEtelWrongModemType; + break; + case EClass2point0: + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassTwoPointZero)==0) + return KErrEtelWrongModemType; + break; + case EClass2point1: + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & RPhone::KCapsFaxClassTwoPointOne)==0) + return KErrEtelWrongModemType; + break; + default: + return KErrEtelWrongModemType; + } + return KErrNone; + } + +typedef CFaxSession* (*TFaxServerEntry)(); +void CCallMobileFax::GetFaxBaseL() + { + __ASSERT_DEBUG(iFaxCompletion,Panic(EFaxCompletionPtrNull)); + RFs fs; + (void)User::LeaveIfError(fs.Connect()); + + TInt r=iFaxServerLib.Load(KFaxServerName); + if (r==KErrNone) + { + // Check the Uid2 +#if defined (_UNICODE) + if(iFaxServerLib.Type()[1]!=TUid::Uid(KUidUnicodeDynamicFaxServer)) + r = KErrBadLibraryEntryPoint; +#else + if(iFaxServerLib.Type()[1]!=TUid::Uid(KUidDynamicFaxServer)) + r = KErrBadLibraryEntryPoint; +#endif + if (r==KErrNone) + { + TFaxServerEntry libEntry=(TFaxServerEntry)iFaxServerLib.Lookup(1); + if (libEntry!=NULL) + { + TRAP(r,iFaxSession=(*libEntry)()); // libEntry may leave. + if (r==KErrNone) + { + LOGTEXT(_L8("Loaded Fax Server")); + iFaxSession->SetCallBack(iFaxCompletion); + } + else + iFaxServerLib.Close(); + } + else + { + r = KErrBadLibraryEntryPoint; + iFaxServerLib.Close(); + } + } + else + iFaxServerLib.Close(); + } + fs.Close(); + (void)User::LeaveIfError(r); + } + +TInt CCallMobileFax::FaxConnectHandler(const TTsyReqHandle aTsyReqHandle) + { + TInt ret = ValidateFaxClass(iFaxSettings.iFaxClass); + if (ret!=KErrNone) + { + (void)SetUnowned(); + ReqCompleted(aTsyReqHandle,ret); + return ret; + } + if (REINTERPRET_CAST(CLineMobileFax*,Owner())->iFaxOpened==TRUE && iFax==NULL) + { + (void)SetUnowned(); + ReqCompleted(aTsyReqHandle,KErrEtelNotFaxOwner); + return ret; + } + + TRAPD(res,GetFaxBaseL()); + if (res!=KErrNone) + { + (void)SetUnowned(); + ReqCompleted(aTsyReqHandle,res); + } + iPhoneGlobals->iEventSignalActive = EFalse; + return res; + } + +void CCallMobileFax::FaxDial(const TTsyReqHandle aTsyReqHandle,TDesC* aTelNumber) +// +// Called once any initialising has been done. Checks here that modem supports fax, +// and that no other CCallHayes has opened a fax object +// + { + if (FaxConnectHandler(aTsyReqHandle)!=KErrNone) // ReqCompleted is called inside FaxConnectHandler + // if there is an error + return; + TFaxMode faxMode; + if (iFaxSettings.iMode==RCall::ETransmit) + { + faxMode = EDialAndTransmit; + } + else // we're receiving + { + if (iFaxSettings.iFaxRetrieveType==RCall::EFaxPoll) + faxMode = EDialAndReceivePoll; + else + faxMode = EDialAndReceiveFaxBack; + } + TInt res = OpenFax(aTelNumber,faxMode); + if (res!=KErrNone) // make sure cleaned up. + { + ReqCompleted(aTsyReqHandle,res); + return; + } + ChangeLineStatus(RCall::EStatusDialling); + // EStatusDialling always results in KErrNone return + (void) ChangeCallStatus(RMobileCall::EStatusDialling); + iPhoneGlobals->iNotificationStore->CheckNotification(this,EBegunConnecting); + iFaxCompletion->Configure(aTsyReqHandle,this); + iIo->Cancel(); + iPhoneGlobals->iPhoneStatus.iPortAccess = EPortAccessDenied; // so CATIO won't queue a read + + if (faxMode == EDialAndTransmit) + { + LOGTEXT(_L8("About to call CETelFaxBase::TxConnect")); + //this transfers ownership of the file handles object to the fax session object. + iFaxSession->SetFaxHeaderFile(iFileHandles); + //we now aren't resonsible for its deletion. + iFileHandles = NULL; + iFaxSession->TxConnect(); + } + else + { + LOGTEXT(_L8("About to call CETelFaxBase::RxConnect")); + iFaxSession->RxConnect(); + } + } + +TInt CCallMobileFax::Dial(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* aTelNumber) +// +// Dial a fax call +// Check that call is not owned by another client, and line is idle +// + { + TInt ret = ValidateRequest(aTsyReqHandle,RCall::EStatusIdle); + if (ret==KErrNone) + { + (void)SetOwnership(aTsyReqHandle); + SetCallParams(aCallParams); + LOGTEXT(_L8("FaxCall:\tSubmitting Dial Command")); + iDialFax->ExecuteCommand(aTsyReqHandle,aTelNumber,&iCallInfo); + } + else + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + +void CCallMobileFax::FaxCancelCommand(const TTsyReqHandle aTsyReqHandle) +// +// Cancels the fax session (for ConnectCancel and AnswerCancel as well) +// + { + LOGTEXT(_L8("FaxCall:\tCancel Fax call and Unload module")); + if(!iFaxSession) // if iFaxSession is NULL + { // then CleanUpFaxServer has already been called + LOGTEXT(_L8("FaxCall:\tModule already unloaded, completing...")); + ReqCompleted(aTsyReqHandle,KErrCancel); // so return without further processing + return; + } + + LOGTEXT(_L8("FaxCall:\tClosing down fax server module")); + iFaxSession->Cancel(); + CleanUpFaxServer(); + iIo->Read(); + SetToIdle(); + ReqCompleted(aTsyReqHandle,KErrCancel); + } + +TInt CCallMobileFax::DialCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT2(_L8("FaxCall:\tDialCancel(%d) called"),aTsyReqHandle); + iDialFax->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +void CCallMobileFax::FaxConnect(const TTsyReqHandle aTsyReqHandle) +// +// Called once any initialising has been done. Checks here that modem supports fax. +// + { + if (FaxConnectHandler(aTsyReqHandle)!=KErrNone) + return; + TFaxMode faxMode; + if (iFaxSettings.iMode==RCall::ETransmit) + faxMode = EImmediateTransmit; + else + faxMode = EImmediateReceive; + TBuf<1> null; + null.Zero(); + TInt res = OpenFax(&null,faxMode); + if (res!=KErrNone) + { + ReqCompleted(aTsyReqHandle,res); + return; + } + ChangeLineStatus(RCall::EStatusConnecting); + // EStatusConnecting always returns KErrNone + (void)ChangeCallStatus(RMobileCall::EStatusConnecting); + iPhoneGlobals->iNotificationStore->CheckNotification(this,EBegunConnecting); + iFaxCompletion->Configure(aTsyReqHandle,this); + iIo->Cancel(); + iPhoneGlobals->iPhoneStatus.iPortAccess = EPortAccessDenied; // so CATIO won't queue a read + if (faxMode == EImmediateTransmit) + iFaxSession->TxConnect(); + else + iFaxSession->RxConnect(); + } + +TInt CCallMobileFax::Connect(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams) +// +// Immediate connect to a fax call +// Check that call is not owned by another client, and line is idle +// + { + TInt ret = ValidateRequest(aTsyReqHandle,RCall::EStatusIdle); + if (ret==KErrNone) + { + (void)SetOwnership(aTsyReqHandle); + SetCallParams(aCallParams); + LOGTEXT(_L8("FaxCall:\tSubmitting Connect Command")); + iConnectFax->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + } + else + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + +TInt CCallMobileFax::ConnectCancel(const TTsyReqHandle aTsyReqHandle) + { + LOGTEXT2(_L8("FaxCall:\tConnectCancel(%d) called"),aTsyReqHandle); + iConnectFax->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +void CCallMobileFax::FaxAnswer(const TTsyReqHandle aTsyReqHandle) + { + if (FaxConnectHandler(aTsyReqHandle)!=KErrNone) + return; + TFaxMode faxMode; + if (iFaxSettings.iMode==RCall::ETransmit) + faxMode = EWaitForRingAndTransmit; + else + faxMode = EWaitForRingAndReceive; + TBuf<1> null; + null.Zero(); + TInt res = OpenFax(&null,faxMode); + if (res!=KErrNone) + { + ReqCompleted(aTsyReqHandle,res); + return; + } + LOGTEXT(_L8("FaxCall:\tAnswering Fax call")); + ChangeLineStatus(RCall::EStatusAnswering); + // EStatusAnswering always results in KerrNone return + (void)ChangeCallStatus(RMobileCall::EStatusAnswering); + CPhoneHayes* phone=STATIC_CAST(CPhoneHayes*,Owner()->Owner()); + phone->StopRingCounter(); // RING should no longer come in + iPhoneGlobals->iNotificationStore->CheckNotification(this,EBegunConnecting); + iFaxCompletion->Configure(aTsyReqHandle,this); + iIo->Cancel(); + iPhoneGlobals->iPhoneStatus.iPortAccess = EPortAccessDenied; // so CATIO won't queue a read + if (faxMode == EWaitForRingAndTransmit) + iFaxSession->TxConnect(); + else + iFaxSession->RxConnect(); + } + +TInt CCallMobileFax::AnswerIncomingCall(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams) +// +// Answer a fax call +// + { + TInt ret=KErrNone; + CCallBase::TCallOwnership owned = CheckOwnership(aTsyReqHandle); + if (owned==CCallBase::EOwnedFalse) // call owned by another client + { + ret=KErrEtelNotCallOwner; + } + else if (REINTERPRET_CAST(CPhoneHayes*,Owner()->Owner())->CheckForOutstandingAnswer()) + ret=KErrEtelAnswerAlreadyOutstanding; + + if (ret==KErrNone) + { + CLineHayes* line = STATIC_CAST(CLineHayes*,Owner()); + CPhoneHayes* phone=STATIC_CAST(CPhoneHayes*,line->Owner()); + phone->CancelOtherRingingCall(line); + line->FreePreAllocCallIfNecessary(); + SetCallParams(aCallParams); + if (iCallInfo.iMobileStatus==RMobileCall::EStatusRinging) + { + LOGTEXT(_L8("FaxCall:\tSubmitting Answer Command")); + iAnswerFax->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + } + else // This call is now a client-designated Incoming Call object. + { + iIsForIncomingCall=ETrue; + iAnswerTsyReqHandle = aTsyReqHandle; + } + return KErrNone; + } + ReqCompleted(aTsyReqHandle,ret); + return KErrNone; + } + +TInt CCallMobileFax::AnswerIncomingCallCancel(const TTsyReqHandle aTsyReqHandle) +// +// Cancel the answer command if possible +// + { + LOGTEXT2(_L8("FaxCall:\tAnswerCancel(%d) called"),aTsyReqHandle); + if (iIsForIncomingCall) + { + iIsForIncomingCall=EFalse; + ReqCompleted(aTsyReqHandle,KErrCancel); + } + else + iAnswerFax->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +void CCallMobileFax::AnswerImmediately() + { + (void)SetOwnership(iAnswerTsyReqHandle); + // EStatusRinging always results in KErrNone return + (void)ChangeCallStatus(RMobileCall::EStatusRinging);// new 14/1/99 + iPhoneGlobals->iNotificationStore->CheckNotification(this,ERingOccurred); + iIsForIncomingCall=EFalse; + LOGTEXT(_L8("FaxCall:\tSubmitting Answer command")); + iAnswerFax->ExecuteCommand(iAnswerTsyReqHandle,NULL,&iCallInfo); + } + +void CCallMobileFax::FaxHangUp(const TTsyReqHandle aTsyReqHandle) +// +// Fax server reconfigures port so no need to here. +// + { + if (iFaxSession) + { + // EStatusDisconnecting always results in KErrNone return + (void)ChangeCallStatus(RMobileCall::EStatusDisconnecting); + ChangeLineStatus(RCall::EStatusHangingUp); + iPhoneGlobals->iNotificationStore->CheckNotification(this,EBegunHangingUp); + CleanUpFaxServer(); + iIo->Read(); + SetToIdle(); + } + ReqCompleted(aTsyReqHandle,KErrNone); + } + +TInt CCallMobileFax::HangUp(const TTsyReqHandle aTsyReqHandle) +// +// Terminate a fax call. Checks fax capability, call ownership and line status. +// + { + if ((iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags & KFaxCaps) == 0) + { + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + if (CheckOwnership(aTsyReqHandle)==CCallBase::EOwnedFalse) + { + ReqCompleted(aTsyReqHandle,KErrEtelNotCallOwner); + return KErrNone; + } + if (iPhoneGlobals->iPhoneStatus.iLineStatus != RCall::EStatusConnected) + { + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + LOGTEXT(_L8("FaxCall:\tHanging up")); + iHangUpFax->ExecuteCommand(aTsyReqHandle,NULL,&iCallInfo); + return KErrNone; + } + +TInt CCallMobileFax::HangUpCancel(const TTsyReqHandle aTsyReqHandle) + { + iHangUpFax->CancelCommand(aTsyReqHandle); + return KErrNone; + } + +TInt CCallMobileFax::RelinquishOwnership() +// +// Called by server to tell TSY to either pass ownership on to another interested client +// or hang up immediately +// + { + LOGTEXT(_L8("FaxCall:\tRelinquish Ownership")); + if(iList->iAcquireList.IsEmpty()) + { + if (iDialFax->IsPreConnectInProgress() || + iConnectFax->IsPreConnectInProgress() || + iAnswerFax->IsPreConnectInProgress()) // fax server has not yet been started + { + iCallInfo.iClientPanicOccurred = EPanicOccurredWithoutDataPortLoan; + return KErrNone; + } + (void)SetUnowned(); + TInt ret = KErrNone; + if (iCallInfo.iMobileStatus==RMobileCall::EStatusDialling || + iCallInfo.iMobileStatus==RMobileCall::EStatusConnecting || + iCallInfo.iMobileStatus==RMobileCall::EStatusAnswering || + iCallInfo.iMobileStatus==RMobileCall::EStatusConnected || + iCallInfo.iMobileStatus==RMobileCall::EStatusDisconnecting + ) + { + LOGTEXT(_L8("FaxCall:\tHanging up")); + ChangeLineStatus(RCall::EStatusHangingUp); + // EStatusDisconnecting always results in KErrNone return + (void)ChangeCallStatus(RMobileCall::EStatusDisconnecting); + CleanUpFaxServer(); + ChangeLineStatus(RCall::EStatusIdle); + // EStatusIdle always results in KErrNone return + (void)ChangeCallStatus(RMobileCall::EStatusIdle); + iPhoneGlobals->iPhoneStatus.iMode = RPhone::EModeIdle; + iIo->Cancel(); + TCommConfig aConfigPckg; + TInt ret = iPhoneGlobals->iConfiguration->PortConfig(aConfigPckg,EConfigTypeInit); + if (ret==KErrNone) + ret = iIo->ConfigurePort(aConfigPckg); + if (ret) + iPhoneGlobals->iPhoneStatus.iInitStatus = EPhoneNotInitialised; + else + iIo->Read(); // should a read be queued in this case? + } + RelinquishOwnershipCompleted(ret); + return KErrNone; + } + CAcquireEntry* entry=iList->iAcquireList.First(); + if (entry) + { + (void)SetOwnership(entry->iTsyReqHandle); + ReqCompleted(entry->iTsyReqHandle,KErrNone); + iList->Remove(entry); + } + RelinquishOwnershipCompleted(KErrNone); + return KErrNone; + } + +TInt CCallMobileFax::GetFaxSettings(const TTsyReqHandle aTsyReqHandle,RCall::TFaxSessionSettings* aSettings) +// +// Which are stored privately in CCallMobileFax +// + { + LOGTEXT(_L8("FaxCall:\tGetting fax settings")); + SetFaxSessionSettings(*aSettings,iFaxSettings); + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +TInt CCallMobileFax::SetFaxSettings(const TTsyReqHandle aTsyReqHandle,const RCall::TFaxSessionSettings* aSettings) + { + LOGTEXT(_L8("FaxCall:\tSetting fax settings")); + TUint phoneCaps = iPhoneGlobals->iPhoneStatus.iDataAndFaxFlags; + if (aSettings->iFaxClass==EClass1 && (phoneCaps&RPhone::KCapsFaxClassOne) || + aSettings->iFaxClass==EClass2 && (phoneCaps&RPhone::KCapsFaxClassTwo) || + aSettings->iFaxClass==EClass2point0 && (phoneCaps&RPhone::KCapsFaxClassTwoPointZero) || + aSettings->iFaxClass==EClass1point0 && (phoneCaps&RPhone::KCapsFaxClassOnePointZero) || + aSettings->iFaxClass==EClass2point1 && (phoneCaps&RPhone::KCapsFaxClassTwoPointOne) || + aSettings->iFaxClass==EClassAuto) + { + SetFaxSessionSettings(iFaxSettings,*aSettings); + ReqCompleted(aTsyReqHandle,KErrNone); + } + else if (iPhoneGlobals->iPhoneStatus.iInitStatus!=EPhoneInitialised) + ReqCompleted(aTsyReqHandle,KErrEtelUnknownModemCapability); + else + ReqCompleted(aTsyReqHandle,KErrNotSupported); + return KErrNone; + } + +TInt CCallMobileFax::SetFaxSharedHeaderFile(const TTsyReqHandle aTsyReqHandle, CFaxSharedFileHandles* aFaxSharedFileHandles) + { + //if we already own an object delete and re-point to new one. + if(iFileHandles) + { + delete iFileHandles; + iFileHandles = NULL; + } + iFileHandles = aFaxSharedFileHandles; + + ReqCompleted(aTsyReqHandle,KErrNone); + return KErrNone; + } + +CTelObject* CCallMobileFax::OpenNewObjectByNameL(const TDesC& /*aName*/) +// +// Only want one CFaxHayes object to be opened per phone. +// Previously only the connected call could open a CFaxHayes object, so it was easy to check +// whether one had already been opened. Now a fax call can open a fax object at any time +// making it less clear how to check that no other call has opened one. +// + { + if (iPhoneGlobals->iPhoneStatus.iLineStatus != GetCoreCallStatus()) + { // ie another fax call is in progress so this call cannot open a fax object + User::Leave(KErrEtelNotCallOwner); + } + TBool& faxOpened = REINTERPRET_CAST(CLineMobileFax*,Owner())->iFaxOpened; + if (faxOpened==TRUE) + { + User::Leave(KErrAlreadyExists); + } + faxOpened=ETrue; + iFax = CFaxHayes::NewL(this,iPhoneGlobals); + return iFax; + } + +void CCallMobileFax::RemoveFax(CFaxHayes* aFaxHayes) + { + if (iFax == aFaxHayes) + iFax=NULL; + REINTERPRET_CAST(CLineMobileFax*,Owner())->iFaxOpened=EFalse; + } + +void CCallMobileFax::CleanUpFaxServer() + { + LOGTEXT(_L8("Closing down Fax Server")); + (void)iFaxSession->FxClose(); + iFaxServerLib.Close(); + iFaxSession = NULL; + iPhoneGlobals->iPhoneStatus.iPortAccess = EPortAccessAllowed; + iPhoneGlobals->iEventSignalActive = EFalse; + }