smsprotocols/smsstack/smsprot/Src/smspstor.cpp
changeset 0 3553901f7fa8
child 5 7ef16719d8cb
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements CSmsReassemblyStore and CSmsSegmentationStore.
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 
       
    22 #include <e32svr.h>
       
    23 #include <es_ini.h>
       
    24 #include "smspstor.h"
       
    25 #include "smspmain.h"
       
    26 #include "smsuaddr.H"
       
    27 #include "Gsmumsg.h"
       
    28 #include "gsmubuf.h"
       
    29 #include <logwrap.h>
       
    30 #include <logwraplimits.h>
       
    31 #include "Gsmuelem.h"
       
    32 #include "gsmuieoperations.h"
       
    33 #include "gsmunonieoperations.h"
       
    34 
       
    35 LOCAL_C TPtrC TrimLeadingZeros(const TDesC& aString)
       
    36 	{
       
    37 	LOGSMSPROT1("CSARStore::ExternalizeEntryArrayL()");
       
    38 
       
    39 	const TInt len = aString.Length();
       
    40 
       
    41 	if (len == 0)
       
    42 		return aString;
       
    43 
       
    44 	const TUint16* startChar = &aString[0];
       
    45 	const TUint16* endChar = &aString[len-1];
       
    46 
       
    47 	while (startChar <= endChar && *startChar == '0')
       
    48 		{
       
    49 		++startChar;
       
    50 		}
       
    51 	return TPtrC(startChar, endChar - startChar + 1);
       
    52 	} // TrimLeadingZeros
       
    53 
       
    54 
       
    55 /**
       
    56  *  Creates new CSmsReassemblyStore instance
       
    57  *  
       
    58  *  @param aFs  File Server handle.
       
    59  */
       
    60 CSmsReassemblyStore* CSmsReassemblyStore::NewL(RFs& aFs)
       
    61 	{
       
    62 	LOGSMSPROT1("CSmsReassemblyStore::NewL()");
       
    63 
       
    64 	CSmsReassemblyStore*  self = new (ELeave) CSmsReassemblyStore(aFs);
       
    65 	CleanupStack::PushL(self);
       
    66 	self->ConstructL();
       
    67 	CleanupStack::Pop(self);
       
    68 
       
    69 	return self;
       
    70 	} // CSmsReassemblyStore::NewL
       
    71 
       
    72 
       
    73 /**
       
    74  *  Creates and starts timer
       
    75  */
       
    76 void CSmsReassemblyStore::ConstructL()
       
    77 	{
       
    78 	LOGSMSPROT1("CSmsReassemblyStore::ConstructL()");
       
    79 
       
    80 	//
       
    81 	// Generate the full path to the reassembly store.
       
    82 	//
       
    83 	PrivatePath(iFullPathBuf);
       
    84 	iFullPathBuf.Append(KReassemblyStoreName);
       
    85 
       
    86  	iLastReceivedTime.UniversalTime();
       
    87  	iLastRealTime = iLastReceivedTime;
       
    88 	} // CSmsReassemblyStore::ConstructL
       
    89 
       
    90 
       
    91 /**
       
    92  *  Destructor
       
    93  */
       
    94 CSmsReassemblyStore::~CSmsReassemblyStore()
       
    95 	{
       
    96 	// NOP
       
    97 	} // CSmsReassemblyStore::~CSmsReassemblyStore
       
    98 
       
    99 
       
   100 void CSmsReassemblyStore::UpdateLogServerIdL(TInt aIndex, TLogId aLogServerId)
       
   101 	{
       
   102 	LOGSMSPROT1("CSmsReassemblyStore::UpdateLogServerIdL()");
       
   103 
       
   104 	TSmsReassemblyEntry entry(reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[aIndex]));
       
   105 
       
   106 	if (entry.LogServerId() != aLogServerId)
       
   107 		{
       
   108 		entry.SetLogServerId(aLogServerId);
       
   109 		BeginTransactionLC();
       
   110 		ChangeEntryL(aIndex, entry);
       
   111 		CommitTransactionL();
       
   112 		}
       
   113 	} // CSmsReassemblyStore::UpdateLogServerIdL
       
   114 
       
   115 
       
   116 /**
       
   117  *  Searches the reassembly store for a CSmsMessage and returns its index.
       
   118  *
       
   119  *  @param aSmsMessage  Message to search for.
       
   120  *  @param aPassed      Determines if we are searching for a message already
       
   121  *                      passed to the client.
       
   122  *  @param aIndex       Return index value.
       
   123  *
       
   124  *  @return True and an index if aSmsMessage is found in this reassembly store
       
   125  */
       
   126 TBool CSmsReassemblyStore::FindMessageL(const CSmsMessage& aSmsMessage,
       
   127 										TBool aPassed,
       
   128 										TInt& aIndex)
       
   129  	{
       
   130  	LOGSMSPROT1("CSmsReassemblyStore::FindMessageL()");
       
   131 
       
   132 	//
       
   133 	// Parse the GSM data from the SMS message...
       
   134 	//
       
   135 	TGsmSmsTelNumber  parsedAddress;
       
   136 
       
   137 	aSmsMessage.ParsedToFromAddress(parsedAddress);
       
   138 
       
   139 	//
       
   140 	// Search the store for a matching message...
       
   141 	//
       
   142  	for (TInt index = Entries().Count() - 1;  index >= 0;  index--)
       
   143  		{
       
   144 		const TSmsReassemblyEntry&  entry = reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[index]);
       
   145 
       
   146 		// Always search the basic types first and strings last!
       
   147 		if (entry.PduType() == aSmsMessage.Type()  &&
       
   148 			entry.PassedToClient() == aPassed  &&
       
   149 			entry.Storage() == aSmsMessage.Storage()  &&
       
   150 			entry.Time() == aSmsMessage.Time()  &&
       
   151 			entry.Description2().Right(8) == parsedAddress.iTelNumber.Right(8))
       
   152  			{
       
   153 			//
       
   154 			// Found!
       
   155 			//
       
   156 			LOGSMSPROT2("CSmsReassemblyStore::FindMessage(): Found! index=%d", index);
       
   157 
       
   158 			aIndex = index;
       
   159 
       
   160 			return ETrue;
       
   161 			}
       
   162  		}
       
   163 
       
   164 	//
       
   165 	// Not found...
       
   166 	//
       
   167 	LOGSMSPROT1("CSmsReassemblyStore::FindMessage(): Not found!");
       
   168 
       
   169  	return EFalse;
       
   170  	} // CSmsReassemblyStore::FindMessageL
       
   171 
       
   172 
       
   173 /**
       
   174  *  Adds Pdu to reassembly store
       
   175  *  
       
   176  *  @param aSmsMessage  PDU to 
       
   177  *  @param aGsmSms Used to
       
   178  *  @param aIndex Used to
       
   179  *  @param aComplete Used to
       
   180  *  @param aServiceCenterAddressPresent Used to
       
   181  */
       
   182 void CSmsReassemblyStore::MatchPDUToExistingMessage(const CSmsMessage& aSmsMessage,
       
   183 													TInt& aIndex)
       
   184 	{
       
   185 	LOGSMSPROT1("CSmsReassemblyStore::MatchPDUToExistingMessage()");
       
   186 
       
   187 	__ASSERT_ALWAYS(!aSmsMessage.IsDecoded(), SmspPanic(KSmspPanicMessageConcatenated));
       
   188 
       
   189 	aIndex = KErrNotFound;
       
   190 
       
   191 	TGsmSmsTelNumber  parsedAddress;
       
   192 	aSmsMessage.ParsedToFromAddress(parsedAddress);
       
   193 
       
   194 	//
       
   195 	// Search the reassembly store for a matching entry (start from the
       
   196 	// end as the most recent PDUs appear at the end)...
       
   197 	//
       
   198 	TInt reassemblyCount = Entries().Count();
       
   199 
       
   200 	for (TInt index = reassemblyCount - 1;  index >= 0;  index--)
       
   201 		{
       
   202 		TSmsReassemblyEntry&  entry = (TSmsReassemblyEntry&) Entries()[index];
       
   203 
       
   204 		// Always check the fields in order of the quickest to check...
       
   205 		if (entry.IsComplete() == EFalse  &&
       
   206 		    entry.PduType() == aSmsMessage.Type()  &&
       
   207 			entry.Storage() == aSmsMessage.Storage())
       
   208 			{
       
   209 			TInt  telLen = Min(entry.Description2().Length(),
       
   210 					           parsedAddress.iTelNumber.Length());
       
   211 			
       
   212 			if (entry.Description2().Right(telLen) == parsedAddress.iTelNumber.Right(telLen)  &&
       
   213 		        entry.Total() == aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs()  &&
       
   214 			    entry.Reference() == aSmsMessage.SmsPDU().ConcatenatedMessageReference())
       
   215 				{
       
   216 				//
       
   217 				// Found it!
       
   218 				//
       
   219 				aIndex = index;
       
   220 				break;
       
   221 				}
       
   222 			}
       
   223 		}
       
   224 
       
   225 	LOGSMSPROT3("CSmsReassemblyStore::MatchPDUToExistingMessage(): reassemblyCount=%d, aIndex=%d", reassemblyCount, aIndex);
       
   226 	} // CSmsReassemblyStore::MatchPDUToExistingMessage
       
   227 
       
   228 
       
   229 void CSmsReassemblyStore::UpdateExistingMessageL(const CSmsMessage& aSmsMessage,
       
   230 												 const TGsmSms& aGsmSms, TInt aIndex,
       
   231 												 TBool& aComplete,
       
   232 												 TBool& aDuplicateMsgRef,
       
   233 												 TBool& aDuplicateSlot)
       
   234 	{
       
   235 	LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL()");
       
   236 
       
   237 	aComplete        = EFalse;
       
   238 	aDuplicateMsgRef = EFalse;
       
   239 	aDuplicateSlot   = EFalse;
       
   240 
       
   241 	//
       
   242 	// Read the segment from the store into a CSmsMessage buffer...
       
   243 	//
       
   244 	TSmsReassemblyEntry  entry = (TSmsReassemblyEntry&) Entries()[aIndex];
       
   245 
       
   246 	CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(8);
       
   247 	CleanupStack::PushL(indexArray);
       
   248 	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(8);
       
   249 	CleanupStack::PushL(smsArray);
       
   250 	CSmsBuffer*  buffer = CSmsBuffer::NewL();
       
   251 	CSmsMessage*  smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
       
   252 	CleanupStack::PushL(smsMessage);
       
   253 
       
   254 	InternalizeEntryL(entry.DataStreamId(), *smsMessage, *indexArray, *smsArray);
       
   255 	
       
   256 	//
       
   257 	// Check if this is a duplicated enumerated PDU (e.g. on the SIM or phone memory)
       
   258 	// or a duplicated PDU (e.g. in the Reassembly Store)...
       
   259 	//
       
   260 	TInt  concatPDUIndex = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
       
   261 
       
   262 	if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage  ||
       
   263 		smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
       
   264 		{
       
   265 		//
       
   266 		// In most cases this PDU is being enumerated, but not always. It is
       
   267 		// possible for the PDU to be stored on the SIM first before it is
       
   268 		// received.
       
   269 		//
       
   270 		const TGsmSmsSlotEntry&  newSlot = aSmsMessage.iSlotArray[0];
       
   271 		TInt  slotArrayCount = smsMessage->iSlotArray.Count();
       
   272 
       
   273 		for (TInt slotNum = 0;  slotNum < slotArrayCount;  slotNum++ )
       
   274 			{
       
   275 			const TGsmSmsSlotEntry&  slot = smsMessage->iSlotArray[slotNum];
       
   276 
       
   277 			if (slot.iIndex == newSlot.iIndex  && slot.iStore == newSlot.iStore)
       
   278 				{
       
   279 				LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate enumerated PDU.");
       
   280 
       
   281 				// It is a duplicate that was already stored on the SIM...
       
   282 				aDuplicateSlot = ETrue;
       
   283 				break;
       
   284 				}
       
   285 			}
       
   286 		}
       
   287 
       
   288 	TInt  indexArrayCount = indexArray->Count();
       
   289 
       
   290 	for (TInt index = 0;  index < indexArrayCount;  index++ )
       
   291 		{
       
   292 		if (indexArray->At(index) == concatPDUIndex)
       
   293 			{
       
   294 			LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate concatenated PDU.");
       
   295 
       
   296 			// The PDU is already stored in the reassembly store.
       
   297 			aDuplicateMsgRef = ETrue;
       
   298 			break;
       
   299 			}
       
   300 		}
       
   301 
       
   302 	if (aDuplicateMsgRef  ||  aDuplicateSlot)
       
   303 		{
       
   304 		CleanupStack::PopAndDestroy(3, indexArray); // smsMessage, smsArray, indexArray
       
   305 		return;
       
   306 		}
       
   307 
       
   308 	//
       
   309 	// If the PDU is stored then add the slot information...
       
   310 	//
       
   311 	if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage  ||
       
   312 		smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
       
   313 		{
       
   314 		smsMessage->AddSlotL(aSmsMessage.iSlotArray[0]);
       
   315 		}
       
   316 
       
   317 	//
       
   318 	// If the PDU is Unsent or Unread, then store that information...
       
   319 	//
       
   320 	NMobileSmsStore::TMobileSmsStoreStatus  status = aSmsMessage.Status();
       
   321 
       
   322 	if (status == NMobileSmsStore::EStoredMessageUnsent  ||
       
   323 		status == NMobileSmsStore::EStoredMessageUnread)
       
   324 		{
       
   325 		smsMessage->SetStatus(status);
       
   326 		}
       
   327 
       
   328 	//
       
   329 	// Does this PDU mean the message is complete? If so then decode the message,
       
   330 	// reset the index and sms arrays (to save space for completed SMSs).
       
   331 	//
       
   332 	indexArray->AppendL(concatPDUIndex);
       
   333 	smsArray->AppendL(aGsmSms);
       
   334 
       
   335 	if (smsArray->Count() == smsMessage->SmsPDU().NumConcatenatedMessagePDUs())
       
   336 		{
       
   337 		smsMessage->DecodeMessagePDUsL(*smsArray);
       
   338 
       
   339 		indexArray->Reset();
       
   340 		smsArray->Reset();
       
   341 
       
   342 		aComplete = ETrue;
       
   343 		}
       
   344 
       
   345 	//
       
   346 	// Write the entry back into the store...
       
   347 	//
       
   348 	TStreamId  streamid = entry.DataStreamId();
       
   349 	smsMessage->SetLogServerId(entry.LogServerId());
       
   350 
       
   351 	BeginTransactionLC();
       
   352 	ExternalizeEntryL(streamid, *smsMessage, *indexArray, *smsArray);
       
   353 	PopulateEntry(entry, *smsMessage, smsArray->Count());
       
   354 	ChangeEntryL(aIndex, entry);
       
   355 	CommitTransactionL();
       
   356 
       
   357 	CleanupStack::PopAndDestroy(3, indexArray); // smsMessage, smsArray, indexArray
       
   358 	} // CSmsReassemblyStore::UpdateExistingMessageL
       
   359 
       
   360 
       
   361 void CSmsReassemblyStore::NewMessagePDUL(TInt& aIndex,CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
       
   362 	{
       
   363 	LOGSMSPROT1("CSmsReassemblyStore::NewMessagePDUL");
       
   364 
       
   365 	CArrayFix<TInt>* indexarray=new(ELeave) CArrayFixFlat<TInt>(8);
       
   366 	CleanupStack::PushL(indexarray);
       
   367 	CArrayFixFlat<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
       
   368 	CleanupStack::PushL(smsarray);
       
   369 	TInt index=aSmsMessage.IsDecoded()? 0: aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
       
   370 	indexarray->AppendL(index);
       
   371 	smsarray->AppendL(aGsmSms);
       
   372 	aIndex=Entries().Count();
       
   373 	CreateEntryL(aSmsMessage,*indexarray,*smsarray);
       
   374 	CleanupStack::PopAndDestroy(2);
       
   375 	} // CSmsReassemblyStore::NewMessagePDUL
       
   376 
       
   377 
       
   378 void CSmsReassemblyStore::GetMessageL(TInt aIndex,CSmsMessage& aSmsMessage)
       
   379 	{
       
   380 	LOGSMSPROT2("CSmsReassemblyStore::GetMessageL [aIndex=%d]", aIndex);
       
   381 
       
   382 	CArrayFix<TInt>* indexarray=new(ELeave) CArrayFixFlat<TInt>(8);
       
   383 	CleanupStack::PushL(indexarray);
       
   384 	CArrayFixFlat<TGsmSms>* smsarray=new(ELeave) CArrayFixFlat<TGsmSms>(8);
       
   385 	CleanupStack::PushL(smsarray);
       
   386 	InternalizeEntryL(Entries()[aIndex].DataStreamId(),aSmsMessage,*indexarray,*smsarray);
       
   387 	TInt logid=Entries()[aIndex].LogServerId();
       
   388 	if(aSmsMessage.LogServerId() == KLogNullId &&  logid != KLogNullId)
       
   389 		aSmsMessage.SetLogServerId(logid);
       
   390 	CleanupStack::PopAndDestroy(2); // smsarray, indexarray
       
   391 	} // CSmsReassemblyStore::GetMessageL
       
   392 
       
   393 
       
   394 /**
       
   395  *  internalize all the entries from the permanent file store to internal memory
       
   396  *  
       
   397  *  NOTE! You have to call CSARStore::OpenFileLC() before calling this function
       
   398  */
       
   399 void CSmsReassemblyStore::InternalizeEntryL(const TStreamId& aStreamId,CSmsMessage& aSmsMessage,CArrayFix<TInt>& aIndexArray,CArrayFix<TGsmSms>& aSmsArray)
       
   400 	{
       
   401 	LOGSMSPROT2("CSmsReassemblyStore::InternalizeEntryL Start [sid=%d]", aStreamId.Value());
       
   402 	RStoreReadStream readstream;
       
   403 	readstream.OpenLC(FileStore(),aStreamId);
       
   404 	readstream >> aSmsMessage;
       
   405 	TInt count=readstream.ReadInt32L();
       
   406 	aIndexArray.Reset();
       
   407 	TInt i;
       
   408 	for (i=0; i<count; i++)
       
   409 		{
       
   410 		TInt index=readstream.ReadInt32L();
       
   411 		aIndexArray.AppendL(index);
       
   412 		}
       
   413 	count=readstream.ReadInt32L();
       
   414 	if(count!=aIndexArray.Count())
       
   415 		User::Leave(KErrCorrupt);
       
   416 	aSmsArray.Reset();
       
   417 	for (i=0; i<count; i++)
       
   418 		{
       
   419 		RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
   420 		readstream >> pdu;
       
   421 		TGsmSms sms;
       
   422 		sms.SetPdu(pdu);
       
   423 		aSmsArray.AppendL(sms);
       
   424 		}
       
   425 	CleanupStack::PopAndDestroy();
       
   426 	LOGSMSPROT2("CSmsReassemblyStore::InternalizeEntryL End [count=%d]", count);
       
   427 	} // CSARStore::OpenFileLC
       
   428 
       
   429 
       
   430 /**
       
   431  *  externalizes all the entries from the internal memory to the permanent file store
       
   432  *  
       
   433  *  NOTE! You have to call CSARStore::OpenFileLC() before calling this function
       
   434  */
       
   435 void CSmsReassemblyStore::ExternalizeEntryL(TStreamId& aStreamId,const CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
       
   436 	{
       
   437 	LOGSMSPROT2("CSmsReassemblyStore::ExternalizeEntryL Start [sid=%d]", aStreamId.Value());
       
   438 
       
   439 	RStoreWriteStream writestream;
       
   440 	if (aStreamId==KNullStreamId)
       
   441 		aStreamId=writestream.CreateLC(FileStore());
       
   442 	else
       
   443 		writestream.ReplaceLC(FileStore(),aStreamId);
       
   444 	writestream << aSmsMessage;
       
   445 	TInt count=aIndexArray.Count();
       
   446 	__ASSERT_ALWAYS(count==aIndexArray.Count(),SmspPanic(KSmspPanicBadIndexArray));
       
   447 	writestream.WriteInt32L(count);
       
   448 	TInt i=0;
       
   449 	for (; i<count; i++)
       
   450 		writestream.WriteInt32L(aIndexArray[i]);
       
   451 	count=aSmsArray.Count();
       
   452 	writestream.WriteInt32L(count);
       
   453 	for (i=0; i<count; i++)
       
   454 		{
       
   455 		RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
   456 		pdu=aSmsArray[i].Pdu();
       
   457 		writestream << pdu;
       
   458 		}
       
   459 	writestream.CommitL();
       
   460 	CleanupStack::PopAndDestroy();
       
   461 
       
   462 	LOGSMSPROT2("CSmsReassemblyStore::ExternalizeEntryL End [count=%d]", count);
       
   463 	} // CSARStore::OpenFileLC
       
   464 
       
   465 
       
   466 void CSmsReassemblyStore::PopulateEntry(TSmsReassemblyEntry& aEntry,const CSmsMessage& aSmsMessage,TInt aNumSmss)
       
   467 	{
       
   468 	LOGSMSPROT1("CSmsReassemblyStore::PopulateEntry");
       
   469 	aEntry.SetReference(0);
       
   470 	aEntry.SetTotal(1);
       
   471 	aEntry.SetCount(1);
       
   472 
       
   473 	if (aSmsMessage.TextPresent())
       
   474 		{
       
   475 		if (aSmsMessage.SmsPDU().TextConcatenated())
       
   476 			{
       
   477 			aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
       
   478 			aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
       
   479 			aEntry.SetCount(aSmsMessage.IsComplete()? aEntry.Total(): aNumSmss);
       
   480 			}
       
   481 		TInt bits7to4=aSmsMessage.SmsPDU().Bits7To4();
       
   482 		TInt count=aSmsMessage.SmsPDU().UserData().NumInformationElements();
       
   483 		TInt identifier1=0xFF;
       
   484 		TInt identifier2=0x00;
       
   485 		for (TInt i=0; i<count; i++)
       
   486 			{
       
   487 			TInt identifier=aSmsMessage.SmsPDU().UserData().InformationElement(i).Identifier();
       
   488 			if ((identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages8BitReference) && (identifier!=CSmsInformationElement::ESmsIEIConcatenatedShortMessages16BitReference))
       
   489 				{
       
   490 				if (identifier<identifier1)
       
   491 					identifier1=identifier;
       
   492 				if (identifier>identifier2)
       
   493 					identifier2=identifier;
       
   494 				}
       
   495 			}
       
   496 
       
   497 		if ((bits7to4>=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage) && (bits7to4<=TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2))
       
   498 			aEntry.SetBits7to4andIdentifiers(bits7to4, identifier1, identifier2);
       
   499 		else
       
   500 			aEntry.SetBits7to4andIdentifiers(0, identifier1, identifier2);
       
   501 		}
       
   502 
       
   503 	//Set the logServerId to aSmsMessage.LogServerId()
       
   504 
       
   505 	aEntry.SetLogServerId(aSmsMessage.LogServerId());
       
   506 
       
   507 	const CSmsPDU::TSmsPDUType type(aSmsMessage.Type());
       
   508 	aEntry.SetPduType(type);
       
   509 	aEntry.SetPassedToClient(EFalse);
       
   510 
       
   511 	aEntry.SetStorage(aSmsMessage.Storage());
       
   512 	if ((type!=CSmsPDU::ESmsSubmitReport) && (type!=CSmsPDU::ESmsDeliverReport))
       
   513 		{
       
   514 		//  Strip out spaces etc from address
       
   515 		TGsmSmsTelNumber parsedaddress;
       
   516 		aSmsMessage.ParsedToFromAddress(parsedaddress);
       
   517 		aEntry.SetDescription2(parsedaddress.iTelNumber);
       
   518 		}
       
   519 
       
   520 	aEntry.SetTime(aSmsMessage.Time());
       
   521 	} // CSmsReassemblyStore::PopulateEntry
       
   522 
       
   523 
       
   524 void CSmsReassemblyStore::CreateEntryL(CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
       
   525 	{
       
   526 	LOGSMSPROT1("CSmsReassemblyStore::CreateEntryL");
       
   527  	TStreamId streamid=KNullStreamId;
       
   528  	if (aSmsMessage.Time() >= iLastRealTime)
       
   529  		{
       
   530  		iLastRealTime=aSmsMessage.Time();
       
   531  		if(iLastReceivedTime >= aSmsMessage.Time())
       
   532  			{
       
   533  			aSmsMessage.SetTime(iLastReceivedTime+(TTimeIntervalMicroSeconds32)1);
       
   534  			}
       
   535  		iLastReceivedTime=aSmsMessage.Time(); //provide uniqueness of time
       
   536  		}
       
   537  	else  // clock turned back
       
   538  		{
       
   539  		iLastReceivedTime=aSmsMessage.Time();
       
   540  		}
       
   541 	BeginTransactionLC();
       
   542 	ExternalizeEntryL(streamid,aSmsMessage,aIndexArray,aSmsArray);
       
   543 	TSmsReassemblyEntry entry;
       
   544 	entry.SetDataStreamId(streamid);
       
   545 
       
   546 	PopulateEntry(entry,aSmsMessage,aSmsArray.Count());
       
   547 	AddEntryL(entry);
       
   548 	CommitTransactionL();
       
   549 	} // CSmsReassemblyStore::CreateEntryL
       
   550 
       
   551 
       
   552 TBool CSmsReassemblyStore::PassedToClient( TInt aIndex ) const
       
   553 	{
       
   554 	LOGSMSPROT1("CSmsReassemblyStore::PassedToClient()");
       
   555 
       
   556 	const TSmsReassemblyEntry& entry = reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[ aIndex ]);
       
   557 	return entry.PassedToClient();
       
   558 	} // CSmsReassemblyStore::PassedToClient
       
   559 
       
   560 
       
   561 void CSmsReassemblyStore::SetPassedToClientL(TInt aIndex, TBool aPassed)
       
   562 //TODO CommentThisFunction
       
   563 	{
       
   564 	LOGSMSPROT1("CSmsReassemblyStore::SetPassedToClientL()");
       
   565 
       
   566 	TSmsReassemblyEntry entry(reinterpret_cast<const TSmsReassemblyEntry&>(Entries()[aIndex]));
       
   567 
       
   568 	const TBool alreadyPassed = entry.PassedToClient();
       
   569 
       
   570 	if ((!aPassed && alreadyPassed) || (aPassed && !alreadyPassed))
       
   571 		{
       
   572 		entry.SetPassedToClient(aPassed);
       
   573 		ChangeEntryL(aIndex, entry);
       
   574 		}
       
   575 	} // CSmsReassemblyStore::SetPassedToClientL
       
   576 
       
   577 
       
   578 /**
       
   579  *  Open the sms reassembly store.
       
   580  */
       
   581 void CSmsReassemblyStore::OpenStoreL()
       
   582 	{
       
   583 	LOGSMSPROT1("CSmsReassemblyStore::OpenStoreL()");
       
   584 
       
   585 	this->OpenL(iFullPathBuf,KReassemblyStoreUid);
       
   586 	} // CSmsReassemblyStore::OpenStoreL
       
   587 
       
   588 
       
   589 /**
       
   590  *  Constructor
       
   591  *  
       
   592  *  @param aFs Used to set CSARStore object
       
   593  */
       
   594 CSmsReassemblyStore::CSmsReassemblyStore(RFs& aFs)
       
   595 	:CSARStore(aFs)
       
   596 	{
       
   597 	// NOP
       
   598 	} // CSmsReassemblyStore::CSmsReassemblyStore
       
   599 
       
   600 
       
   601 CSmsSegmentationStore* CSmsSegmentationStore::NewL(RFs& aFs)
       
   602 	{
       
   603 	LOGSMSPROT1("CSmsSegmentationStore::NewL()");
       
   604 
       
   605 	CSmsSegmentationStore* segmentationStore = new(ELeave) CSmsSegmentationStore(aFs);
       
   606 	CleanupStack::PushL( segmentationStore );
       
   607 	segmentationStore->ConstructL();
       
   608 	CleanupStack::Pop( segmentationStore );
       
   609 	return segmentationStore;
       
   610 	} // CSmsSegmentationStore::NewL
       
   611 
       
   612 
       
   613 void CSmsSegmentationStore::ConstructL()
       
   614 	{
       
   615 	LOGSMSPROT1("CSmsSegmentationStore::ConstructL()");
       
   616 
       
   617 	//generate fullpath of segmentation store.
       
   618 	PrivatePath(iFullPathBuf);
       
   619 	//append store name
       
   620 	iFullPathBuf.Append(KSegmentationStoreName);
       
   621 	
       
   622 	// Set the default value for the maxmum number messages in the segmentation store.
       
   623 	iMaxmumNumberOfMessagesInSegmentationStore = KDefaultMaxmumNumberOfMessagesInSegmentationStore;
       
   624 
       
   625 	CESockIniData*  ini = NULL;
       
   626 	_LIT(KSmseskfile, "smswap.sms.esk");
       
   627 	TRAPD(ret, ini=CESockIniData::NewL(KSmseskfile));
       
   628 	if(ret == KErrNone)
       
   629 	    {
       
   630 	    // Get the maximum number of messages allowed in the segmentation store from .ESK file
       
   631         CleanupStack::PushL(ini);
       
   632         
       
   633         TPtrC value;
       
   634         if((ini->FindVar(_L("SegmentationStoreOptions"),_L("MaxNumOfMessInSegStore"),value)))
       
   635             {
       
   636             TLex16 valueconv(value);
       
   637             valueconv.Val(iMaxmumNumberOfMessagesInSegmentationStore); 
       
   638             }
       
   639         CleanupStack::PopAndDestroy(ini);    
       
   640 	    }
       
   641 	else if (ret != KErrNotFound && ret != KErrPathNotFound)
       
   642 	    {
       
   643 	    User::Leave(ret);
       
   644 	    }
       
   645 	} // CSmsSegmentationStore::ConstructL
       
   646 
       
   647 
       
   648 CSmsSegmentationStore::~CSmsSegmentationStore()
       
   649     {
       
   650     // NOP
       
   651     } // CSmsSegmentationStore::~CSmsSegmentationStore
       
   652 
       
   653 
       
   654 TInt CSmsSegmentationStore::Next8BitReferenceL()
       
   655 	{
       
   656 	LOGSMSPROT1("CSmsSegmentationStore::Next8BitReferenceL");
       
   657 
       
   658 	TInt reference8bit=0;
       
   659 	TInt reference16bit=0;
       
   660 	TStreamId streamid=ExtraStreamId();
       
   661 
       
   662 	//
       
   663 	// access file store
       
   664 	//
       
   665 	BeginTransactionLC();
       
   666 	if (streamid!=KNullStreamId)
       
   667 		{
       
   668 		TRAPD(ret,InternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
       
   669 		if(ret != KErrNone)
       
   670 			{
       
   671 			// We have to leave on any error; otherwise a duplicate reference number will be generated
       
   672 			// The transaction will revert
       
   673 			LOGSMSPROT2("WARNING! CSmsSegmentationStore::InternalizeConcatenationReferencesL left with %d", ret);
       
   674 			User::Leave(ret);  //  stream not corrupted
       
   675 			}
       
   676 		reference8bit=(reference8bit+1)%0x100;
       
   677 		}
       
   678 	TRAPD(ret, ExternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
       
   679 	if(ret != KErrNone)
       
   680 		{
       
   681 		// We have to leave on any error; otherwise a duplicate reference number will be generated
       
   682 		// The transaction will revert
       
   683 		LOGSMSPROT2("WARNING! CSmsSegmentationStore::ExternalizeConcatenationReferencesL left with %d", ret);
       
   684 		User::Leave(ret);  //  stream not corrupted
       
   685 		}
       
   686 	SetExtraStreamIdL(streamid);
       
   687 	CommitTransactionL();
       
   688 	return reference8bit;
       
   689 	} // CSmsSegmentationStore::Next8BitReferenceL
       
   690 
       
   691 
       
   692 TInt CSmsSegmentationStore::Next16BitReferenceL()
       
   693 	{
       
   694 	LOGSMSPROT1("CSmsSegmentationStore::Next16BitReferenceL");
       
   695 	TInt reference8bit=0;
       
   696 	TInt reference16bit=0x100;
       
   697 	TStreamId streamid=ExtraStreamId();
       
   698 	//
       
   699 	// access file store
       
   700 	//
       
   701 	BeginTransactionLC();
       
   702 	if (streamid!=KNullStreamId)
       
   703 		{
       
   704 		TRAPD(ret,InternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
       
   705 		if(ret != KErrNone)
       
   706 			{
       
   707 			// We have to leave on any error; otherwise a duplicate reference number will be generated
       
   708 			// The transaction will revert
       
   709 			LOGSMSPROT2("WARNING! CSmsSegmentationStore::InternalizeConcatenationReferencesL left with %d", ret);
       
   710 			User::Leave(ret);  //  stream not corrupted
       
   711 			}
       
   712 		reference16bit=((reference16bit+1)%0xFF00)+0x100;
       
   713 		}
       
   714 	TRAPD(ret, ExternalizeConcatenationReferencesL(streamid,reference8bit,reference16bit));
       
   715 	if(ret != KErrNone)
       
   716 		{
       
   717 		// We have to leave on any error; otherwise a duplicate reference number will be generated
       
   718 		// The transaction will revert
       
   719 		LOGSMSPROT2("WARNING! CSmsSegmentationStore::ExternalizeConcatenationReferencesL left with %d", ret);
       
   720 		User::Leave(ret);  //  stream not corrupted
       
   721 		}
       
   722 	SetExtraStreamIdL(streamid);
       
   723 	CommitTransactionL();
       
   724 	return reference16bit;
       
   725 	} // CSmsSegmentationStore::Next16BitReferenceL
       
   726 
       
   727 
       
   728 /**
       
   729  *  Adds a CSmsMessage to the segmentation store
       
   730  *  
       
   731  *  @note aSumbit.Buffer() may be shortened to TSAREntry::ESmsSAREntryDescriptionLength
       
   732  *  
       
   733  *  @param aSubmit Message to add to the segmentation store
       
   734  *  @pre aSubmit.Type() is ESmsSubmit
       
   735  *  @pre aSubmit.EncodeMessagePdusL() has been called. This is so PopulateEntry sets the correct total on the TSAREntry
       
   736  */
       
   737 void CSmsSegmentationStore::AddSubmitL(const TSmsAddr& aSmsAddr,CSmsMessage& aSubmit)
       
   738 	{
       
   739 	LOGSMSPROT1("CSmsSegmentationStore::AddSubmitL");
       
   740 
       
   741 	__ASSERT_ALWAYS(aSubmit.Type()==CSmsPDU::ESmsSubmit,SmspPanic(KSmspPanicNotSubmit));
       
   742 
       
   743 	BeginTransactionLC();
       
   744 
       
   745 
       
   746 	RSmsSegmentationStoreRefStatusArray refStatus;
       
   747 	CleanupClosePushL(refStatus);
       
   748 
       
   749 	TStreamId streamid=KNullStreamId;
       
   750 	CSmsBufferBase& buffer=aSubmit.Buffer();
       
   751 	TInt length=buffer.Length();
       
   752 	if (length>TSAREntry::ESmsSAREntryDescriptionLength)
       
   753 		buffer.DeleteL(TSAREntry::ESmsSAREntryDescriptionLength,length-TSAREntry::ESmsSAREntryDescriptionLength);
       
   754 
       
   755 	ExternalizeEntryL(streamid,aSmsAddr,aSubmit, refStatus);
       
   756 
       
   757 	TSmsSegmentationEntry entry;
       
   758 	entry.SetDataStreamId(streamid);
       
   759 	PopulateEntry(entry, aSubmit, refStatus);
       
   760 
       
   761 	CleanupStack::PopAndDestroy(&refStatus);
       
   762 
       
   763 	AddEntryL(entry);
       
   764 	CommitTransactionL();
       
   765 	} // CSmsSegmentationStore::AddSubmitL
       
   766 
       
   767 
       
   768 TBool CSmsSegmentationStore::AddCommandL(const TSmsAddr& aSmsAddr,const CSmsMessage& aCommand, CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray& aRefStatus)
       
   769 	{
       
   770 	LOGSMSPROT1("CSmsSegmentationStore::AddCommandL");
       
   771 	__ASSERT_ALWAYS(aCommand.Type()==CSmsPDU::ESmsCommand,SmspPanic(KSmspPanicNotCommand));
       
   772 	const TInt count=Entries().Count();
       
   773 	const TLogId logid=(TLogId) aCommand.LogServerId();
       
   774 
       
   775 	BeginTransactionLC();
       
   776 
       
   777 	//TODO AA: What is it doing here? Please comment
       
   778 	for (TInt i=count-1; i>=0; --i)
       
   779 		{
       
   780 		if ((logid!=KLogNullId) && (logid==Entries()[i].LogServerId()))
       
   781 			{
       
   782 			DeleteEntryL(i);
       
   783 			break;
       
   784 			}
       
   785 		}
       
   786 	TBool found=EFalse;
       
   787 
       
   788 	CSmsBuffer* buffer=CSmsBuffer::NewL();
       
   789 	CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsSubmit,buffer);
       
   790 	CleanupStack::PushL(smsmessage);
       
   791 	TGsmSmsTelNumber parsedaddress;
       
   792 	aCommand.ParsedToFromAddress(parsedaddress);
       
   793 	TInt telLen;
       
   794 
       
   795 	for (TInt j=0; j<count; j++)
       
   796 		{
       
   797 		TSmsSegmentationEntry entry = (TSmsSegmentationEntry&)Entries()[j];
       
   798 		const CSmsPDU::TSmsPDUType type = entry.PduType();
       
   799 		telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
       
   800 		if ((type==CSmsPDU::ESmsSubmit) &&
       
   801 			 entry.IsComplete() &&
       
   802 		    (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)) &&
       
   803 		    (entry.Time()==aCommand.Time()))
       
   804 			{
       
   805 			found=ETrue;
       
   806 			TSmsAddr smsaddr;
       
   807 
       
   808 			InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, aRefStatus);
       
   809 			TStreamId streamid;
       
   810 			CSmsSubmit& submit=(CSmsSubmit&) smsmessage->SmsPDU();
       
   811 			if ((((CSmsCommand&) aCommand.SmsPDU()).CommandType()==TSmsCommandType::ESmsCommandTypeEnableStatusReportRequest) &&
       
   812 			     (!submit.StatusReportRequest()))
       
   813 				{
       
   814 				submit.SetStatusReportRequest(ETrue);
       
   815 				streamid=entry.DataStreamId();
       
   816 				ExternalizeEntryL(streamid,smsaddr,*smsmessage, aRefStatus);
       
   817 				PopulateEntry(entry,*smsmessage, aRefStatus);
       
   818 				ChangeEntryL(j,entry);
       
   819 				}
       
   820 
       
   821 			//TODO What is happening here? Seems strange
       
   822 			RSmsSegmentationStoreRefStatusArray refStatusTemp;
       
   823 			CleanupClosePushL(refStatusTemp);
       
   824 
       
   825 			streamid=KNullStreamId;
       
   826 
       
   827 			ExternalizeEntryL(streamid,aSmsAddr,aCommand, refStatusTemp);
       
   828 			entry.SetDataStreamId(streamid);
       
   829 			PopulateEntry(entry,aCommand, refStatusTemp);
       
   830 
       
   831 			CleanupStack::PopAndDestroy(&refStatusTemp);
       
   832 
       
   833 			AddEntryL(entry);
       
   834 
       
   835 			break;
       
   836 			}
       
   837 		}
       
   838 	CleanupStack::PopAndDestroy(smsmessage);  // smsmessage
       
   839 	CommitTransactionL();
       
   840 
       
   841 	return found;
       
   842 	} // CSmsSegmentationStore::AddCommandL
       
   843 
       
   844 
       
   845 TBool CSmsSegmentationStore::AddReferenceL(const CSmsMessage& aSmsMessage,TInt aReference)
       
   846 	{
       
   847 	TSmsSegmentationEntry entry; // TODO const and inside loop
       
   848 	const TInt count=Entries().Count();
       
   849 	LOGSMSPROT3("CSmsSegmentationStore::AddReferenceL [count=%d, ref=%d]", count, aReference);
       
   850 	TInt i=0;
       
   851 	TInt logserverid=aSmsMessage.LogServerId();
       
   852 	if (logserverid!=KLogNullId)
       
   853 		{
       
   854 		for (i=0; i<count; i++)
       
   855 			{
       
   856 			entry = (TSmsSegmentationEntry&)Entries()[i];
       
   857 			if (logserverid==entry.LogServerId())
       
   858 				break;
       
   859 			}
       
   860 		}
       
   861 	else
       
   862 		{
       
   863 		TGsmSmsTelNumber parsedaddress;
       
   864 		aSmsMessage.ParsedToFromAddress(parsedaddress);
       
   865 		TInt telLen;
       
   866 		for (i=0; i<count; i++)
       
   867 			{
       
   868 			entry = (TSmsSegmentationEntry&)Entries()[i];
       
   869 			telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
       
   870 			const CSmsPDU::TSmsPDUType type=entry.PduType();
       
   871 			if ((type==aSmsMessage.Type()) && (!entry.IsComplete()) && (aSmsMessage.Time()==entry.Time()) && (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
       
   872 				break;
       
   873 			}
       
   874 		}
       
   875 //	__ASSERT_DEBUG(i<count,SmspPanic(KSmspPanicEntryWithLogServerIdNotFound)); TODO
       
   876 	if(i>=count)
       
   877 		{
       
   878 		LOGSMSPROT3("WARNING! KSmspPanicEntryWithLogServerIdNotFound [i=%d, count=%d]", i, count);
       
   879 		}
       
   880 
       
   881 	RSmsSegmentationStoreRefStatusArray refStatusArray;
       
   882 	CleanupClosePushL(refStatusArray);
       
   883 
       
   884 	TStreamId streamid=entry.DataStreamId();
       
   885 	TSmsAddr smsaddr;
       
   886 	CSmsBuffer* buffer=CSmsBuffer::NewL();
       
   887 	CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
       
   888 	CleanupStack::PushL(smsmessage);
       
   889 
       
   890 	//
       
   891 	// access the file store
       
   892 	//
       
   893 	InternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
       
   894 	refStatusArray.InsertL(aReference);
       
   895 
       
   896 	BeginTransactionLC();
       
   897 	ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
       
   898 
       
   899 	PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray);
       
   900 	ChangeEntryL(i,entry);
       
   901 	CommitTransactionL();
       
   902 
       
   903 	//
       
   904 	// AEH: moved here because if is done before calling ChangeEntryL
       
   905 	//      it will pop and destroy the filestore which is also on
       
   906 	//      the cleanup stack
       
   907 	//
       
   908 	CleanupStack::PopAndDestroy(2);  //  smsmessage, refStatus
       
   909 
       
   910 	return entry.Total()==entry.Count();
       
   911 	}
       
   912 
       
   913 	
       
   914 /**
       
   915  *  Does exactly the same thing as AddReferenceL() i.e. adds the the segment refernce to a list. But 
       
   916  *  to support the new status report schemes a slight change has been made. Instead of inserting
       
   917  *  just a reference now its status is inserted as well. This is provided one of the two new schemes
       
   918  *  is being used. If the status is required then we do exactly the same as AddReferenceL(), but if
       
   919  *  it's not then we just call the InsertL() method with an extra parameter: EStatusComplete.
       
   920  *  
       
   921  *  @param aSmsMessage Reference to CSmsMessage.
       
   922  *  @param aReference  The PDU reference.
       
   923  */
       
   924 TBool CSmsSegmentationStore::AddReferenceStatusPairL(const CSmsMessage& aSmsMessage,TInt aReference, TUint aSegmentSequenceNumber)
       
   925  	{
       
   926 	TSmsSegmentationEntry entry; // TODO const and inside loop
       
   927 	const TInt count=Entries().Count();
       
   928 	LOGSMSPROT3("CSmsSegmentationStore::AddReferenceStatusPairL [count=%d, ref=%d]", count, aReference);
       
   929 	TInt i=0;
       
   930 	TInt logserverid=aSmsMessage.LogServerId();
       
   931 	if (logserverid!=KLogNullId)
       
   932 		{
       
   933 		for (i=0; i<count; i++)
       
   934 			{
       
   935 			entry = (TSmsSegmentationEntry&)Entries()[i];
       
   936 			if (logserverid==entry.LogServerId())
       
   937 				break;
       
   938 			}
       
   939 		}
       
   940 	else
       
   941 		{
       
   942 		TGsmSmsTelNumber parsedaddress;
       
   943 		aSmsMessage.ParsedToFromAddress(parsedaddress);
       
   944 		TInt telLen;
       
   945 		for (i=0; i<count; i++)
       
   946 			{
       
   947 			entry = (TSmsSegmentationEntry&)Entries()[i];
       
   948 			telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
       
   949 			const CSmsPDU::TSmsPDUType type=entry.PduType();
       
   950 			if ((type==aSmsMessage.Type()) && (!entry.IsComplete()) && (aSmsMessage.Time()==entry.Time()) && (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
       
   951 				break;
       
   952 			}
       
   953 		}
       
   954 //	__ASSERT_DEBUG(i<count,SmspPanic(KSmspPanicEntryWithLogServerIdNotFound)); TODO
       
   955 	if(i>=count)
       
   956 		{
       
   957 		LOGSMSPROT3("WARNING! KSmspPanicEntryWithLogServerIdNotFound [i=%d, count=%d]", i, count);
       
   958 		}
       
   959 
       
   960 	RSmsSegmentationStoreRefStatusArray refStatusArray;
       
   961 	CleanupClosePushL(refStatusArray);
       
   962 
       
   963 	TStreamId streamid=entry.DataStreamId();
       
   964 	TSmsAddr smsaddr;
       
   965 	CSmsBuffer* buffer=CSmsBuffer::NewL();
       
   966 	CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
       
   967 	CleanupStack::PushL(smsmessage);
       
   968 
       
   969 	//
       
   970 	// access the file store
       
   971 	//
       
   972 	InternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
       
   973 	
       
   974 	if (aSmsMessage.Scheme() == EControlParametersScheme)
       
   975 		{
       
   976 		TUint8 octet(0);
       
   977 		TInt  ret;
       
   978 		
       
   979 		ret = ((CSmsSMSCCtrlParameterOperations&)aSmsMessage.GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters)).GetStatusReport(aSegmentSequenceNumber, octet);
       
   980 		if (ret == KErrNone)
       
   981 			{
       
   982 			if (octet & ESmsSMSCControlParametersMask)
       
   983 				{
       
   984 				refStatusArray.InsertL(aReference);	
       
   985 				}
       
   986 			else
       
   987 				{
       
   988 				refStatusArray.InsertL(TSmsSegmentationStoreRefStatus(aReference, EStatusComplete));	
       
   989 				}
       
   990 			}
       
   991 		}
       
   992 	else if(aSmsMessage.Scheme() == ETPSRRScheme)
       
   993 		{
       
   994 		TInt tpsrr;
       
   995 		tpsrr =  ((CSmsTPSRROperations&)aSmsMessage.GetOperationsForNonIEL(ESmsTPSRRParameter)).GetStatusReport(aSegmentSequenceNumber);
       
   996 		
       
   997 		if(tpsrr == TSmsFirstOctet::ESmsStatusReportNotRequested)
       
   998 			{
       
   999 			refStatusArray.InsertL(TSmsSegmentationStoreRefStatus(aReference, EStatusComplete));
       
  1000 			}
       
  1001 		else if(tpsrr == TSmsFirstOctet::ESmsStatusReportRequested)
       
  1002 			{
       
  1003 			refStatusArray.InsertL(aReference);	
       
  1004 			}	
       
  1005 		}
       
  1006 	else
       
  1007 		{
       
  1008 		User::Leave(KErrArgument);
       
  1009 		}
       
  1010 	
       
  1011 
       
  1012 	BeginTransactionLC();
       
  1013 	ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
       
  1014 
       
  1015 	PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray);
       
  1016 	ChangeEntryL(i,entry);
       
  1017 	CommitTransactionL();
       
  1018 
       
  1019 	//
       
  1020 	// AEH: moved here because if is done before calling ChangeEntryL
       
  1021 	//      it will pop and destroy the filestore which is also on
       
  1022 	//      the cleanup stack
       
  1023 	//
       
  1024 	CleanupStack::PopAndDestroy(2);  //  smsmessage, refStatus
       
  1025 
       
  1026 	return entry.Total()==entry.Count();
       
  1027 	} // CSmsSegmentationStore::AddReferenceStatusPairL
       
  1028 
       
  1029 
       
  1030 TBool CSmsSegmentationStore::AddStatusReportL(TInt& aIndex,TBool& aComplete,const CSmsMessage& aStatusReport)
       
  1031 	{
       
  1032 	LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL");
       
  1033 
       
  1034 	__ASSERT_DEBUG(aStatusReport.Type()==CSmsPDU::ESmsStatusReport,SmspPanic(KSmspPanicNotStatusReport));
       
  1035 
       
  1036 	const CSmsStatusReport& statusreport=(CSmsStatusReport&) aStatusReport.SmsPDU();
       
  1037 	const TInt reference=statusreport.MessageReference();
       
  1038 	const TInt status=statusreport.Status();
       
  1039 	const TInt isPerm = IsPermanentStatus(status);
       
  1040 	const TSmsFirstOctet::TSmsStatusReportQualifier qualifier=statusreport.StatusReportQualifier();
       
  1041 	TBool found=EFalse;
       
  1042 	aComplete=EFalse;
       
  1043 
       
  1044 	LOGSMSPROT4("CSmsSegmentationStore::AddStatusReportL [ref=%d status=%d IsPerm=%d]", reference, status, isPerm);
       
  1045 
       
  1046 	if(!isPerm)
       
  1047 		{
       
  1048 		return EFalse;
       
  1049 		}
       
  1050 
       
  1051 	RSmsSegmentationStoreRefStatusArray refStatusArray;
       
  1052 	CleanupClosePushL(refStatusArray);
       
  1053 
       
  1054 	const TInt count1=Entries().Count();
       
  1055 
       
  1056 	TSmsAddr smsaddr;
       
  1057 	CSmsBuffer* buffer=CSmsBuffer::NewL();
       
  1058 	CSmsMessage* smsmessage=CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver,buffer);
       
  1059 	CleanupStack::PushL(smsmessage);
       
  1060 	TGsmSmsTelNumber parsedaddress;
       
  1061 	aStatusReport.ParsedToFromAddress(parsedaddress);
       
  1062 	TSmsSegmentationEntry entry; // TODO const ref and inside loop
       
  1063 
       
  1064 	BeginTransactionLC();
       
  1065 
       
  1066 	aIndex = count1;
       
  1067 
       
  1068 	TInt telLen;
       
  1069 	while (!found && aIndex--)
       
  1070 		{
       
  1071 		entry = (TSmsSegmentationEntry&)Entries()[aIndex];
       
  1072 
       
  1073 		// Remove leading zeros of national numbers
       
  1074 		TPtrC trimmedTelNumber(TrimLeadingZeros(entry.Description2()));
       
  1075 		TPtrC trimmedParsedTelNumber(TrimLeadingZeros(parsedaddress.iTelNumber));
       
  1076 
       
  1077 		telLen=Min(trimmedTelNumber.Length(),trimmedParsedTelNumber.Length());
       
  1078 
       
  1079 		const CSmsPDU::TSmsPDUType type = entry.PduType();
       
  1080 		const TInt startref = entry.Reference1();
       
  1081 		const TInt stopref = entry.Reference2();
       
  1082 
       
  1083 		TBool sameTelNumbers = entry.Description2().Right(telLen) == parsedaddress.iTelNumber.Right(telLen);
       
  1084 		
       
  1085 		if (sameTelNumbers)
       
  1086 			{
       
  1087 			LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL telNumber from submit report matches that from SMS message");
       
  1088 			}
       
  1089 		else
       
  1090 			{
       
  1091 			LOGSMSPROT1("CSmsSegmentationStore::AddStatusReportL telNumber from submit report does NOT match that from SMS message");
       
  1092 			}
       
  1093 
       
  1094 		if (sameTelNumbers &&
       
  1095 		  (((qualifier==TSmsFirstOctet::ESmsStatusReportResultOfCommand) && (type==CSmsPDU::ESmsCommand)) ||
       
  1096 		   ((qualifier==TSmsFirstOctet::ESmsStatusReportResultOfSubmit) &&  (type==CSmsPDU::ESmsSubmit))) &&
       
  1097 		   (((stopref>=startref) &&(reference>=startref) && (reference<=stopref))||((stopref<startref) &&((reference>=startref) || (reference<=stopref))))
       
  1098 		   )
       
  1099 			{
       
  1100 			InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, refStatusArray);
       
  1101 			TInt refStatusPos = refStatusArray.Find(reference); //assumes Find returns the first matching reference in the array
       
  1102 			TInt numMessagePDUs=entry.Total();
       
  1103 
       
  1104 			if (refStatusPos != KErrNotFound)
       
  1105 				{
       
  1106 				const TInt refStatusArrayCount = refStatusArray.Count();
       
  1107 
       
  1108 				//Find an element in refStatusArray where Reference() == reference and Status() is not permanent
       
  1109 				while (!found && refStatusPos < refStatusArrayCount && refStatusArray[refStatusPos].Reference() == reference)
       
  1110 					{
       
  1111 					//@note This loop assumes refStatusArray is sorted iReference
       
  1112 					if (!IsPermanentStatus(refStatusArray[refStatusPos].Status())&&(refStatusArrayCount <= numMessagePDUs))
       
  1113 						{
       
  1114 						found = ETrue;
       
  1115 						}
       
  1116 					else
       
  1117 						{
       
  1118 						LOGSMSPROT4("CSmsSegmentationStore::AddStatusReportL WARNING: Status already perm [status=%d refStatusPos=%d count=%d]", refStatusArray[refStatusPos].Status(), refStatusPos, refStatusArrayCount);
       
  1119 						refStatusPos++;
       
  1120 						}
       
  1121 					}
       
  1122 
       
  1123 				if (found)
       
  1124 					{
       
  1125 					LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL Found [refStatusPos=%d]", refStatusPos);
       
  1126 					refStatusArray[refStatusPos].SetStatus(status);
       
  1127 					TStreamId streamid=entry.DataStreamId();
       
  1128 					ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray);
       
  1129 					PopulateEntry(entry,*smsmessage, refStatusArray);
       
  1130 					ChangeEntryL(aIndex,entry);
       
  1131 					aComplete=StatusArrayComplete(refStatusArray, entry);
       
  1132 				    LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL StatusArrayComplete %d", aComplete);
       
  1133 					}
       
  1134 				}
       
  1135 			}
       
  1136 		}
       
  1137 
       
  1138 	if (found && (smsmessage->Type()==CSmsPDU::ESmsCommand))  // look for original submit
       
  1139 		{
       
  1140 		TTime time=smsmessage->Time();
       
  1141 		found=EFalse;
       
  1142 
       
  1143 		RSmsSegmentationStoreRefStatusArray refStatusArray2;
       
  1144 		CleanupClosePushL(refStatusArray2);
       
  1145 		refStatusArray2.CopyL(refStatusArray);
       
  1146 		refStatusArray2.ResetAllStatus();
       
  1147 
       
  1148 		aComplete=EFalse;
       
  1149 		TInt telLen;
       
  1150 		for (aIndex=0; aIndex<count1; aIndex++)
       
  1151 			{
       
  1152 			entry = (TSmsSegmentationEntry&)Entries()[aIndex];
       
  1153 			telLen=Min(entry.Description2().Length(),parsedaddress.iTelNumber.Length());
       
  1154 			const CSmsPDU::TSmsPDUType type = entry.PduType();
       
  1155 			if ((type==CSmsPDU::ESmsSubmit) &&
       
  1156 				 entry.IsComplete() &&
       
  1157 			    (entry.Time()==time) &&
       
  1158 			    (entry.Description2().Right(telLen)==parsedaddress.iTelNumber.Right(telLen)))
       
  1159 				{
       
  1160 
       
  1161 				/*
       
  1162 				TODO ahe - this should take out of the for loop
       
  1163 				only set/delete flags in the for loop and let the methods:
       
  1164 				InternalizeXXX
       
  1165 				ExternalizeXXX
       
  1166 				PopulateEntry
       
  1167 				ChangeEntry
       
  1168 				... all ... other big CSarStore methods
       
  1169 				have only to run once -> internal loop in this function through
       
  1170 				the array of flags
       
  1171 				*/
       
  1172 
       
  1173 				found=ETrue;
       
  1174 				InternalizeEntryL(entry.DataStreamId(),smsaddr,*smsmessage, refStatusArray2);
       
  1175 				const TInt count2 = refStatusArray.Count();
       
  1176 				__ASSERT_DEBUG(count2 == refStatusArray2.Count(),SmspPanic(KSmspPanicBadReferenceArray));
       
  1177 				for (TInt i=0; i<count2; i++)
       
  1178 					{
       
  1179 					//TODO What is this doing?
       
  1180 					TSmsSegmentationStoreRefStatus& refStatus2 = refStatusArray2[i];
       
  1181 					if (!IsPermanentStatus(refStatus2.Status()))
       
  1182 						{
       
  1183 						refStatus2.SetStatus(refStatusArray[i].Status());
       
  1184 						}
       
  1185 					}
       
  1186 
       
  1187 				TStreamId streamid=entry.DataStreamId();
       
  1188 				ExternalizeEntryL(streamid,smsaddr,*smsmessage, refStatusArray2);
       
  1189 				PopulateEntry(entry,/*smsaddr,*/*smsmessage, refStatusArray2);
       
  1190 				ChangeEntryL(aIndex,entry);
       
  1191 				aComplete=StatusArrayComplete(refStatusArray2, entry);
       
  1192 			    LOGSMSPROT3("CSmsSegmentationStore::StatusArrayComplete [aStatus=%d, ret=%d]", status, aComplete);
       
  1193 				break;
       
  1194 				}
       
  1195 			}
       
  1196 
       
  1197 		CleanupStack::PopAndDestroy(&refStatusArray2);
       
  1198 		}
       
  1199 
       
  1200 	CommitTransactionL();
       
  1201 	CleanupStack::PopAndDestroy(2); // smsmessage, refStatusArray
       
  1202 
       
  1203 	LOGSMSPROT2("CSmsSegmentationStore::AddStatusReportL Exit [found=%d]", found);
       
  1204 	return found;
       
  1205 	} // CSmsSegmentationStore::AddStatusReportL
       
  1206 
       
  1207 
       
  1208 void CSmsSegmentationStore::GetMessageL(TInt aIndex,TSmsAddr& aSmsAddr,CSmsMessage& aSmsMessage, RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
       
  1209 	{
       
  1210 	LOGSMSPROT2("CSmsSegmentationStore::GetMessageL [aIndex=%d]", aIndex);
       
  1211 
       
  1212 	InternalizeEntryL(Entries()[aIndex].DataStreamId(),aSmsAddr,aSmsMessage, aRefStatusArray);
       
  1213 	} // CSmsSegmentationStore::GetMessageL
       
  1214 
       
  1215 
       
  1216 /**
       
  1217  *  internalize the concat refs from the permanent file store to internal memory
       
  1218  *  
       
  1219  *  @note You have to call CSARStore::OpenFileLC() before calling this function
       
  1220  *  and CSARStore::CloseFile() after.
       
  1221  */
       
  1222 void CSmsSegmentationStore::InternalizeConcatenationReferencesL(const TStreamId& aStreamId,TInt& aReference8bit,TInt& aReference16bit)
       
  1223 	{
       
  1224 	LOGSMSPROT1("CSmsSegmentationStore::InternalizeConcatenationReferencesL Start");
       
  1225 	RStoreReadStream readstream;
       
  1226 	readstream.OpenLC(FileStore(),aStreamId);
       
  1227 	aReference8bit=readstream.ReadInt32L();
       
  1228 	aReference16bit=readstream.ReadInt32L();
       
  1229 	CleanupStack::PopAndDestroy();
       
  1230 	LOGSMSPROT1("CSmsSegmentationStore::InternalizeConcatenationReferencesL End");
       
  1231 	} // CSmsSegmentationStore::InternalizeConcatenationReferencesL
       
  1232 
       
  1233 
       
  1234 /**
       
  1235  *  externalize the concat refs from the permanent file store to internal memory
       
  1236  *  
       
  1237  *  @note You have to call CSARStore::OpenFileLC() before calling this function
       
  1238  *  and CSARStore::CloseFile() after.
       
  1239  */
       
  1240 void CSmsSegmentationStore::ExternalizeConcatenationReferencesL(TStreamId& aStreamId,TInt aReference8bit,TInt aReference16bit)
       
  1241 	{
       
  1242 	LOGSMSPROT1("CSmsSegmentationStore::ExternalizeConcatenationReferencesL Start");
       
  1243 	RStoreWriteStream writestream;
       
  1244 	if (aStreamId==KNullStreamId)
       
  1245 		aStreamId=writestream.CreateLC(FileStore());
       
  1246 	else
       
  1247 		writestream.ReplaceLC(FileStore(),aStreamId);
       
  1248 	writestream.WriteInt32L(aReference8bit);
       
  1249 	writestream.WriteInt32L(aReference16bit);
       
  1250 	writestream.CommitL();
       
  1251 	CleanupStack::PopAndDestroy();
       
  1252 	LOGSMSPROT1("CSmsSegmentationStore::ExternalizeConcatenationReferencesL End");
       
  1253 	} // CSmsSegmentationStore::ExternalizeConcatenationReferencesL
       
  1254 
       
  1255 
       
  1256 /**
       
  1257  *  internalize all the entries from the permanent file store to internal memory
       
  1258  *  
       
  1259  *  @note You have to call CSARStore::OpenFileLC() before calling this function
       
  1260  *  and CSARStore::CloseFile() after.
       
  1261  */
       
  1262 void CSmsSegmentationStore::InternalizeEntryL(const TStreamId& aStreamId,TSmsAddr& aSmsAddr,CSmsMessage& aSmsMessage, RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
       
  1263 	{
       
  1264 	LOGSMSPROT1("CSmsSegmentationStore::InternalizeEntryL Start");
       
  1265 
       
  1266 	aRefStatusArray.Reset();
       
  1267 
       
  1268 	RStoreReadStream readstream;
       
  1269 	readstream.OpenLC(FileStore(),aStreamId);
       
  1270 	readstream >> aSmsAddr;
       
  1271 	readstream >> aSmsMessage;
       
  1272 	readstream >> aRefStatusArray;
       
  1273 	CleanupStack::PopAndDestroy(&readstream);
       
  1274 
       
  1275 	LOGSMSPROT2("CSmsSegmentationStore::InternalizeEntryL End [count=%d]", aRefStatusArray.Count());
       
  1276 	} // CSmsSegmentationStore::InternalizeEntryL
       
  1277 
       
  1278 
       
  1279 /**
       
  1280  *  externalizes all the entries from the internal memory to the permanent file store
       
  1281  */
       
  1282 void CSmsSegmentationStore::ExternalizeEntryL(TStreamId& aStreamId,const TSmsAddr& aSmsAddr,const CSmsMessage& aSmsMessage, const RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
       
  1283 	{
       
  1284 	LOGSMSPROT1("CSmsSegmentationStore::ExternalizeEntryL Start");
       
  1285 
       
  1286 	RStoreWriteStream writestream;
       
  1287 
       
  1288 	if (aStreamId==KNullStreamId)
       
  1289 		aStreamId=writestream.CreateLC(FileStore());
       
  1290 	else
       
  1291 		writestream.ReplaceLC(FileStore(),aStreamId);
       
  1292 
       
  1293 	writestream << aSmsAddr;
       
  1294 	writestream << aSmsMessage;
       
  1295 	writestream << aRefStatusArray;
       
  1296 	writestream.CommitL();
       
  1297 	CleanupStack::PopAndDestroy(&writestream);
       
  1298 
       
  1299 	LOGSMSPROT2("CSmsSegmentationStore::ExternalizeEntryL End [count=%d]", aRefStatusArray.Count());
       
  1300 	} // CSmsSegmentationStore::ExternalizeEntryL
       
  1301 
       
  1302 
       
  1303 /**
       
  1304  *  Populates an SMS message into SAR store entry
       
  1305  *  
       
  1306  *  @pre aSmsMessage.EncodeMessagePdusL() has been called
       
  1307  *  
       
  1308  *  @param aEntry          Entry to be populated to
       
  1309  *  @param aSmsMessage     SMS message to be populated from
       
  1310  *  @param aReferenceArray Array containing references
       
  1311  *  @param aStatusArray    Array containing status
       
  1312  */
       
  1313 void CSmsSegmentationStore::PopulateEntry(TSmsSegmentationEntry& aEntry,
       
  1314 					  const CSmsMessage& aSmsMessage,
       
  1315 					  const RSmsSegmentationStoreRefStatusArray& aRefStatusArray)
       
  1316 	{
       
  1317 	LOGSMSPROT1("CSmsSegmentationStore::PopulateEntry");
       
  1318 	TBool statusreportrequest=EFalse;
       
  1319 	if (aSmsMessage.Type()==CSmsPDU::ESmsSubmit)
       
  1320 		{
       
  1321 		aEntry.SetReference(0);
       
  1322 		aEntry.SetTotal(1);
       
  1323 		CSmsSubmit& submit=(CSmsSubmit&) aSmsMessage.SmsPDU();
       
  1324 		aEntry.SetValidityPeriod(submit.ValidityPeriod().Int()); // TODO use val per type
       
  1325 		
       
  1326 		if (aSmsMessage.Scheme() == EDefaultScheme)
       
  1327 		    {
       
  1328 	    	statusreportrequest=((CSmsSubmit&) aSmsMessage.SmsPDU()).StatusReportRequest();		    
       
  1329 		    }
       
  1330 		else
       
  1331 		    {
       
  1332 		    statusreportrequest = ETrue;    
       
  1333 		    }
       
  1334 		}
       
  1335 	else
       
  1336 		{
       
  1337 		statusreportrequest=((CSmsCommand&) aSmsMessage.SmsPDU()).StatusReportRequest();
       
  1338 		}
       
  1339 
       
  1340 	if (aSmsMessage.TextPresent())
       
  1341 		{
       
  1342 		if (aSmsMessage.SmsPDU().TextConcatenated())
       
  1343 			{
       
  1344 			aEntry.SetReference(aSmsMessage.SmsPDU().ConcatenatedMessageReference());
       
  1345 
       
  1346 			//
       
  1347 			// aSmsMessage.EncodeMessagePdusL() must have been called before this point,
       
  1348 			// otherwise aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs() will return 1.
       
  1349 			//
       
  1350 			aEntry.SetTotal(aSmsMessage.SmsPDU().NumConcatenatedMessagePDUs());
       
  1351 			}
       
  1352 		}
       
  1353 
       
  1354 	aEntry.SetLogServerId(aSmsMessage.LogServerId());
       
  1355 	//  Strip out spaces etc from address
       
  1356 	TGsmSmsTelNumber parsedaddress;
       
  1357 	aSmsMessage.ParsedToFromAddress(parsedaddress);
       
  1358 	aEntry.SetDescription2(parsedaddress.iTelNumber);
       
  1359 	aEntry.SetTime(aSmsMessage.Time());
       
  1360 
       
  1361 	const TInt count= aRefStatusArray.Count();
       
  1362 	__ASSERT_DEBUG((count>=0) && (count<=aEntry.Total()),SmspPanic(KSmspPanicBadReferenceArray));
       
  1363 	aEntry.SetCount(count);
       
  1364 	TInt reference1=0xFF;
       
  1365 	TInt reference2=0x00;
       
  1366 	TInt startref=reference1;
       
  1367 	TInt stopref=reference2;
       
  1368 
       
  1369 	if(count>0 && statusreportrequest)
       
  1370 	{
       
  1371 		startref=aRefStatusArray[0].Reference();
       
  1372 		stopref=aRefStatusArray[count-1].Reference();
       
  1373 	}
       
  1374 
       
  1375 	TInt delivered=0;
       
  1376 	TInt failed=0;
       
  1377 	for (TInt i=0; i<count; i++)
       
  1378 		{
       
  1379 		const TSmsSegmentationStoreRefStatus& refStatus = aRefStatusArray[i];
       
  1380 
       
  1381 		if (refStatus.Status() == TSmsStatus::ESmsShortMessageReceivedBySME)
       
  1382 			delivered++;
       
  1383 		else if (IsPermanentStatus(refStatus.Status()))
       
  1384 			failed++;
       
  1385 		}
       
  1386 
       
  1387 	//
       
  1388 	// AEH: Defect fix for EDNPAHN-4WADW3 'Unreliable logging'
       
  1389 	//
       
  1390 	//      a little hack here to store information about whether
       
  1391 	//      we need Status Report or not, in the TSAREntry. This
       
  1392 	//      is because we want to retrieve it later in PurgeL.
       
  1393 	//      An extra bit is added iData4, LSB of byte 3. See gsmustor.h
       
  1394 	//      for more documentation.
       
  1395 	//
       
  1396 	aEntry.SetDeliveredAndFailed(delivered, failed);	
       
  1397 	TBool have_sr = EFalse;
       
  1398 
       
  1399 	if (aSmsMessage.Scheme() == EDefaultScheme)
       
  1400 		    {
       
  1401 	    	have_sr=((CSmsSubmit&) aSmsMessage.SmsPDU()).StatusReportRequest();		    
       
  1402 		    }
       
  1403 	else
       
  1404 		    {
       
  1405 		    have_sr = ETrue;    
       
  1406 		    }
       
  1407 
       
  1408 	aEntry.SetPduTypeAndRefs(have_sr, aSmsMessage.Type(), startref, stopref);
       
  1409 	} // CSmsSegmentationStore::PopulateEntry
       
  1410 
       
  1411 
       
  1412 /**
       
  1413  *  Returns ETrue if the status array is complete
       
  1414  *  
       
  1415  *  @param aStatusArray    Array containing status
       
  1416  *  @param aEntry          SAR Entry
       
  1417  */
       
  1418 TBool CSmsSegmentationStore::StatusArrayComplete(const RSmsSegmentationStoreRefStatusArray& aRefStatusArray, TSAREntry& aEntry)
       
  1419 	{
       
  1420 	TInt permanent=0;
       
  1421 	const TInt count= aRefStatusArray.Count();
       
  1422 	for (TInt i=0; i<count; i++)
       
  1423 		{
       
  1424 		const TBool ret = IsPermanentStatus(aRefStatusArray[i].Status());
       
  1425 		LOGSMSPROT4("CSmsSegmentationStore::IsPermanentStatus [Status: %d, RetVal: %d, count=%d]", aRefStatusArray[i].Status(), ret, count);
       
  1426 		if (ret)
       
  1427 			permanent++;
       
  1428 		}
       
  1429 	/*
       
  1430 	 *  
       
  1431 	 *  TODO ahe - for release
       
  1432 	 *  tested hack: the messagereceived function will be called right
       
  1433 	 *  I did a lot of testing with multipart messages, the sms are
       
  1434 	 *  almost always received and sent now, there might be only problems
       
  1435 	 *  with the SR now - to wait for more logs to see what happens in this
       
  1436 	 *  special cases - and the device crashes and is too slow of course
       
  1437 	 *  
       
  1438 	 */
       
  1439 	return (permanent==count) && (permanent==aEntry.Total() );
       
  1440 	} // CSmsSegmentationStore::StatusArrayComplete
       
  1441 
       
  1442 
       
  1443   /**
       
  1444    *  C'tor
       
  1445    */
       
  1446 CSmsSegmentationStore::CSmsSegmentationStore(RFs& aFs)
       
  1447     :CSARStore(aFs)
       
  1448     {
       
  1449     LOGSMSPROT1("CSmsSegmentationStore::CSmsSegmentationStore()");
       
  1450 
       
  1451     } // CSmsSegmentationStore::CSmsSegmentationStore
       
  1452 
       
  1453 
       
  1454 TInt CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare(const TSmsSegmentationStoreRefStatus& aLeft, const TSmsSegmentationStoreRefStatus& aRight)
       
  1455 	{
       
  1456 	LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare()");
       
  1457 
       
  1458 	return aLeft.iReference - aRight.iReference;
       
  1459 	} // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::Compare
       
  1460 
       
  1461 
       
  1462 void CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL(RReadStream& aStream)
       
  1463 	{
       
  1464 	LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL()");
       
  1465 
       
  1466 	iReference = aStream.ReadInt32L();
       
  1467 	iStatus = aStream.ReadInt32L();
       
  1468 	} // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::InternalizeL
       
  1469 
       
  1470 
       
  1471 void CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL(RWriteStream& aStream) const
       
  1472 	{
       
  1473 	LOGSMSPROT1("CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL()");
       
  1474 
       
  1475 	aStream.WriteInt32L(iReference);
       
  1476 	aStream.WriteInt32L(iStatus);
       
  1477 	} // CSmsSegmentationStore::TSmsSegmentationStoreRefStatus::ExternalizeL
       
  1478 
       
  1479 
       
  1480 void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL(const TSmsSegmentationStoreRefStatus& aRefStatus)
       
  1481 	{
       
  1482 	LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL()");
       
  1483 
       
  1484 	TLinearOrder<TSmsSegmentationStoreRefStatus> order(TSmsSegmentationStoreRefStatus::Compare);
       
  1485 	User::LeaveIfError(InsertInOrderAllowRepeats(aRefStatus, order));
       
  1486 	} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InsertL
       
  1487 
       
  1488 
       
  1489 TInt CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find(const TSmsSegmentationStoreRefStatus& aRefStatus) const
       
  1490 	{
       
  1491 	LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find()");
       
  1492 
       
  1493 	TLinearOrder<TSmsSegmentationStoreRefStatus> order(TSmsSegmentationStoreRefStatus::Compare);
       
  1494 	TInt index = FindInOrder(aRefStatus, order);
       
  1495 	if (index != KErrNotFound)
       
  1496 		{
       
  1497         //The  function is to return  the first occurence.  However FindInOrder()
       
  1498         //uses a binary search algorithm and does not guarantee to return the 1st item if there are duplicate items.
       
  1499         //Therefore we manually check for duplicates to the left of the found item.
       
  1500         while (index > 0 && (operator[](index-1).Reference() == aRefStatus.Reference()))
       
  1501 			{
       
  1502 			--index;
       
  1503 			}
       
  1504 		}
       
  1505 	return index;
       
  1506 	} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::Find
       
  1507 
       
  1508 
       
  1509 void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL(const RSmsSegmentationStoreRefStatusArray& aOther)
       
  1510 	{
       
  1511 	LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL()");
       
  1512 
       
  1513 	Reset();
       
  1514 
       
  1515 	TInt count = aOther.Count();
       
  1516 	while (count--)
       
  1517 		{
       
  1518 		InsertL(aOther[count]);
       
  1519 		}
       
  1520 	} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::CopyL
       
  1521 
       
  1522 
       
  1523 void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus(TInt aStatus)
       
  1524 	{
       
  1525 	LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus()");
       
  1526 
       
  1527 	TInt count = Count();
       
  1528 	while (count--)
       
  1529 		{
       
  1530 		(*this)[count].SetStatus(aStatus);
       
  1531 		}
       
  1532 	} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ResetAllStatus
       
  1533 
       
  1534 
       
  1535 void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL(RReadStream& aStream)
       
  1536 	{
       
  1537 	LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL()");
       
  1538 
       
  1539 	TInt count = aStream.ReadInt32L();
       
  1540 	while (count--)
       
  1541 		{
       
  1542 		TSmsSegmentationStoreRefStatus refStatus;
       
  1543 		aStream >> refStatus;
       
  1544 		InsertL(refStatus); //maintain order
       
  1545 		}
       
  1546 	} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::InternalizeL
       
  1547 
       
  1548 
       
  1549 void CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL(RWriteStream& aStream) const
       
  1550 	{
       
  1551 	LOGSMSPROT1("CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL()");
       
  1552 
       
  1553 	const TInt count = Count();
       
  1554 	aStream.WriteInt32L(count);
       
  1555 
       
  1556 	for (TInt i = 0; i < count; i++)
       
  1557 		{
       
  1558 		aStream << (*this)[i];
       
  1559 		}
       
  1560 	} // CSmsSegmentationStore::RSmsSegmentationStoreRefStatusArray::ExternalizeL
       
  1561 
       
  1562 
       
  1563 TBool CSmsSegmentationStore::HasEntryWithLogIdL(TLogId aLogID,TInt& aRefNo,TInt& aSent)
       
  1564 	{
       
  1565 	LOGSMSPROT1("CSmsSegmentationStore::HasEntryWithLogIdL()");
       
  1566 
       
  1567 	TInt count=Entries().Count();
       
  1568 	TBool found=EFalse;
       
  1569 	if(aLogID != KLogNullId)
       
  1570 		{
       
  1571 		TInt total;
       
  1572 		TInt sent;
       
  1573 		BeginTransactionLC();
       
  1574 		for (TInt i=count-1; i>=0; --i)
       
  1575 			{
       
  1576 			if (aLogID==Entries()[i].LogServerId())
       
  1577 				{
       
  1578 				const TSAREntry& entry=Entries()[i];
       
  1579 				total=entry.Total();
       
  1580 				sent=entry.Count();
       
  1581 				if( sent < total)
       
  1582 					{
       
  1583 					aSent=sent;
       
  1584 					aRefNo=entry.Reference();
       
  1585 					found=ETrue;
       
  1586 					}
       
  1587 				else
       
  1588 					{
       
  1589 					DeleteEntryL(i);
       
  1590 					LOGSMSPROT3("CSmsSegmentationStore::HasEntryWithLogIdL [Entry: %d LogId %d - deleted]", i, aLogID );
       
  1591 					}
       
  1592 				break;
       
  1593 				}
       
  1594 			}
       
  1595 		CommitTransactionL();
       
  1596 		}
       
  1597 	return found;
       
  1598 } // CSmsSegmentationStore::HasEntryWithLogIdL
       
  1599 
       
  1600 
       
  1601 /**
       
  1602  *  Open the sms segmentation store.
       
  1603  */
       
  1604 void CSmsSegmentationStore::OpenStoreL()
       
  1605 	{
       
  1606 	LOGSMSPROT1("CSmsSegmentationStore::OpenStoreL()");
       
  1607 
       
  1608 	this->OpenL(iFullPathBuf,KSegmentationStoreUid);
       
  1609 	} // CSmsSegmentationStore::OpenStoreL