diff -r 6b1d113cdff3 -r 6638e7f4bd8f telephonyserverplugins/multimodetsy/Multimode/sms/mSMSSEND.CPP --- 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 - -#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) - { - 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(posiSubmitReport.Zero(); - while(posiSubmitReport.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 + +#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) + { + 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(posiSubmitReport.Zero(); + while(posiSubmitReport.Append(TChar(iBuffer[pos])); + ++pos; + } + iMsgAttributes->iFlags|=RMobileSmsMessaging::KGsmSubmitReport; + } + } + + return KErrNone; + } + +