smsprotocols/smsstack/smsprot/Src/smspclass0stor.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 2007-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 CPreallocatedFile.
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 #include "smspclass0stor.h"
       
    22 #include "gsmubuf.h"
       
    23 #include "gsmunonieoperations.h"
       
    24 
       
    25 const TInt KSizeOfPreallocatedFileVersion = sizeof(CPreallocatedFile::TPreAllocatedFileVersion);
       
    26 const TInt KSizeOfNumberOfEntrySection = sizeof(TInt);
       
    27 //size of 32-bit checksum
       
    28 const TInt KSizeOfChecksum = sizeof(TUint32);
       
    29 const TInt KSizeOfPreAllocatedStoreEntry = sizeof(TSmsPreAllocatedFileStoreReassemblyEntry);
       
    30 const TInt KSizeOfGsmSmsSlotEntry = sizeof(TGsmSmsSlotEntry);
       
    31 const TInt KSizeOfIndexEntry = sizeof(TInt);
       
    32 const TInt KSizeOfSmsGsmPDU = sizeof(RMobileSmsMessaging::TMobileSmsGsmTpdu);
       
    33 const TInt KSizeOfAContainer = KSizeOfGsmSmsSlotEntry + KSizeOfIndexEntry + KSizeOfSmsGsmPDU;
       
    34 const TInt KBeginOfMasterHeaderSection = KSizeOfPreallocatedFileVersion;
       
    35 
       
    36 /**
       
    37 Static factory constructor. Uses two phase 
       
    38 construction and leaves nothing on the CleanupStack.
       
    39 
       
    40 @param aFs  File Server handle.
       
    41 @param aFileName  Permanent file store name.
       
    42 @param aThirdUid  Uid of file.
       
    43 @leave KErrNoMemory
       
    44 
       
    45 @return A pointer to the newly created CSmsPermanentFileStore object.
       
    46 
       
    47 @pre A connected file server session must be passed as parameter.
       
    48 @post CSmsPermanentFileStore object is now fully initialised
       
    49 
       
    50 @internalComponent
       
    51 */
       
    52 CSmsPermanentFileStore* CSmsPermanentFileStore::NewL(RFs& aFs, const TDesC& aFileName, const TUid& aThirdUid)
       
    53 	{
       
    54 	LOGSMSPROT1("CSmsPermanentFileStore::NewL()");
       
    55 	CSmsPermanentFileStore*  self = new (ELeave) CSmsPermanentFileStore(aFs, aThirdUid);
       
    56 	CleanupStack::PushL(self);
       
    57 	self->ConstructL(aFileName);
       
    58 	CleanupStack::Pop(self);
       
    59 
       
    60 	return self;
       
    61 	}
       
    62 
       
    63 void CSmsPermanentFileStore::ConstructL(const TDesC& aFileName)
       
    64 	{
       
    65 	LOGSMSPROT1("CSmsPermanentFileStore::ConstructL()");
       
    66 	iFileName = aFileName.AllocL();
       
    67 	}
       
    68 
       
    69 /**
       
    70  *  Constructor.
       
    71 */
       
    72 CSmsPermanentFileStore::CSmsPermanentFileStore(RFs& aFs, const TUid& aThirdUid)
       
    73 							: iFs(aFs), iFileName(NULL), iThirdUid(aThirdUid), iFileStore(NULL), iEntryArray(KFlatArrayGranularity)
       
    74 	{
       
    75 	}
       
    76 
       
    77 /**
       
    78  *  Destructor. It destroys all the member variables.
       
    79 */
       
    80 CSmsPermanentFileStore::~CSmsPermanentFileStore()
       
    81 	{
       
    82 	delete iFileName;
       
    83 	}
       
    84 
       
    85 /**
       
    86 It checks & returns whether the file exist or not. If file is there whether
       
    87 it is corrupted or not.
       
    88 
       
    89 @internalComponent
       
    90 */
       
    91 TBool CSmsPermanentFileStore::IsFileOK()
       
    92 	{
       
    93 	TBool retBool(EFalse);
       
    94 	TUidType uidtype(KPermanentFileStoreLayoutUid,KSARStoreUid,iThirdUid);
       
    95 	TEntry entry;
       
    96 	TInt ret=iFs.Entry(iFileName->Des(), entry);
       
    97 	//  Check file existence & corruption
       
    98 	if ((ret == KErrNone) && (entry.iType == uidtype))
       
    99 		{
       
   100 		retBool = ETrue;
       
   101 		}
       
   102 	return retBool;
       
   103 	}
       
   104 
       
   105 /**
       
   106 It creates a permanent store file.
       
   107 
       
   108 @internalComponent
       
   109 */
       
   110 void CSmsPermanentFileStore::CreateL()
       
   111 	{
       
   112 	LOGSMSPROT1("CSmsPermanentFileStore::CreateL()");
       
   113 	TUidType uidtype(KPermanentFileStoreLayoutUid,KSARStoreUid,iThirdUid);
       
   114 	iFileStore=CPermanentFileStore::ReplaceL(iFs, iFileName->Des(), EFileShareExclusive|EFileStream|EFileRead|EFileWrite);
       
   115 	iFileStore->SetTypeL(uidtype);
       
   116 	iEntryArray.Reset();
       
   117 	ExternalizeEntryArrayL();
       
   118 	iFileStore->CommitL();
       
   119 	// Close it to make sure that file is created correctly (defensive approach).
       
   120 	Close();
       
   121 	//Again Open the file
       
   122 	OpenL();
       
   123 	}
       
   124 
       
   125 /**
       
   126 It opens the permanent store file and internalizes the entries.
       
   127 
       
   128 @internalComponent
       
   129 */
       
   130 void CSmsPermanentFileStore::OpenL()
       
   131 	{
       
   132 	LOGSMSPROT1("CSmsPermanentFileStore::OpenL()");
       
   133 	iFileStore=CPermanentFileStore::OpenL(iFs,iFileName->Des(),EFileShareExclusive|EFileStream|EFileRead|EFileWrite);
       
   134 	InternalizeEntryArrayL();
       
   135 	}
       
   136 
       
   137 /**
       
   138 It closes the permanent store file.
       
   139 
       
   140 @internalComponent
       
   141 */
       
   142 void CSmsPermanentFileStore::Close()
       
   143 	{
       
   144 	LOGSMSPROT1("CSmsPermanentFileStore::Close()");
       
   145 	delete iFileStore;
       
   146 	iFileStore = NULL;
       
   147 	iEntryArray.Reset();
       
   148 	}
       
   149 
       
   150 /*
       
   151 This function cleans its entries against the passed entries.
       
   152 This is needed because there might be a scenario where user has deleted a message
       
   153 but the corresponding message is not deleted from permanent store file
       
   154 due to out-of-disk condition. But the entry is invalid because
       
   155 it is no more in the pre-allocated file which contains master header info.
       
   156 And also at the time of forwarding an incomplete message a forwarded 
       
   157 message has not been deleted due to above reason.
       
   158 This function also compacts the store after deletion.
       
   159 
       
   160 @param aEntryArray entray array against whose clean up is carried out.
       
   161 
       
   162 @internalComponent
       
   163 */
       
   164 void CSmsPermanentFileStore::CleanupEntriesWithCompactL(const CArrayFix<TSmsPreAllocatedFileStoreReassemblyEntry>& aEntryArray)
       
   165 	{
       
   166     // Ignore in code coverage - a previous CleanupEntries would need to have failed with KErrDiskFull
       
   167 	BULLSEYE_OFF
       
   168 	LOGSMSPROT1("CSmsPermanentFileStore::CleanupEntriesWithCompactL()");
       
   169 
       
   170 	iCompact = ETrue;
       
   171 	CleanupEntriesL(aEntryArray);
       
   172 	BULLSEYE_RESTORE	
       
   173 	}
       
   174 
       
   175 /*
       
   176 This function cleans its entries against the passed entries.
       
   177 This is needed because there migth be a scenario where user has deleted a message
       
   178 but the corresponding message is not deleted from permanent store file
       
   179 due to out-of-disk condition. But the entry is invalid because
       
   180 it is no more in the pre-allocated file which contains master header info.
       
   181 And also at the time of forwarding an incomplete message a forwarded 
       
   182 message has not been deleted due to above reason.
       
   183 
       
   184 @param aEntryArray entray array against whose clean up is carried out.
       
   185 
       
   186 @internalComponent
       
   187 */
       
   188 void CSmsPermanentFileStore::CleanupEntriesL(const CArrayFix<TSmsPreAllocatedFileStoreReassemblyEntry>& aEntryArray)
       
   189 	{
       
   190 	LOGSMSPROT1("CSmsPermanentFileStore::CleanupEntriesL()");
       
   191 
       
   192 	TInt reassemblyCount = iEntryArray.Count();
       
   193 	TInt index, index2;
       
   194 
       
   195 	for (index = 0;  index < reassemblyCount;  index++)
       
   196 		{
       
   197 		for (index2 = 0;  index2 < aEntryArray.Count();  index2++)
       
   198 			{
       
   199 			if (iEntryArray[index].Reference() == aEntryArray[index2].Reference()  &&
       
   200 			    iEntryArray[index].Total() == aEntryArray[index2].Total()  &&
       
   201 			    iEntryArray[index].PduType() == aEntryArray[index2].PduType()  &&
       
   202 				iEntryArray[index].Storage() == aEntryArray[index2].Storage()  &&
       
   203 				iEntryArray[index].Description2() == aEntryArray[index2].Description2())
       
   204 				{
       
   205 				if (aEntryArray[index2].NumberOfPDUsForwardToClient() > 0)
       
   206 					{
       
   207 					//Internalize the entries.
       
   208 					CSmsBuffer*  buffer = CSmsBuffer::NewL();
       
   209 					CSmsMessage*  smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
       
   210 					CleanupStack::PushL(smsMessage);
       
   211 
       
   212 					CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
   213 					CleanupStack::PushL(indexArray);
       
   214 					CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
   215 					CleanupStack::PushL(smsArray);
       
   216 
       
   217 					InternalizeEntryL(index, *smsMessage, *indexArray, *smsArray);
       
   218 					TInt noOfForwardedEntries = 0;
       
   219 					for (TInt j=indexArray->Count(); j>0 ;j--)
       
   220 						{
       
   221 						TUint8 bitMapIndex = (indexArray->At(j-1)-1)/8;
       
   222 						TUint8 bitPos = (indexArray->At(j-1)-1)%8;
       
   223 						TUint8 bitMap;
       
   224 						TSmsPreAllocatedFileStoreReassemblyEntry entry;
       
   225 						entry = aEntryArray[index2];
       
   226 						entry.GetBitMap(bitMapIndex, bitMap);
       
   227 						TUint8 tmpBitMap = 1;
       
   228 						tmpBitMap <<= bitPos;
       
   229 						if (tmpBitMap == (bitMap & tmpBitMap))
       
   230 							{
       
   231 							noOfForwardedEntries++;
       
   232 							indexArray->Delete(j-1);
       
   233 							smsArray->Delete(j-1);
       
   234 							}
       
   235 						}
       
   236 					if (noOfForwardedEntries > 0)
       
   237 						{
       
   238 						TStreamId streamId = iEntryArray[index].DataStreamId();
       
   239 						ExternalizeEntryL(streamId, *smsMessage, *indexArray, *smsArray);
       
   240 						}
       
   241 					CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray
       
   242 					}
       
   243 				break;
       
   244 				}
       
   245 			}
       
   246 		if (index2 == aEntryArray.Count())
       
   247 			{
       
   248 			DeleteEntryL(index);
       
   249 			}
       
   250 		}
       
   251 	}
       
   252 
       
   253 /**
       
   254 It internalizes its entry array.
       
   255 
       
   256 @internalComponent
       
   257 */
       
   258 void CSmsPermanentFileStore::InternalizeEntryArrayL()
       
   259 	{
       
   260 	LOGSMSPROT1("CSmsPermanentFileStore::InternalizeEntryArrayL()");
       
   261 
       
   262 	iEntryArray.Reset();
       
   263 	TStreamId headerid=iFileStore->Root();
       
   264 	RStoreReadStream stream;
       
   265 	stream.OpenLC(*iFileStore,headerid);
       
   266 	TInt count=stream.ReadInt32L();
       
   267 	for (TInt i=0; i<count; i++)
       
   268 		{
       
   269 		TSmsReassemblyEntry sarentry;
       
   270 		stream >> sarentry;
       
   271 		iEntryArray.AppendL(sarentry);
       
   272 		}
       
   273 	CleanupStack::PopAndDestroy();  //  stream
       
   274 	}
       
   275 
       
   276 /**
       
   277 It externalizes its entry array.
       
   278 
       
   279 @internalComponent
       
   280 */
       
   281 void CSmsPermanentFileStore::ExternalizeEntryArrayL()
       
   282 	{
       
   283 	LOGSMSPROT4("CSmsPermanentFileStore::ExternalizeEntryArrayL(): this=0x%08X count=%d headerid=%d]",
       
   284 			 this, iEntryArray.Count(), iFileStore->Root().Value());
       
   285 
       
   286 	TStreamId headerid=iFileStore->Root();
       
   287 	RStoreWriteStream stream;
       
   288 	if (headerid==KNullStreamId)
       
   289 		{
       
   290 		headerid=stream.CreateLC(*iFileStore);
       
   291 		iFileStore->SetRootL(headerid);
       
   292 		}
       
   293 	else
       
   294 		{
       
   295 		stream.ReplaceLC(*iFileStore,headerid);
       
   296 		}
       
   297 
       
   298 	TInt count1=iEntryArray.Count();
       
   299 	TInt count2=0;
       
   300 	TInt i=0;
       
   301 
       
   302 	for (; i<count1; i++)
       
   303 		{
       
   304 		if (!iEntryArray[i].IsDeleted())
       
   305 			{
       
   306 			count2++;
       
   307 			}
       
   308 		}
       
   309 	stream.WriteInt32L(count2);
       
   310 	for (i=0; i<count1; i++)
       
   311 		{
       
   312 		if (!iEntryArray[i].IsDeleted())
       
   313 			{
       
   314 			stream << iEntryArray[i];
       
   315 			}
       
   316 		}
       
   317 
       
   318 	stream.CommitL();
       
   319 	CleanupStack::PopAndDestroy(&stream);
       
   320 	}
       
   321 
       
   322 /*
       
   323 It adds the new message in permanent store file.
       
   324 
       
   325 @param aIndex (output) index number on which message is added.
       
   326 @param aSmsMessage reference to sms message to be added.
       
   327 @param aGsmSms reference to GsmSms object to be added.
       
   328 
       
   329 @internalComponent
       
   330 */
       
   331 void CSmsPermanentFileStore::AddNewMessageL(TInt& aIndex, CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
       
   332 	{
       
   333 	LOGSMSPROT1("CSmsPermanentFileStore::AddNewMessageL");
       
   334 
       
   335 	CArrayFix<TInt>* indexArray=new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
   336 	CleanupStack::PushL(indexArray);
       
   337 	CArrayFixFlat<TGsmSms>* smsArray=new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
   338 	CleanupStack::PushL(smsArray);
       
   339 	//Index must initialize to 0.
       
   340 	TInt index = 0;
       
   341 	if (!aSmsMessage.IsDecoded())
       
   342 		{
       
   343 		index = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
       
   344 		}
       
   345 	indexArray->AppendL(index);
       
   346 	smsArray->AppendL(aGsmSms);
       
   347 
       
   348 	TStreamId streamid = KNullStreamId;
       
   349 	ExternalizeEntryL(streamid, aSmsMessage, *indexArray, *smsArray);
       
   350 
       
   351 	TSmsReassemblyEntry tmpEntry;
       
   352 	//Fill-up entry information...
       
   353 	CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1);
       
   354 	// Update Data stream id.
       
   355 	tmpEntry.SetDataStreamId(streamid);
       
   356 
       
   357 	aIndex = iEntryArray.Count();
       
   358 	AddEntryL(tmpEntry);
       
   359 	CleanupStack::PopAndDestroy(2);	//indexArray, smsArray
       
   360 	}
       
   361 
       
   362 /*
       
   363 It updates the existing message in permanent store file.
       
   364 
       
   365 @param aIndex index number on which message is to be updated.
       
   366 @param aSmsMessage reference to sms message to be updated.
       
   367 @param aIndexArray array of index of all the PDUs.
       
   368 @param aSmsArray array of sms of all the PDUs.
       
   369 
       
   370 @internalComponent
       
   371 */
       
   372 void CSmsPermanentFileStore::UpdateExistingMessageL(TInt aIndex, const CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
       
   373 	{
       
   374 	LOGSMSPROT1("CSmsPermanentFileStore::UpdateExistingMessageL()");
       
   375 	TStreamId  streamid = iEntryArray[aIndex].DataStreamId();
       
   376 	ExternalizeEntryL(streamid, aSmsMessage, aIndexArray, aSmsArray);
       
   377 	TSmsReassemblyEntry entry;
       
   378 	CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, aSmsArray.Count());
       
   379 	entry.SetDataStreamId(streamid);
       
   380 	ChangeEntryL(aIndex, entry);
       
   381 	}
       
   382 
       
   383 /*
       
   384 It matches the entry with entry in permanent store file & returns
       
   385 the index. If not found it returns KErrNotFound.
       
   386 
       
   387 @param aEntry reference to entry information.
       
   388 @param aIndex (output) returns the index number.
       
   389 
       
   390 @internalComponent
       
   391 */
       
   392 void CSmsPermanentFileStore::MatchEntryToExistingMessage(const TReassemblyEntry& aEntry,
       
   393 													TInt& aIndex)
       
   394 	{
       
   395 	LOGSMSPROT1("CSmsPermanentFileStore::MatchEntryToExistingMessage()");
       
   396 
       
   397 	aIndex = KErrNotFound;
       
   398 
       
   399 	//
       
   400 	// Search the reassembly store for a matching entry...
       
   401 	//
       
   402 	TInt reassemblyCount = iEntryArray.Count();
       
   403 	for (TInt  index = 0;  index < reassemblyCount;  index++)
       
   404 		{
       
   405 		TSmsReassemblyEntry&  entry = iEntryArray[index];
       
   406 
       
   407 		if (entry.Reference() == aEntry.Reference()  &&
       
   408 			entry.Total() == aEntry.Total()  &&
       
   409 			entry.PduType() == aEntry.PduType()  &&
       
   410 			entry.Storage() == aEntry.Storage()  &&
       
   411 			entry.Description2() == aEntry.Description2())
       
   412 			{
       
   413 			//
       
   414 			// Found it!
       
   415 			//
       
   416 			aIndex = index;
       
   417 			break;
       
   418 			}
       
   419 		}
       
   420 
       
   421 	LOGSMSPROT2("CSmsPermanentFileStore::MatchEntryToExistingMessage(): aIndex=%d", aIndex);
       
   422 	}
       
   423 
       
   424 /*
       
   425 It updates the log server id of the message.
       
   426 
       
   427 @param aIndex index number of the message to be updated.
       
   428 @param aLogServerId log server id.
       
   429 
       
   430 @internalComponent
       
   431 */
       
   432 void CSmsPermanentFileStore::UpdateLogServerIdL(TInt& aIndex, TLogId aLogServerId)
       
   433 	{
       
   434 	LOGSMSPROT1("CSmsPermanentFileStore::UpdateLogServerIdL");
       
   435 
       
   436 	TSmsReassemblyEntry entry;
       
   437 	entry = iEntryArray[aIndex];
       
   438 
       
   439 	if (entry.LogServerId() != aLogServerId)
       
   440 		{
       
   441 		entry.SetLogServerId(aLogServerId);
       
   442 		ChangeEntryL(aIndex, entry);
       
   443 		}
       
   444 	}
       
   445 
       
   446 /*
       
   447 It sets the message passed to client or not.
       
   448 
       
   449 @param aIndex index number of the message to be updated.
       
   450 @param aBool boolean value indicating whether message is passes or not.
       
   451 
       
   452 @internalComponent
       
   453 */
       
   454 void CSmsPermanentFileStore::SetPassedToClientL(TInt aIndex, TBool aBool)
       
   455 	{
       
   456 	LOGSMSPROT2("CSmsPermanentFileStore::SetPassedToClientL(): aIndex=%d", aIndex);
       
   457 
       
   458 	TSmsReassemblyEntry entry;
       
   459 	entry = iEntryArray[aIndex];
       
   460 
       
   461 	if (entry.PassedToClient() != aBool)
       
   462 		{
       
   463 		entry.SetPassedToClient(aBool);
       
   464 		ChangeEntryL(aIndex, entry);
       
   465 		}
       
   466 	}
       
   467 
       
   468 /*
       
   469 It adds the new entry in the existing entry array.
       
   470 
       
   471 @param aEntry entry to be added.
       
   472 
       
   473 @internalComponent
       
   474 */
       
   475 void CSmsPermanentFileStore::AddEntryL(TSmsReassemblyEntry& aEntry)
       
   476 	{
       
   477 	iEntryArray.AppendL(aEntry);
       
   478 	iEntryArray[iEntryArray.Count()-1].SetIsAdded(ETrue);
       
   479 	}
       
   480 
       
   481 /*
       
   482 It changes the existing entry with new entry.
       
   483 
       
   484 @param aIndex index number of the entry which will be changed.
       
   485 @param aNewEntry entry to be updated.
       
   486 
       
   487 @internalComponent
       
   488 */
       
   489 void CSmsPermanentFileStore::ChangeEntryL(TInt aIndex,const TSmsReassemblyEntry& aNewEntry)
       
   490 	{
       
   491 	LOGSMSPROT2("CSmsPermanentFileStore::ChangeEntryL(): aIndex=%d", aIndex);
       
   492 
       
   493 	iEntryArray[aIndex].SetIsDeleted(ETrue);
       
   494 	iEntryArray.InsertL(aIndex,aNewEntry);
       
   495 	iEntryArray[aIndex].SetIsAdded(ETrue);
       
   496 	}
       
   497 
       
   498 /*
       
   499 It deletes the entry.
       
   500 
       
   501 @param aIndex index number of the entry which will be deleted.
       
   502 
       
   503 @internalComponent
       
   504 */
       
   505 void CSmsPermanentFileStore::DeleteEntryL(TInt aIndex)
       
   506 	{
       
   507 	iFileStore->DeleteL(iEntryArray[aIndex].DataStreamId());
       
   508 	iEntryArray[aIndex].SetIsDeleted(ETrue);
       
   509 	}
       
   510 
       
   511 /*
       
   512 It externalizes(writes) the entry in permanent store file.
       
   513 
       
   514 @param aStreamId stream id which needs to externalized.
       
   515 @param aSmsMessage reference to sms message which needs to be externalized.
       
   516 @param aIndexArray refence to array of index which needs to be externalized.
       
   517 @param aSmsArray refence to array of sms which needs to be externalized.
       
   518 
       
   519 @internalComponent
       
   520 */
       
   521 void CSmsPermanentFileStore::ExternalizeEntryL(TStreamId& aStreamId,const CSmsMessage& aSmsMessage,const CArrayFix<TInt>& aIndexArray,const CArrayFix<TGsmSms>& aSmsArray)
       
   522 	{
       
   523 	LOGSMSPROT2("CSmsPermanentFileStore::ExternalizeEntryL Start [sid=%d]", aStreamId.Value());
       
   524 
       
   525 	RStoreWriteStream writestream;
       
   526 	if (aStreamId==KNullStreamId)
       
   527 		aStreamId=writestream.CreateLC(*iFileStore);
       
   528 	else
       
   529 		writestream.ReplaceLC(*iFileStore,aStreamId);
       
   530 	writestream << aSmsMessage;
       
   531 	TInt count=aIndexArray.Count();
       
   532 	writestream.WriteInt32L(count);
       
   533 	TInt i=0;
       
   534 	for (; i<count; i++)
       
   535 		writestream.WriteInt32L(aIndexArray[i]);
       
   536 	count=aSmsArray.Count();
       
   537 	writestream.WriteInt32L(count);
       
   538 	for (i=0; i<count; i++)
       
   539 		{
       
   540 		RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
   541 		pdu=aSmsArray[i].Pdu();
       
   542 		writestream << pdu;
       
   543 		}
       
   544 	writestream.CommitL();
       
   545 	CleanupStack::PopAndDestroy();
       
   546 
       
   547 	LOGSMSPROT2("CClass0PermanentFileStore::ExternalizeEntryL End [count=%d]", count);
       
   548 	}
       
   549 
       
   550 /*
       
   551 It internalizes(reads) the entry from permanent store file.
       
   552 
       
   553 @param aIndex index number of the message to be internalized.
       
   554 @param aSmsMessage (output) reference to sms message.
       
   555 @param aIndexArray (output) refence to array of index.
       
   556 @param aSmsArray (output) refence to array of sms.
       
   557 
       
   558 @internalComponent
       
   559 */
       
   560 void CSmsPermanentFileStore::InternalizeEntryL(const TInt aIndex, CSmsMessage& aSmsMessage, CArrayFix<TInt>& aIndexArray, CArrayFix<TGsmSms>& aSmsArray)
       
   561 	{
       
   562 	TSmsReassemblyEntry&  entry = iEntryArray[aIndex];
       
   563 	LOGSMSPROT2("CSmsPermanentFileStore::InternalizeEntryL Start [sid=%d]", entry.DataStreamId().Value());
       
   564 	RStoreReadStream readstream;
       
   565 	readstream.OpenLC(*iFileStore, entry.DataStreamId());
       
   566 	readstream >> aSmsMessage;
       
   567 	TInt count=readstream.ReadInt32L();
       
   568 	TInt i;
       
   569 	for (i=0; i<count; i++)
       
   570 		{
       
   571 		TInt index=readstream.ReadInt32L();
       
   572 		aIndexArray.AppendL(index);
       
   573 		}
       
   574 	count=readstream.ReadInt32L();
       
   575 	if(count!=aIndexArray.Count())
       
   576 		{
       
   577 		User::Leave(KErrCorrupt);
       
   578 		}
       
   579 	for (i=0; i<count; i++)
       
   580 		{
       
   581 		RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
   582 		readstream >> pdu;
       
   583 		TGsmSms sms;
       
   584 		sms.SetPdu(pdu);
       
   585 		aSmsArray.AppendL(sms);
       
   586 		}
       
   587 	CleanupStack::PopAndDestroy();
       
   588 	//Set other properties of CSmsMessage
       
   589 	aSmsMessage.SetStorage(entry.Storage());
       
   590 	aSmsMessage.SetLogServerId(entry.LogServerId());
       
   591 	aSmsMessage.SetTime(entry.Time());
       
   592 	LOGSMSPROT2("CSmsPermanentFileStore::InternalizeEntryL End [count=%d]", count);
       
   593 	}
       
   594 
       
   595 /*
       
   596 It removes the PDUs from permanent store file.
       
   597 This function is needed because after forwarding the incomplete message
       
   598 to client, the corresponding PDUs needs to be be removed from permanent
       
   599 store file.
       
   600 This functionality is specific to class 0 re-assembly store.
       
   601 
       
   602 @param aIndex index number of the message to be removed.
       
   603 @param aStartPos starting pos of pdu to be removed.
       
   604 @param aEndPos end pos of pdu to be removed.
       
   605 
       
   606 @internalComponent
       
   607 */
       
   608 void CSmsPermanentFileStore::RemovePDUsL(TInt aIndex, TInt aStartPos, TInt aEndPos)
       
   609 	{
       
   610 	LOGSMSPROT1("CSmsPermanentFileStore::RemovePDUsL");
       
   611 
       
   612 	CSmsBuffer*  buffer = CSmsBuffer::NewL();
       
   613 	CSmsMessage*  smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
       
   614 	CleanupStack::PushL(smsMessage);
       
   615 
       
   616 	CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
   617 	CleanupStack::PushL(indexArray);
       
   618 	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
   619 	CleanupStack::PushL(smsArray);
       
   620 
       
   621 	InternalizeEntryL(aIndex, *smsMessage, *indexArray, *smsArray);
       
   622 
       
   623 	TInt count = indexArray->Count();
       
   624 	for (TInt i=count; i>0; i--)
       
   625 		{
       
   626 		if ((indexArray->At(i-1) >= aStartPos) && (indexArray->At(i-1) <= aEndPos))
       
   627 			{
       
   628 			indexArray->Delete(i-1);
       
   629 			smsArray->Delete(i-1);
       
   630 			}
       
   631 		}
       
   632 
       
   633 	/*
       
   634 	There are 3 scenarios in this case:
       
   635 	1. If all the entries are removed,
       
   636 	then there is no need to store the entry in this permanent file.
       
   637 	2. If few entries are removed,
       
   638 	then externalize the remaining entries. Update count field also.
       
   639 	3. If no entries are removed, then do nothing.
       
   640 	*/
       
   641 	if (indexArray->Count()==0)
       
   642 		{
       
   643 		DeleteEntryL(aIndex);
       
   644 		}
       
   645 	else if (count!=indexArray->Count())
       
   646 		{
       
   647 		TStreamId  streamid = iEntryArray[aIndex].DataStreamId();
       
   648 		ExternalizeEntryL(streamid, *smsMessage, *indexArray, *smsArray);
       
   649 
       
   650 		TSmsReassemblyEntry entry;
       
   651 		entry = iEntryArray[aIndex];
       
   652 		entry.SetCount(indexArray->Count());
       
   653 		ChangeEntryL(aIndex, entry);
       
   654 		}
       
   655 	CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray
       
   656 	}
       
   657 
       
   658 /**
       
   659  *  Sets the permanent store as in-transaction.
       
   660  *  
       
   661  *  The function checks the validity of the call and leaves KErrAccessDenied if
       
   662  *  invalid.
       
   663  *  @capability None
       
   664  */
       
   665 void CSmsPermanentFileStore::BeginTransactionL()
       
   666 	{
       
   667     LOGSMSPROT4("CSmsPermanentFileStore::BeginTransactionL [this=0x%08X iInTransaction=%d iFileStore=0x%08X]", this, iInTransaction, iFileStore);
       
   668 
       
   669 	if (iFileStore == NULL || iInTransaction)
       
   670 		{
       
   671 		LOGSMSPROT1("WARNING CSmsPermanentFileStore::BeginTransactionL leaving with KErrAccessDenied");
       
   672 		User::Leave(KErrAccessDenied);
       
   673 		}
       
   674 
       
   675 	iInTransaction = ETrue;
       
   676 	} // CSmsPermanentFileStore::BeginTransactionL
       
   677 
       
   678 /**
       
   679  *  It reverts the transaction.
       
   680  */
       
   681 void CSmsPermanentFileStore::Revert()
       
   682 	{
       
   683 	LOGSMSPROT3("CSmsPermanentFileStore::Revert(): this=0x%08X, iInTransaction=%d",
       
   684     		 this, iInTransaction);
       
   685 
       
   686 	iFileStore->Revert();
       
   687 	iInTransaction = EFalse;
       
   688 	ReinstateDeletedEntries();
       
   689 	} // CSmsPermanentFileStore::Revert
       
   690 
       
   691 /**
       
   692  *  It commits the transaction. Then it compact the permanent store file.
       
   693  */
       
   694 void CSmsPermanentFileStore::DoCommitAndCompactL()
       
   695 	{
       
   696 	LOGSMSPROT1("CSmsPermanentFileStore::DoCommitAndCompactL()");
       
   697 
       
   698 	LOGSMSPROTTIMESTAMP();
       
   699 	iFileStore->CommitL();
       
   700 	LOGSMSPROTTIMESTAMP();
       
   701 
       
   702 	iCommitCount--;
       
   703 	if ((iCommitCount < 0) || (iCompact))
       
   704 		{
       
   705 		iCommitCount = KNumStoreCommitsBeforeCompaction;
       
   706 		iFileStore->CompactL();
       
   707 		iFileStore->CommitL();
       
   708 		iCompact = EFalse;
       
   709 		}
       
   710 	} // CSmsPermanentFileStore::DoCommitAndCompactL
       
   711 
       
   712 /**
       
   713  *  It commits the transaction.
       
   714  */
       
   715 void CSmsPermanentFileStore::CommitTransactionL()
       
   716 	{
       
   717 	LOGSMSPROT4("CSmsPermanentFileStore::CommitTransactionL(): this=0x%08X iInTransaction=%d iFileStore=0x%08X",
       
   718     		 this, iInTransaction, iFileStore);
       
   719 
       
   720 	ExternalizeEntryArrayL();
       
   721 
       
   722 #ifdef _SMS_LOGGING_ENABLED
       
   723 	TRAPD(err, DoCommitAndCompactL());
       
   724 	if (err != KErrNone)
       
   725 		{
       
   726 		LOGGSMU2("WARNING! could not CommitL/CompactL due to %d", err);
       
   727 		User::Leave(err);
       
   728 		}
       
   729 #else
       
   730 	DoCommitAndCompactL();
       
   731 #endif
       
   732 
       
   733 	iInTransaction = EFalse;
       
   734 	RemoveDeletedEntries();
       
   735 	}
       
   736 
       
   737 /**
       
   738  *  It removes the deleted entries from entry arry.
       
   739  *	This function is called after commit.
       
   740  */
       
   741 void CSmsPermanentFileStore::RemoveDeletedEntries()
       
   742 	{
       
   743 	LOGSMSPROT1("CSmsPermanentFileStore::RemoveDeletedEntries()");
       
   744 
       
   745 	TInt count=iEntryArray.Count();
       
   746 	while (count--)
       
   747 		{
       
   748 		TSmsReassemblyEntry& entry = iEntryArray[count];
       
   749 
       
   750 		if (entry.IsDeleted())
       
   751 			{
       
   752 			iEntryArray.Delete(count);
       
   753 			}
       
   754 		else
       
   755 			{
       
   756 			entry.SetIsAdded(EFalse);
       
   757 			}
       
   758 		}
       
   759 	} // CSmsPermanentFileStore::RemoveDeletedEntries
       
   760 
       
   761 /**
       
   762  *  It reinstate the deleted/added entries from entry arry.
       
   763  *	This function is called after revert operation.
       
   764  */
       
   765 void CSmsPermanentFileStore::ReinstateDeletedEntries()
       
   766 	{
       
   767 	LOGSMSPROT1("CSmsPermanentFileStore::ReinstateDeletedEntries()");
       
   768 
       
   769 	TInt count=iEntryArray.Count();
       
   770 	while (count--)
       
   771 		{
       
   772 		TSmsReassemblyEntry& entry = iEntryArray[count];
       
   773 
       
   774 		if (entry.IsAdded())
       
   775 			{
       
   776 			iEntryArray.Delete(count);
       
   777 			}
       
   778 		else
       
   779 			{
       
   780 			entry.SetIsDeleted(EFalse);
       
   781 			}
       
   782 		}
       
   783 	} // CSmsPermanentFileStore::ReinstateDeletedEntries
       
   784 
       
   785 /**
       
   786  *  Constructor
       
   787  *  
       
   788  *  @capability None
       
   789  */
       
   790 TSmsPreAllocatedFileStoreReassemblyEntry::TSmsPreAllocatedFileStoreReassemblyEntry():
       
   791 	TSmsReassemblyEntry(),
       
   792 	iPreAllocatedStorageId(0),
       
   793 	iStatus(RMobileSmsStore::EStoredMessageUnknownStatus),
       
   794 	iTimeOffset(0),
       
   795 	iDecodedOnSim(EFalse),
       
   796 	iForwardToClient(EFalse),
       
   797 	iForwardedCount(0),
       
   798 	iBitMap(NULL)
       
   799 	{
       
   800 	//Have to externalize so initialize to 0.
       
   801 	for (TInt i=0; i<KBitMapLen; i++)
       
   802 		{
       
   803 		iBitMap.Append(0x00);
       
   804 		}
       
   805 	}
       
   806 
       
   807 /*
       
   808 It returns the reference of a particular bit-map index.
       
   809 
       
   810 @param aIndex index number of the bit-map.
       
   811 @param aBitMap bit-map value.
       
   812 
       
   813 @internalComponent
       
   814 */
       
   815 void TSmsPreAllocatedFileStoreReassemblyEntry::GetBitMap(TUint8 aIndex, TUint8& aBitMap)
       
   816 	{
       
   817 	aBitMap = iBitMap[aIndex];
       
   818 	}
       
   819 
       
   820 /*
       
   821 It sets the value of a bit-map.
       
   822 
       
   823 @param aIndex index number of the bit-map.
       
   824 @param aBitMap bit-map value
       
   825 
       
   826 @internalComponent
       
   827 */
       
   828 void TSmsPreAllocatedFileStoreReassemblyEntry::SetBitMap(TUint8 aIndex, TUint8 aBitMap)
       
   829 	{
       
   830 	iBitMap[aIndex] = aBitMap;
       
   831 	}
       
   832 
       
   833 /**
       
   834 Static factory constructor. Uses two phase 
       
   835 construction and leaves nothing on the CleanupStack.
       
   836 
       
   837 @param aFs  File Server handle.
       
   838 @param aFileName  Permanent file store name.
       
   839 @param aMaxClass0Msg max class 0 message that can be stored.
       
   840 @param aMaxPDUSeg max number of pdus that can be stored.
       
   841 @param aVersion version number of pre-allocated file.
       
   842 
       
   843 @return A pointer to the newly created CPreallocatedFile object.
       
   844 
       
   845 @pre A connected file server session must be passed as parameter.
       
   846 @post CPreallocatedFile object is now fully initialised
       
   847 
       
   848 @internalComponent
       
   849 */
       
   850 CPreallocatedFile* CPreallocatedFile::NewL(RFs& aFs, const TDesC& aFileName, TInt aMaxClass0Msg, TInt aMaxPDUSeg, TPreAllocatedFileVersion aVersion)
       
   851 	{
       
   852 	LOGSMSPROT1("CPreallocatedFile::NewL()");
       
   853 	CPreallocatedFile*  self = new (ELeave) CPreallocatedFile(aFs, aMaxClass0Msg, aMaxPDUSeg, aVersion);
       
   854 	CleanupStack::PushL(self);
       
   855 	self->ConstructL(aFileName);
       
   856 	CleanupStack::Pop(self);
       
   857 
       
   858 	return self;
       
   859 	}
       
   860 
       
   861 void CPreallocatedFile::ConstructL(const TDesC& aFileName)
       
   862 	{
       
   863 	LOGSMSPROT1("CPreallocatedFile::ConstructL()");
       
   864 	iFileName = aFileName.AllocL();
       
   865 	}
       
   866 
       
   867 /**
       
   868  *  Constructor.
       
   869 */
       
   870 CPreallocatedFile::CPreallocatedFile(RFs& aFs, TInt aMaxClass0Msg, TInt aMaxPDUSeg, TPreAllocatedFileVersion aVersion)
       
   871 	:iFs(aFs), iEntryArray(KFlatArrayGranularity), iReinstateEntryInfo(KFlatArrayGranularity), iMaxClass0Msg(aMaxClass0Msg), iMaxPDUSeg(aMaxPDUSeg), iVersion(aVersion)
       
   872 	{
       
   873 	/*
       
   874 	Format of File:
       
   875 	Version Number, Header Section & Data Section
       
   876 	Version Number - Interger Value.
       
   877 	Header Section: Number of entries, Array of Entries, Array of PDU identifier section, Checksum.
       
   878 	Data Section: Array of Container. Each container contains Sms slot informatiuon, index number & PDU.
       
   879 	*/
       
   880 
       
   881 	// Calculate the size of each section.
       
   882 
       
   883 	// Entry section will always contain one more entry than configured one by the user.
       
   884 	// Because it will provide one extra slot to store the new message for time being
       
   885 	// before forwarding the oldest message.
       
   886 	iSizeOfEntrySection = (KSizeOfPreAllocatedStoreEntry * (iMaxClass0Msg + 1));
       
   887 
       
   888 	iSizeOfStorageIdentifierSection = ((sizeof(TInt))*(iMaxPDUSeg+1));
       
   889 
       
   890 	TInt sizeOfHeaderSection = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + KSizeOfChecksum;
       
   891 
       
   892 	TInt sizeOfDataSection = KSizeOfAContainer  * (iMaxPDUSeg+1);
       
   893 
       
   894 	// Calculate the size of File.
       
   895 	iSizeOfFile = KSizeOfPreallocatedFileVersion + 2 * sizeOfHeaderSection + sizeOfDataSection;
       
   896 
       
   897 	iBeginOfDuplicateHeaderSection = KSizeOfPreallocatedFileVersion + sizeOfHeaderSection;
       
   898 	iBeginOfDataSection = KSizeOfPreallocatedFileVersion + 2 * sizeOfHeaderSection;
       
   899 	}
       
   900 
       
   901 /**
       
   902  *  Destructor. It destroys all the member variables.
       
   903 */
       
   904 CPreallocatedFile::~CPreallocatedFile()
       
   905 	{
       
   906 	delete iFileName;
       
   907 	}
       
   908 
       
   909 /**
       
   910 It checks & returns whether the file exist or not. If file is there whether
       
   911 it is corrupted or not.
       
   912 
       
   913 @internalComponent
       
   914 */
       
   915 TBool CPreallocatedFile::IsFileOK()
       
   916 	{
       
   917 	LOGSMSPROT1("CPreallocatedFile::IsFileOK()");
       
   918 
       
   919 	TEntry entry;
       
   920 	//  Check file exists
       
   921 	TInt ret=iFs.Entry(iFileName->Des(), entry);
       
   922 	// Check the size of file, if size does not match then assume that file
       
   923 	// is corrupted, then return KErrNotFound.
       
   924 	if ((ret == KErrNone) && (entry.iSize != iSizeOfFile))
       
   925 		{
       
   926 		ret = KErrNotFound;
       
   927 		}
       
   928 
       
   929 	if (ret == KErrNone)
       
   930 		{
       
   931 		return ETrue;
       
   932 		}
       
   933 	else
       
   934 		{
       
   935 		return EFalse;
       
   936 		}
       
   937 	}
       
   938 
       
   939 /**
       
   940 It creates a pre-allocated file.
       
   941 
       
   942 @internalComponent
       
   943 */
       
   944 void CPreallocatedFile::CreateL()
       
   945 	{
       
   946 	LOGSMSPROT1("CPreallocatedFile::CreateL");
       
   947 
       
   948 	User::LeaveIfError(iFile.Replace(iFs, iFileName->Des(), EFileWrite));
       
   949 	User::LeaveIfError(iFile.SetSize(iSizeOfFile));
       
   950 	iFile.Flush();
       
   951 
       
   952 	// Externalize Version Number
       
   953 	//TInt version = iVersion;
       
   954 	TPtr8 memPtr((TUint8*) &iVersion, KSizeOfPreallocatedFileVersion, KSizeOfPreallocatedFileVersion);
       
   955 	iFile.Write(0, memPtr);
       
   956 
       
   957 	//Externalize Header Information
       
   958 	ExternalizeEntryArray();
       
   959 
       
   960 	// Initialize Storage Identifier Section.
       
   961 	TInt storageIdentifier=0;
       
   962 	memPtr.Set((TUint8*) &storageIdentifier, sizeof(storageIdentifier), sizeof(storageIdentifier));
       
   963 	TInt pos = KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
   964 	TInt pos2 = 0;
       
   965 	for (TInt count=0; count<iMaxPDUSeg+1; count++)
       
   966 		{
       
   967 		pos2 = pos + count * sizeof(storageIdentifier);
       
   968 		iFile.Write(KBeginOfMasterHeaderSection + pos2, memPtr);
       
   969 		//iFile.Write(iBeginOfDuplicateHeaderSection + pos2, memPtr);
       
   970 		}
       
   971 
       
   972 	// Initialize Checksum
       
   973 	PutChecksumValueL();
       
   974 
       
   975 	// Close it to make sure that file is created correctly (defensive approach).
       
   976 	iFile.Close();
       
   977 	//Again Open the file
       
   978 	OpenL();
       
   979 	}
       
   980 
       
   981 /**
       
   982 It opens the pre-allocated file. Then it internalizes all the entry information.
       
   983 
       
   984 @internalComponent
       
   985 */
       
   986 void CPreallocatedFile::OpenL()
       
   987 	{
       
   988 	User::LeaveIfError(iFile.Open(iFs, iFileName->Des(), EFileShareExclusive|EFileRead|EFileWrite));
       
   989 	// Check the validity of the data.
       
   990 	CheckDataL();
       
   991 	// Internalize data
       
   992 	InternalizeEntryArrayL();
       
   993 	}
       
   994 
       
   995 /**
       
   996 It closes the pre-allocated file.
       
   997 
       
   998 @internalComponent
       
   999 */
       
  1000 void CPreallocatedFile::Close()
       
  1001 	{
       
  1002 	iFile.Close();
       
  1003 	iEntryArray.Reset();
       
  1004 	iReinstateEntryInfo.Reset();
       
  1005 	}
       
  1006 
       
  1007 /**
       
  1008 It internalizes the entry info from pre-allocated file.
       
  1009 
       
  1010 @internalComponent
       
  1011 */
       
  1012 void CPreallocatedFile::InternalizeEntryArrayL()
       
  1013 	{
       
  1014 	iEntryArray.Reset();
       
  1015 	TInt numberOfMessage;
       
  1016 	TPtr8 memPtr((TUint8*) &numberOfMessage, sizeof(numberOfMessage), sizeof(numberOfMessage));
       
  1017 	iFile.Read(KBeginOfMasterHeaderSection, memPtr);
       
  1018 
       
  1019 	TSmsPreAllocatedFileStoreReassemblyEntry tmpClass0ReassemblyStore;
       
  1020 	memPtr.Set((TUint8*) &tmpClass0ReassemblyStore, KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry);
       
  1021 
       
  1022 	TInt pos = 0;
       
  1023 	for (TInt count=0; count < numberOfMessage; count++)
       
  1024 		{
       
  1025 		pos = sizeof(TInt) + (count * KSizeOfPreAllocatedStoreEntry);
       
  1026 		iFile.Read(KBeginOfMasterHeaderSection + pos, memPtr);
       
  1027 		iEntryArray.AppendL(tmpClass0ReassemblyStore);
       
  1028 		}
       
  1029 	}
       
  1030 
       
  1031 /**
       
  1032 It externalizes the entry info to pre-allocated file.
       
  1033 
       
  1034 @internalComponent
       
  1035 */
       
  1036 void CPreallocatedFile::ExternalizeEntryArray()
       
  1037 	{
       
  1038 	TInt count=iEntryArray.Count();
       
  1039 	TInt numberOfMessage=0;
       
  1040 	TInt i=0;
       
  1041 
       
  1042 	for (; i<count; i++)
       
  1043 		{
       
  1044 		if (!iEntryArray[i].IsDeleted())
       
  1045 			{
       
  1046 			numberOfMessage++;
       
  1047 			}
       
  1048 		}
       
  1049 
       
  1050 	//Externalize number of mesages.
       
  1051 	TPtr8 memPtr((TUint8*) &numberOfMessage, sizeof(numberOfMessage), sizeof(numberOfMessage));
       
  1052 	iFile.Write(KBeginOfMasterHeaderSection, memPtr);
       
  1053 
       
  1054 	TInt entryNumber = 0;
       
  1055 	//Externalize all the entries.
       
  1056 	for (i=0; i<count; i++)
       
  1057 		{
       
  1058 		if (!iEntryArray[i].IsDeleted())
       
  1059 			{
       
  1060 			//At the time of externalizing don't externalize IsAdded(), IsDeleted() value
       
  1061 			TBool isAdded = iEntryArray[i].IsAdded();
       
  1062 			TBool isDeleted = iEntryArray[i].IsDeleted();
       
  1063 			iEntryArray[i].SetIsAdded(EFalse);
       
  1064 			iEntryArray[i].SetIsDeleted(EFalse);
       
  1065 			memPtr.Set((TUint8*) &iEntryArray[i], KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry);
       
  1066 			iFile.Write(KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + (entryNumber * KSizeOfPreAllocatedStoreEntry), memPtr);
       
  1067 			//Again update IsAdded(), IsDeleted() with previous value
       
  1068 			iEntryArray[i].SetIsAdded(isAdded);
       
  1069 			iEntryArray[i].SetIsDeleted(isDeleted);
       
  1070 			entryNumber++;
       
  1071 			}
       
  1072 		}
       
  1073 
       
  1074 	count = numberOfMessage;
       
  1075 	/*
       
  1076 	Externalize extra entry information with default information.
       
  1077 	This initialization is required because of checksum.
       
  1078 	*/
       
  1079 	TSmsPreAllocatedFileStoreReassemblyEntry tmpClass0ReassemblyStore;
       
  1080 	memPtr.Set((TUint8*) &tmpClass0ReassemblyStore, KSizeOfPreAllocatedStoreEntry, KSizeOfPreAllocatedStoreEntry);
       
  1081 	TInt pos = 0;
       
  1082 	for (; count<iMaxClass0Msg + 1; count++)
       
  1083 		{
       
  1084 		pos = KSizeOfNumberOfEntrySection + (count * KSizeOfPreAllocatedStoreEntry);
       
  1085 		iFile.Write(KBeginOfMasterHeaderSection + pos, memPtr);
       
  1086 		}
       
  1087 	iFile.Flush();
       
  1088 	}
       
  1089 
       
  1090 /*
       
  1091 It adds the new message in pre-allocated file.
       
  1092 
       
  1093 @param aIndex (output) index number on which message is added.
       
  1094 @param aSmsMessage reference to sms message to be added.
       
  1095 @param aGsmSms reference to GsmSms object to be added.
       
  1096 
       
  1097 @internalComponent
       
  1098 */
       
  1099 void CPreallocatedFile::AddNewMessageL(TInt& aIndex, CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
       
  1100 	{
       
  1101 	LOGSMSPROT1("CPreallocatedFile::AddNewMessageL");
       
  1102 	//Gets the next free slot where the message will be stored.
       
  1103 	TInt nextFreeSlot = GetFreeContainer();
       
  1104 	TInt pduIndex=aSmsMessage.IsDecoded()? 0: aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
       
  1105 	if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage  ||
       
  1106 		aSmsMessage.Storage() == CSmsMessage::ESmsCombinedStorage)
       
  1107 		{
       
  1108 		const TGsmSmsSlotEntry&  newSlot = aSmsMessage.iSlotArray[0];
       
  1109 		ExternalizeEntry(nextFreeSlot, newSlot, pduIndex, aGsmSms);
       
  1110 		}
       
  1111 	else
       
  1112 		{
       
  1113 		ExternalizeEntry(nextFreeSlot, pduIndex, aGsmSms);
       
  1114 		}
       
  1115 
       
  1116 	/*
       
  1117 	Gets the unique id which will identify the containers where the 
       
  1118 	PDU related to this messsage are stored.
       
  1119 	*/
       
  1120 	TInt freeStorageId = GetFreeStorageId();
       
  1121 	AddStorageIdL(nextFreeSlot, freeStorageId);
       
  1122 
       
  1123 	TSmsPreAllocatedFileStoreReassemblyEntry tmpEntry;
       
  1124 	//Fill-up entry information...
       
  1125 	CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1);
       
  1126 	tmpEntry.SetPreAllocatedStorageId(freeStorageId);
       
  1127 	//The properties below need to be set only once when a PDU of a new message arrives.
       
  1128 	tmpEntry.SetStatus((RMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status());
       
  1129 	tmpEntry.SetUTCOffset(aSmsMessage.UTCOffset());
       
  1130 	tmpEntry.SetDecodedOnSIM(aSmsMessage.DecodedOnSim());
       
  1131 	tmpEntry.SetForwardToClient(aSmsMessage.ForwardToClient());
       
  1132 
       
  1133 	// Add & extrenalize entry array.
       
  1134 	aIndex = iEntryArray.Count();
       
  1135 	AddEntryL(tmpEntry);
       
  1136 	}
       
  1137 
       
  1138 /*
       
  1139 It updates the existing message in permanent store file.
       
  1140 
       
  1141 @param aIndex index number on which message is to be updated.
       
  1142 @param aSmsMessage reference to sms message to be updated.
       
  1143 @param aPduIndex index of the PDU to be updated.
       
  1144 @param aSms sms of the PDU to be updated.
       
  1145 
       
  1146 @internalComponent
       
  1147 */
       
  1148 void CPreallocatedFile::UpdateExistingMessageL(TInt aIndex, const CSmsMessage& aSmsMessage, TInt aPduIndex, const TGsmSms& aSms)
       
  1149 	{
       
  1150 	LOGSMSPROT1("CPreallocatedFile::UpdateExistingMessageL()");
       
  1151 	TInt preAllocatedStorageId = iEntryArray[aIndex].PreAllocatedStorageId();
       
  1152 	if (preAllocatedStorageId == KErrNotFound)
       
  1153 		{
       
  1154 		/*
       
  1155 		This condition arises when part of message is stored in permanent store file & 
       
  1156 		other parts arrive when system is out of disk.
       
  1157 		*/
       
  1158 		preAllocatedStorageId = GetFreeStorageId();
       
  1159 		iEntryArray[aIndex].SetPreAllocatedStorageId(preAllocatedStorageId);
       
  1160 		}
       
  1161 	// Externalize Entry in one of free containers.
       
  1162 	TInt freeSlot = GetFreeContainer();
       
  1163 	if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage  ||
       
  1164 		aSmsMessage.Storage() == CSmsMessage::ESmsCombinedStorage)
       
  1165 		{
       
  1166 		const TGsmSmsSlotEntry&  newSlot = aSmsMessage.iSlotArray[0];
       
  1167 		ExternalizeEntry(freeSlot, newSlot, aPduIndex, aSms);
       
  1168 		}
       
  1169 	else
       
  1170 		{
       
  1171 		ExternalizeEntry(freeSlot, aPduIndex, aSms);
       
  1172 		}
       
  1173 
       
  1174 	AddStorageIdL(freeSlot, preAllocatedStorageId);
       
  1175 	TSmsPreAllocatedFileStoreReassemblyEntry entry;
       
  1176 	entry = iEntryArray[aIndex];
       
  1177 	/*
       
  1178 	This value must be set because this may the first PDU of an 
       
  1179 	existing message which is stored in pre-allocated store file.
       
  1180 	*/
       
  1181 	entry.SetPreAllocatedStorageId(preAllocatedStorageId);
       
  1182 	entry.SetCount(entry.Count()+1);
       
  1183 	ChangeEntryL(aIndex, entry);
       
  1184 	}
       
  1185 
       
  1186 /*
       
  1187 It matches the entry with entry in pre-allocated file & returns
       
  1188 the index. If not found it returns KErrNotFound.
       
  1189 
       
  1190 @param aEntry reference to entry information.
       
  1191 @param aIndex (output) returns the index number.
       
  1192 
       
  1193 @internalComponent
       
  1194 */
       
  1195 void CPreallocatedFile::MatchEntryToExistingMessage(const TReassemblyEntry& aEntry,
       
  1196 													TInt& aIndex)
       
  1197 	{
       
  1198 	LOGSMSPROT1("CPreallocatedFile::MatchEntryToExistingMessage()");
       
  1199 
       
  1200 	aIndex = KErrNotFound;
       
  1201 
       
  1202 	//
       
  1203 	// Search the reassembly store for a matching entry...
       
  1204 	//
       
  1205 	TInt reassemblyCount = iEntryArray.Count();
       
  1206 
       
  1207 	for (TInt  index = 0;  index < reassemblyCount;  index++)
       
  1208 		{
       
  1209 		TSmsPreAllocatedFileStoreReassemblyEntry&  entry = iEntryArray[index];
       
  1210 
       
  1211 		if (entry.Reference() == aEntry.Reference()  &&
       
  1212 		    entry.Total() == aEntry.Total()  &&
       
  1213 		    entry.PduType() == aEntry.PduType()  &&
       
  1214 			entry.Storage() == aEntry.Storage()  &&
       
  1215 			entry.Description2() == aEntry.Description2())
       
  1216 			{
       
  1217 			//
       
  1218 			// Found it!
       
  1219 			//
       
  1220 			aIndex = index;
       
  1221 			break;
       
  1222 			}
       
  1223 		}
       
  1224 
       
  1225 	LOGSMSPROT2("CPreallocatedFile::MatchEntryToExistingMessage(): aIndex=%d", aIndex);
       
  1226 	}
       
  1227 
       
  1228 /*
       
  1229 It updates the log server id of the message.
       
  1230 
       
  1231 @param aIndex index number of the message to be updated.
       
  1232 @param aLogServerId log server id.
       
  1233 
       
  1234 @internalComponent
       
  1235 */
       
  1236 void CPreallocatedFile::UpdateLogServerIdL(TInt& aIndex, TLogId aLogServerId)
       
  1237 	{
       
  1238 	LOGSMSPROT1("CPreallocatedFile::UpdateLogServerId");
       
  1239 
       
  1240 	TSmsPreAllocatedFileStoreReassemblyEntry entry;
       
  1241 	entry = iEntryArray[aIndex];
       
  1242 
       
  1243 	if (entry.LogServerId() != aLogServerId)
       
  1244 		{
       
  1245 		entry.SetLogServerId(aLogServerId);
       
  1246 		ChangeEntryL(aIndex, entry);
       
  1247 		}
       
  1248 	}
       
  1249 
       
  1250 /*
       
  1251 It sets the message passed to client or not.
       
  1252 
       
  1253 @param aIndex index number of the message to be updated.
       
  1254 @param aBool boolean value indicating whether message is passes or not.
       
  1255 
       
  1256 @internalComponent
       
  1257 */
       
  1258 void CPreallocatedFile::SetPassedToClientL(TInt aIndex, TBool aBool)
       
  1259 	{
       
  1260 	LOGSMSPROT2("CPreallocatedFile::SetPassedToClientL(): aIndex=%d", aIndex);
       
  1261 
       
  1262 	TSmsPreAllocatedFileStoreReassemblyEntry entry;
       
  1263 	entry = iEntryArray[aIndex];
       
  1264 
       
  1265 	if (entry.PassedToClient() != aBool)
       
  1266 		{
       
  1267 		entry.SetPassedToClient(aBool);
       
  1268 		ChangeEntryL(aIndex, entry);
       
  1269 		}
       
  1270 	}
       
  1271 
       
  1272 /*
       
  1273 It adds the new entry in the existing entry array.
       
  1274 
       
  1275 @param aEntry entry to be added.
       
  1276 
       
  1277 @internalComponent
       
  1278 */
       
  1279 void CPreallocatedFile::AddEntryL(TSmsPreAllocatedFileStoreReassemblyEntry& aEntry)
       
  1280 	{
       
  1281 	LOGSMSPROT1("CPreallocatedFile::AddEntryL");
       
  1282 	iEntryArray.AppendL(aEntry);
       
  1283 	iEntryArray[iEntryArray.Count()-1].SetIsAdded(ETrue);
       
  1284 	}
       
  1285 
       
  1286 /*
       
  1287 It changes the existing entry with new entry.
       
  1288 
       
  1289 @param aIndex index number of the entry which will be changed.
       
  1290 @param aNewEntry entry to be updated.
       
  1291 
       
  1292 @internalComponent
       
  1293 */
       
  1294 void CPreallocatedFile::ChangeEntryL(TInt aIndex, const TSmsPreAllocatedFileStoreReassemblyEntry& aNewEntry)
       
  1295 	{
       
  1296 	LOGSMSPROT2("CPreallocatedFile::ChangeEntryL(): aIndex=%d", aIndex);
       
  1297 	iEntryArray[aIndex].SetIsDeleted(ETrue);
       
  1298 	iEntryArray.InsertL(aIndex,aNewEntry);
       
  1299 	iEntryArray[aIndex].SetIsAdded(ETrue);
       
  1300 	}
       
  1301 
       
  1302 /*
       
  1303 It deletes the entry.
       
  1304 
       
  1305 @param aIndex index number of the entry which will be deleted.
       
  1306 
       
  1307 @internalComponent
       
  1308 */
       
  1309 void CPreallocatedFile::DeleteEntryL(TInt aIndex)
       
  1310 	{
       
  1311 	LOGSMSPROT2("CPreallocatedFile::DeleteEntryL(): aIndex=%d", aIndex);
       
  1312 	if (iEntryArray[aIndex].PreAllocatedStorageId() != KErrNotFound)
       
  1313 		{
       
  1314 		ClearEntryL(iEntryArray[aIndex].PreAllocatedStorageId(), iEntryArray[aIndex].Count());
       
  1315 		}
       
  1316 	iEntryArray[aIndex].SetIsDeleted(ETrue);
       
  1317 	}
       
  1318 
       
  1319 /*
       
  1320 It searches all the container & clears all the entries which
       
  1321 contain the PDUs of the message (uniquely identified by aStorageId).
       
  1322 
       
  1323 NOTE:
       
  1324 	It keeps the record of removed entries (container id, pre-allocated storage id 
       
  1325 	& operation performed (add/delete)) in iReinstateEntryInfo variable.
       
  1326 	It will be required in case of revert operation. As the container which
       
  1327 	refers to the container which contains actual PDU is freed,
       
  1328 	so it will not be a problem to restore the removed PDUs.
       
  1329 	In case of revert operation, the removed information can be found in
       
  1330 	iReinstateEntryInfo variable which can be restored easily. 
       
  1331 	The container can be replaced with previous pre-allocated storage id.
       
  1332 	After commiting the transaction, this varaible will be re-initialized.
       
  1333 
       
  1334 @param aStorageId unique id of message to be cleared.
       
  1335 @param aNumberOfPDUs number of PDUs to be cleared.
       
  1336 
       
  1337 @internalComponent
       
  1338 */
       
  1339 void CPreallocatedFile::ClearEntryL(TInt aStorageId, TInt aNumberOfPDUs)
       
  1340 	{
       
  1341 	LOGSMSPROT1("CPreallocatedFile::ClearEntryL");
       
  1342 
       
  1343 	//Read storage id.
       
  1344 	TInt storageId;
       
  1345 	TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId));
       
  1346 	TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  1347 	TInt beginOfStorageId = 0;
       
  1348 	TInt count;
       
  1349 	TInt count2(0);
       
  1350 
       
  1351 	TInt cleanStorageId=0;
       
  1352 	TPtr8 memPtr2((TUint8*) &cleanStorageId, sizeof(cleanStorageId), sizeof(cleanStorageId));
       
  1353 
       
  1354 	for (count=0; count<iMaxPDUSeg+1; count++)
       
  1355 		{
       
  1356 		TReinstateEntryInfo entry;
       
  1357 		entry.iPreAllocatedStorageId=aStorageId;
       
  1358 		entry.iFlag=EEntryIsDeleted;
       
  1359 
       
  1360 		beginOfStorageId = beginOfStorageIdSection + (count * sizeof(storageId));
       
  1361 		iFile.Read(beginOfStorageId, memPtr);
       
  1362 		if (storageId == aStorageId)
       
  1363 			{
       
  1364 			count2++;
       
  1365 			iFile.Write(beginOfStorageId, memPtr2);
       
  1366 			entry.iContainerId=count+1;
       
  1367 			iReinstateEntryInfo.AppendL(entry);
       
  1368 			}
       
  1369 		if (count2 >= aNumberOfPDUs)
       
  1370 			{
       
  1371 			break;
       
  1372 			}
       
  1373 		}
       
  1374 	iFile.Flush();
       
  1375 	}
       
  1376 
       
  1377 /*
       
  1378 It updates the storage identifier section. It updates the corresponding container
       
  1379 in the storage identifier section specifying the PDU where it is stored.
       
  1380 
       
  1381 NOTE:
       
  1382 	It keeps the record of added entries in iReinstateEntryInfo variable.
       
  1383 	It will be required in case of revert operation.
       
  1384 	After commiting the transaction, this varaible should be re-initialized.
       
  1385 
       
  1386 @param aIndex index number of the container where PDU has been stored..
       
  1387 @param aStorageId unique id of added message.
       
  1388 
       
  1389 @internalComponent
       
  1390 */
       
  1391 void CPreallocatedFile::AddStorageIdL(TInt aIndex, TInt aStorageId)
       
  1392 	{
       
  1393 	//Put storage id in master header section
       
  1394 	TPtr8 memPtr((TUint8*) &aStorageId, sizeof(aStorageId), sizeof(aStorageId));
       
  1395 	TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  1396 	iFile.Write( beginOfStorageIdentifierSection + ((aIndex - 1) * sizeof(TInt)), memPtr);
       
  1397 
       
  1398 	TReinstateEntryInfo entry;
       
  1399 	entry.iContainerId=aIndex;
       
  1400 	entry.iPreAllocatedStorageId=aStorageId;
       
  1401 	entry.iFlag=EEntryIsAdded;
       
  1402 	iReinstateEntryInfo.AppendL(entry);
       
  1403 	}
       
  1404 
       
  1405 /*
       
  1406 It returns the next free available free container where next PDU can be stored.
       
  1407 
       
  1408 It goes through storage identifier section, it reads the conents of all storage
       
  1409 identfier & return that container which is free.
       
  1410 All the free container is identifiable by value 0. If the value is not 0 then it
       
  1411 contains the storage id of a particular message.
       
  1412 
       
  1413 @internalComponent
       
  1414 */
       
  1415 TInt CPreallocatedFile::GetFreeContainer()
       
  1416 	{
       
  1417 	// Get the next free slot.
       
  1418 	TInt storageId;
       
  1419 	TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId));
       
  1420 	TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  1421 	TInt beginOfStorageId = 0;
       
  1422 	TInt count;
       
  1423 
       
  1424 	for (count=0; count<iMaxPDUSeg+1; count++)
       
  1425 		{
       
  1426 		beginOfStorageId = beginOfStorageIdSection + (count * sizeof(storageId));
       
  1427 		iFile.Read(beginOfStorageId, memPtr);
       
  1428 		if (storageId == 0)
       
  1429 			{
       
  1430 			break;
       
  1431 			}
       
  1432 		}
       
  1433 
       
  1434 	// Count should never equal to iMaxPDUSeg+1
       
  1435 	__ASSERT_DEBUG(count < iMaxPDUSeg+1, SmspPanic(KSmspPanicPreallocatedFileNoFreeContainer));
       
  1436 	
       
  1437 	return (count + 1);
       
  1438 	}
       
  1439 
       
  1440 /*
       
  1441 It returns the next free storage id.
       
  1442 
       
  1443 Storage id is used to identify the messages stored in pre-allocated file.
       
  1444 A message might contain multiple PDUs and all those PDUs will be stored in 
       
  1445 different container. This storage id will be used to identify on which 
       
  1446 container the PDUs of a message are stored.
       
  1447 
       
  1448 This logic is based on the max number of messages that can be stored in
       
  1449 pre-allocated file at one time. So free storage id is always used from
       
  1450 this pool of numbers (from 1 till (max calls 0 message+2)).
       
  1451 
       
  1452 @internalComponent
       
  1453 */
       
  1454 TInt CPreallocatedFile::GetFreeStorageId()
       
  1455 	{
       
  1456 	TInt count;
       
  1457 
       
  1458 	for (count=1; count < iMaxClass0Msg + 2; count++)
       
  1459 		{
       
  1460 		TInt numberOfEntries = iEntryArray.Count();
       
  1461 		TInt count2;
       
  1462 		for (count2 = 0; count2 < numberOfEntries; count2++)
       
  1463 			{
       
  1464 			if (count == iEntryArray[count2].PreAllocatedStorageId())
       
  1465 				{
       
  1466 				break;
       
  1467 				}
       
  1468 			}
       
  1469 			if (count2 == numberOfEntries)
       
  1470 				{
       
  1471 				break;
       
  1472 				}
       
  1473 		}
       
  1474 		return count;
       
  1475 	}
       
  1476 
       
  1477 /*
       
  1478 It externalizes(writes) the entry in permanent store file.
       
  1479 
       
  1480 @param aContainerId container id where the sms pdu needs to externalized.
       
  1481 @param aSmsSlot reference to slot information.
       
  1482 @param aIndex index number of PDU.
       
  1483 @param aGsmSms refence to sms pdu.
       
  1484 
       
  1485 @internalComponent
       
  1486 */
       
  1487 void CPreallocatedFile::ExternalizeEntry(TInt aContainerId, const TGsmSmsSlotEntry& aSmsSlot, TInt aIndex, const TGsmSms& aGsmSms)
       
  1488 	{
       
  1489 	LOGSMSPROT3("CPreallocatedFile::ExternalizeEntry() 1: aContainerId=%d, aIndex=%d", aContainerId, aIndex);
       
  1490 
       
  1491 	// Container id must not be greater than max pdu segment.
       
  1492 	TInt pos = iBeginOfDataSection + ((aContainerId - 1) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
       
  1493 	// Store slot info
       
  1494 	TPtr8 memPtr((TUint8*) &aSmsSlot, sizeof(aSmsSlot), sizeof(aSmsSlot));
       
  1495 	iFile.Write(pos, memPtr);
       
  1496 	// Store the PDU index value
       
  1497 	memPtr.Set((TUint8*) &aIndex, sizeof(aIndex), sizeof(aIndex));
       
  1498 	iFile.Write(pos + KSizeOfGsmSmsSlotEntry, memPtr);
       
  1499 	// Store the TGsmSms value
       
  1500 	RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
  1501 	pdu = aGsmSms.Pdu();
       
  1502 	memPtr.Set((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU);
       
  1503 	iFile.Write(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt), memPtr);
       
  1504 
       
  1505 	__ASSERT_DEBUG(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU <= iSizeOfFile,
       
  1506 			       SmspPanic(KSmspPanicPreallocatedFileCorrupt));
       
  1507 	}
       
  1508 
       
  1509 /*
       
  1510 It externalizes(writes) the entry in permanent store file.
       
  1511 
       
  1512 @param aContainerId container id where the sms pdu needs to externalized.
       
  1513 @param aIndex index number of PDU.
       
  1514 @param aGsmSms refence to sms pdu.
       
  1515 
       
  1516 @internalComponent
       
  1517 */
       
  1518 void CPreallocatedFile::ExternalizeEntry(TInt aContainerId, TInt aIndex, const TGsmSms& aGsmSms)
       
  1519 	{
       
  1520 	LOGSMSPROT3("CPreallocatedFile::ExternalizeEntry() 2: aContainerId=%d, aIndex=%d", aContainerId, aIndex);
       
  1521 
       
  1522 	// Container id must not be greater than max pdu segment.
       
  1523 	TInt pos = iBeginOfDataSection + ((aContainerId - 1) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
       
  1524 	// Store the PDU index value
       
  1525 	TPtr8 memPtr((TUint8*) &aIndex, sizeof(aIndex), sizeof(aIndex));
       
  1526 	iFile.Write(pos + KSizeOfGsmSmsSlotEntry, memPtr);
       
  1527 	// Store the TGsmSms value
       
  1528 	RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
  1529 	pdu = aGsmSms.Pdu();
       
  1530 	memPtr.Set((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU);
       
  1531 	iFile.Write(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt), memPtr);
       
  1532 
       
  1533 	__ASSERT_DEBUG(pos + KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU <= iSizeOfFile,
       
  1534 			       SmspPanic(KSmspPanicPreallocatedFileCorrupt));
       
  1535 	}
       
  1536 
       
  1537 /*
       
  1538 It internalizes(reads) the entry from permanent store file.
       
  1539 
       
  1540 @param aIndex index number of the message to be internalized.
       
  1541 @param aSmsMessage (output) reference to sms message.
       
  1542 @param aIndexArray (output) refence to array of index.
       
  1543 @param aSmsArray (output) refence to array of sms.
       
  1544 
       
  1545 @internalComponent
       
  1546 */
       
  1547 void CPreallocatedFile::InternalizeEntryL(const TInt aIndex, CSmsMessage& aSmsMessage, CArrayFix<TInt>& aIndexArray, CArrayFix<TGsmSms>& aSmsArray)
       
  1548 	{
       
  1549 	LOGSMSPROT1("CPreallocatedFile::InternalizeEntryL");
       
  1550 	TSmsPreAllocatedFileStoreReassemblyEntry&  entry = iEntryArray[aIndex];
       
  1551 	//Set other properties of CSmsMessage
       
  1552 	aSmsMessage.SetStorage(entry.Storage());
       
  1553 	aSmsMessage.SetStatus((NMobileSmsStore::TMobileSmsStoreStatus)entry.Status());
       
  1554 	aSmsMessage.SetLogServerId(entry.LogServerId());
       
  1555 	aSmsMessage.SetTime(entry.Time());
       
  1556 	aSmsMessage.SetUTCOffset(entry.UTCOffset());
       
  1557 	aSmsMessage.SetDecodedOnSIM(entry.DecodedOnSIM());
       
  1558 	aSmsMessage.SetForwardToClient(entry.ForwardToClient());
       
  1559 	aSmsMessage.SetToFromAddressL(entry.Description2());
       
  1560 
       
  1561 	LOGSMSPROT2("CPreallocatedFile::InternalizeEntryL Start [sid=%d]", entry.PreAllocatedStorageId());
       
  1562 	if (entry.PreAllocatedStorageId()==KErrNotFound)
       
  1563 		{
       
  1564 		return;
       
  1565 		}
       
  1566 
       
  1567 	TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  1568 	//This will be used to read the storgae id which will indicate 
       
  1569 	//that corresponding container contains actual PDU
       
  1570 	TInt storageId=0;
       
  1571 	TPtr8 memPtr1((TUint8*) &storageId, sizeof(storageId), sizeof(storageId));
       
  1572 
       
  1573 	TInt storageIdPos = 0;
       
  1574 	TInt dataPos = 0;
       
  1575 	//This will be used to read the slot information
       
  1576 	TGsmSmsSlotEntry smsSlotEntry;
       
  1577 	TPtr8 memPtr2((TUint8*) &smsSlotEntry, KSizeOfGsmSmsSlotEntry, KSizeOfGsmSmsSlotEntry);
       
  1578 	//This will be used to read the concatenated PDU index.
       
  1579 	TInt index=0;
       
  1580 	TPtr8 memPtr3((TUint8*) &index, sizeof(index), sizeof(index));
       
  1581 	//This will be used to read PDU.
       
  1582 	RMobileSmsMessaging::TMobileSmsGsmTpdu pdu;
       
  1583 	TPtr8 memPtr4((TUint8*) &pdu, KSizeOfSmsGsmPDU, KSizeOfSmsGsmPDU);
       
  1584 	TGsmSms sms;
       
  1585 
       
  1586 	//Number of PDUs stored in this pre-allocated file
       
  1587 	TInt noOfPDUs = iEntryArray[aIndex].Count();
       
  1588 	//Will indicate how many number of PDUs already read from pre-allocated file.
       
  1589 	TInt noOfPDUsRead = 0;
       
  1590 	// Can also get the number of pdu stored in pre-allocated file from count's variable.
       
  1591 	for (TInt count=0; count<iMaxPDUSeg+1; count++)
       
  1592 		{
       
  1593 		storageIdPos = beginOfStorageIdSection + count * sizeof(TInt);
       
  1594 		iFile.Read(storageIdPos, memPtr1);
       
  1595 		if (storageId == entry.PreAllocatedStorageId())
       
  1596 			{//This means corresponding container contains the actual PDU
       
  1597 			noOfPDUsRead++;
       
  1598 			//Find the position of container where actaul PDU is stored.
       
  1599 			dataPos = iBeginOfDataSection + ((count) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
       
  1600 			//Read slot information
       
  1601 			if (entry.Storage() == CSmsMessage::ESmsSIMStorage  ||
       
  1602 				entry.Storage() == CSmsMessage::ESmsCombinedStorage)
       
  1603 				{
       
  1604 				iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry, memPtr2);
       
  1605 				aSmsMessage.AddSlotL(smsSlotEntry);
       
  1606 				}
       
  1607 			//Read index information
       
  1608 			iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry, memPtr3);
       
  1609 			aIndexArray.AppendL(index);
       
  1610 			//Read PDU
       
  1611 			iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry + sizeof(index), memPtr4);
       
  1612 			sms.SetPdu(pdu);
       
  1613 			aSmsArray.AppendL(sms);
       
  1614 			if (noOfPDUsRead == noOfPDUs)
       
  1615 				{
       
  1616 				break;
       
  1617 				}
       
  1618 			}
       
  1619 		}
       
  1620 
       
  1621 	LOGSMSPROT2("CPreallocatedFile::InternalizeEntryL End [noOfPDUsRead=%d]", noOfPDUsRead);
       
  1622 	}
       
  1623 
       
  1624 /*
       
  1625 It removes the PDUs from pre-allocated store file.
       
  1626 This function is needed because after forwarding the incomplete message
       
  1627 to client, the corresponding PDUs needs to be be removed from permanent
       
  1628 store file.
       
  1629 This functionality is specific to class 0 re-assembly store.
       
  1630 
       
  1631 @param aIndex index number of the message to be removed.
       
  1632 @param aStartPos starting pos of pdu to be removed.
       
  1633 @param aEndPos end pos of pdu to be removed.
       
  1634 
       
  1635 @internalComponent
       
  1636 */
       
  1637 void CPreallocatedFile::RemovePDUsL(TInt aIndex, TInt aStartPos, TInt aEndPos)
       
  1638 	{
       
  1639 	LOGSMSPROT1("CPreallocatedFile::RemovePDUsL");
       
  1640 
       
  1641 	if ((aStartPos < 1) || (aEndPos > 256) || (aStartPos > aEndPos))
       
  1642 		{
       
  1643 		User::Leave(KErrArgument);
       
  1644 		}
       
  1645 
       
  1646 	LOGSMSPROT2("CPreallocatedFile::RemovePDUsL Start [sid=%d]", iEntryArray[aIndex].PreAllocatedStorageId());
       
  1647 	if (iEntryArray[aIndex].PreAllocatedStorageId()==KErrNotFound)
       
  1648 		{
       
  1649 		return;
       
  1650 		}
       
  1651 
       
  1652 	TInt beginOfStorageIdSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  1653 	//This will be used to read the storgae id which will indicate 
       
  1654 	//that corresponding container contains actual PDU
       
  1655 	TInt storageId=0;
       
  1656 	TPtr8 memPtr1((TUint8*) &storageId, sizeof(storageId), sizeof(storageId));
       
  1657 
       
  1658 	//This will be used to cleanup the storage id.
       
  1659 	TInt cleanStorageId=0;
       
  1660 	TPtr8 memPtr2((TUint8*) &cleanStorageId, sizeof(cleanStorageId), sizeof(cleanStorageId));
       
  1661 
       
  1662 	//This will be used to read the concatenated PDU index.
       
  1663 	TInt index=0;
       
  1664 	TPtr8 memPtr3((TUint8*) &index, sizeof(index), sizeof(index));
       
  1665 
       
  1666 	//Number of PDUs stored in this pre-allocated file
       
  1667 	TInt noOfPDUs = iEntryArray[aIndex].Count();
       
  1668 	//Will indicate how many number of PDUs already read from pre-allocated file.
       
  1669 	TInt noOfPDUsRead = 0;
       
  1670 	// Can also get the number of pdu stored in pre-allocated file from count's variable.
       
  1671 	TInt noOfEntriesRemoved=0;
       
  1672 	for (TInt count=0; count<iMaxPDUSeg+1; count++)
       
  1673 		{
       
  1674 		TInt storageIdPos = beginOfStorageIdSection + count * sizeof(TInt);
       
  1675 		iFile.Read(storageIdPos, memPtr1);
       
  1676 		if (storageId == iEntryArray[aIndex].PreAllocatedStorageId())
       
  1677 			{//This means corresponding container contains the actual PDU
       
  1678 			noOfPDUsRead++;
       
  1679 			//Find the position of container where actaul PDU is stored.
       
  1680 			TInt dataPos = iBeginOfDataSection + ((count) * (KSizeOfGsmSmsSlotEntry + sizeof(TInt) + KSizeOfSmsGsmPDU));
       
  1681 			//Read index information
       
  1682 			iFile.Read(dataPos + KSizeOfGsmSmsSlotEntry, memPtr3);
       
  1683 
       
  1684 			if ((index >= aStartPos) && (index <= aEndPos))
       
  1685 				{
       
  1686 				noOfEntriesRemoved++;
       
  1687 				//Remove the PDU entry.
       
  1688 				iFile.Write(storageIdPos, memPtr2);
       
  1689 				}
       
  1690 
       
  1691 			if (noOfPDUsRead == noOfPDUs)
       
  1692 				{
       
  1693 				break;
       
  1694 				}
       
  1695 			}
       
  1696 		}
       
  1697 
       
  1698 	/*
       
  1699 	There are 3 scenarios in this case:
       
  1700 	1. If all the entries need to be removed,
       
  1701 	then there is no need to store the entry in this permanent file.
       
  1702 	2. If few entries need to be removed,
       
  1703 	then externalize the remaining entries. Update count field also.
       
  1704 	3. If no entries need to be removed, then do nothing.
       
  1705 	*/
       
  1706 	TSmsPreAllocatedFileStoreReassemblyEntry entry;
       
  1707 	entry = iEntryArray[aIndex];
       
  1708 
       
  1709 	if (entry.Count() == noOfEntriesRemoved)
       
  1710 		{
       
  1711 		entry.SetPreAllocatedStorageId(KErrNotFound);
       
  1712 		entry.SetCount(0);
       
  1713 		ChangeEntryL(aIndex, entry);
       
  1714 		}
       
  1715 	else if (noOfEntriesRemoved > 0)
       
  1716 		{
       
  1717 		entry.SetCount(entry.Count() - noOfEntriesRemoved);
       
  1718 		ChangeEntryL(aIndex, entry);
       
  1719 		}
       
  1720 	}
       
  1721 
       
  1722 /*
       
  1723 It stores the forwarded message info in forwarded pdu bit-map.
       
  1724 
       
  1725 @param aIndex index number of the forwarded message.
       
  1726 @param aStartPos starting pos of forwarded pdu.
       
  1727 @param aEndPos end pos of forwarded pdu.
       
  1728 
       
  1729 @internalComponent
       
  1730 */
       
  1731 void CPreallocatedFile::StoreForwardedPDUsInfoL(TInt aIndex, TInt aStartPos, TInt aEndPos)
       
  1732 	{
       
  1733 	TSmsPreAllocatedFileStoreReassemblyEntry entry;
       
  1734 	entry = iEntryArray[aIndex];
       
  1735 
       
  1736 	TUint8 startBitMapIndex = (aStartPos-1)/8;
       
  1737 	TUint8 endBitMapIndex = (aEndPos-1)/8;
       
  1738 	TUint8 startBitPos = (aStartPos-1)%8;
       
  1739 	TUint8 endBitPos = (aEndPos-1)%8;
       
  1740 
       
  1741 	if (startBitMapIndex == endBitMapIndex)
       
  1742 		{
       
  1743 		TUint8 bitMap;
       
  1744 		entry.GetBitMap(startBitMapIndex, bitMap);
       
  1745 		TUint8 tmpBitMap = (0 | 0xFF);
       
  1746 		tmpBitMap <<= ((8 - endBitPos) - 1);
       
  1747 		tmpBitMap >>= (8 - ((endBitPos - startBitPos)+1));
       
  1748 		tmpBitMap <<= startBitPos;
       
  1749 		bitMap |= tmpBitMap;
       
  1750 		entry.SetBitMap(startBitMapIndex, bitMap);
       
  1751 		}
       
  1752 	else
       
  1753 		{
       
  1754 		TUint8 bitMap;
       
  1755 		entry.GetBitMap(startBitMapIndex, bitMap);
       
  1756 		TUint8 tmpBitMap = (0 | 0xFF);
       
  1757 		tmpBitMap >>= (8 - ((7 - startBitPos)+1));
       
  1758 		tmpBitMap <<= startBitPos;
       
  1759 		bitMap |= tmpBitMap;
       
  1760 		entry.SetBitMap(startBitMapIndex, bitMap);
       
  1761 
       
  1762 		entry.GetBitMap(endBitMapIndex, bitMap);
       
  1763 		tmpBitMap = (0 | 0xFF);
       
  1764 		tmpBitMap <<= ((8 - endBitPos) - 1);
       
  1765 		tmpBitMap >>= (8 - ((endBitPos - 0)+1));
       
  1766 		tmpBitMap <<= 0;
       
  1767 		bitMap |= tmpBitMap;
       
  1768 		entry.SetBitMap(endBitMapIndex, bitMap);
       
  1769 		}
       
  1770 
       
  1771 	TInt noOfForwardedPDUs = (aEndPos - aStartPos) + 1;
       
  1772 	entry.SetNumberOfPDUsForwardToClient(entry.NumberOfPDUsForwardToClient()+noOfForwardedPDUs);
       
  1773 
       
  1774 	ChangeEntryL(aIndex, entry);
       
  1775 	}
       
  1776 
       
  1777 /*
       
  1778 It checks the validity of master header section by comparing checksum value.
       
  1779 If the checksum value does not match, then it copies data from duplicate header section to
       
  1780 master header section.
       
  1781 */
       
  1782 void CPreallocatedFile::CheckDataL()
       
  1783 	{
       
  1784 	TUint32 checksum;
       
  1785 	TInt checksumPos = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection;
       
  1786 
       
  1787 	TPtr8 memPtr((TUint8*) &checksum, sizeof(checksum), sizeof(checksum));
       
  1788 	iFile.Read(checksumPos, memPtr);
       
  1789 
       
  1790 	if (ChecksumValue() != checksum)
       
  1791 		{
       
  1792 		CopyDuplicateToMasterL();
       
  1793 		}
       
  1794 	}
       
  1795 
       
  1796 /*
       
  1797 It writes the checksum value & then copies header information from master section to duplicate section.
       
  1798 */
       
  1799 void CPreallocatedFile::PutChecksumValueL()
       
  1800 	{
       
  1801 	TUint32 checksum = ChecksumValue();
       
  1802 	TInt checksumPos = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection;
       
  1803 
       
  1804 	TPtr8 memPtr((TUint8*) &checksum, sizeof(checksum), sizeof(checksum));
       
  1805 	iFile.Write(checksumPos, memPtr);
       
  1806 	iFile.Flush();
       
  1807 	CopyMasterToDuplicateL();
       
  1808 	}
       
  1809 
       
  1810 /*
       
  1811 It calculates & returns the checksum value of master header section.
       
  1812 */
       
  1813 TUint32 CPreallocatedFile::ChecksumValue()
       
  1814 	{
       
  1815 	TInt sizeOfDataToBeChecksum = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection;
       
  1816 
       
  1817 	TUint32 checksum(0);
       
  1818 
       
  1819 	TUint32 tmpValue;
       
  1820 	TPtr8 memPtr((TUint8*) &tmpValue, sizeof(tmpValue), sizeof(tmpValue));
       
  1821 
       
  1822 	for (TInt i = 0; i < sizeOfDataToBeChecksum/4 ; i++)
       
  1823 		{
       
  1824 		iFile.Read(KBeginOfMasterHeaderSection + (i*4), memPtr);
       
  1825 		checksum += tmpValue;
       
  1826 		}
       
  1827 	return 	checksum;
       
  1828 	}
       
  1829 
       
  1830 /*
       
  1831 It copies header information from master copy to duplicate copy.
       
  1832 */
       
  1833 void CPreallocatedFile::CopyMasterToDuplicateL()
       
  1834 	{
       
  1835 	TInt sizeOfDataToBeCopied = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + 4;
       
  1836 
       
  1837 	HBufC8* heapBuffer = HBufC8::NewL(sizeOfDataToBeCopied);
       
  1838 	CleanupStack::PushL(heapBuffer);
       
  1839 	TPtr8 memPtr(heapBuffer->Des());
       
  1840 	iFile.Read(KBeginOfMasterHeaderSection, memPtr);
       
  1841 	iFile.Write(iBeginOfDuplicateHeaderSection, memPtr);
       
  1842 	iFile.Flush();
       
  1843 	CleanupStack::PopAndDestroy(heapBuffer);
       
  1844 	}
       
  1845 
       
  1846 /*
       
  1847 It copies header information from duplicate copy to master copy.
       
  1848 */
       
  1849 void CPreallocatedFile::CopyDuplicateToMasterL()
       
  1850 	{
       
  1851 	TInt sizeOfDataToBeCopied = KSizeOfNumberOfEntrySection + iSizeOfEntrySection + iSizeOfStorageIdentifierSection + 4;
       
  1852 
       
  1853 	HBufC8* heapBuffer = HBufC8::NewL(sizeOfDataToBeCopied);
       
  1854 	CleanupStack::PushL(heapBuffer);
       
  1855 	TPtr8 memPtr(heapBuffer->Des());
       
  1856 	iFile.Read(iBeginOfDuplicateHeaderSection, memPtr);
       
  1857 	iFile.Write(KBeginOfMasterHeaderSection, memPtr);
       
  1858 	iFile.Flush();
       
  1859 	CleanupStack::PopAndDestroy(heapBuffer);
       
  1860 	}
       
  1861 
       
  1862 /*
       
  1863 It returns the total number of PDUs stored in pre-allocated file.
       
  1864 */
       
  1865 TInt CPreallocatedFile::NumberOfPDUStored()
       
  1866 	{
       
  1867 	TInt noOfPDUs = 0;
       
  1868 	for (TInt i = 0; i < iEntryArray.Count(); i++)
       
  1869 		{
       
  1870 		noOfPDUs += iEntryArray[i].Count();
       
  1871 		}
       
  1872 	return noOfPDUs;
       
  1873 	}
       
  1874 
       
  1875 /**
       
  1876  *  Sets the pre-allocated file store as in-transaction.
       
  1877  *  
       
  1878  *  The function checks the validity of the call and leaves KErrAccessDenied if
       
  1879  *  invalid.
       
  1880  *  @capability None
       
  1881  */
       
  1882 void CPreallocatedFile::BeginTransactionL()
       
  1883 	{
       
  1884 	LOGSMSPROT3("CPreallocatedFile::BeginTransactionL [this=0x%08X iInTransaction=%d]", this, iInTransaction);
       
  1885 
       
  1886 	if (iInTransaction)
       
  1887 		{
       
  1888 	    LOGGSMU1("WARNING CPreallocatedFile::BeginTransactionL leaving with KErrAccessDenied");
       
  1889 		User::Leave(KErrAccessDenied);
       
  1890 		}
       
  1891 
       
  1892 	iInTransaction = ETrue;
       
  1893 	}
       
  1894 
       
  1895 /**
       
  1896  *  It commits the transaction.
       
  1897  */
       
  1898 void CPreallocatedFile::CommitTransactionL()
       
  1899 	{
       
  1900 	LOGSMSPROT3("CPreallocatedFile::CommitTransactionL(): this=0x%08X iInTransaction=%d",
       
  1901 				this, iInTransaction);
       
  1902 
       
  1903 	ExternalizeEntryArray();
       
  1904 	//Commit
       
  1905 	PutChecksumValueL();
       
  1906 	iInTransaction = EFalse;
       
  1907 	iReinstateEntryInfo.Reset();
       
  1908 	RemoveDeletedEntries();
       
  1909 	}
       
  1910 
       
  1911 /*
       
  1912 It reverts the transaction.
       
  1913 */
       
  1914 void CPreallocatedFile::Revert()
       
  1915 	{
       
  1916 	LOGSMSPROT3("CPreallocatedFile::Revert(): this=0x%08X, iInTransaction=%d",
       
  1917     		 this, iInTransaction);
       
  1918 
       
  1919 	ReinstateEntries();
       
  1920 	ExternalizeEntryArray();
       
  1921 	iInTransaction = EFalse;
       
  1922 	ReinstateDeletedEntries();
       
  1923 	}
       
  1924 
       
  1925 /**
       
  1926  *  It removes the deleted entries from entry arry.
       
  1927  *	This function is called after commit.
       
  1928  */
       
  1929 void CPreallocatedFile::RemoveDeletedEntries()
       
  1930 	{
       
  1931 	LOGSMSPROT1("CPreallocatedFile::RemoveDeletedEntries()");
       
  1932 
       
  1933 	TInt count=iEntryArray.Count();
       
  1934 	while (count--)
       
  1935 		{
       
  1936 		TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[count];
       
  1937 
       
  1938 		if (entry.IsDeleted())
       
  1939 			{
       
  1940 			iEntryArray.Delete(count);
       
  1941 			}
       
  1942 		else
       
  1943 			{
       
  1944 			entry.SetIsAdded(EFalse);
       
  1945 			}
       
  1946 		}
       
  1947 	} // CPreallocatedFile::RemoveDeletedEntries
       
  1948 
       
  1949 /**
       
  1950  *  It reinstate the deleted/added entries from entry arry.
       
  1951  *	This function is called after revert operation.
       
  1952  */
       
  1953 void CPreallocatedFile::ReinstateDeletedEntries()
       
  1954 	{
       
  1955 	LOGSMSPROT1("CPreallocatedFile::ReinstateDeletedEntries()");
       
  1956 
       
  1957 	TInt count=iEntryArray.Count();
       
  1958 	while (count--)
       
  1959 		{
       
  1960 		TSmsPreAllocatedFileStoreReassemblyEntry& entry = iEntryArray[count];
       
  1961 
       
  1962 		if (entry.IsAdded())
       
  1963 			{
       
  1964 			iEntryArray.Delete(count);
       
  1965 			}
       
  1966 		else
       
  1967 			{
       
  1968 			entry.SetIsDeleted(EFalse);
       
  1969 			}
       
  1970 		}
       
  1971 	} // CPreallocatedFile::ReinstateDeletedEntries
       
  1972 
       
  1973 /**
       
  1974  *  It reinstate the deleted/added entries from the container.
       
  1975  *	This function is called at the time of revert operation.
       
  1976  *	Unlike permanent store file which supports revert. pre-allocated
       
  1977  *	file (raw data file) supports the revert mecahnism using this function.
       
  1978  */
       
  1979 void CPreallocatedFile::ReinstateEntries()
       
  1980 	{
       
  1981 	LOGSMSPROT1("CPreallocatedFile::ReinstateEntries()");
       
  1982 
       
  1983 	TInt containerId;
       
  1984 	TInt storageId;
       
  1985 	TPtr8 memPtr((TUint8*) &storageId, sizeof(storageId), sizeof(storageId));
       
  1986 
       
  1987 	TInt count = iReinstateEntryInfo.Count();
       
  1988 
       
  1989 	for (TInt i=0; i<count; i++)
       
  1990 		{
       
  1991 		if (iReinstateEntryInfo[i].iFlag == EEntryIsDeleted)
       
  1992 			{
       
  1993 			//Add the Pre-allocated storage info in the container.
       
  1994 			storageId = iReinstateEntryInfo[i].iPreAllocatedStorageId;
       
  1995 			containerId = iReinstateEntryInfo[i].iContainerId;
       
  1996 			TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  1997 			iFile.Write( beginOfStorageIdentifierSection + ((containerId - 1) * sizeof(TInt)), memPtr);
       
  1998 			}
       
  1999 		else	//EEntryIsAdded
       
  2000 			{
       
  2001 			//Delete the Pre-allocated storage info from the container.
       
  2002 			storageId = 0;
       
  2003 			containerId = iReinstateEntryInfo[i].iContainerId;
       
  2004 			TInt beginOfStorageIdentifierSection = KBeginOfMasterHeaderSection + KSizeOfNumberOfEntrySection + iSizeOfEntrySection;
       
  2005 			iFile.Write( beginOfStorageIdentifierSection + ((containerId - 1) * sizeof(TInt)), memPtr);
       
  2006 			}
       
  2007 		}
       
  2008 	iFile.Flush();
       
  2009 	iReinstateEntryInfo.Reset();
       
  2010 	}
       
  2011 
       
  2012 /*
       
  2013 It returns the index of oldest message in pre-allocated file.
       
  2014 */
       
  2015 TInt CPreallocatedFile::GetOldestMessageEntryIndex()
       
  2016 	{
       
  2017 	LOGSMSPROT1("CPreallocatedFile::GetOldestMessageEntryIndex()");
       
  2018 
       
  2019 	TInt index = KErrNotFound;
       
  2020 	TTime time;
       
  2021 	time.UniversalTime();
       
  2022 
       
  2023 	for (TInt index2=0; index2 < iEntryArray.Count(); index2++)
       
  2024 		{
       
  2025 		if ((iEntryArray[index2].Time() < time) && (iEntryArray[index2].Count()>0))
       
  2026 			{
       
  2027 			time = iEntryArray[index2].Time();
       
  2028 			index = index2;
       
  2029 			}
       
  2030 		}
       
  2031 	return index;
       
  2032 	}
       
  2033 
       
  2034 /**
       
  2035 Static factory constructor. Uses two phase 
       
  2036 construction and leaves nothing on the CleanupStack.
       
  2037 
       
  2038 @param aClass0ReassemblyStore reference to class 0 reasembly store.
       
  2039 @param aGuardTimeout guard time out in hours.
       
  2040 
       
  2041 @return A pointer to the newly created CGuardTimer object.
       
  2042 
       
  2043 @internalComponent
       
  2044 */
       
  2045 CGuardTimer* CGuardTimer::NewL(CClass0SmsReassemblyStore& aClass0ReassemblyStore, TInt aGuardTimeout)
       
  2046 	{
       
  2047 	LOGSMSPROT1("CGuardTimer::NewL()");
       
  2048 
       
  2049 	CGuardTimer* timer = new(ELeave) CGuardTimer(aClass0ReassemblyStore, aGuardTimeout);
       
  2050 	CleanupStack::PushL(timer);
       
  2051 	timer->ConstructL();
       
  2052 	CleanupStack::Pop();
       
  2053 	return timer;
       
  2054 	} // CGuardTimer::NewL
       
  2055 
       
  2056 /**
       
  2057  *  Constructor
       
  2058  */
       
  2059 CGuardTimer::CGuardTimer(CClass0SmsReassemblyStore& aClass0ReassemblyStore, TInt aGuardTimeout)
       
  2060 	:CTimer(KSmsSessionPriority),
       
  2061 	iClass0ReassemblyStore(aClass0ReassemblyStore),
       
  2062 	iTimeoutInSecs(aGuardTimeout*3600)
       
  2063 	{
       
  2064 	CActiveScheduler::Add(this);
       
  2065 	} //CGuardTimer::CGuardTimer
       
  2066 
       
  2067 /**
       
  2068  *  Destructor
       
  2069  */
       
  2070 CGuardTimer::~CGuardTimer()
       
  2071 	{
       
  2072 	Cancel();
       
  2073 	} // CGuardTimer::~CGuardTimer
       
  2074 
       
  2075 /**
       
  2076  *  Enable the Gurad Timer
       
  2077  */
       
  2078 void CGuardTimer::EnableGuardTimer()
       
  2079 	{
       
  2080 	LOGSMSPROT1("CGuardTimer::EnableGuardTimer()");
       
  2081 	if (!IsActive())
       
  2082 		{
       
  2083 		TTime nextTimeOut;
       
  2084 		iClass0ReassemblyStore.GetNextGuardTimeout(nextTimeOut);
       
  2085 		At(nextTimeOut);
       
  2086 		}
       
  2087 	} //CGuardTimer::EnableGuardTimer
       
  2088 
       
  2089 /**
       
  2090  *  Disable the Gurad Timer
       
  2091  */
       
  2092 void CGuardTimer::DisableGuardTimer()
       
  2093 	{
       
  2094 	Cancel();
       
  2095 	}
       
  2096 
       
  2097 /**
       
  2098  *  Timer completed
       
  2099  */
       
  2100 void CGuardTimer::RunL()
       
  2101 	{
       
  2102 	LOGSMSPROT2("CGuardTimer::RunL [iStatus=%d]", iStatus.Int());
       
  2103 	iClass0ReassemblyStore.ProcessTimeoutMessageL();
       
  2104 	EnableGuardTimer();
       
  2105 	} // CGuardTimer::RunL
       
  2106 
       
  2107 /**
       
  2108 Static factory constructor. Uses two phase 
       
  2109 construction and leaves nothing on the CleanupStack.
       
  2110 
       
  2111 @param aFs  File Server handle.
       
  2112 @param aSmsComm reference to MSmsComm event handler.
       
  2113 
       
  2114 @return A pointer to the newly created CClass0SmsReassemblyStore object.
       
  2115 
       
  2116 @pre A connected file server session must be passed as parameter.
       
  2117 @post CClass0SmsReassemblyStore object is now fully initialised
       
  2118 
       
  2119 @internalComponent
       
  2120 */
       
  2121 CClass0SmsReassemblyStore* CClass0SmsReassemblyStore::NewL(RFs& aFs, MSmsComm& aSmsComm)
       
  2122 	{
       
  2123 	LOGSMSPROT1("CClass0SmsReassemblyStore::NewL()");
       
  2124 
       
  2125 	CClass0SmsReassemblyStore*  self = new (ELeave) CClass0SmsReassemblyStore(aFs, aSmsComm);
       
  2126 	CleanupStack::PushL(self);
       
  2127 	self->ConstructL();
       
  2128 	CleanupStack::Pop(self);
       
  2129 
       
  2130 	return self;
       
  2131 	}
       
  2132 
       
  2133 /**
       
  2134  *  C'tor
       
  2135  */
       
  2136 CClass0SmsReassemblyStore::CClass0SmsReassemblyStore(RFs& aFs, MSmsComm& aSmsComm)
       
  2137 	:CReassemblyStore(aFs), iSmsComm(aSmsComm), iPermanentFileStore(NULL), iPreallocatedFile(NULL),
       
  2138 	iGuardTimer(NULL), iInTransaction(EFalse), iDiskSpaceStatus(ESmsDiskSpaceAvailable)
       
  2139 	{
       
  2140 	}
       
  2141 
       
  2142 /**
       
  2143  *  D'tor
       
  2144  */
       
  2145 CClass0SmsReassemblyStore::~CClass0SmsReassemblyStore()
       
  2146 	{
       
  2147 	delete iPermanentFileStore;
       
  2148 	delete iPreallocatedFile;
       
  2149 	delete iGuardTimer;
       
  2150 	}
       
  2151 
       
  2152 /*
       
  2153 It constructs permanent and pre-allocated file to store the class 0 messages.
       
  2154 It creates a guard timer so that messages can be deleted if all the constituent
       
  2155 PDU of a message is not received within configured time-frame.
       
  2156 It also reserves 4KB disk space so that reserved space can be used to 
       
  2157 delete a stream from permanent file store in out-of-disk condition.
       
  2158 
       
  2159 @internalComponent
       
  2160 */
       
  2161 void CClass0SmsReassemblyStore::ConstructL()
       
  2162 	{
       
  2163 	//Reserve Drive Space
       
  2164 	User::LeaveIfError(iFs.ReserveDriveSpace(KStoreDrive, 4*1024));
       
  2165 
       
  2166 	//Read Configuration file
       
  2167 	ReadConfigurableClass0SmsSettingsL(iMaxClass0Msg, iMaxPDUSeg, iGuardTimeOut);
       
  2168 	//Create Permanent store file
       
  2169 	TFileName permanentStoreFileName;
       
  2170 	CReassemblyStoreUtility::PrivatePath(iFs, permanentStoreFileName);
       
  2171 	permanentStoreFileName.Append(KClass0ReassemblyStoreName);
       
  2172 	iPermanentFileStore = CSmsPermanentFileStore::NewL(iFs, permanentStoreFileName, KClass0ReassemblyStoreUid);
       
  2173 	//Create Pre-allocated file
       
  2174 	TFileName preAllocatedFileName;
       
  2175 	CReassemblyStoreUtility::PrivatePath(iFs, preAllocatedFileName);
       
  2176 	preAllocatedFileName.Append(KPreAllocatedFileName);
       
  2177 	iPreallocatedFile = CPreallocatedFile::NewL(iFs, preAllocatedFileName, iMaxClass0Msg, iMaxPDUSeg);
       
  2178 	//Create Gurad Timer
       
  2179 	iGuardTimer = CGuardTimer::NewL(*this, iGuardTimeOut);
       
  2180 	}
       
  2181 
       
  2182 /*
       
  2183 It reads class 0 re-assembly store configuration information from smswap.sms.esk file. 
       
  2184 It reads the following information: MaxClass0Messages, NumberOfPDUSegements, GuardTimeOut.
       
  2185 If any of the above element is missing it takes the default value.
       
  2186 
       
  2187 @internalComponent
       
  2188 */
       
  2189 void CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL(TInt& aMaxClass0Msg, TInt& aMaxPDUSeg, TInt& aGuardTimeOut)
       
  2190 	{
       
  2191 	LOGSMSPROT1("CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL()");
       
  2192 
       
  2193 	aMaxClass0Msg = KMaxNumberOfClass0MessagesInReassemblyStore;
       
  2194 	aMaxPDUSeg    = KNumberOfPDUSegmentsStoredInOODCondition;
       
  2195 	aGuardTimeOut = KGuardTimeOut;
       
  2196 
       
  2197 	CESockIniData*  ini = NULL;
       
  2198 	TRAPD(ret, ini=CESockIniData::NewL(_L("smswap.sms.esk")));
       
  2199 	if(ret!=KErrNone)
       
  2200 		{
       
  2201 		LOGSMSPROT2("CESockIniData::NewL() returned=%d", ret);
       
  2202 		}
       
  2203 	else
       
  2204 		{
       
  2205 		CleanupStack::PushL(ini);
       
  2206 
       
  2207 		TInt var(0);
       
  2208 		if(ini->FindVar(_L("ReassemblyStore"),_L("MaxClass0Messages"),var))
       
  2209 			{
       
  2210 			if (var > 0)
       
  2211 				{
       
  2212 				LOGSMSPROT2("MaxClass0Messages [%d]", var);
       
  2213 				aMaxClass0Msg = var;
       
  2214 				}
       
  2215 			}
       
  2216 
       
  2217 		if(ini->FindVar(_L("ReassemblyStore"),_L("NumberOfPDUSegements"),var))
       
  2218 			{
       
  2219 			if (var > 0)
       
  2220 				{
       
  2221 				LOGSMSPROT2("MaxClass0Messages [%d]", var);
       
  2222 				aMaxPDUSeg = var;
       
  2223 				}
       
  2224 			}
       
  2225 
       
  2226 		if(ini->FindVar(_L("ReassemblyStore"),_L("GuardTimeOut"),var))
       
  2227 			{
       
  2228 			if (var > 0)
       
  2229 				{
       
  2230 				LOGSMSPROT2("MaxClass0Messages [%d]", var);
       
  2231 				aGuardTimeOut = var;
       
  2232 				}
       
  2233 			}
       
  2234 
       
  2235 		CleanupStack::PopAndDestroy(ini);
       
  2236 		}
       
  2237 
       
  2238 	LOGSMSPROT4("CClass0SmsReassemblyStore::ReadConfigurableClass0SmsSettingsL(): aMaxClass0Msg=%d, aMaxPDUSeg=%d, aGuardTimeOut=%d",
       
  2239 			    aMaxClass0Msg, aMaxPDUSeg, aGuardTimeOut);
       
  2240 	}
       
  2241 
       
  2242 /**
       
  2243 It opens the class 0 re-assembly store.
       
  2244 Then it populates the entry information (all the messages stored in re-assembly store).
       
  2245 
       
  2246 @internalComponent
       
  2247 */
       
  2248 void CClass0SmsReassemblyStore::OpenStoreL()
       
  2249 	{
       
  2250 	LOGSMSPROT1("CClass0SmsReassemblyStore::OpenStoreL()");
       
  2251 	TFileName pathName;
       
  2252 	CReassemblyStoreUtility::PrivatePath(iFs, pathName);
       
  2253 	//Create the directory if it is not created.
       
  2254 	iFs.MkDirAll(pathName);
       
  2255 	// If any one file becomes corrupt or does not exist then we have to create both files.
       
  2256 	if (iPreallocatedFile->IsFileOK() && iPermanentFileStore->IsFileOK())
       
  2257 		{
       
  2258 		iPreallocatedFile->OpenL();
       
  2259 		iPermanentFileStore->OpenL();
       
  2260 		}
       
  2261 	else
       
  2262 		{
       
  2263 		iPreallocatedFile->CreateL();
       
  2264 		iPermanentFileStore->CreateL();
       
  2265 		}
       
  2266 	PopulateEntryArrayL(iEntryArray);
       
  2267 	iGuardTimer->EnableGuardTimer();
       
  2268 	}
       
  2269 
       
  2270 /**
       
  2271 It closes the class 0 re-assembly store.
       
  2272 
       
  2273 @internalComponent
       
  2274 */
       
  2275 void CClass0SmsReassemblyStore::Close()
       
  2276 	{
       
  2277 	LOGSMSPROT1("CClass0SmsReassemblyStore::CloseStore()");
       
  2278 	iGuardTimer->DisableGuardTimer();
       
  2279 	iEntryArray.Reset();
       
  2280 	iPreallocatedFile->Close();
       
  2281 	iPermanentFileStore->Close();
       
  2282 	}
       
  2283 
       
  2284 /**
       
  2285 It populates the entry information stored in class 0 reassembly store.
       
  2286 
       
  2287 @param aEntryArray reference to entry array.
       
  2288 
       
  2289 @internalComponent
       
  2290 */
       
  2291 void CClass0SmsReassemblyStore::PopulateEntryArrayL(CArrayFix<TReassemblyEntry>& aEntryArray)
       
  2292 	{
       
  2293 	LOGSMSPROT1("CClass0SmsReassemblyStore::PopulateEntryArrayL()");
       
  2294 	aEntryArray.Reset();
       
  2295 	//Populate Entries from Pre-allocated file.
       
  2296 	for (TInt count = 0; count < iPreallocatedFile->Entries().Count(); count++)
       
  2297 		{
       
  2298 		TReassemblyEntry entry;
       
  2299 		entry.SetReference(iPreallocatedFile->Entries()[count].Reference());
       
  2300 		entry.SetTotal(iPreallocatedFile->Entries()[count].Total());
       
  2301 		entry.SetCount(iPreallocatedFile->Entries()[count].Count()+iPreallocatedFile->Entries()[count].NumberOfPDUsForwardToClient());
       
  2302 		entry.SetLogServerId(iPreallocatedFile->Entries()[count].LogServerId());
       
  2303  		
       
  2304  		// Check that descriptor2 (sms address )is not corrupted
       
  2305  		TPtrC ptr = iPreallocatedFile->Entries()[count].Description2();
       
  2306 		
       
  2307 		if (ptr.Length() <= CSmsAddress::KSmsAddressMaxAddressLength)
       
  2308 			{
       
  2309  			entry.SetDescription2(iPreallocatedFile->Entries()[count].Description2());
       
  2310  			}
       
  2311 	
       
  2312 		entry.SetPduType(iPreallocatedFile->Entries()[count].PduType());
       
  2313 		entry.SetStorage(iPreallocatedFile->Entries()[count].Storage());
       
  2314 		entry.SetTime(iPreallocatedFile->Entries()[count].Time());
       
  2315 		entry.SetPassedToClient(iPreallocatedFile->Entries()[count].PassedToClient());
       
  2316 		aEntryArray.AppendL(entry);
       
  2317 		}
       
  2318 
       
  2319 	/*
       
  2320 	Then populate the entries from permanent store file. It is needed
       
  2321 	because permanent store file might contain few mesages.
       
  2322 	But before populating the entry information it is needed to cleanup 
       
  2323 	the entries in permanent store file. It is needed to ensure that permanent file
       
  2324 	clean itself with pre-allocated file. There migth be a scenario where 
       
  2325 	user has deleted a message but the corresponding message has not been 
       
  2326 	deleted from permanent store file due to out-of-disk condition. 
       
  2327 	And also at the time of forwarding an incomplete message a forwarded 
       
  2328 	message has not been deleted due to above reason. But the entry/PDU is 
       
  2329 	invalid because it is no more in the pre-allocated file which 
       
  2330 	contains master header info.
       
  2331 	*/
       
  2332 	TInt ret = CleanReassemblyEntries();
       
  2333 
       
  2334 	if (ret == KErrNone)
       
  2335 		{
       
  2336 		/*
       
  2337 		In this case permanent store file contains correct information.
       
  2338 		So populate Entry information from Permanent store file.
       
  2339 		In this case only count information needs to be updated.
       
  2340 		*/
       
  2341 		TInt permanentFileStoreIndex;
       
  2342 		for (TInt i=0; i<aEntryArray.Count(); i++)
       
  2343 			{
       
  2344 			permanentFileStoreIndex=KErrNotFound;
       
  2345 			iPermanentFileStore->MatchEntryToExistingMessage(aEntryArray[i], permanentFileStoreIndex);
       
  2346 			if (permanentFileStoreIndex!=KErrNotFound)
       
  2347 				{
       
  2348 				aEntryArray[i].SetCount(aEntryArray[i].Count() + iPermanentFileStore->Entries()[permanentFileStoreIndex].Count());
       
  2349 				if (aEntryArray[i].Count() > aEntryArray[i].Total())
       
  2350 					{
       
  2351 					aEntryArray[i].SetCount(aEntryArray[i].Total());
       
  2352 					}
       
  2353 				}
       
  2354 			}
       
  2355 		}
       
  2356 	else if (ret == KErrDiskFull)
       
  2357 		{
       
  2358 		LOGSMSPROT1("CleanReassemblyEntries() returns KErrDiskFull");
       
  2359 		/*
       
  2360 		In this case permanent store file contains incorrect information.
       
  2361 		For example forwarded message might be still stored in this store.
       
  2362 		Because it has not been deleted due to out-of-disk condition.
       
  2363 		So be careful at the time of updating the count information
       
  2364 		about the message.
       
  2365 		*/
       
  2366 		TInt permanentFileStoreIndex;
       
  2367 		for (TInt i=0; i<aEntryArray.Count(); i++)
       
  2368 			{
       
  2369 			permanentFileStoreIndex=KErrNotFound;
       
  2370 			iPermanentFileStore->MatchEntryToExistingMessage(aEntryArray[i], permanentFileStoreIndex);
       
  2371 			if (permanentFileStoreIndex!=KErrNotFound)
       
  2372 				{
       
  2373 				TSmsPreAllocatedFileStoreReassemblyEntry entry = iPreallocatedFile->Entries()[i];
       
  2374 				if (entry.NumberOfPDUsForwardToClient() > 0)
       
  2375 					{
       
  2376 					//Internalize the entries.
       
  2377 					CSmsBuffer*  buffer = CSmsBuffer::NewL();
       
  2378 					CSmsMessage*  smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
       
  2379 					CleanupStack::PushL(smsMessage);
       
  2380 
       
  2381 					CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
  2382 					CleanupStack::PushL(indexArray);
       
  2383 					CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2384 					CleanupStack::PushL(smsArray);
       
  2385 					//Internalize to check whether removed PDUs still stored in Permanent store file.
       
  2386 					iPermanentFileStore->InternalizeEntryL(permanentFileStoreIndex, *smsMessage, *indexArray, *smsArray);
       
  2387 					TInt noOfForwardedEntries=0;
       
  2388 					for (TInt j=0; j<indexArray->Count() ;j++)
       
  2389 						{
       
  2390 						TUint8 bitMapIndex = (indexArray->At(j)-1)/8;
       
  2391 						TUint8 bitPos = (indexArray->At(j)-1)%8;
       
  2392 						TUint8 bitMap;
       
  2393 						entry.GetBitMap(bitMapIndex, bitMap);
       
  2394 						TUint8 tmpBitMap = 1;
       
  2395 						tmpBitMap <<= bitPos;
       
  2396 						if (tmpBitMap == (bitMap & tmpBitMap))
       
  2397 							{
       
  2398 							noOfForwardedEntries++;
       
  2399 							}
       
  2400 						}
       
  2401 					TInt count = iPermanentFileStore->Entries()[permanentFileStoreIndex].Count() - noOfForwardedEntries;
       
  2402 					aEntryArray[i].SetCount(aEntryArray[i].Count() + count);
       
  2403 
       
  2404 					CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray
       
  2405 					}
       
  2406 				else
       
  2407 					{
       
  2408 					aEntryArray[i].SetCount(aEntryArray[i].Count() + iPermanentFileStore->Entries()[permanentFileStoreIndex].Count());
       
  2409 					}
       
  2410 				}
       
  2411 			}
       
  2412 		}
       
  2413 	else
       
  2414 		{
       
  2415 		User::Leave(ret);
       
  2416 		}
       
  2417 	}
       
  2418 
       
  2419 /**
       
  2420 It sets the disk space status.
       
  2421 If disk space is full, then class 0 re-assembly store stores the incoming message in
       
  2422 pre-allocated file. Otherwise it stores the message in permanent store file.
       
  2423 */
       
  2424 void CClass0SmsReassemblyStore::SetDiskSpaceState(TSmsDiskSpaceMonitorStatus aDiskSpaceStatus)
       
  2425 	{
       
  2426 	LOGSMSPROT1("CClass0SmsReassemblyStore::SetDiskSpaceState()");
       
  2427 	iDiskSpaceStatus = aDiskSpaceStatus;
       
  2428 	}
       
  2429 
       
  2430 /*
       
  2431 It adds the new message in class 0 reassembly store.
       
  2432 It first tries to add the message in permanent store file. If it is
       
  2433 successful, then it adds the entry information in pre-allocated file.
       
  2434 Because pre-allocated file contains master header entry information.
       
  2435 Otherwise (if disk space is full), it adds the message in pre-allocated file.
       
  2436 
       
  2437 @param aSmsMessage reference to sms message to be added.
       
  2438 @param aGsmSms reference to GsmSms object to be added.
       
  2439 
       
  2440 @internalComponent
       
  2441 */
       
  2442 void CClass0SmsReassemblyStore::AddNewMessageL(CSmsMessage& aSmsMessage,const TGsmSms& aGsmSms)
       
  2443 	{
       
  2444 	LOGSMSPROT1("CClass0SmsReassemblyStore::AddNewMessageL");
       
  2445 
       
  2446 	// Add entry in permanent store file
       
  2447 	TInt index;
       
  2448 	TInt ret = KErrNone;
       
  2449 
       
  2450 	if (iDiskSpaceStatus == ESmsDiskSpaceFull)
       
  2451 		{
       
  2452 		ret = KErrDiskFull;
       
  2453 		}
       
  2454 	else
       
  2455 		{
       
  2456 		TRAP(ret, iPermanentFileStore->AddNewMessageL(index, aSmsMessage, aGsmSms));
       
  2457 		}
       
  2458 
       
  2459 	if (ret == KErrNone)
       
  2460 		{
       
  2461 		// Add a new entry in pre-allocated file
       
  2462 		TSmsPreAllocatedFileStoreReassemblyEntry tmpEntry;
       
  2463 		//Fill-up entry information...
       
  2464 		CReassemblyStoreUtility::PopulateEntry(tmpEntry, aSmsMessage, 1);
       
  2465 
       
  2466 		//The properties below need to be set only once when a PDU of a new message arrives.
       
  2467 		tmpEntry.SetStatus((RMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status());
       
  2468 		tmpEntry.SetUTCOffset(aSmsMessage.UTCOffset());
       
  2469 		tmpEntry.SetDecodedOnSIM(aSmsMessage.DecodedOnSim());
       
  2470 		tmpEntry.SetForwardToClient(aSmsMessage.ForwardToClient());
       
  2471 		//Set KErrNotFound because message corresponding to 
       
  2472 		//this entry is not in this pr-allocated file.
       
  2473 		tmpEntry.SetPreAllocatedStorageId(KErrNotFound);
       
  2474 		//Has to set 0 because PDU is stored in Permanent store file instead of pre-allocated file.
       
  2475 		tmpEntry.SetCount(0);
       
  2476 
       
  2477 		iPreallocatedFile->AddEntryL(tmpEntry);
       
  2478 		}
       
  2479 	else if (ret == KErrDiskFull)
       
  2480 		{
       
  2481 		// Add the new message in pre-allocated file
       
  2482 		iPreallocatedFile->AddNewMessageL(index, aSmsMessage, aGsmSms);
       
  2483 		}
       
  2484 	else
       
  2485 		{
       
  2486 		User::Leave(ret);
       
  2487 		}
       
  2488 	}
       
  2489 
       
  2490 /*
       
  2491 It updates the existing message in class 0 re-assembly store.
       
  2492 
       
  2493 @param aSmsMessage reference to sms message to be updated.
       
  2494 @param aGsmSms reference to GsmSms object to be added.
       
  2495 @param aDuplicateMsgRef boolean value (output) indicates whether the added PDU is a duplicate or not.
       
  2496 @param aDuplicateSlot boolean value (output) indicates whether the added PDU is a duplicate enumerated PDU.
       
  2497 
       
  2498 @internalComponent
       
  2499 */
       
  2500 void CClass0SmsReassemblyStore::UpdateExistingMessageL(CSmsMessage& aSmsMessage, const TGsmSms& aGsmSms, TBool& aDuplicateMsgRef, TBool& aDuplicateSlot)
       
  2501 	{
       
  2502 	LOGSMSPROT1("CClass0SmsReassemblyStore::UpdateExistingMessageL()");
       
  2503 
       
  2504 	aDuplicateMsgRef = EFalse;
       
  2505 	aDuplicateSlot   = EFalse;
       
  2506 
       
  2507 	CSmsBuffer*  buffer = CSmsBuffer::NewL();
       
  2508 	CSmsMessage*  smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer);
       
  2509 	CleanupStack::PushL(smsMessage);
       
  2510 
       
  2511 	CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
  2512 	CleanupStack::PushL(indexArray);
       
  2513 	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2514 	CleanupStack::PushL(smsArray);
       
  2515 
       
  2516 	//Internalize stored message in permanent store file
       
  2517 	TReassemblyEntry entry;
       
  2518 	CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, 1);
       
  2519 	TInt permanentStoreIndex;
       
  2520 	iPermanentFileStore->MatchEntryToExistingMessage(entry, permanentStoreIndex);
       
  2521 	if (permanentStoreIndex!=KErrNotFound)
       
  2522 		{
       
  2523 		iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, *smsMessage, *indexArray, *smsArray);
       
  2524 		}
       
  2525 
       
  2526 	//Internalize stored message in pre-allocated file
       
  2527 	TInt preAllocatedFileIndex;
       
  2528 	iPreallocatedFile->MatchEntryToExistingMessage(entry, preAllocatedFileIndex);
       
  2529 	if (preAllocatedFileIndex!=KErrNotFound)
       
  2530 		{
       
  2531 		iPreallocatedFile->InternalizeEntryL(preAllocatedFileIndex, *smsMessage, *indexArray, *smsArray);
       
  2532 		}
       
  2533 	else
       
  2534 		{
       
  2535 		//This condition should never arise
       
  2536 		User::Leave(KErrNotFound);
       
  2537 		}
       
  2538 
       
  2539 	//
       
  2540 	// Check if this is a duplicated enumerated PDU (e.g. on the SIM or phone memory)
       
  2541 	// or a duplicated PDU (e.g. in the Reassembly Store)...
       
  2542 	//
       
  2543 	TInt  concatPDUIndex = aSmsMessage.SmsPDU().ConcatenatedMessagePDUIndex();
       
  2544 
       
  2545 	if (smsMessage->Storage() == CSmsMessage::ESmsSIMStorage  ||
       
  2546 		smsMessage->Storage() == CSmsMessage::ESmsCombinedStorage)
       
  2547 		{
       
  2548 		//
       
  2549 		// In most cases this PDU is being enumerated, but not always. It is
       
  2550 		// possible for the PDU to be stored on the SIM first before it is
       
  2551 		// received.
       
  2552 		//
       
  2553 		const TGsmSmsSlotEntry&  newSlot = aSmsMessage.iSlotArray[0];
       
  2554 		TInt  slotArrayCount = smsMessage->iSlotArray.Count();
       
  2555 
       
  2556 		for (TInt slotNum = 0;  slotNum < slotArrayCount;  slotNum++ )
       
  2557 			{
       
  2558 			const TGsmSmsSlotEntry&  slot = smsMessage->iSlotArray[slotNum];
       
  2559 
       
  2560 			if (slot.iIndex == newSlot.iIndex  && slot.iStore == newSlot.iStore)
       
  2561 				{
       
  2562 				LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate enumerated PDU.");
       
  2563 
       
  2564 				// It is a duplicate that was already stored on the SIM...
       
  2565 				aDuplicateSlot = ETrue;
       
  2566 				break;
       
  2567 				}
       
  2568 			}
       
  2569 		}
       
  2570 
       
  2571 	TInt  indexArrayCount = indexArray->Count();
       
  2572 
       
  2573 	for (TInt index = 0;  index < indexArrayCount;  index++ )
       
  2574 		{
       
  2575 		if (indexArray->At(index) == concatPDUIndex)
       
  2576 			{
       
  2577 			LOGSMSPROT1("CSmsReassemblyStore::UpdateExistingMessageL(): Duplicate concatenated PDU.");
       
  2578 
       
  2579 			// The PDU is already stored in the reassembly store.
       
  2580 			aDuplicateMsgRef = ETrue;
       
  2581 			break;
       
  2582 			}
       
  2583 		}
       
  2584 
       
  2585 	//Check whether this PDU is part of forwarded PDU.
       
  2586 	TSmsPreAllocatedFileStoreReassemblyEntry preAllocatedFileEntry = iPreallocatedFile->Entries()[preAllocatedFileIndex];
       
  2587 	if (preAllocatedFileEntry.NumberOfPDUsForwardToClient() > 0)
       
  2588 		{
       
  2589 		TUint8 bitMapIndex = (concatPDUIndex-1)/8;
       
  2590 		TUint8 bitPos = (concatPDUIndex-1)%8;
       
  2591 		TUint8 bitMap;
       
  2592 		preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap);
       
  2593 		TUint8 tmpBitMap = 1;
       
  2594 		tmpBitMap <<= bitPos;
       
  2595 		if (tmpBitMap == (bitMap & tmpBitMap))
       
  2596 			{
       
  2597 			aDuplicateMsgRef = ETrue;
       
  2598 			}		
       
  2599 		}
       
  2600 
       
  2601 	if (aDuplicateMsgRef  ||  aDuplicateSlot)
       
  2602 		{
       
  2603 		CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, smsArray, indexArray
       
  2604 		return;
       
  2605 		}
       
  2606 
       
  2607 	//
       
  2608 	// If the PDU is stored then add the slot information...
       
  2609 	//
       
  2610 	if (aSmsMessage.Storage() == CSmsMessage::ESmsSIMStorage  ||
       
  2611 		aSmsMessage.Storage() == CSmsMessage::ESmsCombinedStorage)
       
  2612 		{
       
  2613 		smsMessage->AddSlotL(aSmsMessage.iSlotArray[0]);
       
  2614 		}
       
  2615 
       
  2616 	//
       
  2617 	// If the PDU is Unsent or Unread, then store that information...
       
  2618 	//
       
  2619 	NMobileSmsStore::TMobileSmsStoreStatus  status = aSmsMessage.Status();
       
  2620 
       
  2621 	if (status == NMobileSmsStore::EStoredMessageUnsent  ||
       
  2622 		status == NMobileSmsStore::EStoredMessageUnread)
       
  2623 		{
       
  2624 		smsMessage->SetStatus(status);
       
  2625 		}
       
  2626 
       
  2627 	/*
       
  2628 	Below logic is written in keeping view of different scenarios that might occur here:
       
  2629 	(1) Previous PDUs are in Permanent store file, this PDU arrives in out-of-disk condition (so will be stored in Pre-allocated file).
       
  2630 	(2) Previous PDUs are in Pre-allocated file (means PDU arrives in out-of-disk condition), this PDU arrives in normal condition.
       
  2631 	(3) Previous PDUs are in Permanent store file, this PDU also arrives in normal condition.
       
  2632 	(4) Previous PDUs are in Pre-allocated file (means PDU arrives in out-of-disk condition), this PDU also arrives in out-of-disk condition.
       
  2633 	*/
       
  2634 
       
  2635 	//Always first try to store the message in permanent store file.
       
  2636 	//In case of out-of-disk condition store the message in pre-allocated file
       
  2637 	TInt ret = KErrNone;
       
  2638 	if (iDiskSpaceStatus == ESmsDiskSpaceFull)
       
  2639 		{
       
  2640 		ret = KErrDiskFull;
       
  2641 		}
       
  2642 	else
       
  2643 		{
       
  2644 		if (permanentStoreIndex==KErrNotFound)
       
  2645 			{
       
  2646 			// See condition (2)
       
  2647 			TInt tmpIndex;
       
  2648 			TRAP(ret, iPermanentFileStore->AddNewMessageL(tmpIndex, aSmsMessage, aGsmSms));
       
  2649 			}
       
  2650 		else
       
  2651 			{
       
  2652 			CSmsBuffer*  tmpBuffer = CSmsBuffer::NewL();
       
  2653 			CSmsMessage*  tmpSmsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, tmpBuffer);
       
  2654 			CleanupStack::PushL(tmpSmsMessage);
       
  2655 
       
  2656 			indexArray->Reset();
       
  2657 			smsArray->Reset();
       
  2658 			iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, *tmpSmsMessage, *indexArray, *smsArray);
       
  2659 			/*
       
  2660 			Check & remove those PDU from permanent store file which has already been 
       
  2661 			forwarded to client. Forwarded PDU might still remain in permanent store 
       
  2662 			file if it is deleted at the time of out-of-disk condition.
       
  2663 			*/
       
  2664 			if (preAllocatedFileEntry.NumberOfPDUsForwardToClient()>0)
       
  2665 				{
       
  2666 				for (TInt j=indexArray->Count(); j>0 ;j--)
       
  2667 					{
       
  2668 					TUint8 bitMapIndex = (indexArray->At(j-1)-1)/8;
       
  2669 					TUint8 bitPos = (indexArray->At(j-1)-1)%8;
       
  2670 					TUint8 bitMap;
       
  2671 					preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap);
       
  2672 					TUint8 tmpBitMap = 1;
       
  2673 					tmpBitMap <<= bitPos;
       
  2674 					if (tmpBitMap == (bitMap & tmpBitMap))
       
  2675 						{
       
  2676 						indexArray->Delete(j-1);
       
  2677 						smsArray->Delete(j-1);
       
  2678 						}
       
  2679 					}
       
  2680 				}
       
  2681 
       
  2682 			indexArray->AppendL(concatPDUIndex);
       
  2683 			smsArray->AppendL(aGsmSms);
       
  2684 
       
  2685 			TRAP(ret, iPermanentFileStore->UpdateExistingMessageL(permanentStoreIndex, *smsMessage, *indexArray, *smsArray));
       
  2686 
       
  2687 			CleanupStack::PopAndDestroy(1); //tmpSmsMessage
       
  2688 			}
       
  2689 		}
       
  2690 
       
  2691 	if (ret == KErrDiskFull)
       
  2692 		{
       
  2693 		iPreallocatedFile->UpdateExistingMessageL(preAllocatedFileIndex, aSmsMessage, concatPDUIndex, aGsmSms);
       
  2694 		}
       
  2695 	else if (ret!=KErrNone)
       
  2696 		{
       
  2697 		User::Leave(ret);
       
  2698 		}
       
  2699 
       
  2700 	CleanupStack::PopAndDestroy(3, smsMessage); // smsMessage, indexArray, smsArray
       
  2701 	}
       
  2702 
       
  2703 /*
       
  2704 It retrieves class 0 message from re-assembly store.
       
  2705 The message which match the passed entry information is returned from this function.
       
  2706 
       
  2707 @param aEntry reference to entry information.
       
  2708 @param aSmsMessage reference to returned sms message.
       
  2709 
       
  2710 @internalComponent
       
  2711 */
       
  2712 void CClass0SmsReassemblyStore::RetrieveMessageL(const TReassemblyEntry& aEntry, CSmsMessage& aSmsMessage)
       
  2713 	{
       
  2714 	CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
  2715 	CleanupStack::PushL(indexArray);
       
  2716 	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2717 	CleanupStack::PushL(smsArray);
       
  2718 
       
  2719 	GetSmsEntriesL(aEntry, aSmsMessage, *indexArray, *smsArray);
       
  2720 
       
  2721 	//There is no need to decode a single segment message
       
  2722 	if (aEntry.Total()>1)
       
  2723 		{
       
  2724 		if (smsArray->Count() == aEntry.Total())
       
  2725 			{
       
  2726 			aSmsMessage.DecodeMessagePDUsL(*smsArray);
       
  2727 			}
       
  2728 		}
       
  2729 	CleanupStack::PopAndDestroy(2, indexArray); //smsArray, indexArray
       
  2730 	}
       
  2731 
       
  2732 /*
       
  2733 It deletes the entry from re-assembly store.
       
  2734 
       
  2735 @param aEntry reference to entry information.
       
  2736 
       
  2737 @internalComponent
       
  2738 */
       
  2739 void CClass0SmsReassemblyStore::DeleteEntryL(const TReassemblyEntry& aEntry)
       
  2740 	{
       
  2741 	TInt index;
       
  2742 	iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index);
       
  2743 	if (index == KErrNotFound)
       
  2744 		{
       
  2745 		//This condition should never arise
       
  2746 		User::Leave(KErrNotFound);
       
  2747 		}
       
  2748 	iPreallocatedFile->DeleteEntryL(index);
       
  2749 	iPermanentFileStore->MatchEntryToExistingMessage(aEntry, index);
       
  2750 	if (index != KErrNotFound)
       
  2751 		{
       
  2752 		TRAP_IGNORE(iPermanentFileStore->DeleteEntryL(index));
       
  2753 		}
       
  2754 	}
       
  2755 
       
  2756 /*
       
  2757 It updates the log server id of the passed entry (message).
       
  2758 
       
  2759 @param aEntry reference to entry information.
       
  2760 @param aLogId log id of the message to be updated.
       
  2761 
       
  2762 @internalComponent
       
  2763 */
       
  2764 void CClass0SmsReassemblyStore::UpdateLogServerIdL(const TReassemblyEntry& aEntry, TLogId aLogServerId)
       
  2765 	{
       
  2766 	TInt index;
       
  2767 	iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index);
       
  2768 	if (index == KErrNotFound)
       
  2769 		{
       
  2770 		//This condition should never arise
       
  2771 		User::Leave(KErrNotFound);
       
  2772 		}
       
  2773 	iPreallocatedFile->UpdateLogServerIdL(index, aLogServerId);
       
  2774 	}
       
  2775 
       
  2776 /*
       
  2777 It sets the message passed to client or not. The message, which match the 
       
  2778 passed entry information, its passed to client value is set.
       
  2779 
       
  2780 @param aEntry reference to entry information.
       
  2781 @param aBool boolean value indicating whether message is passed or not.
       
  2782 
       
  2783 @internalComponent
       
  2784 */
       
  2785 void CClass0SmsReassemblyStore::SetPassedToClientL(const TReassemblyEntry& aEntry, TBool aBool)
       
  2786 	{
       
  2787 	TInt index;
       
  2788 	iPreallocatedFile->MatchEntryToExistingMessage(aEntry, index);
       
  2789 	if (index == KErrNotFound)
       
  2790 		{
       
  2791 		//This condition should never arise
       
  2792 		User::Leave(KErrNotFound);
       
  2793 		}
       
  2794 	iPreallocatedFile->SetPassedToClientL(index, aBool);
       
  2795 	}
       
  2796 
       
  2797 /**
       
  2798 It forwards the complete class 0 messages to client.
       
  2799 It checks whether the received object is complete or not.
       
  2800 If it is complete, then it forwards the complete message to client.
       
  2801 Otherwise it forms the message & forward the message to client.
       
  2802 In this it might be possible to forward multiple incomplete message.
       
  2803 
       
  2804 @param aSmsComm  a reference to aSmsComm object which implemented the events.
       
  2805 
       
  2806 @param aSmsMessage	a reference to sms message object. This sms message must be class 0 messages.
       
  2807 
       
  2808 @param aOriginalSmsAddr pointer to the address of the sender of a previously sent
       
  2809 
       
  2810 @param aOriginalSmsMessage pointer to a message previously sent matched to the received 
       
  2811 							one (e.g. status report).	Null if not matched.
       
  2812 
       
  2813 @param aDes user data for the deliver report acknowledging this message to the SC.
       
  2814 			Filled in by the observer.
       
  2815 
       
  2816 @internalComponent
       
  2817 */
       
  2818 void CClass0SmsReassemblyStore::ForwardCompleteClass0SmsMessagesL(MSmsComm& aSmsComm, const CSmsMessage& aSmsMessage,const TSmsAddr* aOriginalSmsAddr,const CSmsMessage* aOriginalSmsMessage,TDes& aDes)
       
  2819 	{
       
  2820 	TBool passedToClient=ETrue;
       
  2821 
       
  2822 	if (aSmsMessage.IsComplete())
       
  2823 		{
       
  2824 		//Message is complete so forward it.
       
  2825 		TInt ret = aSmsComm.ProcessMessageL(aSmsMessage, aOriginalSmsAddr, aOriginalSmsMessage, aDes);
       
  2826 		if (ret!=KErrNone)
       
  2827 			{
       
  2828 			passedToClient = EFalse;
       
  2829 			}
       
  2830 		}
       
  2831 	else
       
  2832 		{
       
  2833 		/*
       
  2834 		Message is not complete, but re-assembly store contains other constituent PDU
       
  2835 		of the message which makes the message complete.
       
  2836 
       
  2837 		In case of class 0 messages, it is possible to forward the incomplete messages. So after forwarding
       
  2838 		the incomplete message, if we receive other constituent PDU of that message then in that case we 
       
  2839 		might receive all the constituent PDU of that message but aSmsMesssage will contain partial complete message.
       
  2840 		*/
       
  2841 		TReassemblyEntry entry;
       
  2842 		CReassemblyStoreUtility::PopulateEntry(entry, aSmsMessage, 1);
       
  2843 
       
  2844 		CSmsBuffer* buffer = CSmsBuffer::NewL();
       
  2845 		CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer );
       
  2846 		CleanupStack::PushL( smsMessage );
       
  2847 
       
  2848 		CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
  2849 		CleanupStack::PushL(indexArray);
       
  2850 		CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2851 		CleanupStack::PushL(smsArray);
       
  2852 
       
  2853 		GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray);
       
  2854 		SortPDUsL(*indexArray, *smsArray);
       
  2855 
       
  2856 		CArrayFixFlat<TGsmSms>*  tmpSmsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2857 		CleanupStack::PushL(tmpSmsArray);
       
  2858 
       
  2859 		//Form the sequence of incomplete message & forward it to client.
       
  2860 		TInt startSeqIndex(0), endSeqIndex(0);
       
  2861 		TInt i;
       
  2862 		do
       
  2863 			{
       
  2864 			i = startSeqIndex;
       
  2865 			for (; i < indexArray->Count() - 1; i++)
       
  2866 				{
       
  2867 				if (indexArray->At(i) + 1 != indexArray->At(i+1))
       
  2868 					{
       
  2869 					endSeqIndex = i;
       
  2870 					break;
       
  2871 					}
       
  2872 				}
       
  2873 
       
  2874 			if (i == (indexArray->Count() - 1))
       
  2875 				{
       
  2876 				endSeqIndex = i;
       
  2877 				}
       
  2878 
       
  2879 			tmpSmsArray->Reset();
       
  2880 			for (TInt j = startSeqIndex; j <= endSeqIndex; j++)
       
  2881 				{
       
  2882 				tmpSmsArray->AppendL(smsArray->At(j));
       
  2883 				}
       
  2884 
       
  2885 			if (tmpSmsArray->Count() == entry.Total())
       
  2886 				{
       
  2887 				smsMessage->DecodeMessagePDUsL(*tmpSmsArray);
       
  2888 				}
       
  2889 			else
       
  2890 				{
       
  2891 				//Build the partial complete message.
       
  2892 				if (endSeqIndex == (indexArray->Count() - 1))
       
  2893 					{
       
  2894 					smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue);
       
  2895 					}
       
  2896 				else
       
  2897 					{
       
  2898 					smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse);
       
  2899 					}
       
  2900 				}
       
  2901 
       
  2902 			//Forward the partial complete message to client.
       
  2903 			TInt ret=KErrNone;
       
  2904 			TRAP(ret, aSmsComm.ProcessMessageL(*smsMessage, aOriginalSmsAddr, aOriginalSmsMessage, aDes));
       
  2905 			if (ret != KErrNone)
       
  2906 				{
       
  2907 				passedToClient = EFalse;
       
  2908 				}
       
  2909 			startSeqIndex = endSeqIndex + 1;
       
  2910 			endSeqIndex = startSeqIndex;
       
  2911 			}
       
  2912 		while (startSeqIndex < indexArray->Count());
       
  2913 
       
  2914 		CleanupStack::PopAndDestroy(4);	//tmpSmsArray, indexArray, smsArray, smsMessage
       
  2915 		}
       
  2916 
       
  2917 	if(passedToClient)
       
  2918 		{
       
  2919 		SetMessagePassedToClientL(aSmsMessage);
       
  2920 		}
       
  2921 
       
  2922 	//If the latest segement exceeds the limitation, then we can't wait till ack.
       
  2923 	//So call ProcessMessageIfExceedLimitationL() function & delete the oldest message.
       
  2924 	if (IsExceedLimitation())
       
  2925 		{
       
  2926 		ProcessMessageIfExceedLimitationL(aSmsComm);
       
  2927 		}
       
  2928 	}
       
  2929 
       
  2930 /**
       
  2931 It frees the space by forwarding the class 0 message if class 0 re-assembly store 
       
  2932 exceeds limitation (max class 0 message, max reserved pdu segment).
       
  2933 
       
  2934 @param aSmsComm  a reference to aSmsComm object which implemented the events.
       
  2935 
       
  2936 @internalComponent
       
  2937 */
       
  2938 void CClass0SmsReassemblyStore::ProcessMessageIfExceedLimitationL(MSmsComm& aSmsComm)
       
  2939 	{
       
  2940 	//Add Comment
       
  2941 	TInt class0MsgCount = iEntryArray.Count();
       
  2942 	TInt noOfMsgStoredInPreAllocatedFile = iPreallocatedFile->NumberOfPDUStored();
       
  2943 	if ((class0MsgCount > iMaxClass0Msg)
       
  2944 			|| (noOfMsgStoredInPreAllocatedFile >= iMaxPDUSeg))
       
  2945 		{
       
  2946 		CSmsBuffer* buffer = CSmsBuffer::NewL();
       
  2947 		CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer );
       
  2948 		CleanupStack::PushL( smsMessage );
       
  2949 
       
  2950 		CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
  2951 		CleanupStack::PushL(indexArray);
       
  2952 		CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2953 		CleanupStack::PushL(smsArray);
       
  2954 
       
  2955 		//Add Comment
       
  2956 		TInt index;
       
  2957 		if (class0MsgCount > iMaxClass0Msg)
       
  2958 			{
       
  2959 			index = GetIndexOfOldestMessage();
       
  2960 			}
       
  2961 		else
       
  2962 			{
       
  2963 			index = GetIndexOfOldestMessageFromReservedFileL();
       
  2964 			}
       
  2965 
       
  2966 		TReassemblyEntry entry = iEntryArray[index];
       
  2967 
       
  2968 		GetSmsEntriesL(entry, *smsMessage, *indexArray, *smsArray);
       
  2969 
       
  2970 		SortPDUsL(*indexArray, *smsArray);
       
  2971 
       
  2972 		CArrayFixFlat<TGsmSms>*  tmpSmsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  2973 		CleanupStack::PushL(tmpSmsArray);
       
  2974 
       
  2975 		//Form the message & forward it to client.
       
  2976 		TInt startSeqIndex(0), endSeqIndex(0);
       
  2977 		TInt i;
       
  2978 		do
       
  2979 			{
       
  2980 			i = startSeqIndex;
       
  2981 			for (; i < indexArray->Count() - 1; i++)
       
  2982 				{
       
  2983 				if (indexArray->At(i) + 1 != indexArray->At(i+1))
       
  2984 					{
       
  2985 					endSeqIndex = i;
       
  2986 					break;
       
  2987 					}
       
  2988 				}
       
  2989 			if (i == (indexArray->Count() - 1))
       
  2990 				{
       
  2991 				endSeqIndex = i;
       
  2992 				}
       
  2993 			tmpSmsArray->Reset();
       
  2994 
       
  2995 			for (TInt j = startSeqIndex; j <= endSeqIndex; j++)
       
  2996 				{
       
  2997 				tmpSmsArray->AppendL(smsArray->At(j));
       
  2998 				}
       
  2999 
       
  3000 			if (entry.IsComplete())
       
  3001 				{
       
  3002 				if (tmpSmsArray->Count() == entry.Total())
       
  3003 					{
       
  3004 					smsMessage->DecodeMessagePDUsL(*tmpSmsArray);
       
  3005 					}
       
  3006 				else
       
  3007 					{
       
  3008 					//Build the partial complete message.
       
  3009 					if (endSeqIndex == (indexArray->Count() - 1))
       
  3010 						{
       
  3011 						smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue);
       
  3012 						}
       
  3013 					else
       
  3014 						{
       
  3015 						smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse);
       
  3016 						}
       
  3017 					}
       
  3018 				}
       
  3019 			else
       
  3020 				{
       
  3021 				//Build the partial complete message.
       
  3022 				smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse);
       
  3023 				}
       
  3024 			//Forward the partial complete message to client.
       
  3025 			TBuf16<CSmsPDUProcessor::ESmsMaxDeliverReportBufferSize> buffer;
       
  3026 			TRAP_IGNORE(aSmsComm.ProcessMessageL(*smsMessage, NULL, NULL, buffer));
       
  3027 
       
  3028 			/*
       
  3029 			Can't do much. So free the reserved space & also stored the information 
       
  3030 			related to forwarded message. If the message is complete then delete
       
  3031 			the complete message (see the condition after the while loop)rather 
       
  3032 			than freeing the memory. No need to store the complete messages forwaded 
       
  3033 			info.
       
  3034 			*/
       
  3035 			if ((noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg) && (!entry.IsComplete()))
       
  3036 				{
       
  3037 				SetIncompleteMessageForwardedToClientL(*smsMessage);
       
  3038 				}
       
  3039 			startSeqIndex = endSeqIndex + 1;
       
  3040 			endSeqIndex = startSeqIndex;
       
  3041 			}
       
  3042 		while (startSeqIndex < indexArray->Count());
       
  3043 		//Can't do much. So removed the oldest message.
       
  3044 		if ((class0MsgCount > iMaxClass0Msg) ||
       
  3045 			((noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg) && (entry.IsComplete())))
       
  3046 			{
       
  3047 			DeleteMessageL(*smsMessage, EFalse);
       
  3048 			}
       
  3049 		CleanupStack::PopAndDestroy(4);	//tmpSmsArray, indexArray, smsArray, smsMessage
       
  3050 		}
       
  3051 	}
       
  3052 
       
  3053 /**
       
  3054 Guard timer calls this function when timer expires.
       
  3055 It goes through all the messages stored in re-assembly store & forwards those message
       
  3056 whose time has expired.
       
  3057 It is also called when a new observer is added or a PDU has been received and successfully 
       
  3058 processed. It is also called from ProcessCompleteClass0SmsMessagesL.
       
  3059 
       
  3060 @internalComponent
       
  3061 */
       
  3062 void CClass0SmsReassemblyStore::ProcessTimeoutMessageL()
       
  3063 	{
       
  3064 	LOGSMSPROT1("CClass0SmsReassemblyStore::ProcessTimeoutMessageL()");
       
  3065 	TBool passedToClient=ETrue;
       
  3066 	TInt count=iEntryArray.Count();
       
  3067 
       
  3068 	CSmsBuffer* buffer = CSmsBuffer::NewL();
       
  3069 	CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, CSmsPDU::ESmsDeliver, buffer );
       
  3070 	CleanupStack::PushL( smsMessage );
       
  3071 
       
  3072 	CArrayFix<TInt>*  indexArray = new(ELeave) CArrayFixFlat<TInt>(KFlatArrayGranularity);
       
  3073 	CleanupStack::PushL(indexArray);
       
  3074 	CArrayFixFlat<TGsmSms>*  smsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  3075 	CleanupStack::PushL(smsArray);
       
  3076 
       
  3077 	CArrayFixFlat<TGsmSms>*  tmpSmsArray = new(ELeave) CArrayFixFlat<TGsmSms>(KFlatArrayGranularity);
       
  3078 	CleanupStack::PushL(tmpSmsArray);
       
  3079 
       
  3080 	TTime time;
       
  3081 	time.UniversalTime();
       
  3082 
       
  3083 	TTimeIntervalSeconds timeOutInSecs = iGuardTimeOut*3600;
       
  3084 
       
  3085 	for (TInt k=count-1; k>=0; k--)
       
  3086 		{
       
  3087 		if (!iEntryArray[k].PassedToClient())
       
  3088 			{
       
  3089 			TTimeIntervalSeconds diffInSecs;
       
  3090 			time.SecondsFrom(iEntryArray[k].Time(), diffInSecs);
       
  3091 			indexArray->Reset();
       
  3092 			smsArray->Reset();
       
  3093 			if (diffInSecs >= timeOutInSecs)
       
  3094 				{
       
  3095 				GetSmsEntriesL(iEntryArray[k], *smsMessage, *indexArray, *smsArray);
       
  3096 				SortPDUsL(*indexArray, *smsArray);
       
  3097 
       
  3098 				//Form the message & forward it to client.
       
  3099 				TInt startSeqIndex(0), endSeqIndex(0);
       
  3100 				TInt i;
       
  3101 				do
       
  3102 					{
       
  3103 					i = startSeqIndex;
       
  3104 					for (; i < indexArray->Count() - 1; i++)
       
  3105 						{
       
  3106 						if (indexArray->At(i) + 1 != indexArray->At(i+1))
       
  3107 							{
       
  3108 							endSeqIndex = i;
       
  3109 							break;
       
  3110 							}
       
  3111 						}
       
  3112 					if (i == (indexArray->Count() - 1))
       
  3113 						{
       
  3114 						endSeqIndex = i;
       
  3115 						}
       
  3116 					tmpSmsArray->Reset();
       
  3117 					for (TInt j = startSeqIndex; j <= endSeqIndex; j++)
       
  3118 						{
       
  3119 						tmpSmsArray->AppendL(smsArray->At(j));
       
  3120 						}
       
  3121 
       
  3122 					if (iEntryArray[k].IsComplete())
       
  3123 						{
       
  3124 						if (tmpSmsArray->Count() == iEntryArray[k].Total())
       
  3125 							{
       
  3126 							smsMessage->DecodeMessagePDUsL(*tmpSmsArray);
       
  3127 							}
       
  3128 						else
       
  3129 							{
       
  3130 							//Build the partial complete message.
       
  3131 							if (endSeqIndex == (indexArray->Count() - 1))
       
  3132 								{
       
  3133 								smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue);
       
  3134 								}
       
  3135 							else
       
  3136 								{
       
  3137 								smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse);
       
  3138 								}
       
  3139 							}				
       
  3140 						}
       
  3141 					else
       
  3142 						{
       
  3143 						//Build the partial complete message.
       
  3144 						if (endSeqIndex == (indexArray->Count() - 1))
       
  3145 							{
       
  3146 							smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, ETrue);
       
  3147 							}
       
  3148 						else
       
  3149 							{
       
  3150 							smsMessage->DecodePartialCompleteMessagePDUsL(*tmpSmsArray, EFalse);
       
  3151 							}
       
  3152 						}
       
  3153 
       
  3154 					//Forward the partial complete message to client.
       
  3155 					TInt ret=KErrNone;
       
  3156 					TBuf16<CSmsPDUProcessor::ESmsMaxDeliverReportBufferSize> buffer;
       
  3157 					ret = iSmsComm.ProcessMessageL(*smsMessage, NULL, NULL, buffer);
       
  3158 					if (ret != KErrNone)
       
  3159 						{
       
  3160 						passedToClient = EFalse;
       
  3161 						}
       
  3162 
       
  3163 					startSeqIndex = endSeqIndex + 1;
       
  3164 					endSeqIndex = startSeqIndex;
       
  3165 					}
       
  3166 				while (startSeqIndex < indexArray->Count());
       
  3167 
       
  3168 				if(passedToClient)
       
  3169 					{
       
  3170 					SetMessagePassedToClientL(*smsMessage);
       
  3171 					}
       
  3172 				}	//diffInSecs >= timeOutInSecs
       
  3173 			}	//!iEntryArray[k].PassedToClient()
       
  3174 		}	//For k loop
       
  3175 	CleanupStack::PopAndDestroy(4);	//tmpSmsArray, indexArray, smsArray, smsMessage
       
  3176 	}
       
  3177 
       
  3178 /**
       
  3179 It sets the bit-map of forwarded incomplete message to client.
       
  3180 It frees up the memory by removing the forwarded PDUs.
       
  3181 
       
  3182 @param aSmsMessage	a reference to forwaded incomplete class 0 sms message object.
       
  3183 
       
  3184 @internalComponent
       
  3185 */
       
  3186 void CClass0SmsReassemblyStore::SetIncompleteMessageForwardedToClientL(const CSmsMessage& aSmsMessage)
       
  3187 	{
       
  3188 	LOGSMSPROT1("CClass0SmsReassemblyStore::SetIncompleteMessageForwardedToClientL()");
       
  3189 	TInt index = KErrNotFound;
       
  3190 
       
  3191 	if (aSmsMessage.IsComplete())
       
  3192 		{
       
  3193 		LOGSMSPROT1("This function must be called when message is incomplete");
       
  3194 		User::Leave(KErrArgument);
       
  3195 		}
       
  3196 
       
  3197 	if (FindMessageL(aSmsMessage, EFalse, index))
       
  3198 		{
       
  3199 		CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo &) aSmsMessage.GetOperationsForNonIEL(ESmsIncompleteClass0MessageParameter);
       
  3200 		// Retrieve incomplete class 0 message information & process
       
  3201 		TInt startPos, endPos;
       
  3202 		TBool isLastMessage;
       
  3203 		incompleteClass0MsgInfo.GetIncompleteMessageInfoL(startPos, endPos, isLastMessage);
       
  3204 
       
  3205 		const TReassemblyEntry&  entry = iEntryArray[index];
       
  3206 
       
  3207 		//Remove the forwarded PDU entries from pre-allocated file
       
  3208 		TInt preAllocatedFileIndex=KErrNotFound;
       
  3209 		iPreallocatedFile->MatchEntryToExistingMessage(entry, preAllocatedFileIndex);
       
  3210 		if (preAllocatedFileIndex!=KErrNotFound)
       
  3211 			{
       
  3212 			BeginTransactionLC();
       
  3213 			iPreallocatedFile->RemovePDUsL(preAllocatedFileIndex, startPos, endPos);
       
  3214 			iPreallocatedFile->StoreForwardedPDUsInfoL(preAllocatedFileIndex, startPos, endPos);
       
  3215 			CommitTransactionL();
       
  3216 			}
       
  3217 		else
       
  3218 			{
       
  3219 			//This situation should never arise
       
  3220 			User::Leave(KErrNotFound);
       
  3221 			}
       
  3222 
       
  3223 		//Remove the forwarded PDU entries from permanent store file
       
  3224 		TInt permanentStoreIndex=KErrNotFound;
       
  3225 		iPermanentFileStore->MatchEntryToExistingMessage(entry, permanentStoreIndex);
       
  3226 		if (permanentStoreIndex!=KErrNotFound)
       
  3227 			{
       
  3228 			TRAP_IGNORE(BeginTransactionLC();
       
  3229 						iPermanentFileStore->RemovePDUsL(permanentStoreIndex, startPos, endPos);
       
  3230 						CommitTransactionL(););
       
  3231 			}
       
  3232 		}
       
  3233 	}
       
  3234 
       
  3235 /**
       
  3236 This function is needed to ensure that permanent file
       
  3237 clean itself with pre-allocated file.
       
  3238 There migth be a scenario where user has deleted a message
       
  3239 but the corresponding message has not been deleted from permanent store file
       
  3240 due to out-of-disk condition. But the entry is invalid because
       
  3241 it is no more in the pre-allocated file which contains master header info.
       
  3242 
       
  3243 @return the error code.
       
  3244 
       
  3245 @internalComponent
       
  3246 */
       
  3247 TInt CClass0SmsReassemblyStore::CleanReassemblyEntries()
       
  3248 	{
       
  3249 	LOGSMSPROT1("CleanReassemblyEntries");
       
  3250 	const CArrayFix<TSmsPreAllocatedFileStoreReassemblyEntry>& preAllocatedFileEntryArray = iPreallocatedFile->Entries();
       
  3251 	TInt ret=KErrNone;
       
  3252 	TRAP(ret,	BeginTransactionLC();
       
  3253 				iPermanentFileStore->CleanupEntriesL(preAllocatedFileEntryArray);
       
  3254 				CommitTransactionL(););
       
  3255 
       
  3256 	if (ret == KErrDiskFull)
       
  3257 		{
       
  3258 		LOGSMSPROT1("CleanupEntriesL returns KErrDiskFull");
       
  3259 		/*
       
  3260 		Get access to reserve memory, call again to clean the entries with compact.
       
  3261 		Compact needs to be called at this instance because permanent store
       
  3262 		will use reserve disk space to delete, but after deletion reserve
       
  3263 		disk space will be freed. So compact will make sure that reserve disk
       
  3264 		space is not used after compaction.
       
  3265 		*/
       
  3266 		iFs.GetReserveAccess(KStoreDrive);
       
  3267 		TRAP(ret,	BeginTransactionLC();
       
  3268 					iPermanentFileStore->CleanupEntriesWithCompactL(preAllocatedFileEntryArray);
       
  3269 					CommitTransactionL(););
       
  3270 		LOGSMSPROT2("CleanupEntriesWithCompactL returns %d", ret);
       
  3271 		iFs.ReleaseReserveAccess(KStoreDrive);
       
  3272 		}
       
  3273 	return ret;
       
  3274 	}
       
  3275 
       
  3276 /**
       
  3277 It returns the SMS entries (sms messages, sms pdu arrays & the corresponding index array)
       
  3278 from its permanent store & pre-allocated file.
       
  3279 
       
  3280 @param aEntry reference to entry information. The message which match this entry information
       
  3281 				is returned to caller of the function.
       
  3282 @param aSmsMessage	a reference to class 0 sms message object.
       
  3283 @param aIndexArray	a reference to the array of pdu index.
       
  3284 @param aSmsArray	a reference to the array of pdu.
       
  3285 
       
  3286 @internalComponent
       
  3287 */
       
  3288 void CClass0SmsReassemblyStore::GetSmsEntriesL(const TReassemblyEntry& aEntry, CSmsMessage& aSmsMessage, CArrayFix<TInt>& aIndexArray, CArrayFix<TGsmSms>& aSmsArray)
       
  3289 	{
       
  3290 	LOGSMSPROT1("CClass0SmsReassemblyStore::GetSmsEntriesL()");
       
  3291 	TInt permanentStoreIndex=KErrNotFound;
       
  3292 	iPermanentFileStore->MatchEntryToExistingMessage(aEntry, permanentStoreIndex);
       
  3293 	if (permanentStoreIndex!=KErrNotFound)
       
  3294 		{
       
  3295 		iPermanentFileStore->InternalizeEntryL(permanentStoreIndex, aSmsMessage, aIndexArray, aSmsArray);
       
  3296 		}
       
  3297 	else
       
  3298 		{
       
  3299 		LOGSMSPROT1("No PDUs in Permanent store file");
       
  3300 		}
       
  3301 
       
  3302 	TInt preAllocatedFileIndex=KErrNotFound;
       
  3303 	iPreallocatedFile->MatchEntryToExistingMessage(aEntry, preAllocatedFileIndex);
       
  3304 	if (preAllocatedFileIndex!=KErrNotFound)
       
  3305 		{
       
  3306 		iPreallocatedFile->InternalizeEntryL(preAllocatedFileIndex, aSmsMessage, aIndexArray, aSmsArray);
       
  3307 
       
  3308 		//Filter forwarde PDU here..this condition might arise if the PDU
       
  3309 		//could not be deleted at the time of OOD condition from permanent store file.
       
  3310 		TSmsPreAllocatedFileStoreReassemblyEntry preAllocatedFileEntry = iPreallocatedFile->Entries()[preAllocatedFileIndex];
       
  3311 		if (preAllocatedFileEntry.NumberOfPDUsForwardToClient() > 0)
       
  3312 			{
       
  3313 			for (TInt j=aIndexArray.Count(); j>0 ;j--)
       
  3314 				{
       
  3315 				TUint8 bitMapIndex = (aIndexArray.At(j-1)-1)/8;
       
  3316 				TUint8 bitPos = (aIndexArray.At(j-1)-1)%8;
       
  3317 				TUint8 bitMap;
       
  3318 				preAllocatedFileEntry.GetBitMap(bitMapIndex, bitMap);
       
  3319 				TUint8 tmpBitMap = 1;
       
  3320 				tmpBitMap <<= bitPos;
       
  3321 				if (tmpBitMap == (bitMap & tmpBitMap))
       
  3322 					{
       
  3323 					aIndexArray.Delete(j-1);
       
  3324 					aSmsArray.Delete(j-1);
       
  3325 					}
       
  3326 				}
       
  3327 			}
       
  3328 
       
  3329 		if (permanentStoreIndex==KErrNotFound)
       
  3330 			{
       
  3331 			//In this scenario a CSmsMessage object has to be created from the existing PDU in
       
  3332 			//pre-allocated file & then serialized into aSmsMessage.
       
  3333 			LOGSMSPROT2("Number of PDUs in Pre-allocated file %d", aIndexArray.Count());
       
  3334 			if (aIndexArray.Count() > 0)
       
  3335 				{
       
  3336 				CSmsBuffer* smsBuffer = CSmsBuffer::NewL();
       
  3337 				CSmsMessage* smsMessage = CSmsMessage::NewL(iFs, aSmsArray.At(0), smsBuffer, EFalse, ETrue);
       
  3338 				CleanupStack::PushL(smsMessage);
       
  3339 
       
  3340 				//Update sms messages's properties.
       
  3341 				smsMessage->SetStorage(aSmsMessage.Storage());
       
  3342 				smsMessage->SetStatus((NMobileSmsStore::TMobileSmsStoreStatus)aSmsMessage.Status());
       
  3343 				smsMessage->SetLogServerId(aSmsMessage.LogServerId());
       
  3344 				smsMessage->SetTime(aSmsMessage.Time());
       
  3345 				smsMessage->SetUTCOffset(aSmsMessage.UTCOffset());
       
  3346 				smsMessage->SetDecodedOnSIM(aSmsMessage.DecodedOnSim());
       
  3347 				smsMessage->SetForwardToClient(aSmsMessage.ForwardToClient());
       
  3348 				smsMessage->SetToFromAddressL(aSmsMessage.ToFromAddress());
       
  3349 
       
  3350 				CBufSeg* recvbufseg = CBufSeg::NewL(KSmsMaxSegmentLength);
       
  3351 				CleanupStack::PushL(recvbufseg);
       
  3352 				// Attempt to serialize this message into the buffer
       
  3353 				RBufWriteStream writestream(*recvbufseg);
       
  3354 				writestream.Open(*recvbufseg);
       
  3355 				CleanupClosePushL(writestream);
       
  3356 				writestream << *smsMessage;
       
  3357 
       
  3358 				// Initialize the read stream with the buffer
       
  3359 				RBufReadStream readstream(*recvbufseg);
       
  3360 				readstream.Open(*recvbufseg,0);
       
  3361 				CleanupClosePushL(readstream);
       
  3362 				// De-serialize the message from using the read stream
       
  3363 				readstream >> aSmsMessage;
       
  3364 				CleanupStack::PopAndDestroy(4);		//readstream, writestream, recvbufseg, smsMessage
       
  3365 				}
       
  3366 			}
       
  3367 		}
       
  3368 	}
       
  3369 
       
  3370 /*
       
  3371 It returns when the next timeout should occur.
       
  3372 */
       
  3373 void CClass0SmsReassemblyStore::GetNextGuardTimeout(TTime& aNextTimeout)
       
  3374 	{
       
  3375 	TTime curTime;
       
  3376 	curTime.UniversalTime();
       
  3377 	TTimeIntervalSeconds timeOutInSecs = iGuardTimeOut*3600;
       
  3378 	aNextTimeout = curTime + timeOutInSecs;
       
  3379 
       
  3380 	TInt class0ReassemblyStoreCount = iEntryArray.Count();
       
  3381 
       
  3382 	if (class0ReassemblyStoreCount > 0)
       
  3383 		{
       
  3384 		for (TInt i=0; i<class0ReassemblyStoreCount;i++)
       
  3385 			{
       
  3386 			TTime guradTimeout = iEntryArray[i].Time() + timeOutInSecs;
       
  3387 			if ((guradTimeout > curTime) &&
       
  3388 				(guradTimeout < aNextTimeout))
       
  3389 				{
       
  3390 				aNextTimeout = guradTimeout;
       
  3391 				}
       
  3392 			}
       
  3393 		}
       
  3394 	}
       
  3395 
       
  3396 /*
       
  3397 It returns the index of oldest message in class 0 re-assembly store.
       
  3398 */
       
  3399 TInt CClass0SmsReassemblyStore::GetIndexOfOldestMessage()
       
  3400 	{
       
  3401 	TInt index = 0;
       
  3402 	TTime time = iEntryArray[index].Time();
       
  3403 	for (TInt index2=1; index2 < iEntryArray.Count(); index2++)
       
  3404 		{
       
  3405 		if (iEntryArray[index2].Time() < time)
       
  3406 			{
       
  3407 			index = index2;
       
  3408 			}
       
  3409 		}
       
  3410 	return index;
       
  3411 	}
       
  3412 
       
  3413 /*
       
  3414 It returns the index of oldest message in class 0 re-assembly store.
       
  3415 */
       
  3416 TInt CClass0SmsReassemblyStore::GetIndexOfOldestMessageFromReservedFileL()
       
  3417 	{
       
  3418 	TInt index = KErrNotFound;
       
  3419 	//Find the index of oldest message in pre-allocated file.
       
  3420 	index = iPreallocatedFile->GetOldestMessageEntryIndex();
       
  3421 	if (index == KErrNotFound)
       
  3422 		{
       
  3423 		//This condition should never arise
       
  3424 		User::Leave(KErrNotFound);
       
  3425 		}
       
  3426 
       
  3427 	//Compare the oldest pre-allocated message entry against class 0 reassembly store entry
       
  3428 	//and return the index of class 0 reassembly store entry.
       
  3429 	const TSmsPreAllocatedFileStoreReassemblyEntry& preAllocatedFileEntry = iPreallocatedFile->Entries()[index];
       
  3430 
       
  3431 	TInt reassemblyCount = iEntryArray.Count();
       
  3432 	TInt count;
       
  3433 	for (count = 0;  count < reassemblyCount;  count++)
       
  3434 		{
       
  3435 		TReassemblyEntry&  entry = iEntryArray[count];
       
  3436 
       
  3437 		if (entry.Reference() == preAllocatedFileEntry.Reference()  &&
       
  3438 			entry.Total() == preAllocatedFileEntry.Total()  &&
       
  3439 			entry.PduType() == preAllocatedFileEntry.PduType()  &&
       
  3440 			entry.Storage() == preAllocatedFileEntry.Storage()  &&
       
  3441 			entry.Description2() == preAllocatedFileEntry.Description2())
       
  3442 			{
       
  3443 			//
       
  3444 			// Found it!
       
  3445 			//
       
  3446 			index = count;
       
  3447 			break;
       
  3448 			}
       
  3449 		}
       
  3450 	if (count == reassemblyCount)
       
  3451 		{
       
  3452 		//This condition should never arise
       
  3453 		User::Leave(KErrNotFound);
       
  3454 		}
       
  3455 	return index;
       
  3456 	}
       
  3457 
       
  3458 /*
       
  3459 It returns a boolean value indicating whether the limitation (max class 0 message,
       
  3460 max pdu stored in pre-allocated file) imposed on class 0 reassembly store exceeds or not.
       
  3461 */
       
  3462 TBool CClass0SmsReassemblyStore::IsExceedLimitation()
       
  3463 	{
       
  3464 	TInt class0MsgCount = iEntryArray.Count();
       
  3465 	TInt noOfMsgStoredInPreAllocatedFile = iPreallocatedFile->NumberOfPDUStored();
       
  3466 	if ((class0MsgCount > iMaxClass0Msg)
       
  3467 			|| (noOfMsgStoredInPreAllocatedFile > iMaxPDUSeg))
       
  3468 		{
       
  3469 		return ETrue;
       
  3470 		}
       
  3471 
       
  3472 	return EFalse;
       
  3473 	}
       
  3474 
       
  3475 /*
       
  3476 This sorting algorithm is based on bubble sort
       
  3477 */
       
  3478 void CClass0SmsReassemblyStore::SortPDUsL(CArrayFix<TInt>& aIndexArray, CArrayFix<TGsmSms>& aSmsArray)
       
  3479 	{
       
  3480 	//Test---Index array count must be equal to sms array count
       
  3481 	TBool swapped;
       
  3482 
       
  3483 	do
       
  3484 		{
       
  3485 		swapped = EFalse;
       
  3486 		for (TInt i=0; i<aIndexArray.Count()-1 ;i++)
       
  3487 			{
       
  3488 			if (aIndexArray[i] > aIndexArray[i+1])
       
  3489 				{
       
  3490 				aSmsArray.InsertL(i, aSmsArray[i+1]);
       
  3491 				aSmsArray.Delete(i+2);
       
  3492 				aIndexArray.InsertL(i, aIndexArray[i+1]);
       
  3493 				aIndexArray.Delete(i+2);
       
  3494 				swapped = ETrue;
       
  3495 				}
       
  3496 			}
       
  3497 		}
       
  3498 	while (swapped);
       
  3499 	}
       
  3500 
       
  3501 /**
       
  3502  *  Utility func for cleanup stack
       
  3503  */
       
  3504 void CClass0StoreCloseObject(TAny* aObj)
       
  3505 	{
       
  3506 	LOGGSMU2("WARNING! Hey, CClass0StoreCloseObject called by Untrapper! [0x%08x]", aObj);
       
  3507 	((CClass0SmsReassemblyStore*)aObj)->Revert();
       
  3508 	}
       
  3509 
       
  3510 /**
       
  3511  *  Sets the class 0 re-assembly store as in-transaction.
       
  3512  *  
       
  3513  *  The function checks the validity of the call and leaves KErrAccessDenied if
       
  3514  *  invalid.
       
  3515  *  @capability None
       
  3516  */
       
  3517 void CClass0SmsReassemblyStore::BeginTransactionLC()
       
  3518 	{
       
  3519 	LOGSMSPROT3("CClass0SmsReassemblyStore::BeginTransactionLC [this=0x%08X iInTransaction=%d]", this, iInTransaction);
       
  3520 
       
  3521 	if (iInTransaction)
       
  3522 		{
       
  3523 	    LOGGSMU1("WARNING CClass0SmsReassemblyStore::BeginTransactionLC leaving with KErrAccessDenied");
       
  3524 		User::Leave(KErrAccessDenied);
       
  3525 		}
       
  3526 
       
  3527 	TCleanupItem class0StoreClose(CClass0StoreCloseObject, this);
       
  3528 	CleanupStack::PushL(class0StoreClose);
       
  3529 	iPreallocatedFile->BeginTransactionL();
       
  3530 	iPermanentFileStore->BeginTransactionL();
       
  3531 	iInTransaction = ETrue;
       
  3532 	}
       
  3533 
       
  3534 /**
       
  3535  *  It commits the transaction.
       
  3536  */
       
  3537 void CClass0SmsReassemblyStore::CommitTransactionL()
       
  3538 	{
       
  3539 	LOGSMSPROT3("CClass0SmsReassemblyStore::CommitTransactionL(): this=0x%08X iInTransaction=%d",
       
  3540 				this, iInTransaction);
       
  3541 
       
  3542 	//Commit permanent store file
       
  3543 	iPermanentFileStore->CommitTransactionL();
       
  3544 	//Commit pre-allocated file
       
  3545 	iPreallocatedFile->CommitTransactionL();
       
  3546 	CleanupStack::Pop(this);	//CClass0StoreCloseObject
       
  3547 	iInTransaction = EFalse;
       
  3548 	}
       
  3549 
       
  3550 /**
       
  3551  *  It reverts the transaction.
       
  3552  */
       
  3553 void CClass0SmsReassemblyStore::Revert()
       
  3554 	{
       
  3555 	LOGSMSPROT3("CClass0SmsReassemblyStore::Revert(): this=0x%08X, iInTransaction=%d",
       
  3556     		 this, iInTransaction);
       
  3557 
       
  3558 	iPreallocatedFile->Revert();
       
  3559 	iPermanentFileStore->Revert();
       
  3560 	iInTransaction = EFalse;
       
  3561 	}