smsprotocols/smsstack/smsprot/Src/smspsend.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspsend.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +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