smsprotocols/smsstack/smsprot/Src/smspreassemblystore.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspreassemblystore.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +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