smsprotocols/smsstack/smsprot/Src/smspclass0stor.cpp
changeset 0 3553901f7fa8
child 24 6638e7f4bd8f
child 42 3adadc800673
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspclass0stor.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +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<TSmsPreAllocatedFileStoreReassemblyEntry>& 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<TSmsPreAllocatedFileStoreReassemblyEntry>& 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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+					CleanupStack::PushL(indexArray);
+					CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<count; i++)
+		{
+		TSmsReassemblyEntry sarentry;
+		stream >> 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<count1; i++)
+		{
+		if (!iEntryArray[i].IsDeleted())
+			{
+			count2++;
+			}
+		}
+	stream.WriteInt32L(count2);
+	for (i=0; i<count1; i++)
+		{
+		if (!iEntryArray[i].IsDeleted())
+			{
+			stream << iEntryArray[i];
+			}
+		}
+
+	stream.CommitL();
+	CleanupStack::PopAndDestroy(&stream);
+	}
+
+/*
+It adds the new message in permanent store file.
+
+@param aIndex (output) index number on which message is added.
+@param aSmsMessage reference to sms message to be added.
+@param aGsmSms reference to GsmSms object to be added.
+
+@internalComponent
+*/
+void CSmsPermanentFileStore::AddNewMessageL(TInt& aIndex, CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
+	{
+	LOGSMSPROT1("CSmsPermanentFileStore::AddNewMessageL");
+
+	CArrayFix<TInt>* indexArray=new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+	CleanupStack::PushL(indexArray);
+	CArrayFixFlat<TGsmSms>* smsArray=new(ELeave) CArrayFixFlat<TGsmSms>(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<TInt>& aIndexArray,const CArrayFix<TGsmSms>& 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<TInt>& aIndexArray,const CArrayFix<TGsmSms>& 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<count; i++)
+		writestream.WriteInt32L(aIndexArray[i]);
+	count=aSmsArray.Count();
+	writestream.WriteInt32L(count);
+	for (i=0; i<count; i++)
+		{
+		RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
+		pdu=aSmsArray[i].Pdu();
+		writestream << pdu;
+		}
+	writestream.CommitL();
+	CleanupStack::PopAndDestroy();
+
+	LOGSMSPROT2("CClass0PermanentFileStore::ExternalizeEntryL End [count=%d]", count);
+	}
+
+/*
+It internalizes(reads) the entry from permanent store file.
+
+@param aIndex index number of the message to be internalized.
+@param aSmsMessage (output) reference to sms message.
+@param aIndexArray (output) refence to array of index.
+@param aSmsArray (output) refence to array of sms.
+
+@internalComponent
+*/
+void CSmsPermanentFileStore::InternalizeEntryL(const TInt aIndex, CSmsMessage& aSmsMessage, CArrayFix<TInt>& aIndexArray, CArrayFix<TGsmSms>& 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<count; i++)
+		{
+		TInt index=readstream.ReadInt32L();
+		aIndexArray.AppendL(index);
+		}
+	count=readstream.ReadInt32L();
+	if(count!=aIndexArray.Count())
+		{
+		User::Leave(KErrCorrupt);
+		}
+	for (i=0; i<count; i++)
+		{
+		RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
+		readstream >> 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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+	CleanupStack::PushL(indexArray);
+	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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; i<KBitMapLen; i++)
+		{
+		iBitMap.Append(0x00);
+		}
+	}
+
+/*
+It returns the reference of a particular bit-map index.
+
+@param aIndex index number of the bit-map.
+@param aBitMap bit-map value.
+
+@internalComponent
+*/
+void TSmsPreAllocatedFileStoreReassemblyEntry::GetBitMap(TUint8 aIndex, TUint8& aBitMap)
+	{
+	aBitMap = iBitMap[aIndex];
+	}
+
+/*
+It sets the value of a bit-map.
+
+@param aIndex index number of the bit-map.
+@param aBitMap bit-map value
+
+@internalComponent
+*/
+void TSmsPreAllocatedFileStoreReassemblyEntry::SetBitMap(TUint8 aIndex, TUint8 aBitMap)
+	{
+	iBitMap[aIndex] = aBitMap;
+	}
+
+/**
+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 aMaxClass0Msg max class 0 message that can be stored.
+@param aMaxPDUSeg max number of pdus that can be stored.
+@param aVersion version number of pre-allocated file.
+
+@return A pointer to the newly created CPreallocatedFile object.
+
+@pre A connected file server session must be passed as parameter.
+@post CPreallocatedFile object is now fully initialised
+
+@internalComponent
+*/
+CPreallocatedFile* CPreallocatedFile::NewL(RFs& aFs, const TDesC& aFileName, TInt aMaxClass0Msg, TInt aMaxPDUSeg, TPreAllocatedFileVersion aVersion)
+	{
+	LOGSMSPROT1("CPreallocatedFile::NewL()");
+	CPreallocatedFile*  self = new (ELeave) CPreallocatedFile(aFs, aMaxClass0Msg, aMaxPDUSeg, aVersion);
+	CleanupStack::PushL(self);
+	self->ConstructL(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; count<iMaxPDUSeg+1; count++)
+		{
+		pos2 = pos + count * sizeof(storageIdentifier);
+		iFile.Write(KBeginOfMasterHeaderSection + pos2, memPtr);
+		//iFile.Write(iBeginOfDuplicateHeaderSection + pos2, memPtr);
+		}
+
+	// Initialize Checksum
+	PutChecksumValueL();
+
+	// Close it to make sure that file is created correctly (defensive approach).
+	iFile.Close();
+	//Again Open the file
+	OpenL();
+	}
+
+/**
+It opens the pre-allocated file. Then it internalizes all the entry information.
+
+@internalComponent
+*/
+void CPreallocatedFile::OpenL()
+	{
+	User::LeaveIfError(iFile.Open(iFs, iFileName->Des(), 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<count; i++)
+		{
+		if (!iEntryArray[i].IsDeleted())
+			{
+			numberOfMessage++;
+			}
+		}
+
+	//Externalize number of mesages.
+	TPtr8 memPtr((TUint8*) &numberOfMessage, sizeof(numberOfMessage), sizeof(numberOfMessage));
+	iFile.Write(KBeginOfMasterHeaderSection, memPtr);
+
+	TInt entryNumber = 0;
+	//Externalize all the entries.
+	for (i=0; i<count; i++)
+		{
+		if (!iEntryArray[i].IsDeleted())
+			{
+			//At the time of externalizing don't externalize IsAdded(), IsDeleted() value
+			TBool isAdded = iEntryArray[i].IsAdded();
+			TBool isDeleted = iEntryArray[i].IsDeleted();
+			iEntryArray[i].SetIsAdded(EFalse);
+			iEntryArray[i].SetIsDeleted(EFalse);
+			memPtr.Set((TUint8*) &iEntryArray[i], KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry);
+			iFile.Write(KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + (entryNumber * KSizeOfPreAllocatedStoreEntry), memPtr);
+			//Again update IsAdded(), IsDeleted() with previous value
+			iEntryArray[i].SetIsAdded(isAdded);
+			iEntryArray[i].SetIsDeleted(isDeleted);
+			entryNumber++;
+			}
+		}
+
+	count = numberOfMessage;
+	/*
+	Externalize extra entry information with default information.
+	This initialization is required because of checksum.
+	*/
+	TSmsPreAllocatedFileStoreReassemblyEntry tmpClass0ReassemblyStore;
+	memPtr.Set((TUint8*) &tmpClass0ReassemblyStore, KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry);
+	TInt pos = 0;
+	for (; count<iMaxClass0Msg + 1; count++)
+		{
+		pos = KSizeOfNumberOfEntrySection + (count * KSizeOfPreAllocatedStoreEntry);
+		iFile.Write(KBeginOfMasterHeaderSection + pos, memPtr);
+		}
+	iFile.Flush();
+	}
+
+/*
+It adds the new message in pre-allocated file.
+
+@param aIndex (output) index number on which message is added.
+@param aSmsMessage reference to sms message to be added.
+@param aGsmSms reference to GsmSms object to be added.
+
+@internalComponent
+*/
+void CPreallocatedFile::AddNewMessageL(TInt& aIndex, CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
+	{
+	LOGSMSPROT1("CPreallocatedFile::AddNewMessageL");
+	//Gets the next free slot where the message will be stored.
+	TInt nextFreeSlot = GetFreeContainer();
+	TInt pduIndex=aSmsMessage.IsDecoded()? 0: aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
+	if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage  ||
+		aSmsMessage.Storage() == CSmsMessage::ESmsCombinedStorage)
+		{
+		const TGsmSmsSlotEntry&  newSlot = aSmsMessage.iSlotArray[0];
+		ExternalizeEntry(nextFreeSlot, newSlot, pduIndex, aGsmSms);
+		}
+	else
+		{
+		ExternalizeEntry(nextFreeSlot, pduIndex, aGsmSms);
+		}
+
+	/*
+	Gets the unique id which will identify the containers where the 
+	PDU related to this messsage are stored.
+	*/
+	TInt freeStorageId = GetFreeStorageId();
+	AddStorageIdL(nextFreeSlot, freeStorageId);
+
+	TSmsPreAllocatedFileStoreReassemblyEntry tmpEntry;
+	//Fill-up entry information...
+	CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1);
+	tmpEntry.SetPreAllocatedStorageId(freeStorageId);
+	//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());
+
+	// Add & extrenalize entry array.
+	aIndex = iEntryArray.Count();
+	AddEntryL(tmpEntry);
+	}
+
+/*
+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 aPduIndex index of the PDU to be updated.
+@param aSms sms of the PDU to be updated.
+
+@internalComponent
+*/
+void CPreallocatedFile::UpdateExistingMessageL(TInt aIndex, const CSmsMessage& aSmsMessage, TInt aPduIndex, const TGsmSms& aSms)
+	{
+	LOGSMSPROT1("CPreallocatedFile::UpdateExistingMessageL()");
+	TInt preAllocatedStorageId = iEntryArray[aIndex].PreAllocatedStorageId();
+	if (preAllocatedStorageId == KErrNotFound)
+		{
+		/*
+		This condition arises when part of message is stored in permanent store file & 
+		other parts arrive when system is out of disk.
+		*/
+		preAllocatedStorageId = GetFreeStorageId();
+		iEntryArray[aIndex].SetPreAllocatedStorageId(preAllocatedStorageId);
+		}
+	// Externalize Entry in one of free containers.
+	TInt freeSlot = GetFreeContainer();
+	if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage  ||
+		aSmsMessage.Storage() == CSmsMessage::ESmsCombinedStorage)
+		{
+		const TGsmSmsSlotEntry&  newSlot = aSmsMessage.iSlotArray[0];
+		ExternalizeEntry(freeSlot, newSlot, aPduIndex, aSms);
+		}
+	else
+		{
+		ExternalizeEntry(freeSlot, aPduIndex, aSms);
+		}
+
+	AddStorageIdL(freeSlot, preAllocatedStorageId);
+	TSmsPreAllocatedFileStoreReassemblyEntry entry;
+	entry = iEntryArray[aIndex];
+	/*
+	This value must be set because this may the first PDU of an 
+	existing message which is stored in pre-allocated store file.
+	*/
+	entry.SetPreAllocatedStorageId(preAllocatedStorageId);
+	entry.SetCount(entry.Count()+1);
+	ChangeEntryL(aIndex, entry);
+	}
+
+/*
+It matches the entry with entry in pre-allocated 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 CPreallocatedFile::MatchEntryToExistingMessage(const TReassemblyEntry& aEntry,
+													TInt& aIndex)
+	{
+	LOGSMSPROT1("CPreallocatedFile::MatchEntryToExistingMessage()");
+
+	aIndex = KErrNotFound;
+
+	//
+	// Search the reassembly store for a matching entry...
+	//
+	TInt reassemblyCount = iEntryArray.Count();
+
+	for (TInt  index = 0;  index < reassemblyCount;  index++)
+		{
+		TSmsPreAllocatedFileStoreReassemblyEntry&  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("CPreallocatedFile::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 CPreallocatedFile::UpdateLogServerIdL(TInt& aIndex, TLogId aLogServerId)
+	{
+	LOGSMSPROT1("CPreallocatedFile::UpdateLogServerId");
+
+	TSmsPreAllocatedFileStoreReassemblyEntry 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 CPreallocatedFile::SetPassedToClientL(TInt aIndex, TBool aBool)
+	{
+	LOGSMSPROT2("CPreallocatedFile::SetPassedToClientL(): aIndex=%d", aIndex);
+
+	TSmsPreAllocatedFileStoreReassemblyEntry 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 CPreallocatedFile::AddEntryL(TSmsPreAllocatedFileStoreReassemblyEntry& aEntry)
+	{
+	LOGSMSPROT1("CPreallocatedFile::AddEntryL");
+	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 CPreallocatedFile::ChangeEntryL(TInt aIndex, const TSmsPreAllocatedFileStoreReassemblyEntry& aNewEntry)
+	{
+	LOGSMSPROT2("CPreallocatedFile::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 CPreallocatedFile::DeleteEntryL(TInt aIndex)
+	{
+	LOGSMSPROT2("CPreallocatedFile::DeleteEntryL(): aIndex=%d", aIndex);
+	if (iEntryArray[aIndex].PreAllocatedStorageId() != KErrNotFound)
+		{
+		ClearEntryL(iEntryArray[aIndex].PreAllocatedStorageId(), iEntryArray[aIndex].Count());
+		}
+	iEntryArray[aIndex].SetIsDeleted(ETrue);
+	}
+
+/*
+It searches all the container & clears all the entries which
+contain the PDUs of the message (uniquely identified by aStorageId).
+
+NOTE:
+	It keeps the record of removed entries (container id, pre-allocated storage id 
+	& operation performed (add/delete)) in iReinstateEntryInfo variable.
+	It will be required in case of revert operation. As the container which
+	refers to the container which contains actual PDU is freed,
+	so it will not be a problem to restore the removed PDUs.
+	In case of revert operation, the removed information can be found in
+	iReinstateEntryInfo variable which can be restored easily. 
+	The container can be replaced with previous pre-allocated storage id.
+	After commiting the transaction, this varaible will be re-initialized.
+
+@param aStorageId unique id of message to be cleared.
+@param aNumberOfPDUs number of PDUs to be cleared.
+
+@internalComponent
+*/
+void CPreallocatedFile::ClearEntryL(TInt aStorageId, TInt aNumberOfPDUs)
+	{
+	LOGSMSPROT1("CPreallocatedFile::ClearEntryL");
+
+	//Read storage id.
+	TInt storageId;
+	TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId));
+	TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
+	TInt beginOfStorageId = 0;
+	TInt count;
+	TInt count2(0);
+
+	TInt cleanStorageId=0;
+	TPtr8 memPtr2((TUint8*) &cleanStorageId, sizeof(cleanStorageId), sizeof(cleanStorageId));
+
+	for (count=0; count<iMaxPDUSeg+1; count++)
+		{
+		TReinstateEntryInfo entry;
+		entry.iPreAllocatedStorageId=aStorageId;
+		entry.iFlag=EEntryIsDeleted;
+
+		beginOfStorageId = beginOfStorageIdSection + (count * sizeof(storageId));
+		iFile.Read(beginOfStorageId, memPtr);
+		if (storageId == aStorageId)
+			{
+			count2++;
+			iFile.Write(beginOfStorageId, memPtr2);
+			entry.iContainerId=count+1;
+			iReinstateEntryInfo.AppendL(entry);
+			}
+		if (count2 >= 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<iMaxPDUSeg+1; count++)
+		{
+		beginOfStorageId = beginOfStorageIdSection + (count * sizeof(storageId));
+		iFile.Read(beginOfStorageId, memPtr);
+		if (storageId == 0)
+			{
+			break;
+			}
+		}
+
+	// Count should never equal to iMaxPDUSeg+1
+	__ASSERT_DEBUG(count < iMaxPDUSeg+1, SmspPanic(KSmspPanicPreallocatedFileNoFreeContainer));
+	
+	return (count + 1);
+	}
+
+/*
+It returns the next free storage id.
+
+Storage id is used to identify the messages stored in pre-allocated file.
+A message might contain multiple PDUs and all those PDUs will be stored in 
+different container. This storage id will be used to identify on which 
+container the PDUs of a message are stored.
+
+This logic is based on the max number of messages that can be stored in
+pre-allocated file at one time. So free storage id is always used from
+this pool of numbers (from 1 till (max calls 0 message+2)).
+
+@internalComponent
+*/
+TInt CPreallocatedFile::GetFreeStorageId()
+	{
+	TInt count;
+
+	for (count=1; count < iMaxClass0Msg + 2; count++)
+		{
+		TInt numberOfEntries = iEntryArray.Count();
+		TInt count2;
+		for (count2 = 0; count2 < numberOfEntries; count2++)
+			{
+			if (count == iEntryArray[count2].PreAllocatedStorageId())
+				{
+				break;
+				}
+			}
+			if (count2 == numberOfEntries)
+				{
+				break;
+				}
+		}
+		return count;
+	}
+
+/*
+It externalizes(writes) the entry in permanent store file.
+
+@param aContainerId container id where the sms pdu needs to externalized.
+@param aSmsSlot reference to slot information.
+@param aIndex index number of PDU.
+@param aGsmSms refence to sms pdu.
+
+@internalComponent
+*/
+void CPreallocatedFile::ExternalizeEntry(TInt aContainerId, const TGsmSmsSlotEntry& aSmsSlot, TInt aIndex, const TGsmSms& aGsmSms)
+	{
+	LOGSMSPROT3("CPreallocatedFile::ExternalizeEntry() 1: aContainerId=%d, aIndex=%d", aContainerId, aIndex);
+
+	// Container id must not be greater than max pdu segment.
+	TInt pos = iBeginOfDataSection + ((aContainerId - 1) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
+	// Store slot info
+	TPtr8 memPtr((TUint8*) &aSmsSlot, sizeof(aSmsSlot), sizeof(aSmsSlot));
+	iFile.Write(pos, memPtr);
+	// Store the PDU index value
+	memPtr.Set((TUint8*) &aIndex, sizeof(aIndex), sizeof(aIndex));
+	iFile.Write(pos + KSizeOfGsmSmsSlotEntry, memPtr);
+	// Store the TGsmSms value
+	RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
+	pdu = aGsmSms.Pdu();
+	memPtr.Set((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU);
+	iFile.Write(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt), memPtr);
+
+	__ASSERT_DEBUG(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU <= iSizeOfFile,
+			       SmspPanic(KSmspPanicPreallocatedFileCorrupt));
+	}
+
+/*
+It externalizes(writes) the entry in permanent store file.
+
+@param aContainerId container id where the sms pdu needs to externalized.
+@param aIndex index number of PDU.
+@param aGsmSms refence to sms pdu.
+
+@internalComponent
+*/
+void CPreallocatedFile::ExternalizeEntry(TInt aContainerId, TInt aIndex, const TGsmSms& aGsmSms)
+	{
+	LOGSMSPROT3("CPreallocatedFile::ExternalizeEntry() 2: aContainerId=%d, aIndex=%d", aContainerId, aIndex);
+
+	// Container id must not be greater than max pdu segment.
+	TInt pos = iBeginOfDataSection + ((aContainerId - 1) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
+	// Store the PDU index value
+	TPtr8 memPtr((TUint8*) &aIndex, sizeof(aIndex), sizeof(aIndex));
+	iFile.Write(pos + KSizeOfGsmSmsSlotEntry, memPtr);
+	// Store the TGsmSms value
+	RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
+	pdu = aGsmSms.Pdu();
+	memPtr.Set((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU);
+	iFile.Write(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt), memPtr);
+
+	__ASSERT_DEBUG(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU <= iSizeOfFile,
+			       SmspPanic(KSmspPanicPreallocatedFileCorrupt));
+	}
+
+/*
+It internalizes(reads) the entry from permanent store file.
+
+@param aIndex index number of the message to be internalized.
+@param aSmsMessage (output) reference to sms message.
+@param aIndexArray (output) refence to array of index.
+@param aSmsArray (output) refence to array of sms.
+
+@internalComponent
+*/
+void CPreallocatedFile::InternalizeEntryL(const TInt aIndex, CSmsMessage& aSmsMessage, CArrayFix<TInt>& aIndexArray, CArrayFix<TGsmSms>& 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<iMaxPDUSeg+1; count++)
+		{
+		storageIdPos = beginOfStorageIdSection + count * sizeof(TInt);
+		iFile.Read(storageIdPos, memPtr1);
+		if (storageId == entry.PreAllocatedStorageId())
+			{//This means corresponding container contains the actual PDU
+			noOfPDUsRead++;
+			//Find the position of container where actaul PDU is stored.
+			dataPos = iBeginOfDataSection + ((count) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
+			//Read slot information
+			if (entry.Storage() == CSmsMessage::ESmsSIMStorage  ||
+				entry.Storage() == CSmsMessage::ESmsCombinedStorage)
+				{
+				iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry, memPtr2);
+				aSmsMessage.AddSlotL(smsSlotEntry);
+				}
+			//Read index information
+			iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry, memPtr3);
+			aIndexArray.AppendL(index);
+			//Read PDU
+			iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry + sizeof(index), memPtr4);
+			sms.SetPdu(pdu);
+			aSmsArray.AppendL(sms);
+			if (noOfPDUsRead == noOfPDUs)
+				{
+				break;
+				}
+			}
+		}
+
+	LOGSMSPROT2("CPreallocatedFile::InternalizeEntryL End [noOfPDUsRead=%d]", noOfPDUsRead);
+	}
+
+/*
+It removes the PDUs from pre-allocated 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 CPreallocatedFile::RemovePDUsL(TInt aIndex, TInt aStartPos, TInt aEndPos)
+	{
+	LOGSMSPROT1("CPreallocatedFile::RemovePDUsL");
+
+	if ((aStartPos < 1) || (aEndPos > 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<iMaxPDUSeg+1; count++)
+		{
+		TInt storageIdPos = beginOfStorageIdSection + count * sizeof(TInt);
+		iFile.Read(storageIdPos, memPtr1);
+		if (storageId == iEntryArray[aIndex].PreAllocatedStorageId())
+			{//This means corresponding container contains the actual PDU
+			noOfPDUsRead++;
+			//Find the position of container where actaul PDU is stored.
+			TInt dataPos = iBeginOfDataSection + ((count) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
+			//Read index information
+			iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry, memPtr3);
+
+			if ((index >= 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; i<count; i++)
+		{
+		if (iReinstateEntryInfo[i].iFlag == EEntryIsDeleted)
+			{
+			//Add the Pre-allocated storage info in the container.
+			storageId = iReinstateEntryInfo[i].iPreAllocatedStorageId;
+			containerId = iReinstateEntryInfo[i].iContainerId;
+			TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
+			iFile.Write( beginOfStorageIdentifierSection + ((containerId - 1) * sizeof(TInt)), memPtr);
+			}
+		else	//EEntryIsAdded
+			{
+			//Delete the Pre-allocated storage info from the container.
+			storageId = 0;
+			containerId = iReinstateEntryInfo[i].iContainerId;
+			TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
+			iFile.Write( beginOfStorageIdentifierSection + ((containerId - 1) * sizeof(TInt)), memPtr);
+			}
+		}
+	iFile.Flush();
+	iReinstateEntryInfo.Reset();
+	}
+
+/*
+It returns the index of oldest message in pre-allocated file.
+*/
+TInt CPreallocatedFile::GetOldestMessageEntryIndex()
+	{
+	LOGSMSPROT1("CPreallocatedFile::GetOldestMessageEntryIndex()");
+
+	TInt index = KErrNotFound;
+	TTime time;
+	time.UniversalTime();
+
+	for (TInt index2=0; index2 < iEntryArray.Count(); index2++)
+		{
+		if ((iEntryArray[index2].Time() < time) && (iEntryArray[index2].Count()>0))
+			{
+			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<TReassemblyEntry>& 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; i<aEntryArray.Count(); i++)
+			{
+			permanentFileStoreIndex=KErrNotFound;
+			iPermanentFileStore->MatchEntryToExistingMessage(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; i<aEntryArray.Count(); i++)
+			{
+			permanentFileStoreIndex=KErrNotFound;
+			iPermanentFileStore->MatchEntryToExistingMessage(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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+					CleanupStack::PushL(indexArray);
+					CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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; j<indexArray->Count() ;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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+	CleanupStack::PushL(indexArray);
+	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+	CleanupStack::PushL(indexArray);
+	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+		CleanupStack::PushL(indexArray);
+		CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
+		CleanupStack::PushL(smsArray);
+
+		GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray);
+		SortPDUsL(*indexArray, *smsArray);
+
+		CArrayFixFlat<TGsmSms>*  tmpSmsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+		CleanupStack::PushL(indexArray);
+		CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<TGsmSms>*  tmpSmsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<CSmsPDUProcessor::ESmsMaxDeliverReportBufferSize> 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<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
+	CleanupStack::PushL(indexArray);
+	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
+	CleanupStack::PushL(smsArray);
+
+	CArrayFixFlat<TGsmSms>*  tmpSmsArray = new(ELeave) CArrayFixFlat<TGsmSms>(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<CSmsPDUProcessor::ESmsMaxDeliverReportBufferSize> 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<TSmsPreAllocatedFileStoreReassemblyEntry>& 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<TInt>& aIndexArray, CArrayFix<TGsmSms>& 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<class0ReassemblyStoreCount;i++)
+			{
+			TTime guradTimeout = iEntryArray[i].Time() + timeOutInSecs;
+			if ((guradTimeout > 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<TInt>& aIndexArray, CArrayFix<TGsmSms>& aSmsArray)
+	{
+	//Test---Index array count must be equal to sms array count
+	TBool swapped;
+
+	do
+		{
+		swapped = EFalse;
+		for (TInt i=0; i<aIndexArray.Count()-1 ;i++)
+			{
+			if (aIndexArray[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;
+	}