diff -r 6b1d113cdff3 -r 6638e7f4bd8f smsprotocols/smsstack/smsprot/Src/smspclass0stor.cpp --- a/smsprotocols/smsstack/smsprot/Src/smspclass0stor.cpp Mon May 03 13:37:20 2010 +0300 +++ b/smsprotocols/smsstack/smsprot/Src/smspclass0stor.cpp Thu May 06 15:10:38 2010 +0100 @@ -1,3561 +1,3561 @@ -// Copyright (c) 2007-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 CPreallocatedFile. -// -// - -/** - @file -*/ -#include "smspclass0stor.h" -#include "gsmubuf.h" -#include "gsmunonieoperations.h" - -const TInt KSizeOfPreallocatedFileVersion = sizeof(CPreallocatedFile::TPreAllocatedFileVersion); -const TInt KSizeOfNumberOfEntrySection = sizeof(TInt); -//size of 32-bit checksum -const TInt KSizeOfChecksum = sizeof(TUint32); -const TInt KSizeOfPreAllocatedStoreEntry = sizeof(TSmsPreAllocatedFileStoreReassemblyEntry); -const TInt KSizeOfGsmSmsSlotEntry = sizeof(TGsmSmsSlotEntry); -const TInt KSizeOfIndexEntry = sizeof(TInt); -const TInt KSizeOfSmsGsmPDU = sizeof(RMobileSmsMessaging::TMobileSmsGsmTpdu); -const TInt KSizeOfAContainer = KSizeOfGsmSmsSlotEntry + KSizeOfIndexEntry + KSizeOfSmsGsmPDU; -const TInt KBeginOfMasterHeaderSection = KSizeOfPreallocatedFileVersion; - -/** -Static factory constructor. Uses two phase -construction and leaves nothing on the CleanupStack. - -@param aFs File Server handle. -@param aFileName Permanent file store name. -@param aThirdUid Uid of file. -@leave KErrNoMemory - -@return A pointer to the newly created CSmsPermanentFileStore object. - -@pre A connected file server session must be passed as parameter. -@post CSmsPermanentFileStore object is now fully initialised - -@internalComponent -*/ -CSmsPermanentFileStore* CSmsPermanentFileStore::NewL(RFs& aFs, const TDesC& aFileName, const TUid& aThirdUid) - { - LOGSMSPROT1("CSmsPermanentFileStore::NewL()"); - CSmsPermanentFileStore* self = new (ELeave) CSmsPermanentFileStore(aFs, aThirdUid); - CleanupStack::PushL(self); - self->ConstructL(aFileName); - CleanupStack::Pop(self); - - return self; - } - -void CSmsPermanentFileStore::ConstructL(const TDesC& aFileName) - { - LOGSMSPROT1("CSmsPermanentFileStore::ConstructL()"); - iFileName = aFileName.AllocL(); - } - -/** - * Constructor. -*/ -CSmsPermanentFileStore::CSmsPermanentFileStore(RFs& aFs, const TUid& aThirdUid) - : iFs(aFs), iFileName(NULL), iThirdUid(aThirdUid), iFileStore(NULL), iEntryArray(KFlatArrayGranularity) - { - } - -/** - * Destructor. It destroys all the member variables. -*/ -CSmsPermanentFileStore::~CSmsPermanentFileStore() - { - delete iFileName; - } - -/** -It checks & returns whether the file exist or not. If file is there whether -it is corrupted or not. - -@internalComponent -*/ -TBool CSmsPermanentFileStore::IsFileOK() - { - TBool retBool(EFalse); - TUidType uidtype(KPermanentFileStoreLayoutUid,KSARStoreUid,iThirdUid); - TEntry entry; - TInt ret=iFs.Entry(iFileName->Des(), entry); - // Check file existence & corruption - if ((ret == KErrNone) && (entry.iType == uidtype)) - { - retBool = ETrue; - } - return retBool; - } - -/** -It creates a permanent store file. - -@internalComponent -*/ -void CSmsPermanentFileStore::CreateL() - { - LOGSMSPROT1("CSmsPermanentFileStore::CreateL()"); - TUidType uidtype(KPermanentFileStoreLayoutUid,KSARStoreUid,iThirdUid); - iFileStore=CPermanentFileStore::ReplaceL(iFs, iFileName->Des(), EFileShareExclusive|EFileStream|EFileRead|EFileWrite); - iFileStore->SetTypeL(uidtype); - iEntryArray.Reset(); - ExternalizeEntryArrayL(); - iFileStore->CommitL(); - // Close it to make sure that file is created correctly (defensive approach). - Close(); - //Again Open the file - OpenL(); - } - -/** -It opens the permanent store file and internalizes the entries. - -@internalComponent -*/ -void CSmsPermanentFileStore::OpenL() - { - LOGSMSPROT1("CSmsPermanentFileStore::OpenL()"); - iFileStore=CPermanentFileStore::OpenL(iFs,iFileName->Des(),EFileShareExclusive|EFileStream|EFileRead|EFileWrite); - InternalizeEntryArrayL(); - } - -/** -It closes the permanent store file. - -@internalComponent -*/ -void CSmsPermanentFileStore::Close() - { - LOGSMSPROT1("CSmsPermanentFileStore::Close()"); - delete iFileStore; - iFileStore = NULL; - iEntryArray.Reset(); - } - -/* -This function cleans its entries against the passed entries. -This is needed because there might be a scenario where user has deleted a message -but the corresponding message is not deleted from permanent store file -due to out-of-disk condition. But the entry is invalid because -it is no more in the pre-allocated file which contains master header info. -And also at the time of forwarding an incomplete message a forwarded -message has not been deleted due to above reason. -This function also compacts the store after deletion. - -@param aEntryArray entray array against whose clean up is carried out. - -@internalComponent -*/ -void CSmsPermanentFileStore::CleanupEntriesWithCompactL(const CArrayFix& aEntryArray) - { - // Ignore in code coverage - a previous CleanupEntries would need to have failed with KErrDiskFull - BULLSEYE_OFF - LOGSMSPROT1("CSmsPermanentFileStore::CleanupEntriesWithCompactL()"); - - iCompact = ETrue; - CleanupEntriesL(aEntryArray); - BULLSEYE_RESTORE - } - -/* -This function cleans its entries against the passed entries. -This is needed because there migth be a scenario where user has deleted a message -but the corresponding message is not deleted from permanent store file -due to out-of-disk condition. But the entry is invalid because -it is no more in the pre-allocated file which contains master header info. -And also at the time of forwarding an incomplete message a forwarded -message has not been deleted due to above reason. - -@param aEntryArray entray array against whose clean up is carried out. - -@internalComponent -*/ -void CSmsPermanentFileStore::CleanupEntriesL(const CArrayFix& aEntryArray) - { - LOGSMSPROT1("CSmsPermanentFileStore::CleanupEntriesL()"); - - TInt reassemblyCount = iEntryArray.Count(); - TInt index, index2; - - for (index = 0; index < reassemblyCount; index++) - { - for (index2 = 0; index2 < aEntryArray.Count(); index2++) - { - if (iEntryArray[index].Reference() == aEntryArray[index2].Reference() && - iEntryArray[index].Total() == aEntryArray[index2].Total() && - iEntryArray[index].PduType() == aEntryArray[index2].PduType() && - iEntryArray[index].Storage() == aEntryArray[index2].Storage() && - iEntryArray[index].Description2() == aEntryArray[index2].Description2()) - { - if (aEntryArray[index2].NumberOfPDUsForwardToClient() > 0) - { - //Internalize the entries. - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); - CleanupStack::PushL(smsMessage); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - InternalizeEntryL(index, *smsMessage, *indexArray, *smsArray); - TInt noOfForwardedEntries = 0; - for (TInt j=indexArray->Count(); j>0 ;j--) - { - TUint8 bitMapIndex = (indexArray->At(j-1)-1)/8; - TUint8 bitPos = (indexArray->At(j-1)-1)%8; - TUint8 bitMap; - TSmsPreAllocatedFileStoreReassemblyEntry entry; - entry = aEntryArray[index2]; - entry.GetBitMap(bitMapIndex, bitMap); - TUint8 tmpBitMap = 1; - tmpBitMap <<= bitPos; - if (tmpBitMap == (bitMap & tmpBitMap)) - { - noOfForwardedEntries++; - indexArray->Delete(j-1); - smsArray->Delete(j-1); - } - } - if (noOfForwardedEntries > 0) - { - TStreamId streamId = iEntryArray[index].DataStreamId(); - ExternalizeEntryL(streamId, *smsMessage, *indexArray, *smsArray); - } - CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray - } - break; - } - } - if (index2 == aEntryArray.Count()) - { - DeleteEntryL(index); - } - } - } - -/** -It internalizes its entry array. - -@internalComponent -*/ -void CSmsPermanentFileStore::InternalizeEntryArrayL() - { - LOGSMSPROT1("CSmsPermanentFileStore::InternalizeEntryArrayL()"); - - iEntryArray.Reset(); - TStreamId headerid=iFileStore->Root(); - RStoreReadStream stream; - stream.OpenLC(*iFileStore,headerid); - TInt count=stream.ReadInt32L(); - for (TInt i=0; i> sarentry; - iEntryArray.AppendL(sarentry); - } - CleanupStack::PopAndDestroy(); // stream - } - -/** -It externalizes its entry array. - -@internalComponent -*/ -void CSmsPermanentFileStore::ExternalizeEntryArrayL() - { - LOGSMSPROT4("CSmsPermanentFileStore::ExternalizeEntryArrayL(): this=0x%08X count=%d headerid=%d]", - this, iEntryArray.Count(), iFileStore->Root().Value()); - - TStreamId headerid=iFileStore->Root(); - RStoreWriteStream stream; - if (headerid==KNullStreamId) - { - headerid=stream.CreateLC(*iFileStore); - iFileStore->SetRootL(headerid); - } - else - { - stream.ReplaceLC(*iFileStore,headerid); - } - - TInt count1=iEntryArray.Count(); - TInt count2=0; - TInt i=0; - - for (; i* indexArray=new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray=new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - //Index must initialize to 0. - TInt index = 0; - if (!aSmsMessage.IsDecoded()) - { - index = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex(); - } - indexArray->AppendL(index); - smsArray->AppendL(aGsmSms); - - TStreamId streamid = KNullStreamId; - ExternalizeEntryL(streamid, aSmsMessage, *indexArray, *smsArray); - - TSmsReassemblyEntry tmpEntry; - //Fill-up entry information... - CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1); - // Update Data stream id. - tmpEntry.SetDataStreamId(streamid); - - aIndex = iEntryArray.Count(); - AddEntryL(tmpEntry); - CleanupStack::PopAndDestroy(2); //indexArray, smsArray - } - -/* -It updates the existing message in permanent store file. - -@param aIndex index number on which message is to be updated. -@param aSmsMessage reference to sms message to be updated. -@param aIndexArray array of index of all the PDUs. -@param aSmsArray array of sms of all the PDUs. - -@internalComponent -*/ -void CSmsPermanentFileStore::UpdateExistingMessageL(TInt aIndex, const CSmsMessage& aSmsMessage,const CArrayFix& aIndexArray,const CArrayFix& aSmsArray) - { - LOGSMSPROT1("CSmsPermanentFileStore::UpdateExistingMessageL()"); - TStreamId streamid = iEntryArray[aIndex].DataStreamId(); - ExternalizeEntryL(streamid, aSmsMessage, aIndexArray, aSmsArray); - TSmsReassemblyEntry entry; - CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, aSmsArray.Count()); - entry.SetDataStreamId(streamid); - ChangeEntryL(aIndex, entry); - } - -/* -It matches the entry with entry in permanent store file & returns -the index. If not found it returns KErrNotFound. - -@param aEntry reference to entry information. -@param aIndex (output) returns the index number. - -@internalComponent -*/ -void CSmsPermanentFileStore::MatchEntryToExistingMessage(const TReassemblyEntry& aEntry, - TInt& aIndex) - { - LOGSMSPROT1("CSmsPermanentFileStore::MatchEntryToExistingMessage()"); - - aIndex = KErrNotFound; - - // - // Search the reassembly store for a matching entry... - // - TInt reassemblyCount = iEntryArray.Count(); - for (TInt index = 0; index < reassemblyCount; index++) - { - TSmsReassemblyEntry& entry = iEntryArray[index]; - - if (entry.Reference() == aEntry.Reference() && - entry.Total() == aEntry.Total() && - entry.PduType() == aEntry.PduType() && - entry.Storage() == aEntry.Storage() && - entry.Description2() == aEntry.Description2()) - { - // - // Found it! - // - aIndex = index; - break; - } - } - - LOGSMSPROT2("CSmsPermanentFileStore::MatchEntryToExistingMessage(): aIndex=%d", aIndex); - } - -/* -It updates the log server id of the message. - -@param aIndex index number of the message to be updated. -@param aLogServerId log server id. - -@internalComponent -*/ -void CSmsPermanentFileStore::UpdateLogServerIdL(TInt& aIndex, TLogId aLogServerId) - { - LOGSMSPROT1("CSmsPermanentFileStore::UpdateLogServerIdL"); - - TSmsReassemblyEntry entry; - entry = iEntryArray[aIndex]; - - if (entry.LogServerId() != aLogServerId) - { - entry.SetLogServerId(aLogServerId); - ChangeEntryL(aIndex, entry); - } - } - -/* -It sets the message passed to client or not. - -@param aIndex index number of the message to be updated. -@param aBool boolean value indicating whether message is passes or not. - -@internalComponent -*/ -void CSmsPermanentFileStore::SetPassedToClientL(TInt aIndex, TBool aBool) - { - LOGSMSPROT2("CSmsPermanentFileStore::SetPassedToClientL(): aIndex=%d", aIndex); - - TSmsReassemblyEntry entry; - entry = iEntryArray[aIndex]; - - if (entry.PassedToClient() != aBool) - { - entry.SetPassedToClient(aBool); - ChangeEntryL(aIndex, entry); - } - } - -/* -It adds the new entry in the existing entry array. - -@param aEntry entry to be added. - -@internalComponent -*/ -void CSmsPermanentFileStore::AddEntryL(TSmsReassemblyEntry& aEntry) - { - iEntryArray.AppendL(aEntry); - iEntryArray[iEntryArray.Count()-1].SetIsAdded(ETrue); - } - -/* -It changes the existing entry with new entry. - -@param aIndex index number of the entry which will be changed. -@param aNewEntry entry to be updated. - -@internalComponent -*/ -void CSmsPermanentFileStore::ChangeEntryL(TInt aIndex,const TSmsReassemblyEntry& aNewEntry) - { - LOGSMSPROT2("CSmsPermanentFileStore::ChangeEntryL(): aIndex=%d", aIndex); - - iEntryArray[aIndex].SetIsDeleted(ETrue); - iEntryArray.InsertL(aIndex,aNewEntry); - iEntryArray[aIndex].SetIsAdded(ETrue); - } - -/* -It deletes the entry. - -@param aIndex index number of the entry which will be deleted. - -@internalComponent -*/ -void CSmsPermanentFileStore::DeleteEntryL(TInt aIndex) - { - iFileStore->DeleteL(iEntryArray[aIndex].DataStreamId()); - iEntryArray[aIndex].SetIsDeleted(ETrue); - } - -/* -It externalizes(writes) the entry in permanent store file. - -@param aStreamId stream id which needs to externalized. -@param aSmsMessage reference to sms message which needs to be externalized. -@param aIndexArray refence to array of index which needs to be externalized. -@param aSmsArray refence to array of sms which needs to be externalized. - -@internalComponent -*/ -void CSmsPermanentFileStore::ExternalizeEntryL(TStreamId& aStreamId,const CSmsMessage& aSmsMessage,const CArrayFix& aIndexArray,const CArrayFix& aSmsArray) - { - LOGSMSPROT2("CSmsPermanentFileStore::ExternalizeEntryL Start [sid=%d]", aStreamId.Value()); - - RStoreWriteStream writestream; - if (aStreamId==KNullStreamId) - aStreamId=writestream.CreateLC(*iFileStore); - else - writestream.ReplaceLC(*iFileStore,aStreamId); - writestream << aSmsMessage; - TInt count=aIndexArray.Count(); - writestream.WriteInt32L(count); - TInt i=0; - for (; i& aIndexArray, CArrayFix& aSmsArray) - { - TSmsReassemblyEntry& entry = iEntryArray[aIndex]; - LOGSMSPROT2("CSmsPermanentFileStore::InternalizeEntryL Start [sid=%d]", entry.DataStreamId().Value()); - RStoreReadStream readstream; - readstream.OpenLC(*iFileStore, entry.DataStreamId()); - readstream >> aSmsMessage; - TInt count=readstream.ReadInt32L(); - TInt i; - for (i=0; i> pdu; - TGsmSms sms; - sms.SetPdu(pdu); - aSmsArray.AppendL(sms); - } - CleanupStack::PopAndDestroy(); - //Set other properties of CSmsMessage - aSmsMessage.SetStorage(entry.Storage()); - aSmsMessage.SetLogServerId(entry.LogServerId()); - aSmsMessage.SetTime(entry.Time()); - LOGSMSPROT2("CSmsPermanentFileStore::InternalizeEntryL End [count=%d]", count); - } - -/* -It removes the PDUs from permanent store file. -This function is needed because after forwarding the incomplete message -to client, the corresponding PDUs needs to be be removed from permanent -store file. -This functionality is specific to class 0 re-assembly store. - -@param aIndex index number of the message to be removed. -@param aStartPos starting pos of pdu to be removed. -@param aEndPos end pos of pdu to be removed. - -@internalComponent -*/ -void CSmsPermanentFileStore::RemovePDUsL(TInt aIndex, TInt aStartPos, TInt aEndPos) - { - LOGSMSPROT1("CSmsPermanentFileStore::RemovePDUsL"); - - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); - CleanupStack::PushL(smsMessage); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - InternalizeEntryL(aIndex, *smsMessage, *indexArray, *smsArray); - - TInt count = indexArray->Count(); - for (TInt i=count; i>0; i--) - { - if ((indexArray->At(i-1) >= aStartPos) && (indexArray->At(i-1) <= aEndPos)) - { - indexArray->Delete(i-1); - smsArray->Delete(i-1); - } - } - - /* - There are 3 scenarios in this case: - 1. If all the entries are removed, - then there is no need to store the entry in this permanent file. - 2. If few entries are removed, - then externalize the remaining entries. Update count field also. - 3. If no entries are removed, then do nothing. - */ - if (indexArray->Count()==0) - { - DeleteEntryL(aIndex); - } - else if (count!=indexArray->Count()) - { - TStreamId streamid = iEntryArray[aIndex].DataStreamId(); - ExternalizeEntryL(streamid, *smsMessage, *indexArray, *smsArray); - - TSmsReassemblyEntry entry; - entry = iEntryArray[aIndex]; - entry.SetCount(indexArray->Count()); - ChangeEntryL(aIndex, entry); - } - CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray - } - -/** - * Sets the permanent store as in-transaction. - * - * The function checks the validity of the call and leaves KErrAccessDenied if - * invalid. - * @capability None - */ -void CSmsPermanentFileStore::BeginTransactionL() - { - LOGSMSPROT4("CSmsPermanentFileStore::BeginTransactionL [this=0x%08X iInTransaction=%d iFileStore=0x%08X]", this, iInTransaction, iFileStore); - - if (iFileStore == NULL || iInTransaction) - { - LOGSMSPROT1("WARNING CSmsPermanentFileStore::BeginTransactionL leaving with KErrAccessDenied"); - User::Leave(KErrAccessDenied); - } - - iInTransaction = ETrue; - } // CSmsPermanentFileStore::BeginTransactionL - -/** - * It reverts the transaction. - */ -void CSmsPermanentFileStore::Revert() - { - LOGSMSPROT3("CSmsPermanentFileStore::Revert(): this=0x%08X, iInTransaction=%d", - this, iInTransaction); - - iFileStore->Revert(); - iInTransaction = EFalse; - ReinstateDeletedEntries(); - } // CSmsPermanentFileStore::Revert - -/** - * It commits the transaction. Then it compact the permanent store file. - */ -void CSmsPermanentFileStore::DoCommitAndCompactL() - { - LOGSMSPROT1("CSmsPermanentFileStore::DoCommitAndCompactL()"); - - LOGSMSPROTTIMESTAMP(); - iFileStore->CommitL(); - LOGSMSPROTTIMESTAMP(); - - iCommitCount--; - if ((iCommitCount < 0) || (iCompact)) - { - iCommitCount = KNumStoreCommitsBeforeCompaction; - iFileStore->CompactL(); - iFileStore->CommitL(); - iCompact = EFalse; - } - } // CSmsPermanentFileStore::DoCommitAndCompactL - -/** - * It commits the transaction. - */ -void CSmsPermanentFileStore::CommitTransactionL() - { - LOGSMSPROT4("CSmsPermanentFileStore::CommitTransactionL(): this=0x%08X iInTransaction=%d iFileStore=0x%08X", - this, iInTransaction, iFileStore); - - ExternalizeEntryArrayL(); - -#ifdef _SMS_LOGGING_ENABLED - TRAPD(err, DoCommitAndCompactL()); - if (err != KErrNone) - { - LOGGSMU2("WARNING! could not CommitL/CompactL due to %d", err); - User::Leave(err); - } -#else - DoCommitAndCompactL(); -#endif - - iInTransaction = EFalse; - RemoveDeletedEntries(); - } - -/** - * It removes the deleted entries from entry arry. - * This function is called after commit. - */ -void CSmsPermanentFileStore::RemoveDeletedEntries() - { - LOGSMSPROT1("CSmsPermanentFileStore::RemoveDeletedEntries()"); - - TInt count=iEntryArray.Count(); - while (count--) - { - TSmsReassemblyEntry& entry = iEntryArray[count]; - - if (entry.IsDeleted()) - { - iEntryArray.Delete(count); - } - else - { - entry.SetIsAdded(EFalse); - } - } - } // CSmsPermanentFileStore::RemoveDeletedEntries - -/** - * It reinstate the deleted/added entries from entry arry. - * This function is called after revert operation. - */ -void CSmsPermanentFileStore::ReinstateDeletedEntries() - { - LOGSMSPROT1("CSmsPermanentFileStore::ReinstateDeletedEntries()"); - - TInt count=iEntryArray.Count(); - while (count--) - { - TSmsReassemblyEntry& entry = iEntryArray[count]; - - if (entry.IsAdded()) - { - iEntryArray.Delete(count); - } - else - { - entry.SetIsDeleted(EFalse); - } - } - } // CSmsPermanentFileStore::ReinstateDeletedEntries - -/** - * Constructor - * - * @capability None - */ -TSmsPreAllocatedFileStoreReassemblyEntry::TSmsPreAllocatedFileStoreReassemblyEntry(): - TSmsReassemblyEntry(), - iPreAllocatedStorageId(0), - iStatus(RMobileSmsStore::EStoredMessageUnknownStatus), - iTimeOffset(0), - iDecodedOnSim(EFalse), - iForwardToClient(EFalse), - iForwardedCount(0), - iBitMap(NULL) - { - //Have to externalize so initialize to 0. - for (TInt i=0; iConstructL(aFileName); - CleanupStack::Pop(self); - - return self; - } - -void CPreallocatedFile::ConstructL(const TDesC& aFileName) - { - LOGSMSPROT1("CPreallocatedFile::ConstructL()"); - iFileName = aFileName.AllocL(); - } - -/** - * Constructor. -*/ -CPreallocatedFile::CPreallocatedFile(RFs& aFs, TInt aMaxClass0Msg, TInt aMaxPDUSeg, TPreAllocatedFileVersion aVersion) - :iFs(aFs), iEntryArray(KFlatArrayGranularity), iReinstateEntryInfo(KFlatArrayGranularity), iMaxClass0Msg(aMaxClass0Msg), iMaxPDUSeg(aMaxPDUSeg), iVersion(aVersion) - { - /* - Format of File: - Version Number, Header Section & Data Section - Version Number - Interger Value. - Header Section: Number of entries, Array of Entries, Array of PDU identifier section, Checksum. - Data Section: Array of Container. Each container contains Sms slot informatiuon, index number & PDU. - */ - - // Calculate the size of each section. - - // Entry section will always contain one more entry than configured one by the user. - // Because it will provide one extra slot to store the new message for time being - // before forwarding the oldest message. - iSizeOfEntrySection = (KSizeOfPreAllocatedStoreEntry * (iMaxClass0Msg + 1)); - - iSizeOfStorageIdentifierSection = ((sizeof(TInt))*(iMaxPDUSeg+1)); - - TInt sizeOfHeaderSection = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + KSizeOfChecksum; - - TInt sizeOfDataSection = KSizeOfAContainer * (iMaxPDUSeg+1); - - // Calculate the size of File. - iSizeOfFile = KSizeOfPreallocatedFileVersion + 2 * sizeOfHeaderSection + sizeOfDataSection; - - iBeginOfDuplicateHeaderSection = KSizeOfPreallocatedFileVersion + sizeOfHeaderSection; - iBeginOfDataSection = KSizeOfPreallocatedFileVersion + 2 * sizeOfHeaderSection; - } - -/** - * Destructor. It destroys all the member variables. -*/ -CPreallocatedFile::~CPreallocatedFile() - { - delete iFileName; - } - -/** -It checks & returns whether the file exist or not. If file is there whether -it is corrupted or not. - -@internalComponent -*/ -TBool CPreallocatedFile::IsFileOK() - { - LOGSMSPROT1("CPreallocatedFile::IsFileOK()"); - - TEntry entry; - // Check file exists - TInt ret=iFs.Entry(iFileName->Des(), entry); - // Check the size of file, if size does not match then assume that file - // is corrupted, then return KErrNotFound. - if ((ret == KErrNone) && (entry.iSize != iSizeOfFile)) - { - ret = KErrNotFound; - } - - if (ret == KErrNone) - { - return ETrue; - } - else - { - return EFalse; - } - } - -/** -It creates a pre-allocated file. - -@internalComponent -*/ -void CPreallocatedFile::CreateL() - { - LOGSMSPROT1("CPreallocatedFile::CreateL"); - - User::LeaveIfError(iFile.Replace(iFs, iFileName->Des(), EFileWrite)); - User::LeaveIfError(iFile.SetSize(iSizeOfFile)); - iFile.Flush(); - - // Externalize Version Number - //TInt version = iVersion; - TPtr8 memPtr((TUint8*) &iVersion, KSizeOfPreallocatedFileVersion, KSizeOfPreallocatedFileVersion); - iFile.Write(0, memPtr); - - //Externalize Header Information - ExternalizeEntryArray(); - - // Initialize Storage Identifier Section. - TInt storageIdentifier=0; - memPtr.Set((TUint8*) &storageIdentifier, sizeof(storageIdentifier), sizeof(storageIdentifier)); - TInt pos = KSizeOfNumberOfEntrySection + iSizeOfEntrySection; - TInt pos2 = 0; - for (TInt count=0; countDes(), EFileShareExclusive|EFileRead|EFileWrite)); - // Check the validity of the data. - CheckDataL(); - // Internalize data - InternalizeEntryArrayL(); - } - -/** -It closes the pre-allocated file. - -@internalComponent -*/ -void CPreallocatedFile::Close() - { - iFile.Close(); - iEntryArray.Reset(); - iReinstateEntryInfo.Reset(); - } - -/** -It internalizes the entry info from pre-allocated file. - -@internalComponent -*/ -void CPreallocatedFile::InternalizeEntryArrayL() - { - iEntryArray.Reset(); - TInt numberOfMessage; - TPtr8 memPtr((TUint8*) &numberOfMessage, sizeof(numberOfMessage), sizeof(numberOfMessage)); - iFile.Read(KBeginOfMasterHeaderSection, memPtr); - - TSmsPreAllocatedFileStoreReassemblyEntry tmpClass0ReassemblyStore; - memPtr.Set((TUint8*) &tmpClass0ReassemblyStore, KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry); - - TInt pos = 0; - for (TInt count=0; count < numberOfMessage; count++) - { - pos = sizeof(TInt) + (count * KSizeOfPreAllocatedStoreEntry); - iFile.Read(KBeginOfMasterHeaderSection + pos, memPtr); - iEntryArray.AppendL(tmpClass0ReassemblyStore); - } - } - -/** -It externalizes the entry info to pre-allocated file. - -@internalComponent -*/ -void CPreallocatedFile::ExternalizeEntryArray() - { - TInt count=iEntryArray.Count(); - TInt numberOfMessage=0; - TInt i=0; - - for (; i= aNumberOfPDUs) - { - break; - } - } - iFile.Flush(); - } - -/* -It updates the storage identifier section. It updates the corresponding container -in the storage identifier section specifying the PDU where it is stored. - -NOTE: - It keeps the record of added entries in iReinstateEntryInfo variable. - It will be required in case of revert operation. - After commiting the transaction, this varaible should be re-initialized. - -@param aIndex index number of the container where PDU has been stored.. -@param aStorageId unique id of added message. - -@internalComponent -*/ -void CPreallocatedFile::AddStorageIdL(TInt aIndex, TInt aStorageId) - { - //Put storage id in master header section - TPtr8 memPtr((TUint8*) &aStorageId, sizeof(aStorageId), sizeof(aStorageId)); - TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; - iFile.Write( beginOfStorageIdentifierSection + ((aIndex - 1) * sizeof(TInt)), memPtr); - - TReinstateEntryInfo entry; - entry.iContainerId=aIndex; - entry.iPreAllocatedStorageId=aStorageId; - entry.iFlag=EEntryIsAdded; - iReinstateEntryInfo.AppendL(entry); - } - -/* -It returns the next free available free container where next PDU can be stored. - -It goes through storage identifier section, it reads the conents of all storage -identfier & return that container which is free. -All the free container is identifiable by value 0. If the value is not 0 then it -contains the storage id of a particular message. - -@internalComponent -*/ -TInt CPreallocatedFile::GetFreeContainer() - { - // Get the next free slot. - TInt storageId; - TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); - TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; - TInt beginOfStorageId = 0; - TInt count; - - for (count=0; count& aIndexArray, CArrayFix& aSmsArray) - { - LOGSMSPROT1("CPreallocatedFile::InternalizeEntryL"); - TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[aIndex]; - //Set other properties of CSmsMessage - aSmsMessage.SetStorage(entry.Storage()); - aSmsMessage.SetStatus((NMobileSmsStore::TMobileSmsStoreStatus)entry.Status()); - aSmsMessage.SetLogServerId(entry.LogServerId()); - aSmsMessage.SetTime(entry.Time()); - aSmsMessage.SetUTCOffset(entry.UTCOffset()); - aSmsMessage.SetDecodedOnSIM(entry.DecodedOnSIM()); - aSmsMessage.SetForwardToClient(entry.ForwardToClient()); - aSmsMessage.SetToFromAddressL(entry.Description2()); - - LOGSMSPROT2("CPreallocatedFile::InternalizeEntryL Start [sid=%d]", entry.PreAllocatedStorageId()); - if (entry.PreAllocatedStorageId()==KErrNotFound) - { - return; - } - - TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; - //This will be used to read the storgae id which will indicate - //that corresponding container contains actual PDU - TInt storageId=0; - TPtr8 memPtr1((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); - - TInt storageIdPos = 0; - TInt dataPos = 0; - //This will be used to read the slot information - TGsmSmsSlotEntry smsSlotEntry; - TPtr8 memPtr2((TUint8*) &smsSlotEntry, KSizeOfGsmSmsSlotEntry, KSizeOfGsmSmsSlotEntry); - //This will be used to read the concatenated PDU index. - TInt index=0; - TPtr8 memPtr3((TUint8*) &index, sizeof(index), sizeof(index)); - //This will be used to read PDU. - RMobileSmsMessaging::TMobileSmsGsmTpdu pdu; - TPtr8 memPtr4((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU); - TGsmSms sms; - - //Number of PDUs stored in this pre-allocated file - TInt noOfPDUs = iEntryArray[aIndex].Count(); - //Will indicate how many number of PDUs already read from pre-allocated file. - TInt noOfPDUsRead = 0; - // Can also get the number of pdu stored in pre-allocated file from count's variable. - for (TInt count=0; count 256) || (aStartPos > aEndPos)) - { - User::Leave(KErrArgument); - } - - LOGSMSPROT2("CPreallocatedFile::RemovePDUsL Start [sid=%d]", iEntryArray[aIndex].PreAllocatedStorageId()); - if (iEntryArray[aIndex].PreAllocatedStorageId()==KErrNotFound) - { - return; - } - - TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; - //This will be used to read the storgae id which will indicate - //that corresponding container contains actual PDU - TInt storageId=0; - TPtr8 memPtr1((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); - - //This will be used to cleanup the storage id. - TInt cleanStorageId=0; - TPtr8 memPtr2((TUint8*) &cleanStorageId, sizeof(cleanStorageId), sizeof(cleanStorageId)); - - //This will be used to read the concatenated PDU index. - TInt index=0; - TPtr8 memPtr3((TUint8*) &index, sizeof(index), sizeof(index)); - - //Number of PDUs stored in this pre-allocated file - TInt noOfPDUs = iEntryArray[aIndex].Count(); - //Will indicate how many number of PDUs already read from pre-allocated file. - TInt noOfPDUsRead = 0; - // Can also get the number of pdu stored in pre-allocated file from count's variable. - TInt noOfEntriesRemoved=0; - for (TInt count=0; count= aStartPos) && (index <= aEndPos)) - { - noOfEntriesRemoved++; - //Remove the PDU entry. - iFile.Write(storageIdPos, memPtr2); - } - - if (noOfPDUsRead == noOfPDUs) - { - break; - } - } - } - - /* - There are 3 scenarios in this case: - 1. If all the entries need to be removed, - then there is no need to store the entry in this permanent file. - 2. If few entries need to be removed, - then externalize the remaining entries. Update count field also. - 3. If no entries need to be removed, then do nothing. - */ - TSmsPreAllocatedFileStoreReassemblyEntry entry; - entry = iEntryArray[aIndex]; - - if (entry.Count() == noOfEntriesRemoved) - { - entry.SetPreAllocatedStorageId(KErrNotFound); - entry.SetCount(0); - ChangeEntryL(aIndex, entry); - } - else if (noOfEntriesRemoved > 0) - { - entry.SetCount(entry.Count() - noOfEntriesRemoved); - ChangeEntryL(aIndex, entry); - } - } - -/* -It stores the forwarded message info in forwarded pdu bit-map. - -@param aIndex index number of the forwarded message. -@param aStartPos starting pos of forwarded pdu. -@param aEndPos end pos of forwarded pdu. - -@internalComponent -*/ -void CPreallocatedFile::StoreForwardedPDUsInfoL(TInt aIndex, TInt aStartPos, TInt aEndPos) - { - TSmsPreAllocatedFileStoreReassemblyEntry entry; - entry = iEntryArray[aIndex]; - - TUint8 startBitMapIndex = (aStartPos-1)/8; - TUint8 endBitMapIndex = (aEndPos-1)/8; - TUint8 startBitPos = (aStartPos-1)%8; - TUint8 endBitPos = (aEndPos-1)%8; - - if (startBitMapIndex == endBitMapIndex) - { - TUint8 bitMap; - entry.GetBitMap(startBitMapIndex, bitMap); - TUint8 tmpBitMap = (0 | 0xFF); - tmpBitMap <<= ((8 - endBitPos) - 1); - tmpBitMap >>= (8 - ((endBitPos - startBitPos)+1)); - tmpBitMap <<= startBitPos; - bitMap |= tmpBitMap; - entry.SetBitMap(startBitMapIndex, bitMap); - } - else - { - TUint8 bitMap; - entry.GetBitMap(startBitMapIndex, bitMap); - TUint8 tmpBitMap = (0 | 0xFF); - tmpBitMap >>= (8 - ((7 - startBitPos)+1)); - tmpBitMap <<= startBitPos; - bitMap |= tmpBitMap; - entry.SetBitMap(startBitMapIndex, bitMap); - - entry.GetBitMap(endBitMapIndex, bitMap); - tmpBitMap = (0 | 0xFF); - tmpBitMap <<= ((8 - endBitPos) - 1); - tmpBitMap >>= (8 - ((endBitPos - 0)+1)); - tmpBitMap <<= 0; - bitMap |= tmpBitMap; - entry.SetBitMap(endBitMapIndex, bitMap); - } - - TInt noOfForwardedPDUs = (aEndPos - aStartPos) + 1; - entry.SetNumberOfPDUsForwardToClient(entry.NumberOfPDUsForwardToClient()+noOfForwardedPDUs); - - ChangeEntryL(aIndex, entry); - } - -/* -It checks the validity of master header section by comparing checksum value. -If the checksum value does not match, then it copies data from duplicate header section to -master header section. -*/ -void CPreallocatedFile::CheckDataL() - { - TUint32 checksum; - TInt checksumPos = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection; - - TPtr8 memPtr((TUint8*) &checksum, sizeof(checksum), sizeof(checksum)); - iFile.Read(checksumPos, memPtr); - - if (ChecksumValue() != checksum) - { - CopyDuplicateToMasterL(); - } - } - -/* -It writes the checksum value & then copies header information from master section to duplicate section. -*/ -void CPreallocatedFile::PutChecksumValueL() - { - TUint32 checksum = ChecksumValue(); - TInt checksumPos = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection; - - TPtr8 memPtr((TUint8*) &checksum, sizeof(checksum), sizeof(checksum)); - iFile.Write(checksumPos, memPtr); - iFile.Flush(); - CopyMasterToDuplicateL(); - } - -/* -It calculates & returns the checksum value of master header section. -*/ -TUint32 CPreallocatedFile::ChecksumValue() - { - TInt sizeOfDataToBeChecksum = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection; - - TUint32 checksum(0); - - TUint32 tmpValue; - TPtr8 memPtr((TUint8*) &tmpValue, sizeof(tmpValue), sizeof(tmpValue)); - - for (TInt i = 0; i < sizeOfDataToBeChecksum/4 ; i++) - { - iFile.Read(KBeginOfMasterHeaderSection + (i*4), memPtr); - checksum += tmpValue; - } - return checksum; - } - -/* -It copies header information from master copy to duplicate copy. -*/ -void CPreallocatedFile::CopyMasterToDuplicateL() - { - TInt sizeOfDataToBeCopied = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + 4; - - HBufC8* heapBuffer = HBufC8::NewL(sizeOfDataToBeCopied); - CleanupStack::PushL(heapBuffer); - TPtr8 memPtr(heapBuffer->Des()); - iFile.Read(KBeginOfMasterHeaderSection, memPtr); - iFile.Write(iBeginOfDuplicateHeaderSection, memPtr); - iFile.Flush(); - CleanupStack::PopAndDestroy(heapBuffer); - } - -/* -It copies header information from duplicate copy to master copy. -*/ -void CPreallocatedFile::CopyDuplicateToMasterL() - { - TInt sizeOfDataToBeCopied = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + 4; - - HBufC8* heapBuffer = HBufC8::NewL(sizeOfDataToBeCopied); - CleanupStack::PushL(heapBuffer); - TPtr8 memPtr(heapBuffer->Des()); - iFile.Read(iBeginOfDuplicateHeaderSection, memPtr); - iFile.Write(KBeginOfMasterHeaderSection, memPtr); - iFile.Flush(); - CleanupStack::PopAndDestroy(heapBuffer); - } - -/* -It returns the total number of PDUs stored in pre-allocated file. -*/ -TInt CPreallocatedFile::NumberOfPDUStored() - { - TInt noOfPDUs = 0; - for (TInt i = 0; i < iEntryArray.Count(); i++) - { - noOfPDUs += iEntryArray[i].Count(); - } - return noOfPDUs; - } - -/** - * Sets the pre-allocated file store as in-transaction. - * - * The function checks the validity of the call and leaves KErrAccessDenied if - * invalid. - * @capability None - */ -void CPreallocatedFile::BeginTransactionL() - { - LOGSMSPROT3("CPreallocatedFile::BeginTransactionL [this=0x%08X iInTransaction=%d]", this, iInTransaction); - - if (iInTransaction) - { - LOGGSMU1("WARNING CPreallocatedFile::BeginTransactionL leaving with KErrAccessDenied"); - User::Leave(KErrAccessDenied); - } - - iInTransaction = ETrue; - } - -/** - * It commits the transaction. - */ -void CPreallocatedFile::CommitTransactionL() - { - LOGSMSPROT3("CPreallocatedFile::CommitTransactionL(): this=0x%08X iInTransaction=%d", - this, iInTransaction); - - ExternalizeEntryArray(); - //Commit - PutChecksumValueL(); - iInTransaction = EFalse; - iReinstateEntryInfo.Reset(); - RemoveDeletedEntries(); - } - -/* -It reverts the transaction. -*/ -void CPreallocatedFile::Revert() - { - LOGSMSPROT3("CPreallocatedFile::Revert(): this=0x%08X, iInTransaction=%d", - this, iInTransaction); - - ReinstateEntries(); - ExternalizeEntryArray(); - iInTransaction = EFalse; - ReinstateDeletedEntries(); - } - -/** - * It removes the deleted entries from entry arry. - * This function is called after commit. - */ -void CPreallocatedFile::RemoveDeletedEntries() - { - LOGSMSPROT1("CPreallocatedFile::RemoveDeletedEntries()"); - - TInt count=iEntryArray.Count(); - while (count--) - { - TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[count]; - - if (entry.IsDeleted()) - { - iEntryArray.Delete(count); - } - else - { - entry.SetIsAdded(EFalse); - } - } - } // CPreallocatedFile::RemoveDeletedEntries - -/** - * It reinstate the deleted/added entries from entry arry. - * This function is called after revert operation. - */ -void CPreallocatedFile::ReinstateDeletedEntries() - { - LOGSMSPROT1("CPreallocatedFile::ReinstateDeletedEntries()"); - - TInt count=iEntryArray.Count(); - while (count--) - { - TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[count]; - - if (entry.IsAdded()) - { - iEntryArray.Delete(count); - } - else - { - entry.SetIsDeleted(EFalse); - } - } - } // CPreallocatedFile::ReinstateDeletedEntries - -/** - * It reinstate the deleted/added entries from the container. - * This function is called at the time of revert operation. - * Unlike permanent store file which supports revert. pre-allocated - * file (raw data file) supports the revert mecahnism using this function. - */ -void CPreallocatedFile::ReinstateEntries() - { - LOGSMSPROT1("CPreallocatedFile::ReinstateEntries()"); - - TInt containerId; - TInt storageId; - TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); - - TInt count = iReinstateEntryInfo.Count(); - - for (TInt i=0; i0)) - { - time = iEntryArray[index2].Time(); - index = index2; - } - } - return index; - } - -/** -Static factory constructor. Uses two phase -construction and leaves nothing on the CleanupStack. - -@param aClass0ReassemblyStore reference to class 0 reasembly store. -@param aGuardTimeout guard time out in hours. - -@return A pointer to the newly created CGuardTimer object. - -@internalComponent -*/ -CGuardTimer* CGuardTimer::NewL(CClass0SmsReassemblyStore& aClass0ReassemblyStore, TInt aGuardTimeout) - { - LOGSMSPROT1("CGuardTimer::NewL()"); - - CGuardTimer* timer = new(ELeave) CGuardTimer(aClass0ReassemblyStore, aGuardTimeout); - CleanupStack::PushL(timer); - timer->ConstructL(); - CleanupStack::Pop(); - return timer; - } // CGuardTimer::NewL - -/** - * Constructor - */ -CGuardTimer::CGuardTimer(CClass0SmsReassemblyStore& aClass0ReassemblyStore, TInt aGuardTimeout) - :CTimer(KSmsSessionPriority), - iClass0ReassemblyStore(aClass0ReassemblyStore), - iTimeoutInSecs(aGuardTimeout*3600) - { - CActiveScheduler::Add(this); - } //CGuardTimer::CGuardTimer - -/** - * Destructor - */ -CGuardTimer::~CGuardTimer() - { - Cancel(); - } // CGuardTimer::~CGuardTimer - -/** - * Enable the Gurad Timer - */ -void CGuardTimer::EnableGuardTimer() - { - LOGSMSPROT1("CGuardTimer::EnableGuardTimer()"); - if (!IsActive()) - { - TTime nextTimeOut; - iClass0ReassemblyStore.GetNextGuardTimeout(nextTimeOut); - At(nextTimeOut); - } - } //CGuardTimer::EnableGuardTimer - -/** - * Disable the Gurad Timer - */ -void CGuardTimer::DisableGuardTimer() - { - Cancel(); - } - -/** - * Timer completed - */ -void CGuardTimer::RunL() - { - LOGSMSPROT2("CGuardTimer::RunL [iStatus=%d]", iStatus.Int()); - iClass0ReassemblyStore.ProcessTimeoutMessageL(); - EnableGuardTimer(); - } // CGuardTimer::RunL - -/** -Static factory constructor. Uses two phase -construction and leaves nothing on the CleanupStack. - -@param aFs File Server handle. -@param aSmsComm reference to MSmsComm event handler. - -@return A pointer to the newly created CClass0SmsReassemblyStore object. - -@pre A connected file server session must be passed as parameter. -@post CClass0SmsReassemblyStore object is now fully initialised - -@internalComponent -*/ -CClass0SmsReassemblyStore* CClass0SmsReassemblyStore::NewL(RFs& aFs, MSmsComm& aSmsComm) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::NewL()"); - - CClass0SmsReassemblyStore* self = new (ELeave) CClass0SmsReassemblyStore(aFs, aSmsComm); - CleanupStack::PushL(self); - self->ConstructL(); - CleanupStack::Pop(self); - - return self; - } - -/** - * C'tor - */ -CClass0SmsReassemblyStore::CClass0SmsReassemblyStore(RFs& aFs, MSmsComm& aSmsComm) - :CReassemblyStore(aFs), iSmsComm(aSmsComm), iPermanentFileStore(NULL), iPreallocatedFile(NULL), - iGuardTimer(NULL), iInTransaction(EFalse), iDiskSpaceStatus(ESmsDiskSpaceAvailable) - { - } - -/** - * D'tor - */ -CClass0SmsReassemblyStore::~CClass0SmsReassemblyStore() - { - delete iPermanentFileStore; - delete iPreallocatedFile; - delete iGuardTimer; - } - -/* -It constructs permanent and pre-allocated file to store the class 0 messages. -It creates a guard timer so that messages can be deleted if all the constituent -PDU of a message is not received within configured time-frame. -It also reserves 4KB disk space so that reserved space can be used to -delete a stream from permanent file store in out-of-disk condition. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::ConstructL() - { - //Reserve Drive Space - User::LeaveIfError(iFs.ReserveDriveSpace(KStoreDrive, 4*1024)); - - //Read Configuration file - ReadConfigurableClass0SmsSettingsL(iMaxClass0Msg, iMaxPDUSeg, iGuardTimeOut); - //Create Permanent store file - TFileName permanentStoreFileName; - CReassemblyStoreUtility::PrivatePath(iFs, permanentStoreFileName); - permanentStoreFileName.Append(KClass0ReassemblyStoreName); - iPermanentFileStore = CSmsPermanentFileStore::NewL(iFs, permanentStoreFileName, KClass0ReassemblyStoreUid); - //Create Pre-allocated file - TFileName preAllocatedFileName; - CReassemblyStoreUtility::PrivatePath(iFs, preAllocatedFileName); - preAllocatedFileName.Append(KPreAllocatedFileName); - iPreallocatedFile = CPreallocatedFile::NewL(iFs, preAllocatedFileName, iMaxClass0Msg, iMaxPDUSeg); - //Create Gurad Timer - iGuardTimer = CGuardTimer::NewL(*this, iGuardTimeOut); - } - -/* -It reads class 0 re-assembly store configuration information from smswap.sms.esk file. -It reads the following information: MaxClass0Messages, NumberOfPDUSegements, GuardTimeOut. -If any of the above element is missing it takes the default value. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL(TInt& aMaxClass0Msg, TInt& aMaxPDUSeg, TInt& aGuardTimeOut) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL()"); - - aMaxClass0Msg = KMaxNumberOfClass0MessagesInReassemblyStore; - aMaxPDUSeg = KNumberOfPDUSegmentsStoredInOODCondition; - aGuardTimeOut = KGuardTimeOut; - - CESockIniData* ini = NULL; - TRAPD(ret, ini=CESockIniData::NewL(_L("smswap.sms.esk"))); - if(ret!=KErrNone) - { - LOGSMSPROT2("CESockIniData::NewL() returned=%d", ret); - } - else - { - CleanupStack::PushL(ini); - - TInt var(0); - if(ini->FindVar(_L("ReassemblyStore"),_L("MaxClass0Messages"),var)) - { - if (var > 0) - { - LOGSMSPROT2("MaxClass0Messages [%d]", var); - aMaxClass0Msg = var; - } - } - - if(ini->FindVar(_L("ReassemblyStore"),_L("NumberOfPDUSegements"),var)) - { - if (var > 0) - { - LOGSMSPROT2("MaxClass0Messages [%d]", var); - aMaxPDUSeg = var; - } - } - - if(ini->FindVar(_L("ReassemblyStore"),_L("GuardTimeOut"),var)) - { - if (var > 0) - { - LOGSMSPROT2("MaxClass0Messages [%d]", var); - aGuardTimeOut = var; - } - } - - CleanupStack::PopAndDestroy(ini); - } - - LOGSMSPROT4("CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL(): aMaxClass0Msg=%d, aMaxPDUSeg=%d, aGuardTimeOut=%d", - aMaxClass0Msg, aMaxPDUSeg, aGuardTimeOut); - } - -/** -It opens the class 0 re-assembly store. -Then it populates the entry information (all the messages stored in re-assembly store). - -@internalComponent -*/ -void CClass0SmsReassemblyStore::OpenStoreL() - { - LOGSMSPROT1("CClass0SmsReassemblyStore::OpenStoreL()"); - TFileName pathName; - CReassemblyStoreUtility::PrivatePath(iFs, pathName); - //Create the directory if it is not created. - iFs.MkDirAll(pathName); - // If any one file becomes corrupt or does not exist then we have to create both files. - if (iPreallocatedFile->IsFileOK() && iPermanentFileStore->IsFileOK()) - { - iPreallocatedFile->OpenL(); - iPermanentFileStore->OpenL(); - } - else - { - iPreallocatedFile->CreateL(); - iPermanentFileStore->CreateL(); - } - PopulateEntryArrayL(iEntryArray); - iGuardTimer->EnableGuardTimer(); - } - -/** -It closes the class 0 re-assembly store. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::Close() - { - LOGSMSPROT1("CClass0SmsReassemblyStore::CloseStore()"); - iGuardTimer->DisableGuardTimer(); - iEntryArray.Reset(); - iPreallocatedFile->Close(); - iPermanentFileStore->Close(); - } - -/** -It populates the entry information stored in class 0 reassembly store. - -@param aEntryArray reference to entry array. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::PopulateEntryArrayL(CArrayFix& aEntryArray) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::PopulateEntryArrayL()"); - aEntryArray.Reset(); - //Populate Entries from Pre-allocated file. - for (TInt count = 0; count < iPreallocatedFile->Entries().Count(); count++) - { - TReassemblyEntry entry; - entry.SetReference(iPreallocatedFile->Entries()[count].Reference()); - entry.SetTotal(iPreallocatedFile->Entries()[count].Total()); - entry.SetCount(iPreallocatedFile->Entries()[count].Count()+iPreallocatedFile->Entries()[count].NumberOfPDUsForwardToClient()); - entry.SetLogServerId(iPreallocatedFile->Entries()[count].LogServerId()); - - // Check that descriptor2 (sms address )is not corrupted - TPtrC ptr = iPreallocatedFile->Entries()[count].Description2(); - - if (ptr.Length() <= CSmsAddress::KSmsAddressMaxAddressLength) - { - entry.SetDescription2(iPreallocatedFile->Entries()[count].Description2()); - } - - entry.SetPduType(iPreallocatedFile->Entries()[count].PduType()); - entry.SetStorage(iPreallocatedFile->Entries()[count].Storage()); - entry.SetTime(iPreallocatedFile->Entries()[count].Time()); - entry.SetPassedToClient(iPreallocatedFile->Entries()[count].PassedToClient()); - aEntryArray.AppendL(entry); - } - - /* - Then populate the entries from permanent store file. It is needed - because permanent store file might contain few mesages. - But before populating the entry information it is needed to cleanup - the entries in permanent store file. It is needed to ensure that permanent file - clean itself with pre-allocated file. There migth be a scenario where - user has deleted a message but the corresponding message has not been - deleted from permanent store file due to out-of-disk condition. - And also at the time of forwarding an incomplete message a forwarded - message has not been deleted due to above reason. But the entry/PDU is - invalid because it is no more in the pre-allocated file which - contains master header info. - */ - TInt ret = CleanReassemblyEntries(); - - if (ret == KErrNone) - { - /* - In this case permanent store file contains correct information. - So populate Entry information from Permanent store file. - In this case only count information needs to be updated. - */ - TInt permanentFileStoreIndex; - for (TInt i=0; iMatchEntryToExistingMessage(aEntryArray[i], permanentFileStoreIndex); - if (permanentFileStoreIndex!=KErrNotFound) - { - aEntryArray[i].SetCount(aEntryArray[i].Count() + iPermanentFileStore->Entries()[permanentFileStoreIndex].Count()); - if (aEntryArray[i].Count() > aEntryArray[i].Total()) - { - aEntryArray[i].SetCount(aEntryArray[i].Total()); - } - } - } - } - else if (ret == KErrDiskFull) - { - LOGSMSPROT1("CleanReassemblyEntries() returns KErrDiskFull"); - /* - In this case permanent store file contains incorrect information. - For example forwarded message might be still stored in this store. - Because it has not been deleted due to out-of-disk condition. - So be careful at the time of updating the count information - about the message. - */ - TInt permanentFileStoreIndex; - for (TInt i=0; iMatchEntryToExistingMessage(aEntryArray[i], permanentFileStoreIndex); - if (permanentFileStoreIndex!=KErrNotFound) - { - TSmsPreAllocatedFileStoreReassemblyEntry entry = iPreallocatedFile->Entries()[i]; - if (entry.NumberOfPDUsForwardToClient() > 0) - { - //Internalize the entries. - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); - CleanupStack::PushL(smsMessage); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - //Internalize to check whether removed PDUs still stored in Permanent store file. - iPermanentFileStore->InternalizeEntryL(permanentFileStoreIndex, *smsMessage, *indexArray, *smsArray); - TInt noOfForwardedEntries=0; - for (TInt j=0; jCount() ;j++) - { - TUint8 bitMapIndex = (indexArray->At(j)-1)/8; - TUint8 bitPos = (indexArray->At(j)-1)%8; - TUint8 bitMap; - entry.GetBitMap(bitMapIndex, bitMap); - TUint8 tmpBitMap = 1; - tmpBitMap <<= bitPos; - if (tmpBitMap == (bitMap & tmpBitMap)) - { - noOfForwardedEntries++; - } - } - TInt count = iPermanentFileStore->Entries()[permanentFileStoreIndex].Count() - noOfForwardedEntries; - aEntryArray[i].SetCount(aEntryArray[i].Count() + count); - - CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray - } - else - { - aEntryArray[i].SetCount(aEntryArray[i].Count() + iPermanentFileStore->Entries()[permanentFileStoreIndex].Count()); - } - } - } - } - else - { - User::Leave(ret); - } - } - -/** -It sets the disk space status. -If disk space is full, then class 0 re-assembly store stores the incoming message in -pre-allocated file. Otherwise it stores the message in permanent store file. -*/ -void CClass0SmsReassemblyStore::SetDiskSpaceState(TSmsDiskSpaceMonitorStatus aDiskSpaceStatus) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::SetDiskSpaceState()"); - iDiskSpaceStatus = aDiskSpaceStatus; - } - -/* -It adds the new message in class 0 reassembly store. -It first tries to add the message in permanent store file. If it is -successful, then it adds the entry information in pre-allocated file. -Because pre-allocated file contains master header entry information. -Otherwise (if disk space is full), it adds the message in pre-allocated file. - -@param aSmsMessage reference to sms message to be added. -@param aGsmSms reference to GsmSms object to be added. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::AddNewMessageL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::AddNewMessageL"); - - // Add entry in permanent store file - TInt index; - TInt ret = KErrNone; - - if (iDiskSpaceStatus == ESmsDiskSpaceFull) - { - ret = KErrDiskFull; - } - else - { - TRAP(ret, iPermanentFileStore->AddNewMessageL(index, aSmsMessage, aGsmSms)); - } - - if (ret == KErrNone) - { - // Add a new entry in pre-allocated file - TSmsPreAllocatedFileStoreReassemblyEntry tmpEntry; - //Fill-up entry information... - CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1); - - //The properties below need to be set only once when a PDU of a new message arrives. - tmpEntry.SetStatus((RMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status()); - tmpEntry.SetUTCOffset(aSmsMessage.UTCOffset()); - tmpEntry.SetDecodedOnSIM(aSmsMessage.DecodedOnSim()); - tmpEntry.SetForwardToClient(aSmsMessage.ForwardToClient()); - //Set KErrNotFound because message corresponding to - //this entry is not in this pr-allocated file. - tmpEntry.SetPreAllocatedStorageId(KErrNotFound); - //Has to set 0 because PDU is stored in Permanent store file instead of pre-allocated file. - tmpEntry.SetCount(0); - - iPreallocatedFile->AddEntryL(tmpEntry); - } - else if (ret == KErrDiskFull) - { - // Add the new message in pre-allocated file - iPreallocatedFile->AddNewMessageL(index, aSmsMessage, aGsmSms); - } - else - { - User::Leave(ret); - } - } - -/* -It updates the existing message in class 0 re-assembly store. - -@param aSmsMessage reference to sms message to be updated. -@param aGsmSms reference to GsmSms object to be added. -@param aDuplicateMsgRef boolean value (output) indicates whether the added PDU is a duplicate or not. -@param aDuplicateSlot boolean value (output) indicates whether the added PDU is a duplicate enumerated PDU. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::UpdateExistingMessageL(CSmsMessage& aSmsMessage, const TGsmSms& aGsmSms, TBool& aDuplicateMsgRef, TBool& aDuplicateSlot) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::UpdateExistingMessageL()"); - - aDuplicateMsgRef = EFalse; - aDuplicateSlot = EFalse; - - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); - CleanupStack::PushL(smsMessage); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - //Internalize stored message in permanent store file - TReassemblyEntry entry; - CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, 1); - TInt permanentStoreIndex; - iPermanentFileStore->MatchEntryToExistingMessage(entry, permanentStoreIndex); - if (permanentStoreIndex!=KErrNotFound) - { - iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, *smsMessage, *indexArray, *smsArray); - } - - //Internalize stored message in pre-allocated file - TInt preAllocatedFileIndex; - iPreallocatedFile->MatchEntryToExistingMessage(entry, preAllocatedFileIndex); - if (preAllocatedFileIndex!=KErrNotFound) - { - iPreallocatedFile->InternalizeEntryL(preAllocatedFileIndex, *smsMessage, *indexArray, *smsArray); - } - else - { - //This condition should never arise - User::Leave(KErrNotFound); - } - - // - // 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; - } - } - - //Check whether this PDU is part of forwarded PDU. - TSmsPreAllocatedFileStoreReassemblyEntry preAllocatedFileEntry = iPreallocatedFile->Entries()[preAllocatedFileIndex]; - if (preAllocatedFileEntry.NumberOfPDUsForwardToClient() > 0) - { - TUint8 bitMapIndex = (concatPDUIndex-1)/8; - TUint8 bitPos = (concatPDUIndex-1)%8; - TUint8 bitMap; - preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap); - TUint8 tmpBitMap = 1; - tmpBitMap <<= bitPos; - if (tmpBitMap == (bitMap & tmpBitMap)) - { - aDuplicateMsgRef = ETrue; - } - } - - if (aDuplicateMsgRef || aDuplicateSlot) - { - CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, smsArray, indexArray - return; - } - - // - // If the PDU is stored then add the slot information... - // - if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage || - aSmsMessage.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); - } - - /* - Below logic is written in keeping view of different scenarios that might occur here: - (1) Previous PDUs are in Permanent store file, this PDU arrives in out-of-disk condition (so will be stored in Pre-allocated file). - (2) Previous PDUs are in Pre-allocated file (means PDU arrives in out-of-disk condition), this PDU arrives in normal condition. - (3) Previous PDUs are in Permanent store file, this PDU also arrives in normal condition. - (4) Previous PDUs are in Pre-allocated file (means PDU arrives in out-of-disk condition), this PDU also arrives in out-of-disk condition. - */ - - //Always first try to store the message in permanent store file. - //In case of out-of-disk condition store the message in pre-allocated file - TInt ret = KErrNone; - if (iDiskSpaceStatus == ESmsDiskSpaceFull) - { - ret = KErrDiskFull; - } - else - { - if (permanentStoreIndex==KErrNotFound) - { - // See condition (2) - TInt tmpIndex; - TRAP(ret, iPermanentFileStore->AddNewMessageL(tmpIndex, aSmsMessage, aGsmSms)); - } - else - { - CSmsBuffer* tmpBuffer = CSmsBuffer::NewL(); - CSmsMessage* tmpSmsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, tmpBuffer); - CleanupStack::PushL(tmpSmsMessage); - - indexArray->Reset(); - smsArray->Reset(); - iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, *tmpSmsMessage, *indexArray, *smsArray); - /* - Check & remove those PDU from permanent store file which has already been - forwarded to client. Forwarded PDU might still remain in permanent store - file if it is deleted at the time of out-of-disk condition. - */ - if (preAllocatedFileEntry.NumberOfPDUsForwardToClient()>0) - { - for (TInt j=indexArray->Count(); j>0 ;j--) - { - TUint8 bitMapIndex = (indexArray->At(j-1)-1)/8; - TUint8 bitPos = (indexArray->At(j-1)-1)%8; - TUint8 bitMap; - preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap); - TUint8 tmpBitMap = 1; - tmpBitMap <<= bitPos; - if (tmpBitMap == (bitMap & tmpBitMap)) - { - indexArray->Delete(j-1); - smsArray->Delete(j-1); - } - } - } - - indexArray->AppendL(concatPDUIndex); - smsArray->AppendL(aGsmSms); - - TRAP(ret, iPermanentFileStore->UpdateExistingMessageL(permanentStoreIndex, *smsMessage, *indexArray, *smsArray)); - - CleanupStack::PopAndDestroy(1); //tmpSmsMessage - } - } - - if (ret == KErrDiskFull) - { - iPreallocatedFile->UpdateExistingMessageL(preAllocatedFileIndex, aSmsMessage, concatPDUIndex, aGsmSms); - } - else if (ret!=KErrNone) - { - User::Leave(ret); - } - - CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray - } - -/* -It retrieves class 0 message from re-assembly store. -The message which match the passed entry information is returned from this function. - -@param aEntry reference to entry information. -@param aSmsMessage reference to returned sms message. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::RetrieveMessageL(const TReassemblyEntry& aEntry, CSmsMessage& aSmsMessage) - { - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - GetSmsEntriesL(aEntry, aSmsMessage, *indexArray, *smsArray); - - //There is no need to decode a single segment message - if (aEntry.Total()>1) - { - if (smsArray->Count() == aEntry.Total()) - { - aSmsMessage.DecodeMessagePDUsL(*smsArray); - } - } - CleanupStack::PopAndDestroy(2, indexArray); //smsArray, indexArray - } - -/* -It deletes the entry from re-assembly store. - -@param aEntry reference to entry information. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::DeleteEntryL(const TReassemblyEntry& aEntry) - { - TInt index; - iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index); - if (index == KErrNotFound) - { - //This condition should never arise - User::Leave(KErrNotFound); - } - iPreallocatedFile->DeleteEntryL(index); - iPermanentFileStore->MatchEntryToExistingMessage(aEntry, index); - if (index != KErrNotFound) - { - TRAP_IGNORE(iPermanentFileStore->DeleteEntryL(index)); - } - } - -/* -It updates the log server id of the passed entry (message). - -@param aEntry reference to entry information. -@param aLogId log id of the message to be updated. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::UpdateLogServerIdL(const TReassemblyEntry& aEntry, TLogId aLogServerId) - { - TInt index; - iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index); - if (index == KErrNotFound) - { - //This condition should never arise - User::Leave(KErrNotFound); - } - iPreallocatedFile->UpdateLogServerIdL(index, aLogServerId); - } - -/* -It sets the message passed to client or not. The message, which match the -passed entry information, its passed to client value is set. - -@param aEntry reference to entry information. -@param aBool boolean value indicating whether message is passed or not. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::SetPassedToClientL(const TReassemblyEntry& aEntry, TBool aBool) - { - TInt index; - iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index); - if (index == KErrNotFound) - { - //This condition should never arise - User::Leave(KErrNotFound); - } - iPreallocatedFile->SetPassedToClientL(index, aBool); - } - -/** -It forwards the complete class 0 messages to client. -It checks whether the received object is complete or not. -If it is complete, then it forwards the complete message to client. -Otherwise it forms the message & forward the message to client. -In this it might be possible to forward multiple incomplete message. - -@param aSmsComm a reference to aSmsComm object which implemented the events. - -@param aSmsMessage a reference to sms message object. This sms message must be class 0 messages. - -@param aOriginalSmsAddr pointer to the address of the sender of a previously sent - -@param aOriginalSmsMessage pointer to a message previously sent matched to the received - one (e.g. status report). Null if not matched. - -@param aDes user data for the deliver report acknowledging this message to the SC. - Filled in by the observer. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::ForwardCompleteClass0SmsMessagesL(MSmsComm& aSmsComm, const CSmsMessage& aSmsMessage,const TSmsAddr* aOriginalSmsAddr,const CSmsMessage* aOriginalSmsMessage,TDes& aDes) - { - TBool passedToClient=ETrue; - - if (aSmsMessage.IsComplete()) - { - //Message is complete so forward it. - TInt ret = aSmsComm.ProcessMessageL(aSmsMessage, aOriginalSmsAddr, aOriginalSmsMessage, aDes); - if (ret!=KErrNone) - { - passedToClient = EFalse; - } - } - else - { - /* - Message is not complete, but re-assembly store contains other constituent PDU - of the message which makes the message complete. - - In case of class 0 messages, it is possible to forward the incomplete messages. So after forwarding - the incomplete message, if we receive other constituent PDU of that message then in that case we - might receive all the constituent PDU of that message but aSmsMesssage will contain partial complete message. - */ - TReassemblyEntry entry; - CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, 1); - - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer ); - CleanupStack::PushL( smsMessage ); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray); - SortPDUsL(*indexArray, *smsArray); - - CArrayFixFlat* tmpSmsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(tmpSmsArray); - - //Form the sequence of incomplete message & forward it to client. - TInt startSeqIndex(0), endSeqIndex(0); - TInt i; - do - { - i = startSeqIndex; - for (; i < indexArray->Count() - 1; i++) - { - if (indexArray->At(i) + 1 != indexArray->At(i+1)) - { - endSeqIndex = i; - break; - } - } - - if (i == (indexArray->Count() - 1)) - { - endSeqIndex = i; - } - - tmpSmsArray->Reset(); - for (TInt j = startSeqIndex; j <= endSeqIndex; j++) - { - tmpSmsArray->AppendL(smsArray->At(j)); - } - - if (tmpSmsArray->Count() == entry.Total()) - { - smsMessage->DecodeMessagePDUsL(*tmpSmsArray); - } - else - { - //Build the partial complete message. - if (endSeqIndex == (indexArray->Count() - 1)) - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); - } - else - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); - } - } - - //Forward the partial complete message to client. - TInt ret=KErrNone; - TRAP(ret, aSmsComm.ProcessMessageL(*smsMessage, aOriginalSmsAddr, aOriginalSmsMessage, aDes)); - if (ret != KErrNone) - { - passedToClient = EFalse; - } - startSeqIndex = endSeqIndex + 1; - endSeqIndex = startSeqIndex; - } - while (startSeqIndex < indexArray->Count()); - - CleanupStack::PopAndDestroy(4); //tmpSmsArray, indexArray, smsArray, smsMessage - } - - if(passedToClient) - { - SetMessagePassedToClientL(aSmsMessage); - } - - //If the latest segement exceeds the limitation, then we can't wait till ack. - //So call ProcessMessageIfExceedLimitationL() function & delete the oldest message. - if (IsExceedLimitation()) - { - ProcessMessageIfExceedLimitationL(aSmsComm); - } - } - -/** -It frees the space by forwarding the class 0 message if class 0 re-assembly store -exceeds limitation (max class 0 message, max reserved pdu segment). - -@param aSmsComm a reference to aSmsComm object which implemented the events. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::ProcessMessageIfExceedLimitationL(MSmsComm& aSmsComm) - { - //Add Comment - TInt class0MsgCount = iEntryArray.Count(); - TInt noOfMsgStoredInPreAllocatedFile = iPreallocatedFile->NumberOfPDUStored(); - if ((class0MsgCount > iMaxClass0Msg) - || (noOfMsgStoredInPreAllocatedFile >= iMaxPDUSeg)) - { - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer ); - CleanupStack::PushL( smsMessage ); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - //Add Comment - TInt index; - if (class0MsgCount > iMaxClass0Msg) - { - index = GetIndexOfOldestMessage(); - } - else - { - index = GetIndexOfOldestMessageFromReservedFileL(); - } - - TReassemblyEntry entry = iEntryArray[index]; - - GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray); - - SortPDUsL(*indexArray, *smsArray); - - CArrayFixFlat* tmpSmsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(tmpSmsArray); - - //Form the message & forward it to client. - TInt startSeqIndex(0), endSeqIndex(0); - TInt i; - do - { - i = startSeqIndex; - for (; i < indexArray->Count() - 1; i++) - { - if (indexArray->At(i) + 1 != indexArray->At(i+1)) - { - endSeqIndex = i; - break; - } - } - if (i == (indexArray->Count() - 1)) - { - endSeqIndex = i; - } - tmpSmsArray->Reset(); - - for (TInt j = startSeqIndex; j <= endSeqIndex; j++) - { - tmpSmsArray->AppendL(smsArray->At(j)); - } - - if (entry.IsComplete()) - { - if (tmpSmsArray->Count() == entry.Total()) - { - smsMessage->DecodeMessagePDUsL(*tmpSmsArray); - } - else - { - //Build the partial complete message. - if (endSeqIndex == (indexArray->Count() - 1)) - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); - } - else - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); - } - } - } - else - { - //Build the partial complete message. - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); - } - //Forward the partial complete message to client. - TBuf16 buffer; - TRAP_IGNORE(aSmsComm.ProcessMessageL(*smsMessage, NULL, NULL, buffer)); - - /* - Can't do much. So free the reserved space & also stored the information - related to forwarded message. If the message is complete then delete - the complete message (see the condition after the while loop)rather - than freeing the memory. No need to store the complete messages forwaded - info. - */ - if ((noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg) && (!entry.IsComplete())) - { - SetIncompleteMessageForwardedToClientL(*smsMessage); - } - startSeqIndex = endSeqIndex + 1; - endSeqIndex = startSeqIndex; - } - while (startSeqIndex < indexArray->Count()); - //Can't do much. So removed the oldest message. - if ((class0MsgCount > iMaxClass0Msg) || - ((noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg) && (entry.IsComplete()))) - { - DeleteMessageL(*smsMessage, EFalse); - } - CleanupStack::PopAndDestroy(4); //tmpSmsArray, indexArray, smsArray, smsMessage - } - } - -/** -Guard timer calls this function when timer expires. -It goes through all the messages stored in re-assembly store & forwards those message -whose time has expired. -It is also called when a new observer is added or a PDU has been received and successfully -processed. It is also called from ProcessCompleteClass0SmsMessagesL. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::ProcessTimeoutMessageL() - { - LOGSMSPROT1("CClass0SmsReassemblyStore::ProcessTimeoutMessageL()"); - TBool passedToClient=ETrue; - TInt count=iEntryArray.Count(); - - CSmsBuffer* buffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer ); - CleanupStack::PushL( smsMessage ); - - CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(indexArray); - CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(smsArray); - - CArrayFixFlat* tmpSmsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); - CleanupStack::PushL(tmpSmsArray); - - TTime time; - time.UniversalTime(); - - TTimeIntervalSeconds timeOutInSecs = iGuardTimeOut*3600; - - for (TInt k=count-1; k>=0; k--) - { - if (!iEntryArray[k].PassedToClient()) - { - TTimeIntervalSeconds diffInSecs; - time.SecondsFrom(iEntryArray[k].Time(), diffInSecs); - indexArray->Reset(); - smsArray->Reset(); - if (diffInSecs >= timeOutInSecs) - { - GetSmsEntriesL(iEntryArray[k], *smsMessage, *indexArray, *smsArray); - SortPDUsL(*indexArray, *smsArray); - - //Form the message & forward it to client. - TInt startSeqIndex(0), endSeqIndex(0); - TInt i; - do - { - i = startSeqIndex; - for (; i < indexArray->Count() - 1; i++) - { - if (indexArray->At(i) + 1 != indexArray->At(i+1)) - { - endSeqIndex = i; - break; - } - } - if (i == (indexArray->Count() - 1)) - { - endSeqIndex = i; - } - tmpSmsArray->Reset(); - for (TInt j = startSeqIndex; j <= endSeqIndex; j++) - { - tmpSmsArray->AppendL(smsArray->At(j)); - } - - if (iEntryArray[k].IsComplete()) - { - if (tmpSmsArray->Count() == iEntryArray[k].Total()) - { - smsMessage->DecodeMessagePDUsL(*tmpSmsArray); - } - else - { - //Build the partial complete message. - if (endSeqIndex == (indexArray->Count() - 1)) - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); - } - else - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); - } - } - } - else - { - //Build the partial complete message. - if (endSeqIndex == (indexArray->Count() - 1)) - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); - } - else - { - smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); - } - } - - //Forward the partial complete message to client. - TInt ret=KErrNone; - TBuf16 buffer; - ret = iSmsComm.ProcessMessageL(*smsMessage, NULL, NULL, buffer); - if (ret != KErrNone) - { - passedToClient = EFalse; - } - - startSeqIndex = endSeqIndex + 1; - endSeqIndex = startSeqIndex; - } - while (startSeqIndex < indexArray->Count()); - - if(passedToClient) - { - SetMessagePassedToClientL(*smsMessage); - } - } //diffInSecs >= timeOutInSecs - } //!iEntryArray[k].PassedToClient() - } //For k loop - CleanupStack::PopAndDestroy(4); //tmpSmsArray, indexArray, smsArray, smsMessage - } - -/** -It sets the bit-map of forwarded incomplete message to client. -It frees up the memory by removing the forwarded PDUs. - -@param aSmsMessage a reference to forwaded incomplete class 0 sms message object. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::SetIncompleteMessageForwardedToClientL(const CSmsMessage& aSmsMessage) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::SetIncompleteMessageForwardedToClientL()"); - TInt index = KErrNotFound; - - if (aSmsMessage.IsComplete()) - { - LOGSMSPROT1("This function must be called when message is incomplete"); - User::Leave(KErrArgument); - } - - if (FindMessageL(aSmsMessage, EFalse, index)) - { - CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo &) aSmsMessage.GetOperationsForNonIEL(ESmsIncompleteClass0MessageParameter); - // Retrieve incomplete class 0 message information & process - TInt startPos, endPos; - TBool isLastMessage; - incompleteClass0MsgInfo.GetIncompleteMessageInfoL(startPos, endPos, isLastMessage); - - const TReassemblyEntry& entry = iEntryArray[index]; - - //Remove the forwarded PDU entries from pre-allocated file - TInt preAllocatedFileIndex=KErrNotFound; - iPreallocatedFile->MatchEntryToExistingMessage(entry, preAllocatedFileIndex); - if (preAllocatedFileIndex!=KErrNotFound) - { - BeginTransactionLC(); - iPreallocatedFile->RemovePDUsL(preAllocatedFileIndex, startPos, endPos); - iPreallocatedFile->StoreForwardedPDUsInfoL(preAllocatedFileIndex, startPos, endPos); - CommitTransactionL(); - } - else - { - //This situation should never arise - User::Leave(KErrNotFound); - } - - //Remove the forwarded PDU entries from permanent store file - TInt permanentStoreIndex=KErrNotFound; - iPermanentFileStore->MatchEntryToExistingMessage(entry, permanentStoreIndex); - if (permanentStoreIndex!=KErrNotFound) - { - TRAP_IGNORE(BeginTransactionLC(); - iPermanentFileStore->RemovePDUsL(permanentStoreIndex, startPos, endPos); - CommitTransactionL();); - } - } - } - -/** -This function is needed to ensure that permanent file -clean itself with pre-allocated file. -There migth be a scenario where user has deleted a message -but the corresponding message has not been deleted from permanent store file -due to out-of-disk condition. But the entry is invalid because -it is no more in the pre-allocated file which contains master header info. - -@return the error code. - -@internalComponent -*/ -TInt CClass0SmsReassemblyStore::CleanReassemblyEntries() - { - LOGSMSPROT1("CleanReassemblyEntries"); - const CArrayFix& preAllocatedFileEntryArray = iPreallocatedFile->Entries(); - TInt ret=KErrNone; - TRAP(ret, BeginTransactionLC(); - iPermanentFileStore->CleanupEntriesL(preAllocatedFileEntryArray); - CommitTransactionL();); - - if (ret == KErrDiskFull) - { - LOGSMSPROT1("CleanupEntriesL returns KErrDiskFull"); - /* - Get access to reserve memory, call again to clean the entries with compact. - Compact needs to be called at this instance because permanent store - will use reserve disk space to delete, but after deletion reserve - disk space will be freed. So compact will make sure that reserve disk - space is not used after compaction. - */ - iFs.GetReserveAccess(KStoreDrive); - TRAP(ret, BeginTransactionLC(); - iPermanentFileStore->CleanupEntriesWithCompactL(preAllocatedFileEntryArray); - CommitTransactionL();); - LOGSMSPROT2("CleanupEntriesWithCompactL returns %d", ret); - iFs.ReleaseReserveAccess(KStoreDrive); - } - return ret; - } - -/** -It returns the SMS entries (sms messages, sms pdu arrays & the corresponding index array) -from its permanent store & pre-allocated file. - -@param aEntry reference to entry information. The message which match this entry information - is returned to caller of the function. -@param aSmsMessage a reference to class 0 sms message object. -@param aIndexArray a reference to the array of pdu index. -@param aSmsArray a reference to the array of pdu. - -@internalComponent -*/ -void CClass0SmsReassemblyStore::GetSmsEntriesL(const TReassemblyEntry& aEntry, CSmsMessage& aSmsMessage, CArrayFix& aIndexArray, CArrayFix& aSmsArray) - { - LOGSMSPROT1("CClass0SmsReassemblyStore::GetSmsEntriesL()"); - TInt permanentStoreIndex=KErrNotFound; - iPermanentFileStore->MatchEntryToExistingMessage(aEntry, permanentStoreIndex); - if (permanentStoreIndex!=KErrNotFound) - { - iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, aSmsMessage, aIndexArray, aSmsArray); - } - else - { - LOGSMSPROT1("No PDUs in Permanent store file"); - } - - TInt preAllocatedFileIndex=KErrNotFound; - iPreallocatedFile->MatchEntryToExistingMessage(aEntry, preAllocatedFileIndex); - if (preAllocatedFileIndex!=KErrNotFound) - { - iPreallocatedFile->InternalizeEntryL(preAllocatedFileIndex, aSmsMessage, aIndexArray, aSmsArray); - - //Filter forwarde PDU here..this condition might arise if the PDU - //could not be deleted at the time of OOD condition from permanent store file. - TSmsPreAllocatedFileStoreReassemblyEntry preAllocatedFileEntry = iPreallocatedFile->Entries()[preAllocatedFileIndex]; - if (preAllocatedFileEntry.NumberOfPDUsForwardToClient() > 0) - { - for (TInt j=aIndexArray.Count(); j>0 ;j--) - { - TUint8 bitMapIndex = (aIndexArray.At(j-1)-1)/8; - TUint8 bitPos = (aIndexArray.At(j-1)-1)%8; - TUint8 bitMap; - preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap); - TUint8 tmpBitMap = 1; - tmpBitMap <<= bitPos; - if (tmpBitMap == (bitMap & tmpBitMap)) - { - aIndexArray.Delete(j-1); - aSmsArray.Delete(j-1); - } - } - } - - if (permanentStoreIndex==KErrNotFound) - { - //In this scenario a CSmsMessage object has to be created from the existing PDU in - //pre-allocated file & then serialized into aSmsMessage. - LOGSMSPROT2("Number of PDUs in Pre-allocated file %d", aIndexArray.Count()); - if (aIndexArray.Count() > 0) - { - CSmsBuffer* smsBuffer = CSmsBuffer::NewL(); - CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, aSmsArray.At(0), smsBuffer, EFalse, ETrue); - CleanupStack::PushL(smsMessage); - - //Update sms messages's properties. - smsMessage->SetStorage(aSmsMessage.Storage()); - smsMessage->SetStatus((NMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status()); - smsMessage->SetLogServerId(aSmsMessage.LogServerId()); - smsMessage->SetTime(aSmsMessage.Time()); - smsMessage->SetUTCOffset(aSmsMessage.UTCOffset()); - smsMessage->SetDecodedOnSIM(aSmsMessage.DecodedOnSim()); - smsMessage->SetForwardToClient(aSmsMessage.ForwardToClient()); - smsMessage->SetToFromAddressL(aSmsMessage.ToFromAddress()); - - CBufSeg* recvbufseg = CBufSeg::NewL(KSmsMaxSegmentLength); - CleanupStack::PushL(recvbufseg); - // Attempt to serialize this message into the buffer - RBufWriteStream writestream(*recvbufseg); - writestream.Open(*recvbufseg); - CleanupClosePushL(writestream); - writestream << *smsMessage; - - // Initialize the read stream with the buffer - RBufReadStream readstream(*recvbufseg); - readstream.Open(*recvbufseg,0); - CleanupClosePushL(readstream); - // De-serialize the message from using the read stream - readstream >> aSmsMessage; - CleanupStack::PopAndDestroy(4); //readstream, writestream, recvbufseg, smsMessage - } - } - } - } - -/* -It returns when the next timeout should occur. -*/ -void CClass0SmsReassemblyStore::GetNextGuardTimeout(TTime& aNextTimeout) - { - TTime curTime; - curTime.UniversalTime(); - TTimeIntervalSeconds timeOutInSecs = iGuardTimeOut*3600; - aNextTimeout = curTime + timeOutInSecs; - - TInt class0ReassemblyStoreCount = iEntryArray.Count(); - - if (class0ReassemblyStoreCount > 0) - { - for (TInt i=0; i curTime) && - (guradTimeout < aNextTimeout)) - { - aNextTimeout = guradTimeout; - } - } - } - } - -/* -It returns the index of oldest message in class 0 re-assembly store. -*/ -TInt CClass0SmsReassemblyStore::GetIndexOfOldestMessage() - { - TInt index = 0; - TTime time = iEntryArray[index].Time(); - for (TInt index2=1; index2 < iEntryArray.Count(); index2++) - { - if (iEntryArray[index2].Time() < time) - { - index = index2; - } - } - return index; - } - -/* -It returns the index of oldest message in class 0 re-assembly store. -*/ -TInt CClass0SmsReassemblyStore::GetIndexOfOldestMessageFromReservedFileL() - { - TInt index = KErrNotFound; - //Find the index of oldest message in pre-allocated file. - index = iPreallocatedFile->GetOldestMessageEntryIndex(); - if (index == KErrNotFound) - { - //This condition should never arise - User::Leave(KErrNotFound); - } - - //Compare the oldest pre-allocated message entry against class 0 reassembly store entry - //and return the index of class 0 reassembly store entry. - const TSmsPreAllocatedFileStoreReassemblyEntry& preAllocatedFileEntry = iPreallocatedFile->Entries()[index]; - - TInt reassemblyCount = iEntryArray.Count(); - TInt count; - for (count = 0; count < reassemblyCount; count++) - { - TReassemblyEntry& entry = iEntryArray[count]; - - if (entry.Reference() == preAllocatedFileEntry.Reference() && - entry.Total() == preAllocatedFileEntry.Total() && - entry.PduType() == preAllocatedFileEntry.PduType() && - entry.Storage() == preAllocatedFileEntry.Storage() && - entry.Description2() == preAllocatedFileEntry.Description2()) - { - // - // Found it! - // - index = count; - break; - } - } - if (count == reassemblyCount) - { - //This condition should never arise - User::Leave(KErrNotFound); - } - return index; - } - -/* -It returns a boolean value indicating whether the limitation (max class 0 message, -max pdu stored in pre-allocated file) imposed on class 0 reassembly store exceeds or not. -*/ -TBool CClass0SmsReassemblyStore::IsExceedLimitation() - { - TInt class0MsgCount = iEntryArray.Count(); - TInt noOfMsgStoredInPreAllocatedFile = iPreallocatedFile->NumberOfPDUStored(); - if ((class0MsgCount > iMaxClass0Msg) - || (noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg)) - { - return ETrue; - } - - return EFalse; - } - -/* -This sorting algorithm is based on bubble sort -*/ -void CClass0SmsReassemblyStore::SortPDUsL(CArrayFix& aIndexArray, CArrayFix& aSmsArray) - { - //Test---Index array count must be equal to sms array count - TBool swapped; - - do - { - swapped = EFalse; - for (TInt i=0; i aIndexArray[i+1]) - { - aSmsArray.InsertL(i, aSmsArray[i+1]); - aSmsArray.Delete(i+2); - aIndexArray.InsertL(i, aIndexArray[i+1]); - aIndexArray.Delete(i+2); - swapped = ETrue; - } - } - } - while (swapped); - } - -/** - * Utility func for cleanup stack - */ -void CClass0StoreCloseObject(TAny* aObj) - { - LOGGSMU2("WARNING! Hey, CClass0StoreCloseObject called by Untrapper! [0x%08x]", aObj); - ((CClass0SmsReassemblyStore*)aObj)->Revert(); - } - -/** - * Sets the class 0 re-assembly store as in-transaction. - * - * The function checks the validity of the call and leaves KErrAccessDenied if - * invalid. - * @capability None - */ -void CClass0SmsReassemblyStore::BeginTransactionLC() - { - LOGSMSPROT3("CClass0SmsReassemblyStore::BeginTransactionLC [this=0x%08X iInTransaction=%d]", this, iInTransaction); - - if (iInTransaction) - { - LOGGSMU1("WARNING CClass0SmsReassemblyStore::BeginTransactionLC leaving with KErrAccessDenied"); - User::Leave(KErrAccessDenied); - } - - TCleanupItem class0StoreClose(CClass0StoreCloseObject, this); - CleanupStack::PushL(class0StoreClose); - iPreallocatedFile->BeginTransactionL(); - iPermanentFileStore->BeginTransactionL(); - iInTransaction = ETrue; - } - -/** - * It commits the transaction. - */ -void CClass0SmsReassemblyStore::CommitTransactionL() - { - LOGSMSPROT3("CClass0SmsReassemblyStore::CommitTransactionL(): this=0x%08X iInTransaction=%d", - this, iInTransaction); - - //Commit permanent store file - iPermanentFileStore->CommitTransactionL(); - //Commit pre-allocated file - iPreallocatedFile->CommitTransactionL(); - CleanupStack::Pop(this); //CClass0StoreCloseObject - iInTransaction = EFalse; - } - -/** - * It reverts the transaction. - */ -void CClass0SmsReassemblyStore::Revert() - { - LOGSMSPROT3("CClass0SmsReassemblyStore::Revert(): this=0x%08X, iInTransaction=%d", - this, iInTransaction); - - iPreallocatedFile->Revert(); - iPermanentFileStore->Revert(); - iInTransaction = EFalse; - } +// Copyright (c) 2007-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 CPreallocatedFile. +// +// + +/** + @file +*/ +#include "smspclass0stor.h" +#include "gsmubuf.h" +#include "gsmunonieoperations.h" + +const TInt KSizeOfPreallocatedFileVersion = sizeof(CPreallocatedFile::TPreAllocatedFileVersion); +const TInt KSizeOfNumberOfEntrySection = sizeof(TInt); +//size of 32-bit checksum +const TInt KSizeOfChecksum = sizeof(TUint32); +const TInt KSizeOfPreAllocatedStoreEntry = sizeof(TSmsPreAllocatedFileStoreReassemblyEntry); +const TInt KSizeOfGsmSmsSlotEntry = sizeof(TGsmSmsSlotEntry); +const TInt KSizeOfIndexEntry = sizeof(TInt); +const TInt KSizeOfSmsGsmPDU = sizeof(RMobileSmsMessaging::TMobileSmsGsmTpdu); +const TInt KSizeOfAContainer = KSizeOfGsmSmsSlotEntry + KSizeOfIndexEntry + KSizeOfSmsGsmPDU; +const TInt KBeginOfMasterHeaderSection = KSizeOfPreallocatedFileVersion; + +/** +Static factory constructor. Uses two phase +construction and leaves nothing on the CleanupStack. + +@param aFs File Server handle. +@param aFileName Permanent file store name. +@param aThirdUid Uid of file. +@leave KErrNoMemory + +@return A pointer to the newly created CSmsPermanentFileStore object. + +@pre A connected file server session must be passed as parameter. +@post CSmsPermanentFileStore object is now fully initialised + +@internalComponent +*/ +CSmsPermanentFileStore* CSmsPermanentFileStore::NewL(RFs& aFs, const TDesC& aFileName, const TUid& aThirdUid) + { + LOGSMSPROT1("CSmsPermanentFileStore::NewL()"); + CSmsPermanentFileStore* self = new (ELeave) CSmsPermanentFileStore(aFs, aThirdUid); + CleanupStack::PushL(self); + self->ConstructL(aFileName); + CleanupStack::Pop(self); + + return self; + } + +void CSmsPermanentFileStore::ConstructL(const TDesC& aFileName) + { + LOGSMSPROT1("CSmsPermanentFileStore::ConstructL()"); + iFileName = aFileName.AllocL(); + } + +/** + * Constructor. +*/ +CSmsPermanentFileStore::CSmsPermanentFileStore(RFs& aFs, const TUid& aThirdUid) + : iFs(aFs), iFileName(NULL), iThirdUid(aThirdUid), iFileStore(NULL), iEntryArray(KFlatArrayGranularity) + { + } + +/** + * Destructor. It destroys all the member variables. +*/ +CSmsPermanentFileStore::~CSmsPermanentFileStore() + { + delete iFileName; + } + +/** +It checks & returns whether the file exist or not. If file is there whether +it is corrupted or not. + +@internalComponent +*/ +TBool CSmsPermanentFileStore::IsFileOK() + { + TBool retBool(EFalse); + TUidType uidtype(KPermanentFileStoreLayoutUid,KSARStoreUid,iThirdUid); + TEntry entry; + TInt ret=iFs.Entry(iFileName->Des(), entry); + // Check file existence & corruption + if ((ret == KErrNone) && (entry.iType == uidtype)) + { + retBool = ETrue; + } + return retBool; + } + +/** +It creates a permanent store file. + +@internalComponent +*/ +void CSmsPermanentFileStore::CreateL() + { + LOGSMSPROT1("CSmsPermanentFileStore::CreateL()"); + TUidType uidtype(KPermanentFileStoreLayoutUid,KSARStoreUid,iThirdUid); + iFileStore=CPermanentFileStore::ReplaceL(iFs, iFileName->Des(), EFileShareExclusive|EFileStream|EFileRead|EFileWrite); + iFileStore->SetTypeL(uidtype); + iEntryArray.Reset(); + ExternalizeEntryArrayL(); + iFileStore->CommitL(); + // Close it to make sure that file is created correctly (defensive approach). + Close(); + //Again Open the file + OpenL(); + } + +/** +It opens the permanent store file and internalizes the entries. + +@internalComponent +*/ +void CSmsPermanentFileStore::OpenL() + { + LOGSMSPROT1("CSmsPermanentFileStore::OpenL()"); + iFileStore=CPermanentFileStore::OpenL(iFs,iFileName->Des(),EFileShareExclusive|EFileStream|EFileRead|EFileWrite); + InternalizeEntryArrayL(); + } + +/** +It closes the permanent store file. + +@internalComponent +*/ +void CSmsPermanentFileStore::Close() + { + LOGSMSPROT1("CSmsPermanentFileStore::Close()"); + delete iFileStore; + iFileStore = NULL; + iEntryArray.Reset(); + } + +/* +This function cleans its entries against the passed entries. +This is needed because there might be a scenario where user has deleted a message +but the corresponding message is not deleted from permanent store file +due to out-of-disk condition. But the entry is invalid because +it is no more in the pre-allocated file which contains master header info. +And also at the time of forwarding an incomplete message a forwarded +message has not been deleted due to above reason. +This function also compacts the store after deletion. + +@param aEntryArray entray array against whose clean up is carried out. + +@internalComponent +*/ +void CSmsPermanentFileStore::CleanupEntriesWithCompactL(const CArrayFix& aEntryArray) + { + // Ignore in code coverage - a previous CleanupEntries would need to have failed with KErrDiskFull + BULLSEYE_OFF + LOGSMSPROT1("CSmsPermanentFileStore::CleanupEntriesWithCompactL()"); + + iCompact = ETrue; + CleanupEntriesL(aEntryArray); + BULLSEYE_RESTORE + } + +/* +This function cleans its entries against the passed entries. +This is needed because there migth be a scenario where user has deleted a message +but the corresponding message is not deleted from permanent store file +due to out-of-disk condition. But the entry is invalid because +it is no more in the pre-allocated file which contains master header info. +And also at the time of forwarding an incomplete message a forwarded +message has not been deleted due to above reason. + +@param aEntryArray entray array against whose clean up is carried out. + +@internalComponent +*/ +void CSmsPermanentFileStore::CleanupEntriesL(const CArrayFix& aEntryArray) + { + LOGSMSPROT1("CSmsPermanentFileStore::CleanupEntriesL()"); + + TInt reassemblyCount = iEntryArray.Count(); + TInt index, index2; + + for (index = 0; index < reassemblyCount; index++) + { + for (index2 = 0; index2 < aEntryArray.Count(); index2++) + { + if (iEntryArray[index].Reference() == aEntryArray[index2].Reference() && + iEntryArray[index].Total() == aEntryArray[index2].Total() && + iEntryArray[index].PduType() == aEntryArray[index2].PduType() && + iEntryArray[index].Storage() == aEntryArray[index2].Storage() && + iEntryArray[index].Description2() == aEntryArray[index2].Description2()) + { + if (aEntryArray[index2].NumberOfPDUsForwardToClient() > 0) + { + //Internalize the entries. + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); + CleanupStack::PushL(smsMessage); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + InternalizeEntryL(index, *smsMessage, *indexArray, *smsArray); + TInt noOfForwardedEntries = 0; + for (TInt j=indexArray->Count(); j>0 ;j--) + { + TUint8 bitMapIndex = (indexArray->At(j-1)-1)/8; + TUint8 bitPos = (indexArray->At(j-1)-1)%8; + TUint8 bitMap; + TSmsPreAllocatedFileStoreReassemblyEntry entry; + entry = aEntryArray[index2]; + entry.GetBitMap(bitMapIndex, bitMap); + TUint8 tmpBitMap = 1; + tmpBitMap <<= bitPos; + if (tmpBitMap == (bitMap & tmpBitMap)) + { + noOfForwardedEntries++; + indexArray->Delete(j-1); + smsArray->Delete(j-1); + } + } + if (noOfForwardedEntries > 0) + { + TStreamId streamId = iEntryArray[index].DataStreamId(); + ExternalizeEntryL(streamId, *smsMessage, *indexArray, *smsArray); + } + CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray + } + break; + } + } + if (index2 == aEntryArray.Count()) + { + DeleteEntryL(index); + } + } + } + +/** +It internalizes its entry array. + +@internalComponent +*/ +void CSmsPermanentFileStore::InternalizeEntryArrayL() + { + LOGSMSPROT1("CSmsPermanentFileStore::InternalizeEntryArrayL()"); + + iEntryArray.Reset(); + TStreamId headerid=iFileStore->Root(); + RStoreReadStream stream; + stream.OpenLC(*iFileStore,headerid); + TInt count=stream.ReadInt32L(); + for (TInt i=0; i> sarentry; + iEntryArray.AppendL(sarentry); + } + CleanupStack::PopAndDestroy(); // stream + } + +/** +It externalizes its entry array. + +@internalComponent +*/ +void CSmsPermanentFileStore::ExternalizeEntryArrayL() + { + LOGSMSPROT4("CSmsPermanentFileStore::ExternalizeEntryArrayL(): this=0x%08X count=%d headerid=%d]", + this, iEntryArray.Count(), iFileStore->Root().Value()); + + TStreamId headerid=iFileStore->Root(); + RStoreWriteStream stream; + if (headerid==KNullStreamId) + { + headerid=stream.CreateLC(*iFileStore); + iFileStore->SetRootL(headerid); + } + else + { + stream.ReplaceLC(*iFileStore,headerid); + } + + TInt count1=iEntryArray.Count(); + TInt count2=0; + TInt i=0; + + for (; i* indexArray=new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray=new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + //Index must initialize to 0. + TInt index = 0; + if (!aSmsMessage.IsDecoded()) + { + index = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex(); + } + indexArray->AppendL(index); + smsArray->AppendL(aGsmSms); + + TStreamId streamid = KNullStreamId; + ExternalizeEntryL(streamid, aSmsMessage, *indexArray, *smsArray); + + TSmsReassemblyEntry tmpEntry; + //Fill-up entry information... + CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1); + // Update Data stream id. + tmpEntry.SetDataStreamId(streamid); + + aIndex = iEntryArray.Count(); + AddEntryL(tmpEntry); + CleanupStack::PopAndDestroy(2); //indexArray, smsArray + } + +/* +It updates the existing message in permanent store file. + +@param aIndex index number on which message is to be updated. +@param aSmsMessage reference to sms message to be updated. +@param aIndexArray array of index of all the PDUs. +@param aSmsArray array of sms of all the PDUs. + +@internalComponent +*/ +void CSmsPermanentFileStore::UpdateExistingMessageL(TInt aIndex, const CSmsMessage& aSmsMessage,const CArrayFix& aIndexArray,const CArrayFix& aSmsArray) + { + LOGSMSPROT1("CSmsPermanentFileStore::UpdateExistingMessageL()"); + TStreamId streamid = iEntryArray[aIndex].DataStreamId(); + ExternalizeEntryL(streamid, aSmsMessage, aIndexArray, aSmsArray); + TSmsReassemblyEntry entry; + CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, aSmsArray.Count()); + entry.SetDataStreamId(streamid); + ChangeEntryL(aIndex, entry); + } + +/* +It matches the entry with entry in permanent store file & returns +the index. If not found it returns KErrNotFound. + +@param aEntry reference to entry information. +@param aIndex (output) returns the index number. + +@internalComponent +*/ +void CSmsPermanentFileStore::MatchEntryToExistingMessage(const TReassemblyEntry& aEntry, + TInt& aIndex) + { + LOGSMSPROT1("CSmsPermanentFileStore::MatchEntryToExistingMessage()"); + + aIndex = KErrNotFound; + + // + // Search the reassembly store for a matching entry... + // + TInt reassemblyCount = iEntryArray.Count(); + for (TInt index = 0; index < reassemblyCount; index++) + { + TSmsReassemblyEntry& entry = iEntryArray[index]; + + if (entry.Reference() == aEntry.Reference() && + entry.Total() == aEntry.Total() && + entry.PduType() == aEntry.PduType() && + entry.Storage() == aEntry.Storage() && + entry.Description2() == aEntry.Description2()) + { + // + // Found it! + // + aIndex = index; + break; + } + } + + LOGSMSPROT2("CSmsPermanentFileStore::MatchEntryToExistingMessage(): aIndex=%d", aIndex); + } + +/* +It updates the log server id of the message. + +@param aIndex index number of the message to be updated. +@param aLogServerId log server id. + +@internalComponent +*/ +void CSmsPermanentFileStore::UpdateLogServerIdL(TInt& aIndex, TLogId aLogServerId) + { + LOGSMSPROT1("CSmsPermanentFileStore::UpdateLogServerIdL"); + + TSmsReassemblyEntry entry; + entry = iEntryArray[aIndex]; + + if (entry.LogServerId() != aLogServerId) + { + entry.SetLogServerId(aLogServerId); + ChangeEntryL(aIndex, entry); + } + } + +/* +It sets the message passed to client or not. + +@param aIndex index number of the message to be updated. +@param aBool boolean value indicating whether message is passes or not. + +@internalComponent +*/ +void CSmsPermanentFileStore::SetPassedToClientL(TInt aIndex, TBool aBool) + { + LOGSMSPROT2("CSmsPermanentFileStore::SetPassedToClientL(): aIndex=%d", aIndex); + + TSmsReassemblyEntry entry; + entry = iEntryArray[aIndex]; + + if (entry.PassedToClient() != aBool) + { + entry.SetPassedToClient(aBool); + ChangeEntryL(aIndex, entry); + } + } + +/* +It adds the new entry in the existing entry array. + +@param aEntry entry to be added. + +@internalComponent +*/ +void CSmsPermanentFileStore::AddEntryL(TSmsReassemblyEntry& aEntry) + { + iEntryArray.AppendL(aEntry); + iEntryArray[iEntryArray.Count()-1].SetIsAdded(ETrue); + } + +/* +It changes the existing entry with new entry. + +@param aIndex index number of the entry which will be changed. +@param aNewEntry entry to be updated. + +@internalComponent +*/ +void CSmsPermanentFileStore::ChangeEntryL(TInt aIndex,const TSmsReassemblyEntry& aNewEntry) + { + LOGSMSPROT2("CSmsPermanentFileStore::ChangeEntryL(): aIndex=%d", aIndex); + + iEntryArray[aIndex].SetIsDeleted(ETrue); + iEntryArray.InsertL(aIndex,aNewEntry); + iEntryArray[aIndex].SetIsAdded(ETrue); + } + +/* +It deletes the entry. + +@param aIndex index number of the entry which will be deleted. + +@internalComponent +*/ +void CSmsPermanentFileStore::DeleteEntryL(TInt aIndex) + { + iFileStore->DeleteL(iEntryArray[aIndex].DataStreamId()); + iEntryArray[aIndex].SetIsDeleted(ETrue); + } + +/* +It externalizes(writes) the entry in permanent store file. + +@param aStreamId stream id which needs to externalized. +@param aSmsMessage reference to sms message which needs to be externalized. +@param aIndexArray refence to array of index which needs to be externalized. +@param aSmsArray refence to array of sms which needs to be externalized. + +@internalComponent +*/ +void CSmsPermanentFileStore::ExternalizeEntryL(TStreamId& aStreamId,const CSmsMessage& aSmsMessage,const CArrayFix& aIndexArray,const CArrayFix& aSmsArray) + { + LOGSMSPROT2("CSmsPermanentFileStore::ExternalizeEntryL Start [sid=%d]", aStreamId.Value()); + + RStoreWriteStream writestream; + if (aStreamId==KNullStreamId) + aStreamId=writestream.CreateLC(*iFileStore); + else + writestream.ReplaceLC(*iFileStore,aStreamId); + writestream << aSmsMessage; + TInt count=aIndexArray.Count(); + writestream.WriteInt32L(count); + TInt i=0; + for (; i& aIndexArray, CArrayFix& aSmsArray) + { + TSmsReassemblyEntry& entry = iEntryArray[aIndex]; + LOGSMSPROT2("CSmsPermanentFileStore::InternalizeEntryL Start [sid=%d]", entry.DataStreamId().Value()); + RStoreReadStream readstream; + readstream.OpenLC(*iFileStore, entry.DataStreamId()); + readstream >> aSmsMessage; + TInt count=readstream.ReadInt32L(); + TInt i; + for (i=0; i> pdu; + TGsmSms sms; + sms.SetPdu(pdu); + aSmsArray.AppendL(sms); + } + CleanupStack::PopAndDestroy(); + //Set other properties of CSmsMessage + aSmsMessage.SetStorage(entry.Storage()); + aSmsMessage.SetLogServerId(entry.LogServerId()); + aSmsMessage.SetTime(entry.Time()); + LOGSMSPROT2("CSmsPermanentFileStore::InternalizeEntryL End [count=%d]", count); + } + +/* +It removes the PDUs from permanent store file. +This function is needed because after forwarding the incomplete message +to client, the corresponding PDUs needs to be be removed from permanent +store file. +This functionality is specific to class 0 re-assembly store. + +@param aIndex index number of the message to be removed. +@param aStartPos starting pos of pdu to be removed. +@param aEndPos end pos of pdu to be removed. + +@internalComponent +*/ +void CSmsPermanentFileStore::RemovePDUsL(TInt aIndex, TInt aStartPos, TInt aEndPos) + { + LOGSMSPROT1("CSmsPermanentFileStore::RemovePDUsL"); + + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); + CleanupStack::PushL(smsMessage); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + InternalizeEntryL(aIndex, *smsMessage, *indexArray, *smsArray); + + TInt count = indexArray->Count(); + for (TInt i=count; i>0; i--) + { + if ((indexArray->At(i-1) >= aStartPos) && (indexArray->At(i-1) <= aEndPos)) + { + indexArray->Delete(i-1); + smsArray->Delete(i-1); + } + } + + /* + There are 3 scenarios in this case: + 1. If all the entries are removed, + then there is no need to store the entry in this permanent file. + 2. If few entries are removed, + then externalize the remaining entries. Update count field also. + 3. If no entries are removed, then do nothing. + */ + if (indexArray->Count()==0) + { + DeleteEntryL(aIndex); + } + else if (count!=indexArray->Count()) + { + TStreamId streamid = iEntryArray[aIndex].DataStreamId(); + ExternalizeEntryL(streamid, *smsMessage, *indexArray, *smsArray); + + TSmsReassemblyEntry entry; + entry = iEntryArray[aIndex]; + entry.SetCount(indexArray->Count()); + ChangeEntryL(aIndex, entry); + } + CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray + } + +/** + * Sets the permanent store as in-transaction. + * + * The function checks the validity of the call and leaves KErrAccessDenied if + * invalid. + * @capability None + */ +void CSmsPermanentFileStore::BeginTransactionL() + { + LOGSMSPROT4("CSmsPermanentFileStore::BeginTransactionL [this=0x%08X iInTransaction=%d iFileStore=0x%08X]", this, iInTransaction, iFileStore); + + if (iFileStore == NULL || iInTransaction) + { + LOGSMSPROT1("WARNING CSmsPermanentFileStore::BeginTransactionL leaving with KErrAccessDenied"); + User::Leave(KErrAccessDenied); + } + + iInTransaction = ETrue; + } // CSmsPermanentFileStore::BeginTransactionL + +/** + * It reverts the transaction. + */ +void CSmsPermanentFileStore::Revert() + { + LOGSMSPROT3("CSmsPermanentFileStore::Revert(): this=0x%08X, iInTransaction=%d", + this, iInTransaction); + + iFileStore->Revert(); + iInTransaction = EFalse; + ReinstateDeletedEntries(); + } // CSmsPermanentFileStore::Revert + +/** + * It commits the transaction. Then it compact the permanent store file. + */ +void CSmsPermanentFileStore::DoCommitAndCompactL() + { + LOGSMSPROT1("CSmsPermanentFileStore::DoCommitAndCompactL()"); + + LOGSMSPROTTIMESTAMP(); + iFileStore->CommitL(); + LOGSMSPROTTIMESTAMP(); + + iCommitCount--; + if ((iCommitCount < 0) || (iCompact)) + { + iCommitCount = KNumStoreCommitsBeforeCompaction; + iFileStore->CompactL(); + iFileStore->CommitL(); + iCompact = EFalse; + } + } // CSmsPermanentFileStore::DoCommitAndCompactL + +/** + * It commits the transaction. + */ +void CSmsPermanentFileStore::CommitTransactionL() + { + LOGSMSPROT4("CSmsPermanentFileStore::CommitTransactionL(): this=0x%08X iInTransaction=%d iFileStore=0x%08X", + this, iInTransaction, iFileStore); + + ExternalizeEntryArrayL(); + +#ifdef _SMS_LOGGING_ENABLED + TRAPD(err, DoCommitAndCompactL()); + if (err != KErrNone) + { + LOGGSMU2("WARNING! could not CommitL/CompactL due to %d", err); + User::Leave(err); + } +#else + DoCommitAndCompactL(); +#endif + + iInTransaction = EFalse; + RemoveDeletedEntries(); + } + +/** + * It removes the deleted entries from entry arry. + * This function is called after commit. + */ +void CSmsPermanentFileStore::RemoveDeletedEntries() + { + LOGSMSPROT1("CSmsPermanentFileStore::RemoveDeletedEntries()"); + + TInt count=iEntryArray.Count(); + while (count--) + { + TSmsReassemblyEntry& entry = iEntryArray[count]; + + if (entry.IsDeleted()) + { + iEntryArray.Delete(count); + } + else + { + entry.SetIsAdded(EFalse); + } + } + } // CSmsPermanentFileStore::RemoveDeletedEntries + +/** + * It reinstate the deleted/added entries from entry arry. + * This function is called after revert operation. + */ +void CSmsPermanentFileStore::ReinstateDeletedEntries() + { + LOGSMSPROT1("CSmsPermanentFileStore::ReinstateDeletedEntries()"); + + TInt count=iEntryArray.Count(); + while (count--) + { + TSmsReassemblyEntry& entry = iEntryArray[count]; + + if (entry.IsAdded()) + { + iEntryArray.Delete(count); + } + else + { + entry.SetIsDeleted(EFalse); + } + } + } // CSmsPermanentFileStore::ReinstateDeletedEntries + +/** + * Constructor + * + * @capability None + */ +TSmsPreAllocatedFileStoreReassemblyEntry::TSmsPreAllocatedFileStoreReassemblyEntry(): + TSmsReassemblyEntry(), + iPreAllocatedStorageId(0), + iStatus(RMobileSmsStore::EStoredMessageUnknownStatus), + iTimeOffset(0), + iDecodedOnSim(EFalse), + iForwardToClient(EFalse), + iForwardedCount(0), + iBitMap(NULL) + { + //Have to externalize so initialize to 0. + for (TInt i=0; iConstructL(aFileName); + CleanupStack::Pop(self); + + return self; + } + +void CPreallocatedFile::ConstructL(const TDesC& aFileName) + { + LOGSMSPROT1("CPreallocatedFile::ConstructL()"); + iFileName = aFileName.AllocL(); + } + +/** + * Constructor. +*/ +CPreallocatedFile::CPreallocatedFile(RFs& aFs, TInt aMaxClass0Msg, TInt aMaxPDUSeg, TPreAllocatedFileVersion aVersion) + :iFs(aFs), iEntryArray(KFlatArrayGranularity), iReinstateEntryInfo(KFlatArrayGranularity), iMaxClass0Msg(aMaxClass0Msg), iMaxPDUSeg(aMaxPDUSeg), iVersion(aVersion) + { + /* + Format of File: + Version Number, Header Section & Data Section + Version Number - Interger Value. + Header Section: Number of entries, Array of Entries, Array of PDU identifier section, Checksum. + Data Section: Array of Container. Each container contains Sms slot informatiuon, index number & PDU. + */ + + // Calculate the size of each section. + + // Entry section will always contain one more entry than configured one by the user. + // Because it will provide one extra slot to store the new message for time being + // before forwarding the oldest message. + iSizeOfEntrySection = (KSizeOfPreAllocatedStoreEntry * (iMaxClass0Msg + 1)); + + iSizeOfStorageIdentifierSection = ((sizeof(TInt))*(iMaxPDUSeg+1)); + + TInt sizeOfHeaderSection = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + KSizeOfChecksum; + + TInt sizeOfDataSection = KSizeOfAContainer * (iMaxPDUSeg+1); + + // Calculate the size of File. + iSizeOfFile = KSizeOfPreallocatedFileVersion + 2 * sizeOfHeaderSection + sizeOfDataSection; + + iBeginOfDuplicateHeaderSection = KSizeOfPreallocatedFileVersion + sizeOfHeaderSection; + iBeginOfDataSection = KSizeOfPreallocatedFileVersion + 2 * sizeOfHeaderSection; + } + +/** + * Destructor. It destroys all the member variables. +*/ +CPreallocatedFile::~CPreallocatedFile() + { + delete iFileName; + } + +/** +It checks & returns whether the file exist or not. If file is there whether +it is corrupted or not. + +@internalComponent +*/ +TBool CPreallocatedFile::IsFileOK() + { + LOGSMSPROT1("CPreallocatedFile::IsFileOK()"); + + TEntry entry; + // Check file exists + TInt ret=iFs.Entry(iFileName->Des(), entry); + // Check the size of file, if size does not match then assume that file + // is corrupted, then return KErrNotFound. + if ((ret == KErrNone) && (entry.iSize != iSizeOfFile)) + { + ret = KErrNotFound; + } + + if (ret == KErrNone) + { + return ETrue; + } + else + { + return EFalse; + } + } + +/** +It creates a pre-allocated file. + +@internalComponent +*/ +void CPreallocatedFile::CreateL() + { + LOGSMSPROT1("CPreallocatedFile::CreateL"); + + User::LeaveIfError(iFile.Replace(iFs, iFileName->Des(), EFileWrite)); + User::LeaveIfError(iFile.SetSize(iSizeOfFile)); + iFile.Flush(); + + // Externalize Version Number + //TInt version = iVersion; + TPtr8 memPtr((TUint8*) &iVersion, KSizeOfPreallocatedFileVersion, KSizeOfPreallocatedFileVersion); + iFile.Write(0, memPtr); + + //Externalize Header Information + ExternalizeEntryArray(); + + // Initialize Storage Identifier Section. + TInt storageIdentifier=0; + memPtr.Set((TUint8*) &storageIdentifier, sizeof(storageIdentifier), sizeof(storageIdentifier)); + TInt pos = KSizeOfNumberOfEntrySection + iSizeOfEntrySection; + TInt pos2 = 0; + for (TInt count=0; countDes(), EFileShareExclusive|EFileRead|EFileWrite)); + // Check the validity of the data. + CheckDataL(); + // Internalize data + InternalizeEntryArrayL(); + } + +/** +It closes the pre-allocated file. + +@internalComponent +*/ +void CPreallocatedFile::Close() + { + iFile.Close(); + iEntryArray.Reset(); + iReinstateEntryInfo.Reset(); + } + +/** +It internalizes the entry info from pre-allocated file. + +@internalComponent +*/ +void CPreallocatedFile::InternalizeEntryArrayL() + { + iEntryArray.Reset(); + TInt numberOfMessage; + TPtr8 memPtr((TUint8*) &numberOfMessage, sizeof(numberOfMessage), sizeof(numberOfMessage)); + iFile.Read(KBeginOfMasterHeaderSection, memPtr); + + TSmsPreAllocatedFileStoreReassemblyEntry tmpClass0ReassemblyStore; + memPtr.Set((TUint8*) &tmpClass0ReassemblyStore, KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry); + + TInt pos = 0; + for (TInt count=0; count < numberOfMessage; count++) + { + pos = sizeof(TInt) + (count * KSizeOfPreAllocatedStoreEntry); + iFile.Read(KBeginOfMasterHeaderSection + pos, memPtr); + iEntryArray.AppendL(tmpClass0ReassemblyStore); + } + } + +/** +It externalizes the entry info to pre-allocated file. + +@internalComponent +*/ +void CPreallocatedFile::ExternalizeEntryArray() + { + TInt count=iEntryArray.Count(); + TInt numberOfMessage=0; + TInt i=0; + + for (; i= aNumberOfPDUs) + { + break; + } + } + iFile.Flush(); + } + +/* +It updates the storage identifier section. It updates the corresponding container +in the storage identifier section specifying the PDU where it is stored. + +NOTE: + It keeps the record of added entries in iReinstateEntryInfo variable. + It will be required in case of revert operation. + After commiting the transaction, this varaible should be re-initialized. + +@param aIndex index number of the container where PDU has been stored.. +@param aStorageId unique id of added message. + +@internalComponent +*/ +void CPreallocatedFile::AddStorageIdL(TInt aIndex, TInt aStorageId) + { + //Put storage id in master header section + TPtr8 memPtr((TUint8*) &aStorageId, sizeof(aStorageId), sizeof(aStorageId)); + TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; + iFile.Write( beginOfStorageIdentifierSection + ((aIndex - 1) * sizeof(TInt)), memPtr); + + TReinstateEntryInfo entry; + entry.iContainerId=aIndex; + entry.iPreAllocatedStorageId=aStorageId; + entry.iFlag=EEntryIsAdded; + iReinstateEntryInfo.AppendL(entry); + } + +/* +It returns the next free available free container where next PDU can be stored. + +It goes through storage identifier section, it reads the conents of all storage +identfier & return that container which is free. +All the free container is identifiable by value 0. If the value is not 0 then it +contains the storage id of a particular message. + +@internalComponent +*/ +TInt CPreallocatedFile::GetFreeContainer() + { + // Get the next free slot. + TInt storageId; + TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); + TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; + TInt beginOfStorageId = 0; + TInt count; + + for (count=0; count& aIndexArray, CArrayFix& aSmsArray) + { + LOGSMSPROT1("CPreallocatedFile::InternalizeEntryL"); + TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[aIndex]; + //Set other properties of CSmsMessage + aSmsMessage.SetStorage(entry.Storage()); + aSmsMessage.SetStatus((NMobileSmsStore::TMobileSmsStoreStatus)entry.Status()); + aSmsMessage.SetLogServerId(entry.LogServerId()); + aSmsMessage.SetTime(entry.Time()); + aSmsMessage.SetUTCOffset(entry.UTCOffset()); + aSmsMessage.SetDecodedOnSIM(entry.DecodedOnSIM()); + aSmsMessage.SetForwardToClient(entry.ForwardToClient()); + aSmsMessage.SetToFromAddressL(entry.Description2()); + + LOGSMSPROT2("CPreallocatedFile::InternalizeEntryL Start [sid=%d]", entry.PreAllocatedStorageId()); + if (entry.PreAllocatedStorageId()==KErrNotFound) + { + return; + } + + TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; + //This will be used to read the storgae id which will indicate + //that corresponding container contains actual PDU + TInt storageId=0; + TPtr8 memPtr1((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); + + TInt storageIdPos = 0; + TInt dataPos = 0; + //This will be used to read the slot information + TGsmSmsSlotEntry smsSlotEntry; + TPtr8 memPtr2((TUint8*) &smsSlotEntry, KSizeOfGsmSmsSlotEntry, KSizeOfGsmSmsSlotEntry); + //This will be used to read the concatenated PDU index. + TInt index=0; + TPtr8 memPtr3((TUint8*) &index, sizeof(index), sizeof(index)); + //This will be used to read PDU. + RMobileSmsMessaging::TMobileSmsGsmTpdu pdu; + TPtr8 memPtr4((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU); + TGsmSms sms; + + //Number of PDUs stored in this pre-allocated file + TInt noOfPDUs = iEntryArray[aIndex].Count(); + //Will indicate how many number of PDUs already read from pre-allocated file. + TInt noOfPDUsRead = 0; + // Can also get the number of pdu stored in pre-allocated file from count's variable. + for (TInt count=0; count 256) || (aStartPos > aEndPos)) + { + User::Leave(KErrArgument); + } + + LOGSMSPROT2("CPreallocatedFile::RemovePDUsL Start [sid=%d]", iEntryArray[aIndex].PreAllocatedStorageId()); + if (iEntryArray[aIndex].PreAllocatedStorageId()==KErrNotFound) + { + return; + } + + TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection; + //This will be used to read the storgae id which will indicate + //that corresponding container contains actual PDU + TInt storageId=0; + TPtr8 memPtr1((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); + + //This will be used to cleanup the storage id. + TInt cleanStorageId=0; + TPtr8 memPtr2((TUint8*) &cleanStorageId, sizeof(cleanStorageId), sizeof(cleanStorageId)); + + //This will be used to read the concatenated PDU index. + TInt index=0; + TPtr8 memPtr3((TUint8*) &index, sizeof(index), sizeof(index)); + + //Number of PDUs stored in this pre-allocated file + TInt noOfPDUs = iEntryArray[aIndex].Count(); + //Will indicate how many number of PDUs already read from pre-allocated file. + TInt noOfPDUsRead = 0; + // Can also get the number of pdu stored in pre-allocated file from count's variable. + TInt noOfEntriesRemoved=0; + for (TInt count=0; count= aStartPos) && (index <= aEndPos)) + { + noOfEntriesRemoved++; + //Remove the PDU entry. + iFile.Write(storageIdPos, memPtr2); + } + + if (noOfPDUsRead == noOfPDUs) + { + break; + } + } + } + + /* + There are 3 scenarios in this case: + 1. If all the entries need to be removed, + then there is no need to store the entry in this permanent file. + 2. If few entries need to be removed, + then externalize the remaining entries. Update count field also. + 3. If no entries need to be removed, then do nothing. + */ + TSmsPreAllocatedFileStoreReassemblyEntry entry; + entry = iEntryArray[aIndex]; + + if (entry.Count() == noOfEntriesRemoved) + { + entry.SetPreAllocatedStorageId(KErrNotFound); + entry.SetCount(0); + ChangeEntryL(aIndex, entry); + } + else if (noOfEntriesRemoved > 0) + { + entry.SetCount(entry.Count() - noOfEntriesRemoved); + ChangeEntryL(aIndex, entry); + } + } + +/* +It stores the forwarded message info in forwarded pdu bit-map. + +@param aIndex index number of the forwarded message. +@param aStartPos starting pos of forwarded pdu. +@param aEndPos end pos of forwarded pdu. + +@internalComponent +*/ +void CPreallocatedFile::StoreForwardedPDUsInfoL(TInt aIndex, TInt aStartPos, TInt aEndPos) + { + TSmsPreAllocatedFileStoreReassemblyEntry entry; + entry = iEntryArray[aIndex]; + + TUint8 startBitMapIndex = (aStartPos-1)/8; + TUint8 endBitMapIndex = (aEndPos-1)/8; + TUint8 startBitPos = (aStartPos-1)%8; + TUint8 endBitPos = (aEndPos-1)%8; + + if (startBitMapIndex == endBitMapIndex) + { + TUint8 bitMap; + entry.GetBitMap(startBitMapIndex, bitMap); + TUint8 tmpBitMap = (0 | 0xFF); + tmpBitMap <<= ((8 - endBitPos) - 1); + tmpBitMap >>= (8 - ((endBitPos - startBitPos)+1)); + tmpBitMap <<= startBitPos; + bitMap |= tmpBitMap; + entry.SetBitMap(startBitMapIndex, bitMap); + } + else + { + TUint8 bitMap; + entry.GetBitMap(startBitMapIndex, bitMap); + TUint8 tmpBitMap = (0 | 0xFF); + tmpBitMap >>= (8 - ((7 - startBitPos)+1)); + tmpBitMap <<= startBitPos; + bitMap |= tmpBitMap; + entry.SetBitMap(startBitMapIndex, bitMap); + + entry.GetBitMap(endBitMapIndex, bitMap); + tmpBitMap = (0 | 0xFF); + tmpBitMap <<= ((8 - endBitPos) - 1); + tmpBitMap >>= (8 - ((endBitPos - 0)+1)); + tmpBitMap <<= 0; + bitMap |= tmpBitMap; + entry.SetBitMap(endBitMapIndex, bitMap); + } + + TInt noOfForwardedPDUs = (aEndPos - aStartPos) + 1; + entry.SetNumberOfPDUsForwardToClient(entry.NumberOfPDUsForwardToClient()+noOfForwardedPDUs); + + ChangeEntryL(aIndex, entry); + } + +/* +It checks the validity of master header section by comparing checksum value. +If the checksum value does not match, then it copies data from duplicate header section to +master header section. +*/ +void CPreallocatedFile::CheckDataL() + { + TUint32 checksum; + TInt checksumPos = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection; + + TPtr8 memPtr((TUint8*) &checksum, sizeof(checksum), sizeof(checksum)); + iFile.Read(checksumPos, memPtr); + + if (ChecksumValue() != checksum) + { + CopyDuplicateToMasterL(); + } + } + +/* +It writes the checksum value & then copies header information from master section to duplicate section. +*/ +void CPreallocatedFile::PutChecksumValueL() + { + TUint32 checksum = ChecksumValue(); + TInt checksumPos = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection; + + TPtr8 memPtr((TUint8*) &checksum, sizeof(checksum), sizeof(checksum)); + iFile.Write(checksumPos, memPtr); + iFile.Flush(); + CopyMasterToDuplicateL(); + } + +/* +It calculates & returns the checksum value of master header section. +*/ +TUint32 CPreallocatedFile::ChecksumValue() + { + TInt sizeOfDataToBeChecksum = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection; + + TUint32 checksum(0); + + TUint32 tmpValue; + TPtr8 memPtr((TUint8*) &tmpValue, sizeof(tmpValue), sizeof(tmpValue)); + + for (TInt i = 0; i < sizeOfDataToBeChecksum/4 ; i++) + { + iFile.Read(KBeginOfMasterHeaderSection + (i*4), memPtr); + checksum += tmpValue; + } + return checksum; + } + +/* +It copies header information from master copy to duplicate copy. +*/ +void CPreallocatedFile::CopyMasterToDuplicateL() + { + TInt sizeOfDataToBeCopied = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + 4; + + HBufC8* heapBuffer = HBufC8::NewL(sizeOfDataToBeCopied); + CleanupStack::PushL(heapBuffer); + TPtr8 memPtr(heapBuffer->Des()); + iFile.Read(KBeginOfMasterHeaderSection, memPtr); + iFile.Write(iBeginOfDuplicateHeaderSection, memPtr); + iFile.Flush(); + CleanupStack::PopAndDestroy(heapBuffer); + } + +/* +It copies header information from duplicate copy to master copy. +*/ +void CPreallocatedFile::CopyDuplicateToMasterL() + { + TInt sizeOfDataToBeCopied = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + 4; + + HBufC8* heapBuffer = HBufC8::NewL(sizeOfDataToBeCopied); + CleanupStack::PushL(heapBuffer); + TPtr8 memPtr(heapBuffer->Des()); + iFile.Read(iBeginOfDuplicateHeaderSection, memPtr); + iFile.Write(KBeginOfMasterHeaderSection, memPtr); + iFile.Flush(); + CleanupStack::PopAndDestroy(heapBuffer); + } + +/* +It returns the total number of PDUs stored in pre-allocated file. +*/ +TInt CPreallocatedFile::NumberOfPDUStored() + { + TInt noOfPDUs = 0; + for (TInt i = 0; i < iEntryArray.Count(); i++) + { + noOfPDUs += iEntryArray[i].Count(); + } + return noOfPDUs; + } + +/** + * Sets the pre-allocated file store as in-transaction. + * + * The function checks the validity of the call and leaves KErrAccessDenied if + * invalid. + * @capability None + */ +void CPreallocatedFile::BeginTransactionL() + { + LOGSMSPROT3("CPreallocatedFile::BeginTransactionL [this=0x%08X iInTransaction=%d]", this, iInTransaction); + + if (iInTransaction) + { + LOGGSMU1("WARNING CPreallocatedFile::BeginTransactionL leaving with KErrAccessDenied"); + User::Leave(KErrAccessDenied); + } + + iInTransaction = ETrue; + } + +/** + * It commits the transaction. + */ +void CPreallocatedFile::CommitTransactionL() + { + LOGSMSPROT3("CPreallocatedFile::CommitTransactionL(): this=0x%08X iInTransaction=%d", + this, iInTransaction); + + ExternalizeEntryArray(); + //Commit + PutChecksumValueL(); + iInTransaction = EFalse; + iReinstateEntryInfo.Reset(); + RemoveDeletedEntries(); + } + +/* +It reverts the transaction. +*/ +void CPreallocatedFile::Revert() + { + LOGSMSPROT3("CPreallocatedFile::Revert(): this=0x%08X, iInTransaction=%d", + this, iInTransaction); + + ReinstateEntries(); + ExternalizeEntryArray(); + iInTransaction = EFalse; + ReinstateDeletedEntries(); + } + +/** + * It removes the deleted entries from entry arry. + * This function is called after commit. + */ +void CPreallocatedFile::RemoveDeletedEntries() + { + LOGSMSPROT1("CPreallocatedFile::RemoveDeletedEntries()"); + + TInt count=iEntryArray.Count(); + while (count--) + { + TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[count]; + + if (entry.IsDeleted()) + { + iEntryArray.Delete(count); + } + else + { + entry.SetIsAdded(EFalse); + } + } + } // CPreallocatedFile::RemoveDeletedEntries + +/** + * It reinstate the deleted/added entries from entry arry. + * This function is called after revert operation. + */ +void CPreallocatedFile::ReinstateDeletedEntries() + { + LOGSMSPROT1("CPreallocatedFile::ReinstateDeletedEntries()"); + + TInt count=iEntryArray.Count(); + while (count--) + { + TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[count]; + + if (entry.IsAdded()) + { + iEntryArray.Delete(count); + } + else + { + entry.SetIsDeleted(EFalse); + } + } + } // CPreallocatedFile::ReinstateDeletedEntries + +/** + * It reinstate the deleted/added entries from the container. + * This function is called at the time of revert operation. + * Unlike permanent store file which supports revert. pre-allocated + * file (raw data file) supports the revert mecahnism using this function. + */ +void CPreallocatedFile::ReinstateEntries() + { + LOGSMSPROT1("CPreallocatedFile::ReinstateEntries()"); + + TInt containerId; + TInt storageId; + TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId)); + + TInt count = iReinstateEntryInfo.Count(); + + for (TInt i=0; i0)) + { + time = iEntryArray[index2].Time(); + index = index2; + } + } + return index; + } + +/** +Static factory constructor. Uses two phase +construction and leaves nothing on the CleanupStack. + +@param aClass0ReassemblyStore reference to class 0 reasembly store. +@param aGuardTimeout guard time out in hours. + +@return A pointer to the newly created CGuardTimer object. + +@internalComponent +*/ +CGuardTimer* CGuardTimer::NewL(CClass0SmsReassemblyStore& aClass0ReassemblyStore, TInt aGuardTimeout) + { + LOGSMSPROT1("CGuardTimer::NewL()"); + + CGuardTimer* timer = new(ELeave) CGuardTimer(aClass0ReassemblyStore, aGuardTimeout); + CleanupStack::PushL(timer); + timer->ConstructL(); + CleanupStack::Pop(); + return timer; + } // CGuardTimer::NewL + +/** + * Constructor + */ +CGuardTimer::CGuardTimer(CClass0SmsReassemblyStore& aClass0ReassemblyStore, TInt aGuardTimeout) + :CTimer(KSmsSessionPriority), + iClass0ReassemblyStore(aClass0ReassemblyStore), + iTimeoutInSecs(aGuardTimeout*3600) + { + CActiveScheduler::Add(this); + } //CGuardTimer::CGuardTimer + +/** + * Destructor + */ +CGuardTimer::~CGuardTimer() + { + Cancel(); + } // CGuardTimer::~CGuardTimer + +/** + * Enable the Gurad Timer + */ +void CGuardTimer::EnableGuardTimer() + { + LOGSMSPROT1("CGuardTimer::EnableGuardTimer()"); + if (!IsActive()) + { + TTime nextTimeOut; + iClass0ReassemblyStore.GetNextGuardTimeout(nextTimeOut); + At(nextTimeOut); + } + } //CGuardTimer::EnableGuardTimer + +/** + * Disable the Gurad Timer + */ +void CGuardTimer::DisableGuardTimer() + { + Cancel(); + } + +/** + * Timer completed + */ +void CGuardTimer::RunL() + { + LOGSMSPROT2("CGuardTimer::RunL [iStatus=%d]", iStatus.Int()); + iClass0ReassemblyStore.ProcessTimeoutMessageL(); + EnableGuardTimer(); + } // CGuardTimer::RunL + +/** +Static factory constructor. Uses two phase +construction and leaves nothing on the CleanupStack. + +@param aFs File Server handle. +@param aSmsComm reference to MSmsComm event handler. + +@return A pointer to the newly created CClass0SmsReassemblyStore object. + +@pre A connected file server session must be passed as parameter. +@post CClass0SmsReassemblyStore object is now fully initialised + +@internalComponent +*/ +CClass0SmsReassemblyStore* CClass0SmsReassemblyStore::NewL(RFs& aFs, MSmsComm& aSmsComm) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::NewL()"); + + CClass0SmsReassemblyStore* self = new (ELeave) CClass0SmsReassemblyStore(aFs, aSmsComm); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + + return self; + } + +/** + * C'tor + */ +CClass0SmsReassemblyStore::CClass0SmsReassemblyStore(RFs& aFs, MSmsComm& aSmsComm) + :CReassemblyStore(aFs), iSmsComm(aSmsComm), iPermanentFileStore(NULL), iPreallocatedFile(NULL), + iGuardTimer(NULL), iInTransaction(EFalse), iDiskSpaceStatus(ESmsDiskSpaceAvailable) + { + } + +/** + * D'tor + */ +CClass0SmsReassemblyStore::~CClass0SmsReassemblyStore() + { + delete iPermanentFileStore; + delete iPreallocatedFile; + delete iGuardTimer; + } + +/* +It constructs permanent and pre-allocated file to store the class 0 messages. +It creates a guard timer so that messages can be deleted if all the constituent +PDU of a message is not received within configured time-frame. +It also reserves 4KB disk space so that reserved space can be used to +delete a stream from permanent file store in out-of-disk condition. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::ConstructL() + { + //Reserve Drive Space + User::LeaveIfError(iFs.ReserveDriveSpace(KStoreDrive, 4*1024)); + + //Read Configuration file + ReadConfigurableClass0SmsSettingsL(iMaxClass0Msg, iMaxPDUSeg, iGuardTimeOut); + //Create Permanent store file + TFileName permanentStoreFileName; + CReassemblyStoreUtility::PrivatePath(iFs, permanentStoreFileName); + permanentStoreFileName.Append(KClass0ReassemblyStoreName); + iPermanentFileStore = CSmsPermanentFileStore::NewL(iFs, permanentStoreFileName, KClass0ReassemblyStoreUid); + //Create Pre-allocated file + TFileName preAllocatedFileName; + CReassemblyStoreUtility::PrivatePath(iFs, preAllocatedFileName); + preAllocatedFileName.Append(KPreAllocatedFileName); + iPreallocatedFile = CPreallocatedFile::NewL(iFs, preAllocatedFileName, iMaxClass0Msg, iMaxPDUSeg); + //Create Gurad Timer + iGuardTimer = CGuardTimer::NewL(*this, iGuardTimeOut); + } + +/* +It reads class 0 re-assembly store configuration information from smswap.sms.esk file. +It reads the following information: MaxClass0Messages, NumberOfPDUSegements, GuardTimeOut. +If any of the above element is missing it takes the default value. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL(TInt& aMaxClass0Msg, TInt& aMaxPDUSeg, TInt& aGuardTimeOut) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL()"); + + aMaxClass0Msg = KMaxNumberOfClass0MessagesInReassemblyStore; + aMaxPDUSeg = KNumberOfPDUSegmentsStoredInOODCondition; + aGuardTimeOut = KGuardTimeOut; + + CESockIniData* ini = NULL; + TRAPD(ret, ini=CESockIniData::NewL(_L("smswap.sms.esk"))); + if(ret!=KErrNone) + { + LOGSMSPROT2("CESockIniData::NewL() returned=%d", ret); + } + else + { + CleanupStack::PushL(ini); + + TInt var(0); + if(ini->FindVar(_L("ReassemblyStore"),_L("MaxClass0Messages"),var)) + { + if (var > 0) + { + LOGSMSPROT2("MaxClass0Messages [%d]", var); + aMaxClass0Msg = var; + } + } + + if(ini->FindVar(_L("ReassemblyStore"),_L("NumberOfPDUSegements"),var)) + { + if (var > 0) + { + LOGSMSPROT2("MaxClass0Messages [%d]", var); + aMaxPDUSeg = var; + } + } + + if(ini->FindVar(_L("ReassemblyStore"),_L("GuardTimeOut"),var)) + { + if (var > 0) + { + LOGSMSPROT2("MaxClass0Messages [%d]", var); + aGuardTimeOut = var; + } + } + + CleanupStack::PopAndDestroy(ini); + } + + LOGSMSPROT4("CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL(): aMaxClass0Msg=%d, aMaxPDUSeg=%d, aGuardTimeOut=%d", + aMaxClass0Msg, aMaxPDUSeg, aGuardTimeOut); + } + +/** +It opens the class 0 re-assembly store. +Then it populates the entry information (all the messages stored in re-assembly store). + +@internalComponent +*/ +void CClass0SmsReassemblyStore::OpenStoreL() + { + LOGSMSPROT1("CClass0SmsReassemblyStore::OpenStoreL()"); + TFileName pathName; + CReassemblyStoreUtility::PrivatePath(iFs, pathName); + //Create the directory if it is not created. + iFs.MkDirAll(pathName); + // If any one file becomes corrupt or does not exist then we have to create both files. + if (iPreallocatedFile->IsFileOK() && iPermanentFileStore->IsFileOK()) + { + iPreallocatedFile->OpenL(); + iPermanentFileStore->OpenL(); + } + else + { + iPreallocatedFile->CreateL(); + iPermanentFileStore->CreateL(); + } + PopulateEntryArrayL(iEntryArray); + iGuardTimer->EnableGuardTimer(); + } + +/** +It closes the class 0 re-assembly store. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::Close() + { + LOGSMSPROT1("CClass0SmsReassemblyStore::CloseStore()"); + iGuardTimer->DisableGuardTimer(); + iEntryArray.Reset(); + iPreallocatedFile->Close(); + iPermanentFileStore->Close(); + } + +/** +It populates the entry information stored in class 0 reassembly store. + +@param aEntryArray reference to entry array. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::PopulateEntryArrayL(CArrayFix& aEntryArray) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::PopulateEntryArrayL()"); + aEntryArray.Reset(); + //Populate Entries from Pre-allocated file. + for (TInt count = 0; count < iPreallocatedFile->Entries().Count(); count++) + { + TReassemblyEntry entry; + entry.SetReference(iPreallocatedFile->Entries()[count].Reference()); + entry.SetTotal(iPreallocatedFile->Entries()[count].Total()); + entry.SetCount(iPreallocatedFile->Entries()[count].Count()+iPreallocatedFile->Entries()[count].NumberOfPDUsForwardToClient()); + entry.SetLogServerId(iPreallocatedFile->Entries()[count].LogServerId()); + + // Check that descriptor2 (sms address )is not corrupted + TPtrC ptr = iPreallocatedFile->Entries()[count].Description2(); + + if (ptr.Length() <= CSmsAddress::KSmsAddressMaxAddressLength) + { + entry.SetDescription2(iPreallocatedFile->Entries()[count].Description2()); + } + + entry.SetPduType(iPreallocatedFile->Entries()[count].PduType()); + entry.SetStorage(iPreallocatedFile->Entries()[count].Storage()); + entry.SetTime(iPreallocatedFile->Entries()[count].Time()); + entry.SetPassedToClient(iPreallocatedFile->Entries()[count].PassedToClient()); + aEntryArray.AppendL(entry); + } + + /* + Then populate the entries from permanent store file. It is needed + because permanent store file might contain few mesages. + But before populating the entry information it is needed to cleanup + the entries in permanent store file. It is needed to ensure that permanent file + clean itself with pre-allocated file. There migth be a scenario where + user has deleted a message but the corresponding message has not been + deleted from permanent store file due to out-of-disk condition. + And also at the time of forwarding an incomplete message a forwarded + message has not been deleted due to above reason. But the entry/PDU is + invalid because it is no more in the pre-allocated file which + contains master header info. + */ + TInt ret = CleanReassemblyEntries(); + + if (ret == KErrNone) + { + /* + In this case permanent store file contains correct information. + So populate Entry information from Permanent store file. + In this case only count information needs to be updated. + */ + TInt permanentFileStoreIndex; + for (TInt i=0; iMatchEntryToExistingMessage(aEntryArray[i], permanentFileStoreIndex); + if (permanentFileStoreIndex!=KErrNotFound) + { + aEntryArray[i].SetCount(aEntryArray[i].Count() + iPermanentFileStore->Entries()[permanentFileStoreIndex].Count()); + if (aEntryArray[i].Count() > aEntryArray[i].Total()) + { + aEntryArray[i].SetCount(aEntryArray[i].Total()); + } + } + } + } + else if (ret == KErrDiskFull) + { + LOGSMSPROT1("CleanReassemblyEntries() returns KErrDiskFull"); + /* + In this case permanent store file contains incorrect information. + For example forwarded message might be still stored in this store. + Because it has not been deleted due to out-of-disk condition. + So be careful at the time of updating the count information + about the message. + */ + TInt permanentFileStoreIndex; + for (TInt i=0; iMatchEntryToExistingMessage(aEntryArray[i], permanentFileStoreIndex); + if (permanentFileStoreIndex!=KErrNotFound) + { + TSmsPreAllocatedFileStoreReassemblyEntry entry = iPreallocatedFile->Entries()[i]; + if (entry.NumberOfPDUsForwardToClient() > 0) + { + //Internalize the entries. + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); + CleanupStack::PushL(smsMessage); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + //Internalize to check whether removed PDUs still stored in Permanent store file. + iPermanentFileStore->InternalizeEntryL(permanentFileStoreIndex, *smsMessage, *indexArray, *smsArray); + TInt noOfForwardedEntries=0; + for (TInt j=0; jCount() ;j++) + { + TUint8 bitMapIndex = (indexArray->At(j)-1)/8; + TUint8 bitPos = (indexArray->At(j)-1)%8; + TUint8 bitMap; + entry.GetBitMap(bitMapIndex, bitMap); + TUint8 tmpBitMap = 1; + tmpBitMap <<= bitPos; + if (tmpBitMap == (bitMap & tmpBitMap)) + { + noOfForwardedEntries++; + } + } + TInt count = iPermanentFileStore->Entries()[permanentFileStoreIndex].Count() - noOfForwardedEntries; + aEntryArray[i].SetCount(aEntryArray[i].Count() + count); + + CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray + } + else + { + aEntryArray[i].SetCount(aEntryArray[i].Count() + iPermanentFileStore->Entries()[permanentFileStoreIndex].Count()); + } + } + } + } + else + { + User::Leave(ret); + } + } + +/** +It sets the disk space status. +If disk space is full, then class 0 re-assembly store stores the incoming message in +pre-allocated file. Otherwise it stores the message in permanent store file. +*/ +void CClass0SmsReassemblyStore::SetDiskSpaceState(TSmsDiskSpaceMonitorStatus aDiskSpaceStatus) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::SetDiskSpaceState()"); + iDiskSpaceStatus = aDiskSpaceStatus; + } + +/* +It adds the new message in class 0 reassembly store. +It first tries to add the message in permanent store file. If it is +successful, then it adds the entry information in pre-allocated file. +Because pre-allocated file contains master header entry information. +Otherwise (if disk space is full), it adds the message in pre-allocated file. + +@param aSmsMessage reference to sms message to be added. +@param aGsmSms reference to GsmSms object to be added. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::AddNewMessageL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::AddNewMessageL"); + + // Add entry in permanent store file + TInt index; + TInt ret = KErrNone; + + if (iDiskSpaceStatus == ESmsDiskSpaceFull) + { + ret = KErrDiskFull; + } + else + { + TRAP(ret, iPermanentFileStore->AddNewMessageL(index, aSmsMessage, aGsmSms)); + } + + if (ret == KErrNone) + { + // Add a new entry in pre-allocated file + TSmsPreAllocatedFileStoreReassemblyEntry tmpEntry; + //Fill-up entry information... + CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1); + + //The properties below need to be set only once when a PDU of a new message arrives. + tmpEntry.SetStatus((RMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status()); + tmpEntry.SetUTCOffset(aSmsMessage.UTCOffset()); + tmpEntry.SetDecodedOnSIM(aSmsMessage.DecodedOnSim()); + tmpEntry.SetForwardToClient(aSmsMessage.ForwardToClient()); + //Set KErrNotFound because message corresponding to + //this entry is not in this pr-allocated file. + tmpEntry.SetPreAllocatedStorageId(KErrNotFound); + //Has to set 0 because PDU is stored in Permanent store file instead of pre-allocated file. + tmpEntry.SetCount(0); + + iPreallocatedFile->AddEntryL(tmpEntry); + } + else if (ret == KErrDiskFull) + { + // Add the new message in pre-allocated file + iPreallocatedFile->AddNewMessageL(index, aSmsMessage, aGsmSms); + } + else + { + User::Leave(ret); + } + } + +/* +It updates the existing message in class 0 re-assembly store. + +@param aSmsMessage reference to sms message to be updated. +@param aGsmSms reference to GsmSms object to be added. +@param aDuplicateMsgRef boolean value (output) indicates whether the added PDU is a duplicate or not. +@param aDuplicateSlot boolean value (output) indicates whether the added PDU is a duplicate enumerated PDU. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::UpdateExistingMessageL(CSmsMessage& aSmsMessage, const TGsmSms& aGsmSms, TBool& aDuplicateMsgRef, TBool& aDuplicateSlot) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::UpdateExistingMessageL()"); + + aDuplicateMsgRef = EFalse; + aDuplicateSlot = EFalse; + + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer); + CleanupStack::PushL(smsMessage); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + //Internalize stored message in permanent store file + TReassemblyEntry entry; + CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, 1); + TInt permanentStoreIndex; + iPermanentFileStore->MatchEntryToExistingMessage(entry, permanentStoreIndex); + if (permanentStoreIndex!=KErrNotFound) + { + iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, *smsMessage, *indexArray, *smsArray); + } + + //Internalize stored message in pre-allocated file + TInt preAllocatedFileIndex; + iPreallocatedFile->MatchEntryToExistingMessage(entry, preAllocatedFileIndex); + if (preAllocatedFileIndex!=KErrNotFound) + { + iPreallocatedFile->InternalizeEntryL(preAllocatedFileIndex, *smsMessage, *indexArray, *smsArray); + } + else + { + //This condition should never arise + User::Leave(KErrNotFound); + } + + // + // 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; + } + } + + //Check whether this PDU is part of forwarded PDU. + TSmsPreAllocatedFileStoreReassemblyEntry preAllocatedFileEntry = iPreallocatedFile->Entries()[preAllocatedFileIndex]; + if (preAllocatedFileEntry.NumberOfPDUsForwardToClient() > 0) + { + TUint8 bitMapIndex = (concatPDUIndex-1)/8; + TUint8 bitPos = (concatPDUIndex-1)%8; + TUint8 bitMap; + preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap); + TUint8 tmpBitMap = 1; + tmpBitMap <<= bitPos; + if (tmpBitMap == (bitMap & tmpBitMap)) + { + aDuplicateMsgRef = ETrue; + } + } + + if (aDuplicateMsgRef || aDuplicateSlot) + { + CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, smsArray, indexArray + return; + } + + // + // If the PDU is stored then add the slot information... + // + if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage || + aSmsMessage.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); + } + + /* + Below logic is written in keeping view of different scenarios that might occur here: + (1) Previous PDUs are in Permanent store file, this PDU arrives in out-of-disk condition (so will be stored in Pre-allocated file). + (2) Previous PDUs are in Pre-allocated file (means PDU arrives in out-of-disk condition), this PDU arrives in normal condition. + (3) Previous PDUs are in Permanent store file, this PDU also arrives in normal condition. + (4) Previous PDUs are in Pre-allocated file (means PDU arrives in out-of-disk condition), this PDU also arrives in out-of-disk condition. + */ + + //Always first try to store the message in permanent store file. + //In case of out-of-disk condition store the message in pre-allocated file + TInt ret = KErrNone; + if (iDiskSpaceStatus == ESmsDiskSpaceFull) + { + ret = KErrDiskFull; + } + else + { + if (permanentStoreIndex==KErrNotFound) + { + // See condition (2) + TInt tmpIndex; + TRAP(ret, iPermanentFileStore->AddNewMessageL(tmpIndex, aSmsMessage, aGsmSms)); + } + else + { + CSmsBuffer* tmpBuffer = CSmsBuffer::NewL(); + CSmsMessage* tmpSmsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, tmpBuffer); + CleanupStack::PushL(tmpSmsMessage); + + indexArray->Reset(); + smsArray->Reset(); + iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, *tmpSmsMessage, *indexArray, *smsArray); + /* + Check & remove those PDU from permanent store file which has already been + forwarded to client. Forwarded PDU might still remain in permanent store + file if it is deleted at the time of out-of-disk condition. + */ + if (preAllocatedFileEntry.NumberOfPDUsForwardToClient()>0) + { + for (TInt j=indexArray->Count(); j>0 ;j--) + { + TUint8 bitMapIndex = (indexArray->At(j-1)-1)/8; + TUint8 bitPos = (indexArray->At(j-1)-1)%8; + TUint8 bitMap; + preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap); + TUint8 tmpBitMap = 1; + tmpBitMap <<= bitPos; + if (tmpBitMap == (bitMap & tmpBitMap)) + { + indexArray->Delete(j-1); + smsArray->Delete(j-1); + } + } + } + + indexArray->AppendL(concatPDUIndex); + smsArray->AppendL(aGsmSms); + + TRAP(ret, iPermanentFileStore->UpdateExistingMessageL(permanentStoreIndex, *smsMessage, *indexArray, *smsArray)); + + CleanupStack::PopAndDestroy(1); //tmpSmsMessage + } + } + + if (ret == KErrDiskFull) + { + iPreallocatedFile->UpdateExistingMessageL(preAllocatedFileIndex, aSmsMessage, concatPDUIndex, aGsmSms); + } + else if (ret!=KErrNone) + { + User::Leave(ret); + } + + CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray + } + +/* +It retrieves class 0 message from re-assembly store. +The message which match the passed entry information is returned from this function. + +@param aEntry reference to entry information. +@param aSmsMessage reference to returned sms message. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::RetrieveMessageL(const TReassemblyEntry& aEntry, CSmsMessage& aSmsMessage) + { + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + GetSmsEntriesL(aEntry, aSmsMessage, *indexArray, *smsArray); + + //There is no need to decode a single segment message + if (aEntry.Total()>1) + { + if (smsArray->Count() == aEntry.Total()) + { + aSmsMessage.DecodeMessagePDUsL(*smsArray); + } + } + CleanupStack::PopAndDestroy(2, indexArray); //smsArray, indexArray + } + +/* +It deletes the entry from re-assembly store. + +@param aEntry reference to entry information. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::DeleteEntryL(const TReassemblyEntry& aEntry) + { + TInt index; + iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index); + if (index == KErrNotFound) + { + //This condition should never arise + User::Leave(KErrNotFound); + } + iPreallocatedFile->DeleteEntryL(index); + iPermanentFileStore->MatchEntryToExistingMessage(aEntry, index); + if (index != KErrNotFound) + { + TRAP_IGNORE(iPermanentFileStore->DeleteEntryL(index)); + } + } + +/* +It updates the log server id of the passed entry (message). + +@param aEntry reference to entry information. +@param aLogId log id of the message to be updated. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::UpdateLogServerIdL(const TReassemblyEntry& aEntry, TLogId aLogServerId) + { + TInt index; + iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index); + if (index == KErrNotFound) + { + //This condition should never arise + User::Leave(KErrNotFound); + } + iPreallocatedFile->UpdateLogServerIdL(index, aLogServerId); + } + +/* +It sets the message passed to client or not. The message, which match the +passed entry information, its passed to client value is set. + +@param aEntry reference to entry information. +@param aBool boolean value indicating whether message is passed or not. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::SetPassedToClientL(const TReassemblyEntry& aEntry, TBool aBool) + { + TInt index; + iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index); + if (index == KErrNotFound) + { + //This condition should never arise + User::Leave(KErrNotFound); + } + iPreallocatedFile->SetPassedToClientL(index, aBool); + } + +/** +It forwards the complete class 0 messages to client. +It checks whether the received object is complete or not. +If it is complete, then it forwards the complete message to client. +Otherwise it forms the message & forward the message to client. +In this it might be possible to forward multiple incomplete message. + +@param aSmsComm a reference to aSmsComm object which implemented the events. + +@param aSmsMessage a reference to sms message object. This sms message must be class 0 messages. + +@param aOriginalSmsAddr pointer to the address of the sender of a previously sent + +@param aOriginalSmsMessage pointer to a message previously sent matched to the received + one (e.g. status report). Null if not matched. + +@param aDes user data for the deliver report acknowledging this message to the SC. + Filled in by the observer. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::ForwardCompleteClass0SmsMessagesL(MSmsComm& aSmsComm, const CSmsMessage& aSmsMessage,const TSmsAddr* aOriginalSmsAddr,const CSmsMessage* aOriginalSmsMessage,TDes& aDes) + { + TBool passedToClient=ETrue; + + if (aSmsMessage.IsComplete()) + { + //Message is complete so forward it. + TInt ret = aSmsComm.ProcessMessageL(aSmsMessage, aOriginalSmsAddr, aOriginalSmsMessage, aDes); + if (ret!=KErrNone) + { + passedToClient = EFalse; + } + } + else + { + /* + Message is not complete, but re-assembly store contains other constituent PDU + of the message which makes the message complete. + + In case of class 0 messages, it is possible to forward the incomplete messages. So after forwarding + the incomplete message, if we receive other constituent PDU of that message then in that case we + might receive all the constituent PDU of that message but aSmsMesssage will contain partial complete message. + */ + TReassemblyEntry entry; + CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, 1); + + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer ); + CleanupStack::PushL( smsMessage ); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray); + SortPDUsL(*indexArray, *smsArray); + + CArrayFixFlat* tmpSmsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(tmpSmsArray); + + //Form the sequence of incomplete message & forward it to client. + TInt startSeqIndex(0), endSeqIndex(0); + TInt i; + do + { + i = startSeqIndex; + for (; i < indexArray->Count() - 1; i++) + { + if (indexArray->At(i) + 1 != indexArray->At(i+1)) + { + endSeqIndex = i; + break; + } + } + + if (i == (indexArray->Count() - 1)) + { + endSeqIndex = i; + } + + tmpSmsArray->Reset(); + for (TInt j = startSeqIndex; j <= endSeqIndex; j++) + { + tmpSmsArray->AppendL(smsArray->At(j)); + } + + if (tmpSmsArray->Count() == entry.Total()) + { + smsMessage->DecodeMessagePDUsL(*tmpSmsArray); + } + else + { + //Build the partial complete message. + if (endSeqIndex == (indexArray->Count() - 1)) + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); + } + else + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); + } + } + + //Forward the partial complete message to client. + TInt ret=KErrNone; + TRAP(ret, aSmsComm.ProcessMessageL(*smsMessage, aOriginalSmsAddr, aOriginalSmsMessage, aDes)); + if (ret != KErrNone) + { + passedToClient = EFalse; + } + startSeqIndex = endSeqIndex + 1; + endSeqIndex = startSeqIndex; + } + while (startSeqIndex < indexArray->Count()); + + CleanupStack::PopAndDestroy(4); //tmpSmsArray, indexArray, smsArray, smsMessage + } + + if(passedToClient) + { + SetMessagePassedToClientL(aSmsMessage); + } + + //If the latest segement exceeds the limitation, then we can't wait till ack. + //So call ProcessMessageIfExceedLimitationL() function & delete the oldest message. + if (IsExceedLimitation()) + { + ProcessMessageIfExceedLimitationL(aSmsComm); + } + } + +/** +It frees the space by forwarding the class 0 message if class 0 re-assembly store +exceeds limitation (max class 0 message, max reserved pdu segment). + +@param aSmsComm a reference to aSmsComm object which implemented the events. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::ProcessMessageIfExceedLimitationL(MSmsComm& aSmsComm) + { + //Add Comment + TInt class0MsgCount = iEntryArray.Count(); + TInt noOfMsgStoredInPreAllocatedFile = iPreallocatedFile->NumberOfPDUStored(); + if ((class0MsgCount > iMaxClass0Msg) + || (noOfMsgStoredInPreAllocatedFile >= iMaxPDUSeg)) + { + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer ); + CleanupStack::PushL( smsMessage ); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + //Add Comment + TInt index; + if (class0MsgCount > iMaxClass0Msg) + { + index = GetIndexOfOldestMessage(); + } + else + { + index = GetIndexOfOldestMessageFromReservedFileL(); + } + + TReassemblyEntry entry = iEntryArray[index]; + + GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray); + + SortPDUsL(*indexArray, *smsArray); + + CArrayFixFlat* tmpSmsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(tmpSmsArray); + + //Form the message & forward it to client. + TInt startSeqIndex(0), endSeqIndex(0); + TInt i; + do + { + i = startSeqIndex; + for (; i < indexArray->Count() - 1; i++) + { + if (indexArray->At(i) + 1 != indexArray->At(i+1)) + { + endSeqIndex = i; + break; + } + } + if (i == (indexArray->Count() - 1)) + { + endSeqIndex = i; + } + tmpSmsArray->Reset(); + + for (TInt j = startSeqIndex; j <= endSeqIndex; j++) + { + tmpSmsArray->AppendL(smsArray->At(j)); + } + + if (entry.IsComplete()) + { + if (tmpSmsArray->Count() == entry.Total()) + { + smsMessage->DecodeMessagePDUsL(*tmpSmsArray); + } + else + { + //Build the partial complete message. + if (endSeqIndex == (indexArray->Count() - 1)) + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); + } + else + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); + } + } + } + else + { + //Build the partial complete message. + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); + } + //Forward the partial complete message to client. + TBuf16 buffer; + TRAP_IGNORE(aSmsComm.ProcessMessageL(*smsMessage, NULL, NULL, buffer)); + + /* + Can't do much. So free the reserved space & also stored the information + related to forwarded message. If the message is complete then delete + the complete message (see the condition after the while loop)rather + than freeing the memory. No need to store the complete messages forwaded + info. + */ + if ((noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg) && (!entry.IsComplete())) + { + SetIncompleteMessageForwardedToClientL(*smsMessage); + } + startSeqIndex = endSeqIndex + 1; + endSeqIndex = startSeqIndex; + } + while (startSeqIndex < indexArray->Count()); + //Can't do much. So removed the oldest message. + if ((class0MsgCount > iMaxClass0Msg) || + ((noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg) && (entry.IsComplete()))) + { + DeleteMessageL(*smsMessage, EFalse); + } + CleanupStack::PopAndDestroy(4); //tmpSmsArray, indexArray, smsArray, smsMessage + } + } + +/** +Guard timer calls this function when timer expires. +It goes through all the messages stored in re-assembly store & forwards those message +whose time has expired. +It is also called when a new observer is added or a PDU has been received and successfully +processed. It is also called from ProcessCompleteClass0SmsMessagesL. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::ProcessTimeoutMessageL() + { + LOGSMSPROT1("CClass0SmsReassemblyStore::ProcessTimeoutMessageL()"); + TBool passedToClient=ETrue; + TInt count=iEntryArray.Count(); + + CSmsBuffer* buffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer ); + CleanupStack::PushL( smsMessage ); + + CArrayFix* indexArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(indexArray); + CArrayFixFlat* smsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(smsArray); + + CArrayFixFlat* tmpSmsArray = new(ELeave) CArrayFixFlat(KFlatArrayGranularity); + CleanupStack::PushL(tmpSmsArray); + + TTime time; + time.UniversalTime(); + + TTimeIntervalSeconds timeOutInSecs = iGuardTimeOut*3600; + + for (TInt k=count-1; k>=0; k--) + { + if (!iEntryArray[k].PassedToClient()) + { + TTimeIntervalSeconds diffInSecs; + time.SecondsFrom(iEntryArray[k].Time(), diffInSecs); + indexArray->Reset(); + smsArray->Reset(); + if (diffInSecs >= timeOutInSecs) + { + GetSmsEntriesL(iEntryArray[k], *smsMessage, *indexArray, *smsArray); + SortPDUsL(*indexArray, *smsArray); + + //Form the message & forward it to client. + TInt startSeqIndex(0), endSeqIndex(0); + TInt i; + do + { + i = startSeqIndex; + for (; i < indexArray->Count() - 1; i++) + { + if (indexArray->At(i) + 1 != indexArray->At(i+1)) + { + endSeqIndex = i; + break; + } + } + if (i == (indexArray->Count() - 1)) + { + endSeqIndex = i; + } + tmpSmsArray->Reset(); + for (TInt j = startSeqIndex; j <= endSeqIndex; j++) + { + tmpSmsArray->AppendL(smsArray->At(j)); + } + + if (iEntryArray[k].IsComplete()) + { + if (tmpSmsArray->Count() == iEntryArray[k].Total()) + { + smsMessage->DecodeMessagePDUsL(*tmpSmsArray); + } + else + { + //Build the partial complete message. + if (endSeqIndex == (indexArray->Count() - 1)) + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); + } + else + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); + } + } + } + else + { + //Build the partial complete message. + if (endSeqIndex == (indexArray->Count() - 1)) + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue); + } + else + { + smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse); + } + } + + //Forward the partial complete message to client. + TInt ret=KErrNone; + TBuf16 buffer; + ret = iSmsComm.ProcessMessageL(*smsMessage, NULL, NULL, buffer); + if (ret != KErrNone) + { + passedToClient = EFalse; + } + + startSeqIndex = endSeqIndex + 1; + endSeqIndex = startSeqIndex; + } + while (startSeqIndex < indexArray->Count()); + + if(passedToClient) + { + SetMessagePassedToClientL(*smsMessage); + } + } //diffInSecs >= timeOutInSecs + } //!iEntryArray[k].PassedToClient() + } //For k loop + CleanupStack::PopAndDestroy(4); //tmpSmsArray, indexArray, smsArray, smsMessage + } + +/** +It sets the bit-map of forwarded incomplete message to client. +It frees up the memory by removing the forwarded PDUs. + +@param aSmsMessage a reference to forwaded incomplete class 0 sms message object. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::SetIncompleteMessageForwardedToClientL(const CSmsMessage& aSmsMessage) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::SetIncompleteMessageForwardedToClientL()"); + TInt index = KErrNotFound; + + if (aSmsMessage.IsComplete()) + { + LOGSMSPROT1("This function must be called when message is incomplete"); + User::Leave(KErrArgument); + } + + if (FindMessageL(aSmsMessage, EFalse, index)) + { + CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo &) aSmsMessage.GetOperationsForNonIEL(ESmsIncompleteClass0MessageParameter); + // Retrieve incomplete class 0 message information & process + TInt startPos, endPos; + TBool isLastMessage; + incompleteClass0MsgInfo.GetIncompleteMessageInfoL(startPos, endPos, isLastMessage); + + const TReassemblyEntry& entry = iEntryArray[index]; + + //Remove the forwarded PDU entries from pre-allocated file + TInt preAllocatedFileIndex=KErrNotFound; + iPreallocatedFile->MatchEntryToExistingMessage(entry, preAllocatedFileIndex); + if (preAllocatedFileIndex!=KErrNotFound) + { + BeginTransactionLC(); + iPreallocatedFile->RemovePDUsL(preAllocatedFileIndex, startPos, endPos); + iPreallocatedFile->StoreForwardedPDUsInfoL(preAllocatedFileIndex, startPos, endPos); + CommitTransactionL(); + } + else + { + //This situation should never arise + User::Leave(KErrNotFound); + } + + //Remove the forwarded PDU entries from permanent store file + TInt permanentStoreIndex=KErrNotFound; + iPermanentFileStore->MatchEntryToExistingMessage(entry, permanentStoreIndex); + if (permanentStoreIndex!=KErrNotFound) + { + TRAP_IGNORE(BeginTransactionLC(); + iPermanentFileStore->RemovePDUsL(permanentStoreIndex, startPos, endPos); + CommitTransactionL();); + } + } + } + +/** +This function is needed to ensure that permanent file +clean itself with pre-allocated file. +There migth be a scenario where user has deleted a message +but the corresponding message has not been deleted from permanent store file +due to out-of-disk condition. But the entry is invalid because +it is no more in the pre-allocated file which contains master header info. + +@return the error code. + +@internalComponent +*/ +TInt CClass0SmsReassemblyStore::CleanReassemblyEntries() + { + LOGSMSPROT1("CleanReassemblyEntries"); + const CArrayFix& preAllocatedFileEntryArray = iPreallocatedFile->Entries(); + TInt ret=KErrNone; + TRAP(ret, BeginTransactionLC(); + iPermanentFileStore->CleanupEntriesL(preAllocatedFileEntryArray); + CommitTransactionL();); + + if (ret == KErrDiskFull) + { + LOGSMSPROT1("CleanupEntriesL returns KErrDiskFull"); + /* + Get access to reserve memory, call again to clean the entries with compact. + Compact needs to be called at this instance because permanent store + will use reserve disk space to delete, but after deletion reserve + disk space will be freed. So compact will make sure that reserve disk + space is not used after compaction. + */ + iFs.GetReserveAccess(KStoreDrive); + TRAP(ret, BeginTransactionLC(); + iPermanentFileStore->CleanupEntriesWithCompactL(preAllocatedFileEntryArray); + CommitTransactionL();); + LOGSMSPROT2("CleanupEntriesWithCompactL returns %d", ret); + iFs.ReleaseReserveAccess(KStoreDrive); + } + return ret; + } + +/** +It returns the SMS entries (sms messages, sms pdu arrays & the corresponding index array) +from its permanent store & pre-allocated file. + +@param aEntry reference to entry information. The message which match this entry information + is returned to caller of the function. +@param aSmsMessage a reference to class 0 sms message object. +@param aIndexArray a reference to the array of pdu index. +@param aSmsArray a reference to the array of pdu. + +@internalComponent +*/ +void CClass0SmsReassemblyStore::GetSmsEntriesL(const TReassemblyEntry& aEntry, CSmsMessage& aSmsMessage, CArrayFix& aIndexArray, CArrayFix& aSmsArray) + { + LOGSMSPROT1("CClass0SmsReassemblyStore::GetSmsEntriesL()"); + TInt permanentStoreIndex=KErrNotFound; + iPermanentFileStore->MatchEntryToExistingMessage(aEntry, permanentStoreIndex); + if (permanentStoreIndex!=KErrNotFound) + { + iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, aSmsMessage, aIndexArray, aSmsArray); + } + else + { + LOGSMSPROT1("No PDUs in Permanent store file"); + } + + TInt preAllocatedFileIndex=KErrNotFound; + iPreallocatedFile->MatchEntryToExistingMessage(aEntry, preAllocatedFileIndex); + if (preAllocatedFileIndex!=KErrNotFound) + { + iPreallocatedFile->InternalizeEntryL(preAllocatedFileIndex, aSmsMessage, aIndexArray, aSmsArray); + + //Filter forwarde PDU here..this condition might arise if the PDU + //could not be deleted at the time of OOD condition from permanent store file. + TSmsPreAllocatedFileStoreReassemblyEntry preAllocatedFileEntry = iPreallocatedFile->Entries()[preAllocatedFileIndex]; + if (preAllocatedFileEntry.NumberOfPDUsForwardToClient() > 0) + { + for (TInt j=aIndexArray.Count(); j>0 ;j--) + { + TUint8 bitMapIndex = (aIndexArray.At(j-1)-1)/8; + TUint8 bitPos = (aIndexArray.At(j-1)-1)%8; + TUint8 bitMap; + preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap); + TUint8 tmpBitMap = 1; + tmpBitMap <<= bitPos; + if (tmpBitMap == (bitMap & tmpBitMap)) + { + aIndexArray.Delete(j-1); + aSmsArray.Delete(j-1); + } + } + } + + if (permanentStoreIndex==KErrNotFound) + { + //In this scenario a CSmsMessage object has to be created from the existing PDU in + //pre-allocated file & then serialized into aSmsMessage. + LOGSMSPROT2("Number of PDUs in Pre-allocated file %d", aIndexArray.Count()); + if (aIndexArray.Count() > 0) + { + CSmsBuffer* smsBuffer = CSmsBuffer::NewL(); + CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, aSmsArray.At(0), smsBuffer, EFalse, ETrue); + CleanupStack::PushL(smsMessage); + + //Update sms messages's properties. + smsMessage->SetStorage(aSmsMessage.Storage()); + smsMessage->SetStatus((NMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status()); + smsMessage->SetLogServerId(aSmsMessage.LogServerId()); + smsMessage->SetTime(aSmsMessage.Time()); + smsMessage->SetUTCOffset(aSmsMessage.UTCOffset()); + smsMessage->SetDecodedOnSIM(aSmsMessage.DecodedOnSim()); + smsMessage->SetForwardToClient(aSmsMessage.ForwardToClient()); + smsMessage->SetToFromAddressL(aSmsMessage.ToFromAddress()); + + CBufSeg* recvbufseg = CBufSeg::NewL(KSmsMaxSegmentLength); + CleanupStack::PushL(recvbufseg); + // Attempt to serialize this message into the buffer + RBufWriteStream writestream(*recvbufseg); + writestream.Open(*recvbufseg); + CleanupClosePushL(writestream); + writestream << *smsMessage; + + // Initialize the read stream with the buffer + RBufReadStream readstream(*recvbufseg); + readstream.Open(*recvbufseg,0); + CleanupClosePushL(readstream); + // De-serialize the message from using the read stream + readstream >> aSmsMessage; + CleanupStack::PopAndDestroy(4); //readstream, writestream, recvbufseg, smsMessage + } + } + } + } + +/* +It returns when the next timeout should occur. +*/ +void CClass0SmsReassemblyStore::GetNextGuardTimeout(TTime& aNextTimeout) + { + TTime curTime; + curTime.UniversalTime(); + TTimeIntervalSeconds timeOutInSecs = iGuardTimeOut*3600; + aNextTimeout = curTime + timeOutInSecs; + + TInt class0ReassemblyStoreCount = iEntryArray.Count(); + + if (class0ReassemblyStoreCount > 0) + { + for (TInt i=0; i curTime) && + (guradTimeout < aNextTimeout)) + { + aNextTimeout = guradTimeout; + } + } + } + } + +/* +It returns the index of oldest message in class 0 re-assembly store. +*/ +TInt CClass0SmsReassemblyStore::GetIndexOfOldestMessage() + { + TInt index = 0; + TTime time = iEntryArray[index].Time(); + for (TInt index2=1; index2 < iEntryArray.Count(); index2++) + { + if (iEntryArray[index2].Time() < time) + { + index = index2; + } + } + return index; + } + +/* +It returns the index of oldest message in class 0 re-assembly store. +*/ +TInt CClass0SmsReassemblyStore::GetIndexOfOldestMessageFromReservedFileL() + { + TInt index = KErrNotFound; + //Find the index of oldest message in pre-allocated file. + index = iPreallocatedFile->GetOldestMessageEntryIndex(); + if (index == KErrNotFound) + { + //This condition should never arise + User::Leave(KErrNotFound); + } + + //Compare the oldest pre-allocated message entry against class 0 reassembly store entry + //and return the index of class 0 reassembly store entry. + const TSmsPreAllocatedFileStoreReassemblyEntry& preAllocatedFileEntry = iPreallocatedFile->Entries()[index]; + + TInt reassemblyCount = iEntryArray.Count(); + TInt count; + for (count = 0; count < reassemblyCount; count++) + { + TReassemblyEntry& entry = iEntryArray[count]; + + if (entry.Reference() == preAllocatedFileEntry.Reference() && + entry.Total() == preAllocatedFileEntry.Total() && + entry.PduType() == preAllocatedFileEntry.PduType() && + entry.Storage() == preAllocatedFileEntry.Storage() && + entry.Description2() == preAllocatedFileEntry.Description2()) + { + // + // Found it! + // + index = count; + break; + } + } + if (count == reassemblyCount) + { + //This condition should never arise + User::Leave(KErrNotFound); + } + return index; + } + +/* +It returns a boolean value indicating whether the limitation (max class 0 message, +max pdu stored in pre-allocated file) imposed on class 0 reassembly store exceeds or not. +*/ +TBool CClass0SmsReassemblyStore::IsExceedLimitation() + { + TInt class0MsgCount = iEntryArray.Count(); + TInt noOfMsgStoredInPreAllocatedFile = iPreallocatedFile->NumberOfPDUStored(); + if ((class0MsgCount > iMaxClass0Msg) + || (noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg)) + { + return ETrue; + } + + return EFalse; + } + +/* +This sorting algorithm is based on bubble sort +*/ +void CClass0SmsReassemblyStore::SortPDUsL(CArrayFix& aIndexArray, CArrayFix& aSmsArray) + { + //Test---Index array count must be equal to sms array count + TBool swapped; + + do + { + swapped = EFalse; + for (TInt i=0; i aIndexArray[i+1]) + { + aSmsArray.InsertL(i, aSmsArray[i+1]); + aSmsArray.Delete(i+2); + aIndexArray.InsertL(i, aIndexArray[i+1]); + aIndexArray.Delete(i+2); + swapped = ETrue; + } + } + } + while (swapped); + } + +/** + * Utility func for cleanup stack + */ +void CClass0StoreCloseObject(TAny* aObj) + { + LOGGSMU2("WARNING! Hey, CClass0StoreCloseObject called by Untrapper! [0x%08x]", aObj); + ((CClass0SmsReassemblyStore*)aObj)->Revert(); + } + +/** + * Sets the class 0 re-assembly store as in-transaction. + * + * The function checks the validity of the call and leaves KErrAccessDenied if + * invalid. + * @capability None + */ +void CClass0SmsReassemblyStore::BeginTransactionLC() + { + LOGSMSPROT3("CClass0SmsReassemblyStore::BeginTransactionLC [this=0x%08X iInTransaction=%d]", this, iInTransaction); + + if (iInTransaction) + { + LOGGSMU1("WARNING CClass0SmsReassemblyStore::BeginTransactionLC leaving with KErrAccessDenied"); + User::Leave(KErrAccessDenied); + } + + TCleanupItem class0StoreClose(CClass0StoreCloseObject, this); + CleanupStack::PushL(class0StoreClose); + iPreallocatedFile->BeginTransactionL(); + iPermanentFileStore->BeginTransactionL(); + iInTransaction = ETrue; + } + +/** + * It commits the transaction. + */ +void CClass0SmsReassemblyStore::CommitTransactionL() + { + LOGSMSPROT3("CClass0SmsReassemblyStore::CommitTransactionL(): this=0x%08X iInTransaction=%d", + this, iInTransaction); + + //Commit permanent store file + iPermanentFileStore->CommitTransactionL(); + //Commit pre-allocated file + iPreallocatedFile->CommitTransactionL(); + CleanupStack::Pop(this); //CClass0StoreCloseObject + iInTransaction = EFalse; + } + +/** + * It reverts the transaction. + */ +void CClass0SmsReassemblyStore::Revert() + { + LOGSMSPROT3("CClass0SmsReassemblyStore::Revert(): this=0x%08X, iInTransaction=%d", + this, iInTransaction); + + iPreallocatedFile->Revert(); + iPermanentFileStore->Revert(); + iInTransaction = EFalse; + }