--- a/smsprotocols/smsstack/smsprot/Src/smspsend.cpp Mon May 03 13:37:20 2010 +0300
+++ b/smsprotocols/smsstack/smsprot/Src/smspsend.cpp Thu May 06 15:10:38 2010 +0100
@@ -1,767 +1,767 @@
-// 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 for the CSmsuActiveBase based class CSmsMessageSend.
-//
-//
-
-/**
- @file
- @internalAll
-*/
-
-#include "smspsend.h"
-#include "smspstor.h"
-#include "smspmain.h"
-#include "smsuset.h"
-#include "smsulog.h"
-#include "exterror.h"
-#include "gsmubuf.h"
-#include "SmsuTimer.h"
-#include <logwraplimits.h>
-
-
-/**
- * Static object constructor for CSmsMessageSend.
- *
- * @param aSegmentationStore Segmentation Store.
- * @param aSmsMessaging ETel SMS messaging subsession.
- * @param aSmsSettings The global SMS settings.
- * @param aMobileSmsCaps SMS messaging capabilities of TSY/phone.
- * @param aPriority Priority to use for the Active Object.
- * @param aSmspSetBearer Set bearer object.
- */
-CSmsMessageSend* CSmsMessageSend::NewL(CSmsSegmentationStore& aSegmentationStore,
- const TSmsSettings& aSmsSettings,
- const RMobileSmsMessaging::TMobileSmsCapsV1& aMobileSmsCaps,
- RMobileSmsMessaging& aSmsMessaging,
- TInt aPriority,
- CSmspSetBearer& aSmspSetBearer)
- {
- LOGSMSPROT1("CSmsMessageSend::NewL()");
-
- CSmsMessageSend* self = new (ELeave) CSmsMessageSend(aSegmentationStore,
- aSmsSettings,
- aMobileSmsCaps,
- aSmsMessaging,
- aPriority,
- aSmspSetBearer);
- CleanupStack::PushL(self);
- self->ConstructL();
- CleanupStack::Pop(self);
-
- return self;
- } // CSmsMessageSend::NewL
-
-
-/**
- * 2nd Phase of construction.
- *
- * Creates CSmsTimeout object and the SMS event logger.
- */
-void CSmsMessageSend::ConstructL()
- {
- LOGSMSPROT1("CSmsMessageSend::ConstructL()");
-
- iSmsEventLogger = CSmsEventLogger::NewL(iSegmentationStore.FileSession(),
- Priority());
-
- ConstructTimeoutL();
- } // CSmsMessageSend::ConstructL
-
-
-/**
- * Default constructor.
- *
- * @param aSegmentationStore Segmentation Store.
- * @param aSmsSettings The global SMS settings.
- * @param aMobileSmsCaps SMS messaging capabilities of TSY/phone.
- * @param aSmsMessaging ETel SMS messaging subsession.
- * @param aPriority Priority to use for the Active Object.
- * @param aSmspSetBearer Set bearer object.
- */
-CSmsMessageSend::CSmsMessageSend(CSmsSegmentationStore& aSegmentationStore,
- const TSmsSettings& aSmsSettings,
- const RMobileSmsMessaging::TMobileSmsCapsV1& aMobileSmsCaps,
- RMobileSmsMessaging& aSmsMessaging,
- TInt aPriority,
- CSmspSetBearer& aSmspSetBearer)
- : CSmsuActiveBase(aPriority),
- iState(ESmsMessageSendIdle),
- iSegmentationStore(aSegmentationStore),
- iSmspSetBearer(aSmspSetBearer),
- iSmsSettings(aSmsSettings),
- iMobileSmsCaps(aMobileSmsCaps),
- iSmsMessaging(aSmsMessaging),
- iMobileSmsSendAttributesV1Pckg(iMobileSmsSendAttributesV1),
- iSmsArray(8),
- iSegmentSequenceNumber(-1)
- {
- // NOP
- } // CSmsMessageSend::CSmsMessageSend
-
-
-/**
- * Standard destructor.
- */
-CSmsMessageSend::~CSmsMessageSend()
- {
- Cancel();
- delete iSmsEventLogger;
- } // CSmsMessageSend::~CSmsMessageSend
-
-
-void CSmsMessageSend::Start(CSmsMessage& aSmsMessage, TInt aOptions,
- const TSmsAddr& aSmsAddr, TRequestStatus& aStatus)
- {
- LOGSMSPROT1("CSmsMessageSend::Start()");
-
- __ASSERT_DEBUG(iState == ESmsMessageSendIdle,SmspPanic(KSmspPanicUnexpectedState));
-
- //
- // Store the request status that we will complete when finished...
- //
- Queue(aStatus);
-
- //
- // Initialise member data...
- //
- iSmsMessage=&aSmsMessage;
- iSmsMessage->ParsedToFromAddress(iToFromTelNumber);
- iOptions = aOptions;
- iSmsAddr = aSmsAddr;
-
- iSmsPDUData.iType = aSmsMessage.Type();
- iSmsPDUData.iTotal = 0;
- iSmsPDUData.iSent = 0;
- iSmsPDUData.iDelivered = 0;
-
- iSendError = KErrNone;
- iSmsEventLogger->Event().SetId(KLogNullId);
-
- //
- // Begin by setting the bearer...
- //
- iState = ESmsMessageSendSetBearer;
- iSmspSetBearer.NotifyBearerSet(iStatus);
- SetActive();
- } // CSmsMessageSend::Start
-
-
-void CSmsMessageSend::DoRunL()
- {
- LOGSMSPROT3("CSmsMessageSend::RunL(): iStatus=%d, iState=%d", iStatus.Int(), iState);
-
- switch (iState)
- {
- case ESmsMessageSendSetBearer:
- {
- //
- // If setting of bearer was successful then send the message.
- //
- // The TSY will complete with KErrNotSupported if it doesn't
- // support setting the send bearer.
- //
- if (iStatus.Int() == KErrNone ||
- iStatus.Int() == KErrNotSupported)
- {
- if (iSmsEventLogger->ClientAvailable())
- {
- CreateLogServerEvent();
- }
- else
- {
- SegmentMessage();
- }
- }
- }
- break;
-
- case ESmsMessageSendCreatingLogServerEvent:
- {
- //
- // If a log event was created ok, then store the id...
- //
- if (iStatus.Int() == KErrNone)
- {
- iSmsMessage->SetLogServerId(iSmsEventLogger->Event().Id());
- }
- else
- {
- iSmsEventLogger->Event().SetId(KLogNullId);
- }
-
- //
- // Segment the message. This will send the first PDU as well...
- //
- SegmentMessage();
- }
- break;
-
- case ESmsMessageSendSegmentingMessage:
- {
- //
- // If the previous PDU was sent ok, then send the next one...
- //
- if (iStatus.Int() == KErrNone)
- {
- SendNextPDU();
- }
- else
- {
- //
- // An error occured. Save the error for later and either
- // update the log event, or drop to the end of RunL() so
- // that Complete() is called...
- //
- iSendError = iStatus.Int();
-
- if (iSmsEventLogger->Event().Id() != KLogNullId)
- {
- UpdateLogServerEvent();
- }
- }
- }
- break;
-
- case ESmsMessageSendPDU:
- {
- //
- // If the PDU is sent with an acknowledgement, then decode the
- // submit report...
- //
- if (iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsSendWithAck &&
- iMobileSmsSendAttributesV1.iFlags & RMobileSmsMessaging::KGsmSubmitReport)
- {
- DecodeSubmitReportL();
- }
-
- if (iStatus.Int() == KErrNone && !IsRPError())
- {
- LOGSMSIF2("CSmsMessageSend::RunL(): Submit ACK'd MsgRef=%d",
- iMobileSmsSendAttributesV1.iMsgRef);
- }
- else if (IsRPError())
- {
- LOGSMSIF2("CSmsMessageSend::RunL(): Submit N'ACK'D MsgRef=%d",
- iMobileSmsSendAttributesV1.iMsgRef);
- }
- else
- {
- LOGSMSIF2("CSmsMessageSend::RunL(): MsgRef=%d",
- iMobileSmsSendAttributesV1.iMsgRef);
- }
-
- //
- // If the PDU was sent okay, then update the segmentation store...
- //
- if (iStatus.Int() ==KErrNone)
- {
- iSegmentSequenceNumber++;
- UpdateSegmentationStore();
- }
- else
- {
- //
- // An error occured. Save the error for later and either
- // update the log event, or drop to the end of RunL() so
- // that Complete() is called...
- //
- iSendError = iStatus.Int();
-
- if (iSmsEventLogger->Event().Id() != KLogNullId)
- {
- UpdateLogServerEvent();
- }
- }
- }
- break;
-
- case ESmsMessageSendUpdatingSegmentationStore:
- {
- if (iStatus.Int() == KErrNone)
- {
- //
- // The update has been successful, so update the log event or
- // send the next PDU. If the log event is updated, then it
- // will then send the next PDU...
- //
- if (iSmsEventLogger->Event().Id() != KLogNullId)
- {
- UpdateLogServerEvent();
- }
- else
- {
- SendNextPDU();
- }
- }
- else
- {
- //
- // An error occured. Save the error for later and either
- // update the log event, or drop to the end of RunL() so
- // that Complete() is called...
- //
- iSendError = iStatus.Int();
-
- if (iSmsEventLogger->Event().Id() != KLogNullId)
- {
- UpdateLogServerEvent();
- }
- }
- }
- break;
-
- case ESmsMessageSendUpdatingLogEvent:
- {
- //
- // Ignore log server error and continue with the next PDU if
- // the last send was okay, otherwise drop to the bottom of the
- // RunL() and Complete().
- //
- if (iSendError == KErrNone)
- {
- SendNextPDU();
- }
- }
- break;
-
- default:
- {
- SmspPanic(KSmspPanicUnexpectedState);
- }
- break;
- };
-
- //
- // DoRunL() will now return to CSmsuActiveBase which if the object
- // is not active, will call Complete().
- //
- } // CSmsMessageSend::DoRunL
-
-
-void CSmsMessageSend::DoCancel()
- {
- LOGSMSPROT2("CSmsMessageSend::DoCancel(): iState=%d", iState);
-
- TimedSetActiveCancel();
-
- switch (iState)
- {
- case ESmsMessageSendSetBearer:
- {
- iSmspSetBearer.Cancel();
- }
- break;
-
- case ESmsMessageSendSegmentingMessage:
- {
- // NOP
- }
- break;
-
- case ESmsMessageSendCreatingLogServerEvent:
- case ESmsMessageSendUpdatingLogEvent:
- {
- iSmsEventLogger->Cancel();
- }
- break;
-
- case ESmsMessageSendPDU:
- {
- iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingSendMessage);
- }
- break;
-
- case ESmsMessageSendUpdatingSegmentationStore:
- {
- // NOP
- }
- break;
-
- default:
- {
- SmspPanic(KSmspPanicUnexpectedState);
- }
- break;
- };
-
- iSendError = KErrCancel;
-
- //
- // Handle completion of this Active Object. Note that the object
- // may well still be active at this point...
- //
- if (TimedOut())
- {
- Complete(KErrTimedOut);
- }
- else
- {
- Complete(KErrCancel);
- }
- } // CSmsMessageSend::DoCancel
-
-
-/**
- * Decodes SMS-SUBMIT-REPORT PDU and checks if it is SMS-SUBMIT-REPORT for
- * RP-ERROR.
- *
- * @leave Leaves if CSmsBuffer::NewL or CSmsMessage::NewL leaves.
- *
- */
-void CSmsMessageSend::DecodeSubmitReportL()
- {
- LOGSMSPROT1("CSmsMessageSend::DecodeSubmitReportL()");
-
- //
- // Only try to decode the submit report if error is a RP-error, in which case there should be a valid PDU
- //
- if (IsRPError())
- {
- TGsmSms sms;
- sms.SetPdu(iMobileSmsSendAttributesV1.iSubmitReport);
- CSmsBuffer* buffer=CSmsBuffer::NewL();
-
- // try to create a sms message from the submit report PDU (smsMessage takes ownership of the buffer)
- CSmsMessage* smsMessage = CSmsMessage::NewL(iSegmentationStore.FileSession(),
- sms,buffer,IsRPError(),ETrue);
- CleanupStack::PushL(smsMessage);
-
- if (smsMessage->SmsPDU().Type() == CSmsPDU::ESmsSubmitReport)
- {
- CSmsSubmitReport& submitReport =(CSmsSubmitReport&) smsMessage->SmsPDU();
- TInt failureCause = submitReport.FailureCause();
-
- if (failureCause != TSmsFailureCause::ESmsErrorFree)
- {
- iStatus = FailureCauseToError(failureCause);
- }
- }
- else
- {
- LOGSMSPROT3("Invalid PDU Type = %d with iStatus = %d", smsMessage->SmsPDU().Type(), iStatus.Int() );
- }
-
- CleanupStack::PopAndDestroy(smsMessage);
- }
- } // CSmsMessageSend::DecodeSubmitReportL
-
-
-/**
- * Checks if TSY completed send message request with RP-error.
- *
- * @return boolean.
- */
-TBool CSmsMessageSend::IsRPError() const
- {
- LOGSMSPROT1("CSmsMessageSend::IsRPError()");
-
- TBool isRPError = EFalse;
-
- switch (iStatus.Int())
- {
- case KErrGsmSMSUnassignedNumber:
- case KErrGsmSMSOperatorDeterminedBarring:
- case KErrGsmSMSCallBarred:
- case KErrGsmSMSReserved:
- case KErrGsmSMSNetworkFailure:
- case KErrGsmSMSShortMessageTransferRejected:
- case KErrGsmSMSMemoryCapacityExceeded:
- case KErrGsmSMSDestinationOutOfOrder:
- case KErrGsmSMSUnidentifiedSubscriber:
- case KErrGsmSMSFacilityRejected:
- case KErrGsmSMSUnknownSubscriber:
- case KErrGsmSMSNetworkOutOfOrder:
- case KErrGsmSMSTemporaryFailure:
- case KErrGsmSMSCongestion:
- case KErrGsmSMSResourcesUnavailable:
- case KErrGsmSMSRequestedFacilityNotSubscribed:
- case KErrGsmSMSRequestedFacilityNotImplemented:
- case KErrGsmSMSInvalidShortMessageTransferReferenceValue:
- case KErrGsmSMSUnspecifiedInvalidMessage:
- case KErrGsmSMSInvalidMandatoryInformation:
- case KErrGsmSMSNonExistentMessageType:
- case KErrGsmSMSIncompatibleMessageWithSmsProtocolState:
- case KErrGsmSMSInformationElementNotImplemented:
- case KErrGsmSMSUnspecifiedProtocolError:
- case KErrGsmSMSUnspecifiedInterworkingError:
- {
- isRPError = ETrue;
- }
- break;
-
- default:
- {
- // NOP
- }
- break;
- }
-
- return isRPError;
- } // CSmsMessageSend::IsRPError
-
-
-void CSmsMessageSend::SegmentMessage()
- {
- LOGSMSPROT1("CSmsMessageSend::SegmentMessage()");
-
- iState = ESmsMessageSendSegmentingMessage;
-
- TRAPD(ret,DoSegmentMessageL());
-
- CompleteMyself(ret);
- } // CSmsMessageSend::SegmentMessage
-
-
-void CSmsMessageSend::DoSegmentMessageL()
- {
- LOGSMSPROT1("CSmsMessageSend::DoSegmentMessageL()");
-
- TInt reference=0;
- if (iSmsMessage->Type()==CSmsPDU::ESmsCommand)
- {
- CSmsCommand& command=(CSmsCommand&) iSmsMessage->SmsPDU();
-
- CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray referencearray;
- CleanupClosePushL(referencearray);
-
- if (!iSegmentationStore.AddCommandL(iSmsAddr,*iSmsMessage, referencearray))
- {
- User::Leave(KErrNotFound);
- }
-
- const TInt count=referencearray.Count();
- CArrayFix<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
- CleanupStack::PushL(smsarray);
-
- for (TInt i=0; i<count; i++)
- {
- command.SetMessageNumber(referencearray[i].Reference());
- //TODO should reference be set to referencearray[i].iReference here?
- iSmsMessage->EncodeMessagePDUsL(*smsarray, reference);
- iSmsArray.AppendL(smsarray->At(0));
- smsarray->Reset();
- }
- CleanupStack::PopAndDestroy(2); // smsarray, referencearray
- }
- else
- {
- TBool iSentBefore=EFalse;
- TBool is16bit = EFalse;
- TBool concatenationIEPresent= iSmsMessage->SmsPDU().TextConcatenated( &is16bit );
- iSmsMessage->SmsPDU().SetTextConcatenatedL(EFalse,EFalse);
-
- // Fix for INC039985;
- // The cause was that resending a SMS message(single PDU, same LogId),
- // caused an assertion fault; This did not happen with an SMS with multiple PDUs.
- // The reason for that is that for the multiple PDU case the stack employes a caching mechanism
- // built in - it checks which PDUs from an SMS message have already been sent and
- // then sends only the ones which have not been sent. This is performed by using the LodId,
- // which is used to uniquely identify an SMS message and the PDUs it consists of.
- // If an SMS message consisting of multiple PDUs is resend by an application and it has been already
- // sent sucessfully, the stack deletes the previous entry corresponding to the old LogId
- // segmentation store and replaces it with the new one with a new logid.
- // This mechanism has been extended for SMS messages consisting of single PDU.
- if(!iSmsMessage->EncodeIntoSinglePDUL(iSmsArray))
- {
- if (concatenationIEPresent && is16bit)
- {
- iSmsMessage->Set16BitConcatenation(ETrue);
- }
-
- if(iSegmentationStore.HasEntryWithLogIdL(iSmsMessage->LogServerId(),reference,iSmsPDUData.iSent))
- {
- iSentBefore=ETrue;
- }
- else
- {
- reference=is16bit? iSegmentationStore.Next16BitReferenceL(): iSegmentationStore.Next8BitReferenceL();
- }
- iSmsMessage->EncodeMessagePDUsL(iSmsArray, reference);
- }
- else
- {
- if( iSegmentationStore.HasEntryWithLogIdL(iSmsMessage->LogServerId(),reference,iSmsPDUData.iSent))
- {
- iSentBefore=ETrue;
- }
- }
-
- LOGSMSPROT3("CSmsMesageSend::DoSegmentMessageL [LogServerId=%d][iSentBefore=%d]",iSmsMessage->LogServerId(),iSentBefore);
- LOGSMSPROT3("CSmsMesageSend::DoSegmentMessageL [referenceNo=%d] [iCountOfSentBefore=%d ]",reference,iSmsPDUData.iSent);
- if(!iSentBefore)
- {
- iSegmentationStore.AddSubmitL(iSmsAddr,*iSmsMessage);
- }
- }
- } // CSmsMessageSend::DoSegmentMessageL
-
-
-void CSmsMessageSend::CreateLogServerEvent()
- {
- LOGSMSPROT1("CSmsMessageSend::CreateLogServerEvent()");
-
- iState=ESmsMessageSendCreatingLogServerEvent;
- TLogId logid=(TLogId) iSmsMessage->LogServerId();
-
- if (logid == KLogNullId)
- {
- iSmsPDUData.iTotal=iSmsArray.Count();
- iSmsEventLogger->AddEvent(iStatus,*iSmsMessage,iSmsPDUData);
- }
- else
- {
- iSmsEventLogger->GetEvent(iStatus,logid);
- }
- SetActive();
- } // CSmsMessageSend::CreateLogServerEvent
-
-
-void CSmsMessageSend::SendNextPDU()
- {
- LOGSMSPROT3("CSmsMessageSend::SendNextPDU [sending pdu %d of count=%d]",iSmsPDUData.iSent, iSmsArray.Count() );
-
- if (iSmsPDUData.iSent<iSmsArray.Count())
- {
- NMobilePhone::TMobileTON ton;
- NMobilePhone::TMobileNPI npi;
-
- TGsmSmsTelNumber parsedAddress(iSmsArray[iSmsPDUData.iSent].Sca());
-
- iMobileSmsSendAttributesV1.iFlags = RMobileSmsMessaging::KGsmServiceCentre |
- RMobileSmsMessaging::KRemotePartyInfo |
- RMobileSmsMessaging::KSmsDataFormat |
- RMobileSmsMessaging::KMoreToSend;
-
- //
- // Set service centre address...
- //
- parsedAddress.iTypeOfAddress.ConvertToETelMM(ton, npi);
- iMobileSmsSendAttributesV1.iGsmServiceCentre.iTelNumber = parsedAddress.iTelNumber;
- iMobileSmsSendAttributesV1.iGsmServiceCentre.iTypeOfNumber = static_cast<RMobilePhone::TMobileTON>(static_cast<TInt>(ton));
- iMobileSmsSendAttributesV1.iGsmServiceCentre.iNumberPlan = static_cast<RMobilePhone::TMobileNPI>(static_cast<TInt>(npi));
-
- //
- // Set destination address...
- //
- iToFromTelNumber.iTypeOfAddress.ConvertToETelMM(ton, npi);
- iMobileSmsSendAttributesV1.iDestination.iTelNumber = iToFromTelNumber.iTelNumber;
- iMobileSmsSendAttributesV1.iDestination.iTypeOfNumber = static_cast<RMobilePhone::TMobileTON>(static_cast<TInt>(ton));
- iMobileSmsSendAttributesV1.iDestination.iNumberPlan = static_cast<RMobilePhone::TMobileNPI>(static_cast<TInt>(npi));
-
- iMobileSmsSendAttributesV1.iDataFormat = RMobileSmsMessaging::EFormatGsmTpdu;
-
- if (iSmsPDUData.iSent < iSmsArray.Count() - 1)
- {
- iMobileSmsSendAttributesV1.iMore = ETrue;
- }
- else
- {
- iMobileSmsSendAttributesV1.iMore = EFalse;
- }
-
- //
- // Debug logging of the PDU we are sending...
- //
- LOGSMSIFPDU(_L8("ETEL TX PDU: "), iSmsArray[iSmsPDUData.iSent].Pdu(), ETrue);
- LOGSMSIFSENDATTRIBUTES(_L8("SENDATTRIBS: "), iMobileSmsSendAttributesV1);
- LOGSMSIFTIMESTAMP();
-
- //
- // Send the message and enter the correct state...
- //
- iState = ESmsMessageSendPDU;
- iSmsMessaging.SendMessage(iStatus, iSmsArray[iSmsPDUData.iSent].Pdu(),
- iMobileSmsSendAttributesV1Pckg);
- TimedSetActive(iSmsSettings.SendTryTimeout());
- }
- } // CSmsMessageSend::SendNextPDU
-
-
-void CSmsMessageSend::UpdateSegmentationStore()
- {
- iState = ESmsMessageSendUpdatingSegmentationStore;
-
- TRAPD(ret,DoUpdateSegmentationStoreL());
-
- CompleteMyself(ret);
- } // CSmsMessageSend::UpdateSegmentationStore
-
-
-void CSmsMessageSend::DoUpdateSegmentationStoreL()
- {
- LOGSMSPROT1("CSmsMessageSend::DoUpdateSegmentationStoreL()");
-
- iSmsPDUData.iSent++; // This is the end of the sequence for sending an SMS PDU
-
- if (iSmsMessage->Scheme() == EControlParametersScheme ||
- iSmsMessage->Scheme() == ETPSRRScheme)
- {
- iSegmentationStore.AddReferenceStatusPairL(*iSmsMessage,(TInt) iMobileSmsSendAttributesV1.iMsgRef, iSegmentSequenceNumber);
- }
- else if (iSmsMessage->Scheme() == EDefaultScheme)
- {
- iSegmentationStore.AddReferenceL(*iSmsMessage,(TInt) iMobileSmsSendAttributesV1.iMsgRef);
- }
- else
- {
- User::Leave(KErrNotFound);
- }
- } // CSmsMessageSend::DoUpdateSegmentationStoreL
-
-
-void CSmsMessageSend::UpdateLogServerEvent()
- {
- LOGSMSPROT1("CSmsMessageSend::UpdateLogServerEvent()");
-
- //
- // Fill in log event...
- //
- iState = ESmsMessageSendUpdatingLogEvent;
- iSmsPDUData.iTotal = iSmsArray.Count();
- iSmsEventLogger->ChangeEvent(iStatus, *iSmsMessage, iSmsPDUData);
- SetActive();
- } // CSmsMessageSend::UpdateLogServerEvent
-
-
-void CSmsMessageSend::Complete(TInt aStatus)
- {
- LOGSMSPROT3("CSmsMessageSend::Complete [iStatus=%d, iState=%d]", iStatus.Int(), iState );
-
- //
- // For completion during log events, use the saved error code instead...
- //
- if (iState == ESmsMessageSendCreatingLogServerEvent ||
- iState == ESmsMessageSendUpdatingLogEvent)
- {
- aStatus = iSendError;
- }
-
- //
- // Clear all PDU data that was sent...
- //
- for (TInt i=0; i < iSmsPDUData.iSent; i++)
- {
- iSmsArray.Delete(0);
- }
-
- iSmsArray.Reset();
-
- iState = ESmsMessageSendIdle;
-
- //
- // Call the base function to perform the actual complete...
- //
- CSmsuActiveBase::Complete(aStatus);
- } // CSmsMessageSend::Complete
+// 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 for the CSmsuActiveBase based class CSmsMessageSend.
+//
+//
+
+/**
+ @file
+ @internalAll
+*/
+
+#include "smspsend.h"
+#include "smspstor.h"
+#include "smspmain.h"
+#include "smsuset.h"
+#include "smsulog.h"
+#include "exterror.h"
+#include "gsmubuf.h"
+#include "SmsuTimer.h"
+#include <logwraplimits.h>
+
+
+/**
+ * Static object constructor for CSmsMessageSend.
+ *
+ * @param aSegmentationStore Segmentation Store.
+ * @param aSmsMessaging ETel SMS messaging subsession.
+ * @param aSmsSettings The global SMS settings.
+ * @param aMobileSmsCaps SMS messaging capabilities of TSY/phone.
+ * @param aPriority Priority to use for the Active Object.
+ * @param aSmspSetBearer Set bearer object.
+ */
+CSmsMessageSend* CSmsMessageSend::NewL(CSmsSegmentationStore& aSegmentationStore,
+ const TSmsSettings& aSmsSettings,
+ const RMobileSmsMessaging::TMobileSmsCapsV1& aMobileSmsCaps,
+ RMobileSmsMessaging& aSmsMessaging,
+ TInt aPriority,
+ CSmspSetBearer& aSmspSetBearer)
+ {
+ LOGSMSPROT1("CSmsMessageSend::NewL()");
+
+ CSmsMessageSend* self = new (ELeave) CSmsMessageSend(aSegmentationStore,
+ aSmsSettings,
+ aMobileSmsCaps,
+ aSmsMessaging,
+ aPriority,
+ aSmspSetBearer);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+
+ return self;
+ } // CSmsMessageSend::NewL
+
+
+/**
+ * 2nd Phase of construction.
+ *
+ * Creates CSmsTimeout object and the SMS event logger.
+ */
+void CSmsMessageSend::ConstructL()
+ {
+ LOGSMSPROT1("CSmsMessageSend::ConstructL()");
+
+ iSmsEventLogger = CSmsEventLogger::NewL(iSegmentationStore.FileSession(),
+ Priority());
+
+ ConstructTimeoutL();
+ } // CSmsMessageSend::ConstructL
+
+
+/**
+ * Default constructor.
+ *
+ * @param aSegmentationStore Segmentation Store.
+ * @param aSmsSettings The global SMS settings.
+ * @param aMobileSmsCaps SMS messaging capabilities of TSY/phone.
+ * @param aSmsMessaging ETel SMS messaging subsession.
+ * @param aPriority Priority to use for the Active Object.
+ * @param aSmspSetBearer Set bearer object.
+ */
+CSmsMessageSend::CSmsMessageSend(CSmsSegmentationStore& aSegmentationStore,
+ const TSmsSettings& aSmsSettings,
+ const RMobileSmsMessaging::TMobileSmsCapsV1& aMobileSmsCaps,
+ RMobileSmsMessaging& aSmsMessaging,
+ TInt aPriority,
+ CSmspSetBearer& aSmspSetBearer)
+ : CSmsuActiveBase(aPriority),
+ iState(ESmsMessageSendIdle),
+ iSegmentationStore(aSegmentationStore),
+ iSmspSetBearer(aSmspSetBearer),
+ iSmsSettings(aSmsSettings),
+ iMobileSmsCaps(aMobileSmsCaps),
+ iSmsMessaging(aSmsMessaging),
+ iMobileSmsSendAttributesV1Pckg(iMobileSmsSendAttributesV1),
+ iSmsArray(8),
+ iSegmentSequenceNumber(-1)
+ {
+ // NOP
+ } // CSmsMessageSend::CSmsMessageSend
+
+
+/**
+ * Standard destructor.
+ */
+CSmsMessageSend::~CSmsMessageSend()
+ {
+ Cancel();
+ delete iSmsEventLogger;
+ } // CSmsMessageSend::~CSmsMessageSend
+
+
+void CSmsMessageSend::Start(CSmsMessage& aSmsMessage, TInt aOptions,
+ const TSmsAddr& aSmsAddr, TRequestStatus& aStatus)
+ {
+ LOGSMSPROT1("CSmsMessageSend::Start()");
+
+ __ASSERT_DEBUG(iState == ESmsMessageSendIdle,SmspPanic(KSmspPanicUnexpectedState));
+
+ //
+ // Store the request status that we will complete when finished...
+ //
+ Queue(aStatus);
+
+ //
+ // Initialise member data...
+ //
+ iSmsMessage=&aSmsMessage;
+ iSmsMessage->ParsedToFromAddress(iToFromTelNumber);
+ iOptions = aOptions;
+ iSmsAddr = aSmsAddr;
+
+ iSmsPDUData.iType = aSmsMessage.Type();
+ iSmsPDUData.iTotal = 0;
+ iSmsPDUData.iSent = 0;
+ iSmsPDUData.iDelivered = 0;
+
+ iSendError = KErrNone;
+ iSmsEventLogger->Event().SetId(KLogNullId);
+
+ //
+ // Begin by setting the bearer...
+ //
+ iState = ESmsMessageSendSetBearer;
+ iSmspSetBearer.NotifyBearerSet(iStatus);
+ SetActive();
+ } // CSmsMessageSend::Start
+
+
+void CSmsMessageSend::DoRunL()
+ {
+ LOGSMSPROT3("CSmsMessageSend::RunL(): iStatus=%d, iState=%d", iStatus.Int(), iState);
+
+ switch (iState)
+ {
+ case ESmsMessageSendSetBearer:
+ {
+ //
+ // If setting of bearer was successful then send the message.
+ //
+ // The TSY will complete with KErrNotSupported if it doesn't
+ // support setting the send bearer.
+ //
+ if (iStatus.Int() == KErrNone ||
+ iStatus.Int() == KErrNotSupported)
+ {
+ if (iSmsEventLogger->ClientAvailable())
+ {
+ CreateLogServerEvent();
+ }
+ else
+ {
+ SegmentMessage();
+ }
+ }
+ }
+ break;
+
+ case ESmsMessageSendCreatingLogServerEvent:
+ {
+ //
+ // If a log event was created ok, then store the id...
+ //
+ if (iStatus.Int() == KErrNone)
+ {
+ iSmsMessage->SetLogServerId(iSmsEventLogger->Event().Id());
+ }
+ else
+ {
+ iSmsEventLogger->Event().SetId(KLogNullId);
+ }
+
+ //
+ // Segment the message. This will send the first PDU as well...
+ //
+ SegmentMessage();
+ }
+ break;
+
+ case ESmsMessageSendSegmentingMessage:
+ {
+ //
+ // If the previous PDU was sent ok, then send the next one...
+ //
+ if (iStatus.Int() == KErrNone)
+ {
+ SendNextPDU();
+ }
+ else
+ {
+ //
+ // An error occured. Save the error for later and either
+ // update the log event, or drop to the end of RunL() so
+ // that Complete() is called...
+ //
+ iSendError = iStatus.Int();
+
+ if (iSmsEventLogger->Event().Id() != KLogNullId)
+ {
+ UpdateLogServerEvent();
+ }
+ }
+ }
+ break;
+
+ case ESmsMessageSendPDU:
+ {
+ //
+ // If the PDU is sent with an acknowledgement, then decode the
+ // submit report...
+ //
+ if (iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsSendWithAck &&
+ iMobileSmsSendAttributesV1.iFlags & RMobileSmsMessaging::KGsmSubmitReport)
+ {
+ DecodeSubmitReportL();
+ }
+
+ if (iStatus.Int() == KErrNone && !IsRPError())
+ {
+ LOGSMSIF2("CSmsMessageSend::RunL(): Submit ACK'd MsgRef=%d",
+ iMobileSmsSendAttributesV1.iMsgRef);
+ }
+ else if (IsRPError())
+ {
+ LOGSMSIF2("CSmsMessageSend::RunL(): Submit N'ACK'D MsgRef=%d",
+ iMobileSmsSendAttributesV1.iMsgRef);
+ }
+ else
+ {
+ LOGSMSIF2("CSmsMessageSend::RunL(): MsgRef=%d",
+ iMobileSmsSendAttributesV1.iMsgRef);
+ }
+
+ //
+ // If the PDU was sent okay, then update the segmentation store...
+ //
+ if (iStatus.Int() ==KErrNone)
+ {
+ iSegmentSequenceNumber++;
+ UpdateSegmentationStore();
+ }
+ else
+ {
+ //
+ // An error occured. Save the error for later and either
+ // update the log event, or drop to the end of RunL() so
+ // that Complete() is called...
+ //
+ iSendError = iStatus.Int();
+
+ if (iSmsEventLogger->Event().Id() != KLogNullId)
+ {
+ UpdateLogServerEvent();
+ }
+ }
+ }
+ break;
+
+ case ESmsMessageSendUpdatingSegmentationStore:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ //
+ // The update has been successful, so update the log event or
+ // send the next PDU. If the log event is updated, then it
+ // will then send the next PDU...
+ //
+ if (iSmsEventLogger->Event().Id() != KLogNullId)
+ {
+ UpdateLogServerEvent();
+ }
+ else
+ {
+ SendNextPDU();
+ }
+ }
+ else
+ {
+ //
+ // An error occured. Save the error for later and either
+ // update the log event, or drop to the end of RunL() so
+ // that Complete() is called...
+ //
+ iSendError = iStatus.Int();
+
+ if (iSmsEventLogger->Event().Id() != KLogNullId)
+ {
+ UpdateLogServerEvent();
+ }
+ }
+ }
+ break;
+
+ case ESmsMessageSendUpdatingLogEvent:
+ {
+ //
+ // Ignore log server error and continue with the next PDU if
+ // the last send was okay, otherwise drop to the bottom of the
+ // RunL() and Complete().
+ //
+ if (iSendError == KErrNone)
+ {
+ SendNextPDU();
+ }
+ }
+ break;
+
+ default:
+ {
+ SmspPanic(KSmspPanicUnexpectedState);
+ }
+ break;
+ };
+
+ //
+ // DoRunL() will now return to CSmsuActiveBase which if the object
+ // is not active, will call Complete().
+ //
+ } // CSmsMessageSend::DoRunL
+
+
+void CSmsMessageSend::DoCancel()
+ {
+ LOGSMSPROT2("CSmsMessageSend::DoCancel(): iState=%d", iState);
+
+ TimedSetActiveCancel();
+
+ switch (iState)
+ {
+ case ESmsMessageSendSetBearer:
+ {
+ iSmspSetBearer.Cancel();
+ }
+ break;
+
+ case ESmsMessageSendSegmentingMessage:
+ {
+ // NOP
+ }
+ break;
+
+ case ESmsMessageSendCreatingLogServerEvent:
+ case ESmsMessageSendUpdatingLogEvent:
+ {
+ iSmsEventLogger->Cancel();
+ }
+ break;
+
+ case ESmsMessageSendPDU:
+ {
+ iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingSendMessage);
+ }
+ break;
+
+ case ESmsMessageSendUpdatingSegmentationStore:
+ {
+ // NOP
+ }
+ break;
+
+ default:
+ {
+ SmspPanic(KSmspPanicUnexpectedState);
+ }
+ break;
+ };
+
+ iSendError = KErrCancel;
+
+ //
+ // Handle completion of this Active Object. Note that the object
+ // may well still be active at this point...
+ //
+ if (TimedOut())
+ {
+ Complete(KErrTimedOut);
+ }
+ else
+ {
+ Complete(KErrCancel);
+ }
+ } // CSmsMessageSend::DoCancel
+
+
+/**
+ * Decodes SMS-SUBMIT-REPORT PDU and checks if it is SMS-SUBMIT-REPORT for
+ * RP-ERROR.
+ *
+ * @leave Leaves if CSmsBuffer::NewL or CSmsMessage::NewL leaves.
+ *
+ */
+void CSmsMessageSend::DecodeSubmitReportL()
+ {
+ LOGSMSPROT1("CSmsMessageSend::DecodeSubmitReportL()");
+
+ //
+ // Only try to decode the submit report if error is a RP-error, in which case there should be a valid PDU
+ //
+ if (IsRPError())
+ {
+ TGsmSms sms;
+ sms.SetPdu(iMobileSmsSendAttributesV1.iSubmitReport);
+ CSmsBuffer* buffer=CSmsBuffer::NewL();
+
+ // try to create a sms message from the submit report PDU (smsMessage takes ownership of the buffer)
+ CSmsMessage* smsMessage = CSmsMessage::NewL(iSegmentationStore.FileSession(),
+ sms,buffer,IsRPError(),ETrue);
+ CleanupStack::PushL(smsMessage);
+
+ if (smsMessage->SmsPDU().Type() == CSmsPDU::ESmsSubmitReport)
+ {
+ CSmsSubmitReport& submitReport =(CSmsSubmitReport&) smsMessage->SmsPDU();
+ TInt failureCause = submitReport.FailureCause();
+
+ if (failureCause != TSmsFailureCause::ESmsErrorFree)
+ {
+ iStatus = FailureCauseToError(failureCause);
+ }
+ }
+ else
+ {
+ LOGSMSPROT3("Invalid PDU Type = %d with iStatus = %d", smsMessage->SmsPDU().Type(), iStatus.Int() );
+ }
+
+ CleanupStack::PopAndDestroy(smsMessage);
+ }
+ } // CSmsMessageSend::DecodeSubmitReportL
+
+
+/**
+ * Checks if TSY completed send message request with RP-error.
+ *
+ * @return boolean.
+ */
+TBool CSmsMessageSend::IsRPError() const
+ {
+ LOGSMSPROT1("CSmsMessageSend::IsRPError()");
+
+ TBool isRPError = EFalse;
+
+ switch (iStatus.Int())
+ {
+ case KErrGsmSMSUnassignedNumber:
+ case KErrGsmSMSOperatorDeterminedBarring:
+ case KErrGsmSMSCallBarred:
+ case KErrGsmSMSReserved:
+ case KErrGsmSMSNetworkFailure:
+ case KErrGsmSMSShortMessageTransferRejected:
+ case KErrGsmSMSMemoryCapacityExceeded:
+ case KErrGsmSMSDestinationOutOfOrder:
+ case KErrGsmSMSUnidentifiedSubscriber:
+ case KErrGsmSMSFacilityRejected:
+ case KErrGsmSMSUnknownSubscriber:
+ case KErrGsmSMSNetworkOutOfOrder:
+ case KErrGsmSMSTemporaryFailure:
+ case KErrGsmSMSCongestion:
+ case KErrGsmSMSResourcesUnavailable:
+ case KErrGsmSMSRequestedFacilityNotSubscribed:
+ case KErrGsmSMSRequestedFacilityNotImplemented:
+ case KErrGsmSMSInvalidShortMessageTransferReferenceValue:
+ case KErrGsmSMSUnspecifiedInvalidMessage:
+ case KErrGsmSMSInvalidMandatoryInformation:
+ case KErrGsmSMSNonExistentMessageType:
+ case KErrGsmSMSIncompatibleMessageWithSmsProtocolState:
+ case KErrGsmSMSInformationElementNotImplemented:
+ case KErrGsmSMSUnspecifiedProtocolError:
+ case KErrGsmSMSUnspecifiedInterworkingError:
+ {
+ isRPError = ETrue;
+ }
+ break;
+
+ default:
+ {
+ // NOP
+ }
+ break;
+ }
+
+ return isRPError;
+ } // CSmsMessageSend::IsRPError
+
+
+void CSmsMessageSend::SegmentMessage()
+ {
+ LOGSMSPROT1("CSmsMessageSend::SegmentMessage()");
+
+ iState = ESmsMessageSendSegmentingMessage;
+
+ TRAPD(ret,DoSegmentMessageL());
+
+ CompleteMyself(ret);
+ } // CSmsMessageSend::SegmentMessage
+
+
+void CSmsMessageSend::DoSegmentMessageL()
+ {
+ LOGSMSPROT1("CSmsMessageSend::DoSegmentMessageL()");
+
+ TInt reference=0;
+ if (iSmsMessage->Type()==CSmsPDU::ESmsCommand)
+ {
+ CSmsCommand& command=(CSmsCommand&) iSmsMessage->SmsPDU();
+
+ CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray referencearray;
+ CleanupClosePushL(referencearray);
+
+ if (!iSegmentationStore.AddCommandL(iSmsAddr,*iSmsMessage, referencearray))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ const TInt count=referencearray.Count();
+ CArrayFix<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
+ CleanupStack::PushL(smsarray);
+
+ for (TInt i=0; i<count; i++)
+ {
+ command.SetMessageNumber(referencearray[i].Reference());
+ //TODO should reference be set to referencearray[i].iReference here?
+ iSmsMessage->EncodeMessagePDUsL(*smsarray, reference);
+ iSmsArray.AppendL(smsarray->At(0));
+ smsarray->Reset();
+ }
+ CleanupStack::PopAndDestroy(2); // smsarray, referencearray
+ }
+ else
+ {
+ TBool iSentBefore=EFalse;
+ TBool is16bit = EFalse;
+ TBool concatenationIEPresent= iSmsMessage->SmsPDU().TextConcatenated( &is16bit );
+ iSmsMessage->SmsPDU().SetTextConcatenatedL(EFalse,EFalse);
+
+ // Fix for INC039985;
+ // The cause was that resending a SMS message(single PDU, same LogId),
+ // caused an assertion fault; This did not happen with an SMS with multiple PDUs.
+ // The reason for that is that for the multiple PDU case the stack employes a caching mechanism
+ // built in - it checks which PDUs from an SMS message have already been sent and
+ // then sends only the ones which have not been sent. This is performed by using the LodId,
+ // which is used to uniquely identify an SMS message and the PDUs it consists of.
+ // If an SMS message consisting of multiple PDUs is resend by an application and it has been already
+ // sent sucessfully, the stack deletes the previous entry corresponding to the old LogId
+ // segmentation store and replaces it with the new one with a new logid.
+ // This mechanism has been extended for SMS messages consisting of single PDU.
+ if(!iSmsMessage->EncodeIntoSinglePDUL(iSmsArray))
+ {
+ if (concatenationIEPresent && is16bit)
+ {
+ iSmsMessage->Set16BitConcatenation(ETrue);
+ }
+
+ if(iSegmentationStore.HasEntryWithLogIdL(iSmsMessage->LogServerId(),reference,iSmsPDUData.iSent))
+ {
+ iSentBefore=ETrue;
+ }
+ else
+ {
+ reference=is16bit? iSegmentationStore.Next16BitReferenceL(): iSegmentationStore.Next8BitReferenceL();
+ }
+ iSmsMessage->EncodeMessagePDUsL(iSmsArray, reference);
+ }
+ else
+ {
+ if( iSegmentationStore.HasEntryWithLogIdL(iSmsMessage->LogServerId(),reference,iSmsPDUData.iSent))
+ {
+ iSentBefore=ETrue;
+ }
+ }
+
+ LOGSMSPROT3("CSmsMesageSend::DoSegmentMessageL [LogServerId=%d][iSentBefore=%d]",iSmsMessage->LogServerId(),iSentBefore);
+ LOGSMSPROT3("CSmsMesageSend::DoSegmentMessageL [referenceNo=%d] [iCountOfSentBefore=%d ]",reference,iSmsPDUData.iSent);
+ if(!iSentBefore)
+ {
+ iSegmentationStore.AddSubmitL(iSmsAddr,*iSmsMessage);
+ }
+ }
+ } // CSmsMessageSend::DoSegmentMessageL
+
+
+void CSmsMessageSend::CreateLogServerEvent()
+ {
+ LOGSMSPROT1("CSmsMessageSend::CreateLogServerEvent()");
+
+ iState=ESmsMessageSendCreatingLogServerEvent;
+ TLogId logid=(TLogId) iSmsMessage->LogServerId();
+
+ if (logid == KLogNullId)
+ {
+ iSmsPDUData.iTotal=iSmsArray.Count();
+ iSmsEventLogger->AddEvent(iStatus,*iSmsMessage,iSmsPDUData);
+ }
+ else
+ {
+ iSmsEventLogger->GetEvent(iStatus,logid);
+ }
+ SetActive();
+ } // CSmsMessageSend::CreateLogServerEvent
+
+
+void CSmsMessageSend::SendNextPDU()
+ {
+ LOGSMSPROT3("CSmsMessageSend::SendNextPDU [sending pdu %d of count=%d]",iSmsPDUData.iSent, iSmsArray.Count() );
+
+ if (iSmsPDUData.iSent<iSmsArray.Count())
+ {
+ NMobilePhone::TMobileTON ton;
+ NMobilePhone::TMobileNPI npi;
+
+ TGsmSmsTelNumber parsedAddress(iSmsArray[iSmsPDUData.iSent].Sca());
+
+ iMobileSmsSendAttributesV1.iFlags = RMobileSmsMessaging::KGsmServiceCentre |
+ RMobileSmsMessaging::KRemotePartyInfo |
+ RMobileSmsMessaging::KSmsDataFormat |
+ RMobileSmsMessaging::KMoreToSend;
+
+ //
+ // Set service centre address...
+ //
+ parsedAddress.iTypeOfAddress.ConvertToETelMM(ton, npi);
+ iMobileSmsSendAttributesV1.iGsmServiceCentre.iTelNumber = parsedAddress.iTelNumber;
+ iMobileSmsSendAttributesV1.iGsmServiceCentre.iTypeOfNumber = static_cast<RMobilePhone::TMobileTON>(static_cast<TInt>(ton));
+ iMobileSmsSendAttributesV1.iGsmServiceCentre.iNumberPlan = static_cast<RMobilePhone::TMobileNPI>(static_cast<TInt>(npi));
+
+ //
+ // Set destination address...
+ //
+ iToFromTelNumber.iTypeOfAddress.ConvertToETelMM(ton, npi);
+ iMobileSmsSendAttributesV1.iDestination.iTelNumber = iToFromTelNumber.iTelNumber;
+ iMobileSmsSendAttributesV1.iDestination.iTypeOfNumber = static_cast<RMobilePhone::TMobileTON>(static_cast<TInt>(ton));
+ iMobileSmsSendAttributesV1.iDestination.iNumberPlan = static_cast<RMobilePhone::TMobileNPI>(static_cast<TInt>(npi));
+
+ iMobileSmsSendAttributesV1.iDataFormat = RMobileSmsMessaging::EFormatGsmTpdu;
+
+ if (iSmsPDUData.iSent < iSmsArray.Count() - 1)
+ {
+ iMobileSmsSendAttributesV1.iMore = ETrue;
+ }
+ else
+ {
+ iMobileSmsSendAttributesV1.iMore = EFalse;
+ }
+
+ //
+ // Debug logging of the PDU we are sending...
+ //
+ LOGSMSIFPDU(_L8("ETEL TX PDU: "), iSmsArray[iSmsPDUData.iSent].Pdu(), ETrue);
+ LOGSMSIFSENDATTRIBUTES(_L8("SENDATTRIBS: "), iMobileSmsSendAttributesV1);
+ LOGSMSIFTIMESTAMP();
+
+ //
+ // Send the message and enter the correct state...
+ //
+ iState = ESmsMessageSendPDU;
+ iSmsMessaging.SendMessage(iStatus, iSmsArray[iSmsPDUData.iSent].Pdu(),
+ iMobileSmsSendAttributesV1Pckg);
+ TimedSetActive(iSmsSettings.SendTryTimeout());
+ }
+ } // CSmsMessageSend::SendNextPDU
+
+
+void CSmsMessageSend::UpdateSegmentationStore()
+ {
+ iState = ESmsMessageSendUpdatingSegmentationStore;
+
+ TRAPD(ret,DoUpdateSegmentationStoreL());
+
+ CompleteMyself(ret);
+ } // CSmsMessageSend::UpdateSegmentationStore
+
+
+void CSmsMessageSend::DoUpdateSegmentationStoreL()
+ {
+ LOGSMSPROT1("CSmsMessageSend::DoUpdateSegmentationStoreL()");
+
+ iSmsPDUData.iSent++; // This is the end of the sequence for sending an SMS PDU
+
+ if (iSmsMessage->Scheme() == EControlParametersScheme ||
+ iSmsMessage->Scheme() == ETPSRRScheme)
+ {
+ iSegmentationStore.AddReferenceStatusPairL(*iSmsMessage,(TInt) iMobileSmsSendAttributesV1.iMsgRef, iSegmentSequenceNumber);
+ }
+ else if (iSmsMessage->Scheme() == EDefaultScheme)
+ {
+ iSegmentationStore.AddReferenceL(*iSmsMessage,(TInt) iMobileSmsSendAttributesV1.iMsgRef);
+ }
+ else
+ {
+ User::Leave(KErrNotFound);
+ }
+ } // CSmsMessageSend::DoUpdateSegmentationStoreL
+
+
+void CSmsMessageSend::UpdateLogServerEvent()
+ {
+ LOGSMSPROT1("CSmsMessageSend::UpdateLogServerEvent()");
+
+ //
+ // Fill in log event...
+ //
+ iState = ESmsMessageSendUpdatingLogEvent;
+ iSmsPDUData.iTotal = iSmsArray.Count();
+ iSmsEventLogger->ChangeEvent(iStatus, *iSmsMessage, iSmsPDUData);
+ SetActive();
+ } // CSmsMessageSend::UpdateLogServerEvent
+
+
+void CSmsMessageSend::Complete(TInt aStatus)
+ {
+ LOGSMSPROT3("CSmsMessageSend::Complete [iStatus=%d, iState=%d]", iStatus.Int(), iState );
+
+ //
+ // For completion during log events, use the saved error code instead...
+ //
+ if (iState == ESmsMessageSendCreatingLogServerEvent ||
+ iState == ESmsMessageSendUpdatingLogEvent)
+ {
+ aStatus = iSendError;
+ }
+
+ //
+ // Clear all PDU data that was sent...
+ //
+ for (TInt i=0; i < iSmsPDUData.iSent; i++)
+ {
+ iSmsArray.Delete(0);
+ }
+
+ iSmsArray.Reset();
+
+ iState = ESmsMessageSendIdle;
+
+ //
+ // Call the base function to perform the actual complete...
+ //
+ CSmsuActiveBase::Complete(aStatus);
+ } // CSmsMessageSend::Complete