--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspstor.cpp Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1609 @@
+// 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:
+// Implements CSmsReassemblyStore and CSmsSegmentationStore.
+//
+//
+
+/**
+ @file
+*/
+
+#include <e32svr.h>
+#include <es_ini.h>
+#include "smspstor.h"
+#include "smspmain.h"
+#include "smsuaddr.H"
+#include "Gsmumsg.h"
+#include "gsmubuf.h"
+#include <logwrap.h>
+#include <logwraplimits.h>
+#include "Gsmuelem.h"
+#include "gsmuieoperations.h"
+#include "gsmunonieoperations.h"
+
+LOCAL_C TPtrC TrimLeadingZeros(const TDesC& aString)
+ {
+ LOGSMSPROT1("CSARStore::ExternalizeEntryArrayL()");
+
+ const TInt len = aString.Length();
+
+ if (len == 0)
+ return aString;
+
+ const TUint16* startChar = &aString[0];
+ const TUint16* endChar = &aString[len-1];
+
+ while (startChar <= endChar && *startChar == '0')
+ {
+ ++startChar;
+ }
+ return TPtrC(startChar, endChar - startChar + 1);
+ } // TrimLeadingZeros
+
+
+/**
+ * Creates new CSmsReassemblyStore instance
+ *
+ * @param aFs File Server handle.
+ */
+CSmsReassemblyStore* CSmsReassemblyStore::NewL(RFs& aFs)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::NewL()");
+
+ CSmsReassemblyStore* self = new (ELeave) CSmsReassemblyStore(aFs);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+
+ return self;
+ } // CSmsReassemblyStore::NewL
+
+
+/**
+ * Creates and starts timer
+ */
+void CSmsReassemblyStore::ConstructL()
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::ConstructL()");
+
+ //
+ // Generate the full path to the reassembly store.
+ //
+ PrivatePath(iFullPathBuf);
+ iFullPathBuf.Append(KReassemblyStoreName);
+
+ iLastReceivedTime.UniversalTime();
+ iLastRealTime = iLastReceivedTime;
+ } // CSmsReassemblyStore::ConstructL
+
+
+/**
+ * Destructor
+ */
+CSmsReassemblyStore::~CSmsReassemblyStore()
+ {
+ // NOP
+ } // CSmsReassemblyStore::~CSmsReassemblyStore
+
+
+void CSmsReassemblyStore::UpdateLogServerIdL(TInt aIndex, TLogId aLogServerId)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::UpdateLogServerIdL()");
+
+ TSmsReassemblyEntry entry(reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[aIndex]));
+
+ if (entry.LogServerId() != aLogServerId)
+ {
+ entry.SetLogServerId(aLogServerId);
+ BeginTransactionLC();
+ ChangeEntryL(aIndex, entry);
+ CommitTransactionL();
+ }
+ } // CSmsReassemblyStore::UpdateLogServerIdL
+
+
+/**
+ * Searches the reassembly store for a CSmsMessage and returns its index.
+ *
+ * @param aSmsMessage Message to search for.
+ * @param aPassed Determines if we are searching for a message already
+ * passed to the client.
+ * @param aIndex Return index value.
+ *
+ * @return True and an index if aSmsMessage is found in this reassembly store
+ */
+TBool CSmsReassemblyStore::FindMessageL(const CSmsMessage& aSmsMessage,
+ TBool aPassed,
+ TInt& aIndex)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::FindMessageL()");
+
+ //
+ // Parse the GSM data from the SMS message...
+ //
+ TGsmSmsTelNumber parsedAddress;
+
+ aSmsMessage.ParsedToFromAddress(parsedAddress);
+
+ //
+ // Search the store for a matching message...
+ //
+ for (TInt index = Entries().Count() - 1; index >= 0; index--)
+ {
+ const TSmsReassemblyEntry& entry = reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[index]);
+
+ // Always search the basic types first and strings last!
+ if (entry.PduType() == aSmsMessage.Type() &&
+ entry.PassedToClient() == aPassed &&
+ entry.Storage() == aSmsMessage.Storage() &&
+ entry.Time() == aSmsMessage.Time() &&
+ entry.Description2().Right(8) == parsedAddress.iTelNumber.Right(8))
+ {
+ //
+ // Found!
+ //
+ LOGSMSPROT2("CSmsReassemblyStore::FindMessage(): Found! index=%d", index);
+
+ aIndex = index;
+
+ return ETrue;
+ }
+ }
+
+ //
+ // Not found...
+ //
+ LOGSMSPROT1("CSmsReassemblyStore::FindMessage(): Not found!");
+
+ return EFalse;
+ } // CSmsReassemblyStore::FindMessageL
+
+
+/**
+ * Adds Pdu to reassembly store
+ *
+ * @param aSmsMessage PDU to
+ * @param aGsmSms Used to
+ * @param aIndex Used to
+ * @param aComplete Used to
+ * @param aServiceCenterAddressPresent Used to
+ */
+void CSmsReassemblyStore::MatchPDUToExistingMessage(const CSmsMessage& aSmsMessage,
+ TInt& aIndex)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::MatchPDUToExistingMessage()");
+
+ __ASSERT_ALWAYS(!aSmsMessage.IsDecoded(), SmspPanic(KSmspPanicMessageConcatenated));
+
+ aIndex = KErrNotFound;
+
+ TGsmSmsTelNumber parsedAddress;
+ aSmsMessage.ParsedToFromAddress(parsedAddress);
+
+ //
+ // Search the reassembly store for a matching entry (start from the
+ // end as the most recent PDUs appear at the end)...
+ //
+ TInt reassemblyCount = Entries().Count();
+
+ for (TInt index = reassemblyCount - 1; index >= 0; index--)
+ {
+ TSmsReassemblyEntry& entry = (TSmsReassemblyEntry&) Entries()[index];
+
+ // Always check the fields in order of the quickest to check...
+ if (entry.IsComplete() == EFalse &&
+ entry.PduType() == aSmsMessage.Type() &&
+ entry.Storage() == aSmsMessage.Storage())
+ {
+ TInt telLen = Min(entry.Description2().Length(),
+ parsedAddress.iTelNumber.Length());
+
+ if (entry.Description2().Right(telLen) == parsedAddress.iTelNumber.Right(telLen) &&
+ entry.Total() == aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs() &&
+ entry.Reference() == aSmsMessage.SmsPDU().ConcatenatedMessageReference())
+ {
+ //
+ // Found it!
+ //
+ aIndex = index;
+ break;
+ }
+ }
+ }
+
+ LOGSMSPROT3("CSmsReassemblyStore::MatchPDUToExistingMessage(): reassemblyCount=%d, aIndex=%d", reassemblyCount, aIndex);
+ } // CSmsReassemblyStore::MatchPDUToExistingMessage
+
+
+void CSmsReassemblyStore::UpdateExistingMessageL(const CSmsMessage& aSmsMessage,
+ const TGsmSms& aGsmSms, TInt aIndex,
+ TBool& aComplete,
+ TBool& aDuplicateMsgRef,
+ TBool& aDuplicateSlot)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL()");
+
+ aComplete = EFalse;
+ aDuplicateMsgRef = EFalse;
+ aDuplicateSlot = EFalse;
+
+ //
+ // Read the segment from the store into a CSmsMessage buffer...
+ //
+ TSmsReassemblyEntry entry = (TSmsReassemblyEntry&) Entries()[aIndex];
+
+ CArrayFix<TInt>* indexArray = new(ELeave) CArrayFixFlat<TInt>(8);
+ CleanupStack::PushL(indexArray);
+ CArrayFixFlat<TGsmSms>* smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(8);
+ CleanupStack::PushL(smsArray);
+ CSmsBuffer* buffer = CSmsBuffer::NewL();
+ CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
+ CleanupStack::PushL(smsMessage);
+
+ InternalizeEntryL(entry.DataStreamId(), *smsMessage, *indexArray, *smsArray);
+
+ //
+ // Check if this is a duplicated enumerated PDU (e.g. on the SIM or phone memory)
+ // or a duplicated PDU (e.g. in the Reassembly Store)...
+ //
+ TInt concatPDUIndex = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
+
+ if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage ||
+ smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
+ {
+ //
+ // In most cases this PDU is being enumerated, but not always. It is
+ // possible for the PDU to be stored on the SIM first before it is
+ // received.
+ //
+ const TGsmSmsSlotEntry& newSlot = aSmsMessage.iSlotArray[0];
+ TInt slotArrayCount = smsMessage->iSlotArray.Count();
+
+ for (TInt slotNum = 0; slotNum < slotArrayCount; slotNum++ )
+ {
+ const TGsmSmsSlotEntry& slot = smsMessage->iSlotArray[slotNum];
+
+ if (slot.iIndex == newSlot.iIndex && slot.iStore == newSlot.iStore)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate enumerated PDU.");
+
+ // It is a duplicate that was already stored on the SIM...
+ aDuplicateSlot = ETrue;
+ break;
+ }
+ }
+ }
+
+ TInt indexArrayCount = indexArray->Count();
+
+ for (TInt index = 0; index < indexArrayCount; index++ )
+ {
+ if (indexArray->At(index) == concatPDUIndex)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate concatenated PDU.");
+
+ // The PDU is already stored in the reassembly store.
+ aDuplicateMsgRef = ETrue;
+ break;
+ }
+ }
+
+ if (aDuplicateMsgRef || aDuplicateSlot)
+ {
+ CleanupStack::PopAndDestroy(3, indexArray); // smsMessage, smsArray, indexArray
+ return;
+ }
+
+ //
+ // If the PDU is stored then add the slot information...
+ //
+ if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage ||
+ smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
+ {
+ smsMessage->AddSlotL(aSmsMessage.iSlotArray[0]);
+ }
+
+ //
+ // If the PDU is Unsent or Unread, then store that information...
+ //
+ NMobileSmsStore::TMobileSmsStoreStatus status = aSmsMessage.Status();
+
+ if (status == NMobileSmsStore::EStoredMessageUnsent ||
+ status == NMobileSmsStore::EStoredMessageUnread)
+ {
+ smsMessage->SetStatus(status);
+ }
+
+ //
+ // Does this PDU mean the message is complete? If so then decode the message,
+ // reset the index and sms arrays (to save space for completed SMSs).
+ //
+ indexArray->AppendL(concatPDUIndex);
+ smsArray->AppendL(aGsmSms);
+
+ if (smsArray->Count() == smsMessage->SmsPDU().NumConcatenatedMessagePDUs())
+ {
+ smsMessage->DecodeMessagePDUsL(*smsArray);
+
+ indexArray->Reset();
+ smsArray->Reset();
+
+ aComplete = ETrue;
+ }
+
+ //
+ // Write the entry back into the store...
+ //
+ TStreamId streamid = entry.DataStreamId();
+ smsMessage->SetLogServerId(entry.LogServerId());
+
+ BeginTransactionLC();
+ ExternalizeEntryL(streamid, *smsMessage, *indexArray, *smsArray);
+ PopulateEntry(entry, *smsMessage, smsArray->Count());
+ ChangeEntryL(aIndex, entry);
+ CommitTransactionL();
+
+ CleanupStack::PopAndDestroy(3, indexArray); // smsMessage, smsArray, indexArray
+ } // CSmsReassemblyStore::UpdateExistingMessageL
+
+
+void CSmsReassemblyStore::NewMessagePDUL(TInt& aIndex,CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::NewMessagePDUL");
+
+ CArrayFix<TInt>* indexarray=new(ELeave) CArrayFixFlat<TInt>(8);
+ CleanupStack::PushL(indexarray);
+ CArrayFixFlat<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
+ CleanupStack::PushL(smsarray);
+ TInt index=aSmsMessage.IsDecoded()? 0: aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
+ indexarray->AppendL(index);
+ smsarray->AppendL(aGsmSms);
+ aIndex=Entries().Count();
+ CreateEntryL(aSmsMessage,*indexarray,*smsarray);
+ CleanupStack::PopAndDestroy(2);
+ } // CSmsReassemblyStore::NewMessagePDUL
+
+
+void CSmsReassemblyStore::GetMessageL(TInt aIndex,CSmsMessage& aSmsMessage)
+ {
+ LOGSMSPROT2("CSmsReassemblyStore::GetMessageL [aIndex=%d]", aIndex);
+
+ CArrayFix<TInt>* indexarray=new(ELeave) CArrayFixFlat<TInt>(8);
+ CleanupStack::PushL(indexarray);
+ CArrayFixFlat<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
+ CleanupStack::PushL(smsarray);
+ InternalizeEntryL(Entries()[aIndex].DataStreamId(),aSmsMessage,*indexarray,*smsarray);
+ TInt logid=Entries()[aIndex].LogServerId();
+ if(aSmsMessage.LogServerId() == KLogNullId && logid != KLogNullId)
+ aSmsMessage.SetLogServerId(logid);
+ CleanupStack::PopAndDestroy(2); // smsarray, indexarray
+ } // CSmsReassemblyStore::GetMessageL
+
+
+/**
+ * internalize all the entries from the permanent file store to internal memory
+ *
+ * NOTE! You have to call CSARStore::OpenFileLC() before calling this function
+ */
+void CSmsReassemblyStore::InternalizeEntryL(const TStreamId& aStreamId,CSmsMessage& aSmsMessage,CArrayFix<TInt>& aIndexArray,CArrayFix<TGsmSms>& aSmsArray)
+ {
+ LOGSMSPROT2("CSmsReassemblyStore::InternalizeEntryL Start [sid=%d]", aStreamId.Value());
+ RStoreReadStream readstream;
+ readstream.OpenLC(FileStore(),aStreamId);
+ readstream >> aSmsMessage;
+ TInt count=readstream.ReadInt32L();
+ aIndexArray.Reset();
+ TInt i;
+ for (i=0; i<count; i++)
+ {
+ TInt index=readstream.ReadInt32L();
+ aIndexArray.AppendL(index);
+ }
+ count=readstream.ReadInt32L();
+ if(count!=aIndexArray.Count())
+ User::Leave(KErrCorrupt);
+ aSmsArray.Reset();
+ for (i=0; i<count; i++)
+ {
+ RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
+ readstream >> pdu;
+ TGsmSms sms;
+ sms.SetPdu(pdu);
+ aSmsArray.AppendL(sms);
+ }
+ CleanupStack::PopAndDestroy();
+ LOGSMSPROT2("CSmsReassemblyStore::InternalizeEntryL End [count=%d]", count);
+ } // CSARStore::OpenFileLC
+
+
+/**
+ * externalizes all the entries from the internal memory to the permanent file store
+ *
+ * NOTE! You have to call CSARStore::OpenFileLC() before calling this function
+ */
+void CSmsReassemblyStore::ExternalizeEntryL(TStreamId& aStreamId,const CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
+ {
+ LOGSMSPROT2("CSmsReassemblyStore::ExternalizeEntryL Start [sid=%d]", aStreamId.Value());
+
+ RStoreWriteStream writestream;
+ if (aStreamId==KNullStreamId)
+ aStreamId=writestream.CreateLC(FileStore());
+ else
+ writestream.ReplaceLC(FileStore(),aStreamId);
+ writestream << aSmsMessage;
+ TInt count=aIndexArray.Count();
+ __ASSERT_ALWAYS(count==aIndexArray.Count(),SmspPanic(KSmspPanicBadIndexArray));
+ writestream.WriteInt32L(count);
+ TInt i=0;
+ for (; i<count; i++)
+ writestream.WriteInt32L(aIndexArray[i]);
+ count=aSmsArray.Count();
+ writestream.WriteInt32L(count);
+ for (i=0; i<count; i++)
+ {
+ RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
+ pdu=aSmsArray[i].Pdu();
+ writestream << pdu;
+ }
+ writestream.CommitL();
+ CleanupStack::PopAndDestroy();
+
+ LOGSMSPROT2("CSmsReassemblyStore::ExternalizeEntryL End [count=%d]", count);
+ } // CSARStore::OpenFileLC
+
+
+void CSmsReassemblyStore::PopulateEntry(TSmsReassemblyEntry& aEntry,const CSmsMessage& aSmsMessage,TInt aNumSmss)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::PopulateEntry");
+ aEntry.SetReference(0);
+ aEntry.SetTotal(1);
+ aEntry.SetCount(1);
+
+ if (aSmsMessage.TextPresent())
+ {
+ if (aSmsMessage.SmsPDU().TextConcatenated())
+ {
+ aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
+ aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
+ aEntry.SetCount(aSmsMessage.IsComplete()? aEntry.Total(): aNumSmss);
+ }
+ TInt bits7to4=aSmsMessage.SmsPDU().Bits7To4();
+ TInt count=aSmsMessage.SmsPDU().UserData().NumInformationElements();
+ TInt identifier1=0xFF;
+ TInt identifier2=0x00;
+ for (TInt i=0; i<count; i++)
+ {
+ TInt identifier=aSmsMessage.SmsPDU().UserData().InformationElement(i).Identifier();
+ if ((identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages8BitReference) && (identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages16BitReference))
+ {
+ if (identifier<identifier1)
+ identifier1=identifier;
+ if (identifier>identifier2)
+ identifier2=identifier;
+ }
+ }
+
+ if ((bits7to4>=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage) && (bits7to4<=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2))
+ aEntry.SetBits7to4andIdentifiers(bits7to4, identifier1, identifier2);
+ else
+ aEntry.SetBits7to4andIdentifiers(0, identifier1, identifier2);
+ }
+
+ //Set the logServerId to aSmsMessage.LogServerId()
+
+ aEntry.SetLogServerId(aSmsMessage.LogServerId());
+
+ const CSmsPDU::TSmsPDUType type(aSmsMessage.Type());
+ aEntry.SetPduType(type);
+ aEntry.SetPassedToClient(EFalse);
+
+ aEntry.SetStorage(aSmsMessage.Storage());
+ if ((type!=CSmsPDU::ESmsSubmitReport) && (type!=CSmsPDU::ESmsDeliverReport))
+ {
+ // Strip out spaces etc from address
+ TGsmSmsTelNumber parsedaddress;
+ aSmsMessage.ParsedToFromAddress(parsedaddress);
+ aEntry.SetDescription2(parsedaddress.iTelNumber);
+ }
+
+ aEntry.SetTime(aSmsMessage.Time());
+ } // CSmsReassemblyStore::PopulateEntry
+
+
+void CSmsReassemblyStore::CreateEntryL(CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::CreateEntryL");
+ TStreamId streamid=KNullStreamId;
+ if (aSmsMessage.Time() >= iLastRealTime)
+ {
+ iLastRealTime=aSmsMessage.Time();
+ if(iLastReceivedTime >= aSmsMessage.Time())
+ {
+ aSmsMessage.SetTime(iLastReceivedTime+(TTimeIntervalMicroSeconds32)1);
+ }
+ iLastReceivedTime=aSmsMessage.Time(); //provide uniqueness of time
+ }
+ else // clock turned back
+ {
+ iLastReceivedTime=aSmsMessage.Time();
+ }
+ BeginTransactionLC();
+ ExternalizeEntryL(streamid,aSmsMessage,aIndexArray,aSmsArray);
+ TSmsReassemblyEntry entry;
+ entry.SetDataStreamId(streamid);
+
+ PopulateEntry(entry,aSmsMessage,aSmsArray.Count());
+ AddEntryL(entry);
+ CommitTransactionL();
+ } // CSmsReassemblyStore::CreateEntryL
+
+
+TBool CSmsReassemblyStore::PassedToClient( TInt aIndex ) const
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::PassedToClient()");
+
+ const TSmsReassemblyEntry& entry = reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[ aIndex ]);
+ return entry.PassedToClient();
+ } // CSmsReassemblyStore::PassedToClient
+
+
+void CSmsReassemblyStore::SetPassedToClientL(TInt aIndex, TBool aPassed)
+//TODO CommentThisFunction
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::SetPassedToClientL()");
+
+ TSmsReassemblyEntry entry(reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[aIndex]));
+
+ const TBool alreadyPassed = entry.PassedToClient();
+
+ if ((!aPassed && alreadyPassed) || (aPassed && !alreadyPassed))
+ {
+ entry.SetPassedToClient(aPassed);
+ ChangeEntryL(aIndex, entry);
+ }
+ } // CSmsReassemblyStore::SetPassedToClientL
+
+
+/**
+ * Open the sms reassembly store.
+ */
+void CSmsReassemblyStore::OpenStoreL()
+ {
+ LOGSMSPROT1("CSmsReassemblyStore::OpenStoreL()");
+
+ this->OpenL(iFullPathBuf,KReassemblyStoreUid);
+ } // CSmsReassemblyStore::OpenStoreL
+
+
+/**
+ * Constructor
+ *
+ * @param aFs Used to set CSARStore object
+ */
+CSmsReassemblyStore::CSmsReassemblyStore(RFs& aFs)
+ :CSARStore(aFs)
+ {
+ // NOP
+ } // CSmsReassemblyStore::CSmsReassemblyStore
+
+
+CSmsSegmentationStore* CSmsSegmentationStore::NewL(RFs& aFs)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::NewL()");
+
+ CSmsSegmentationStore* segmentationStore = new(ELeave) CSmsSegmentationStore(aFs);
+ CleanupStack::PushL( segmentationStore );
+ segmentationStore->ConstructL();
+ CleanupStack::Pop( segmentationStore );
+ return segmentationStore;
+ } // CSmsSegmentationStore::NewL
+
+
+void CSmsSegmentationStore::ConstructL()
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::ConstructL()");
+
+ //generate fullpath of segmentation store.
+ PrivatePath(iFullPathBuf);
+ //append store name
+ iFullPathBuf.Append(KSegmentationStoreName);
+
+ // Set the default value for the maxmum number messages in the segmentation store.
+ iMaxmumNumberOfMessagesInSegmentationStore = KDefaultMaxmumNumberOfMessagesInSegmentationStore;
+
+ CESockIniData* ini = NULL;
+ _LIT(KSmseskfile, "smswap.sms.esk");
+ TRAPD(ret, ini=CESockIniData::NewL(KSmseskfile));
+ if(ret == KErrNone)
+ {
+ // Get the maximum number of messages allowed in the segmentation store from .ESK file
+ CleanupStack::PushL(ini);
+
+ TPtrC value;
+ if((ini->FindVar(_L("SegmentationStoreOptions"),_L("MaxNumOfMessInSegStore"),value)))
+ {
+ TLex16 valueconv(value);
+ valueconv.Val(iMaxmumNumberOfMessagesInSegmentationStore);
+ }
+ CleanupStack::PopAndDestroy(ini);
+ }
+ else if (ret != KErrNotFound && ret != KErrPathNotFound)
+ {
+ User::Leave(ret);
+ }
+ } // CSmsSegmentationStore::ConstructL
+
+
+CSmsSegmentationStore::~CSmsSegmentationStore()
+ {
+ // NOP
+ } // CSmsSegmentationStore::~CSmsSegmentationStore
+
+
+TInt CSmsSegmentationStore::Next8BitReferenceL()
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::Next8BitReferenceL");
+
+ TInt reference8bit=0;
+ TInt reference16bit=0;
+ TStreamId streamid=ExtraStreamId();
+
+ //
+ // access file store
+ //
+ BeginTransactionLC();
+ if (streamid!=KNullStreamId)
+ {
+ TRAPD(ret,InternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
+ if(ret != KErrNone)
+ {
+ // We have to leave on any error; otherwise a duplicate reference number will be generated
+ // The transaction will revert
+ LOGSMSPROT2("WARNING! CSmsSegmentationStore::InternalizeConcatenationReferencesL left with %d", ret);
+ User::Leave(ret); // stream not corrupted
+ }
+ reference8bit=(reference8bit+1)%0x100;
+ }
+ TRAPD(ret, ExternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
+ if(ret != KErrNone)
+ {
+ // We have to leave on any error; otherwise a duplicate reference number will be generated
+ // The transaction will revert
+ LOGSMSPROT2("WARNING! CSmsSegmentationStore::ExternalizeConcatenationReferencesL left with %d", ret);
+ User::Leave(ret); // stream not corrupted
+ }
+ SetExtraStreamIdL(streamid);
+ CommitTransactionL();
+ return reference8bit;
+ } // CSmsSegmentationStore::Next8BitReferenceL
+
+
+TInt CSmsSegmentationStore::Next16BitReferenceL()
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::Next16BitReferenceL");
+ TInt reference8bit=0;
+ TInt reference16bit=0x100;
+ TStreamId streamid=ExtraStreamId();
+ //
+ // access file store
+ //
+ BeginTransactionLC();
+ if (streamid!=KNullStreamId)
+ {
+ TRAPD(ret,InternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
+ if(ret != KErrNone)
+ {
+ // We have to leave on any error; otherwise a duplicate reference number will be generated
+ // The transaction will revert
+ LOGSMSPROT2("WARNING! CSmsSegmentationStore::InternalizeConcatenationReferencesL left with %d", ret);
+ User::Leave(ret); // stream not corrupted
+ }
+ reference16bit=((reference16bit+1)%0xFF00)+0x100;
+ }
+ TRAPD(ret, ExternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
+ if(ret != KErrNone)
+ {
+ // We have to leave on any error; otherwise a duplicate reference number will be generated
+ // The transaction will revert
+ LOGSMSPROT2("WARNING! CSmsSegmentationStore::ExternalizeConcatenationReferencesL left with %d", ret);
+ User::Leave(ret); // stream not corrupted
+ }
+ SetExtraStreamIdL(streamid);
+ CommitTransactionL();
+ return reference16bit;
+ } // CSmsSegmentationStore::Next16BitReferenceL
+
+
+/**
+ * Adds a CSmsMessage to the segmentation store
+ *
+ * @note aSumbit.Buffer() may be shortened to TSAREntry::ESmsSAREntryDescriptionLength
+ *
+ * @param aSubmit Message to add to the segmentation store
+ * @pre aSubmit.Type() is ESmsSubmit
+ * @pre aSubmit.EncodeMessagePdusL() has been called. This is so PopulateEntry sets the correct total on the TSAREntry
+ */
+void CSmsSegmentationStore::AddSubmitL(const TSmsAddr& aSmsAddr,CSmsMessage& aSubmit)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::AddSubmitL");
+
+ __ASSERT_ALWAYS(aSubmit.Type()==CSmsPDU::ESmsSubmit,SmspPanic(KSmspPanicNotSubmit));
+
+ BeginTransactionLC();
+
+
+ RSmsSegmentationStoreRefStatusArray refStatus;
+ CleanupClosePushL(refStatus);
+
+ TStreamId streamid=KNullStreamId;
+ CSmsBufferBase& buffer=aSubmit.Buffer();
+ TInt length=buffer.Length();
+ if (length>TSAREntry::ESmsSAREntryDescriptionLength)
+ buffer.DeleteL(TSAREntry::ESmsSAREntryDescriptionLength,length-TSAREntry::ESmsSAREntryDescriptionLength);
+
+ ExternalizeEntryL(streamid,aSmsAddr,aSubmit, refStatus);
+
+ TSmsSegmentationEntry entry;
+ entry.SetDataStreamId(streamid);
+ PopulateEntry(entry, aSubmit, refStatus);
+
+ CleanupStack::PopAndDestroy(&refStatus);
+
+ AddEntryL(entry);
+ CommitTransactionL();
+ } // CSmsSegmentationStore::AddSubmitL
+
+
+TBool CSmsSegmentationStore::AddCommandL(const TSmsAddr& aSmsAddr,const CSmsMessage& aCommand, CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray& aRefStatus)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::AddCommandL");
+ __ASSERT_ALWAYS(aCommand.Type()==CSmsPDU::ESmsCommand,SmspPanic(KSmspPanicNotCommand));
+ const TInt count=Entries().Count();
+ const TLogId logid=(TLogId) aCommand.LogServerId();
+
+ BeginTransactionLC();
+
+ //TODO AA: What is it doing here? Please comment
+ for (TInt i=count-1; i>=0; --i)
+ {
+ if ((logid!=KLogNullId) && (logid==Entries()[i].LogServerId()))
+ {
+ DeleteEntryL(i);
+ break;
+ }
+ }
+ TBool found=EFalse;
+
+ CSmsBuffer* buffer=CSmsBuffer::NewL();
+ CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsSubmit,buffer);
+ CleanupStack::PushL(smsmessage);
+ TGsmSmsTelNumber parsedaddress;
+ aCommand.ParsedToFromAddress(parsedaddress);
+ TInt telLen;
+
+ for (TInt j=0; j<count; j++)
+ {
+ TSmsSegmentationEntry entry = (TSmsSegmentationEntry&)Entries()[j];
+ const CSmsPDU::TSmsPDUType type = entry.PduType();
+ telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
+ if ((type==CSmsPDU::ESmsSubmit) &&
+ entry.IsComplete() &&
+ (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)) &&
+ (entry.Time()==aCommand.Time()))
+ {
+ found=ETrue;
+ TSmsAddr smsaddr;
+
+ InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, aRefStatus);
+ TStreamId streamid;
+ CSmsSubmit& submit=(CSmsSubmit&) smsmessage->SmsPDU();
+ if ((((CSmsCommand&) aCommand.SmsPDU()).CommandType()==TSmsCommandType::ESmsCommandTypeEnableStatusReportRequest) &&
+ (!submit.StatusReportRequest()))
+ {
+ submit.SetStatusReportRequest(ETrue);
+ streamid=entry.DataStreamId();
+ ExternalizeEntryL(streamid,smsaddr,*smsmessage, aRefStatus);
+ PopulateEntry(entry,*smsmessage, aRefStatus);
+ ChangeEntryL(j,entry);
+ }
+
+ //TODO What is happening here? Seems strange
+ RSmsSegmentationStoreRefStatusArray refStatusTemp;
+ CleanupClosePushL(refStatusTemp);
+
+ streamid=KNullStreamId;
+
+ ExternalizeEntryL(streamid,aSmsAddr,aCommand, refStatusTemp);
+ entry.SetDataStreamId(streamid);
+ PopulateEntry(entry,aCommand, refStatusTemp);
+
+ CleanupStack::PopAndDestroy(&refStatusTemp);
+
+ AddEntryL(entry);
+
+ break;
+ }
+ }
+ CleanupStack::PopAndDestroy(smsmessage); // smsmessage
+ CommitTransactionL();
+
+ return found;
+ } // CSmsSegmentationStore::AddCommandL
+
+
+TBool CSmsSegmentationStore::AddReferenceL(const CSmsMessage& aSmsMessage,TInt aReference)
+ {
+ TSmsSegmentationEntry entry; // TODO const and inside loop
+ const TInt count=Entries().Count();
+ LOGSMSPROT3("CSmsSegmentationStore::AddReferenceL [count=%d, ref=%d]", count, aReference);
+ TInt i=0;
+ TInt logserverid=aSmsMessage.LogServerId();
+ if (logserverid!=KLogNullId)
+ {
+ for (i=0; i<count; i++)
+ {
+ entry = (TSmsSegmentationEntry&)Entries()[i];
+ if (logserverid==entry.LogServerId())
+ break;
+ }
+ }
+ else
+ {
+ TGsmSmsTelNumber parsedaddress;
+ aSmsMessage.ParsedToFromAddress(parsedaddress);
+ TInt telLen;
+ for (i=0; i<count; i++)
+ {
+ entry = (TSmsSegmentationEntry&)Entries()[i];
+ telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
+ const CSmsPDU::TSmsPDUType type=entry.PduType();
+ if ((type==aSmsMessage.Type()) && (!entry.IsComplete()) && (aSmsMessage.Time()==entry.Time()) && (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
+ break;
+ }
+ }
+// __ASSERT_DEBUG(i<count,SmspPanic(KSmspPanicEntryWithLogServerIdNotFound)); TODO
+ if(i>=count)
+ {
+ LOGSMSPROT3("WARNING! KSmspPanicEntryWithLogServerIdNotFound [i=%d, count=%d]", i, count);
+ }
+
+ RSmsSegmentationStoreRefStatusArray refStatusArray;
+ CleanupClosePushL(refStatusArray);
+
+ TStreamId streamid=entry.DataStreamId();
+ TSmsAddr smsaddr;
+ CSmsBuffer* buffer=CSmsBuffer::NewL();
+ CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
+ CleanupStack::PushL(smsmessage);
+
+ //
+ // access the file store
+ //
+ InternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
+ refStatusArray.InsertL(aReference);
+
+ BeginTransactionLC();
+ ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
+
+ PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray);
+ ChangeEntryL(i,entry);
+ CommitTransactionL();
+
+ //
+ // AEH: moved here because if is done before calling ChangeEntryL
+ // it will pop and destroy the filestore which is also on
+ // the cleanup stack
+ //
+ CleanupStack::PopAndDestroy(2); // smsmessage, refStatus
+
+ return entry.Total()==entry.Count();
+ }
+
+
+/**
+ * Does exactly the same thing as AddReferenceL() i.e. adds the the segment refernce to a list. But
+ * to support the new status report schemes a slight change has been made. Instead of inserting
+ * just a reference now its status is inserted as well. This is provided one of the two new schemes
+ * is being used. If the status is required then we do exactly the same as AddReferenceL(), but if
+ * it's not then we just call the InsertL() method with an extra parameter: EStatusComplete.
+ *
+ * @param aSmsMessage Reference to CSmsMessage.
+ * @param aReference The PDU reference.
+ */
+TBool CSmsSegmentationStore::AddReferenceStatusPairL(const CSmsMessage& aSmsMessage,TInt aReference, TUint aSegmentSequenceNumber)
+ {
+ TSmsSegmentationEntry entry; // TODO const and inside loop
+ const TInt count=Entries().Count();
+ LOGSMSPROT3("CSmsSegmentationStore::AddReferenceStatusPairL [count=%d, ref=%d]", count, aReference);
+ TInt i=0;
+ TInt logserverid=aSmsMessage.LogServerId();
+ if (logserverid!=KLogNullId)
+ {
+ for (i=0; i<count; i++)
+ {
+ entry = (TSmsSegmentationEntry&)Entries()[i];
+ if (logserverid==entry.LogServerId())
+ break;
+ }
+ }
+ else
+ {
+ TGsmSmsTelNumber parsedaddress;
+ aSmsMessage.ParsedToFromAddress(parsedaddress);
+ TInt telLen;
+ for (i=0; i<count; i++)
+ {
+ entry = (TSmsSegmentationEntry&)Entries()[i];
+ telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
+ const CSmsPDU::TSmsPDUType type=entry.PduType();
+ if ((type==aSmsMessage.Type()) && (!entry.IsComplete()) && (aSmsMessage.Time()==entry.Time()) && (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
+ break;
+ }
+ }
+// __ASSERT_DEBUG(i<count,SmspPanic(KSmspPanicEntryWithLogServerIdNotFound)); TODO
+ if(i>=count)
+ {
+ LOGSMSPROT3("WARNING! KSmspPanicEntryWithLogServerIdNotFound [i=%d, count=%d]", i, count);
+ }
+
+ RSmsSegmentationStoreRefStatusArray refStatusArray;
+ CleanupClosePushL(refStatusArray);
+
+ TStreamId streamid=entry.DataStreamId();
+ TSmsAddr smsaddr;
+ CSmsBuffer* buffer=CSmsBuffer::NewL();
+ CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
+ CleanupStack::PushL(smsmessage);
+
+ //
+ // access the file store
+ //
+ InternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
+
+ if (aSmsMessage.Scheme() == EControlParametersScheme)
+ {
+ TUint8 octet(0);
+ TInt ret;
+
+ ret = ((CSmsSMSCCtrlParameterOperations&)aSmsMessage.GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters)).GetStatusReport(aSegmentSequenceNumber, octet);
+ if (ret == KErrNone)
+ {
+ if (octet & ESmsSMSCControlParametersMask)
+ {
+ refStatusArray.InsertL(aReference);
+ }
+ else
+ {
+ refStatusArray.InsertL(TSmsSegmentationStoreRefStatus(aReference, EStatusComplete));
+ }
+ }
+ }
+ else if(aSmsMessage.Scheme() == ETPSRRScheme)
+ {
+ TInt tpsrr;
+ tpsrr = ((CSmsTPSRROperations&)aSmsMessage.GetOperationsForNonIEL(ESmsTPSRRParameter)).GetStatusReport(aSegmentSequenceNumber);
+
+ if(tpsrr == TSmsFirstOctet::ESmsStatusReportNotRequested)
+ {
+ refStatusArray.InsertL(TSmsSegmentationStoreRefStatus(aReference, EStatusComplete));
+ }
+ else if(tpsrr == TSmsFirstOctet::ESmsStatusReportRequested)
+ {
+ refStatusArray.InsertL(aReference);
+ }
+ }
+ else
+ {
+ User::Leave(KErrArgument);
+ }
+
+
+ BeginTransactionLC();
+ ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
+
+ PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray);
+ ChangeEntryL(i,entry);
+ CommitTransactionL();
+
+ //
+ // AEH: moved here because if is done before calling ChangeEntryL
+ // it will pop and destroy the filestore which is also on
+ // the cleanup stack
+ //
+ CleanupStack::PopAndDestroy(2); // smsmessage, refStatus
+
+ return entry.Total()==entry.Count();
+ } // CSmsSegmentationStore::AddReferenceStatusPairL
+
+
+TBool CSmsSegmentationStore::AddStatusReportL(TInt& aIndex,TBool& aComplete,const CSmsMessage& aStatusReport)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL");
+
+ __ASSERT_DEBUG(aStatusReport.Type()==CSmsPDU::ESmsStatusReport,SmspPanic(KSmspPanicNotStatusReport));
+
+ const CSmsStatusReport& statusreport=(CSmsStatusReport&) aStatusReport.SmsPDU();
+ const TInt reference=statusreport.MessageReference();
+ const TInt status=statusreport.Status();
+ const TInt isPerm = IsPermanentStatus(status);
+ const TSmsFirstOctet::TSmsStatusReportQualifier qualifier=statusreport.StatusReportQualifier();
+ TBool found=EFalse;
+ aComplete=EFalse;
+
+ LOGSMSPROT4("CSmsSegmentationStore::AddStatusReportL [ref=%d status=%d IsPerm=%d]", reference, status, isPerm);
+
+ if(!isPerm)
+ {
+ return EFalse;
+ }
+
+ RSmsSegmentationStoreRefStatusArray refStatusArray;
+ CleanupClosePushL(refStatusArray);
+
+ const TInt count1=Entries().Count();
+
+ TSmsAddr smsaddr;
+ CSmsBuffer* buffer=CSmsBuffer::NewL();
+ CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
+ CleanupStack::PushL(smsmessage);
+ TGsmSmsTelNumber parsedaddress;
+ aStatusReport.ParsedToFromAddress(parsedaddress);
+ TSmsSegmentationEntry entry; // TODO const ref and inside loop
+
+ BeginTransactionLC();
+
+ aIndex = count1;
+
+ TInt telLen;
+ while (!found && aIndex--)
+ {
+ entry = (TSmsSegmentationEntry&)Entries()[aIndex];
+
+ // Remove leading zeros of national numbers
+ TPtrC trimmedTelNumber(TrimLeadingZeros(entry.Description2()));
+ TPtrC trimmedParsedTelNumber(TrimLeadingZeros(parsedaddress.iTelNumber));
+
+ telLen=Min(trimmedTelNumber.Length(),trimmedParsedTelNumber.Length());
+
+ const CSmsPDU::TSmsPDUType type = entry.PduType();
+ const TInt startref = entry.Reference1();
+ const TInt stopref = entry.Reference2();
+
+ TBool sameTelNumbers = entry.Description2().Right(telLen) == parsedaddress.iTelNumber.Right(telLen);
+
+ if (sameTelNumbers)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL telNumber from submit report matches that from SMS message");
+ }
+ else
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL telNumber from submit report does NOT match that from SMS message");
+ }
+
+ if (sameTelNumbers &&
+ (((qualifier==TSmsFirstOctet::ESmsStatusReportResultOfCommand) && (type==CSmsPDU::ESmsCommand)) ||
+ ((qualifier==TSmsFirstOctet::ESmsStatusReportResultOfSubmit) && (type==CSmsPDU::ESmsSubmit))) &&
+ (((stopref>=startref) &&(reference>=startref) && (reference<=stopref))||((stopref<startref) &&((reference>=startref) || (reference<=stopref))))
+ )
+ {
+ InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, refStatusArray);
+ TInt refStatusPos = refStatusArray.Find(reference); //assumes Find returns the first matching reference in the array
+ TInt numMessagePDUs=entry.Total();
+
+ if (refStatusPos != KErrNotFound)
+ {
+ const TInt refStatusArrayCount = refStatusArray.Count();
+
+ //Find an element in refStatusArray where Reference() == reference and Status() is not permanent
+ while (!found && refStatusPos < refStatusArrayCount && refStatusArray[refStatusPos].Reference() == reference)
+ {
+ //@note This loop assumes refStatusArray is sorted iReference
+ if (!IsPermanentStatus(refStatusArray[refStatusPos].Status())&&(refStatusArrayCount <= numMessagePDUs))
+ {
+ found = ETrue;
+ }
+ else
+ {
+ LOGSMSPROT4("CSmsSegmentationStore::AddStatusReportL WARNING: Status already perm [status=%d refStatusPos=%d count=%d]", refStatusArray[refStatusPos].Status(), refStatusPos, refStatusArrayCount);
+ refStatusPos++;
+ }
+ }
+
+ if (found)
+ {
+ LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL Found [refStatusPos=%d]", refStatusPos);
+ refStatusArray[refStatusPos].SetStatus(status);
+ TStreamId streamid=entry.DataStreamId();
+ ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
+ PopulateEntry(entry,*smsmessage, refStatusArray);
+ ChangeEntryL(aIndex,entry);
+ aComplete=StatusArrayComplete(refStatusArray, entry);
+ LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL StatusArrayComplete %d", aComplete);
+ }
+ }
+ }
+ }
+
+ if (found && (smsmessage->Type()==CSmsPDU::ESmsCommand)) // look for original submit
+ {
+ TTime time=smsmessage->Time();
+ found=EFalse;
+
+ RSmsSegmentationStoreRefStatusArray refStatusArray2;
+ CleanupClosePushL(refStatusArray2);
+ refStatusArray2.CopyL(refStatusArray);
+ refStatusArray2.ResetAllStatus();
+
+ aComplete=EFalse;
+ TInt telLen;
+ for (aIndex=0; aIndex<count1; aIndex++)
+ {
+ entry = (TSmsSegmentationEntry&)Entries()[aIndex];
+ telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
+ const CSmsPDU::TSmsPDUType type = entry.PduType();
+ if ((type==CSmsPDU::ESmsSubmit) &&
+ entry.IsComplete() &&
+ (entry.Time()==time) &&
+ (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
+ {
+
+ /*
+ TODO ahe - this should take out of the for loop
+ only set/delete flags in the for loop and let the methods:
+ InternalizeXXX
+ ExternalizeXXX
+ PopulateEntry
+ ChangeEntry
+ ... all ... other big CSarStore methods
+ have only to run once -> internal loop in this function through
+ the array of flags
+ */
+
+ found=ETrue;
+ InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, refStatusArray2);
+ const TInt count2 = refStatusArray.Count();
+ __ASSERT_DEBUG(count2 == refStatusArray2.Count(),SmspPanic(KSmspPanicBadReferenceArray));
+ for (TInt i=0; i<count2; i++)
+ {
+ //TODO What is this doing?
+ TSmsSegmentationStoreRefStatus& refStatus2 = refStatusArray2[i];
+ if (!IsPermanentStatus(refStatus2.Status()))
+ {
+ refStatus2.SetStatus(refStatusArray[i].Status());
+ }
+ }
+
+ TStreamId streamid=entry.DataStreamId();
+ ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray2);
+ PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray2);
+ ChangeEntryL(aIndex,entry);
+ aComplete=StatusArrayComplete(refStatusArray2, entry);
+ LOGSMSPROT3("CSmsSegmentationStore::StatusArrayComplete [aStatus=%d, ret=%d]", status, aComplete);
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(&refStatusArray2);
+ }
+
+ CommitTransactionL();
+ CleanupStack::PopAndDestroy(2); // smsmessage, refStatusArray
+
+ LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL Exit [found=%d]", found);
+ return found;
+ } // CSmsSegmentationStore::AddStatusReportL
+
+
+void CSmsSegmentationStore::GetMessageL(TInt aIndex,TSmsAddr& aSmsAddr,CSmsMessage& aSmsMessage, RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
+ {
+ LOGSMSPROT2("CSmsSegmentationStore::GetMessageL [aIndex=%d]", aIndex);
+
+ InternalizeEntryL(Entries()[aIndex].DataStreamId(),aSmsAddr,aSmsMessage, aRefStatusArray);
+ } // CSmsSegmentationStore::GetMessageL
+
+
+/**
+ * internalize the concat refs from the permanent file store to internal memory
+ *
+ * @note You have to call CSARStore::OpenFileLC() before calling this function
+ * and CSARStore::CloseFile() after.
+ */
+void CSmsSegmentationStore::InternalizeConcatenationReferencesL(const TStreamId& aStreamId,TInt& aReference8bit,TInt& aReference16bit)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::InternalizeConcatenationReferencesL Start");
+ RStoreReadStream readstream;
+ readstream.OpenLC(FileStore(),aStreamId);
+ aReference8bit=readstream.ReadInt32L();
+ aReference16bit=readstream.ReadInt32L();
+ CleanupStack::PopAndDestroy();
+ LOGSMSPROT1("CSmsSegmentationStore::InternalizeConcatenationReferencesL End");
+ } // CSmsSegmentationStore::InternalizeConcatenationReferencesL
+
+
+/**
+ * externalize the concat refs from the permanent file store to internal memory
+ *
+ * @note You have to call CSARStore::OpenFileLC() before calling this function
+ * and CSARStore::CloseFile() after.
+ */
+void CSmsSegmentationStore::ExternalizeConcatenationReferencesL(TStreamId& aStreamId,TInt aReference8bit,TInt aReference16bit)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::ExternalizeConcatenationReferencesL Start");
+ RStoreWriteStream writestream;
+ if (aStreamId==KNullStreamId)
+ aStreamId=writestream.CreateLC(FileStore());
+ else
+ writestream.ReplaceLC(FileStore(),aStreamId);
+ writestream.WriteInt32L(aReference8bit);
+ writestream.WriteInt32L(aReference16bit);
+ writestream.CommitL();
+ CleanupStack::PopAndDestroy();
+ LOGSMSPROT1("CSmsSegmentationStore::ExternalizeConcatenationReferencesL End");
+ } // CSmsSegmentationStore::ExternalizeConcatenationReferencesL
+
+
+/**
+ * internalize all the entries from the permanent file store to internal memory
+ *
+ * @note You have to call CSARStore::OpenFileLC() before calling this function
+ * and CSARStore::CloseFile() after.
+ */
+void CSmsSegmentationStore::InternalizeEntryL(const TStreamId& aStreamId,TSmsAddr& aSmsAddr,CSmsMessage& aSmsMessage, RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::InternalizeEntryL Start");
+
+ aRefStatusArray.Reset();
+
+ RStoreReadStream readstream;
+ readstream.OpenLC(FileStore(),aStreamId);
+ readstream >> aSmsAddr;
+ readstream >> aSmsMessage;
+ readstream >> aRefStatusArray;
+ CleanupStack::PopAndDestroy(&readstream);
+
+ LOGSMSPROT2("CSmsSegmentationStore::InternalizeEntryL End [count=%d]", aRefStatusArray.Count());
+ } // CSmsSegmentationStore::InternalizeEntryL
+
+
+/**
+ * externalizes all the entries from the internal memory to the permanent file store
+ */
+void CSmsSegmentationStore::ExternalizeEntryL(TStreamId& aStreamId,const TSmsAddr& aSmsAddr,const CSmsMessage& aSmsMessage, const RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::ExternalizeEntryL Start");
+
+ RStoreWriteStream writestream;
+
+ if (aStreamId==KNullStreamId)
+ aStreamId=writestream.CreateLC(FileStore());
+ else
+ writestream.ReplaceLC(FileStore(),aStreamId);
+
+ writestream << aSmsAddr;
+ writestream << aSmsMessage;
+ writestream << aRefStatusArray;
+ writestream.CommitL();
+ CleanupStack::PopAndDestroy(&writestream);
+
+ LOGSMSPROT2("CSmsSegmentationStore::ExternalizeEntryL End [count=%d]", aRefStatusArray.Count());
+ } // CSmsSegmentationStore::ExternalizeEntryL
+
+
+/**
+ * Populates an SMS message into SAR store entry
+ *
+ * @pre aSmsMessage.EncodeMessagePdusL() has been called
+ *
+ * @param aEntry Entry to be populated to
+ * @param aSmsMessage SMS message to be populated from
+ * @param aReferenceArray Array containing references
+ * @param aStatusArray Array containing status
+ */
+void CSmsSegmentationStore::PopulateEntry(TSmsSegmentationEntry& aEntry,
+ const CSmsMessage& aSmsMessage,
+ const RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::PopulateEntry");
+ TBool statusreportrequest=EFalse;
+ if (aSmsMessage.Type()==CSmsPDU::ESmsSubmit)
+ {
+ aEntry.SetReference(0);
+ aEntry.SetTotal(1);
+ CSmsSubmit& submit=(CSmsSubmit&) aSmsMessage.SmsPDU();
+ aEntry.SetValidityPeriod(submit.ValidityPeriod().Int()); // TODO use val per type
+
+ if (aSmsMessage.Scheme() == EDefaultScheme)
+ {
+ statusreportrequest=((CSmsSubmit&) aSmsMessage.SmsPDU()).StatusReportRequest();
+ }
+ else
+ {
+ statusreportrequest = ETrue;
+ }
+ }
+ else
+ {
+ statusreportrequest=((CSmsCommand&) aSmsMessage.SmsPDU()).StatusReportRequest();
+ }
+
+ if (aSmsMessage.TextPresent())
+ {
+ if (aSmsMessage.SmsPDU().TextConcatenated())
+ {
+ aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
+
+ //
+ // aSmsMessage.EncodeMessagePdusL() must have been called before this point,
+ // otherwise aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs() will return 1.
+ //
+ aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
+ }
+ }
+
+ aEntry.SetLogServerId(aSmsMessage.LogServerId());
+ // Strip out spaces etc from address
+ TGsmSmsTelNumber parsedaddress;
+ aSmsMessage.ParsedToFromAddress(parsedaddress);
+ aEntry.SetDescription2(parsedaddress.iTelNumber);
+ aEntry.SetTime(aSmsMessage.Time());
+
+ const TInt count= aRefStatusArray.Count();
+ __ASSERT_DEBUG((count>=0) && (count<=aEntry.Total()),SmspPanic(KSmspPanicBadReferenceArray));
+ aEntry.SetCount(count);
+ TInt reference1=0xFF;
+ TInt reference2=0x00;
+ TInt startref=reference1;
+ TInt stopref=reference2;
+
+ if(count>0 && statusreportrequest)
+ {
+ startref=aRefStatusArray[0].Reference();
+ stopref=aRefStatusArray[count-1].Reference();
+ }
+
+ TInt delivered=0;
+ TInt failed=0;
+ for (TInt i=0; i<count; i++)
+ {
+ const TSmsSegmentationStoreRefStatus& refStatus = aRefStatusArray[i];
+
+ if (refStatus.Status() == TSmsStatus::ESmsShortMessageReceivedBySME)
+ delivered++;
+ else if (IsPermanentStatus(refStatus.Status()))
+ failed++;
+ }
+
+ //
+ // AEH: Defect fix for EDNPAHN-4WADW3 'Unreliable logging'
+ //
+ // a little hack here to store information about whether
+ // we need Status Report or not, in the TSAREntry. This
+ // is because we want to retrieve it later in PurgeL.
+ // An extra bit is added iData4, LSB of byte 3. See gsmustor.h
+ // for more documentation.
+ //
+ aEntry.SetDeliveredAndFailed(delivered, failed);
+ TBool have_sr = EFalse;
+
+ if (aSmsMessage.Scheme() == EDefaultScheme)
+ {
+ have_sr=((CSmsSubmit&) aSmsMessage.SmsPDU()).StatusReportRequest();
+ }
+ else
+ {
+ have_sr = ETrue;
+ }
+
+ aEntry.SetPduTypeAndRefs(have_sr, aSmsMessage.Type(), startref, stopref);
+ } // CSmsSegmentationStore::PopulateEntry
+
+
+/**
+ * Returns ETrue if the status array is complete
+ *
+ * @param aStatusArray Array containing status
+ * @param aEntry SAR Entry
+ */
+TBool CSmsSegmentationStore::StatusArrayComplete(const RSmsSegmentationStoreRefStatusArray& aRefStatusArray, TSAREntry& aEntry)
+ {
+ TInt permanent=0;
+ const TInt count= aRefStatusArray.Count();
+ for (TInt i=0; i<count; i++)
+ {
+ const TBool ret = IsPermanentStatus(aRefStatusArray[i].Status());
+ LOGSMSPROT4("CSmsSegmentationStore::IsPermanentStatus [Status: %d, RetVal: %d, count=%d]", aRefStatusArray[i].Status(), ret, count);
+ if (ret)
+ permanent++;
+ }
+ /*
+ *
+ * TODO ahe - for release
+ * tested hack: the messagereceived function will be called right
+ * I did a lot of testing with multipart messages, the sms are
+ * almost always received and sent now, there might be only problems
+ * with the SR now - to wait for more logs to see what happens in this
+ * special cases - and the device crashes and is too slow of course
+ *
+ */
+ return (permanent==count) && (permanent==aEntry.Total() );
+ } // CSmsSegmentationStore::StatusArrayComplete
+
+
+ /**
+ * C'tor
+ */
+CSmsSegmentationStore::CSmsSegmentationStore(RFs& aFs)
+ :CSARStore(aFs)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::CSmsSegmentationStore()");
+
+ } // CSmsSegmentationStore::CSmsSegmentationStore
+
+
+TInt CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare(const TSmsSegmentationStoreRefStatus& aLeft, const TSmsSegmentationStoreRefStatus& aRight)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare()");
+
+ return aLeft.iReference - aRight.iReference;
+ } // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare
+
+
+void CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL(RReadStream& aStream)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL()");
+
+ iReference = aStream.ReadInt32L();
+ iStatus = aStream.ReadInt32L();
+ } // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL
+
+
+void CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL(RWriteStream& aStream) const
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL()");
+
+ aStream.WriteInt32L(iReference);
+ aStream.WriteInt32L(iStatus);
+ } // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL
+
+
+void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL(const TSmsSegmentationStoreRefStatus& aRefStatus)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL()");
+
+ TLinearOrder<TSmsSegmentationStoreRefStatus> order(TSmsSegmentationStoreRefStatus::Compare);
+ User::LeaveIfError(InsertInOrderAllowRepeats(aRefStatus, order));
+ } // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL
+
+
+TInt CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find(const TSmsSegmentationStoreRefStatus& aRefStatus) const
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find()");
+
+ TLinearOrder<TSmsSegmentationStoreRefStatus> order(TSmsSegmentationStoreRefStatus::Compare);
+ TInt index = FindInOrder(aRefStatus, order);
+ if (index != KErrNotFound)
+ {
+ //The function is to return the first occurence. However FindInOrder()
+ //uses a binary search algorithm and does not guarantee to return the 1st item if there are duplicate items.
+ //Therefore we manually check for duplicates to the left of the found item.
+ while (index > 0 && (operator[](index-1).Reference() == aRefStatus.Reference()))
+ {
+ --index;
+ }
+ }
+ return index;
+ } // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find
+
+
+void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL(const RSmsSegmentationStoreRefStatusArray& aOther)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL()");
+
+ Reset();
+
+ TInt count = aOther.Count();
+ while (count--)
+ {
+ InsertL(aOther[count]);
+ }
+ } // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL
+
+
+void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus(TInt aStatus)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus()");
+
+ TInt count = Count();
+ while (count--)
+ {
+ (*this)[count].SetStatus(aStatus);
+ }
+ } // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus
+
+
+void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL(RReadStream& aStream)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL()");
+
+ TInt count = aStream.ReadInt32L();
+ while (count--)
+ {
+ TSmsSegmentationStoreRefStatus refStatus;
+ aStream >> refStatus;
+ InsertL(refStatus); //maintain order
+ }
+ } // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL
+
+
+void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL(RWriteStream& aStream) const
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL()");
+
+ const TInt count = Count();
+ aStream.WriteInt32L(count);
+
+ for (TInt i = 0; i < count; i++)
+ {
+ aStream << (*this)[i];
+ }
+ } // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL
+
+
+TBool CSmsSegmentationStore::HasEntryWithLogIdL(TLogId aLogID,TInt& aRefNo,TInt& aSent)
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::HasEntryWithLogIdL()");
+
+ TInt count=Entries().Count();
+ TBool found=EFalse;
+ if(aLogID != KLogNullId)
+ {
+ TInt total;
+ TInt sent;
+ BeginTransactionLC();
+ for (TInt i=count-1; i>=0; --i)
+ {
+ if (aLogID==Entries()[i].LogServerId())
+ {
+ const TSAREntry& entry=Entries()[i];
+ total=entry.Total();
+ sent=entry.Count();
+ if( sent < total)
+ {
+ aSent=sent;
+ aRefNo=entry.Reference();
+ found=ETrue;
+ }
+ else
+ {
+ DeleteEntryL(i);
+ LOGSMSPROT3("CSmsSegmentationStore::HasEntryWithLogIdL [Entry: %d LogId %d - deleted]", i, aLogID );
+ }
+ break;
+ }
+ }
+ CommitTransactionL();
+ }
+ return found;
+} // CSmsSegmentationStore::HasEntryWithLogIdL
+
+
+/**
+ * Open the sms segmentation store.
+ */
+void CSmsSegmentationStore::OpenStoreL()
+ {
+ LOGSMSPROT1("CSmsSegmentationStore::OpenStoreL()");
+
+ this->OpenL(iFullPathBuf,KSegmentationStoreUid);
+ } // CSmsSegmentationStore::OpenStoreL