diff -r 000000000000 -r 3553901f7fa8 smsprotocols/smsstack/smsprot/Src/smspread.cpp --- /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 + +// 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(static_cast(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* encodedPdus = new (ELeave) CArrayFixFlat(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