telephonyserverplugins/multimodetsy/Multimode/sms/mSMSWRIT.CPP
changeset 0 3553901f7fa8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/telephonyserverplugins/multimodetsy/Multimode/sms/mSMSWRIT.CPP	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,426 @@
+// 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:
+// This writes an SMS message and stores the message location number. AT+CMGW=xx
+// 
+//
+
+#include "NOTIFY.H"
+#include "mSMSMESS.H"
+#include "mSMSWRIT.H"
+#include "mSLOGGER.H"
+#include "ATIO.H"
+#include "mSMSSTOR.H"
+#include "smsutil.h"
+#include "et_phone_util.h"
+
+_LIT8(KSmsWriteLengthCommand,"AT+CMGW = %d\r");
+_LIT8(KSmsWriteCommand,"AT+CMGW = %d,%d\r");
+
+CATSmsMessagingWrite* CATSmsMessagingWrite::NewL(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit, CPhoneGlobals* aMmStatus)
+	{
+	CATSmsMessagingWrite* self = new(ELeave) CATSmsMessagingWrite(aIo, aTelObject, aInit, aMmStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CATSmsMessagingWrite::CATSmsMessagingWrite(CATIO* aIo, CTelObject* aTelObject, CATInit* aInit, CPhoneGlobals* aMmStatus)
+	:CATSmsCommands(aIo, aTelObject, aInit, aMmStatus)
+	,iExpectString(NULL)
+	,iSmsEntry(NULL)
+	,iCancelled(EFalse)
+	,iSmsStore(reinterpret_cast<CMobileSmsStore*>(aTelObject))
+	{
+	}
+
+CATSmsMessagingWrite::~CATSmsMessagingWrite()
+	{}
+
+void CATSmsMessagingWrite::Start(TTsyReqHandle aTsyReqHandle, TAny* aParams)
+	{
+	__ASSERT_DEBUG(aParams,Panic(EMobileSmsMessagingNullParameter));
+	__ASSERT_DEBUG(aTsyReqHandle!=TSY_HANDLE_INIT_VALUE,Panic(EMobileSmsMessagingNullParameter));
+
+	// Save the parameters into our class data
+	iReqHandle = aTsyReqHandle;
+	iCancelled=EFalse;
+	iSmsEntry = reinterpret_cast<RMobileSmsStore::TMobileGsmSmsEntryV1*>(aParams);
+
+	iNextAttempt=iPhoneGlobals->iPhoneTestState;
+	// If undefined, try old standard first
+	if(iNextAttempt==CPhoneGlobals::EPhoneTestUndefined)
+		iNextAttempt=CPhoneGlobals::EPhoneTestOldStandard;
+
+	iPhoneGlobals->iEventSignalActive = ETrue;
+	if (ComparePrefMem(iSmsStore->iStoreName))
+		StartPduWrite();
+	else // Compared memories are different
+		{
+		SetCurrentPrefMem(iSmsStore->iStoreName);
+		iState = EATWaitForSendingPrefMemComplete;
+		}
+	}
+
+void CATSmsMessagingWrite::EventSignal(TEventSource aSource)
+	{
+	LOGTEXT2(_L8("CATSmsMessagingWrite:\tiState = %D"), iState);
+
+	if (aSource == ETimeOutCompletion)
+		{
+		LOGTEXT(_L8("CATSmsMessagingWrite:\tTimeout Error during Sms Messaging Write"));
+		iPhoneGlobals->iPhoneStatus.iModemDetected = RPhone::EDetectedNotPresent;
+		RemoveStdExpectStrings();
+		if ((iState != EATWaitForPrefMemResponse)&&!ComparePrefMem(iSmsStore->iStoreName))
+			iPhoneGlobals->iPhonePrefMem = iSmsStore->iStoreName; 
+		Complete(KErrTimedOut, aSource);
+		return;
+		} //if
+
+	switch(iState)
+		{
+	// the following 3 cases are special cases, occuring only when the PhonePrefMem != ClientPrefMem
+	case EATWaitForSendingPrefMemComplete:
+		//
+		// Finished writing preferred memory, now wait for response
+		//
+			{
+			HandleWriteCompletion(aSource);
+			iState = EATWaitForPrefMemResponse;
+			}
+		break;
+
+	case EATWaitForPrefMemResponse:
+		//
+		// Got response from writing preferred memory.  Validate response, and if
+		// successful, then start the write sequence
+		//
+			{	
+			TInt ret=HandleResponseCompletion(aSource,EFalse);
+			if (ret!=KErrNone)
+				{
+				Complete(ret,aSource);
+				return;
+				}		
+			TInt pos=iIo->BufferFindF(KCPMSResponseString);
+			if (pos == KErrNotFound)
+				{
+				Complete(pos, aSource);
+				return;
+				}
+			LOGTEXT(_L8("CATSmsMessagingWrite:\tPhone's preferred memory successfully set to client's preferred memory."));
+			iPhoneGlobals->iPhonePrefMem=iSmsStore->iStoreName;
+			if (iCancelled)
+				Complete(KErrCancel,aSource);
+			else
+				StartPduWrite();
+			}
+		break;
+
+	case EATWaitForSendingPduLengthComplete:
+		//
+		// Finished sending pdu length command, now wait for response
+		//
+			{
+			HandleWriteCompletion(aSource);
+			iExpectString=iIo->AddExpectString(this,KSmsEnterPduModeResponse,ETrue); // Expecting "> "
+			iIo->SetTimeOut(this, 5000);
+			iState=EATReadPduEnterPduModeResponseCompleted;
+			}
+		break;
+	
+	case EATReadPduEnterPduModeResponseCompleted:
+		//
+		// Received a response to the pdu length command.  Validate, and if successful
+		// send the actual pdu in ascii form
+		//
+			{
+			TInt ret=HandleResponseCompletion(aSource,EFalse);
+			if (ret!=KErrNone)
+				{
+				Complete(ret,aSource);
+				return;
+				}		
+			ret=ConvertCMSErrorToKErr(CMSErrorValue());
+			iIo->RemoveExpectString(iExpectString);
+			iExpectString=NULL;
+			if(ret)
+				{
+				Complete(ret,aSource);
+				return;
+				}
+			iMsgDataAscii.Append(KCtrlZChar); // Adding the CTRL-Z that indicates the end of the PDU
+			iIo->Write(this,iMsgDataAscii);
+			iIo->SetTimeOut(this, 5000);
+			iState=EATWaitForSendingPduComplete;
+			}
+		break;
+
+	case EATWaitForSendingPduComplete:
+		//
+		// Finished writing pdu, wait for a response
+		//
+			{
+			HandleWriteCompletion(aSource);
+			iState=EATReadSmsRefNumCompleted;
+			}
+		break;
+
+	case EATReadSmsRefNumCompleted:
+		//
+		// Received response to pdu write, validate and if successful set preferred
+		// memory back to original value if it was changed for this command,
+		// otherwise on failure try the new format if the current attempt used the
+		// old ETSI format
+		//
+			{
+			TInt ret=HandleResponseCompletion(aSource,EFalse);
+			if (ret!=KErrNone)
+				{
+				Complete(ret,aSource);
+				return;
+				}		
+			TInt err=ConvertCMSErrorToKErr(CMSErrorValue());
+			
+			if (err==KErrNone)
+			 	TRAP(err,ParseResponseL());
+			
+			if(err!=KErrNone)
+				{ 
+				if (iCancelled)
+					Complete(KErrCancel,aSource);
+				else
+					{	
+					// Try new standard if old standard failed
+					LOGTEXT2(_L8("CATSmsMessagingWrite:\tFailed with code %d"),err);
+					if (iNextAttempt==CPhoneGlobals::EPhoneTestOldStandard)
+						{
+						iNextAttempt=CPhoneGlobals::EPhoneTestNewStandard;
+						StartPduWrite();
+						}
+					else
+						// Must have tried new standard and this failed too
+						Complete(err);
+					}
+				}
+			else
+				{
+				// If new standard worked then store this is as default for this phone
+				if (iNextAttempt==CPhoneGlobals::EPhoneTestNewStandard)
+					iPhoneGlobals->iPhoneTestState=CPhoneGlobals::EPhoneTestNewStandard;
+				Complete(KErrNone,aSource);
+				}
+			}
+		break;
+
+
+	case EATCancellingWaitForWriteComplete:
+		//
+		// Finished writing cancel request, now wait for response
+		//
+			{
+			__ASSERT_ALWAYS(aSource==EWriteCompletion,Panic(EATCommand_IllegalCompletionWriteExpected));
+			AddStdExpectStrings();
+			iIo->SetTimeOut(this);
+			iState=EATCancellingReadCompleted;
+			}
+		break;
+
+	case EATCancellingReadCompleted:
+		//
+		// Cancel command response received
+		//
+			{
+			__ASSERT_ALWAYS(aSource==EReadCompletion,Panic(EATCommand_IllegalCompletionReadExpected));
+			iIo->WriteAndTimerCancel(this);
+			Complete(KErrCancel, aSource);
+			}
+		break;
+
+	default:
+		break;
+		}
+	}
+
+void CATSmsMessagingWrite::StartPduWrite()
+/**
+ * Kicks off the writing of the actual pdu. Begins by converting the pdu
+ * into ascii form, and writing the pdu length and message status to the phone.
+ */
+	{
+	iMsgDataAscii.Zero();
+
+	// Convert PDU from binary to ASCII
+	CATSmsUtils::AppendDataToAscii(iMsgDataAscii,iSmsEntry->iMsgData);
+	if(iMsgDataAscii.Length()==0)
+		{
+		LOGTEXT(_L8("CATSmsMessagingWrite:\tStartPduWrite - 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);
+
+	if (iNextAttempt==CPhoneGlobals::EPhoneTestNewStandard)
+ 		{
+		// Prepend a zero length SCA to PDU - this forces phone to use default SCA
+		// See GSM 07.05 for details
+		_LIT8(zeroLengthSca, "00");
+		iMsgDataAscii.Insert(0,zeroLengthSca);
+		}
+	
+	iTxBuffer.Zero();
+	TInt stat=SetMsgStatus();
+	if (stat==KErrNotSupported)
+		iTxBuffer.Format(KSmsWriteLengthCommand,pduLengthOctets);
+	else
+		iTxBuffer.Format(KSmsWriteCommand,pduLengthOctets,stat);
+	iIo->Write(this,iTxBuffer);
+	iIo->SetTimeOut(this,5000);
+	iState=EATWaitForSendingPduLengthComplete;
+	}
+
+void CATSmsMessagingWrite::Complete(TInt aError)
+	{
+	Complete(aError, EReadCompletion);
+	}
+
+void CATSmsMessagingWrite::Complete(TInt aError, TEventSource aSource)
+	{
+	iIo->WriteAndTimerCancel(this);
+	iIo->RemoveExpectStrings(this);
+	iOKExpectString = NULL;
+	iErrorExpectString = NULL;
+	iExpectString = NULL;
+	iPhoneGlobals->iEventSignalActive = EFalse; 
+	if (iReqHandle != 0)
+		iTelObject->ReqCompleted(iReqHandle, aError);
+	if (aSource == EWriteCompletion)
+		iIo->Read();
+
+	//
+	// Call our base classes Complete so that
+	// we allow it do what ever it needs to do.
+	CATCommands::Complete(aError,aSource);
+
+	iState = EATNotInProgress;
+	}
+
+void CATSmsMessagingWrite::ParseResponseL()
+//
+// Parse the message reference number and return in smsEntry.iIndex
+//
+	{
+	LOGTEXT(_L8("CATSmsMessagingWrite:\tRetrieving message reference number"));
+	iBuffer.Set(iIo->Buffer());
+	TInt pos = iBuffer.FindF(KCMGWResponseString);
+	if (pos == KErrNotFound)
+		{
+		LOGTEXT(_L8("CATSmsMessagingWrite:\tError - Cannot find '+CMGW:' string"));
+		pos = iBuffer.FindF(KErrorString);
+		if (pos != KErrNotFound)
+			User::Leave(KErrGeneral);
+		User::Leave(pos);
+		}
+	pos += 6;
+	
+	// Place the message reference number into buffer (ie: everything after +CMGW: string)
+	TInt woop = iBuffer.Length()-pos;
+	iBuffer.Set(iBuffer.Right(woop));
+	
+	TLex8 yyLex(iBuffer);
+	yyLex.Inc();			// steps over the ':' Should always do this....NEVER falls over!
+	yyLex.SkipSpace();
+	TUint val;
+	if(yyLex.Val(val)==KErrNone) // Grab the message reference number.
+		{
+		iSmsEntry->iIndex = val;
+		}
+	else
+		{
+		LOGTEXT(_L8("CATSmsMessagingWrite:\tError. Invalid Message Reference Number."));
+		User::Leave(KErrGeneral);
+		}
+	}
+
+void CATSmsMessagingWrite::Stop(TTsyReqHandle aTsyReqHandle)
+//
+//	Attempts to halt the process
+//
+	{
+	__ASSERT_ALWAYS(aTsyReqHandle == iReqHandle,Panic(EIllegalTsyReqHandle));		
+	LOGTEXT(_L8("CATSmsMessagingWrite:\tCancelling Sms Write"));
+
+	if ((iState==EATWaitForSendingPduLengthComplete) ||
+		(iState==EATReadPduEnterPduModeResponseCompleted) ||
+		(iState==EATWaitForSendingPduComplete) ||
+		(iState==EATReadSmsRefNumCompleted))
+		{
+		// Attempt to cancel write command if we can
+		RemoveStdExpectStrings();
+		iIo->WriteAndTimerCancel(this);
+		iTxBuffer.Format(KEscapeChar);
+		iIo->Write(this,iTxBuffer);
+		iIo->SetTimeOut(this);
+		iState = EATCancellingWaitForWriteComplete;
+		}
+	else
+		// Wait until safe point to cancel the write
+		iCancelled=ETrue;
+	}
+
+void CATSmsMessagingWrite::CompleteWithIOError(TEventSource /*aSource*/,TInt aStatus)
+	{
+	if (iState!=EATNotInProgress)
+		{
+		iIo->WriteAndTimerCancel(this);
+		iTelObject->ReqCompleted(iReqHandle, aStatus);
+		iState = EATNotInProgress;
+		}
+	}
+
+TInt CATSmsMessagingWrite::SetMsgStatus()
+//
+// Sets the message status
+//
+	{
+	TInt status;
+	switch(iSmsEntry->iMsgStatus)
+		{
+		case (RMobileSmsStore::EStoredMessageUnread): 
+			status = 0;
+		break;
+		
+		case (RMobileSmsStore::EStoredMessageRead):
+			status = 1;
+		break;
+
+		case (RMobileSmsStore::EStoredMessageUnsent):
+			status = 2;
+		break;
+
+		case (RMobileSmsStore::EStoredMessageSent):  
+		case (RMobileSmsStore::EStoredMessageDelivered):   
+			status = 3;
+		break;
+
+		default:
+			status = KErrNotSupported;
+		break;
+		}
+	return status;
+	}
+