telephonyserverplugins/multimodetsy/Multimode/sms/mSMSSEND.CPP
branchopencode
changeset 24 6638e7f4bd8f
parent 0 3553901f7fa8
--- a/telephonyserverplugins/multimodetsy/Multimode/sms/mSMSSEND.CPP	Mon May 03 13:37:20 2010 +0300
+++ b/telephonyserverplugins/multimodetsy/Multimode/sms/mSMSSEND.CPP	Thu May 06 15:10:38 2010 +0100
@@ -1,641 +1,641 @@
-// 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:
-// Implementation of CATSmsMessagingSend.
-// 
-//
-
-/**
- @file
-*/
-
-
-#include <etelmm.h>
-
-#include "NOTIFY.H"
-#include "mSMSMESS.H"
-#include "mSMSSEND.H"
-#include "mSLOGGER.H"
-#include "ATIO.H"
-#include "smsutil.h"	// for CATSmsUtils
-
-//
-// Constants
-//
-const TInt KPduMode=0;
-
-//
-// Macros
-//
-
-#ifdef __LOGDEB__
-_LIT8(KLogEntry,"CATSmsMessagingSend::%S\t%S");
-#define LOCAL_LOGTEXT(function,text) {_LIT8(F,function);_LIT8(T,text);LOGTEXT3(KLogEntry,&F,&T);}
-#else
-#define LOCAL_LOGTEXT(function,text)
-#endif
-
-/**
- * CANCEL_AND_RETURN_IF_NEEDED
- * Used to implement cancellation at safe points inside CATSmsMessagingSend::EventSignal
- */
-#define CANCEL_AND_RETURN_IF_NEEDED()\
-{\
-if(iStop)\
-	{\
-	Complete(KErrCancel);\
-	LOCAL_LOGTEXT("CANCEL_AND_RETURN_IF_NEEDED","Cancelled");\
-	return;\
-	}\
-}
-
-
-//
-// Class Implementation
-//
-CATSmsMessagingSend* CATSmsMessagingSend::NewL(	CATIO* aIo,
-												CTelObject* aTelObject,
-												CATInit* aInit,
-												CPhoneGlobals* aGsmStatus)
-/**
- * Creates a new instance of CATSmsMessagingSend
- */
-	{
-	CATSmsMessagingSend* self=new(ELeave) CATSmsMessagingSend(aIo,aTelObject,aInit,aGsmStatus);
-	CleanupStack::PushL(self);
-	self->ConstructL();
-	CleanupStack::Pop();
-	return self;
-	}
-
-CATSmsMessagingSend::CATSmsMessagingSend(	CATIO* aIo,
-											CTelObject* aTelObject,
-											CATInit* aInit,
-											CPhoneGlobals* aGsmStatus)
-	:CATSmsCommands(aIo,aTelObject,aInit,aGsmStatus)
-/**
- * C++ constructor
- */
-{}
-
-void CATSmsMessagingSend::ConstructL()
-/**
- * 2nd phase contructor
- */
-	{
-	CATCommands::ConstructL();
-	iMsgDataAscii.Zero();			// Just in case
-	}
-
-CATSmsMessagingSend::~CATSmsMessagingSend()
-/**
- * C++ destructor
- */
-	{
-	delete iMsgData;
-	}
-
-void CATSmsMessagingSend::Start(TTsyReqHandle aTsyReqHandle,TAny* aParams)
-/**
- * Starts the procedure of sending an SMS
- * @param aTsyReqHandle Handle to client, to be completed when operation done
- * @param aParams Pointer to the SMS PDU (with or without SC prefixed) to be sent 
- */
-	{
-	LOCAL_LOGTEXT("Start","Have been requested to send a message");
-	
-	// Intialize data 
-	iHaveRetriedWithOtherPduStd=EFalse;
-	iStop=EFalse;
-
-	// ::SetMsgAttributes must be called before ::Start is called
-	__ASSERT_DEBUG(iMsgAttributes,Panic(EATSmsMessagingSendNullMsgAttributes));		
-
-	// Save access to the data we be given thru our parameters
-	iReqHandle=aTsyReqHandle;
-	delete iMsgData;		// Ensure we don't orphan some memory
-	iMsgData=((TDesC8*)aParams)->Alloc();
-	if(!iMsgData)
-		Complete(KErrNoMemory);
-
-	// Kick off first AT stuff
-	LOCAL_LOGTEXT("Start","Setting phone to PDU mode (as opposed to text mode)");
-	iTxBuffer.Format(KSmsFormatCommand,KPduMode);
-	WriteTxBufferToPhone(ESetPhoneToPDUMode);
-	}
-
-
-void CATSmsMessagingSend::StartFindSCA()
-/**
- * Attempt to find an SCA to use when sending message.
- * The following SCA sources are checked in this order...
- *    Supplied by client in iMsgAttributes.iSc
- *    Use default SCA in the phone's memory
- *	  Use default SCA in the phone's memory after doing 'AT+CRES=1'
- */
-	{
-	LOCAL_LOGTEXT("StartFindSCA","");
-
-	// Did client supply SCA in iMsgAttributes.iSc
-	if(iMsgAttributes->iFlags&RMobileSmsMessaging::KGsmServiceCentre && iMsgAttributes->iGsmServiceCentre.iTelNumber.Length()!=0)
-		{
-		iMsgSCA=iMsgAttributes->iGsmServiceCentre;
-		DoneFindSCA();
-		}
-
-	// Does the phone have a default SCA in memory
-	else
-		{
-		TInt ret=CATSmsCommands::RequestATCommand(CATSmsCommands::EGetSCAFromPhone);
-		if(ret!=KErrNone)
-			Complete(ret);
-		}
-	
-	}
-
-
-void CATSmsMessagingSend::DoneFindSCA()
-	{
-	LOCAL_LOGTEXT("DoneFindSCA","");
-	// At this point in the execution we can guarantee that...
-	//	iMsgData holds the PDU to be sent in binary format without a prepended SCA
-	//	iMsgSCA holds the SCA to be used to send the PDU
-
-	// Check we can handle the Type-Of-Address of the SCA
-	if(!(iMsgSCA.iNumberPlan==RMobilePhone::EIsdnNumberPlan &&
-	   (iMsgSCA.iTypeOfNumber==RMobilePhone::EInternationalNumber ||
-		iMsgSCA.iTypeOfNumber==RMobilePhone::EUnknownNumber)))
-		{
-		LOCAL_LOGTEXT("DoneFindSCA","SCA type unsupported");
-		Complete(KErrCorrupt);
-		return;
-		}
-
-	// Check which ETSI standard we think phone conforms to
-	if(PhoneUsesNewPDUStandard())
-		SendMessageToNewPhone();
-	else
-		SendMessageToOldPhone();
-	}
-
-
-void CATSmsMessagingSend::SendMessageToOldPhone()
-/**
- * Send message to phone which uses new ETSI standard (no SCA prefixed to PDU expected,
- * use phone's default SCA setting instead).
- */
- 	{
-	LOCAL_LOGTEXT("SendMessageToOldPhone","");
-	// Set the SCA to use as the default in the phone's memory
-	iRequestSCA=iMsgSCA;
-	TInt ret=CATSmsCommands::RequestATCommand(CATSmsCommands::ESetSCAInPhone);
-	if(ret!=KErrNone)
-		Complete(ret);
-	}
-
-
-void CATSmsMessagingSend::SendMessageToOldPhone_Stage2()
-	{
-	// Convert PDU from binary to ASCII
-	iMsgDataAscii.Zero();
-	CATSmsUtils::AppendDataToAscii(iMsgDataAscii,*iMsgData);
-	if(iMsgDataAscii.Length()==0)
-		{
-		LOCAL_LOGTEXT("SendMessageToOldPhone_Stage2","Failed to convert binary PDU to ASCII");
-		Complete(KErrCorrupt);
-		return;
-		}
-
-	// Send PDU length to the phone
-	const TInt pduLengthSemiOctets(iMsgDataAscii.Length());
-	const TInt pduLengthOctets(pduLengthSemiOctets/2+pduLengthSemiOctets%2);
-	iTxBuffer.Format(KSmsSendPduLengthCommand,pduLengthOctets);
-	WriteTxBufferToPhone(ESendPDULengthToPhone);
-	}
-
-void CATSmsMessagingSend::SendPDUToPhone()
-	{
-	LOCAL_LOGTEXT("SendPDUToPhone","");
-	// Send PDU to phone 
-	iTxBuffer.Format(iMsgDataAscii);
-	iTxBuffer.Append(KCtrlZChar);
-	WriteTxBufferToPhone(ESendPDUToPhone);
-	}
-
-void CATSmsMessagingSend::SendPDUToPhone_Stage2()
-	{
-	// Get the message reference number & submit report and then we've finished 
-	Complete(ParseCMGSResponse());
-	}
-
-void CATSmsMessagingSend::SendMessageToNewPhone()
-/**
- * Send message to phone which uses new ETSI standard (SCA prefixed to PDU expected).
- */
-	{
-	LOCAL_LOGTEXT("SendMessageToNewPhone","");
-
-	// Convert SCA to ASCII (ensure that 03.40 format is used to create SCA)
-	iMsgDataAscii.Zero();
-	if(CATSmsUtils::AppendAddressToAscii(iMsgDataAscii,iMsgSCA,ETrue)!=KErrNone || iMsgDataAscii.Length()==0)
-		{
-		LOCAL_LOGTEXT("SendMessageToNewPhone","Failed to prepend SCA to PDU");
-		Complete(KErrCorrupt);
-		return;
-		}
-	
-	// Convert PDU to ASCII
-	const TInt msgDataAsciiLen(iMsgDataAscii.Length());
-	CATSmsUtils::AppendDataToAscii(iMsgDataAscii,*iMsgData);
-	if(iMsgDataAscii.Length()==msgDataAsciiLen)
-		{
-		LOCAL_LOGTEXT("SendMessageToNewPhone","Failed to convert binary PDU to ASCII");
-		Complete(KErrCorrupt);
-		return;
-		}
-
-	// Send PDU length to the phone
-	const TInt pduLengthSemiOctets(iMsgDataAscii.Length()-msgDataAsciiLen);	// Must not include the prefixed SCA in calculation
-	const TInt pduLengthOctets(pduLengthSemiOctets/2+pduLengthSemiOctets%2);
-	iTxBuffer.Format(KSmsSendPduLengthCommand,pduLengthOctets);
-	WriteTxBufferToPhone(ESendPDULengthToPhone);
-	}
-
-
-void CATSmsMessagingSend::EventSignal(TEventSource aSource)
-/**
- * Handle the events from the comm port
- *
- * This code is first called after the phone has been set to PDU mode.
- * First we find the SCA that we are going to use. 
- * Secondly we send the message to the phone depending on whether the phone seems to be using 
- * the new ETSI format (SCA prefixed to PDU expected) or the old ETSI format (no SCA prefixed
- * to PDU expected).
- *
- * @param aSource denotes if event is due to read, write or timeout
- */
-	{
-	LOCAL_LOGTEXT("EventSignal","");
-	LOGTEXT3(_L8("iState=%D iSource=%D"),iState,aSource);
-	LOGTEXT2(_L8("iStop=%D"),iStop);
-
-	// Check to see if this class or our base class need to process the event
-	if(CATSmsCommands::RequestATActive())
-		{
-		//
-		// Allow base class to handle event, and find out if a request completed
-		//
-		CATSmsCommands::EventSignal(aSource);
-		const CATSmsCommands::TRequest reqCompleted(CATSmsCommands::RequestATCompleted());
-
-		if(reqCompleted!=ENone)
-			CANCEL_AND_RETURN_IF_NEEDED();
-
-		// Otheriwse, Check if a request completed as a result of the event processing
-		switch(reqCompleted)
-			{
-		case CATSmsCommands::EGetSCAFromPhone:
-			LOCAL_LOGTEXT("EventSignal","EGetSCAFromPhone completed");
-			if(iRequestError==KErrNone)
-				{
-				iMsgSCA=iRequestSCA;
-				DoneFindSCA();
-				}
-			else
-				{
-				LOCAL_LOGTEXT("EventSignal","Failed to find an SCA to use");
-				Complete(iRequestError,aSource);
-				}
-			break;
-
-		case CATSmsCommands::ESetSCAInPhone:
-			LOCAL_LOGTEXT("EventSignal","ESetSCAInPhone completed");
-			if(iRequestError==KErrNone)
-				SendMessageToOldPhone_Stage2();
-			else
-				{
-				LOCAL_LOGTEXT("EventSignal","Failed to set SCA in phone");
-				Complete(iRequestError,aSource);
-				}
-			break;
-
-		case CATSmsCommands::ENone:	// Must not be caught by default case 
-			break;
-		default:
-			LOCAL_LOGTEXT("EventSignal","CATSmsCommands unknown request completed");
-			__ASSERT_DEBUG(EFalse,Panic(EATSmsMessagingUnknownRequestCompleted));
-			}
-		}
-	else
-		{
-		//
-		// This class will handle event
-		//
-		if (aSource==ETimeOutCompletion)
-			{
-			LOCAL_LOGTEXT("EventSignal","Timeout error");
-			iIo->WriteAndTimerCancel(this);
-			Complete(KErrTimedOut, aSource);
-			}
-
-		TInt ret(KErrNone);
-		switch(iState)
-			{
-		case ESetPhoneToPDUMode:
-			if(aSource==EWriteCompletion)
-				HandleWriteCompletion(aSource);		
-			else
-				{
-				ret=HandleResponseCompletion(aSource,EFalse);
-				if (ret!=KErrNone)
-					{
-					Complete(ret,aSource);
-					return;
-					}		
-				StartFindSCA();
-				}
-			break;
-
-		case ESendPDULengthToPhone:
-			if(aSource==EWriteCompletion)
-				{
-				HandleWriteCompletion(aSource);
-				iExpectString=iIo->AddExpectString(this,KSmsEnterPduModeResponse,ETrue);
-				}
-			else
-				{
-				ret=HandleResponseCompletion(aSource,EFalse);
-				if (ret!=KErrNone)
-					{
-					Complete(ret,aSource);
-					return;
-					}		
-				ret=ConvertCMSErrorToKErr(CMSErrorValue());
-				iIo->RemoveExpectString(iExpectString);
-				iExpectString=NULL;
-				if (ret!=KErrNone)
-					{
-					Complete(ret,aSource);
-					return;
-					}		
-
-				// If we get a Cancel request just before we send the PDU, we instead send an escape 
-				// character to trigger a PDU send failure and then continue as normal.
-				if (iStop)
-					{
-					LOCAL_LOGTEXT("EventSignal","Cancel requested. Sending Escape Character instead of PDU");
-					
-					// In case of Ericsson phone, after sending the escape char we are not receiving expected
-					// response (OK/ERROR), it is just echoing those char. But if the escape char is prefixed
-					// by "at", then it responds with expected response.
-
-					// But in case of other phones, we believe the escape char alone works.  We have confirmed
-					// this with Nokia phones.
-
-					_LIT16(KEricsson,"*ERICSSON*");
-					if(iPhoneGlobals->iPhoneId.iManufacturer.MatchF(KEricsson)==0)
-						{
-						_LIT8(KEscapeSequenceString,"at%S\r");
-						iTxBuffer.Format(KEscapeSequenceString,&KEscapeChar);
-						}
-					else
-						{
-						iTxBuffer.Format(KEscapeChar);
-						}
-					WriteTxBufferToPhone(ESendEscapeCharToPhone);
-					}
-				else
-					SendPDUToPhone();
-				}
-			break;
-		
-		case ESendPDUToPhone:
-			if(aSource==EWriteCompletion)
-				{
-				HandleWriteCompletion(aSource);
-				}
-			else
-				{
-				const TInt err=ConvertCMSErrorToKErr(CMSErrorValue());
-				ret=HandleResponseCompletion(aSource,EFalse);
-				if (ret!=KErrNone)
-					{
-					Complete(ret,aSource);
-					return;
-					}		
-
-				// Check if an error occurred
-				if(err!=KErrNone)
-					{
-					// If we have not already, then retry using the other Pdu standard
-					if(!iHaveRetriedWithOtherPduStd)
-						{
-						CANCEL_AND_RETURN_IF_NEEDED();
-						// Retry with new standard
-						LOCAL_LOGTEXT("EventSignal","Failed to send message, will retry using other phone standard");
-						iHaveRetriedWithOtherPduStd=ETrue;
-						TogglePhonePDUStandard();
-						DoneFindSCA();
-						}
-					else
-						{
-						// We have tried both PDU standards and have failed :-(
-						LOCAL_LOGTEXT("EventSignal","Failed to send message :-(");
-						Complete(err,aSource);
-						}
-					}
-				else
-					{
-					// Success, we have sent the message ;-)
-					if (iStop)	{LOCAL_LOGTEXT("EventSignal","Message send successful, Cancel request to late, PDU already sent");}
-					else		{LOCAL_LOGTEXT("EventSignal","Message send successful ;-)");}
-					SendPDUToPhone_Stage2();
-					}
-				}
-			break;
-		
-		case ESendEscapeCharToPhone:
-			if(aSource==EWriteCompletion)
-				{
-				HandleWriteCompletion(aSource);
-				}
-			else
-				{
-				ret=HandleResponseCompletion(aSource,EFalse);
-				if (ret!=KErrNone)
-					{
-					Complete(ret,aSource);
-					return;
-					}
-				Complete(KErrCancel,aSource);
-				}
-			break;
-
-		case ENotInProgress: // Required to stop 'unhandled enum' warning with ARM4
-			break;
-			}
-		}
-	}
-
-
-void CATSmsMessagingSend::Complete(TInt aError,TEventSource aSource)
-	{
-	LOCAL_LOGTEXT("Complete","");
-	LOGTEXT3(_L8("aError=%D aSource=%D"),aError,aSource);
-
-	iIo->WriteAndTimerCancel(this);
-	iIo->RemoveExpectStrings(this);
-	iOKExpectString = NULL;
-	iErrorExpectString = NULL;
-	CATCommands::Complete(aError,aSource);
-	iTelObject->ReqCompleted(iReqHandle, aError);
-	if (aSource==EWriteCompletion)
-		iIo->Read();
-	iState = ENotInProgress; 
-	}
-
-void CATSmsMessagingSend::SetMsgAttributes(RMobileSmsMessaging::TMobileSmsSendAttributesV1* aMsgAttributes)
-	{
-	iMsgAttributes=aMsgAttributes;
-	}
-
-void CATSmsMessagingSend::Stop(TTsyReqHandle aTsyReqHandle)
-//
-//	Attempts to halt the process
-//
-	{
-	LOCAL_LOGTEXT("Stop","Client has requested cancel");
-	__ASSERT_ALWAYS(aTsyReqHandle == iReqHandle, Panic(EIllegalTsyReqHandle));
-
-	// Ensure our base class notes that a cancel has been requested
-	CATSmsCommands::RequestATCommandCancel();
-
-	// Set our flag to denote we should cancel as soon as possible
-	iStop=ETrue;
-	}
-
-void CATSmsMessagingSend::CompleteWithIOError(TEventSource /*aSource*/,TInt aStatus)
-	{
-	if (iState!=ENotInProgress)
-		{
-		iIo->WriteAndTimerCancel(this);
-		iTelObject->ReqCompleted(iReqHandle, aStatus);
-		iState = ENotInProgress;
-		}
-	}
-
-//
-// Utility functions 
-//
-TBool CATSmsMessagingSend::PhoneUsesNewPDUStandard()
-/**
- * This code assumes that EPhoneTestOldStandard and EPhoneTestUndefined are 
- * the same.
- */
- 	{
-	return (iPhoneGlobals->iPhoneTestState==CPhoneGlobals::EPhoneTestNewStandard);
-	}
-
-void CATSmsMessagingSend::TogglePhonePDUStandard()
-/**
- * This code assumes that EPhoneTestOldStandard and EPhoneTestUndefined are 
- * the same.
- */
-	{
-	if(iPhoneGlobals->iPhoneTestState==CPhoneGlobals::EPhoneTestNewStandard)
-		iPhoneGlobals->iPhoneTestState=CPhoneGlobals::EPhoneTestOldStandard;		
-	else
-		iPhoneGlobals->iPhoneTestState=CPhoneGlobals::EPhoneTestNewStandard;		
-	}
-
-void CATSmsMessagingSend::WriteTxBufferToPhone(TState aNewState)
-/**
- * Sends the contents of iTxBuffer to the phone
- */
- 	{
-	iIo->Write(this,iTxBuffer);
-	iIo->SetTimeOut(this,KATWriteTimeout);
-	iState=aNewState;
-	}
-
-
-TInt CATSmsMessagingSend::ParseCMGSResponse()		
-/**
- * Parse CMGS response string for Message Reference Number &
- * SUBMIT-REPORT PDU (optional) and store their values in the clients data space.
- *
- * @return Standard KErr... values
- */
-	{
-	__ASSERT_DEBUG(iMsgAttributes,Panic(EATSmsMessagingSendNullMsgAttributes));		
-
-	iBuffer.Set(iIo->Buffer());
-	TInt pos=iBuffer.FindF(KCMGSResponseString);
-	if (pos==KErrNotFound)
-		{
-		LOCAL_LOGTEXT("ParseCMGSResponse","Cannot find '+CMGS:' string");
-		return KErrNotFound;
-		}
-	
-	// Locate the message reference number
-	// (ie. read in all digits form the first found to the end of the string)
-	const TInt bufLength=iBuffer.Length();
-	pos+=KCMGSResponseStringLength;
-	while(pos<bufLength && !(TChar(iBuffer[pos]).IsDigit()))
-		++pos;
-	if(pos>=bufLength)
-		{
-		LOCAL_LOGTEXT("ParseCMGSResponse","Cannot find any digits after '+CMGS:'");
-		return KErrNotFound;
-		}
-
-	// Read message number and store in clients data structure
-	TPtrC8 ptr=iBuffer.Mid(pos);	
-	TLex8 lex(ptr);
-	TUint16 val;
-	TInt ret=lex.Val(val,EDecimal);
-	if(ret!=KErrNone)
-		{
-		LOCAL_LOGTEXT("ParseCMGSResponse","Unable to read Message Reference Number");
-		return ret;
-		}
-	LOGTEXT2(_L8("CATSmsMessagingSend    Message reference number %d"),val);
-	iMsgAttributes->iMsgRef=val;
-	iMsgAttributes->iFlags|=RMobileSmsMessaging::KMessageReference;
-
-	// Locate SUBMIT-REPORT (it does not have to exist)
-	pos=iBuffer.FindF(KCommaChar);
-	if(pos!=KErrNotFound)
-		{
-		while(pos<bufLength && !(TChar(iBuffer[pos]).IsHexDigit()))
-			++pos;
-
-		if(pos<bufLength)
-			{
-			// We have found a SUBMIT-REPORT PDU, so save it to clients data space
-			LOCAL_LOGTEXT("ParseCMGSResponse","Found SUBMIT-REPORT PDU");
-
-			iMsgAttributes->iSubmitReport.Zero();
-			while(pos<bufLength && TChar(iBuffer[pos]).IsHexDigit())
-				{
-				iMsgAttributes->iSubmitReport.Append(TChar(iBuffer[pos]));
-				++pos;
-				}
-			iMsgAttributes->iFlags|=RMobileSmsMessaging::KGsmSubmitReport;
-			}
-		}
-
-	return KErrNone;
-	}
-
-
+// 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:
+// Implementation of CATSmsMessagingSend.
+// 
+//
+
+/**
+ @file
+*/
+
+
+#include <etelmm.h>
+
+#include "NOTIFY.H"
+#include "mSMSMESS.H"
+#include "mSMSSEND.H"
+#include "mSLOGGER.H"
+#include "ATIO.H"
+#include "smsutil.h"	// for CATSmsUtils
+
+//
+// Constants
+//
+const TInt KPduMode=0;
+
+//
+// Macros
+//
+
+#ifdef __LOGDEB__
+_LIT8(KLogEntry,"CATSmsMessagingSend::%S\t%S");
+#define LOCAL_LOGTEXT(function,text) {_LIT8(F,function);_LIT8(T,text);LOGTEXT3(KLogEntry,&F,&T);}
+#else
+#define LOCAL_LOGTEXT(function,text)
+#endif
+
+/**
+ * CANCEL_AND_RETURN_IF_NEEDED
+ * Used to implement cancellation at safe points inside CATSmsMessagingSend::EventSignal
+ */
+#define CANCEL_AND_RETURN_IF_NEEDED()\
+{\
+if(iStop)\
+	{\
+	Complete(KErrCancel);\
+	LOCAL_LOGTEXT("CANCEL_AND_RETURN_IF_NEEDED","Cancelled");\
+	return;\
+	}\
+}
+
+
+//
+// Class Implementation
+//
+CATSmsMessagingSend* CATSmsMessagingSend::NewL(	CATIO* aIo,
+												CTelObject* aTelObject,
+												CATInit* aInit,
+												CPhoneGlobals* aGsmStatus)
+/**
+ * Creates a new instance of CATSmsMessagingSend
+ */
+	{
+	CATSmsMessagingSend* self=new(ELeave) CATSmsMessagingSend(aIo,aTelObject,aInit,aGsmStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CATSmsMessagingSend::CATSmsMessagingSend(	CATIO* aIo,
+											CTelObject* aTelObject,
+											CATInit* aInit,
+											CPhoneGlobals* aGsmStatus)
+	:CATSmsCommands(aIo,aTelObject,aInit,aGsmStatus)
+/**
+ * C++ constructor
+ */
+{}
+
+void CATSmsMessagingSend::ConstructL()
+/**
+ * 2nd phase contructor
+ */
+	{
+	CATCommands::ConstructL();
+	iMsgDataAscii.Zero();			// Just in case
+	}
+
+CATSmsMessagingSend::~CATSmsMessagingSend()
+/**
+ * C++ destructor
+ */
+	{
+	delete iMsgData;
+	}
+
+void CATSmsMessagingSend::Start(TTsyReqHandle aTsyReqHandle,TAny* aParams)
+/**
+ * Starts the procedure of sending an SMS
+ * @param aTsyReqHandle Handle to client, to be completed when operation done
+ * @param aParams Pointer to the SMS PDU (with or without SC prefixed) to be sent 
+ */
+	{
+	LOCAL_LOGTEXT("Start","Have been requested to send a message");
+	
+	// Intialize data 
+	iHaveRetriedWithOtherPduStd=EFalse;
+	iStop=EFalse;
+
+	// ::SetMsgAttributes must be called before ::Start is called
+	__ASSERT_DEBUG(iMsgAttributes,Panic(EATSmsMessagingSendNullMsgAttributes));		
+
+	// Save access to the data we be given thru our parameters
+	iReqHandle=aTsyReqHandle;
+	delete iMsgData;		// Ensure we don't orphan some memory
+	iMsgData=((TDesC8*)aParams)->Alloc();
+	if(!iMsgData)
+		Complete(KErrNoMemory);
+
+	// Kick off first AT stuff
+	LOCAL_LOGTEXT("Start","Setting phone to PDU mode (as opposed to text mode)");
+	iTxBuffer.Format(KSmsFormatCommand,KPduMode);
+	WriteTxBufferToPhone(ESetPhoneToPDUMode);
+	}
+
+
+void CATSmsMessagingSend::StartFindSCA()
+/**
+ * Attempt to find an SCA to use when sending message.
+ * The following SCA sources are checked in this order...
+ *    Supplied by client in iMsgAttributes.iSc
+ *    Use default SCA in the phone's memory
+ *	  Use default SCA in the phone's memory after doing 'AT+CRES=1'
+ */
+	{
+	LOCAL_LOGTEXT("StartFindSCA","");
+
+	// Did client supply SCA in iMsgAttributes.iSc
+	if(iMsgAttributes->iFlags&RMobileSmsMessaging::KGsmServiceCentre && iMsgAttributes->iGsmServiceCentre.iTelNumber.Length()!=0)
+		{
+		iMsgSCA=iMsgAttributes->iGsmServiceCentre;
+		DoneFindSCA();
+		}
+
+	// Does the phone have a default SCA in memory
+	else
+		{
+		TInt ret=CATSmsCommands::RequestATCommand(CATSmsCommands::EGetSCAFromPhone);
+		if(ret!=KErrNone)
+			Complete(ret);
+		}
+	
+	}
+
+
+void CATSmsMessagingSend::DoneFindSCA()
+	{
+	LOCAL_LOGTEXT("DoneFindSCA","");
+	// At this point in the execution we can guarantee that...
+	//	iMsgData holds the PDU to be sent in binary format without a prepended SCA
+	//	iMsgSCA holds the SCA to be used to send the PDU
+
+	// Check we can handle the Type-Of-Address of the SCA
+	if(!(iMsgSCA.iNumberPlan==RMobilePhone::EIsdnNumberPlan &&
+	   (iMsgSCA.iTypeOfNumber==RMobilePhone::EInternationalNumber ||
+		iMsgSCA.iTypeOfNumber==RMobilePhone::EUnknownNumber)))
+		{
+		LOCAL_LOGTEXT("DoneFindSCA","SCA type unsupported");
+		Complete(KErrCorrupt);
+		return;
+		}
+
+	// Check which ETSI standard we think phone conforms to
+	if(PhoneUsesNewPDUStandard())
+		SendMessageToNewPhone();
+	else
+		SendMessageToOldPhone();
+	}
+
+
+void CATSmsMessagingSend::SendMessageToOldPhone()
+/**
+ * Send message to phone which uses new ETSI standard (no SCA prefixed to PDU expected,
+ * use phone's default SCA setting instead).
+ */
+ 	{
+	LOCAL_LOGTEXT("SendMessageToOldPhone","");
+	// Set the SCA to use as the default in the phone's memory
+	iRequestSCA=iMsgSCA;
+	TInt ret=CATSmsCommands::RequestATCommand(CATSmsCommands::ESetSCAInPhone);
+	if(ret!=KErrNone)
+		Complete(ret);
+	}
+
+
+void CATSmsMessagingSend::SendMessageToOldPhone_Stage2()
+	{
+	// Convert PDU from binary to ASCII
+	iMsgDataAscii.Zero();
+	CATSmsUtils::AppendDataToAscii(iMsgDataAscii,*iMsgData);
+	if(iMsgDataAscii.Length()==0)
+		{
+		LOCAL_LOGTEXT("SendMessageToOldPhone_Stage2","Failed to convert binary PDU to ASCII");
+		Complete(KErrCorrupt);
+		return;
+		}
+
+	// Send PDU length to the phone
+	const TInt pduLengthSemiOctets(iMsgDataAscii.Length());
+	const TInt pduLengthOctets(pduLengthSemiOctets/2+pduLengthSemiOctets%2);
+	iTxBuffer.Format(KSmsSendPduLengthCommand,pduLengthOctets);
+	WriteTxBufferToPhone(ESendPDULengthToPhone);
+	}
+
+void CATSmsMessagingSend::SendPDUToPhone()
+	{
+	LOCAL_LOGTEXT("SendPDUToPhone","");
+	// Send PDU to phone 
+	iTxBuffer.Format(iMsgDataAscii);
+	iTxBuffer.Append(KCtrlZChar);
+	WriteTxBufferToPhone(ESendPDUToPhone);
+	}
+
+void CATSmsMessagingSend::SendPDUToPhone_Stage2()
+	{
+	// Get the message reference number & submit report and then we've finished 
+	Complete(ParseCMGSResponse());
+	}
+
+void CATSmsMessagingSend::SendMessageToNewPhone()
+/**
+ * Send message to phone which uses new ETSI standard (SCA prefixed to PDU expected).
+ */
+	{
+	LOCAL_LOGTEXT("SendMessageToNewPhone","");
+
+	// Convert SCA to ASCII (ensure that 03.40 format is used to create SCA)
+	iMsgDataAscii.Zero();
+	if(CATSmsUtils::AppendAddressToAscii(iMsgDataAscii,iMsgSCA,ETrue)!=KErrNone || iMsgDataAscii.Length()==0)
+		{
+		LOCAL_LOGTEXT("SendMessageToNewPhone","Failed to prepend SCA to PDU");
+		Complete(KErrCorrupt);
+		return;
+		}
+	
+	// Convert PDU to ASCII
+	const TInt msgDataAsciiLen(iMsgDataAscii.Length());
+	CATSmsUtils::AppendDataToAscii(iMsgDataAscii,*iMsgData);
+	if(iMsgDataAscii.Length()==msgDataAsciiLen)
+		{
+		LOCAL_LOGTEXT("SendMessageToNewPhone","Failed to convert binary PDU to ASCII");
+		Complete(KErrCorrupt);
+		return;
+		}
+
+	// Send PDU length to the phone
+	const TInt pduLengthSemiOctets(iMsgDataAscii.Length()-msgDataAsciiLen);	// Must not include the prefixed SCA in calculation
+	const TInt pduLengthOctets(pduLengthSemiOctets/2+pduLengthSemiOctets%2);
+	iTxBuffer.Format(KSmsSendPduLengthCommand,pduLengthOctets);
+	WriteTxBufferToPhone(ESendPDULengthToPhone);
+	}
+
+
+void CATSmsMessagingSend::EventSignal(TEventSource aSource)
+/**
+ * Handle the events from the comm port
+ *
+ * This code is first called after the phone has been set to PDU mode.
+ * First we find the SCA that we are going to use. 
+ * Secondly we send the message to the phone depending on whether the phone seems to be using 
+ * the new ETSI format (SCA prefixed to PDU expected) or the old ETSI format (no SCA prefixed
+ * to PDU expected).
+ *
+ * @param aSource denotes if event is due to read, write or timeout
+ */
+	{
+	LOCAL_LOGTEXT("EventSignal","");
+	LOGTEXT3(_L8("iState=%D iSource=%D"),iState,aSource);
+	LOGTEXT2(_L8("iStop=%D"),iStop);
+
+	// Check to see if this class or our base class need to process the event
+	if(CATSmsCommands::RequestATActive())
+		{
+		//
+		// Allow base class to handle event, and find out if a request completed
+		//
+		CATSmsCommands::EventSignal(aSource);
+		const CATSmsCommands::TRequest reqCompleted(CATSmsCommands::RequestATCompleted());
+
+		if(reqCompleted!=ENone)
+			CANCEL_AND_RETURN_IF_NEEDED();
+
+		// Otheriwse, Check if a request completed as a result of the event processing
+		switch(reqCompleted)
+			{
+		case CATSmsCommands::EGetSCAFromPhone:
+			LOCAL_LOGTEXT("EventSignal","EGetSCAFromPhone completed");
+			if(iRequestError==KErrNone)
+				{
+				iMsgSCA=iRequestSCA;
+				DoneFindSCA();
+				}
+			else
+				{
+				LOCAL_LOGTEXT("EventSignal","Failed to find an SCA to use");
+				Complete(iRequestError,aSource);
+				}
+			break;
+
+		case CATSmsCommands::ESetSCAInPhone:
+			LOCAL_LOGTEXT("EventSignal","ESetSCAInPhone completed");
+			if(iRequestError==KErrNone)
+				SendMessageToOldPhone_Stage2();
+			else
+				{
+				LOCAL_LOGTEXT("EventSignal","Failed to set SCA in phone");
+				Complete(iRequestError,aSource);
+				}
+			break;
+
+		case CATSmsCommands::ENone:	// Must not be caught by default case 
+			break;
+		default:
+			LOCAL_LOGTEXT("EventSignal","CATSmsCommands unknown request completed");
+			__ASSERT_DEBUG(EFalse,Panic(EATSmsMessagingUnknownRequestCompleted));
+			}
+		}
+	else
+		{
+		//
+		// This class will handle event
+		//
+		if (aSource==ETimeOutCompletion)
+			{
+			LOCAL_LOGTEXT("EventSignal","Timeout error");
+			iIo->WriteAndTimerCancel(this);
+			Complete(KErrTimedOut, aSource);
+			}
+
+		TInt ret(KErrNone);
+		switch(iState)
+			{
+		case ESetPhoneToPDUMode:
+			if(aSource==EWriteCompletion)
+				HandleWriteCompletion(aSource);		
+			else
+				{
+				ret=HandleResponseCompletion(aSource,EFalse);
+				if (ret!=KErrNone)
+					{
+					Complete(ret,aSource);
+					return;
+					}		
+				StartFindSCA();
+				}
+			break;
+
+		case ESendPDULengthToPhone:
+			if(aSource==EWriteCompletion)
+				{
+				HandleWriteCompletion(aSource);
+				iExpectString=iIo->AddExpectString(this,KSmsEnterPduModeResponse,ETrue);
+				}
+			else
+				{
+				ret=HandleResponseCompletion(aSource,EFalse);
+				if (ret!=KErrNone)
+					{
+					Complete(ret,aSource);
+					return;
+					}		
+				ret=ConvertCMSErrorToKErr(CMSErrorValue());
+				iIo->RemoveExpectString(iExpectString);
+				iExpectString=NULL;
+				if (ret!=KErrNone)
+					{
+					Complete(ret,aSource);
+					return;
+					}		
+
+				// If we get a Cancel request just before we send the PDU, we instead send an escape 
+				// character to trigger a PDU send failure and then continue as normal.
+				if (iStop)
+					{
+					LOCAL_LOGTEXT("EventSignal","Cancel requested. Sending Escape Character instead of PDU");
+					
+					// In case of Ericsson phone, after sending the escape char we are not receiving expected
+					// response (OK/ERROR), it is just echoing those char. But if the escape char is prefixed
+					// by "at", then it responds with expected response.
+
+					// But in case of other phones, we believe the escape char alone works.  We have confirmed
+					// this with Nokia phones.
+
+					_LIT16(KEricsson,"*ERICSSON*");
+					if(iPhoneGlobals->iPhoneId.iManufacturer.MatchF(KEricsson)==0)
+						{
+						_LIT8(KEscapeSequenceString,"at%S\r");
+						iTxBuffer.Format(KEscapeSequenceString,&KEscapeChar);
+						}
+					else
+						{
+						iTxBuffer.Format(KEscapeChar);
+						}
+					WriteTxBufferToPhone(ESendEscapeCharToPhone);
+					}
+				else
+					SendPDUToPhone();
+				}
+			break;
+		
+		case ESendPDUToPhone:
+			if(aSource==EWriteCompletion)
+				{
+				HandleWriteCompletion(aSource);
+				}
+			else
+				{
+				const TInt err=ConvertCMSErrorToKErr(CMSErrorValue());
+				ret=HandleResponseCompletion(aSource,EFalse);
+				if (ret!=KErrNone)
+					{
+					Complete(ret,aSource);
+					return;
+					}		
+
+				// Check if an error occurred
+				if(err!=KErrNone)
+					{
+					// If we have not already, then retry using the other Pdu standard
+					if(!iHaveRetriedWithOtherPduStd)
+						{
+						CANCEL_AND_RETURN_IF_NEEDED();
+						// Retry with new standard
+						LOCAL_LOGTEXT("EventSignal","Failed to send message, will retry using other phone standard");
+						iHaveRetriedWithOtherPduStd=ETrue;
+						TogglePhonePDUStandard();
+						DoneFindSCA();
+						}
+					else
+						{
+						// We have tried both PDU standards and have failed :-(
+						LOCAL_LOGTEXT("EventSignal","Failed to send message :-(");
+						Complete(err,aSource);
+						}
+					}
+				else
+					{
+					// Success, we have sent the message ;-)
+					if (iStop)	{LOCAL_LOGTEXT("EventSignal","Message send successful, Cancel request to late, PDU already sent");}
+					else		{LOCAL_LOGTEXT("EventSignal","Message send successful ;-)");}
+					SendPDUToPhone_Stage2();
+					}
+				}
+			break;
+		
+		case ESendEscapeCharToPhone:
+			if(aSource==EWriteCompletion)
+				{
+				HandleWriteCompletion(aSource);
+				}
+			else
+				{
+				ret=HandleResponseCompletion(aSource,EFalse);
+				if (ret!=KErrNone)
+					{
+					Complete(ret,aSource);
+					return;
+					}
+				Complete(KErrCancel,aSource);
+				}
+			break;
+
+		case ENotInProgress: // Required to stop 'unhandled enum' warning with ARM4
+			break;
+			}
+		}
+	}
+
+
+void CATSmsMessagingSend::Complete(TInt aError,TEventSource aSource)
+	{
+	LOCAL_LOGTEXT("Complete","");
+	LOGTEXT3(_L8("aError=%D aSource=%D"),aError,aSource);
+
+	iIo->WriteAndTimerCancel(this);
+	iIo->RemoveExpectStrings(this);
+	iOKExpectString = NULL;
+	iErrorExpectString = NULL;
+	CATCommands::Complete(aError,aSource);
+	iTelObject->ReqCompleted(iReqHandle, aError);
+	if (aSource==EWriteCompletion)
+		iIo->Read();
+	iState = ENotInProgress; 
+	}
+
+void CATSmsMessagingSend::SetMsgAttributes(RMobileSmsMessaging::TMobileSmsSendAttributesV1* aMsgAttributes)
+	{
+	iMsgAttributes=aMsgAttributes;
+	}
+
+void CATSmsMessagingSend::Stop(TTsyReqHandle aTsyReqHandle)
+//
+//	Attempts to halt the process
+//
+	{
+	LOCAL_LOGTEXT("Stop","Client has requested cancel");
+	__ASSERT_ALWAYS(aTsyReqHandle == iReqHandle, Panic(EIllegalTsyReqHandle));
+
+	// Ensure our base class notes that a cancel has been requested
+	CATSmsCommands::RequestATCommandCancel();
+
+	// Set our flag to denote we should cancel as soon as possible
+	iStop=ETrue;
+	}
+
+void CATSmsMessagingSend::CompleteWithIOError(TEventSource /*aSource*/,TInt aStatus)
+	{
+	if (iState!=ENotInProgress)
+		{
+		iIo->WriteAndTimerCancel(this);
+		iTelObject->ReqCompleted(iReqHandle, aStatus);
+		iState = ENotInProgress;
+		}
+	}
+
+//
+// Utility functions 
+//
+TBool CATSmsMessagingSend::PhoneUsesNewPDUStandard()
+/**
+ * This code assumes that EPhoneTestOldStandard and EPhoneTestUndefined are 
+ * the same.
+ */
+ 	{
+	return (iPhoneGlobals->iPhoneTestState==CPhoneGlobals::EPhoneTestNewStandard);
+	}
+
+void CATSmsMessagingSend::TogglePhonePDUStandard()
+/**
+ * This code assumes that EPhoneTestOldStandard and EPhoneTestUndefined are 
+ * the same.
+ */
+	{
+	if(iPhoneGlobals->iPhoneTestState==CPhoneGlobals::EPhoneTestNewStandard)
+		iPhoneGlobals->iPhoneTestState=CPhoneGlobals::EPhoneTestOldStandard;		
+	else
+		iPhoneGlobals->iPhoneTestState=CPhoneGlobals::EPhoneTestNewStandard;		
+	}
+
+void CATSmsMessagingSend::WriteTxBufferToPhone(TState aNewState)
+/**
+ * Sends the contents of iTxBuffer to the phone
+ */
+ 	{
+	iIo->Write(this,iTxBuffer);
+	iIo->SetTimeOut(this,KATWriteTimeout);
+	iState=aNewState;
+	}
+
+
+TInt CATSmsMessagingSend::ParseCMGSResponse()		
+/**
+ * Parse CMGS response string for Message Reference Number &
+ * SUBMIT-REPORT PDU (optional) and store their values in the clients data space.
+ *
+ * @return Standard KErr... values
+ */
+	{
+	__ASSERT_DEBUG(iMsgAttributes,Panic(EATSmsMessagingSendNullMsgAttributes));		
+
+	iBuffer.Set(iIo->Buffer());
+	TInt pos=iBuffer.FindF(KCMGSResponseString);
+	if (pos==KErrNotFound)
+		{
+		LOCAL_LOGTEXT("ParseCMGSResponse","Cannot find '+CMGS:' string");
+		return KErrNotFound;
+		}
+	
+	// Locate the message reference number
+	// (ie. read in all digits form the first found to the end of the string)
+	const TInt bufLength=iBuffer.Length();
+	pos+=KCMGSResponseStringLength;
+	while(pos<bufLength && !(TChar(iBuffer[pos]).IsDigit()))
+		++pos;
+	if(pos>=bufLength)
+		{
+		LOCAL_LOGTEXT("ParseCMGSResponse","Cannot find any digits after '+CMGS:'");
+		return KErrNotFound;
+		}
+
+	// Read message number and store in clients data structure
+	TPtrC8 ptr=iBuffer.Mid(pos);	
+	TLex8 lex(ptr);
+	TUint16 val;
+	TInt ret=lex.Val(val,EDecimal);
+	if(ret!=KErrNone)
+		{
+		LOCAL_LOGTEXT("ParseCMGSResponse","Unable to read Message Reference Number");
+		return ret;
+		}
+	LOGTEXT2(_L8("CATSmsMessagingSend    Message reference number %d"),val);
+	iMsgAttributes->iMsgRef=val;
+	iMsgAttributes->iFlags|=RMobileSmsMessaging::KMessageReference;
+
+	// Locate SUBMIT-REPORT (it does not have to exist)
+	pos=iBuffer.FindF(KCommaChar);
+	if(pos!=KErrNotFound)
+		{
+		while(pos<bufLength && !(TChar(iBuffer[pos]).IsHexDigit()))
+			++pos;
+
+		if(pos<bufLength)
+			{
+			// We have found a SUBMIT-REPORT PDU, so save it to clients data space
+			LOCAL_LOGTEXT("ParseCMGSResponse","Found SUBMIT-REPORT PDU");
+
+			iMsgAttributes->iSubmitReport.Zero();
+			while(pos<bufLength && TChar(iBuffer[pos]).IsHexDigit())
+				{
+				iMsgAttributes->iSubmitReport.Append(TChar(iBuffer[pos]));
+				++pos;
+				}
+			iMsgAttributes->iFlags|=RMobileSmsMessaging::KGsmSubmitReport;
+			}
+		}
+
+	return KErrNone;
+	}
+
+