telephonyserverplugins/multimodetsy/hayes/CALL.CPP
changeset 0 3553901f7fa8
child 20 244d7c5f118e
--- /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 <commsdattypesv1_1.h>
+#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 <et_clsvr.h>
+#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<CAcquireEntry> 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<RCall::TCallParams>* paramsPckg = (TPckg<RCall::TCallParams>*)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<RCall::TCallParams>* paramsPckg = (TPckg<RCall::TCallParams>*)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<RCall::TStatus>(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<TUint32*>(&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<RMobileCall::TMobileCallDataCapsV1>* pckg = (TPckg<RMobileCall::TMobileCallDataCapsV1>*)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<KGenericBufferSize>& 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 <speed> value we can not send the command.
+	// If we do not have a <ce> value then we can send a command giving only <speed> and <name>.
+	// etc...
+	if(speedSet)
+		{
+		aTxBuffer.Zero();		// Clear tx buffer
+
+		// Append +CBST= and the <speed> parameter
+		aTxBuffer.Append(KDataCallBearerServiceType);
+		aTxBuffer.AppendNum(speed);
+		
+		if(nameSet)
+			{
+			// Append the <name> parameter
+			aTxBuffer.Append(TChar(',')); 
+			aTxBuffer.AppendNum(name);
+
+			if(ceSet)
+				{
+				// Append the <ce> 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;				
+	}