diff -r 000000000000 -r 3553901f7fa8 smsprotocols/smsstack/smsprot/Src/smspproc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/smsprotocols/smsstack/smsprot/Src/smspproc.cpp Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,675 @@ +// Copyright (c) 1999-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 "smspproc.h" +#include "smspmondsk.h" +#include "smspfacadestor.h" +#include "smsuset.h" +#include "smsulog.h" +#include "smspmain.h" + +#include +#include +#include "gsmubuf.h" +#include "Gsmumsg.h" +#include "smspcdb.h" +#include "smspread.h" + + +/** + * Creates new CSmsPDUProcess instance + * + * @return a new CSmsPDUProcess object. + */ +CSmsPDUProcessor* CSmsPDUProcessor::NewL(MSmsComm& aSmsComm, const TSmsSettings& aSmsSettings, + CFacadeSmsReassemblyStore& aReassemblyStore, + CSmsSegmentationStore& aSegmentationStore, + CSmsMonitorDiskSpace& aSmsMonitorDiskSpace) + { + LOGSMSPROT1("CSmsPDUProcessor::NewL()"); + + CSmsPDUProcessor* smsPDUProcessor = new (ELeave) CSmsPDUProcessor(aSmsComm, + aSmsSettings, + aReassemblyStore, + aSegmentationStore, + aSmsMonitorDiskSpace); + + CleanupStack::PushL(smsPDUProcessor); + smsPDUProcessor->ConstructL(); + CleanupStack::Pop(smsPDUProcessor); + + return smsPDUProcessor; + } // CSmsPDUProcessor::NewL + + +CSmsPDUProcessor::~CSmsPDUProcessor() + { + delete iSmsMessage; + delete iOriginalSmsMessage; + iStatusArray.Close(); + } // CSmsPDUProcessor::~CSmsPDUProcessor + + +CSmsPDUProcessor::CSmsPDUProcessor(MSmsComm& aSmsComm, + const TSmsSettings& aSmsSettings, + CFacadeSmsReassemblyStore& aReassemblyStore, + CSmsSegmentationStore& aSegmentationStore, + CSmsMonitorDiskSpace& aSmsMonitorDiskSpace) + :iSmsComm(aSmsComm), + iSmsSettings(aSmsSettings), + iReassemblyStore(aReassemblyStore), + iSegmentationStore(aSegmentationStore), + iSmsMonitorDiskSpace(aSmsMonitorDiskSpace) + { + // NOP + } // CSmsPDUProcessor::CSmsPDUProcess + + +/** + * Second phase constructor. + */ +void CSmsPDUProcessor::ConstructL() + { + LOGSMSPROT1("CSmsPDUProcessor::ConstructL()"); + } // CSmsPDUProcessor::ConstructL + + +void CSmsPDUProcessor::DecodeAndProcessPDUL(TGsmSmsSlot& aSlot, TBool aIsEnumeration) + { + LOGSMSPROT2("CSmsPDUProcessor::DecodeAndProcessPDUL(): aIsEnumeration=%d", + aIsEnumeration); + + // + // Store the slot... + // + iSlot = aSlot; + + // + // We need to know if this message is MT or MO before decoding... + // + if (iSlot.iMsgStatus == RMobileSmsStore::EStoredMessageUnread || + iSlot.iMsgStatus == RMobileSmsStore::EStoredMessageRead) + { + iIsMobileTerminated = ETrue; + } + + LOGSMSPROT2("CSmsStoreRead::DecodeAndProcessPDUL(): iIsMobileTerminated=%d", + iIsMobileTerminated); + + // + // Put the PDU and Service Center Address in the TGsmSms structure... + // + TGsmSmsTelNumber sca; + + sca.iTelNumber = iSlot.iServiceCentre.iTelNumber; + sca.iTypeOfAddress.SetFromETelMM(static_cast(iSlot.iServiceCentre.iTypeOfNumber), + static_cast(iSlot.iServiceCentre.iNumberPlan)); + iGsmSms.SetPdu(iSlot.iMsgData); + iGsmSms.SetSca(sca); + + // + // Allocate a CSmsBuffer for use during the decoding of the PDU and + // create the CSmsMessage object - this will actaully decode the PDU. Note + // that the CSmsBuffer ownership is transfered during NewL()!!! + // + CSmsBuffer* smsBuffer = CSmsBuffer::NewL(); + iSmsMessage = CSmsMessage::NewL(iReassemblyStore.FileSession(), iGsmSms, + smsBuffer, EFalse, iIsMobileTerminated); + + // + // Store the enumeration type and calculate other basic info... + // + iIsEnumeration = aIsEnumeration; + + AnalysePDUCharacteristics(); + + // + // If the store information is supplied, then check if the PDU will + // be deleted from the store. + // + // When enumerating, only messages which are on the SIM or in the + // Combined Store are forwarded to the client. If the message on the + // SIM is marked for automatic deletion or a type 0, then it may + // have its storage set to CSmsMessage::ESmsNoStorage in this routine. + // However the method CSmsProtocol::ExternalizeEnumeratedMessagesL() + // still needs to know that the message was originally on the SIM or + // the combined store. + // + if (iSlot.iStore.Length() > 0) + { + iSmsMessage->SetStatus(static_cast(iSlot.iMsgStatus)); + if (iSlot.iStore == KETelCombinedSmsStore) + { + if (iSmsSettings.DeletePDUsFromCombinedStores() == EFalse) + { + iSmsMessage->SetStorage(CSmsMessage::ESmsCombinedStorage); + } + + iSmsMessage->SetDecodedOnSIM(ETrue); + } + else if (iSlot.iStore == KETelIccSmsStore) + { + if (iSmsSettings.DeletePDUsFromSIM() == EFalse) + { + iSmsMessage->SetStorage(CSmsMessage::ESmsSIMStorage); + } + + iSmsMessage->SetDecodedOnSIM(ETrue); + } + else if (iSmsSettings.DeletePDUsFromPhoneStores() == EFalse) + { + iSmsMessage->SetStorage(CSmsMessage::ESmsPhoneStorage); + } + } + + // + // If the PDU will be deleted, then assume it has no storage... + // + if (iIsPDUToBeDeleted) + { + iSmsMessage->SetStorage(CSmsMessage::ESmsNoStorage); + } + + // + // Is this a MOSES message? + // + if (iSmsMessage->ToFromAddress().CompareF(KNETWORK) == 0) + { + LOGSMSPROT1("CSmsPDUProcessor::DecodeAndProcessPDUL(): MOSES OTE message!"); + if (iSmsComm.NetworkInfoAvailable()) + { + iSmsMessage->SetToFromAddressL(iSmsComm.NetworkInfo().iDisplayTag); + } + } + + // + // Call the processing function for this time of message. Enumerations of + // a PDU can be SUBMIT, DELIVER or STATUS-REPORT. Receiving of a PDU can + // be SUBMIT or STATUS-REPORT... + // + if ((iIsEnumeration && iSmsMessage->Type() == CSmsPDU::ESmsSubmit) || + iSmsMessage->Type() == CSmsPDU::ESmsDeliver) + { + if (iIsForwardMessageToClient) + { + // + // Record that this SMS should be forwarded to the client... + // + iSmsMessage->SetForwardToClient(ETrue); + + // + // Check that there is disk space to process this PDU. This may signal to + // the network to stop SMS reception until further notice, and it may go + // active to monitor the disk space. + // + /* + The below logic is quite complicated. This logic is written to support backward compatibility. + Previously SMS stack was sending -ve ack for class 0 messages before implementation of REQ6523. + Even after implementation of REQ6523, there will be provision so that the customer who does + not want this feature, then can go back to previous implementation. + With REQ6523, there is another requiremnt REQ7012 which states that class 0 WAP messages + will be handled like other non-class 0 messages. That means in out-of-disk condition it will + send -ve ack to network. WAP class 0 messages will be stored in non-class 0 re-assembly store. + + If SMS stack is configured for handling class 0 messages in out-of-disk condition, + Class 0 messages will be stored in reserved space (Pre-allocated file) internally. + But if this function is called at the time of enumeration and disk is full then -ve ack + will be sent to client for disk full. The behaviour is different for class 0 messages + at the time of enumeration & normal read from network. + */ + TInt ret=KErrNone; + iIsWapSms = iReassemblyStore.IsWapSMS(*iSmsMessage); + if (iIsClass0Message && iIsWapSms) + { + //Wap class 0 sms message will be stored in non-class 0 reassembly store. + TRAP(ret, iSmsMonitorDiskSpace.CheckDiskSpaceForPDUL(EFalse)); + } + else + { + TRAP(ret, iSmsMonitorDiskSpace.CheckDiskSpaceForPDUL(iIsClass0Message)); + } + + if ((iIsClass0Message && !iIsWapSms) && iReassemblyStore.IsSeparateClass0StoreSupported() && (!aIsEnumeration)) + { + if (ret == KErrDiskFull) + { + iReassemblyStore.SetDiskSpaceState(ESmsDiskSpaceFull); + ret = KErrNone; + } + else if (ret == KErrNone) + { + iReassemblyStore.SetDiskSpaceState(ESmsDiskSpaceAvailable); + } + } + + if (ret!=KErrNone) + { + User::Leave(ret); + } + + AddSlotToSmsMessageIfRequiredL(); + AddSegmentOfMessageToReassemblyStoreIfRequiredL(); + } + } + else if (iSmsMessage->Type() == CSmsPDU::ESmsStatusReport) + { + FindOriginalMessageAndProcessStatusReportL(); + + if (iIsForwardMessageToClient && iIsMessageGoingToBeStored) + { + // + // Record that this SMS should be forwarded to the client... + // + iSmsMessage->SetForwardToClient(ETrue); + + AddSlotToSmsMessageIfRequiredL(); + AddSegmentOfMessageToReassemblyStoreIfRequiredL(); + } + + // + // If the message to which this report refers is complete (and + // logically most will be as unless it refers to a SMS-SUBMIT + // message we no longer have), then update the received time and + // the + // + if (iIsComplete) + { + UpdateStatusReportL(); + } + } + else + { + User::Leave(KErrCorrupt); + } + + // + // Should we delete the PDU? + // + if ((iIsEnumeration && iSlot.iStore == KETelMeSmsStore) || + (iIsEnumeration == EFalse && iSmsMessage->Storage() != CSmsMessage::ESmsSIMStorage) || + iIsPDUToBeDeleted) + { + DeletePDUL(); + } + } // CSmsPDUProcessor::DecodeAndProcessPDUL + + +void CSmsPDUProcessor::AnalysePDUCharacteristics() + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics()"); + + CSmsPDU& pdu = iSmsMessage->SmsPDU(); + + // + // Check store the message class... + // + TSmsDataCodingScheme::TSmsClass msgClass; + + if (pdu.DataCodingSchemePresent() && pdu.Class(msgClass)) + { + if (msgClass == TSmsDataCodingScheme::ESmsClass0) + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics(): Class 0"); + iIsClass0Message = ETrue; + } + else if (msgClass == TSmsDataCodingScheme::ESmsClass1) + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics(): Class 1"); + iIsClass1Message = ETrue; + } + else if (msgClass == TSmsDataCodingScheme::ESmsClass2) + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics(): Class 2"); + iIsClass2Message = ETrue; + } + else if (msgClass == TSmsDataCodingScheme::ESmsClass3) + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics(): Class 3"); + iIsClass3Message = ETrue; + } + else + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics(): Class Unknown!"); + } + } + else + { + LOGSMSPROT1("CSmsPDUProcessor::AnalysePDUCharacteristics(): Class-less"); + } + + // + // Is this PDU PID Type 0? + // + if (pdu.ProtocolIdentifierPresent() && + pdu.PIDType() == TSmsProtocolIdentifier::ESmsPIDShortMessageType && + pdu.ShortMessageType() == TSmsProtocolIdentifier::ESmsShortMessageType0) + { + iIsPIDType0 = ETrue; + } + + LOGSMSPROT2("CSmsPDUProcessor::AnalysePDUCharacteristics(): iIsPIDType0=%d", + iIsPIDType0); + + // + // Should this message be forwarded to the client? + // + if (!(iIsPIDType0 && + ((iIsClass0Message && iOptionDiscardType0Class0) || + (iIsClass2Message && iOptionDiscardType0Class2) || + (iIsClass0Message == EFalse && iIsClass2Message == EFalse)))) + { + iIsForwardMessageToClient = ETrue; + } + + LOGSMSPROT2("CSmsPDUProcessor::AnalysePDUCharacteristics(): iIsForwardMessageToClient=%d", + iIsForwardMessageToClient); + + // + // Is it flaged for auto-delete? + // + if (pdu.DataCodingSchemePresent()) + { + TInt autoDelete = pdu.Bits7To4() & TSmsDataCodingScheme::ESmsDCSAutomaticDeletionMask; + + if (autoDelete == TSmsDataCodingScheme::ESmsDCSAutomaticDeletion) + { + iIsMarkedForAutoDelete = ETrue; + } + } + + LOGSMSPROT2("CSmsPDUProcessor::AnalysePDUCharacteristics(): iIsMarkedForAutoDelete=%d", + iIsMarkedForAutoDelete); + + // + // Should this PDU be deleted after processing? + // + if (iIsMarkedForAutoDelete && + (iIsClass2Message == EFalse || iOptionApplyAutoDeletionToClass2)) + { + iIsPDUToBeDeleted = ETrue; + } + else if (iIsPIDType0 && + (iIsClass2Message == EFalse || iOptionDiscardType0Class2)) + { + iIsPDUToBeDeleted = ETrue; + } + + LOGSMSPROT2("CSmsPDUProcessor::AnalysePDUCharacteristics(): iIsPDUToBeDeleted=%d", + iIsPDUToBeDeleted); + + // + // Does the message need to be stored??? + // + // Don't store class 2 SMSs with index 0 on SIM. Not sure why, but + // it appears to be delibrate and no one has ever complained! + // + // Don't store messages already stored somewhere other than the + // phone store. + // + if (iIsPDUToBeDeleted == EFalse && + ((iIsEnumeration && iSlot.iIndex != 0 && iSlot.iStore != KETelMeSmsStore) || + (iSlot.iStore != KETelMeSmsStore && iSlot.iStore.Length() > 0))) + { + iIsMessageGoingToBeStored = ETrue; + } + + LOGSMSPROT2("CSmsPDUProcessor::AnalysePDUCharacteristics(): iIsMessageGoingToBeStored=%d", + iIsMessageGoingToBeStored); + + // + // Is the message complete? This value may change later, when the segmentation and + // reassembley stores are examined. + // + iIsComplete = iSmsMessage->IsComplete(); + + LOGSMSPROT2("CSmsPDUProcessor::AnalysePDUCharacteristics(): iIsComplete=%d", + iIsComplete); + + // + // Store PDU Data. These values may be updated later. + // + iSmsPDUData.iType = iSmsMessage->Type(); + iSmsPDUData.iTotal = 1; + iSmsPDUData.iReceived = 1; + } // CSmsPDUProcessor::AnalysePDUCharacteristics + + +void CSmsPDUProcessor::FindOriginalMessageAndProcessStatusReportL() + { + __ASSERT_DEBUG(iSmsMessage->Type() == CSmsPDU::ESmsStatusReport, + SmspPanic(KSmspPanicNotStatusReport)); + + // + // Find the original message in the segmentation store and update its status + // to that contained in the status report. + // + TBool found = iSegmentationStore.AddStatusReportL(iIndex, iIsComplete, *iSmsMessage); + + LOGSMSPROT2("CSmsPDUReadProcess::FindOriginalMessageAndProcessStatusReportL(): found=%d",found); + + if (found) + { + // + // The status report refers to a known message. Update the this status message + // with the correct Log Server ID and it's related info. + // + const TSmsSegmentationEntry& entry = (const TSmsSegmentationEntry&) + iSegmentationStore.Entries()[iIndex]; + + iSmsMessage->SetLogServerId(entry.LogServerId()); + + iSmsPDUData.iType = entry.PduType(); + iSmsPDUData.iTotal = entry.Total(); + iSmsPDUData.iSent = entry.Count(); + iSmsPDUData.iDelivered = entry.Delivered(); + iSmsPDUData.iFailed = entry.Failed(); + + // + // Load the original SUBMIT message into memory for further processing later... + // Note that smsBuffer's ownership transfers straight away!!! + // + CSmsBuffer* smsBuffer = CSmsBuffer::NewL(); + + iOriginalSmsMessage = CSmsMessage::NewL(iReassemblyStore.FileSession(), + CSmsPDU::ESmsSubmit, + smsBuffer); + iSegmentationStore.GetMessageL(iIndex, iSmsAddr, *iOriginalSmsMessage, + iStatusArray); + } + } // CSmsPDUProcessor::FindOriginalMessageAndProcessStatusReportL + + +void CSmsPDUProcessor::UpdateStatusReportL() + { + LOGSMSPROT1("CSmsPDUProcessor::UpdateStatusReportL()"); + + // + // Update the receive time of the status report... + // + TTime currTime; + currTime.UniversalTime(); + + iSmsMessage->SetTime(currTime); + iSmsMessage->SetUTCOffset(User::UTCOffset()); + iSmsMessage->SetToFromAddressL(iOriginalSmsMessage->ToFromAddress()); + + // + // Set the status report to the last status received by the SME... + // + CSmsStatusReport& statusReport = (CSmsStatusReport&) iSmsMessage->SmsPDU(); + TInt count = iStatusArray.Count(); + + for (TInt index = 0; index < count; index++) + { + TInt status = iStatusArray[index].Status(); + + statusReport.SetStatus((TSmsStatus::TSmsStatusValue) status); + if (status != TSmsStatus::ESmsShortMessageReceivedBySME) + { + break; + } + } + } // CSmsPDUProcessor::UpdateStatusReportL + + +void CSmsPDUProcessor::AddSlotToSmsMessageIfRequiredL() + { + LOGSMSPROT1("CSmsPDUProcessor::AddSlotToSmsMessageIfRequiredL()"); + + // + // Add the slot to the message (if it is not going to be deleted and + // the client needs to know it's location e.g. to store it)... + // + if (iIsMessageGoingToBeStored) + { + TGsmSmsSlotEntry smsSlotEntry; + + smsSlotEntry.iIndex = iSlot.iIndex; + smsSlotEntry.iStore = iSlot.iStore; + + iSmsMessage->AddSlotL(smsSlotEntry); + } + } // CSmsPDUProcessor::AddSlotToSmsMessageIfRequiredL + + +/** + * Add the message segment to the reassembly store. There are 5 possiblities: + * + * 1) This is the complete message (e.g. a single-segment message). + * We therefore have all the segments. + * 2) This is a duplicate message segment. + * We will ignore it. + * 3) This is the last segment in the message required to complete it. + * The other segments are already stored. + * 4) This is another PDU to an existing message in the store, but it is + * not yet complete. + * 5) This is the first PDU in the message, and therefore the message is + * not yet complete and no segments are stored. + * + * @note Only SUBMIT or DELIVER PDUs can be added to the reassembly store. + */ +void CSmsPDUProcessor::AddSegmentOfMessageToReassemblyStoreIfRequiredL() + { + LOGSMSPROT2("CSmsPDUReadProcess::AddSegmentOfMessageToReassemblyStoreIfRequiredL(): iIsComplete=%d", + iIsComplete); + + iReassemblyStore.AddSegmentToReassemblyStoreL(*iSmsMessage, iGsmSms, iIndex, iIsComplete, iIsEnumeration, iSmsPDUData.iReceived, iSmsPDUData.iTotal); + } // CSmsPDUProcessor::AddSegmentOfMessageToReassemblyStoreIfRequiredL + + +void CSmsPDUProcessor::UpdateLogServerIdL() + { + LOGSMSPROT1("CSmsPDUProcessor::UpdateLogServerIdL()"); + + // + // If this is a SUBMIT or DELIVER PDU, + // then search for it in the Reassembly store. + // + if (iSmsMessage != NULL && iIndex != KErrNotFound && + (iSmsMessage->Type() == CSmsPDU::ESmsSubmit || + iSmsMessage->Type() == CSmsPDU::ESmsDeliver)) + { + iReassemblyStore.UpdateLogServerIdL(*iSmsMessage, iIndex); + } + } // CSmsPDUProcessor::UpdateLogServerIdL + +void CSmsPDUProcessor::ProcessMessageIfCompleteL() + { + LOGSMSPROT1("CSmsPDUProcessor::ProcessMessageIfCompleteL()"); + + if ((iIsClass0Message && !iIsWapSms) && iReassemblyStore.IsSeparateClass0StoreSupported()) + { + //Note: Process Class 0 Message which is not wap message & return. + if (iIsComplete) + { + // + // Process the message... + // + if (iOriginalSmsMessage == NULL) + { + iReassemblyStore.ForwardCompleteClass0SmsMessagesL(iSmsComm, *iSmsMessage, NULL, iOriginalSmsMessage, iDeliverReportBuffer); + } + else + { + iReassemblyStore.ForwardCompleteClass0SmsMessagesL(iSmsComm, *iSmsMessage, &iSmsAddr, iOriginalSmsMessage, iDeliverReportBuffer); + } + } + else + { + iReassemblyStore.ProcessMessageIfExceedLimitationL(iSmsComm); + } + return; + } + + if (iIsComplete) + { + // + // Process the message... + // + TInt ret(KErrUnknown); + + if (iOriginalSmsMessage == NULL) + { + ret = iSmsComm.ProcessMessageL(*iSmsMessage, NULL, + iOriginalSmsMessage, + iDeliverReportBuffer); + } + else + { + ret = iSmsComm.ProcessMessageL(*iSmsMessage, &iSmsAddr, + iOriginalSmsMessage, + iDeliverReportBuffer); + } + + // + // If successful, mark the entry as delivered to the msgc... + // + if(ret == KErrNone) + { + iReassemblyStore.SetMessagePassedToClientL(*iSmsMessage); + } + } + } // CSmsPDUProcessor::ProcessMessageIfCompleteL + +void CSmsPDUProcessor::DeletePDUL() + { + LOGSMSPROT1("CSmsPDUProcessor::DeletePDUL()"); + + // + // If the slot number has an index and store assigned, then we can delete + // it. + // + if (iSlot.iIndex >= 0 && iSlot.iStore.Length() > 0) + { + CArrayFixFlat* smsSlotEntryArray = new (ELeave) CArrayFixFlat(1); + CleanupStack::PushL(smsSlotEntryArray); + + TGsmSmsSlotEntry smsSlotEntry; + + smsSlotEntry.iIndex = iSlot.iIndex; + smsSlotEntry.iStore = iSlot.iStore; + smsSlotEntryArray->AppendL(smsSlotEntry); + + iSmsComm.DeletePDUs(*smsSlotEntryArray, NULL); + + CleanupStack::PopAndDestroy(smsSlotEntryArray); + } + } // CSmsPDUProcessor::DeletePDUL +