--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspread.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1273 @@
+// 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:
+//
+/**
+ @file
+*/
+
+#include "smspread.h"
+#include "smspmain.h"
+
+#include "smspproc.h"
+#include "smspfacadestor.h"
+#include "smsuset.h"
+#include "smsulog.h"
+
+#include "gsmubuf.h"
+#include "Gsmumsg.h"
+#include "smspcdb.h"
+#include "SmsuTimer.h"
+#include "exterror.h"
+
+#include "es_ini.h"
+#include <logwraplimits.h>
+
+// Delay between sending NAK to TSY & posting Receive() SMS on ETel again
+const TInt KWaitReadPduTime = 1000; // 1 millisecond
+
+
+/**
+ * Creates new CSmsPDURead instance
+ *
+ * @param aSmsComm is used to complete read pdu reguest
+ * @param aSmsMessaging used to set receive mode and start receive message
+ */
+CSmsPDURead* CSmsPDURead::NewL(MSmsComm& aSmsComm,
+ const TSmsSettings& aSmsSettings,
+ RMobileSmsMessaging& aSmsMessaging,
+ CFacadeSmsReassemblyStore& aReassemblyStore,
+ CSmsSegmentationStore& aSegmentationStore,
+ const RMobileSmsMessaging::TMobileSmsCapsV1& aMobileSmsCaps,
+ TInt aPriority,
+ CSmspReceiveMode& aSmspReceiveMode,
+ CSmsMonitorDiskSpace& aSmsMonitorDiskSpace)
+ {
+ LOGSMSPROT1("CSmsPDURead::NewL()");
+
+ CSmsPDURead* smsPduRead = new (ELeave) CSmsPDURead(aSmsComm,
+ aSmsSettings,
+ aSmsMessaging,
+ aReassemblyStore,
+ aSegmentationStore,
+ aMobileSmsCaps,
+ aPriority,
+ aSmspReceiveMode,
+ aSmsMonitorDiskSpace);
+
+ CleanupStack::PushL(smsPduRead);
+ smsPduRead->ConstructL();
+ CleanupStack::Pop(smsPduRead);
+
+ return smsPduRead;
+ } // CSmsPDURead::NewL
+
+
+void CSmsPDURead::ConstructL()
+ {
+ LOGSMSPROT1("CSmsPDURead::ConstructL()");
+
+ ConstructTimeoutL();
+ User::LeaveIfError(iOOMTimer.CreateLocal());
+
+ iLogger = CSmsPDUReadLogger::NewL(iReassemblyStore.FileSession(), Priority());
+ ReadConfigurableSmsSettingsL();
+ } // CSmsPDURead::ConstructL
+
+
+/**
+ * Constructor
+ * Adds CSmsPDURead object to the Active Scheduler
+ *
+ * @param aSmsComm is used to complete read pdu reguest
+ * @param aSmsMessaging used to set receive mode and start receive message
+ * @param aReassemblyStore used to set CSmsPDUProcess
+ * @param aSegmentationStore used to set CSmsPDUProcess
+ * @param aMobileSmsCaps used to set iMobileSmsCaps
+ * @param aPriority used to set CSmsPDUProcess
+ * @param aSmspReceiveMode used to set iReceiveMode
+ * @param aSmsMonitorDiskSpace used to set iSmsMonitorDiskSpace
+ */
+CSmsPDURead::CSmsPDURead(MSmsComm& aSmsComm,
+ const TSmsSettings& aSmsSettings,
+ RMobileSmsMessaging& aSmsMessaging,
+ CFacadeSmsReassemblyStore& aReassemblyStore,
+ CSmsSegmentationStore& aSegmentationStore,
+ const RMobileSmsMessaging::TMobileSmsCapsV1& aMobileSmsCaps,
+ TInt aPriority,
+ CSmspReceiveMode& aSmspReceiveMode,
+ CSmsMonitorDiskSpace& aSmsMonitorDiskSpace)
+ : CSmsuActiveBase(aPriority),
+ iState(ESmsPDUReadIdle),
+ iSmsMessaging(aSmsMessaging),
+ iMsgReceiveAttributesPckg(iMsgReceiveAttributes),
+ iSmsComm(aSmsComm),
+ iSmsSettings(aSmsSettings),
+ iReassemblyStore(aReassemblyStore),
+ iSegmentationStore(aSegmentationStore),
+ iMobileSmsCaps(aMobileSmsCaps),
+ iReceiveMode(aSmspReceiveMode),
+ iSmsMonitorDiskSpace(aSmsMonitorDiskSpace)
+ {
+ } // CSmsPDURead::CSmsPDURead
+
+
+/**
+ * Called by CSmsProtocol to start CSmsStoreRead active object
+ * Issues a Receive to the TSY
+ */
+void CSmsPDURead::Start()
+ {
+ LOGSMSPROT3("CSmsPDURead::Start(): iStatus=%d, iState=%d", iStatus.Int(), iState );
+
+ if (IsSupported() && IsActive() == EFalse && iReassemblyStore.IsFull() == EFalse)
+ {
+ iState = ESmsPDUReadSetReceiveMode;
+
+ iReceiveMode.Start(iStatus);
+ SetActive();
+ }
+ } // CSmsPDURead::Start
+
+
+void CSmsPDURead::ProcessPDUL()
+ {
+ LOGSMSPROT1("CSmsPDURead::ProcessPDUL()");
+
+ //
+ // Initilse the Slot location data...
+ //
+ iSlot.iIndex = iMsgReceiveAttributes.iStoreIndex;
+ iSlot.iStore = iMsgReceiveAttributes.iStore;
+ iSlot.iMsgData = iMsgData;
+ iSlot.iMsgStatus = RMobileSmsStore::EStoredMessageUnread;
+ iSlot.iServiceCentre = iMsgReceiveAttributes.iGsmServiceCentre;
+
+ //
+ // Initialise the PDU processor class...
+ //
+ delete iPduProcessor;
+ iPduProcessor = NULL;
+
+ iPduProcessor = CSmsPDUProcessor::NewL(iSmsComm, iSmsSettings,
+ iReassemblyStore, iSegmentationStore,
+ iSmsMonitorDiskSpace);
+
+ iPduProcessor->SetApplyAutoDeletionToClass2(iConfigAutomaticDeletionForClass2);
+ iPduProcessor->SetDiscardType0Class0(iConfigDiscardingType0Class0);
+ iPduProcessor->SetDiscardType0Class2(iConfigDiscardingType0Class2);
+
+ TRAPD(decodeError, iPduProcessor->DecodeAndProcessPDUL(iSlot, EFalse));
+ iStatus = decodeError;
+ LOGSMSPROT2("CSmsPDURead::ProcessPDUL(): DecodeAndProcessPDUL() returned %d", iStatus.Int());
+
+ //
+ // If the PDU cannot be decoded, and this was not due to memory or disk
+ // space problems, then get rid of it...
+ //
+ if (iStatus != KErrNone && iStatus != KErrNoMemory && iStatus != KErrDiskFull)
+ {
+ iPduProcessor->DeletePDUL();
+ }
+
+ //
+ // Send ACK or NACK delivery report (depends on iState and iError)...
+ //
+ SendDeliverReport();
+ } // CSmsPDURead::ProcessPDUL
+
+
+/**
+ * Called by Active Scheduler to run this object
+ * State ESmsPDUSetReceiveMode:
+ * Calls private method Receive() to change state to ESmsPDUReadWaitingForPDU
+ * and start receive message
+ * State ESmsPDUReadWaitingForPDU:
+ * Calls method Complete to change state to ESmsPDUReadIdle and complete message receive
+ *
+ * @leave Leaves if there was an error
+ * @leave Panic if complete is called while state is ESmsStoreReadIdle
+ */
+void CSmsPDURead::DoRunL()
+ {
+ LOGSMSPROT3("CSmsPDURead::DoRunL [iStatus=%d, iState=%d]", iStatus.Int(), iState);
+
+ //
+ // Handle state changes only for successful operations. Any errors will be
+ // handled when Complete() is called following this DoRunL() call.
+ // Complete() is not called if the object becomes active.
+ //
+ switch (iState)
+ {
+ case ESmsPDUReadSetReceiveMode:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ ResumeSmsReception();
+ }
+ }
+ break;
+
+ case ESmsPDUReadResumeReception:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ Receive();
+ }
+ }
+ break;
+
+ case ESmsPDUReadWaitingForPDU:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ LOGSMSIFPDU(_L8("ETEL RX PDU: "), iMsgData, EFalse);
+ LOGSMSIFTIMESTAMP();
+ ProcessPDUL();
+ }
+ }
+ break;
+
+ case ESmsPDUReadAcceptValidPduSendPositiveAck:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ AddLogEvent();
+ }
+ }
+ break;
+
+ case ESmsPDUReadLogging:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ iPduProcessor->UpdateLogServerIdL();
+ }
+
+ if ((iStatus.Int() == KErrNone) ||
+ (iStatus.Int() == -KErrNotSupported))
+ {
+ iPduProcessor->ProcessMessageIfCompleteL();
+ }
+ }
+ break;
+
+ case ESmsPDUReadSystemOutOfMemorySendNegativeAck:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ LOGSMSPROT1("CSmsPDURead::DoRunL in ESmsPDUReadSystemOutOfMemorySendNack2");
+ LOGSMSPROT1("CSmsPDURead::DoRunL activate post OOM timer");
+ iState = ESmsPDUWaitTimerAfterOOM;
+ iOOMTimer.After(iStatus,KWaitReadPduTime);
+ SetActive();
+ }
+ }
+ break;
+
+ case ESmsPDUWaitTimerAfterOOM:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ Receive();
+ }
+ }
+ break;
+
+ case ESmsPDUReadInvalidPDUSendNegativeAck:
+ case ESmsPDUReadAbsorbInvalidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbValidPduSendPositiveAck:
+ {
+ // NOP
+ }
+ break;
+
+ default:
+ {
+ SmspPanic(KSmspPanicUnexpectedState);
+ }
+ break;
+ }
+
+ //
+ // DoRunL() will now return to CSmsuActiveBase which if the object
+ // is not active, will call Complete().
+ //
+ } // CSmsPDURead::DoRunL
+
+
+/**
+ * public method for starting receive message
+ */
+void CSmsPDURead::ResumeSmsReception()
+ {
+ LOGSMSPROT3("CSmsPDURead::ResumeSmsReception [iStatus=%d, iState=%d]", iStatus.Int(), iState );
+
+ if (!IsActive())
+ {
+ iDelayedResumeSmsReceptionRequired = EFalse;
+ iSmsReceptionSupended = EFalse;
+ iState = ESmsPDUReadResumeReception;
+ iSmsMessaging.ResumeSmsReception( iStatus );
+ SetActive();
+ }
+ else if (iSmsReceptionSupended)
+ {
+ //
+ // We will need to save this for later...
+ //
+ iDelayedResumeSmsReceptionRequired = ETrue;
+ }
+ } // CSmsPDURead::ResumeSmsReception
+
+
+/**
+ * private method for starting receive message
+ */
+void CSmsPDURead::Receive()
+ {
+ LOGSMSPROT3("CSmsPDURead::Receive [iStatus=%d, iState=%d]", iStatus.Int(), iState );
+
+ //
+ // Check if we need to resume reception first. This may be required if a
+ // previous attempt to resume could not be actioned.
+ //
+ if (iDelayedResumeSmsReceptionRequired)
+ {
+ ResumeSmsReception();
+ }
+ else
+ {
+ //
+ // Clears message data buffer before passing reference to the phone side
+ //
+ RMobileSmsMessaging::TMobileSmsReceiveAttributesV1 empty;
+
+ iMsgData.Zero();
+ iMsgReceiveAttributes = empty;
+
+ //
+ // Receive a message...
+ //
+ iState = ESmsPDUReadWaitingForPDU;
+
+ iSmsMessaging.ReceiveMessage( iStatus, iMsgData, iMsgReceiveAttributesPckg );
+ SetActive();
+ }
+ } // CSmsPDURead::Receive
+
+
+/**
+ * Cancels CSmsPDURead object
+ * Cancels reveive message
+ * Completes CSmsPDURead object
+ */
+void CSmsPDURead::DoCancel()
+ {
+ LOGSMSPROT3("CSmsPDURead::DoCancel [iStatus=%d iState=%d]", iStatus.Int(), iState );
+
+ TimedSetActiveCancel();
+
+ switch (iState)
+ {
+ case ESmsPDUReadResumeReception:
+ {
+ iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingResumeSmsReception);
+ }
+ break;
+
+ case ESmsPDUReadSetReceiveMode:
+ {
+ iReceiveMode.Cancel();
+ }
+ break;
+
+ case ESmsPDUReadWaitingForPDU:
+ {
+ iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingReceiveMessage);
+ }
+ break;
+
+ case ESmsPDUReadLogging:
+ {
+ iLogger->Cancel();
+ }
+ break;
+
+ case ESmsPDUReadAcceptValidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbValidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbInvalidPduSendPositiveAck:
+ {
+ iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingAckSmsStored);
+ }
+ break;
+
+ case ESmsPDUReadInvalidPDUSendNegativeAck:
+ case ESmsPDUReadSystemOutOfMemorySendNegativeAck:
+ {
+ iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingNackSmsStored);
+ }
+ break;
+
+ case ESmsPDUWaitTimerAfterOOM:
+ {
+ iOOMTimer.Cancel();
+ }
+ break;
+
+ case ESmsPDUWaitingForDiskMonitor:
+ {
+ // NOP
+ }
+ break;
+
+ default:
+ {
+ SmspPanic(KSmspPanicUnexpectedState);
+ }
+ break;
+ };
+
+ //
+ // 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);
+ }
+ } // CSmsPDURead::DoCancel
+
+
+void CSmsPDURead::AddLogEvent()
+ {
+ LOGSMSPROT1("CSmsPDURead::AddLogEvent()");
+
+ iState = ESmsPDUReadLogging;
+
+ if (iPduProcessor->OriginalSmsMessage() == NULL)
+ {
+ iLogger->ChangeOrAddLogEvent(*iPduProcessor->SmsMessage(),
+ *iPduProcessor->SmsPDUData(), NULL, iStatus);
+ }
+ else
+ {
+ iPduProcessor->OriginalSmsMessage()->SetLogServerId(iPduProcessor->SmsMessage()->LogServerId());
+ //If the original SMS TX log entry is to be updated because a
+ // Status report has come in, pass as arguments both the orginal
+ // TX SMS (*smsmessage) and the Status Report (contained in iSmsMessage).
+ // This allows the discharge time in the Status Report to be logged.
+
+ CSmsMessage* pSmsMsg = iPduProcessor->SmsMessage();
+ CSmsStatusReport& statusReport = const_cast<CSmsStatusReport&>(static_cast<const CSmsStatusReport&>(pSmsMsg->SmsPDU()));
+ TTime dischargeTime;
+ TInt numQuarterHours = 0;
+ statusReport.DischargeTime(dischargeTime, numQuarterHours);
+ iLogger->ChangeOrAddLogEvent(*(iPduProcessor->OriginalSmsMessage()), *iPduProcessor->SmsPDUData(), &dischargeTime, iStatus);
+ }
+
+ SetActive();
+ } // CSmsPDURead::AddLogEvent
+
+
+void CSmsPDURead::DoEncodeDeliverReportL()
+ {
+ LOGSMSPROT2("CSmsPDUReadProcess::DoEncodeDeliverReport [iStatus=%d]", iStatus.Int());
+
+ iDeliverReport.SetPdu(KNullDesC8);
+
+ const TPtrC des(iPduProcessor->DeliverReportBuffer());
+ CSmsBuffer* buffer = CSmsBuffer::NewL();
+ CSmsMessage* smsMessage = CSmsMessage::NewL(iReassemblyStore.FileSession(), CSmsPDU::ESmsDeliverReport, buffer);
+ CleanupStack::PushL(smsMessage);
+
+ CSmsDeliverReport& deliverReport = ( CSmsDeliverReport& ) smsMessage->SmsPDU();
+
+ switch(iState)
+ {
+ case ESmsPDUReadInvalidPDUSendNegativeAck:
+ case ESmsPDUReadSystemOutOfMemorySendNegativeAck:
+ {
+ LOGSMSPROT4("CSmsPDURead::DoEncodeDeliverReport SendNegativeAck [iStatus=%d, iState=%d, iRpErrorCodesSupported= %d]",
+ iStatus.Int(), iState, iRpErrorCodesSupported);
+
+ deliverReport.SetIsRPError(ETrue);
+ const TInt failureCause = ErrorToTPError(iStatus.Int());
+ deliverReport.SetFailureCause((TSmsFailureCause::TSmsFailureCauseError) failureCause);
+ break;
+ }
+ case ESmsPDUReadAcceptValidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbInvalidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbValidPduSendPositiveAck:
+ {
+ LOGSMSPROT4("CSmsPDURead::DoEncodeDeliverReport SendPositiveAck [iStatus=%d, iState=%d, iRpErrorCodesSupported= %d]",
+ iStatus.Int(), iState, iRpErrorCodesSupported);
+ deliverReport.SetIsRPError(EFalse);
+ break;
+ }
+ default:
+ {
+ LOGSMSPROT4("CSmsPDURead::DoEncodeDeliverReport [iStatus=%d, iState=%d, iRpErrorCodesSupported= %d]",
+ iStatus.Int(), iState, iRpErrorCodesSupported);
+ SmspPanic( KSmspPanicUnexpectedStateEncountered );
+ break;
+ }
+ }
+
+ const TBool textPresent = (des.Length() > 0);
+
+ deliverReport.SetUserDataPresent(textPresent);
+ deliverReport.SetDataCodingSchemePresent(textPresent);
+ deliverReport.SetProtocolIdentifierPresent(textPresent);
+
+ if (textPresent)
+ buffer->InsertL( 0, des );
+
+ CArrayFixFlat<TGsmSms>* encodedPdus = new (ELeave) CArrayFixFlat<TGsmSms>(1);
+ CleanupStack::PushL(encodedPdus);
+
+ if(!smsMessage->EncodeIntoSinglePDUL(*encodedPdus))
+ smsMessage->EncodeMessagePDUsL(*encodedPdus);
+
+ if (encodedPdus->Count() > 0)
+ iDeliverReport = (*encodedPdus)[0];
+
+ CleanupStack::PopAndDestroy(2); // smsmessage, encodedPdus
+ } // CSmsPDURead::DoEncodeDeliverReportL
+
+
+/**
+ * The received SMS deliver PDU will be acknowledged or not acknowledged here.
+ *
+ * Because all correction and resending of corrupt PDUs happens within the phone stack we
+ * are assured that the PDU we have is a faithful copy of the one at the SC.
+ * The 'Out of Memory' errors KErrNoMemory & KErrDiskFull are always negatively acknowledged,
+ * All other errors are by default positively acknowledged but quietly discarded
+ * without forwarding to the client. This is because it has been observed that some network
+ * operators do not recognise the possible error codes as permanent and repeatly send the errored
+ * PDU back to the mobile. However, the stack can be configured to support each of the error
+ * codes specified 04.11 5.30. Table 8.4 (Part 2) by configuring the sms esk file - this
+ * procedure is described in the comments relating to method ReadConfigurableSmsSettingsL().
+ *
+ * @note Basic interface for sending sms deliver report to the SC.
+ */
+void CSmsPDURead::SendDeliverReport()
+ {
+ // Method behaviour based on DEF047323
+ LOGSMSPROT2("CSmsPDUReadProcess::SendDeliverReport(): iStatus=%d ",iStatus.Int());
+
+ MakeStateTransitionBasedOnErrorCode();
+
+ if ((iMsgReceiveAttributes.iStatus == RMobileSmsMessaging::EMtMessageUnstoredClientAck) ||
+ (iMsgReceiveAttributes.iStatus == RMobileSmsMessaging::EMtMessageUnknownStatus))
+ {
+ iDeliverReport = TGsmSms();
+
+ TRAPD(err, DoEncodeDeliverReportL());
+ if(err != KErrNone)
+ {
+ LOGSMSPROT2("CSmsPDURead::DoEncodeDeliverReport [err=%d]", err);
+ }
+ }
+ else
+ {
+ iDeliverReport.SetPdu(iMsgData); //create quasi deliver report
+ }
+
+ switch(iState)
+ {
+ case ESmsPDUReadInvalidPDUSendNegativeAck:
+ case ESmsPDUReadSystemOutOfMemorySendNegativeAck:
+ {
+ TInt failureCause = 0;
+ failureCause = ErrorToRPError(iStatus.Int());
+ iSmsMessaging.NackSmsStored(iStatus, iDeliverReport.Pdu(), failureCause);
+ }
+ break;
+
+ case ESmsPDUReadAcceptValidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbValidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbInvalidPduSendPositiveAck:
+ {
+ const TBool full = iReassemblyStore.IsFull();
+ iSmsMessaging.AckSmsStored(iStatus, iDeliverReport.Pdu(), full);
+ iSmsReceptionSupended = (iSmsReceptionSupended || full);
+ }
+ break;
+
+ default:
+ {
+ LOGSMSPROT4("CSmsPDURead::DoEncodeDeliverReport [iStatus=%d, iState=%d, iRpErrorCodesSupported= %d]",
+ iStatus.Int(), iState, iRpErrorCodesSupported);
+ SmspPanic( KSmspPanicUnexpectedStateEncountered );
+ }
+ break;
+ }
+
+ TimedSetActive(iSmsSettings.Timeout());
+ } // CSmsPDURead::SendDeliverReport
+
+
+/**
+ * Sets state to ESmsPDUReadIdle
+ * Completes message receive request to the CSmsProtocol
+ */
+void CSmsPDURead::Complete(TInt aError)
+ {
+ LOGSMSPROT3("CSmsPDURead::Complete [aError=%d, iState=%d]", aError, iState );
+
+ switch (iState)
+ {
+ case ESmsPDUReadAcceptValidPduSendPositiveAck:
+ {
+ if (aError != KErrCancel && aError != KErrTimedOut)
+ {
+ AddLogEvent();
+ break;
+ // pass through otherwise
+ }
+ }
+ case ESmsPDUReadResumeReception:
+ case ESmsPDUReadWaitingForPDU:
+ case ESmsPDUReadLogging:
+ case ESmsPDUReadSystemOutOfMemorySendNegativeAck:
+ case ESmsPDUReadAbsorbValidPduSendPositiveAck:
+ case ESmsPDUReadAbsorbInvalidPduSendPositiveAck:
+ case ESmsPDUReadInvalidPDUSendNegativeAck:
+ case ESmsPDUWaitTimerAfterOOM:
+ {
+ delete iPduProcessor;
+ iPduProcessor = NULL;
+
+ if (aError == KErrServerTerminated)
+ {
+ SmspPanic(ESmspCantError); // could add a new panic code for this?
+ }
+
+ if (aError == KErrTimedOut && IsActive())
+ {
+ //
+ // This request is being called during a timeout Cancel(). We'd like
+ // to kick of a new request, but we cannot as we are still active.
+ // So, request a completion after the Cancel() finishes...
+ //
+ CompleteMyselfAfterTimeout(KErrNone);
+ break;
+ }
+
+ //
+ // Start receiving more messages if possible...
+ //
+ if (aError != KErrCancel && iReassemblyStore.IsFull() == EFalse &&
+ (iState != ESmsPDUReadWaitingForPDU || iStatus != KErrNotSupported))
+ {
+ Receive();
+ }
+ else
+ {
+ iState = ESmsPDUReadIdle;
+ }
+ }
+ break;
+
+ case ESmsPDUReadSetReceiveMode:
+ {
+ iState = ESmsPDUReadIdle;
+ }
+ break;
+
+ case ESmsPDUWaitingForDiskMonitor:
+ {
+ // NOP
+ }
+ break;
+
+ default:
+ {
+ SmspPanic(KSmspPanicUnexpectedState);
+ }
+ break;
+ };
+ } // CSmsPDURead::Complete
+
+
+/**
+ * Destructor
+ */
+CSmsPDURead::~CSmsPDURead()
+ {
+ Cancel();
+ delete iPduProcessor;
+ iOOMTimer.Close();
+ delete iLogger;
+ } // CSmsPDURead::~CSmsPDURead
+
+
+/**
+ * Sets a specified error code to either supported ( i.e. reported
+ * as the Rp Error condition in a delivery report if the error condition
+ * is detected ) or not supported ( i.e not reported as an Rp Error Condition
+ * in a Deliver Report when the condition is detected).
+ *
+ * @param aIndex identifies the bit that represents the error condition in the bit mask
+ * @param aValue specifies whether the error condition is supported.
+ */
+void CSmsPDURead::SetErrorCodeStatus(enum TRpErrorCodeIndex aIndex, TBool aValue)
+ {
+ LOGSMSPROT1("CSmsPDURead::SetErrorCodeStatus()");
+
+ if (aValue)
+ {
+ iRpErrorCodesSupported |= (((TUint8) 0x01) << aIndex);
+ }
+ else
+ {
+ iRpErrorCodesSupported &= ~(((TUint8) 0x01) << aIndex);
+ }
+ } // CSmsPDURead::SetErrorCodeStatus
+
+
+/**
+ *
+ * Retrieves the Error Code Status (i.e. whether the error is to be
+ * reported in a delivery report when the error condition is detected).
+ *
+ * @param aIndex identifies the bit that represents the error condition in the bit mask.
+ * @return whether the error condition is to be reported in a delivery report, if the
+ * condition is detected.
+ */
+TBool CSmsPDURead::GetErrorCodeStatus(enum TRpErrorCodeIndex aIndex)
+ {
+ LOGSMSPROT1("CSmsPDURead::GetErrorCodeStatus()");
+
+ TBool rc;
+ iRpErrorCodesSupported & (((TUint8) 0x01) << aIndex) ? rc = ETrue : rc = EFalse;
+ return rc;
+ } // CSmsPDURead::GetErrorCodeStatus
+
+
+/**
+ *
+ * Maps an RpErrorCode to an index that represents the error in a bit mask.
+ *
+ * @param aRpErrorCode represents the error code to be mapped.
+ * @param aIndex represents the index to the error status in a bit mask.
+ * @return True if the error can be mapped to a bit mask index, otherwise False
+ */
+TBool CSmsPDURead::MapRpErrorToIndex(TInt aRpErrorCode, TRpErrorCodeIndex& aIndex)
+ {
+ LOGSMSPROT1("CSmsPDURead::MapRpErrorToIndex()");
+
+ switch( aRpErrorCode )
+ {
+ case KErrGsmSMSInvalidShortMessageTransferReferenceValue:
+ {
+ aIndex = EInvalidShortMsgTransferReferenceValue;
+ }
+ break;
+
+ case KErrGsmSMSUnspecifiedInvalidMessage:
+ {
+ aIndex = ESemanticallyIncorrectMessage;
+ }
+ break;
+
+ case KErrGsmSMSInvalidMandatoryInformation:
+ {
+ aIndex = EInvalidMandatoryInformaton;
+ }
+ break;
+
+ case KErrGsmSMSNonExistentMessageType:
+ {
+ aIndex = EMessageTypeNonExistent;
+ }
+ break;
+
+ case KErrGsmSMSIncompatibleMessageWithSmsProtocolState:
+ {
+ aIndex = EMessageNotCompatibleWithShortMessageProtocolState;
+ }
+ break;
+
+ case KErrGsmSMSInformationElementNotImplemented:
+ {
+ aIndex = EInformationElementNonExistentOrNotImplemented;
+ }
+ break;
+
+ case KErrGsmSMSUnspecifiedProtocolError:
+ {
+ aIndex = EProtocolErrorUnspecified;
+ }
+ break;
+
+ default:
+ {
+ aIndex = EProtocolErrorUnspecified;
+ }
+ break;
+ }
+
+ //
+ // Currently always returns true, as the default error code
+ // "Protocol Error Unspecified" can be used to map any
+ // error condition that is not explicitly mapped.
+ //
+ return ETrue;
+ } // CSmsPDURead::MapRpErrorToIndex
+
+
+/**
+ * Synopsis: Reads the smswap.sms.ESK file. This can be used
+ * to specify whether the SMS Stack should negatively
+ * acknowledge any of the Rp Error conditions specified
+ * in 04.11 v5.3.0 Table 8.4 (part 2).
+ *
+ * When the behaviour is not specified in the smswap.sms.ESK,
+ * the default behaviour is for the stack to positively
+ * acknowledge any PDU even if decoding it has resulted in one
+ * of the specified error conditions. In addition, the 'Out
+ * of Memory' Condition can not be specified as unsupported -
+ * it always results in the Rp Error 'MemoryCapacityExceeded'
+ * being included a Deliver Report. It cannot be configured as
+ * disabled.
+ *
+ * Example: Segment of a smswap.sms.ESK file which specifies all
+ * the 04.11 error conditions are to be supported.
+ *
+ * [CustomerSmsRpErrorCodes]
+ * InvalidShortMsgTransferRefValue= 1
+ * SemanticallyIncorrectMsg= 1
+ * InvalidMandatoryInformaton= 1
+ * MsgTypeNonExistent= 1
+ * MsgNonCompatibleWithPrtclState= 1
+ * InfoElemNotExist_NotImplemented= 1
+ * ProtocolErrorUnspecified= 1
+ *
+ * Errors will not be reported if the corresponding identifier is set to 0
+ * or is omitted from the file.
+ *
+ * Certain pieces of Release 6 functionality cause breaks to existing functionality.
+ * These are disabled by default, but can be configured as follows.
+ *
+ * (1) Class 2 messages on the SIM will be deleted when the DCS
+ * byte specifies that "the message is specified for automatic deletion"
+ * See 23.038 Section 4, "SMS Data Coding Scheme" and when the following
+ * text segment is included in the smswap.sms.ESK file:
+ *
+ * [Release6Configurability]
+ * AutomaticDeletionOfClass2= 1
+ *
+ * (2) Class 2 messages on the SIM will be deleted and will not be
+ * forwarded to the client when the PID byte specifies that the
+ * message is type 0 as per 23.40 v6.5.0 9.2.3.9 and when the
+ * following text segment is included in the smswap.sms.ESK file:
+ *
+ * [Release6Configurability]
+ * DiscardType0_Class2Message= 1
+ *
+ *
+ * (3) Class 0 messages will not be forwarded to the SMS Stack client
+ * when the PID byte specifies that the message is type 0 as per
+ * 23.40 v6.5.0 9.2.3.9 and when the following text segment is included
+ * in the smswap.sms.esk file:
+ * [Release6Configurability]
+ * DiscardType0_Class0Message= 1
+ *
+ * Note: The Release 6 Configuration Option tag [Release6Configurability]
+ * must only be specified once in the configuration file, even if
+ * more than one Release 6 configuration option is specified. For example
+ * [Release6Configurability]
+ * AutomaticDeletionOfClass2= 1
+ * DiscardType0_Class2Message= 1
+ * DiscardType0_Class0Message= 1
+ */
+void CSmsPDURead::ReadConfigurableSmsSettingsL()
+ {
+ CESockIniData* ini = NULL;
+ TRAPD(ret, ini=CESockIniData::NewL(_L("smswap.sms.esk")));
+ if(ret!=KErrNone)
+ {
+ LOGSMSPROT2("esk read failed, error code = [%d]", ret);
+ User::Leave(ret);
+ }
+
+ CleanupStack::PushL(ini);
+
+ iRpErrorCodesSupported = 0;
+
+ TBool status(EFalse);
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("InvalidShortMsgTransferRefValue"), status))
+ {
+ SetErrorCodeStatus(EInvalidShortMsgTransferReferenceValue, status);
+ }
+
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("SemanticallyIncorrectMsg"),status))
+ {
+ SetErrorCodeStatus(ESemanticallyIncorrectMessage, status);
+ }
+
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("InvalidMandatoryInformaton"),status))
+ {
+ SetErrorCodeStatus(EInvalidMandatoryInformaton, status);
+ }
+
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("MsgTypeNonExistent"),status))
+ {
+ SetErrorCodeStatus(EMessageTypeNonExistent, status);
+ }
+
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("MsgNonCompatibleWithPrtclState"),status))
+ {
+ SetErrorCodeStatus(EMessageNotCompatibleWithShortMessageProtocolState, status);
+ }
+
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("InfoElemNotExist_NotImplemented"),status))
+ {
+ SetErrorCodeStatus(EInformationElementNonExistentOrNotImplemented, status);
+ }
+
+ if (ini->FindVar(_L("CustomerSmsRpErrorCodes"),
+ _L("ProtocolErrorUnspecified"), status))
+ {
+ SetErrorCodeStatus(EProtocolErrorUnspecified, status);
+ }
+
+ if (ini->FindVar(_L("Release6Configurability"),
+ _L("AutomaticDeletionOfClass2"), status))
+ {
+ iConfigAutomaticDeletionForClass2 = status;
+ }
+
+ if (ini->FindVar(_L("Release6Configurability"),
+ _L("DiscardType0_Class2Message"), status))
+ {
+ iConfigDiscardingType0Class2 = status;
+ }
+
+ if (ini->FindVar(_L("Release6Configurability"),
+ _L("DiscardType0_Class0Message"), status))
+ {
+ iConfigDiscardingType0Class0 = status;
+ }
+
+ CleanupStack::PopAndDestroy(ini);
+ } // CSmsPDURead::ReadConfigurableSmsSettingsL
+
+/**
+ * Checks that receiving message is supported by Tsy.
+ */
+TBool CSmsPDURead::IsSupported() const
+ {
+ LOGSMSPROT1("CSmsPDURead::IsSupported()");
+
+ if (( iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsReceiveUnstoredClientAck ) ||
+ ( iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsReceiveUnstoredPhoneAck ) ||
+ ( iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsReceiveStored ) ||
+ ( iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsReceiveEither ))
+ {
+ return ETrue;
+ }
+
+ return EFalse;
+ } // CSmsPDURead::IsSupported
+
+
+/**
+ * Make a state transition from WaitingForPDU based
+ * on:
+ * (i) any error condition detected
+ * (ii) whether the error condition needs to be
+ * positively or negatively acknowledged in the
+ * Delivery Report.
+ *
+ * Note that this function also handles the absorption of
+ * valid PDUs when needed.
+ */
+void CSmsPDURead::MakeStateTransitionBasedOnErrorCode()
+ {
+ LOGSMSPROT1("CSmsPDURead::MakeStateTransitionBasedOnErrorCode()");
+
+ if (iState != ESmsPDUReadWaitingForPDU)
+ SmspPanic( KSmspPanicUnexpectedStateEncountered );
+
+ if (iStatus == KErrNoMemory || iStatus == KErrDiskFull)
+ {
+ iState = ESmsPDUReadSystemOutOfMemorySendNegativeAck;
+ }
+ else if (iStatus != KErrNone)
+ {
+ TRpErrorCodeIndex index;
+ // check:
+ // 1) Is this is a configurable error code ?
+ // 2) If it is, should an error code be sent in a NegativeAck ?
+ if (MapRpErrorToIndex(iStatus.Int(), index) &&
+ GetErrorCodeStatus(index))
+ {
+ iState = ESmsPDUReadInvalidPDUSendNegativeAck;
+ }
+ else
+ {
+ iState = ESmsPDUReadAbsorbInvalidPduSendPositiveAck;
+ }
+ }
+ else
+ {
+ // PDU is valid
+ if (iPduProcessor->IsPIDType0() &&
+ ( (iPduProcessor->IsClass0Message() && iPduProcessor->IsDiscardType0Class0() ) ||
+ (iPduProcessor->IsClass2Message() && iPduProcessor->IsDiscardType0Class2() ) ||
+ (iPduProcessor->IsClass0Message() == EFalse && iPduProcessor->IsClass2Message() == EFalse)) )
+ {
+ LOGSMSPROT1("CSmsPDURead::MakeStateTransitionBasedOnErrorCode Absorb Valid PDU");
+ iState = ESmsPDUReadAbsorbValidPduSendPositiveAck;
+ }
+ else
+ {
+ iState = ESmsPDUReadAcceptValidPduSendPositiveAck;
+ }
+ }
+
+ } // CSmsPDURead::MakeStateTransitionBasedOnErrorCode
+
+
+/**
+ * Two-phase factory for CSmsPDUReadLogger
+ *
+ * @param aFs File Server session
+ * @param aPriority ActiveScheduler priority of this active object
+ * @return Newly constructed CSmsPDUReadLogger
+ */
+CSmsPDUReadLogger* CSmsPDUReadLogger::NewL(RFs& aFs, TInt aPriority)
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::NewL()");
+
+ CSmsPDUReadLogger* self = new (ELeave) CSmsPDUReadLogger(aPriority);
+ CleanupStack::PushL(self);
+ self->ConstructL(aFs);
+ CleanupStack::Pop(self);
+
+ return self;
+ } // CSmsPDUReadLogger::NewL
+
+
+/**
+ * CSmsPDUReadLogger constructor
+ *
+ * @param aPriority ActiveScheduler priority of this active object
+ */
+CSmsPDUReadLogger::CSmsPDUReadLogger(TInt aPriority)
+ : CSmsuActiveBase(aPriority)
+ {
+ } // CSmsPDUReadLogger::CSmsPDUReadLogger
+
+
+/**
+ * 2nd phase of construction for CSmsPDUReadLogger.
+ *
+ * @param aFs File Server session
+ * @leave Leaves (usually with KErrNoMemory) if unable to construct the CSmsEventLogger
+ */
+void CSmsPDUReadLogger::ConstructL(RFs& aFs)
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::ConstructL()");
+
+ iLogger = CSmsEventLogger::NewL(aFs, Priority());
+ } // CSmsPDUReadLogger::ConstructL
+
+
+/**
+ * CSmsPDUReadLogger destructor
+ */
+CSmsPDUReadLogger::~CSmsPDUReadLogger()
+ {
+ Cancel();
+ delete iLogger;
+ } // CSmsPDUReadLogger::~CSmsPDUReadLogger
+
+/**
+ * Asynchonously changes or creates a new log event for aSmsMessage
+ *
+ * @pre aSmsMessage contains the correct LogServerId
+ * @param aSmsMessage The CSmsMessage to add or change on the system log
+ * @param aSmsPDUData Log data relating to aSmsMessage
+ * @param aTime Sms delivery time
+ * @leave Completes aStatus with KErrNone if there is no logging client available
+ */
+void CSmsPDUReadLogger::ChangeOrAddLogEvent(CSmsMessage& aSmsMessage, const TLogSmsPduData& aSmsPDUData, const TTime* aTime, TRequestStatus& aStatus)
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::ChangeOrAddLogEvent()");
+
+ __ASSERT_DEBUG(iState == ESmsPDUReadLoggerIdle, SmspPanic(KSmspPanicUnexpectedState));
+
+ Queue(aStatus);
+
+ if (iLogger->ClientAvailable())
+ {
+ iSmsMessage = &aSmsMessage;
+ iSmsPDUData = &aSmsPDUData;
+ if (aTime != NULL)
+ {
+ iTime = *aTime;
+ iTimePtr = &iTime;
+ }
+ else
+ {
+ iTimePtr = NULL;
+ }
+
+ if (aSmsMessage.LogServerId() == KLogNullId)
+ AddLogEvent();
+ else
+ GetLogEvent();
+ }
+ else
+ {
+ Complete(KErrNone);
+ }
+ }
+
+/**
+ * Adds iSmsMessage to the log
+ */
+void CSmsPDUReadLogger::AddLogEvent()
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::AddLogEvent()");
+
+ iState = ESmsPDUReadLoggerAdd;
+
+ iLogger->AddEvent(iStatus, *iSmsMessage, *iSmsPDUData);
+ SetActive();
+ } // CSmsPDUReadLogger::AddLogEvent
+
+
+/**
+ * Gets the log event with Id iSmsMessage->LogServerId()
+ */
+void CSmsPDUReadLogger::GetLogEvent()
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::GetLogEvent()");
+
+ __ASSERT_DEBUG(iSmsMessage->LogServerId() != KLogNullId, SmspPanic(KSmspPanicLogIdNull));
+
+ iState = ESmsPDUReadLoggerGet;
+
+ iLogger->GetEvent(iStatus, iSmsMessage->LogServerId());
+ SetActive();
+ } // CSmsPDUReadLogger::GetLogEvent
+
+
+/**
+ * Changes the log event with iSmsMessage and iSmsPDUData
+ */
+void CSmsPDUReadLogger::ChangeLogEvent()
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::ChangeLogEvent()");
+
+ iState = ESmsPDUReadLoggerChange;
+ iLogger->ChangeEvent(iStatus, *iSmsMessage, iTimePtr, *iSmsPDUData);
+ SetActive();
+ } // CSmsPDUReadLogger::ChangeLogEvent
+
+
+void CSmsPDUReadLogger::DoRunL()
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::DoRunL()");
+
+ switch (iState)
+ {
+ case ESmsPDUReadLoggerGet:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ ChangeLogEvent();
+ }
+ else
+ {
+ AddLogEvent();
+ }
+ }
+ break;
+
+ case ESmsPDUReadLoggerAdd:
+ {
+ if (iStatus.Int() == KErrNone)
+ {
+ iSmsMessage->SetLogServerId(iLogger->Event().Id());
+ }
+ }
+ break;
+
+ case ESmsPDUReadLoggerChange:
+ {
+ // NOP
+ }
+ break;
+
+ default:
+ {
+ SmspPanic(KSmspPanicUnexpectedState);
+ }
+ break;
+ }
+ // DoRunL() will now return to CSmsuActiveBase which if the object
+ // is not active, will call Complete().
+ }
+
+void CSmsPDUReadLogger::DoCancel()
+ {
+ // Ignore in code coverage - cancel method called from CSmsPDURead
+ // only if CSmsPDURead is itself cancelled during logging state.
+ // CSmsPDURead is only cancelled when SMS stack shuts down. These
+ // conditions are very difficult to create in a deterministic way.
+ BULLSEYE_OFF
+
+ LOGSMSPROT1("CSmsPDUReadLogger::DoCancel()");
+
+ iLogger->Cancel();
+
+ //
+ // 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);
+ }
+ BULLSEYE_RESTORE
+ }
+
+void CSmsPDUReadLogger::Complete(TInt aStatus)
+ {
+ LOGSMSPROT1("CSmsPDUReadLogger::Complete()");
+
+ // Call the base function to perform the actual complete...
+ CSmsuActiveBase::Complete(aStatus);
+
+ iState = ESmsPDUReadLoggerIdle;
+ } // CSmsPDUReadLogger::Complete