smsprotocols/smsstack/smsprot/Src/smspreassemblystore.cpp
branchopencode
changeset 24 6638e7f4bd8f
parent 0 3553901f7fa8
--- a/smsprotocols/smsstack/smsprot/Src/smspreassemblystore.cpp	Mon May 03 13:37:20 2010 +0300
+++ b/smsprotocols/smsstack/smsprot/Src/smspreassemblystore.cpp	Thu May 06 15:10:38 2010 +0100
@@ -1,690 +1,690 @@
-// 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:
-//
-
-#include "smsstacklog.h"
-#include "gsmubuf.h"
-#include "smspreassemblystore.h"
-
-/**
- *  Populate entry information from sms message.
- *  @param aEntry fills up re-assembly entry information from aSmsMessage.
- *  @param aSmsMessage refernce to sms message.
- *	@param aNumSmss number of sms.
- */
-void CReassemblyStoreUtility::PopulateEntry(TSmsReassemblyEntry& aEntry,const CSmsMessage& aSmsMessage,TInt aNumSmss)
-	{
-	LOGSMSPROT1("CReassemblyStoreUtility::PopulateEntry");
-	aEntry.SetReference(0);
-	aEntry.SetTotal(1);
-	aEntry.SetCount(1);
-
-	if (aSmsMessage.TextPresent())
-		{
-		if (aSmsMessage.SmsPDU().TextConcatenated())
-			{
-			aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
-			aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
-			aEntry.SetCount(aSmsMessage.IsComplete()? aEntry.Total(): aNumSmss);
-			}
-		TInt bits7to4=aSmsMessage.SmsPDU().Bits7To4();
-		TInt count=aSmsMessage.SmsPDU().UserData().NumInformationElements();
-		TInt identifier1=0xFF;
-		TInt identifier2=0x00;
-		for (TInt i=0; i<count; i++)
-			{
-			TInt identifier=aSmsMessage.SmsPDU().UserData().InformationElement(i).Identifier();
-			if ((identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages8BitReference) && (identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages16BitReference))
-				{
-				if (identifier<identifier1)
-					identifier1=identifier;
-				if (identifier>identifier2)
-					identifier2=identifier;
-				}
-			}
-
-		if ((bits7to4>=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage) && (bits7to4<=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2))
-			aEntry.SetBits7to4andIdentifiers(bits7to4, identifier1, identifier2);
-		else
-			aEntry.SetBits7to4andIdentifiers(0, identifier1, identifier2);
-		}
-
-	//Set the logServerId to aSmsMessage.LogServerId()
-
-	aEntry.SetLogServerId(aSmsMessage.LogServerId());
-
-	const CSmsPDU::TSmsPDUType type(aSmsMessage.Type());
-	aEntry.SetPduType(type);
-	aEntry.SetPassedToClient(EFalse);
-
-	aEntry.SetStorage(aSmsMessage.Storage());
-	if ((type!=CSmsPDU::ESmsSubmitReport) && (type!=CSmsPDU::ESmsDeliverReport))
-		{
-		//  Strip out spaces etc from address
-		TGsmSmsTelNumber parsedaddress;
-		aSmsMessage.ParsedToFromAddress(parsedaddress);
-		aEntry.SetDescription2(parsedaddress.iTelNumber);
-		}
-
-	aEntry.SetTime(aSmsMessage.Time());
-	}
-
-/**
- *  Returns the private path of the component.
- *  @param aFs File Server handle.
- *  @param aPath (retrurns) private path of the component.
- */
-void CReassemblyStoreUtility::PrivatePath(RFs& aFs, TDes& aPath)
-	{
-	LOGSMSPROT1("CReassemblyStoreUtility::PrivatePath()");
-
-	TDriveUnit driveUnit(KStoreDrive);
-	TDriveName drive=driveUnit.Name();
-	aPath.Insert(0, drive);
-	//append private path
-	TPath privatePath;
-	aFs.PrivatePath(privatePath);
-	aPath.Append(privatePath);
-	aPath.Append(KStoreSubDir);
-	} // CReassemblyStoreUtility::PrivatePath
-
-/**
- *  Constructor.
-*/
-CReassemblyStore::CReassemblyStore(RFs& aFs) : iFs(aFs), iEntryArray(KFlatArrayGranularity)
-	{
-	iLastReceivedTime.UniversalTime();
-	iLastRealTime = iLastReceivedTime;
-	}
-
-/**
- *  Destructor.
-*/
-CReassemblyStore::~CReassemblyStore()
-	{
-	iEntryArray.Reset();
-	}
-
-/**
-It cleans up the re-assembly store.
-This function will be called to allow re-assembly store to initialize/clean-up
-
-@internalComponent
-*/
-void CReassemblyStore::InitializeL()
-	{
-	LOGSMSPROT1("CClass0SmsReassemblyStore::InitializeL()");
-	// Initialize Re-assembly store.
-	OpenStoreL();
-	BeginTransactionLC();
-	TInt count = iEntryArray.Count();
-	while (count--)
-		{
-		TReassemblyEntry entry= iEntryArray[count];
-		if ((entry.Storage() == CSmsMessage::ESmsSIMStorage) || (entry.Storage() == CSmsMessage::ESmsCombinedStorage))
-			{
-			DeleteEntryL(entry);
-			}
-		else
-			{
-			SetPassedToClientL(entry, EFalse);
-			}
-		}
-	CommitTransactionL();
-	Close();
-	}
-
-/**
- *  Purges the reassembly file store.
- *  
- *  After a multipart message, it delete all the old entries.
- *  
- *  Entries will be purged when: 1) The complete message is received; 2) After
- *  aTimerintervalMinutes, if aPurgeIncompletely is false.
- *  
- *  PurgeL() will be called after the booting of the device or when a message
- *  has been received.
- *  
- *  This function opens and closes the file automatically.
- *  
- *  
- *  @param aTimeIntervalMinutes Purge time
- *  @param aPurgeIncompleteOnly Purge complete messages flag
- */
-void CReassemblyStore::PurgeL(const TTimeIntervalMinutes& aTimeIntervalMinutes,TBool aPurgeIncompleteOnly)
-	{
-	//Call purging function
-	LOGSMSPROT3("CReassemblyStore::PurgeL(): aTimeIntervalMinutes=%d, aPurgeIncompleteOnly=%d",
-			 aTimeIntervalMinutes.Int(), aPurgeIncompleteOnly);
-
-	// TODO - flag
-	// we could also save the call of the method from the consruction of the smsprot
-	if( aPurgeIncompleteOnly )
-		return;
-
-	TInt count=iEntryArray.Count();
-	LOGSMSPROT2("CClass0SmsReassemblyStore::PurgeL(): count=%d", count);
-
-	TTime time;
-	time.UniversalTime();
-
-	// we open the file outside the loop
-	// to save some CPU
-	BeginTransactionLC();
-	for (TInt i=count-1; i>=0; i--)
-		{
-		//TReassemblyEntry entry=iEntryArray[i];
-		if (time > (iEntryArray[i].Time()+aTimeIntervalMinutes))
-			// TODO - flag
-			// check the logic o the aPurgeIncompleteOnly flg
-			// don't purge the store if the entry is complete
-			// entry.IsComplete()  )
-			{
-			DeleteEntryL(iEntryArray[i]);
-			}
-		}
-	CommitTransactionL();
-
-	PopulateEntryArrayL(iEntryArray);
-	}
-
-/**
-It deletes all the enumerated SIM messages stored in re-assembly store.
-This function will be called if user choses to cancel the enumeration.
-
-@internalComponent
-*/
-void CReassemblyStore::DeleteEnumeratedSIMEntries()
-	{
-	const TInt count = iEntryArray.Count();
-
-	LOGSMSPROT2("CReassemblyStore::DeleteEnumeratedSIMEntries(): %d messages in RAS", count);
-
-	TInt index;
-
-	for (index = count-1;  index >= 0;  --index)
-		{
-		TReassemblyEntry  entry = iEntryArray[index];
-
-		if (entry.Storage()==CSmsMessage::ESmsSIMStorage)
-			{
-			TRAP_IGNORE(BeginTransactionLC();
-						DeleteEntryL(entry);
-						CommitTransactionL();
-						iEntryArray.Delete(index));
-			}
-		}
-	}
-
-/**
-It returns the number of complete messages in reassembly store.
-
-@internalComponent
-*/
-TInt CReassemblyStore::NumberOfCompleteMessages()
-	{
-	LOGSMSPROT2("CReassemblyStore::NumberOfCompleteMessages(): iEntryArray.Count()=%d",
-				iEntryArray.Count());
-
-	//local variable for complete entries
-	TInt count( 0 );
-	// checks all entrys in the reassembly store
-	for ( TInt i = iEntryArray.Count()-1; i >= 0; i-- )
-		{
-		// checks if entry is completed
-		if ( iEntryArray[i].IsComplete() )
-			{
-			++count;
-			}
-		}
-	return count;
-	}
-
-/**
-It adds the message segment to the reassembly store. There are 5 possiblities:
-
-1) This is the single segment message.
-We therefore have all the segments.
-2) This is a duplicate message segment.
-We will ignore it.
-3) This is the last segment in the message required to complete it.
-The other segments are already stored.
-4) This is another PDU to an existing message in the store, but it is
-not yet complete.
-5) This is the first PDU in the message, and therefore the message is
-not yet complete and no segments are stored.
-
-@note Only SUBMIT or DELIVER PDUs can be added to the reassembly store.
-
-@param aSmsMessage  a reference to the SMS message.
-	It acts both as input & output. If the message is complete, it contains the decoded message.
-	Otherwise it contains the received message with few properties set (LogServerId, Time).
-
-@param aGsmSms	a reference to GsmSms object which contain actual PDU.
-	It acts as input.
-
-@param aIsComplete  Boolean value indicating whether the message is complete or not.
-	It acts both as input & output.
-
-@param aIsEnumeration	Boolean value indicating whether the function is called at the time of enumeration.
-	It acts as only input.
-
-@param aCount  value indicating the number of current PDUs in the re-assembly store for the given SMS message.
-	It acts as only output.
-
-@param aTotal	value indicating the total number of PDUs in the re-assembly store for the given SMS message.
-	It acts as only output.
-
-@internalComponent
-*/
-void CReassemblyStore::AddSegmentToReassemblyStoreL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms, TInt& aIndex, TBool& aIsComplete, TBool aIsEnumeration, TInt& aCount, TInt& aTotal)
-	{
-	LOGSMSPROT2("CReassemblyStore::AddSegmentToReassemblyStoreL(): isComplete Message=%d",
-				aSmsMessage.IsComplete());
-
-	/*
-	(1) If it is a single segment message create a new message
-	(2) If it is part of concatenated message find whether this is the first PDU
-	or it is the part of existing message.
-	If it is a new message then create new one.
-	If it is part of existing message, then check duplication (CheckDuplication()).
-	If it is a duplicate, return. Otherwise update the reassembly store.
-	*/
-
-	if (aIsComplete ||  aSmsMessage.Type() == CSmsPDU::ESmsStatusReport)
-		{
-		//
-		// 1) This is the complete message (e.g. a single-segment message).
-		//    We therefore have all the segments.
-		//
-		// Create the new message in the reassembly store. This is incase the
-		// power fails before the client gets it (note that it will be ack'd
-		// before passed to the client) so keeping it in memory is not
-		// acceptable...
-		//
-		NewMessagePDUL(aIndex, aSmsMessage, aGsmSms);
-		}
-	else
-		{
-		//
-		// If not yet complete, then we must be part of a multiple PDU message.
-		// Search the reassembly store for existing parts of the message.
-		//
-		TInt  segStoreIndex(KErrNotFound);
-
-		MatchPDUToExistingMessage(aSmsMessage, segStoreIndex);
-		LOGSMSPROT2("CSmsReassemblyStore::AddSegmentToReassemblyStoreL(): "
-					"segStoreIndex=%d", segStoreIndex);
-
-		//
-		// If not yet complete, then we must be part of a multiple PDU message.
-		// Search the reassembly store for existing parts of the message. This
-		// may set iIsComplete to true if all segments are then found.
-		//
-		if (segStoreIndex != KErrNotFound)
-			{
-			TBool  isDuplicateSlot(EFalse);
-			TBool  isDuplicateMsgRef(EFalse);
-			//
-			// So we found a related part of the message, add this message to the
-			// store...
-			//
-			aIndex = segStoreIndex;
-			UpdateExistingMessageL(aSmsMessage, aGsmSms, aIndex,
-									aIsComplete, isDuplicateMsgRef,
-									isDuplicateSlot);
-			LOGSMSPROT5("CSmsReassemblyStore::AddSegmentToReassemblyStoreL(): "
-						"aIndex=%d, isComplete=%d, isDuplicateMsgRef=%d, isDuplicateSlot=%d",
-						aIndex, aIsComplete, isDuplicateMsgRef, isDuplicateSlot);
-
-			if (isDuplicateMsgRef)
-				{
-				//
-				// In most cases discard it, unless we are doing an enumeration???
-				//
-				if (aIsEnumeration)
-					{
-					NewMessagePDUL(aIndex, aSmsMessage, aGsmSms);
-					}
-				}
-			else if (aIsComplete)
-				{
-				//
-				// 3) This is the last segment in the message required to complete it.
-				//    The other segments are already stored.
-				//
-				// Load the complete message into memory for futher processing.
-				//
-				GetMessageL(aIndex, aSmsMessage);
-				}
-			else
-				{
-				//
-				// 4) This is another PDU to an existing message in the store, but it is
-				//    not yet complete.
-				//
-				// Update the this segment with the timestamp of the original message.
-				//
-				CSmsBuffer*  buffer = CSmsBuffer::NewL();
-				CSmsMessage*  firstMessagePdu = CSmsMessage::NewL(iFs,
-																  CSmsPDU::ESmsDeliver, buffer);
-				CleanupStack::PushL(firstMessagePdu);
-				GetMessageL(aIndex, *firstMessagePdu);
-				aSmsMessage.SetUTCOffset(firstMessagePdu->UTCOffset());
-				CleanupStack::PopAndDestroy(firstMessagePdu);
-				}
-			}
-		else
-			{
-			//
-			// 5) This is the first PDU in the message, and therefore the message is
-			//    not yet complete and no segments are stored.
-			//
-			// The entry needs to be added to the reassembly store as a new entry.
-			//
-			NewMessagePDUL(aIndex, aSmsMessage, aGsmSms);
-			}
-		}
-
-	const TReassemblyEntry&  entry = iEntryArray[aIndex];
-	aCount = entry.Count();
-	aTotal = entry.Total();
-	}
-
-/**
-It deletes the given SMS message from re-assembly store.
-
-@param aSmsMessage  Message to delete.
-@param aPassed      Determines if we are searching for a message already
-					passed to the client.
-
-@internalComponent
-*/
-void CReassemblyStore::DeleteMessageL(const CSmsMessage& aSmsMessage, TBool aPassed)
-	{
-	LOGSMSPROT1("CReassemblyStore::DeleteMessageL()");
-	TInt index(0);
-	BeginTransactionLC();
-	if (FindMessageL(aSmsMessage, aPassed, index))
-		{
-		const TReassemblyEntry&  entry = iEntryArray[index];
-		DeleteEntryL(entry);
-		iEntryArray.Delete(index);
-		}
-	CommitTransactionL();
-	}
-
-/**
-It updates log server id of the passed message in re-assembly store.
-
-@param aSmsMessage  a reference to a message.
-@param aIndex	index number of sms message to be updated.
-
-@internalComponent
-*/
-void CReassemblyStore::UpdateLogServerIdOfMessageL(const CSmsMessage& aSmsMessage, TInt aIndex)
-	{
-	LOGSMSPROT1("CReassemblyStore::UpdateLogServerIdOfMessageL()");
-    TInt  foundIndex(KErrNotFound);
-	TBool  found(EFalse);
-
-	BeginTransactionLC();
-
-	found = FindMessageL(aSmsMessage , EFalse, foundIndex);
-	if (found  &&  (aIndex == foundIndex))
-		{
-		const TReassemblyEntry&  entry = iEntryArray[foundIndex];
-		UpdateLogServerIdL(entry, aSmsMessage.LogServerId());
-		iEntryArray[foundIndex].SetLogServerId(aSmsMessage.LogServerId());
-		}
-	CommitTransactionL();
-	}
-
-/**
-It updates that the given SMS message in re-assembly store is passed to client.
-
-@param aSmsMessage  Message which is passed to client.
-
-@internalComponent
-*/
-void CReassemblyStore::SetMessagePassedToClientL(const CSmsMessage& aSmsMessage, TBool aPassed)
-	{
-	LOGSMSPROT1("CReassemblyStore::SetMessagePassedToClientL()");
-	TInt index(0);
-
-	BeginTransactionLC();
-
-	if (FindMessageL(aSmsMessage , !aPassed, index))
-		{
-		const TReassemblyEntry&  entry = iEntryArray[index];
-		SetPassedToClientL(entry, aPassed);
-		iEntryArray[index].SetPassedToClient(aPassed);
-		}
-	CommitTransactionL();
-	}
-
-/**
-It adds a new message segment to the reassembly store and it returns an index to the message.
-
-@param aIndex value indicating the index of the message added to re-assembly store.
-	It acts as output.
-
-@param aSmsMessage  a reference to the SMS message.
-	It acts as input.
-
-@param aGsmSms	a reference to GsmSms object which contain actual PDU.
-	It acts as input.
-
-@internalComponent
-*/
-void CReassemblyStore::NewMessagePDUL(TInt& aIndex,CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
-	{
-	LOGSMSPROT1("CReassemblyStore::NewMessagePDUL");
-
-	if (aSmsMessage.Time() >= iLastRealTime)
-		{
-		iLastRealTime=aSmsMessage.Time();
-		if(iLastReceivedTime >= aSmsMessage.Time())
-			{
-			aSmsMessage.SetTime(iLastReceivedTime+(TTimeIntervalMicroSeconds32)1);
-			}
-		iLastReceivedTime=aSmsMessage.Time(); //provide uniqueness of time
-		}
-	else  // clock turned back
-		{
-		iLastReceivedTime=aSmsMessage.Time();
-		}
-
-	TReassemblyEntry entry;
-	CReassemblyStoreUtility::PopulateEntry(entry,aSmsMessage,1);
-	BeginTransactionLC();
-	AddNewMessageL(aSmsMessage, aGsmSms);
-	CommitTransactionL();
-	//Successfully added so add the entry in entry array.
-	aIndex = iEntryArray.Count();
-	iEntryArray.AppendL(entry);
-	}
-
-/**
-It adds a new message segment to the existing message in reassembly store & returns
-whether this segment makes this message complete or not. It also returns whether this
-segment is the duplicate one or not.
-
-@param aSmsMessage  a reference to the SMS message.
-	It acts as input.
-
-@param aGsmSms	a reference to GsmSms object which contain actual PDU.
-	It acts as input.
-
-@param aIndex value indicating the index of the message added to re-assembly store.
-	It acts as output.
-
-@param aIsComplete  Boolean value indicating whether the message is complete or not.
-	It acts as output.
-
-@param aDuplicateMsgRef	Boolean value indicating whether the added segment is a duplicate one or not.
-	It acts as output.
-
-@param aDuplicateSlot Boolean value indicating whether the added segment is from duplicate slot or not.
-	It acts as output.
-
-@internalComponent
-*/
-void CReassemblyStore::UpdateExistingMessageL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms,
-												TInt aIndex, TBool& aIsComplete,
-												TBool& aDuplicateMsgRef, TBool& aDuplicateSlot)
-	{
-	LOGSMSPROT1("CReassemblyStore::UpdateExistingMessageL");
-	aIsComplete = EFalse;
-	BeginTransactionLC();
-	UpdateExistingMessageL(aSmsMessage, aGsmSms, aDuplicateMsgRef, aDuplicateSlot);
-	CommitTransactionL();
-	if ((aDuplicateMsgRef == EFalse) && (aDuplicateSlot==EFalse))
-		{
-		iEntryArray[aIndex].SetCount(iEntryArray[aIndex].Count() + 1);
-		if (iEntryArray[aIndex].IsComplete())
-			{
-			aIsComplete = ETrue;
-			}
-		}
-	}
-
-/**
-It matches the passed message in re-assembly store & returns the index.
-
-@param aSmsMessage  a reference to the SMS message.
-	It acts as input.
-
-@param aIndex index number of message in re-assembly store.
-	It acts as input.
-
-@internalComponent
-*/
-void CReassemblyStore::MatchPDUToExistingMessage(const CSmsMessage& aSmsMessage,
-													TInt& aIndex)
-	{
-	LOGSMSPROT1("CReassemblyStore::MatchPDUToExistingMessage()");
-
-	aIndex = KErrNotFound;
-
-	TGsmSmsTelNumber  parsedAddress;
-	aSmsMessage.ParsedToFromAddress(parsedAddress);
-
-	//
-	// Search the reassembly store for a matching entry (start from the
-	// end as the most recent PDUs appear at the end)...
-	//
-	TInt reassemblyCount = iEntryArray.Count();
-
-	for (TInt  index = 0;  index < reassemblyCount;  index++)
-		{
-		TReassemblyEntry&  entry = iEntryArray[index];
-		// Always check the fields in order of the quickest to check...
-		if (entry.IsComplete() == EFalse  &&
-		    entry.PduType() == aSmsMessage.Type()  &&
-			entry.Storage() == aSmsMessage.Storage())
-			{
-			TInt  telLen = Min(entry.Description2().Length(),
-					           parsedAddress.iTelNumber.Length());
-			
-			if (entry.Description2().Right(telLen) == parsedAddress.iTelNumber.Right(telLen)  &&
-		        entry.Total() == aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs()  &&
-			    entry.Reference() == aSmsMessage.SmsPDU().ConcatenatedMessageReference())
-				{
-				//
-				// Found it!
-				//
-				aIndex = index;
-				break;
-				}
-			}
-		}
-
-	LOGSMSPROT3("CReassemblyStore::MatchPDUToExistingMessage(): reassemblyCount=%d, aIndex=%d", reassemblyCount, aIndex);
-	} // CReassemblyStore::MatchPDUToExistingMessage
-
-/**
-It retrieves the message from re-assembly store.
-
-@param aIndex index number of message in re-assembly store.
-	It acts as input.
-
-@param aSmsMessage  a reference to the SMS message.
-	It acts as output.
-
-@internalComponent
-*/
-void CReassemblyStore::GetMessageL(TInt aIndex, CSmsMessage& aSmsMessage)
-	{
-	LOGSMSPROT1("CReassemblyStore::GetMessageL()");
-	const TReassemblyEntry&  entry = iEntryArray[aIndex];
-	RetrieveMessageL(entry, aSmsMessage);
-	}
-
-/**
- *  Searches the reassembly store for a CSmsMessage with aPassed value (indicates if we 
- *	are searching for a message already passed to client) and returns its index.
- *
- *  @param aSmsMessage  Message to search for.
- *  @param aPassed      Determines if we are searching for a message already
- *                      passed to the client.
- *  @param aIndex       Return index value.
- *
- *  @return True and an index if aSmsMessage is found in this reassembly store
- */
-TBool CReassemblyStore::FindMessageL(const CSmsMessage& aSmsMessage,
-										TBool aPassed,
-										TInt& aIndex)
- 	{
-	LOGSMSPROT1("CReassemblyStore::FindMessageL()");
-
-	//
-	// Parse the GSM data from the SMS message...
-	//
-	TGsmSmsTelNumber  parsedAddress;
-
-	aSmsMessage.ParsedToFromAddress(parsedAddress);
-
-	//
-	// Search the store for a matching message...
-	//
- 	for (TInt index = iEntryArray.Count() - 1;  index >= 0;  index--)
- 		{
-		const TReassemblyEntry&  entry = iEntryArray[index];
-
-		// Always search the basic types first and strings last!
-		if (entry.PduType() == aSmsMessage.Type()  &&
-			entry.PassedToClient() == aPassed  &&
-			entry.Storage() == aSmsMessage.Storage()  &&
-			entry.Time() == aSmsMessage.Time()  &&
-			entry.Description2().Right(8) == parsedAddress.iTelNumber.Right(8))
- 			{
-			//
-			// Found!
-			//
-			LOGSMSPROT2("CReassemblyStore::FindMessage(): Found! index=%d", index);
-
-			aIndex = index;
-			
-			return ETrue;
-			}
- 		}
-
-	//
-	// Not found...
-	//
-	LOGSMSPROT1("CReassemblyStore::FindMessage(): Not found!");
-
-	return EFalse;
-	} // CReassemblyStore::FindMessageL
+// 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:
+//
+
+#include "smsstacklog.h"
+#include "gsmubuf.h"
+#include "smspreassemblystore.h"
+
+/**
+ *  Populate entry information from sms message.
+ *  @param aEntry fills up re-assembly entry information from aSmsMessage.
+ *  @param aSmsMessage refernce to sms message.
+ *	@param aNumSmss number of sms.
+ */
+void CReassemblyStoreUtility::PopulateEntry(TSmsReassemblyEntry& aEntry,const CSmsMessage& aSmsMessage,TInt aNumSmss)
+	{
+	LOGSMSPROT1("CReassemblyStoreUtility::PopulateEntry");
+	aEntry.SetReference(0);
+	aEntry.SetTotal(1);
+	aEntry.SetCount(1);
+
+	if (aSmsMessage.TextPresent())
+		{
+		if (aSmsMessage.SmsPDU().TextConcatenated())
+			{
+			aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
+			aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
+			aEntry.SetCount(aSmsMessage.IsComplete()? aEntry.Total(): aNumSmss);
+			}
+		TInt bits7to4=aSmsMessage.SmsPDU().Bits7To4();
+		TInt count=aSmsMessage.SmsPDU().UserData().NumInformationElements();
+		TInt identifier1=0xFF;
+		TInt identifier2=0x00;
+		for (TInt i=0; i<count; i++)
+			{
+			TInt identifier=aSmsMessage.SmsPDU().UserData().InformationElement(i).Identifier();
+			if ((identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages8BitReference) && (identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages16BitReference))
+				{
+				if (identifier<identifier1)
+					identifier1=identifier;
+				if (identifier>identifier2)
+					identifier2=identifier;
+				}
+			}
+
+		if ((bits7to4>=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage) && (bits7to4<=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2))
+			aEntry.SetBits7to4andIdentifiers(bits7to4, identifier1, identifier2);
+		else
+			aEntry.SetBits7to4andIdentifiers(0, identifier1, identifier2);
+		}
+
+	//Set the logServerId to aSmsMessage.LogServerId()
+
+	aEntry.SetLogServerId(aSmsMessage.LogServerId());
+
+	const CSmsPDU::TSmsPDUType type(aSmsMessage.Type());
+	aEntry.SetPduType(type);
+	aEntry.SetPassedToClient(EFalse);
+
+	aEntry.SetStorage(aSmsMessage.Storage());
+	if ((type!=CSmsPDU::ESmsSubmitReport) && (type!=CSmsPDU::ESmsDeliverReport))
+		{
+		//  Strip out spaces etc from address
+		TGsmSmsTelNumber parsedaddress;
+		aSmsMessage.ParsedToFromAddress(parsedaddress);
+		aEntry.SetDescription2(parsedaddress.iTelNumber);
+		}
+
+	aEntry.SetTime(aSmsMessage.Time());
+	}
+
+/**
+ *  Returns the private path of the component.
+ *  @param aFs File Server handle.
+ *  @param aPath (retrurns) private path of the component.
+ */
+void CReassemblyStoreUtility::PrivatePath(RFs& aFs, TDes& aPath)
+	{
+	LOGSMSPROT1("CReassemblyStoreUtility::PrivatePath()");
+
+	TDriveUnit driveUnit(KStoreDrive);
+	TDriveName drive=driveUnit.Name();
+	aPath.Insert(0, drive);
+	//append private path
+	TPath privatePath;
+	aFs.PrivatePath(privatePath);
+	aPath.Append(privatePath);
+	aPath.Append(KStoreSubDir);
+	} // CReassemblyStoreUtility::PrivatePath
+
+/**
+ *  Constructor.
+*/
+CReassemblyStore::CReassemblyStore(RFs& aFs) : iFs(aFs), iEntryArray(KFlatArrayGranularity)
+	{
+	iLastReceivedTime.UniversalTime();
+	iLastRealTime = iLastReceivedTime;
+	}
+
+/**
+ *  Destructor.
+*/
+CReassemblyStore::~CReassemblyStore()
+	{
+	iEntryArray.Reset();
+	}
+
+/**
+It cleans up the re-assembly store.
+This function will be called to allow re-assembly store to initialize/clean-up
+
+@internalComponent
+*/
+void CReassemblyStore::InitializeL()
+	{
+	LOGSMSPROT1("CClass0SmsReassemblyStore::InitializeL()");
+	// Initialize Re-assembly store.
+	OpenStoreL();
+	BeginTransactionLC();
+	TInt count = iEntryArray.Count();
+	while (count--)
+		{
+		TReassemblyEntry entry= iEntryArray[count];
+		if ((entry.Storage() == CSmsMessage::ESmsSIMStorage) || (entry.Storage() == CSmsMessage::ESmsCombinedStorage))
+			{
+			DeleteEntryL(entry);
+			}
+		else
+			{
+			SetPassedToClientL(entry, EFalse);
+			}
+		}
+	CommitTransactionL();
+	Close();
+	}
+
+/**
+ *  Purges the reassembly file store.
+ *  
+ *  After a multipart message, it delete all the old entries.
+ *  
+ *  Entries will be purged when: 1) The complete message is received; 2) After
+ *  aTimerintervalMinutes, if aPurgeIncompletely is false.
+ *  
+ *  PurgeL() will be called after the booting of the device or when a message
+ *  has been received.
+ *  
+ *  This function opens and closes the file automatically.
+ *  
+ *  
+ *  @param aTimeIntervalMinutes Purge time
+ *  @param aPurgeIncompleteOnly Purge complete messages flag
+ */
+void CReassemblyStore::PurgeL(const TTimeIntervalMinutes& aTimeIntervalMinutes,TBool aPurgeIncompleteOnly)
+	{
+	//Call purging function
+	LOGSMSPROT3("CReassemblyStore::PurgeL(): aTimeIntervalMinutes=%d, aPurgeIncompleteOnly=%d",
+			 aTimeIntervalMinutes.Int(), aPurgeIncompleteOnly);
+
+	// TODO - flag
+	// we could also save the call of the method from the consruction of the smsprot
+	if( aPurgeIncompleteOnly )
+		return;
+
+	TInt count=iEntryArray.Count();
+	LOGSMSPROT2("CClass0SmsReassemblyStore::PurgeL(): count=%d", count);
+
+	TTime time;
+	time.UniversalTime();
+
+	// we open the file outside the loop
+	// to save some CPU
+	BeginTransactionLC();
+	for (TInt i=count-1; i>=0; i--)
+		{
+		//TReassemblyEntry entry=iEntryArray[i];
+		if (time > (iEntryArray[i].Time()+aTimeIntervalMinutes))
+			// TODO - flag
+			// check the logic o the aPurgeIncompleteOnly flg
+			// don't purge the store if the entry is complete
+			// entry.IsComplete()  )
+			{
+			DeleteEntryL(iEntryArray[i]);
+			}
+		}
+	CommitTransactionL();
+
+	PopulateEntryArrayL(iEntryArray);
+	}
+
+/**
+It deletes all the enumerated SIM messages stored in re-assembly store.
+This function will be called if user choses to cancel the enumeration.
+
+@internalComponent
+*/
+void CReassemblyStore::DeleteEnumeratedSIMEntries()
+	{
+	const TInt count = iEntryArray.Count();
+
+	LOGSMSPROT2("CReassemblyStore::DeleteEnumeratedSIMEntries(): %d messages in RAS", count);
+
+	TInt index;
+
+	for (index = count-1;  index >= 0;  --index)
+		{
+		TReassemblyEntry  entry = iEntryArray[index];
+
+		if (entry.Storage()==CSmsMessage::ESmsSIMStorage)
+			{
+			TRAP_IGNORE(BeginTransactionLC();
+						DeleteEntryL(entry);
+						CommitTransactionL();
+						iEntryArray.Delete(index));
+			}
+		}
+	}
+
+/**
+It returns the number of complete messages in reassembly store.
+
+@internalComponent
+*/
+TInt CReassemblyStore::NumberOfCompleteMessages()
+	{
+	LOGSMSPROT2("CReassemblyStore::NumberOfCompleteMessages(): iEntryArray.Count()=%d",
+				iEntryArray.Count());
+
+	//local variable for complete entries
+	TInt count( 0 );
+	// checks all entrys in the reassembly store
+	for ( TInt i = iEntryArray.Count()-1; i >= 0; i-- )
+		{
+		// checks if entry is completed
+		if ( iEntryArray[i].IsComplete() )
+			{
+			++count;
+			}
+		}
+	return count;
+	}
+
+/**
+It adds the message segment to the reassembly store. There are 5 possiblities:
+
+1) This is the single segment message.
+We therefore have all the segments.
+2) This is a duplicate message segment.
+We will ignore it.
+3) This is the last segment in the message required to complete it.
+The other segments are already stored.
+4) This is another PDU to an existing message in the store, but it is
+not yet complete.
+5) This is the first PDU in the message, and therefore the message is
+not yet complete and no segments are stored.
+
+@note Only SUBMIT or DELIVER PDUs can be added to the reassembly store.
+
+@param aSmsMessage  a reference to the SMS message.
+	It acts both as input & output. If the message is complete, it contains the decoded message.
+	Otherwise it contains the received message with few properties set (LogServerId, Time).
+
+@param aGsmSms	a reference to GsmSms object which contain actual PDU.
+	It acts as input.
+
+@param aIsComplete  Boolean value indicating whether the message is complete or not.
+	It acts both as input & output.
+
+@param aIsEnumeration	Boolean value indicating whether the function is called at the time of enumeration.
+	It acts as only input.
+
+@param aCount  value indicating the number of current PDUs in the re-assembly store for the given SMS message.
+	It acts as only output.
+
+@param aTotal	value indicating the total number of PDUs in the re-assembly store for the given SMS message.
+	It acts as only output.
+
+@internalComponent
+*/
+void CReassemblyStore::AddSegmentToReassemblyStoreL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms, TInt& aIndex, TBool& aIsComplete, TBool aIsEnumeration, TInt& aCount, TInt& aTotal)
+	{
+	LOGSMSPROT2("CReassemblyStore::AddSegmentToReassemblyStoreL(): isComplete Message=%d",
+				aSmsMessage.IsComplete());
+
+	/*
+	(1) If it is a single segment message create a new message
+	(2) If it is part of concatenated message find whether this is the first PDU
+	or it is the part of existing message.
+	If it is a new message then create new one.
+	If it is part of existing message, then check duplication (CheckDuplication()).
+	If it is a duplicate, return. Otherwise update the reassembly store.
+	*/
+
+	if (aIsComplete ||  aSmsMessage.Type() == CSmsPDU::ESmsStatusReport)
+		{
+		//
+		// 1) This is the complete message (e.g. a single-segment message).
+		//    We therefore have all the segments.
+		//
+		// Create the new message in the reassembly store. This is incase the
+		// power fails before the client gets it (note that it will be ack'd
+		// before passed to the client) so keeping it in memory is not
+		// acceptable...
+		//
+		NewMessagePDUL(aIndex, aSmsMessage, aGsmSms);
+		}
+	else
+		{
+		//
+		// If not yet complete, then we must be part of a multiple PDU message.
+		// Search the reassembly store for existing parts of the message.
+		//
+		TInt  segStoreIndex(KErrNotFound);
+
+		MatchPDUToExistingMessage(aSmsMessage, segStoreIndex);
+		LOGSMSPROT2("CSmsReassemblyStore::AddSegmentToReassemblyStoreL(): "
+					"segStoreIndex=%d", segStoreIndex);
+
+		//
+		// If not yet complete, then we must be part of a multiple PDU message.
+		// Search the reassembly store for existing parts of the message. This
+		// may set iIsComplete to true if all segments are then found.
+		//
+		if (segStoreIndex != KErrNotFound)
+			{
+			TBool  isDuplicateSlot(EFalse);
+			TBool  isDuplicateMsgRef(EFalse);
+			//
+			// So we found a related part of the message, add this message to the
+			// store...
+			//
+			aIndex = segStoreIndex;
+			UpdateExistingMessageL(aSmsMessage, aGsmSms, aIndex,
+									aIsComplete, isDuplicateMsgRef,
+									isDuplicateSlot);
+			LOGSMSPROT5("CSmsReassemblyStore::AddSegmentToReassemblyStoreL(): "
+						"aIndex=%d, isComplete=%d, isDuplicateMsgRef=%d, isDuplicateSlot=%d",
+						aIndex, aIsComplete, isDuplicateMsgRef, isDuplicateSlot);
+
+			if (isDuplicateMsgRef)
+				{
+				//
+				// In most cases discard it, unless we are doing an enumeration???
+				//
+				if (aIsEnumeration)
+					{
+					NewMessagePDUL(aIndex, aSmsMessage, aGsmSms);
+					}
+				}
+			else if (aIsComplete)
+				{
+				//
+				// 3) This is the last segment in the message required to complete it.
+				//    The other segments are already stored.
+				//
+				// Load the complete message into memory for futher processing.
+				//
+				GetMessageL(aIndex, aSmsMessage);
+				}
+			else
+				{
+				//
+				// 4) This is another PDU to an existing message in the store, but it is
+				//    not yet complete.
+				//
+				// Update the this segment with the timestamp of the original message.
+				//
+				CSmsBuffer*  buffer = CSmsBuffer::NewL();
+				CSmsMessage*  firstMessagePdu = CSmsMessage::NewL(iFs,
+																  CSmsPDU::ESmsDeliver, buffer);
+				CleanupStack::PushL(firstMessagePdu);
+				GetMessageL(aIndex, *firstMessagePdu);
+				aSmsMessage.SetUTCOffset(firstMessagePdu->UTCOffset());
+				CleanupStack::PopAndDestroy(firstMessagePdu);
+				}
+			}
+		else
+			{
+			//
+			// 5) This is the first PDU in the message, and therefore the message is
+			//    not yet complete and no segments are stored.
+			//
+			// The entry needs to be added to the reassembly store as a new entry.
+			//
+			NewMessagePDUL(aIndex, aSmsMessage, aGsmSms);
+			}
+		}
+
+	const TReassemblyEntry&  entry = iEntryArray[aIndex];
+	aCount = entry.Count();
+	aTotal = entry.Total();
+	}
+
+/**
+It deletes the given SMS message from re-assembly store.
+
+@param aSmsMessage  Message to delete.
+@param aPassed      Determines if we are searching for a message already
+					passed to the client.
+
+@internalComponent
+*/
+void CReassemblyStore::DeleteMessageL(const CSmsMessage& aSmsMessage, TBool aPassed)
+	{
+	LOGSMSPROT1("CReassemblyStore::DeleteMessageL()");
+	TInt index(0);
+	BeginTransactionLC();
+	if (FindMessageL(aSmsMessage, aPassed, index))
+		{
+		const TReassemblyEntry&  entry = iEntryArray[index];
+		DeleteEntryL(entry);
+		iEntryArray.Delete(index);
+		}
+	CommitTransactionL();
+	}
+
+/**
+It updates log server id of the passed message in re-assembly store.
+
+@param aSmsMessage  a reference to a message.
+@param aIndex	index number of sms message to be updated.
+
+@internalComponent
+*/
+void CReassemblyStore::UpdateLogServerIdOfMessageL(const CSmsMessage& aSmsMessage, TInt aIndex)
+	{
+	LOGSMSPROT1("CReassemblyStore::UpdateLogServerIdOfMessageL()");
+    TInt  foundIndex(KErrNotFound);
+	TBool  found(EFalse);
+
+	BeginTransactionLC();
+
+	found = FindMessageL(aSmsMessage , EFalse, foundIndex);
+	if (found  &&  (aIndex == foundIndex))
+		{
+		const TReassemblyEntry&  entry = iEntryArray[foundIndex];
+		UpdateLogServerIdL(entry, aSmsMessage.LogServerId());
+		iEntryArray[foundIndex].SetLogServerId(aSmsMessage.LogServerId());
+		}
+	CommitTransactionL();
+	}
+
+/**
+It updates that the given SMS message in re-assembly store is passed to client.
+
+@param aSmsMessage  Message which is passed to client.
+
+@internalComponent
+*/
+void CReassemblyStore::SetMessagePassedToClientL(const CSmsMessage& aSmsMessage, TBool aPassed)
+	{
+	LOGSMSPROT1("CReassemblyStore::SetMessagePassedToClientL()");
+	TInt index(0);
+
+	BeginTransactionLC();
+
+	if (FindMessageL(aSmsMessage , !aPassed, index))
+		{
+		const TReassemblyEntry&  entry = iEntryArray[index];
+		SetPassedToClientL(entry, aPassed);
+		iEntryArray[index].SetPassedToClient(aPassed);
+		}
+	CommitTransactionL();
+	}
+
+/**
+It adds a new message segment to the reassembly store and it returns an index to the message.
+
+@param aIndex value indicating the index of the message added to re-assembly store.
+	It acts as output.
+
+@param aSmsMessage  a reference to the SMS message.
+	It acts as input.
+
+@param aGsmSms	a reference to GsmSms object which contain actual PDU.
+	It acts as input.
+
+@internalComponent
+*/
+void CReassemblyStore::NewMessagePDUL(TInt& aIndex,CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
+	{
+	LOGSMSPROT1("CReassemblyStore::NewMessagePDUL");
+
+	if (aSmsMessage.Time() >= iLastRealTime)
+		{
+		iLastRealTime=aSmsMessage.Time();
+		if(iLastReceivedTime >= aSmsMessage.Time())
+			{
+			aSmsMessage.SetTime(iLastReceivedTime+(TTimeIntervalMicroSeconds32)1);
+			}
+		iLastReceivedTime=aSmsMessage.Time(); //provide uniqueness of time
+		}
+	else  // clock turned back
+		{
+		iLastReceivedTime=aSmsMessage.Time();
+		}
+
+	TReassemblyEntry entry;
+	CReassemblyStoreUtility::PopulateEntry(entry,aSmsMessage,1);
+	BeginTransactionLC();
+	AddNewMessageL(aSmsMessage, aGsmSms);
+	CommitTransactionL();
+	//Successfully added so add the entry in entry array.
+	aIndex = iEntryArray.Count();
+	iEntryArray.AppendL(entry);
+	}
+
+/**
+It adds a new message segment to the existing message in reassembly store & returns
+whether this segment makes this message complete or not. It also returns whether this
+segment is the duplicate one or not.
+
+@param aSmsMessage  a reference to the SMS message.
+	It acts as input.
+
+@param aGsmSms	a reference to GsmSms object which contain actual PDU.
+	It acts as input.
+
+@param aIndex value indicating the index of the message added to re-assembly store.
+	It acts as output.
+
+@param aIsComplete  Boolean value indicating whether the message is complete or not.
+	It acts as output.
+
+@param aDuplicateMsgRef	Boolean value indicating whether the added segment is a duplicate one or not.
+	It acts as output.
+
+@param aDuplicateSlot Boolean value indicating whether the added segment is from duplicate slot or not.
+	It acts as output.
+
+@internalComponent
+*/
+void CReassemblyStore::UpdateExistingMessageL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms,
+												TInt aIndex, TBool& aIsComplete,
+												TBool& aDuplicateMsgRef, TBool& aDuplicateSlot)
+	{
+	LOGSMSPROT1("CReassemblyStore::UpdateExistingMessageL");
+	aIsComplete = EFalse;
+	BeginTransactionLC();
+	UpdateExistingMessageL(aSmsMessage, aGsmSms, aDuplicateMsgRef, aDuplicateSlot);
+	CommitTransactionL();
+	if ((aDuplicateMsgRef == EFalse) && (aDuplicateSlot==EFalse))
+		{
+		iEntryArray[aIndex].SetCount(iEntryArray[aIndex].Count() + 1);
+		if (iEntryArray[aIndex].IsComplete())
+			{
+			aIsComplete = ETrue;
+			}
+		}
+	}
+
+/**
+It matches the passed message in re-assembly store & returns the index.
+
+@param aSmsMessage  a reference to the SMS message.
+	It acts as input.
+
+@param aIndex index number of message in re-assembly store.
+	It acts as input.
+
+@internalComponent
+*/
+void CReassemblyStore::MatchPDUToExistingMessage(const CSmsMessage& aSmsMessage,
+													TInt& aIndex)
+	{
+	LOGSMSPROT1("CReassemblyStore::MatchPDUToExistingMessage()");
+
+	aIndex = KErrNotFound;
+
+	TGsmSmsTelNumber  parsedAddress;
+	aSmsMessage.ParsedToFromAddress(parsedAddress);
+
+	//
+	// Search the reassembly store for a matching entry (start from the
+	// end as the most recent PDUs appear at the end)...
+	//
+	TInt reassemblyCount = iEntryArray.Count();
+
+	for (TInt  index = 0;  index < reassemblyCount;  index++)
+		{
+		TReassemblyEntry&  entry = iEntryArray[index];
+		// Always check the fields in order of the quickest to check...
+		if (entry.IsComplete() == EFalse  &&
+		    entry.PduType() == aSmsMessage.Type()  &&
+			entry.Storage() == aSmsMessage.Storage())
+			{
+			TInt  telLen = Min(entry.Description2().Length(),
+					           parsedAddress.iTelNumber.Length());
+			
+			if (entry.Description2().Right(telLen) == parsedAddress.iTelNumber.Right(telLen)  &&
+		        entry.Total() == aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs()  &&
+			    entry.Reference() == aSmsMessage.SmsPDU().ConcatenatedMessageReference())
+				{
+				//
+				// Found it!
+				//
+				aIndex = index;
+				break;
+				}
+			}
+		}
+
+	LOGSMSPROT3("CReassemblyStore::MatchPDUToExistingMessage(): reassemblyCount=%d, aIndex=%d", reassemblyCount, aIndex);
+	} // CReassemblyStore::MatchPDUToExistingMessage
+
+/**
+It retrieves the message from re-assembly store.
+
+@param aIndex index number of message in re-assembly store.
+	It acts as input.
+
+@param aSmsMessage  a reference to the SMS message.
+	It acts as output.
+
+@internalComponent
+*/
+void CReassemblyStore::GetMessageL(TInt aIndex, CSmsMessage& aSmsMessage)
+	{
+	LOGSMSPROT1("CReassemblyStore::GetMessageL()");
+	const TReassemblyEntry&  entry = iEntryArray[aIndex];
+	RetrieveMessageL(entry, aSmsMessage);
+	}
+
+/**
+ *  Searches the reassembly store for a CSmsMessage with aPassed value (indicates if we 
+ *	are searching for a message already passed to client) and returns its index.
+ *
+ *  @param aSmsMessage  Message to search for.
+ *  @param aPassed      Determines if we are searching for a message already
+ *                      passed to the client.
+ *  @param aIndex       Return index value.
+ *
+ *  @return True and an index if aSmsMessage is found in this reassembly store
+ */
+TBool CReassemblyStore::FindMessageL(const CSmsMessage& aSmsMessage,
+										TBool aPassed,
+										TInt& aIndex)
+ 	{
+	LOGSMSPROT1("CReassemblyStore::FindMessageL()");
+
+	//
+	// Parse the GSM data from the SMS message...
+	//
+	TGsmSmsTelNumber  parsedAddress;
+
+	aSmsMessage.ParsedToFromAddress(parsedAddress);
+
+	//
+	// Search the store for a matching message...
+	//
+ 	for (TInt index = iEntryArray.Count() - 1;  index >= 0;  index--)
+ 		{
+		const TReassemblyEntry&  entry = iEntryArray[index];
+
+		// Always search the basic types first and strings last!
+		if (entry.PduType() == aSmsMessage.Type()  &&
+			entry.PassedToClient() == aPassed  &&
+			entry.Storage() == aSmsMessage.Storage()  &&
+			entry.Time() == aSmsMessage.Time()  &&
+			entry.Description2().Right(8) == parsedAddress.iTelNumber.Right(8))
+ 			{
+			//
+			// Found!
+			//
+			LOGSMSPROT2("CReassemblyStore::FindMessage(): Found! index=%d", index);
+
+			aIndex = index;
+			
+			return ETrue;
+			}
+ 		}
+
+	//
+	// Not found...
+	//
+	LOGSMSPROT1("CReassemblyStore::FindMessage(): Not found!");
+
+	return EFalse;
+	} // CReassemblyStore::FindMessageL