messagingfw/msgsrvnstore/server/src/msvindexadapter.cpp
changeset 0 8e480a14352b
child 16 8147bfb6c710
child 17 d6ba66e59a81
equal deleted inserted replaced
-1:000000000000 0:8e480a14352b
       
     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 //
       
    15 
       
    16 #ifdef _DEBUG
       
    17 #undef _NO_SERVER_LOGGING_
       
    18 #endif
       
    19 
       
    20 /**
       
    21  * User Includes
       
    22  */
       
    23 #include "MSVSERV.H"
       
    24 #include "MSVARRAY.H"
       
    25 #include "msvdbadapter.h"
       
    26 #include "msvcacheentry.h"
       
    27 #include "msvindexadapter.h"
       
    28 #include "msventryfreepool.h"
       
    29 #include "msvcachevisiblefolder.h"
       
    30 #include "msvsearchsortdeltacache.h"
       
    31 #include "msvsearchsortcachemanager.h"
       
    32 
       
    33 /**
       
    34  *System Includes
       
    35  */
       
    36 #include <msvuids.h>
       
    37 #include <msvstd.h>
       
    38 
       
    39 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 
       
    40 #include "msvconsts.h"
       
    41 #endif
       
    42 
       
    43 /**
       
    44  * MACRO DEFINITIONS
       
    45  */
       
    46 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
    47 	#define INITIAL_NUM_ENTRIES 10
       
    48 #else
       
    49 	#define INITIAL_NUM_ENTRIES 13
       
    50 #endif
       
    51 
       
    52 /**
       
    53  * CONSTANT DEFINITIONS
       
    54  */
       
    55 const TInt KMsvMtmListGranularity=8;
       
    56 const TInt KMsvChangeAttributesListGranularity=32;
       
    57 
       
    58 
       
    59 
       
    60 /**
       
    61  * FUNCTION DEFINITIONS
       
    62  */
       
    63 
       
    64 
       
    65 
       
    66 /**
       
    67  * CMsvIndexAdapter()
       
    68  */
       
    69 CMsvIndexAdapter::CMsvIndexAdapter(CMsvServer& aServer)
       
    70     :CActive(EPriorityStandard), iServer(aServer), iFolderListHeader(CMsvCacheVisibleFolder::iOffset)
       
    71 	{	
       
    72 	CActiveScheduler::Add(this);		
       
    73 	}
       
    74 
       
    75 
       
    76 
       
    77 
       
    78 /**
       
    79  * ~CMsvIndexAdapter()
       
    80  */
       
    81 CMsvIndexAdapter::~CMsvIndexAdapter()
       
    82 	{
       
    83 
       
    84 #ifndef _NO_SERVER_LOGGING_
       
    85 	iServer.Log(_L("Destroying CMsvIndexAdapter object."));
       
    86 #endif
       
    87 	
       
    88 	Cancel();
       
    89 	
       
    90 	// 1. Close the database.
       
    91 #ifndef _NO_SERVER_LOGGING_
       
    92 	iServer.Log(_L("Closing the database."));
       
    93 #endif
       
    94 	if(iDbAdapter != NULL)
       
    95 		delete iDbAdapter;
       
    96 
       
    97 	// 2. Delete Cache.
       
    98 #ifndef _NO_SERVER_LOGGING_
       
    99 	iServer.Log(_L("Destroying Cache."));
       
   100 #endif
       
   101 	
       
   102 	CMsvCacheVisibleFolder* folderNode = NULL;
       
   103 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
   104 
       
   105     dqIter.SetToFirst();
       
   106     while ((folderNode = dqIter++) != NULL)
       
   107         {
       
   108         folderNode->iDlink.Deque();
       
   109         delete folderNode;
       
   110         }
       
   111     
       
   112     iFreePoolInstance->ReleaseEntry(iRootEntry);
       
   113     iRootEntry = NULL;
       
   114 
       
   115     // 3. Delete internal data structure.
       
   116     iNonCommittedAddedEntryList.ResetAndDestroy();
       
   117     iNonCommittedChangedEntryList.Reset();
       
   118     iNonCommittedAddedEntryList.Close();
       
   119 	iNonCommittedChangedEntryList.Close();
       
   120     
       
   121     // 4. Flush extra memory in entry freepool.
       
   122     if(iFreePoolInstance != NULL)
       
   123     	{
       
   124     	iFreePoolInstance->FlushExcessMemory();	
       
   125     	}
       
   126 	
       
   127 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   128 	// Added for 557.
       
   129 	iMaxMsvIdList.Close();
       
   130 #endif
       
   131 
       
   132 	delete iIdle;
       
   133 	}
       
   134 
       
   135 
       
   136 
       
   137 
       
   138 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   139 /**
       
   140  * NewL()
       
   141  * @return The newly created index adapter object.
       
   142  * 
       
   143  * Function added as part of PREQ 557.
       
   144  * It returns an instance of CMsvIndexAdapter class. 
       
   145  */
       
   146 CMsvIndexAdapter* CMsvIndexAdapter::NewL(CMsvServer& aServer)
       
   147 	{
       
   148 	CMsvIndexAdapter *self = new(ELeave) CMsvIndexAdapter(aServer);
       
   149 	CleanupStack::PushL(self);
       
   150 	
       
   151 	self->ConstructL();
       
   152 	
       
   153 	CleanupStack::Pop();
       
   154 	return self;
       
   155 	}
       
   156 
       
   157 
       
   158 
       
   159 
       
   160 /**
       
   161  * ConstructL()
       
   162  * 
       
   163  * Function added as part of PREQ 557.
       
   164  * The function is called from NewL().
       
   165  * 1. Create the DB adapter object.
       
   166  * 2. Initialize freepool object.
       
   167  * 3. Create the root entry in cache.
       
   168  * 4. Browse through the preferred drive list.
       
   169  *    i. For each drive in the preferred drive list the function 
       
   170  *       assigns a unique drive-id (0< Id <8).
       
   171  *	 ii. Attach the DB to the primary database.
       
   172  *  iii. Update the maxId of the database to MaxId table.
       
   173  *   iv. If the database is not compatible or corrupt, update the 
       
   174  *       appropriate drive status in CMsvServer data structure.
       
   175  *    v. Fetch children of root entry and Local-Service entry from the DB to the cache.      
       
   176  */
       
   177 void CMsvIndexAdapter::ConstructL()
       
   178 	{
       
   179 #ifndef _NO_SERVER_LOGGING_
       
   180 	iServer.Log(_L("Inside ConstructL()..."));
       
   181 #endif
       
   182 	
       
   183 	// Create database adapter object.
       
   184 	iDbAdapter = CMsvDBAdapter::NewL();
       
   185 		
       
   186 #ifndef _NO_SERVER_LOGGING_
       
   187 	iServer.Log(_L("The database object is created succesfully."));
       
   188 #endif
       
   189 	
       
   190 	iProgress.iCompleted = 0;
       
   191 	iProgress.iTotal = iProgress.iRemaining = INITIAL_NUM_ENTRIES;
       
   192 	
       
   193 	// Initialize freepool object.
       
   194 	iFreePoolInstance = CMsvEntryFreePool::Instance();
       
   195 	iFreePoolInstance->SetEssentialParam(&iFolderListHeader, this);
       
   196 	
       
   197 	// Drive id zero will be synonym of KCurrentDriveId. Drive
       
   198 	// id of a drive (including current) drive will never be zero.
       
   199 	// Drive of the current drive will always by KCurrentDriveId.
       
   200 	TUint driveId = KCurrentDriveId;
       
   201 
       
   202 	// Since driveId starts from 1, the first 
       
   203 	// entry in iMaxMsvIdList is not used.
       
   204 	// Enter a dummy entry in location zero.
       
   205 	iMaxMsvIdList.InsertL(0, 0);
       
   206 	
       
   207 	iProgress.iCompleted++;
       
   208 	iProgress.iRemaining--;
       
   209 	iProgress.iId = KMsvRootIndexEntryId;
       
   210 	
       
   211 	// For each drive in the preferred drive list, perform followings...
       
   212 	// 1. Check if a valid message store is available.
       
   213 	// 2. If not, skip the drive.
       
   214 	// 3. Assign a new drive Id to the drive and
       
   215 	//    update the entry in preferred drive list.
       
   216 	// 4. Attach the drive database to the primary DB.
       
   217 	// 5. Update the max Id list.
       
   218 	// 6. For current drive, fetch the children of root entry into cache.
       
   219 	// 7. Fetch children of localService into cache.
       
   220 	CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
       
   221 	TUint curDriveIndex = driveList->CurrentDriveIndex();
       
   222 	for(TInt index=curDriveIndex; index<driveList->Count(); index++)
       
   223 		{
       
   224 		TMsvPreferredDrive driveEntry;
       
   225 		driveList->DriveInfoL(index, driveEntry);
       
   226 		
       
   227 		if(EMsvMessageStoreAvailableStatus == driveEntry.status)
       
   228 			{
       
   229 			// Assign a unique drive-id.
       
   230 			driveList->UpdateDriveIdL(index, driveId);
       
   231 			
       
   232 			// Attach the database.
       
   233 			TMsvId maxId;
       
   234 			iDbAdapter->AttachDBL(driveEntry.driveNum, driveId, maxId);
       
   235 			
       
   236 			// Insert the max Id in the list.
       
   237 			iMaxMsvIdList.InsertL( ((maxId >= MaskTMsvId(driveId, KFirstFreeEntryId))? (maxId+1): MaskTMsvId(driveId, KFirstFreeEntryId)), driveId);
       
   238 			driveId++;
       
   239 			}
       
   240 		iProgress.iCompleted++;
       
   241 		iProgress.iRemaining--;
       
   242 		}
       
   243 
       
   244 	iFirstFreeDriveId = (driveId%8)? (driveId%8): 2;
       
   245 
       
   246 	// Initializing remaining entries in MaxMsvId list.
       
   247 	for(TInt index=driveId; index<8; index++)
       
   248 		{
       
   249 		iMaxMsvIdList.InsertL(NULL, index);
       
   250 		}
       
   251 	
       
   252 	// For current drive fetch children of root entries also.
       
   253 	RPointerArray<CMsvCacheEntry> childEntryList;
       
   254 	CleanupClosePushL(childEntryList);	
       
   255 	// Create root entry node in the cache. A root folder node will never 
       
   256 	// be swapped out of cache. The children of root entry will be the 
       
   257 	// children of root entry in the current drive.
       
   258 	// Root id is masked to set the driveId in the folder node.
       
   259 	iRootNode = CMsvCacheVisibleFolder::NewL(MaskTMsvId(KCurrentDriveId, KMsvRootIndexEntryId));
       
   260 	iFolderListHeader.AddFirst(*iRootNode);
       
   261 	iRootNode->SetComplete(ETrue);
       
   262 	iDbAdapter->GetChildrenL(KMsvRootIndexEntryId, childEntryList);
       
   263 	iRootNode->AddEntryListL(childEntryList, ETrue);
       
   264 	childEntryList.Reset();
       
   265 	
       
   266 	// Fetch child of LocalServices.
       
   267 	CMsvCacheVisibleFolder* localServiceFolder = CMsvCacheVisibleFolder::NewL(MaskTMsvId(KCurrentDriveId, KMsvLocalServiceIndexEntryId));
       
   268 	iFolderListHeader.AddFirst(*localServiceFolder);
       
   269 	iDbAdapter->GetChildrenL(KMsvLocalServiceIndexEntryId, childEntryList);
       
   270 	localServiceFolder->AddEntryListL(childEntryList, ETrue);
       
   271 	CleanupStack::PopAndDestroy(1);   //childEntryList
       
   272 		
       
   273 	// Create root entry.
       
   274 	iRootEntry = iFreePoolInstance->EntryL(); //taking it from the freepool.
       
   275 	iRootEntry->Entry().iType = KUidMsvRootEntry;
       
   276 	iRootEntry->Entry().iDate.UniversalTime();
       
   277 	iRootEntry->Entry().SetId(KMsvRootIndexEntryId);
       
   278 	iRootEntry->Entry().SetParent(KErrNotFound);
       
   279 	iRootEntry->Entry().SetOwner(ETrue);
       
   280 	iRootEntry->Entry().iSize = 0;
       
   281 	
       
   282 	// Update progress
       
   283 	iProgress.iCompleted = iProgress.iTotal;
       
   284 	iProgress.iRemaining = 0;
       
   285 	iProgress.iId = KMsvRootIndexEntryId;
       
   286 
       
   287 #ifndef _NO_SERVER_LOGGING_
       
   288 	iServer.Log(_L("Cache initialized succesfully."));
       
   289 #endif
       
   290 	
       
   291 	iIdle = CIdle::NewL(CActive::EPriorityIdle);
       
   292 	CompleteSelf();
       
   293 	}
       
   294 
       
   295 
       
   296 
       
   297 /**
       
   298 GetInPreparationIds
       
   299 */
       
   300 void CMsvIndexAdapter::GetInPreparationIds(CMsvEntrySelection& aSelection, TUint aDriveId /*DEFAULT = 0 */)
       
   301 	{
       
   302 	if(iDbAdapter)
       
   303 		{
       
   304 		TRAP_IGNORE(iDbAdapter->GetInPreparationIdL(aSelection, aDriveId));
       
   305 		}
       
   306 	}
       
   307 
       
   308 
       
   309 #else		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   310 
       
   311 
       
   312 /**
       
   313  * NewL()
       
   314  * @param TFileName: DB File Name.
       
   315  * @return The newly created index adapter.
       
   316  * 
       
   317  * It returns an instance of CMsvIndexAdapter class. 
       
   318  */
       
   319 CMsvIndexAdapter* CMsvIndexAdapter::NewL(CMsvServer& aServer, const TFileName& aDbFileName)
       
   320 	{
       
   321 	CMsvIndexAdapter *self = new(ELeave) CMsvIndexAdapter(aServer);
       
   322 	CleanupStack::PushL(self);
       
   323 	
       
   324 	self->ConstructNewL(aDbFileName);
       
   325 	
       
   326 	CleanupStack::Pop();
       
   327 	return self;
       
   328 	}
       
   329 
       
   330 
       
   331 
       
   332 
       
   333 /**
       
   334  * OpenL()
       
   335  * @param TFileName: DB File Name.
       
   336  * @return The newly created index adapter.
       
   337  * 
       
   338  * It returns an instance of CMsvIndexAdapter class. 
       
   339  */
       
   340 CMsvIndexAdapter* CMsvIndexAdapter::OpenL(CMsvServer& aServer, const TFileName& aDbFileName)
       
   341 	{
       
   342 	CMsvIndexAdapter *self = new(ELeave) CMsvIndexAdapter(aServer);
       
   343 	CleanupStack::PushL(self);
       
   344 	
       
   345 	self->ConstructOpenL(aDbFileName);
       
   346 	
       
   347 	CleanupStack::Pop();
       
   348 	return self;
       
   349 	}
       
   350 
       
   351 
       
   352 
       
   353 
       
   354 /**
       
   355  * ConstructNewL()
       
   356  * 
       
   357  * The function is called from NewL().
       
   358  * 1. Check if a database with the passed name already exists.
       
   359  * 1.1. If yes, open the database.
       
   360  * 1.2. If no, create a new database with the same name.
       
   361  * 2. Creates entry cache.
       
   362  * 3. If a new database is created, create root entry also.
       
   363  */
       
   364 void CMsvIndexAdapter::ConstructNewL(const TFileName& aDbFileName)
       
   365 	{
       
   366 #ifndef _NO_SERVER_LOGGING_
       
   367 	iServer.Log(_L("Creating CMsvIndexAdapter instance..."));
       
   368 #endif
       
   369 	
       
   370 	// Delete the database first, if it already exists.
       
   371 	CMsvDBAdapter::DeleteDB(aDbFileName);
       
   372 	
       
   373 	// Get the instance of free pool.
       
   374 	iFreePoolInstance = CMsvEntryFreePool::Instance();
       
   375 
       
   376 	// Create the new database with the same name.
       
   377 	// If this leaves, nothing can be done and let NewL() leave.
       
   378 	iDbAdapter = CMsvDBAdapter::NewL(aDbFileName);
       
   379 #ifndef _NO_SERVER_LOGGING_
       
   380 	iServer.Log(_L("A new database %s is created..."), &aDbFileName);
       
   381 #endif
       
   382 	
       
   383 	iProgress.iTotal = iProgress.iRemaining = 1; //root
       
   384 	// Create root entry. 
       
   385 	CreateInitialSetOfEntriesL();
       
   386 	
       
   387 
       
   388 #ifndef _NO_SERVER_LOGGING_
       
   389 //	iServer.Log(_L("Cache initialized succesfully."));
       
   390 #endif
       
   391 	
       
   392 	iNextCreateId = KFirstFreeEntryId;
       
   393 	iIdle = CIdle::NewL(CActive::EPriorityIdle);
       
   394 	CompleteSelf();
       
   395 	}
       
   396 		
       
   397 
       
   398 
       
   399 
       
   400 	
       
   401 /**
       
   402  * ConstructOpenL()
       
   403  * 
       
   404  * The function is called from NewL().
       
   405  * 1. Check if a database with the passed name already exists.
       
   406  * 1.1. If yes, open the database.
       
   407  * 1.2. If no, create a new database with the same name.
       
   408  * 2. Creates entry cache.
       
   409  * 3. If a new database is created, it then read message resource file 
       
   410  *    and creates entry as mentioned in cache and database.
       
   411  */
       
   412 void CMsvIndexAdapter::ConstructOpenL(const TFileName& aDbFileName)
       
   413 	{
       
   414 #ifndef _NO_SERVER_LOGGING_
       
   415 	iServer.Log(_L("Creating CMsvIndexAdapter instance..."));
       
   416 #endif
       
   417 	
       
   418 	// Get the instance of free pool
       
   419 	iFreePoolInstance = CMsvEntryFreePool::Instance();
       
   420 
       
   421 	// Open the database.
       
   422 	iDbAdapter = CMsvDBAdapter::OpenL(aDbFileName);
       
   423 	
       
   424 #ifndef _NO_SERVER_LOGGING_
       
   425 	iServer.Log(_L("Opening database %s is succesful."), &aDbFileName);
       
   426 #endif
       
   427 		
       
   428 	iProgress.iTotal = iProgress.iRemaining = INITIAL_NUM_ENTRIES;	
       
   429 	CreateInitialCacheL();
       
   430 
       
   431 #ifndef _NO_SERVER_LOGGING_
       
   432 	iServer.Log(_L("Cache initialized succesfully."));
       
   433 #endif
       
   434 
       
   435 	TMsvId tmpNextId = NULL;
       
   436 	iDbAdapter->GetMaxTMsvIdL(tmpNextId);
       
   437 	iNextCreateId = (tmpNextId >= KFirstFreeEntryId)? (tmpNextId+1) : KFirstFreeEntryId;
       
   438 	
       
   439 	iIdle = CIdle::NewL(CActive::EPriorityIdle);
       
   440 	CompleteSelf();
       
   441 	}
       
   442 	
       
   443 
       
   444 
       
   445 
       
   446 /**
       
   447  * CreateInitialSetOfEntries()
       
   448  * 
       
   449  * The function is called from ConstructL(), whenever a new DB is created.
       
   450  * The function creates root entry into database and cache.
       
   451  */
       
   452 void CMsvIndexAdapter::CreateInitialSetOfEntriesL()
       
   453 	{
       
   454 	
       
   455 #ifndef _NO_SERVER_LOGGING_
       
   456 	iServer.Log(_L("Inside CreateInitialSetOfEntriesL(): Creating standard entries for new DB."));
       
   457 #endif
       
   458 	
       
   459 	// 1. Initialize the instance of free pool.
       
   460 	iFreePoolInstance->SetEssentialParam(&iFolderListHeader, this);
       
   461 		
       
   462 	// 2. Creating root entry into database.
       
   463 	iRootEntry = iFreePoolInstance->EntryL(); //taking it from the freepool.
       
   464 	iRootEntry->Entry().iType = KUidMsvRootEntry;
       
   465 	iRootEntry->Entry().iDate.UniversalTime();
       
   466 	iRootEntry->Entry().SetId(KMsvRootIndexEntryId);
       
   467 	iRootEntry->Entry().SetParent(KErrNotFound);
       
   468 	iRootEntry->Entry().iSize = 0;
       
   469 	
       
   470 	TMsvId visibleFolderId = KMsvRootIndexEntryId;
       
   471 	iDbAdapter->CreateEntryL(iRootEntry->Entry(), visibleFolderId);
       
   472 	
       
   473 	// 3. Add root entry to cache as well
       
   474 	CMsvCacheVisibleFolder* rootFolder = CMsvCacheVisibleFolder::NewL(KMsvRootIndexEntryId);
       
   475 	iFolderListHeader.AddFirst(*rootFolder);
       
   476 	rootFolder->SetComplete(ETrue);
       
   477 	
       
   478 	// Update progress
       
   479 	iProgress.iCompleted++;
       
   480 	iProgress.iRemaining--;
       
   481 	iProgress.iId = KMsvRootIndexEntryId;
       
   482 	}
       
   483 
       
   484 
       
   485 
       
   486 
       
   487 
       
   488 /**
       
   489  * CreateInitialCache()
       
   490  * 
       
   491  * The function is called from NewL(), whenever an existing DB is opened.
       
   492  * It creates the intial cache. It creates root entry in cache and fetches
       
   493  * child of root from DB and push them into cache. It then fetches child
       
   494  * entries of LocalServices and push them too into cache. 
       
   495  * 
       
   496  * >>>> The function can be enhanced to load children of additional folders
       
   497  * to cache along with the above standard folders. These additional folders 
       
   498  * can be mentioned by licensees in msgs.ini file.
       
   499  */
       
   500 void CMsvIndexAdapter::CreateInitialCacheL()
       
   501 	{
       
   502 #ifndef _NO_SERVER_LOGGING_
       
   503 	iServer.Log(_L("Inside CreateInitialCache(): Initializing Cache."));
       
   504 #endif
       
   505 
       
   506 	//1. Initialize the instance of free pool.
       
   507 	iFreePoolInstance->SetEssentialParam(&iFolderListHeader, this);
       
   508 	
       
   509 	// 2. Add root entry to cache.
       
   510 	CMsvCacheVisibleFolder* rootFolder = CMsvCacheVisibleFolder::NewL(KMsvRootIndexEntryId);
       
   511 	iFolderListHeader.AddFirst(*rootFolder);
       
   512 	// 2.1 Update progress
       
   513 	iProgress.iCompleted++;
       
   514 	iProgress.iRemaining--;
       
   515 	iProgress.iId = KMsvRootIndexEntryId;
       
   516 	
       
   517 	// 3. Fetch child of root entries from DB.
       
   518 	RPointerArray<CMsvCacheEntry> childrenOfRoot;
       
   519 	iDbAdapter->GetChildrenL(KMsvRootIndexEntryId, childrenOfRoot);
       
   520 
       
   521 	// 3.1 Get the root entry from DB.
       
   522 	CMsvCacheEntry *rootEntry = NULL;
       
   523 	TMsvId visibleFolder = NULL;
       
   524 	iDbAdapter->GetEntryL(KMsvRootIndexEntryId, rootEntry, visibleFolder);
       
   525 	// 3.2 Copy the TMsvEntry of root from CMsvCacheEntry.
       
   526 	//Mem::Copy(&iRootEntry->Entry(), &rootEntry->Entry(), sizeof(TMsvEntry));
       
   527 	iRootEntry = rootEntry;
       
   528 	// 3.3 Release the cache entry back to the freepool.
       
   529 	//iFreePoolInstance->ReleaseEntry(rootEntry);	
       
   530 	
       
   531 	// 4. Add children to cache.
       
   532 	rootFolder->AddEntryListL(childrenOfRoot, ETrue);
       
   533 	// 4.1 Update progress
       
   534 	iProgress.iCompleted += 4;
       
   535 	iProgress.iRemaining -= 4;
       
   536 	iProgress.iId = KMsvLocalServiceIndexEntryId;
       
   537 	
       
   538 	// 5. Set the visible folder as complete
       
   539 	rootFolder->SetComplete(ETrue);
       
   540 	
       
   541 	
       
   542 	// 6. Fetch child of LocalServices
       
   543 	childrenOfRoot.Reset();
       
   544 	iDbAdapter->GetChildrenL(KMsvLocalServiceIndexEntryId, childrenOfRoot);
       
   545 	
       
   546 	CMsvCacheVisibleFolder* localFolder = CMsvCacheVisibleFolder::NewL(KMsvLocalServiceIndexEntryId);
       
   547 	iFolderListHeader.AddFirst(*localFolder);
       
   548 		
       
   549 	// 7. Add children to cache.
       
   550 	localFolder->AddEntryListL(childrenOfRoot);
       
   551 	// 7.1 Update progress
       
   552 	iProgress.iCompleted = iProgress.iTotal;
       
   553 	iProgress.iRemaining = 0;
       
   554 	iProgress.iId = KMsvGlobalInBoxIndexEntryId;
       
   555 	
       
   556 	// 8. Set the visible folder as complete
       
   557 	localFolder->SetComplete(ETrue);
       
   558 	childrenOfRoot.Close();
       
   559 	}
       
   560 	
       
   561 
       
   562 
       
   563 /**
       
   564 GetInPreparationIds
       
   565 */
       
   566 void CMsvIndexAdapter::GetInPreparationIds(CMsvEntrySelection& aSelection)
       
   567 	{
       
   568 	if(iDbAdapter)
       
   569 		{
       
   570 		TRAP_IGNORE(iDbAdapter->GetInPreparationIdL(aSelection));
       
   571 		}	
       
   572 	}
       
   573 
       
   574 
       
   575 #endif 		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   576 
       
   577 
       
   578 /**
       
   579  *CompleteSelf
       
   580  *This will make sure that Runl is called.
       
   581  */
       
   582 void CMsvIndexAdapter::CompleteSelf()
       
   583 	{
       
   584 	iStatus=KRequestPending;
       
   585 	SetActive();
       
   586 	TRequestStatus* st=&iStatus;
       
   587 	User::RequestComplete(st, KErrNone);
       
   588 	}
       
   589 
       
   590 
       
   591 
       
   592 /**
       
   593  * RunL()
       
   594  */
       
   595 void CMsvIndexAdapter::RunL()
       
   596 	{
       
   597 	// Set the state for the background state machine.
       
   598 	iBackgroundOperationState = ERemoveDeletedEntries;
       
   599 	iBackgroundOperationPerformed = 0;
       
   600 	}
       
   601 	
       
   602 
       
   603 
       
   604 
       
   605 /**
       
   606  * DoCancel()
       
   607  */
       
   608 void CMsvIndexAdapter::DoCancel()
       
   609 	{
       
   610 	iIdle->Cancel();	
       
   611 	}
       
   612 
       
   613 
       
   614 
       
   615 
       
   616 /**
       
   617  * AddEntry()
       
   618  */
       
   619 TInt CMsvIndexAdapter::AddEntry(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId)
       
   620 	{
       
   621 	TRAPD(err, DoAddEntryL(aEntry, aOwnerId, aAutoAssignId));
       
   622 	return err;
       
   623 	}
       
   624 
       
   625 
       
   626 /**
       
   627  * AddEntryNoCommit()
       
   628  */
       
   629 TInt CMsvIndexAdapter::AddEntryNoCommit(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId)
       
   630 	{
       
   631 	if(iDbAdapter)
       
   632 		{
       
   633 		TRAP_IGNORE(iDbAdapter->BeginTransactionL());
       
   634 		}
       
   635 	else
       
   636 		{
       
   637 		return ErrorState();
       
   638 		}
       
   639 	TRAPD(err, DoAddEntryL(aEntry, aOwnerId, aAutoAssignId, EFalse));
       
   640 	if(err)
       
   641 		{
       
   642 		RollbackAdditions();
       
   643 		}
       
   644 	return err;
       
   645 	}
       
   646 
       
   647 
       
   648 
       
   649 /**
       
   650  * DoAddEntryL()
       
   651  * 
       
   652  * Add the entry to the index and then the file. 
       
   653  * If either fails the function leaves. Creates 
       
   654  * its own copy of TMsvEntry (SetEntryL() code). 
       
   655  * This can be optimized further.
       
   656  */
       
   657 void CMsvIndexAdapter::DoAddEntryL(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId, TBool aCommitToDb)
       
   658 	{
       
   659 	// Leave if the message store is not currently available.
       
   660     User::LeaveIfError(iErrorState);
       
   661     
       
   662 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   663 	// get and set the unique id
       
   664 	if (aAutoAssignId)
       
   665 		{
       
   666 		aEntry.SetId(NextId(GetDriveId(aEntry.Parent())));
       
   667 		}
       
   668 
       
   669 	if (aEntry.iType == KUidMsvServiceEntry)
       
   670 		{
       
   671 		if(KMsvLocalServiceIndexEntryId == UnmaskTMsvId(aEntry.iId))
       
   672 			{
       
   673 			aEntry.iServiceId = KMsvLocalServiceIndexEntryId;
       
   674 			}
       
   675 		else
       
   676 			{
       
   677 			aEntry.iServiceId = aEntry.Id();
       
   678 			}
       
   679 		}
       
   680 #else		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   681 	if (aAutoAssignId)
       
   682 		{
       
   683 		aEntry.SetId(NextId());
       
   684 		}
       
   685 
       
   686 	if (aEntry.iType == KUidMsvServiceEntry)
       
   687 		{
       
   688 		aEntry.iServiceId = aEntry.Id();
       
   689 		}
       
   690 #endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   691 
       
   692 	CMsvCacheEntry* parentEntry = NULL;
       
   693 	FindEntryL(aEntry.Parent(), parentEntry);
       
   694 
       
   695 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   696 	if(UnmaskTMsvId(aEntry.iId) == KMsvDeletedEntryFolderEntryId)
       
   697 		{
       
   698 		aEntry.SetVisibleFolderFlag(ETrue);
       
   699 		}
       
   700 	else	
       
   701 #endif
       
   702 		{		
       
   703 		// If entry is set to visible while creation, then set the visible folder
       
   704 		// flag to ETrue, this will not change for the lifetime of an TMsvEntry.
       
   705 		if(parentEntry->Entry().VisibleFolderFlag())
       
   706 			{
       
   707 			if( (aEntry.Visible()) && 
       
   708 			    (aEntry.iType == KUidMsvFolderEntry || aEntry.iType == KUidMsvServiceEntry)
       
   709 			  )
       
   710 				{
       
   711 				aEntry.SetVisibleFolderFlag(ETrue);
       
   712 				}
       
   713 			else
       
   714 				{
       
   715 				aEntry.SetVisibleFolderFlag(EFalse);
       
   716 				}				
       
   717 			}
       
   718 		else
       
   719 			{
       
   720 			aEntry.SetVisibleFolderFlag(EFalse);
       
   721 			}
       
   722 		}
       
   723 		
       
   724 	aEntry.SetOwner(EFalse);
       
   725 	TMsvId visibleFolderId;
       
   726 	if(!GetVisibleFolderId(aEntry.Parent(), visibleFolderId))
       
   727 		{
       
   728 		User::Leave(KErrNotFound);
       
   729 		}
       
   730     
       
   731 	// Add entry to cache.      
       
   732     CMsvCacheEntry* newCacheEntry = NULL;   
       
   733     newCacheEntry = iFreePoolInstance->EntryL();
       
   734     // Set the owner ID of the entry - the SID of the owning process.
       
   735     newCacheEntry->SetEntryOwnerId(aOwnerId);
       
   736     
       
   737     CMsvCacheVisibleFolder* visibleFolder = NULL;
       
   738     TRAPD(err, newCacheEntry->SetEntryL(aEntry);
       
   739                visibleFolder = AddEntryToCacheL(visibleFolderId, newCacheEntry);
       
   740          );
       
   741     if(err)
       
   742         {
       
   743         iFreePoolInstance->ReleaseEntryWithoutTransaction(newCacheEntry);
       
   744         User::Leave(err);
       
   745         }
       
   746 
       
   747 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
   748     TRAP(err,
       
   749             if(aCommitToDb)
       
   750                 iDbAdapter->BeginTransactionL();
       
   751             iDbAdapter->CreateEntryL(aEntry, visibleFolderId);
       
   752             // Set the owner flag of parent entry if not already done.
       
   753             // For standard entry created from indexContext, parent Id will not be masked.
       
   754             iDbAdapter->UpdateOwnerStatusL(MaskTMsvId(GetDriveId(aEntry.iId), aEntry.Parent()), parentEntry->Entry(), ETrue);
       
   755             if(aCommitToDb)
       
   756                 iDbAdapter->CommitTransactionL();
       
   757         );
       
   758 #else
       
   759     TRAP(err,
       
   760             if(aCommitToDb)
       
   761                 iDbAdapter->BeginTransactionL();
       
   762             iDbAdapter->CreateEntryL(aEntry, visibleFolderId);
       
   763             // Set the owner flag of parent entry if not already done.
       
   764             // For standard entry created from indexContext, parent Id will not be masked.
       
   765             iDbAdapter->UpdateOwnerStatusL(aEntry.Parent(), parentEntry->Entry(), ETrue);
       
   766             if(aCommitToDb)
       
   767                 iDbAdapter->CommitTransactionL();
       
   768         );
       
   769 #endif  
       
   770     if(err & KSqlErrConstraint != err)
       
   771         {
       
   772         if(aCommitToDb)
       
   773             iDbAdapter->RollbackTransactionL();
       
   774         // This will not leave...
       
   775         TRAP_IGNORE(visibleFolder->DeleteEntryL(newCacheEntry->GetId()));
       
   776         User::Leave(err);
       
   777         }	
       
   778 	parentEntry->Entry().SetOwner(ETrue);
       
   779 
       
   780 	if(!aCommitToDb)
       
   781 		{
       
   782 		// Add entry to the list of non-committed entries.
       
   783 		CNonCommittedAddedEntries* nonCommittedAddedEntries = new(ELeave)CNonCommittedAddedEntries(visibleFolderId, newCacheEntry);
       
   784 		CleanupStack::PushL(nonCommittedAddedEntries);
       
   785 		iNonCommittedAddedEntryList.AppendL(nonCommittedAddedEntries);
       
   786 		CleanupStack::Pop(nonCommittedAddedEntries);
       
   787 		}
       
   788 
       
   789 	if(aEntry.iType.iUid == KUidMsvMessageEntryValue && CMSvSearchSortCacheManager::Instance()->iManagerEntry != NULL)
       
   790 		{	
       
   791 		TMsgType aType(ENewMsg);
       
   792 		if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0)
       
   793 			{
       
   794 			CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aEntry.Id(),aType);
       
   795 			}
       
   796 		}	
       
   797 	}
       
   798 	
       
   799 	
       
   800 
       
   801 
       
   802 /**
       
   803  * GetVisibleFolderId()
       
   804  * 
       
   805  * Returns ETrue, if the parent entry exists. Otherwise returns EFalse.
       
   806  * IN: Parent Id of the entry, whose immediate visible folder has to be found.
       
   807  * OUT: Visible folder Id.
       
   808  */
       
   809 TBool CMsvIndexAdapter::GetVisibleFolderId(TMsvId aParentId, TMsvId& aVisibleFolderId)
       
   810 	{
       
   811 	// If the entry is either a root entry (parent=KErrNotFound) or 
       
   812 	// child of root entry its visibleFolderId will be root entry itself.
       
   813 	if((KErrNotFound == aParentId) || (KMsvRootIndexEntryId == aParentId))
       
   814 		{
       
   815 		aVisibleFolderId = KMsvRootIndexEntryId;
       
   816 		return ETrue;
       
   817 		}
       
   818 	
       
   819 	// Get the visible flag of parent entry.
       
   820 	
       
   821 	// If parent entry is visible, then immediateVisibleFolder of child
       
   822 	// should be parent Id. And if it is invisible then child's immediateVisibleFolder 
       
   823 	// should be same as parent's immediateVisibleFolder.
       
   824 	// First check in cache.
       
   825 	if(!iFolderListHeader.IsEmpty())
       
   826 		{
       
   827 		CMsvCacheVisibleFolder* folderNode = NULL;
       
   828 		TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
   829 		dqIter.SetToFirst(); 
       
   830 		while((folderNode = dqIter++)!=NULL)
       
   831 			{
       
   832 			// Check if the current folder node is parent.
       
   833 			if( aParentId == folderNode->GetFolderId() )
       
   834 				{
       
   835 				aVisibleFolderId = aParentId;
       
   836 				return ETrue;
       
   837 				}
       
   838 			}
       
   839 		dqIter.SetToFirst(); 
       
   840 		CMsvCacheEntry* entry;
       
   841 		while((folderNode = dqIter++)!=NULL)
       
   842 			{
       
   843 			// Check if the current folder node is parent.
       
   844 			if(folderNode->GetEntry(aParentId, entry))
       
   845 				{
       
   846 				if(entry->Entry().VisibleFolderFlag())
       
   847 					{
       
   848 					aVisibleFolderId = aParentId;
       
   849 					}
       
   850 				else
       
   851 					{
       
   852 					//If the visible folder is not the parent, then
       
   853 					//the current folder must be the visible folder,
       
   854 					//as otherwise the parent would have been under another
       
   855 					//folder node.
       
   856 					aVisibleFolderId = folderNode->GetFolderId();
       
   857 					}
       
   858 				return ETrue;
       
   859 				}
       
   860 			}
       
   861 		}
       
   862 	
       
   863 	// Entry cannot be found in cache,
       
   864 	// Now search in DB.
       
   865 	TInt err = KErrNone;
       
   866 	if(iDbAdapter)
       
   867 		{
       
   868 		TRAP(err, iDbAdapter->GetVisibleFolderIdL(aParentId, aVisibleFolderId));
       
   869 		}
       
   870 	else
       
   871 		{
       
   872 		return EFalse;
       
   873 		}
       
   874 	if(KErrNone == err)
       
   875 		{
       
   876 		return ETrue; 		
       
   877 		}
       
   878 	return EFalse;		
       
   879 	}
       
   880 
       
   881 
       
   882 
       
   883 
       
   884 
       
   885 /**
       
   886  * DeleteEntry()
       
   887  */
       
   888 TInt CMsvIndexAdapter::DeleteEntry(TMsvId aId)
       
   889 	{
       
   890 	CMsvEntrySelection* selection = NULL;
       
   891 	
       
   892 	TRAPD(error, selection = new(ELeave)CMsvEntrySelection; selection->AppendL(aId););
       
   893 	if(KErrNone == error)
       
   894 		{
       
   895 		error = DeleteSelection(*selection);
       
   896 		}
       
   897 
       
   898 	TMsgType aType(EDeletedMsg);
       
   899 	if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0 && error == KErrNone)
       
   900 		{
       
   901 		CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aId,aType);
       
   902 		}
       
   903 
       
   904 	delete selection;
       
   905 	return error;
       
   906 	}
       
   907 
       
   908 
       
   909 
       
   910 
       
   911 
       
   912 /**
       
   913  * DeleteSelection
       
   914  * Deletes a selection of entries.
       
   915  *
       
   916  * @param aSelection Selection of TMsvIds of the entries to be deleted
       
   917  * @return TInt System-wide error code.
       
   918  */
       
   919 TInt CMsvIndexAdapter::DeleteSelection(const CMsvEntrySelection& aSelection)
       
   920 	{
       
   921 	TInt count = aSelection.Count();
       
   922 
       
   923 	if(!iDbAdapter)
       
   924 		{
       
   925 		return ErrorState();
       
   926 		}
       
   927 	// Only start a transaction if there are more than 1 entries to be deleted.
       
   928 	if(count > 1)
       
   929 		{
       
   930 		TRAP_IGNORE(iDbAdapter->BeginTransactionL());		
       
   931 		}
       
   932 	// If the transaction is opened, deleted
       
   933 	// entry will be released temporarily.
       
   934 	iFreePoolInstance->BeginTransaction();
       
   935 	TInt error = KErrNone;
       
   936 	TRAP(error, DoDeleteSelectionL(aSelection));
       
   937 	if (error)
       
   938 		{
       
   939 		if(count > 1)
       
   940 			{
       
   941 			TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
       
   942 			}
       
   943 		iFreePoolInstance->RollbackTransaction();
       
   944 		}
       
   945 	else
       
   946 		{
       
   947 		if(count > 1)
       
   948 			{
       
   949 			TRAP_IGNORE(iDbAdapter->CommitTransactionL());
       
   950 			}	
       
   951 		iFreePoolInstance->CommitTransaction();
       
   952 		}
       
   953 	return error;
       
   954 	}
       
   955 
       
   956 
       
   957 
       
   958 
       
   959 
       
   960 /**
       
   961  * DoDeleteSelectionL
       
   962  */
       
   963 void CMsvIndexAdapter::DoDeleteSelectionL(const CMsvEntrySelection& aSelection)
       
   964 	{
       
   965 	User::LeaveIfError(iErrorState);
       
   966 	CMsvCacheVisibleFolder* folderNode = NULL;
       
   967 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
   968 	const TInt count = aSelection.Count();
       
   969 	if(count <= 0)
       
   970 		{
       
   971 		return;
       
   972 		}
       
   973 	
       
   974 	CMsvCacheEntry* entry = NULL;
       
   975 	TBool releaseEntry = FindEntryL(aSelection.At(0), entry, EFalse);
       
   976 	TMsvId parentId = entry->Entry().Parent();
       
   977 	if(releaseEntry)
       
   978 		{
       
   979 		iFreePoolInstance->ReleaseEntry(entry, ETrue);
       
   980 		}
       
   981 	CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
       
   982 	CleanupStack::PushL(children);
       
   983 	
       
   984 	for (TInt index=0; index<count; ++index)
       
   985 		{
       
   986 		dqIter.SetToFirst(); 
       
   987 		TBool found = EFalse;
       
   988 		while((folderNode = dqIter++)!=NULL)
       
   989 			{
       
   990 			TRAPD(err, folderNode->DeleteEntryL(aSelection.At(index)));	
       
   991 			if(err != KErrNotFound && err != KErrNone)
       
   992 				{
       
   993 				User::Leave(err);
       
   994 				}
       
   995 			 else if(err == KErrNone)	
       
   996 			 	{
       
   997 			 	found = ETrue;
       
   998 			 	break;
       
   999 			 	}
       
  1000 			}
       
  1001 		if(!found)
       
  1002 			{
       
  1003 			if(iDbAdapter)
       
  1004 				{
       
  1005 				if(iDbAdapter->EntryExistsL(aSelection.At(index)))
       
  1006 					{
       
  1007 					User::Leave(KErrAccessDenied);
       
  1008 					}
       
  1009 				}
       
  1010 			else
       
  1011 				{
       
  1012 				User::Leave(ErrorState());	
       
  1013 				}
       
  1014 			User::Leave(KErrNotFound);
       
  1015 			}
       
  1016 		
       
  1017 		if(iDbAdapter)
       
  1018 			{
       
  1019 			iDbAdapter->DeleteEntryL(aSelection.At(index));
       
  1020 			}
       
  1021 		else
       
  1022 			{
       
  1023 			User::Leave(ErrorState());	
       
  1024 			}
       
  1025 		}
       
  1026 	//Find the parent entry in cache and check for any children.
       
  1027 	//If there are no more children under the parent, then
       
  1028 	//reset the owner flag in cache and database.
       
  1029 	TRAPD(err, releaseEntry = FindEntryL(parentId, entry, EFalse));
       
  1030 	//If parent was also deleted then nothing left to do.
       
  1031 	if(err == KErrNotFound)
       
  1032 		{
       
  1033 		CleanupStack::PopAndDestroy(); //children
       
  1034 		return;
       
  1035 		}
       
  1036 	TRAP(err, 
       
  1037 		GetChildrenIdL(parentId, *children);
       
  1038 		if(0 == children->Count() && entry->Entry().Owner())
       
  1039 			{
       
  1040 			if(iDbAdapter)
       
  1041 				{
       
  1042 				iDbAdapter->UpdateOwnerStatusL(parentId, entry->Entry(), EFalse);		
       
  1043 				}
       
  1044 			else
       
  1045 				{
       
  1046 				User::Leave(ErrorState());
       
  1047 				}
       
  1048 			entry->Entry().SetOwner(EFalse);
       
  1049 			}
       
  1050 		);
       
  1051 	// Release the entry, since it is not added to cache.
       
  1052 	if(releaseEntry)
       
  1053 		{
       
  1054 		iFreePoolInstance->ReleaseEntry(entry, ETrue);
       
  1055 		}
       
  1056 	User::LeaveIfError(err);
       
  1057 	CleanupStack::PopAndDestroy(); //children
       
  1058 	}
       
  1059 
       
  1060 
       
  1061 
       
  1062 
       
  1063 
       
  1064 /**
       
  1065  * ExpandSelectionRecursively()
       
  1066  * Expands a selection to include all the descendents of the entries. They are order
       
  1067  * in such a way that they can be deleted in order, children first
       
  1068  *
       
  1069  * @param aSelection CMsvEntrySelection, which contains the TMsvIds of the entry passed.
       
  1070  * @return TInt System wide error code.
       
  1071  */
       
  1072 TInt CMsvIndexAdapter::ExpandSelectionRecursively(CMsvEntrySelection& aSelection)
       
  1073 	{
       
  1074 	TInt error = KErrNone;
       
  1075 	iOrigEntryPos=0;
       
  1076 	iRecursionSelection=&aSelection;
       
  1077 	TInt count = aSelection.Count();
       
  1078 	while (iOrigEntryPos < count)
       
  1079 		{
       
  1080 		TMsvId entryId = aSelection.At(iOrigEntryPos);
       
  1081 		if( !EntryExists(entryId) )
       
  1082 			{
       
  1083 			error = KErrNotFound;
       
  1084 			aSelection.Delete(iOrigEntryPos);
       
  1085 			}
       
  1086 		else
       
  1087 			{
       
  1088 			// if the entry has children
       
  1089 			CMsvEntrySelection* children = NULL;
       
  1090 			TRAPD(err, children = new (ELeave)CMsvEntrySelection);
       
  1091 			if(KErrNone != err)
       
  1092 				{
       
  1093 				return err;
       
  1094 				}
       
  1095 			TInt leave = KErrNone;
       
  1096 			TRAP(leave, GetChildrenIdL(entryId, *children));
       
  1097 			if(KErrNone != leave)
       
  1098 				{
       
  1099 				delete children;
       
  1100 				return leave;				
       
  1101 				}
       
  1102 			TInt count = children->Count();
       
  1103 			for(TInt index=0; index<count; ++index)
       
  1104 				{
       
  1105 				iRecursionIndex = iOrigEntryPos;
       
  1106 				TRAP(leave, DoExpandSelectionRecursivelyL(children->At(index)));
       
  1107 				if(KErrNone != leave)
       
  1108 					{
       
  1109 					delete children;
       
  1110 					return leave;
       
  1111 					}
       
  1112 				}
       
  1113 			delete children;	
       
  1114 			++iOrigEntryPos;
       
  1115 			}
       
  1116 		}
       
  1117 	return error;
       
  1118 	}
       
  1119 
       
  1120 
       
  1121 
       
  1122 
       
  1123 
       
  1124 /**
       
  1125  * DoExpandSelectionRecursivelyL
       
  1126  * Expands a selection to include all the descendents of the entry with TMsvId aId. 
       
  1127  *
       
  1128  * @param aId TMsvId of the entire
       
  1129  * @return void
       
  1130  */
       
  1131 void CMsvIndexAdapter::DoExpandSelectionRecursivelyL(TMsvId aId)
       
  1132 	{
       
  1133 	// include this entry
       
  1134 	iRecursionSelection->InsertL(iRecursionIndex,aId);
       
  1135 	iOrigEntryPos++;
       
  1136 	
       
  1137 	// if aEntry has children
       
  1138 	CMsvEntrySelection* children = new (ELeave)CMsvEntrySelection;
       
  1139 	CleanupStack::PushL(children);
       
  1140 	
       
  1141 	GetChildrenIdL(aId, *children);
       
  1142 	
       
  1143 	TInt count = children->Count();
       
  1144 	for(TInt index=0; index<count; ++index)
       
  1145 		{
       
  1146 		DoExpandSelectionRecursivelyL(children->At(index));
       
  1147 		}
       
  1148 	
       
  1149 	CleanupStack::PopAndDestroy(1, children);	//children
       
  1150 	}
       
  1151 
       
  1152 
       
  1153 
       
  1154 /**
       
  1155  * GetChildrenId()
       
  1156  * @param TMsvId: Id os the parent.
       
  1157  * @param CMsvEntrySelection: List of child Ids.
       
  1158  * 
       
  1159  * This function should be used only by ExpandSelectionRecursively()
       
  1160  * and DoExpandSelectionRecursivelyL().
       
  1161  * --- 557 ---
       
  1162  * If aId is an standard id ensure that it is masked. If the aId is
       
  1163  * not masked the function will return children from current drive.
       
  1164  */
       
  1165 void CMsvIndexAdapter::GetChildrenIdL(TMsvId aId, CMsvEntrySelection& aSelection)
       
  1166 	{
       
  1167 	CMsvCacheVisibleFolder* folderNode = NULL;	
       
  1168 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  1169 
       
  1170 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1171 	if(IsStandardId(aId))
       
  1172 		{
       
  1173 		TUint driveId = GetDriveId(aId);
       
  1174 		TMsvId unmaskedId = UnmaskTMsvId(aId);
       
  1175 		
       
  1176 		dqIter.SetToFirst();	
       
  1177 		// Look for the entry in cache.
       
  1178 		if(!iFolderListHeader.IsEmpty())
       
  1179 			{
       
  1180 			while(NULL != (folderNode = dqIter++))
       
  1181 				{
       
  1182 				if((unmaskedId == folderNode->GetFolderId()) && (driveId == folderNode->GetDrive()))
       
  1183 					{
       
  1184 					if(!folderNode->GetChildrenIdL(aSelection))
       
  1185 						{
       
  1186 						if(iDbAdapter)
       
  1187 							{
       
  1188 							iDbAdapter->GetChildrenIdL(aId, aSelection);
       
  1189 							}
       
  1190 						else
       
  1191 							{
       
  1192 							User::Leave(ErrorState());
       
  1193 							}
       
  1194 						}
       
  1195 					return;
       
  1196 					}
       
  1197 				}
       
  1198 			}
       
  1199 		if(iDbAdapter)
       
  1200 			{
       
  1201 			iDbAdapter->GetChildrenIdL(aId, aSelection);
       
  1202 			}
       
  1203 		else
       
  1204 			{
       
  1205 			User::Leave(ErrorState());
       
  1206 			}
       
  1207 		return;
       
  1208 		}
       
  1209 #endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1210 
       
  1211 	dqIter.SetToFirst();	
       
  1212 	// Look for the entry in cache.
       
  1213 	if(!iFolderListHeader.IsEmpty())
       
  1214 		{
       
  1215 		// Check if aId is one of the visible folder,
       
  1216 		// already present in the cache.
       
  1217 		while(NULL != (folderNode = dqIter++))
       
  1218 			{
       
  1219 			if(aId == folderNode->GetFolderId())
       
  1220 				{
       
  1221 				// Fetch children. Returns EFalse if unable
       
  1222 				// to get them.
       
  1223 				if(!folderNode->GetChildrenIdL(aSelection))
       
  1224 					{
       
  1225 					if(iDbAdapter)
       
  1226 						{
       
  1227 						// Childrens not fetched. Get them from DB.
       
  1228 						iDbAdapter->GetChildrenIdL(aId, aSelection);
       
  1229 						}
       
  1230 					else
       
  1231 						{
       
  1232 						User::Leave(ErrorState());	
       
  1233 						}
       
  1234 					}
       
  1235 				return;
       
  1236 				}
       
  1237 			}
       
  1238 
       
  1239 		// Entry is not present in the visibleFolder list.
       
  1240 		CMsvCacheEntry* entry = NULL;
       
  1241 		if(FindEntryInCache(aId, entry))
       
  1242 			{
       
  1243 			if(NULL != entry->ChildIdArray())
       
  1244 				{
       
  1245 				RArray<TMsvId>* childId = entry->ChildIdArray();
       
  1246 				TInt size = childId->Count();
       
  1247 				TInt index = 0;
       
  1248 				while(index < size)
       
  1249 					{
       
  1250 					aSelection.AppendL((*childId)[index++]);
       
  1251 					}
       
  1252 				return;	
       
  1253 				}
       
  1254 			else
       
  1255 				{
       
  1256 				if(iDbAdapter)
       
  1257 					{
       
  1258 					iDbAdapter->GetChildrenIdL(aId, aSelection);
       
  1259 					}
       
  1260 				else
       
  1261 					{
       
  1262 					User::Leave(ErrorState());	
       
  1263 					}
       
  1264 				RArray<TMsvId>* childId = new(ELeave) RArray<TMsvId>;
       
  1265 				TInt size = aSelection.Count();
       
  1266 				TInt index = 0;
       
  1267 				while(index < size)
       
  1268 					{
       
  1269 					TInt err = childId->Append(aSelection[index++]);
       
  1270 					if(KErrNone != err)
       
  1271 						{
       
  1272 						childId->Reset();
       
  1273 						childId->Close();
       
  1274 						delete childId;
       
  1275 						User::Leave(err);
       
  1276 						}
       
  1277 					}
       
  1278 				entry->SetChildIdArray(childId);
       
  1279 				return;
       
  1280 				}
       
  1281 			}
       
  1282 		}
       
  1283 	
       
  1284 	// Could not find parent entry in cache.
       
  1285 	// Check in DB now.	
       
  1286 	if(iDbAdapter)
       
  1287 		{
       
  1288 		iDbAdapter->GetChildrenIdL(aId, aSelection);
       
  1289 		}
       
  1290 	else
       
  1291 		{
       
  1292 		User::Leave(ErrorState());	
       
  1293 		}
       
  1294 	}
       
  1295 
       
  1296 
       
  1297 
       
  1298 
       
  1299 /**
       
  1300  * ChangeEntry
       
  1301  * Change the contents of a TMsvEntry. 
       
  1302  * 
       
  1303  */
       
  1304 TInt CMsvIndexAdapter::ChangeEntry(const TMsvEntry& aEntry, TSecureId aOwnerId, TBool aForcedUpdate)
       
  1305 	{
       
  1306 	TRAPD(err, DoChangeEntryL(aEntry, aOwnerId, EFalse, aForcedUpdate, ETrue));
       
  1307 	return err;
       
  1308 	}
       
  1309 
       
  1310 
       
  1311 /**
       
  1312  * ChangeEntryNoCommit
       
  1313  */
       
  1314 TInt CMsvIndexAdapter::ChangeEntryNoCommit(const TMsvEntry& aEntry, TSecureId aOwnerId, TBool aForcedUpdate)
       
  1315 	{
       
  1316 	if(!iDbAdapter)
       
  1317 		{
       
  1318 		return ErrorState();
       
  1319 		}
       
  1320 	
       
  1321 	TRAP_IGNORE(iDbAdapter->BeginTransactionL());
       
  1322 	TRAPD(err, DoChangeEntryL(aEntry, aOwnerId, EFalse, aForcedUpdate, EFalse));
       
  1323 	if(err)
       
  1324 		{
       
  1325 		RollbackChanges();
       
  1326 		}
       
  1327 	return err;
       
  1328 	}
       
  1329 	
       
  1330 
       
  1331 /**
       
  1332  * ChangeEntryInternal()
       
  1333  */
       
  1334 TInt CMsvIndexAdapter::ChangeEntryInternal(const TMsvEntry& aEntry, TSecureId aOwnerId)
       
  1335 	{
       
  1336 	TRAPD(err, DoChangeEntryL(aEntry, aOwnerId, ETrue, EFalse, ETrue));
       
  1337 	return err;
       
  1338 	}
       
  1339 
       
  1340 
       
  1341 
       
  1342 /**
       
  1343  * DoChangeEntryL
       
  1344  */	
       
  1345 void CMsvIndexAdapter::DoChangeEntryL(const TMsvEntry& aNewEntryContents, TSecureId aOwnerId, TBool aChangeStandardFolder, TBool aForcedUpdate, TBool aCommitToFile)
       
  1346     {
       
  1347     // Leave if the message store is not currently available
       
  1348     User::LeaveIfError(iErrorState);
       
  1349 
       
  1350     // 1. Handle root entry differently.
       
  1351     if(aNewEntryContents.Id() == KMsvRootIndexEntryId)
       
  1352         {
       
  1353         TMsvEntry& entry = const_cast<TMsvEntry&> (aNewEntryContents);
       
  1354         iDbAdapter->UpdateEntryL(entry, KMsvRootIndexEntryId, EFalse);
       
  1355         iRootEntry->Entry() = entry;
       
  1356         return;
       
  1357         }
       
  1358 
       
  1359     // 2. Find entry in cache.
       
  1360     CMsvCacheEntry* oldEntry = NULL;    
       
  1361     CMsvCacheVisibleFolder* oldFolderNode = NULL;
       
  1362     GetVisibleFolderDetailsL(aNewEntryContents.Id(), oldEntry, oldFolderNode);
       
  1363   
       
  1364     // 3. Validate entry.
       
  1365     // If the entry is not present in cache, it means it is not locked.
       
  1366     // Can only change a locked entry and not one marked as a standard 
       
  1367     // folder unless aChangeStandardFolder is true.
       
  1368     if( (!oldEntry->IsEntryLocked()) || (aChangeStandardFolder==EFalse && oldEntry->Entry().StandardFolder()) )
       
  1369         {
       
  1370         User::Leave(KErrAccessDenied);
       
  1371         }
       
  1372 
       
  1373     // Reserving space in changed entry list array.
       
  1374     if(!aCommitToFile)
       
  1375         {
       
  1376         iNonCommittedChangedEntryList.ReserveL(iNonCommittedChangedEntryList.Count()+1);
       
  1377         }
       
  1378 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1379     // We do not support movement of entry to a folder present in a different drive.    
       
  1380     if( oldEntry->Entry().Parent() != KErrNotFound &&   //-1 will appear to be masked. disregard this.
       
  1381         GetDriveId(aNewEntryContents.Id()) != GetDriveId(oldEntry->Entry().Parent()))
       
  1382         {
       
  1383         User::Leave(KErrNotSupported);  
       
  1384         }
       
  1385 #endif
       
  1386 
       
  1387     TMsvId oldParentId = oldEntry->Entry().Parent();
       
  1388     TMsvId oldVisibleFolderId = oldFolderNode->GetFolderId();
       
  1389 
       
  1390     // Check if the parent id is also changed.
       
  1391     CMsvCacheEntry* oldParentEntry = NULL;
       
  1392     CMsvCacheEntry* newParentEntry = NULL;
       
  1393     TBool resetOldParentOwnerFlag = EFalse;
       
  1394     CMsvEntrySelection* descendentList = NULL;
       
  1395     TMsvId newParentId = aNewEntryContents.Parent();
       
  1396     CMsvCacheVisibleFolder* newVisibleFolderNode = NULL;
       
  1397     if(oldParentId != newParentId)
       
  1398         {
       
  1399         // YES, PARENT ID IS CHANGED.
       
  1400         // These steps are similar to MoveEntry()
       
  1401         newVisibleFolderNode = DoChangeEntryPreambleL(oldEntry,
       
  1402                                                       newParentId,
       
  1403                                                       oldParentEntry,
       
  1404                                                       newParentEntry,
       
  1405                                                       oldVisibleFolderId,
       
  1406                                                       resetOldParentOwnerFlag,
       
  1407                                                       descendentList
       
  1408                                                      );
       
  1409         }   // if(oldParentId != newParentId)
       
  1410     TMsvId newVisibleFolderId = newVisibleFolderNode ? newVisibleFolderNode->GetFolderId() : oldVisibleFolderId;
       
  1411     // Update entry in cache.
       
  1412     TBool changedPrivateInfo;
       
  1413     CMsvCacheEntry* bkpEntry = NULL;
       
  1414     TRAPD(err, bkpEntry = iFreePoolInstance->EntryL();
       
  1415                bkpEntry->SetEntryL(oldEntry->Entry());
       
  1416                bkpEntry->SetEntryOwnerId(oldEntry->EntryOwnerId());
       
  1417                oldEntry->CopyEntryL(aNewEntryContents, changedPrivateInfo);
       
  1418          );
       
  1419     if(err)
       
  1420         {
       
  1421         iFreePoolInstance->ReleaseEntryWithoutTransaction(bkpEntry);
       
  1422         if(newVisibleFolderNode)
       
  1423             newVisibleFolderNode->DeleteEntryL(oldEntry->GetId());
       
  1424         User::Leave(err);
       
  1425         }
       
  1426     UpdateDates(*oldEntry, EFalse);
       
  1427     if(aNewEntryContents.Connected())
       
  1428         {
       
  1429         oldEntry->Entry().SetConnected(EFalse);
       
  1430         }
       
  1431     if(aForcedUpdate || changedPrivateInfo && aOwnerId != KMsvServerId )
       
  1432         {
       
  1433         oldEntry->SetEntryOwnerId(aOwnerId);
       
  1434         }
       
  1435 
       
  1436     TRAP(err, 
       
  1437             if(aCommitToFile)
       
  1438                 iDbAdapter->BeginTransactionL();
       
  1439             // Update the actual entry
       
  1440             if(oldParentId != newParentId)
       
  1441                 {
       
  1442                 iDbAdapter->UpdateEntryL(oldEntry->Entry(), newVisibleFolderId);
       
  1443                 }
       
  1444             else
       
  1445                 {
       
  1446                 iDbAdapter->UpdateEntryL(oldEntry->Entry(), newVisibleFolderId, EFalse);
       
  1447                 }
       
  1448             // Reset old parent owner flag.
       
  1449             if(resetOldParentOwnerFlag)
       
  1450                 iDbAdapter->UpdateOwnerStatusL(oldParentId, oldParentEntry->Entry(), EFalse);
       
  1451             // Set new parent owner flag.
       
  1452             if(newParentEntry && (!newParentEntry->Entry().Owner()))
       
  1453                 iDbAdapter->UpdateOwnerStatusL(newParentId, newParentEntry->Entry(), ETrue);
       
  1454             // Update the child entries visibleFolderId in DB.
       
  1455             if(descendentList)
       
  1456                 iDbAdapter->UpdateVisibleFolderL(descendentList, newVisibleFolderId);
       
  1457             if(aCommitToFile)
       
  1458                 iDbAdapter->CommitTransactionL();
       
  1459          );
       
  1460     if(err)
       
  1461         {
       
  1462         if(aCommitToFile)
       
  1463             TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
       
  1464         oldEntry->SetEntryOwnerId(bkpEntry->EntryOwnerId());
       
  1465         oldEntry->CopyEntryL(bkpEntry->Entry(), changedPrivateInfo);
       
  1466         iFreePoolInstance->ReleaseEntryWithoutTransaction(bkpEntry);
       
  1467         if(newVisibleFolderNode)    
       
  1468             newVisibleFolderNode->DeleteEntryL(oldEntry->GetId());
       
  1469         User::Leave(err);
       
  1470         }
       
  1471     // Nothing should fail after this. Ensure that 
       
  1472     // all leaving function after this does not leave.
       
  1473     if(aCommitToFile)
       
  1474         {
       
  1475         iFreePoolInstance->ReleaseEntryWithoutTransaction(bkpEntry);
       
  1476         DoChangeEntryPostamble(oldFolderNode, newVisibleFolderId, oldEntry->GetId(), descendentList, newParentEntry, oldParentEntry, resetOldParentOwnerFlag);
       
  1477         if(descendentList)
       
  1478             {
       
  1479             CleanupStack::PopAndDestroy(descendentList);
       
  1480             }
       
  1481         }   // if(aCommitToFile)
       
  1482     else
       
  1483         {
       
  1484         // Store relevant data for later commit.
       
  1485         TNonCommittedChangedEntries entryDetails(oldFolderNode, 
       
  1486                                                  newVisibleFolderNode, 
       
  1487                                                  oldEntry,
       
  1488                                                  bkpEntry,
       
  1489                                                  oldParentEntry, 
       
  1490                                                  newParentEntry,
       
  1491                                                  descendentList,
       
  1492                                                  resetOldParentOwnerFlag);
       
  1493         iNonCommittedChangedEntryList.Append(entryDetails);
       
  1494         if(descendentList)
       
  1495             CleanupStack::Pop(descendentList);
       
  1496         }
       
  1497 
       
  1498     // Update entry in SearchSort delta cache.
       
  1499     if(aNewEntryContents.iType.iUid == KUidMsvMessageEntryValue && CMSvSearchSortCacheManager::Instance()->iManagerEntry != NULL)
       
  1500         {
       
  1501         TMsgType aType(EUpdatedMsg);
       
  1502         if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0)
       
  1503             {
       
  1504             CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aNewEntryContents.Id(), aType);
       
  1505             }
       
  1506         }
       
  1507     }
       
  1508 
       
  1509 
       
  1510 
       
  1511 // Used only by DoChangeEntryL()
       
  1512 CMsvCacheVisibleFolder* CMsvIndexAdapter::DoChangeEntryPreambleL(CMsvCacheEntry*& aOldEntry, TMsvId aNewParentId, CMsvCacheEntry*& aOldParentEntry, CMsvCacheEntry*& aNewParentEntry, TMsvId aOldVisibleFolderId, TBool& aResetOldParentOwnerFlag, CMsvEntrySelection*& aDescendentList)
       
  1513     {
       
  1514     // YES, PARENT ID IS CHANGED.
       
  1515     // These steps are similar to MoveEntry()
       
  1516     TBool des;
       
  1517     IsADescendent(aOldEntry->Entry().Id(), aNewParentId, des);
       
  1518     if (des)
       
  1519         {
       
  1520         User::Leave(KErrArgument);
       
  1521         }
       
  1522    
       
  1523     // Fetch the parent entries.    
       
  1524     FindEntryL(aOldEntry->Entry().Parent(), aOldParentEntry);
       
  1525     FindEntryL(aNewParentId, aNewParentEntry);
       
  1526 
       
  1527     // Check if the owner flag of the old parent needs to be reset.    
       
  1528     CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
       
  1529     CleanupStack::PushL(children);
       
  1530     GetChildrenIdL(aOldEntry->Entry().Parent(), *children);
       
  1531     if(1 == children->Count() && aOldParentEntry->Entry().Owner())
       
  1532         {
       
  1533         aResetOldParentOwnerFlag = ETrue;
       
  1534         }
       
  1535     CleanupStack::PopAndDestroy(); //children
       
  1536     
       
  1537     // If required, pre-allocate memory for child array of newParentEntry.
       
  1538     if(aNewParentEntry->ChildIdArray())
       
  1539         {
       
  1540         // This to ensure that future append does not fail.
       
  1541         aNewParentEntry->ChildIdArray()->ReserveL(aNewParentEntry->ChildIdArray()->Count() + 1);
       
  1542         }
       
  1543 
       
  1544     // Find the visibleFolder of new parent. 
       
  1545     TMsvId newVisibleFolderId = NULL;
       
  1546     if(!GetVisibleFolderId(aNewParentId, newVisibleFolderId))
       
  1547          {
       
  1548          User::Leave(KErrNotFound);
       
  1549          }
       
  1550 
       
  1551     // Check if the visible folders are different.
       
  1552     CMsvCacheVisibleFolder* newVisibleFolderNode = NULL;
       
  1553     if(aOldVisibleFolderId != newVisibleFolderId)
       
  1554         {
       
  1555         // If the visible folders are different, check if
       
  1556         // child entries also needs to be moved.
       
  1557         if(!aOldEntry->Entry().VisibleFolderFlag())
       
  1558             {
       
  1559             // If yes, create a descendent list of the entry.
       
  1560             aDescendentList = new(ELeave) CMsvEntrySelection;
       
  1561             CleanupStack::PushL(aDescendentList);
       
  1562             aDescendentList->AppendL(aOldEntry->GetId());
       
  1563             User::LeaveIfError(ExpandSelectionRecursively(*aDescendentList));
       
  1564             }
       
  1565         
       
  1566         // Add duplicate entry under new visible folder. Removing 
       
  1567         // entry from old visible folder is done later.
       
  1568         CMsvCacheEntry* newCacheEntry = iFreePoolInstance->EntryL();
       
  1569         TRAPD(err, newCacheEntry->DupNDestroyL(aOldEntry);
       
  1570                    newVisibleFolderNode = AddEntryToCacheL(newVisibleFolderId, newCacheEntry);
       
  1571              );
       
  1572         if(err)
       
  1573             {
       
  1574             iFreePoolInstance->ReleaseEntryWithoutTransaction(newCacheEntry);
       
  1575             User::Leave(err);
       
  1576             }
       
  1577         aOldEntry = newCacheEntry;
       
  1578         }   // if(oldVisibleFolderId != newVisibleFolderId)    }
       
  1579     return newVisibleFolderNode;
       
  1580     }
       
  1581 
       
  1582 
       
  1583 
       
  1584 // Used only by DoChangeEntryL()
       
  1585 void CMsvIndexAdapter::DoChangeEntryPostamble(CMsvCacheVisibleFolder* aOldFolderNode, TMsvId aNewVisibleFolderId, TMsvId aEntryId, CMsvEntrySelection* aDescendentList, CMsvCacheEntry* aNewParentEntry, CMsvCacheEntry* aOldParentEntry, TBool aResetOldParentOwnerFlag)
       
  1586     {
       
  1587      // Removing entry from old visible folder.
       
  1588      if(aOldFolderNode->GetFolderId() != aNewVisibleFolderId)
       
  1589          {
       
  1590          // Will never leave.
       
  1591          //aOldFolderNode->DeleteEntryL(oldEntry->GetId());
       
  1592          TRAP_IGNORE(aOldFolderNode->DeleteEntryL(aEntryId));
       
  1593          }
       
  1594      
       
  1595      // Removing child entries from old visible folder.
       
  1596      if(aDescendentList)
       
  1597          {
       
  1598          for(TInt index=(aDescendentList->Count()-2); index>=0; index--)
       
  1599              {
       
  1600              // Can leave with KErrNotFound.
       
  1601              TRAP_IGNORE(aOldFolderNode->DeleteEntryL(aDescendentList->At(index)));
       
  1602              }         
       
  1603          }
       
  1604     
       
  1605      // Add child id to new parent child array.
       
  1606      if(aNewParentEntry && aNewParentEntry->ChildIdArray())
       
  1607          {
       
  1608          // This will not leave, as memory is already reserved.
       
  1609          TRAP_IGNORE(aNewParentEntry->ChildIdArray()->AppendL(aEntryId));
       
  1610          }
       
  1611      
       
  1612      // Remove child from old parent's child array.
       
  1613      if(aOldParentEntry)
       
  1614          {
       
  1615          RArray<TMsvId>* oldParentChildArr = aOldParentEntry->ChildIdArray();
       
  1616          if(oldParentChildArr)
       
  1617              {
       
  1618              TInt pos = oldParentChildArr->Find(aEntryId);
       
  1619              if(pos != KErrNotFound)
       
  1620                  {
       
  1621                  oldParentChildArr->Remove(pos);
       
  1622                  }
       
  1623              }
       
  1624          }
       
  1625     
       
  1626      // Update owner flag of parent entries.
       
  1627      if(aResetOldParentOwnerFlag)
       
  1628          {
       
  1629          aOldParentEntry->Entry().SetOwner(EFalse);
       
  1630          }
       
  1631      if(aNewParentEntry)
       
  1632          {
       
  1633          aNewParentEntry->Entry().SetOwner(ETrue);
       
  1634          }
       
  1635  }
       
  1636  
       
  1637  
       
  1638  
       
  1639  
       
  1640 /**
       
  1641  * GetEntry()
       
  1642  */
       
  1643 TInt CMsvIndexAdapter::GetEntry(TMsvId aId, TMsvEntry*& aEntry) 
       
  1644 	{
       
  1645 	TSecureId dummy;
       
  1646 	return GetEntry(aId, aEntry, dummy);
       
  1647 	}
       
  1648 
       
  1649 
       
  1650 
       
  1651 /**
       
  1652  * GetEntryNoCache()
       
  1653  * If aAddToCache is EFalse, entry will not be added to cache,
       
  1654  * if the entry is fetched from DB. The user of this function
       
  1655  * should ensure that it releses the memory occupied by entry
       
  1656  * to the freepool.
       
  1657  */
       
  1658 TInt CMsvIndexAdapter::GetEntryNoCache(TMsvId aId, TMsvEntry* aEntry)
       
  1659 	{
       
  1660 	if(KMsvRootIndexEntryId == aId)
       
  1661 		{
       
  1662 		*aEntry = iRootEntry->Entry();				
       
  1663 		return KErrNone;
       
  1664 		}
       
  1665 
       
  1666 	TBool aIsDanglingEntry = EFalse;
       
  1667 	CMsvCacheEntry* serverEntry=NULL;
       
  1668 	TRAPD(err, aIsDanglingEntry = FindEntryL(aId, serverEntry, EFalse));
       
  1669 
       
  1670 	if (err == KErrNone)
       
  1671 		{
       
  1672 		*aEntry = serverEntry->Entry();
       
  1673 		// If entry is not present in cache,
       
  1674 		// it should be handled carefully.
       
  1675 		if(aIsDanglingEntry)
       
  1676 			{
       
  1677 			// Release CMsvCacheEntry to freepool.
       
  1678 			iFreePoolInstance->ReleaseEntry(serverEntry, ETrue);
       
  1679 			}		
       
  1680 		return KErrNone;	
       
  1681 		}
       
  1682 	else
       
  1683 		{
       
  1684 		return KErrNotFound;
       
  1685 		}
       
  1686 	}
       
  1687 
       
  1688 
       
  1689 
       
  1690 	
       
  1691 /**
       
  1692  * GetEntry()
       
  1693  */
       
  1694 TInt CMsvIndexAdapter::GetEntry(TMsvId aId, TMsvEntry*& aEntry, TSecureId& aOwnerId) 
       
  1695 	{
       
  1696 	if(KMsvRootIndexEntryId == aId)
       
  1697 		{
       
  1698 		aEntry = &iRootEntry->Entry();
       
  1699 		aOwnerId = 0;
       
  1700 		return KErrNone;
       
  1701 		}
       
  1702 
       
  1703 	CMsvCacheEntry* serverEntry=NULL;
       
  1704 	TRAPD(err, FindEntryL(aId, serverEntry));	
       
  1705 
       
  1706 	if (err == KErrNone)
       
  1707 		{
       
  1708 		aEntry = &serverEntry->Entry();
       
  1709 		aOwnerId = serverEntry->EntryOwnerId();
       
  1710 		return KErrNone;	
       
  1711 		}
       
  1712 	else
       
  1713 		{
       
  1714 		return KErrNotFound;
       
  1715 		}
       
  1716 	}
       
  1717 	
       
  1718 
       
  1719 
       
  1720 /**
       
  1721  * FindEntryInCache()
       
  1722  * @param aId: Entry Id.
       
  1723  * @return aEntry: CMsvCacheEntry
       
  1724  * @return bool: ETrue if entry found, otherwise EFalse.
       
  1725  * 
       
  1726  * Find an entry only in cache and return the entry.
       
  1727  */
       
  1728 TBool CMsvIndexAdapter::FindEntryInCache(TMsvId aId, CMsvCacheEntry*& aEntry) 
       
  1729 	{
       
  1730 	if(KMsvRootIndexEntryId == aId)
       
  1731 		{
       
  1732 		aEntry = iRootEntry;
       
  1733 		return ETrue;
       
  1734 		}
       
  1735 
       
  1736 	// If cache is not empty.
       
  1737 	if(!iFolderListHeader.IsEmpty())
       
  1738 		{
       
  1739 		CMsvCacheVisibleFolder* folderNode = NULL;
       
  1740 		TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  1741 		dqIter.SetToFirst(); 
       
  1742 		
       
  1743 		while((folderNode = dqIter++)!=NULL)
       
  1744 			{
       
  1745 			if(folderNode->GetEntry(aId, aEntry))
       
  1746 				{
       
  1747 				return ETrue;
       
  1748 				}
       
  1749 			}
       
  1750 		}
       
  1751 	aEntry = NULL;
       
  1752 	return EFalse;
       
  1753 	}
       
  1754 
       
  1755 
       
  1756 
       
  1757 /**
       
  1758  * FindEntryL()
       
  1759  * 
       
  1760  * WARNING:
       
  1761  * Returns CMsvCacheEntry which is still owned by Cache. so aEntry should
       
  1762  * never be deleted by the caller.
       
  1763  *
       
  1764  * If the entry is fetched from DB and not added to cache, the function 
       
  1765  * returns ETrue, indicating that aEntry should be release to the freepool
       
  1766  * by the caller.
       
  1767  */
       
  1768 TBool CMsvIndexAdapter::FindEntryL(TMsvId aId, CMsvCacheEntry*& aEntry, TBool aAddToCache /*DEFAULT=ETrue */)
       
  1769 	{
       
  1770 	// First search the entry in cache, 
       
  1771 	if(FindEntryInCache(aId, aEntry))
       
  1772 		{
       
  1773 		return EFalse;
       
  1774 		}	
       
  1775 
       
  1776 	// Entry cannot be found in cache,
       
  1777 	// Now search in DB.
       
  1778 	TMsvId visibleEntryId;
       
  1779 	if(iDbAdapter)
       
  1780 		{
       
  1781 		iDbAdapter->GetEntryL(aId, aEntry, visibleEntryId);
       
  1782 		}
       
  1783 	else
       
  1784 		{
       
  1785 		User::Leave(ErrorState());	
       
  1786 		}
       
  1787 
       
  1788 	if(aAddToCache)	
       
  1789 		{
       
  1790 		// Add entry to cache.
       
  1791 		AddEntryToCacheL(visibleEntryId, aEntry);	
       
  1792 		}
       
  1793 	else
       
  1794 		{
       
  1795 		// If the entry is not added to cache, we need not start 
       
  1796 		// the background operation. We can return ETrue saying
       
  1797 		// entry is dangling and needs to be freed.
       
  1798 		return ETrue;
       
  1799 		}
       
  1800 	if (!iIdle->IsActive())
       
  1801 		{
       
  1802 		iIdle->Start(TCallBack(BackGroundOperations, this));
       
  1803 		}
       
  1804 	return EFalse;
       
  1805 	}
       
  1806 
       
  1807 
       
  1808 
       
  1809 
       
  1810 /**
       
  1811  * AddEntryNoVisibleL()
       
  1812  */
       
  1813 void CMsvIndexAdapter::AddEntryNoVisibleL(CMsvCacheEntry* aEntry)
       
  1814 	{
       
  1815 	TMsvId visibleFolder;
       
  1816 	if(GetVisibleFolderId(aEntry->Entry().Parent(), visibleFolder))	
       
  1817 		{
       
  1818 		AddEntryToCacheL(visibleFolder, aEntry);
       
  1819 		}
       
  1820 	}
       
  1821 
       
  1822 
       
  1823 
       
  1824 /**
       
  1825  * AddEntryToCacheL()
       
  1826  */
       
  1827 CMsvCacheVisibleFolder* CMsvIndexAdapter::AddEntryToCacheL(TMsvId aVisibleEntryId, CMsvCacheEntry* aEntry)
       
  1828 	{
       
  1829 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1830 	TUint driveId = GetDriveId(aEntry->GetId());
       
  1831 	if(IsStandardId(aEntry->GetId()))
       
  1832 		{
       
  1833 		aEntry->Entry().SetId(UnmaskTMsvId(aEntry->GetId()));
       
  1834 		}
       
  1835 #endif
       
  1836 	// First search the visibleEntry in cache, 
       
  1837 	// if cache is not empty...
       
  1838 	if(!iFolderListHeader.IsEmpty())
       
  1839 		{
       
  1840 		CMsvCacheVisibleFolder* folderNode = NULL;
       
  1841 		TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  1842 		dqIter.SetToFirst();
       
  1843 		
       
  1844 		while((folderNode =  dqIter++)!=NULL)
       
  1845 			{
       
  1846 			TMsvId folderId = folderNode->GetFolderId();
       
  1847 			if(aVisibleEntryId == folderId)
       
  1848 				{
       
  1849 				// Visible folder exists.
       
  1850 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1851 				// For standard entries also check for driveId.
       
  1852 				if(IsStandardId(aVisibleEntryId))
       
  1853 					{
       
  1854 					if(driveId == folderNode->GetDrive())
       
  1855 						{
       
  1856 						folderNode->AddEntryL(aEntry);
       
  1857 						return folderNode;
       
  1858 						}
       
  1859 					}
       
  1860 				else
       
  1861 #endif
       
  1862 					{
       
  1863 					// Add entry to this folder.
       
  1864 					folderNode->AddEntryL(aEntry);
       
  1865 					return folderNode;
       
  1866 					}
       
  1867 				}
       
  1868 			}
       
  1869 		}
       
  1870 
       
  1871 	// Visible folder not found in the folder list.
       
  1872 	// Create the visible folder and add it to the
       
  1873 	// beginning of the list.
       
  1874 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1875 	CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(MaskTMsvId(GetDriveId(aEntry->GetId()), aVisibleEntryId));
       
  1876 #else
       
  1877 	CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(aVisibleEntryId);
       
  1878 #endif
       
  1879 	iFolderListHeader.AddFirst(*newFolder);
       
  1880 	
       
  1881 	// Now add entry to the visible folder
       
  1882 	newFolder->AddEntryL(aEntry);
       
  1883 	return newFolder;
       
  1884 	}
       
  1885 	
       
  1886 
       
  1887 
       
  1888 /**
       
  1889  * GetChildrenL()
       
  1890  */
       
  1891 void CMsvIndexAdapter::GetChildrenL(TMsvId aId, CArrayPtr<const TMsvEntry>& aSelection, const TMsvSelectionOrdering& aOrdering, TUid aMtm)
       
  1892 	{
       
  1893 	TSecureId dummy = KMsvServerId.iId;
       
  1894 	GetChildrenL(aId, aSelection, aOrdering, aMtm, EFalse, dummy);
       
  1895 	}
       
  1896 
       
  1897 
       
  1898 	
       
  1899 /**
       
  1900  * GetChildrenL()
       
  1901  */
       
  1902 void CMsvIndexAdapter::GetChildrenL(TMsvId aId, CArrayPtr<const TMsvEntry>& aSelection, const TMsvSelectionOrdering& aOrdering, TUid aMtm, TBool aFilterByOwnerId, TSecureId aOwnerId)
       
  1903 	{
       
  1904 	CMsvEntryFilter* filter = CMsvEntryFilter::NewLC();
       
  1905 	filter->SetOrder(aOrdering);
       
  1906 	filter->SetSortMtm(aMtm);
       
  1907 	CMsvEntryArray* entries = DoGetChildrenL(aId, *filter, aFilterByOwnerId, aOwnerId);	
       
  1908 	CleanupStack::PushL(entries);	
       
  1909 	
       
  1910 	TInt count = entries->Count();
       
  1911 	for (TInt ii=0; ii<count; ii++)
       
  1912 		{
       
  1913 		aSelection.AppendL(entries->At(ii));
       
  1914 		}
       
  1915 	CleanupStack::PopAndDestroy(2, filter); // filter and entries
       
  1916 	}
       
  1917 
       
  1918 
       
  1919 
       
  1920 	
       
  1921 /**
       
  1922  * DoGetChildrenL
       
  1923  */	
       
  1924 CMsvEntryArray* CMsvIndexAdapter::DoGetChildrenL(TMsvId aId, const CMsvEntryFilter& aFilter, TBool aFilterByOwnerId, TSecureId aOwnerId)
       
  1925 	{
       
  1926 	// Check if entry for aId exists...
       
  1927 	CMsvCacheEntry* entry=NULL;
       
  1928 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1929 	TUint driveId = GetDriveId(aId);
       
  1930 	TMsvId unmaskedId = UnmaskTMsvId(aId);
       
  1931 	if(IsStandardId(aId))
       
  1932 		{		
       
  1933 		FindEntryL(unmaskedId, entry);
       
  1934 		}
       
  1935 	else
       
  1936 #endif
       
  1937 		{
       
  1938 		FindEntryL(aId, entry);
       
  1939 		}
       
  1940 
       
  1941 	TBool isParentAVisibleFolder = EFalse;
       
  1942 	if(entry->Entry().VisibleFolderFlag())
       
  1943 		{
       
  1944 		isParentAVisibleFolder = ETrue;
       
  1945 		}
       
  1946 
       
  1947 	CArrayFixFlat<TUid>* mtmList = new(ELeave) CArrayFixFlat<TUid>(KMsvMtmListGranularity);
       
  1948 	CleanupStack::PushL(mtmList);
       
  1949 	if (KUidMsvNullEntry != aFilter.SortMtm())
       
  1950 		{
       
  1951 		mtmList->AppendL(aFilter.SortMtm());
       
  1952 		}
       
  1953 
       
  1954 	RPointerArray<CMsvCacheEntry> selection;
       
  1955 	CleanupClosePushL(selection);
       
  1956 	
       
  1957 	CMsvCacheVisibleFolder* folderNode = NULL;	
       
  1958 	CMsvEntryArray* entries = CMsvEntryArray::NewLC(*mtmList);
       
  1959 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  1960 	
       
  1961 
       
  1962 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1963 
       
  1964 	if(IsStandardId(aId))
       
  1965 		{
       
  1966 		// Look for the entry in cache.
       
  1967 		if(!iFolderListHeader.IsEmpty())
       
  1968 			{
       
  1969 			dqIter.SetToFirst(); 
       
  1970 			// Check if aId is one of the visible folder,
       
  1971 			// already present in the cache.
       
  1972 			while(NULL != (folderNode = dqIter++))
       
  1973 				{
       
  1974 				if((folderNode->GetFolderId() == unmaskedId) && (folderNode->GetDrive() == driveId))
       
  1975 					{
       
  1976 					folderNode->GetChildrenL(aId, iDbAdapter, selection);
       
  1977 					FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
       
  1978 					CleanupStack::Pop(entries);	// Fetch entries from stack. It will be destroyed by caller.
       
  1979 					CleanupStack::PopAndDestroy(2);
       
  1980 					return entries;
       
  1981 					}
       
  1982 				}
       
  1983 			}
       
  1984 		}
       
  1985 	else
       
  1986 		{				
       
  1987 #endif			// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  1988 
       
  1989 	// Look for the entry in cache.
       
  1990 	if(!iFolderListHeader.IsEmpty())
       
  1991 		{
       
  1992 		dqIter.SetToFirst(); 
       
  1993 		// Check if aId is one of the visible folder,
       
  1994 		// already present in the cache.
       
  1995 		while(NULL != (folderNode = dqIter++))
       
  1996 			{
       
  1997 			if(aId == folderNode->GetFolderId())
       
  1998 				{
       
  1999 				if(iDbAdapter == NULL)
       
  2000 					{
       
  2001 					User::Leave(ErrorState());	
       
  2002 					}
       
  2003 				folderNode->GetChildrenL(aId, iDbAdapter, selection);
       
  2004 				FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
       
  2005 				CleanupStack::Pop(entries);	// Fetch entries from stack. It will be destroyed by caller.
       
  2006 				CleanupStack::PopAndDestroy(2);
       
  2007 				return entries;
       
  2008 				}
       
  2009 			}
       
  2010 
       
  2011 		// If the parent is not a visible folder
       
  2012 		// check if it is child of one of the visible folder.
       
  2013 		if(EFalse == isParentAVisibleFolder)
       
  2014 			{
       
  2015 			dqIter.SetToFirst(); 
       
  2016 			while(NULL != (folderNode = dqIter++))
       
  2017 				{
       
  2018 				TBool retVal=EFalse;
       
  2019 				TRAPD(err, retVal = folderNode->GetChildrenL(aId, iDbAdapter, selection))
       
  2020 
       
  2021 				// aId not found under current visibleFolder.
       
  2022 				if(KErrNotFound == err)
       
  2023 					{
       
  2024 					continue;
       
  2025 					}
       
  2026 				
       
  2027 				// aId found under current visibleFolder.
       
  2028 				if(retVal)
       
  2029 					{
       
  2030 					// Children is fetched succesfully.
       
  2031 					FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);	
       
  2032 					CleanupStack::Pop(entries);  // Fetch entries from stack. It will be destroyed by caller.
       
  2033 					CleanupStack::PopAndDestroy(2);
       
  2034 					return entries;
       
  2035 					}
       
  2036 				else
       
  2037 					{
       
  2038 					// aId itself is a visibleFolder.
       
  2039 					isParentAVisibleFolder = ETrue;
       
  2040 					break;
       
  2041 					}
       
  2042 				}
       
  2043 			}
       
  2044 		}
       
  2045 
       
  2046 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2047 		}
       
  2048 #endif			// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2049 		
       
  2050 	// Could not find parent entry in cache.
       
  2051 	// Check in DB now.	
       
  2052 	TInt err = KErrNone;
       
  2053 	if(iDbAdapter)
       
  2054 		{
       
  2055 		TRAP(err, iDbAdapter->GetChildrenL(aId, selection));
       
  2056 		}
       
  2057 	else
       
  2058 		{
       
  2059 		User::Leave(ErrorState());	
       
  2060 		}
       
  2061 	if(err)
       
  2062 		{
       
  2063 		User::Leave(KErrNotFound);
       
  2064 		}
       
  2065 	FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
       
  2066 	
       
  2067 	// Check if the entire entry list can be added to cache.
       
  2068 	// This is important in a situation when all childs of a 
       
  2069 	// folder cannot be accomodated in cache. In such scenario
       
  2070 	// only entries with higher TMsvId will be added to cache.
       
  2071 	TInt excessEntries = iFreePoolInstance->ExcessMemoryAllocated();
       
  2072 	TBool isCompleteChildren = ETrue;
       
  2073 	if(excessEntries)
       
  2074 		{
       
  2075 		isCompleteChildren = EFalse;
       
  2076 		}
       
  2077 	while(excessEntries)
       
  2078 		{
       
  2079 		if(selection.Count())
       
  2080 			{
       
  2081 			iFreePoolInstance->RecordExcessMemoryL(selection[0]);
       
  2082 			selection.Remove(0);
       
  2083 			}
       
  2084 		--excessEntries;
       
  2085 		}		
       
  2086 
       
  2087 	// Add children to cache.
       
  2088 	TMsvId visibleFolderId;
       
  2089 	if(!isParentAVisibleFolder)
       
  2090 		{
       
  2091 		if(!GetVisibleFolderId(aId, visibleFolderId))
       
  2092 			{
       
  2093 			User::Leave(KErrNotFound);
       
  2094 			}
       
  2095 		}
       
  2096 	else
       
  2097 		{
       
  2098 		visibleFolderId = aId;
       
  2099 		}
       
  2100 	
       
  2101 	TBool isEntryAdded = EFalse;		
       
  2102 	dqIter.SetToFirst();
       
  2103 	while((folderNode = dqIter++)!=NULL)
       
  2104 		{
       
  2105 		if(visibleFolderId == folderNode->GetFolderId())
       
  2106 			{
       
  2107 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2108 			if(IsStandardId(visibleFolderId))
       
  2109 				{
       
  2110 				if(GetDriveId(aId) == folderNode->GetDrive())
       
  2111 					{
       
  2112 					isEntryAdded=ETrue;
       
  2113 					folderNode->AddEntryListL(selection, (isCompleteChildren && isParentAVisibleFolder));
       
  2114 					}
       
  2115 				}
       
  2116 			else
       
  2117 #endif
       
  2118 				{
       
  2119 				isEntryAdded=ETrue;
       
  2120 				folderNode->AddEntryListL(selection, (isCompleteChildren && isParentAVisibleFolder));
       
  2121 				}
       
  2122 			}
       
  2123 		}
       
  2124 	
       
  2125 	if(!isEntryAdded)
       
  2126 		{
       
  2127 		// If aId is the visibleFolder itself then pass
       
  2128 		// aIsCompleteChildOfFolder as ETrue.
       
  2129 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2130 		// Standard Id can be unmasked.
       
  2131 		CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(MaskTMsvId(GetDriveId(aId), visibleFolderId));
       
  2132 #else
       
  2133 		CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(visibleFolderId);
       
  2134 #endif	
       
  2135 		iFolderListHeader.AddFirst(*newFolder);
       
  2136 		newFolder->AddEntryListL(selection, (isCompleteChildren && isParentAVisibleFolder));
       
  2137 		}
       
  2138 
       
  2139 	CleanupStack::Pop(entries);		// Fetch entries from stack. It will be destroyed by caller.
       
  2140 	CleanupStack::PopAndDestroy(2);
       
  2141 	
       
  2142 	//Start the background operations, if not running.
       
  2143 	if (!iIdle->IsActive())
       
  2144 		{
       
  2145 		iIdle->Start(TCallBack(BackGroundOperations, this));
       
  2146 		}
       
  2147 		
       
  2148 	return entries;
       
  2149 	}
       
  2150 
       
  2151 
       
  2152 
       
  2153 
       
  2154 /**
       
  2155  * GetChildrenId()
       
  2156  */
       
  2157 TInt CMsvIndexAdapter::GetChildrenId(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection)
       
  2158 	{
       
  2159 	TSecureId dummy = KMsvServerId.iId;
       
  2160 	return GetChildrenId(aId, aFilter, aSelection, EFalse, dummy);
       
  2161 	}
       
  2162 	
       
  2163 /**
       
  2164  * GetChildrenId()
       
  2165  */
       
  2166 TInt CMsvIndexAdapter::GetChildrenId(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection, TBool aFilterByOwnerId, TSecureId aOwnerId)
       
  2167 	{
       
  2168 	CMsvEntryArray* entries = NULL;
       
  2169 	TInt err = KErrNone;
       
  2170 	TRAP(err, entries=DoGetChildrenL(aId, aFilter, aFilterByOwnerId, aOwnerId));
       
  2171 	if(err)
       
  2172 		{
       
  2173 		delete entries;
       
  2174 		return err;
       
  2175 		}
       
  2176 
       
  2177 	TInt count = entries->Count();
       
  2178 	for(TInt i=0; i<count; ++i)
       
  2179 		{
       
  2180 		TRAP(err, aSelection.AppendL(entries->At(i)->Id()));
       
  2181 		}
       
  2182 	delete entries;
       
  2183 	return err;
       
  2184 	}
       
  2185 
       
  2186 
       
  2187 
       
  2188 /**
       
  2189  * FilterChildrenListL
       
  2190  */	
       
  2191 void CMsvIndexAdapter::FilterChildrenListL(TMsvId aId, RPointerArray<CMsvCacheEntry> aChacheEntry, CMsvEntryArray& aEntryArray, const CMsvEntryFilter& aFilter, TBool aFilterByOwnerId, TSecureId aOwnerId)
       
  2192 	{
       
  2193 	TBool getInvisibleEntries = aFilter.Order().ShowInvisibleEntries();
       
  2194 	TInt count = aChacheEntry.Count();
       
  2195 	for(TInt i=0; i<count; ++i)
       
  2196 		{
       
  2197 		TMsvEntry entry = aChacheEntry[i]->Entry();
       
  2198 		TBool vis = aChacheEntry[i]->Entry().Visible();
       
  2199 		if ((aChacheEntry[i]->Entry().Visible() || getInvisibleEntries) &&
       
  2200 			(aFilter.Service() == KMsvNullIndexEntryId || aChacheEntry[i]->Entry().iServiceId == aFilter.Service()) &&
       
  2201 			(aFilter.Mtm() == KNullUid || aChacheEntry[i]->Entry().iMtm == aFilter.Mtm()) &&
       
  2202 			(aFilter.Type() == KNullUid || aChacheEntry[i]->Entry().iType == aFilter.Type()) &&
       
  2203 			(aFilter.LastChangeDate().Int64() == 0 || aChacheEntry[i]->LastChangeDate() >= aFilter.LastChangeDate()))
       
  2204 			{
       
  2205 			// Add the entry if - 
       
  2206 			// 1. Not filtering by owner ID OR
       
  2207 			// 2. Filtering by owner ID, but entry owner ID matches OR
       
  2208 			// 3. Entry is a standard folder OR
       
  2209 			// 4. Entrt is a service entry.
       
  2210 			if( !aFilterByOwnerId || 
       
  2211 					aChacheEntry[i]->EntryOwnerId() == aOwnerId ||
       
  2212 					aChacheEntry[i]->Entry().StandardFolder() || 
       
  2213 					aChacheEntry[i]->Entry().iType == KUidMsvServiceEntry )
       
  2214 				{
       
  2215 				aEntryArray.AppendL(&aChacheEntry[i]->Entry());
       
  2216 				}
       
  2217 			}
       
  2218 		}
       
  2219 	
       
  2220 	if (aEntryArray.Count())
       
  2221 		{
       
  2222 		if (aId==KMsvRootIndexEntryId)
       
  2223 			{
       
  2224 			aEntryArray.SortL(TMsvSelectionOrdering(KMsvNoGrouping, aFilter.Order().Sorting()));	
       
  2225 			}
       
  2226 		else
       
  2227 			{
       
  2228 			aEntryArray.SortL(aFilter.Order());	
       
  2229 			}
       
  2230 		}	
       
  2231 	}
       
  2232 
       
  2233 
       
  2234 
       
  2235 
       
  2236 /** 
       
  2237  * LockEntry()
       
  2238  */
       
  2239 TInt CMsvIndexAdapter::LockEntry(TMsvId aId)
       
  2240 	{
       
  2241 	//__DEBUG_INVARIANT_ONEXIT;
       
  2242 	
       
  2243 	CMsvCacheEntry* entry = NULL;
       
  2244 	TRAPD(err, FindEntryL(aId, entry))
       
  2245 	if (err)
       
  2246 		{
       
  2247 		return KErrNotFound;
       
  2248 		}
       
  2249 	
       
  2250 	return entry->LockEntry();
       
  2251 	}
       
  2252 		
       
  2253 
       
  2254 
       
  2255 /**
       
  2256  * ReleaseEntry()
       
  2257  */
       
  2258 TInt CMsvIndexAdapter::ReleaseEntry(TMsvId aId)
       
  2259 	{
       
  2260 	//__DEBUG_INVARIANT_ONEXIT;
       
  2261 	
       
  2262 	CMsvCacheEntry* entry = NULL;
       
  2263 	if(FindEntryInCache(aId, entry))
       
  2264 		{
       
  2265 		entry->ReleaseEntry();
       
  2266 		return KErrNone;
       
  2267 		}
       
  2268 	else
       
  2269 		{
       
  2270 		return KErrNotFound;
       
  2271 		}
       
  2272 	}
       
  2273 	
       
  2274 	
       
  2275 
       
  2276 
       
  2277 /**
       
  2278  * IsEntryLocked()
       
  2279  */
       
  2280 TInt CMsvIndexAdapter::IsEntryLocked(TMsvId aId, TBool& aLocked)
       
  2281 	{
       
  2282 	CMsvCacheEntry* entry = NULL;
       
  2283 	TRAPD(err, FindEntryL(aId, entry));
       
  2284 	if(KErrNone != err)
       
  2285 		{
       
  2286 		aLocked = EFalse;
       
  2287 		return err;
       
  2288 		}
       
  2289 	
       
  2290 	aLocked = entry->IsEntryLocked();
       
  2291 	return KErrNone;
       
  2292 	}
       
  2293 	
       
  2294 	
       
  2295 
       
  2296 
       
  2297 
       
  2298 /**
       
  2299  * LockStore()
       
  2300  */
       
  2301 TInt CMsvIndexAdapter::LockStore(TMsvId aId)
       
  2302 	{
       
  2303 	//__DEBUG_INVARIANT_ONEXIT;
       
  2304 	CMsvCacheEntry* entry = NULL;
       
  2305 	TRAPD(err, FindEntryL(aId, entry));
       
  2306 	if (err)
       
  2307 		{
       
  2308 		return KErrNotFound;
       
  2309 		}
       
  2310 	
       
  2311 	return entry->LockStore();
       
  2312 	}
       
  2313 	
       
  2314 
       
  2315 
       
  2316 
       
  2317 /**
       
  2318  * ReleaseStore()
       
  2319  */
       
  2320 TInt CMsvIndexAdapter::ReleaseStore(TMsvId aId)
       
  2321 	{
       
  2322 	//__DEBUG_INVARIANT_ONEXIT;
       
  2323 	
       
  2324 	CMsvCacheEntry* entry = NULL;
       
  2325 	if(FindEntryInCache(aId, entry))
       
  2326 		{
       
  2327 		entry->ReleaseStore();
       
  2328 		return KErrNone;
       
  2329 		}
       
  2330 	else
       
  2331 		{
       
  2332 		return KErrNotFound;
       
  2333 		}
       
  2334 	}
       
  2335 	
       
  2336 
       
  2337 
       
  2338 
       
  2339 /**
       
  2340  * IsStoreLocked()
       
  2341  */
       
  2342 TInt CMsvIndexAdapter::IsStoreLocked(TMsvId aId, TBool& aLocked)
       
  2343 	{
       
  2344 	CMsvCacheEntry* entry = NULL;
       
  2345 	TRAPD(err, FindEntryL(aId, entry));
       
  2346 	if(KErrNone != err)
       
  2347 		{
       
  2348 		aLocked = EFalse;
       
  2349 		return err;
       
  2350 		}
       
  2351 	aLocked = entry->IsStoreLocked();
       
  2352 	return KErrNone;
       
  2353 	}
       
  2354 
       
  2355 
       
  2356 
       
  2357 	
       
  2358 /**
       
  2359  * IsEntryAndStoreLocked()
       
  2360  */
       
  2361 TInt CMsvIndexAdapter::IsEntryOrStoreLocked(TMsvId aId)
       
  2362 	{
       
  2363 	CMsvCacheEntry* entry = NULL;
       
  2364 	TBool locked = EFalse;
       
  2365 	if(FindEntryInCache(aId, entry))
       
  2366 		{
       
  2367 		locked = entry->IsEntryOrStoreLocked();
       
  2368 		}
       
  2369 	if(locked)
       
  2370 		{
       
  2371 		return KErrLocked;
       
  2372 		}
       
  2373 	else
       
  2374 		{
       
  2375 		return KErrNone;
       
  2376 		}
       
  2377 	}
       
  2378 
       
  2379 
       
  2380 
       
  2381 /**
       
  2382  * LockEntryAndStore()
       
  2383  */
       
  2384 TInt CMsvIndexAdapter::LockEntryAndStore(TMsvId aId)
       
  2385 	{
       
  2386 	//__DEBUG_INVARIANT_ONEXIT;
       
  2387 	CMsvCacheEntry* entry = NULL;
       
  2388 	TRAPD(err, FindEntryL(aId, entry));
       
  2389 	if (err)
       
  2390 		{
       
  2391 		return KErrNotFound;
       
  2392 		}
       
  2393 		
       
  2394 	return entry->LockEntryAndStore();
       
  2395 	}
       
  2396 	
       
  2397 
       
  2398 
       
  2399 
       
  2400 /**
       
  2401  * ReleaseEntryAndStore()
       
  2402  */
       
  2403 TInt CMsvIndexAdapter::ReleaseEntryAndStore(TMsvId aId)
       
  2404 	{
       
  2405 	//__DEBUG_INVARIANT_ONEXIT;
       
  2406 	CMsvCacheEntry* entry = NULL;
       
  2407 	if(FindEntryInCache(aId, entry))
       
  2408 		{
       
  2409 		entry->ReleaseEntryAndStore();
       
  2410 		return KErrNone;
       
  2411 		}
       
  2412 	else
       
  2413 		{
       
  2414 		return KErrNotFound;
       
  2415 		}
       
  2416 	}
       
  2417 	
       
  2418 
       
  2419 
       
  2420 
       
  2421 /**
       
  2422  * IsEntryOrStoreLocked()
       
  2423  */
       
  2424 TInt CMsvIndexAdapter::IsEntryOrStoreLocked(TMsvId aId, TBool& aLocked)
       
  2425 	{
       
  2426 	CMsvCacheEntry* entry = NULL;
       
  2427 	if(FindEntryInCache(aId, entry))
       
  2428 		{
       
  2429 		aLocked = entry->IsEntryOrStoreLocked();
       
  2430 		}
       
  2431 	else
       
  2432 		{
       
  2433 		aLocked = EFalse;
       
  2434 		}
       
  2435 	return KErrNone;
       
  2436 	}
       
  2437 	
       
  2438 
       
  2439 
       
  2440 
       
  2441 /**
       
  2442  * IsStoreReadingLocked()
       
  2443  */
       
  2444 TInt CMsvIndexAdapter::IsStoreReadingLocked(TMsvId aId, TBool& aLocked)
       
  2445 	{
       
  2446 	CMsvCacheEntry* entry = NULL;
       
  2447 	if(FindEntryInCache(aId, entry))
       
  2448 		{
       
  2449 		aLocked = entry->IsStoreReadingLocked();
       
  2450 		}
       
  2451 	else
       
  2452 		{
       
  2453 		aLocked = EFalse;
       
  2454 		}
       
  2455 	return KErrNone;	
       
  2456 	}
       
  2457 	
       
  2458 
       
  2459 
       
  2460 
       
  2461 /**
       
  2462  * IncStoreReaderCount()
       
  2463  */
       
  2464 TInt CMsvIndexAdapter::IncStoreReaderCount(TMsvId aId)
       
  2465 	{
       
  2466 	CMsvCacheEntry* entry = NULL;
       
  2467 	TRAPD(err, FindEntryL(aId, entry));
       
  2468 	if (err)
       
  2469 		{
       
  2470 		return KErrNotFound;
       
  2471 		}
       
  2472 		
       
  2473 	entry->IncStoreReaderCount();
       
  2474 	return KErrNone;
       
  2475 	}
       
  2476 	
       
  2477 
       
  2478 
       
  2479 
       
  2480 /**
       
  2481  * DecStoreReaderCount()
       
  2482  */
       
  2483 TInt CMsvIndexAdapter::DecStoreReaderCount(TMsvId aId)
       
  2484 	{
       
  2485 	CMsvCacheEntry* entry = NULL;
       
  2486 	if(FindEntryInCache(aId, entry))
       
  2487 		{
       
  2488 		entry->DecStoreReaderCount();
       
  2489 		}
       
  2490 	return KErrNone;
       
  2491 	}
       
  2492 	
       
  2493 
       
  2494 
       
  2495 
       
  2496 /**
       
  2497  * OwningService()
       
  2498  */
       
  2499 TInt CMsvIndexAdapter::OwningService(TMsvId aId, TMsvId& aService)
       
  2500 	{    
       
  2501 	aService = aId;
       
  2502 	if (aId!=KMsvRootIndexEntryId)
       
  2503 		{
       
  2504 		FOREVER
       
  2505 			{
       
  2506 			CMsvCacheEntry* entry = NULL;	
       
  2507 			TRAPD(err, FindEntryL(aService, entry));
       
  2508 			if (err)
       
  2509 				{
       
  2510 				return KErrNotFound;
       
  2511 				}
       
  2512 
       
  2513 			if (KUidMsvServiceEntry==entry->Entry().iType)
       
  2514 				{
       
  2515 				break;
       
  2516 				}
       
  2517 			aService = entry->Entry().Parent();
       
  2518 			}
       
  2519 		}
       
  2520 
       
  2521 	return KErrNone;
       
  2522 	}
       
  2523 	
       
  2524 
       
  2525 
       
  2526 
       
  2527 /**
       
  2528  * IsLocal()
       
  2529  */
       
  2530 TInt CMsvIndexAdapter::IsLocal(TMsvId aId, TBool& aLocal)
       
  2531 	{
       
  2532 	TInt errVal = KErrNone;
       
  2533 	aLocal = ETrue;
       
  2534 	
       
  2535 	if (aId!=KMsvRootIndexEntryId)
       
  2536 		{
       
  2537 		TMsvId service;
       
  2538 		errVal = OwningService(aId, service);
       
  2539 		aLocal = (KMsvLocalServiceIndexEntryId==service);
       
  2540 		}
       
  2541 		
       
  2542 	return errVal;
       
  2543 	}
       
  2544 
       
  2545 
       
  2546 
       
  2547 
       
  2548 /**
       
  2549  * MoveEntry
       
  2550  * Moves a entry with TMsvId as aId to a folder with target id as aTarget
       
  2551  * 
       
  2552  * @param aId TMsvId of the entry to be moved.
       
  2553  * @param aTarget TMsvId of the parent folder.
       
  2554  * @param aDescendents List of descendents id, if the caller also wants to move descendents
       
  2555  * in cache and DB. The last id in the descendent list must be the entry id itself.
       
  2556  * @return TInt System-wide error code.
       
  2557  */
       
  2558 TInt CMsvIndexAdapter::MoveEntry(TMsvId aId, TMsvId aTarget, CMsvEntrySelection* aDescendents /* DEFAULT=NULL */)
       
  2559 	{
       
  2560 	TRAPD(err, DoMoveEntryL(aId, aTarget, aDescendents));
       
  2561 	return err;
       
  2562 	}
       
  2563 	
       
  2564 
       
  2565 
       
  2566 /**
       
  2567  * DoMoveEntryL()
       
  2568  * Called from MoveEntry()
       
  2569  * */
       
  2570 void CMsvIndexAdapter::DoMoveEntryL(TMsvId aId, TMsvId aTarget, CMsvEntrySelection* aDescendents /* DEFAULT=NULL */)
       
  2571     {
       
  2572     // Leave if the message store is not currently available.
       
  2573     User::LeaveIfError(iErrorState);
       
  2574     
       
  2575     CMsvCacheEntry* entry = NULL;   
       
  2576     CMsvCacheVisibleFolder* oldFolderNode = NULL;
       
  2577     TMsvId oldVisibleFolderId = KMsvNullIndexEntryIdValue;
       
  2578     
       
  2579     // 1. Find the entry in cache.
       
  2580     GetVisibleFolderDetailsL(aId, entry, oldFolderNode);
       
  2581         
       
  2582     // 2. Validate entry.
       
  2583     TBool des;
       
  2584     __ASSERT_DEBUG(entry->IsEntryAndStoreLocked(), PanicServer(EMsvMovingUnlockedEntry));
       
  2585     __ASSERT_DEBUG(entry->Entry().Parent() != aTarget, PanicServer(EMsvMovingWithinSameEntry));
       
  2586     IsADescendent(entry->Entry().Id(), aTarget, des);
       
  2587     if (des)
       
  2588         {// we need to put changes in another method.
       
  2589         User::Leave(KErrArgument);
       
  2590         }
       
  2591     
       
  2592      // 3. Fetch the parent entries.    
       
  2593     CMsvCacheEntry* oldParentEntry = NULL;
       
  2594     CMsvCacheEntry* newParentEntry = NULL;
       
  2595     TMsvId oldParentId = entry->Entry().Parent();
       
  2596     FindEntryL(oldParentId, oldParentEntry);
       
  2597     FindEntryL(aTarget, newParentEntry);
       
  2598     
       
  2599     // 4. Check if the owner flag of the old parent needs to be reset.    
       
  2600     TBool resetOldParentOwnerFlag = EFalse;
       
  2601     CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
       
  2602     CleanupStack::PushL(children);
       
  2603     GetChildrenIdL(oldParentId, *children);
       
  2604     if(1 == children->Count() && oldParentEntry->Entry().Owner())
       
  2605         {
       
  2606         // Just set this flag, this is updated in step 14.
       
  2607         resetOldParentOwnerFlag = ETrue;
       
  2608         }
       
  2609     CleanupStack::PopAndDestroy(); //children
       
  2610     
       
  2611     // 5. If required, pre-allocate memory for child array of newParentEntry.
       
  2612     // This is later updated in step 12.
       
  2613     RArray<TMsvId>* newParentChildArr = newParentEntry->ChildIdArray();
       
  2614     if(newParentChildArr)
       
  2615         {
       
  2616         // This to ensure that future append does not fail.
       
  2617         newParentChildArr->ReserveL(newParentChildArr->Count() + 1);
       
  2618         }
       
  2619 
       
  2620     // Step 6 & 7 is performed in this function.
       
  2621     TBool isChildEntriesNeedsUpdation = EFalse;
       
  2622     CMsvCacheVisibleFolder* newVisibleFolderNode = UpdateCacheForMoveEntryL(aTarget,                                                      
       
  2623                                                                             entry, 
       
  2624                                                                             oldFolderNode, 
       
  2625                                                                             aDescendents,
       
  2626                                                                             isChildEntriesNeedsUpdation);
       
  2627 
       
  2628     TMsvId newVisibleFolderId = newVisibleFolderNode? newVisibleFolderNode->GetFolderId(): oldFolderNode->GetFolderId();
       
  2629 
       
  2630     // 8. Update the entry.    
       
  2631     UpdateDates(*entry, EFalse);
       
  2632     entry->Entry().SetParent(aTarget);
       
  2633 
       
  2634     // 9. Update the DB.
       
  2635     TRAPD(err, 
       
  2636             iDbAdapter->BeginTransactionL();
       
  2637             // Update the actual entry
       
  2638             iDbAdapter->UpdateEntryL(entry->Entry(), newVisibleFolderId);
       
  2639             // Reset old parent owner flag.
       
  2640             if(resetOldParentOwnerFlag)
       
  2641                 iDbAdapter->UpdateOwnerStatusL(oldParentId, oldParentEntry->Entry(), EFalse);
       
  2642             // Set new parent owner flag.
       
  2643             if(!newParentEntry->Entry().Owner())
       
  2644                 iDbAdapter->UpdateOwnerStatusL(aTarget, newParentEntry->Entry(), ETrue);
       
  2645             // Update the child entries visibleFolderId in DB.
       
  2646             if(isChildEntriesNeedsUpdation)
       
  2647                 iDbAdapter->UpdateVisibleFolderL(aDescendents, newVisibleFolderId);
       
  2648             iDbAdapter->CommitTransactionL();
       
  2649          );
       
  2650 
       
  2651     if(err)
       
  2652         {        
       
  2653         TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
       
  2654         // Undo step 8.
       
  2655         entry->Entry().SetParent(oldParentId);
       
  2656         // Undo step 7.
       
  2657         if(newVisibleFolderNode)    
       
  2658             newVisibleFolderNode->DeleteEntryL(aId);
       
  2659         if(isChildEntriesNeedsUpdation)
       
  2660             {
       
  2661             for(TInt index=(aDescendents->Count()-2); index>=0; index--)
       
  2662                 {
       
  2663                 newVisibleFolderNode->DeleteEntryL(aDescendents->At(index));
       
  2664                 }
       
  2665             }
       
  2666         User::Leave(err);
       
  2667         }
       
  2668 
       
  2669     // Nothing should fail after this. Ensure that 
       
  2670     // all leaving function after this does not leave.
       
  2671     
       
  2672     // 10. Continuing step 7.1.
       
  2673     // Removing entry from old visible folder.
       
  2674     if(oldVisibleFolderId != newVisibleFolderId)
       
  2675         {
       
  2676         oldFolderNode->DeleteEntryL(aId);
       
  2677         }
       
  2678     
       
  2679     // 11. Continuing step 7.2.
       
  2680     // Removing child entries from old visible folder.
       
  2681     if(isChildEntriesNeedsUpdation)
       
  2682         {
       
  2683         for(TInt index=(aDescendents->Count()-2); index>=0; index--)
       
  2684             {
       
  2685             oldFolderNode->DeleteEntryL(aDescendents->At(index));
       
  2686             }
       
  2687         }
       
  2688 
       
  2689     // 12. Add child id to new parent child array.
       
  2690     if(newParentChildArr)
       
  2691         {
       
  2692         // This will not leave, as memory is already reserved.
       
  2693         newParentChildArr->AppendL(aId);
       
  2694         }
       
  2695     
       
  2696     // 13. Remove child from old parent's child array.
       
  2697     RArray<TMsvId>* oldParentChildArr = oldParentEntry->ChildIdArray();
       
  2698     if(oldParentChildArr)
       
  2699         {
       
  2700         TInt pos = oldParentChildArr->Find(aId);
       
  2701         if(pos != KErrNotFound)
       
  2702             {
       
  2703             oldParentChildArr->Remove(pos);
       
  2704             }
       
  2705         }
       
  2706 
       
  2707     // 14. Update owner flag of parent entries.
       
  2708     if(resetOldParentOwnerFlag)
       
  2709         {
       
  2710         oldParentEntry->Entry().SetOwner(EFalse);
       
  2711         }
       
  2712     newParentEntry->Entry().SetOwner(ETrue);
       
  2713     }
       
  2714 
       
  2715 
       
  2716 
       
  2717 
       
  2718 void CMsvIndexAdapter::GetVisibleFolderDetailsL(TMsvId aEntryId, CMsvCacheEntry*& aEntry, CMsvCacheVisibleFolder*& aVisibleFolder)
       
  2719     {
       
  2720     TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  2721     dqIter.SetToFirst();
       
  2722     while((aVisibleFolder = dqIter++)!=NULL)
       
  2723         {
       
  2724         if(aVisibleFolder->GetEntry(aEntryId, aEntry))
       
  2725             {
       
  2726             break;
       
  2727             }
       
  2728         }
       
  2729     if(aEntry==NULL)
       
  2730         {
       
  2731         User::Leave(KErrNotFound);
       
  2732         }
       
  2733     }
       
  2734 
       
  2735 
       
  2736 
       
  2737 
       
  2738 CMsvCacheVisibleFolder* CMsvIndexAdapter::UpdateCacheForMoveEntryL(TMsvId aNewParentId,
       
  2739                                                                    CMsvCacheEntry*& aOrigEntry, 
       
  2740                                                                    CMsvCacheVisibleFolder* aOldVisibleFolderNode, 
       
  2741                                                                    CMsvEntrySelection* aDescendents,
       
  2742                                                                    TBool& aIsChildEntriesNeedsUpdation)
       
  2743     {
       
  2744     // 6. Find the visible folder of new parent.
       
  2745     TMsvId newVisibleFolderId = aOldVisibleFolderNode->GetFolderId();
       
  2746     if(!GetVisibleFolderId(aNewParentId, newVisibleFolderId))
       
  2747         {
       
  2748         User::Leave(KErrNotFound);
       
  2749         }
       
  2750     
       
  2751     // 7. Check if the visible folders are different.
       
  2752     CMsvCacheVisibleFolder* newVisibleFolderNode = NULL;
       
  2753     if(aOldVisibleFolderNode->GetFolderId() != newVisibleFolderId)
       
  2754         {
       
  2755         // 7.1. If the visible folders are different, add duplicate
       
  2756         // entry under new visible folder. Removing entry from old
       
  2757         // visible folder is done in step 10 of DoMoveEntryL().
       
  2758         CMsvCacheEntry* newCacheEntry = iFreePoolInstance->EntryL();    
       
  2759         TRAPD(err, newCacheEntry->DupNDestroyL(aOrigEntry);
       
  2760                    newVisibleFolderNode = AddEntryToCacheL(newVisibleFolderId, newCacheEntry);
       
  2761              );
       
  2762         if(err)
       
  2763             {
       
  2764             iFreePoolInstance->ReleaseEntryWithoutTransaction(newCacheEntry);
       
  2765             User::Leave(err);
       
  2766             }
       
  2767     
       
  2768         // 7.2. Check if child entries also needs to be moved. 
       
  2769         aOrigEntry = newCacheEntry;
       
  2770         if(aDescendents && !aOrigEntry->Entry().VisibleFolderFlag())
       
  2771              {
       
  2772              aIsChildEntriesNeedsUpdation = ETrue;
       
  2773              
       
  2774              // Add duplicate child entry under new visible folder.
       
  2775              // Removing child entries from old visible folder is done in step 11.
       
  2776              CMsvCacheEntry* childEntry = NULL;
       
  2777              CMsvCacheEntry* dupChildEntry = NULL;
       
  2778              for(TInt index=(aDescendents->Count()-2); index>=0; index--)
       
  2779                  {
       
  2780                  if(aOldVisibleFolderNode->GetEntry(aDescendents->At(index), childEntry))
       
  2781                      {
       
  2782                      dupChildEntry = NULL;
       
  2783                      // Create the duplicate of original entry.
       
  2784                      TRAP(err, dupChildEntry = iFreePoolInstance->EntryL();
       
  2785                                dupChildEntry->DupNDestroyL(childEntry);
       
  2786                                // Add under new visible folder node.
       
  2787                                newVisibleFolderNode->AddEntryL(dupChildEntry);
       
  2788                           );
       
  2789                      if(err)
       
  2790                          {
       
  2791                          // Delete should not be leaving...
       
  2792                          newVisibleFolderNode->DeleteEntryL(aOrigEntry->GetId());    // Undo step 7.1
       
  2793                          iFreePoolInstance->ReleaseEntryWithoutTransaction(dupChildEntry);   // Undo current entry
       
  2794                          // Undo remaining entries.
       
  2795                          for(TInt numEntries=index+1; numEntries<=(aDescendents->Count()-2); numEntries++)
       
  2796                              {
       
  2797                              newVisibleFolderNode->DeleteEntryL(aDescendents->At(numEntries));
       
  2798                              }
       
  2799                          User::Leave(err);
       
  2800                          }
       
  2801                      }   // if(oldFolderNode->GetEntry(aDescendents->At(index), childEntry))
       
  2802                  }   // for()
       
  2803              }   // if(aDescendents && !entry->Entry().VisibleFolderFlag())
       
  2804         }
       
  2805     return newVisibleFolderNode;
       
  2806     }
       
  2807 
       
  2808 
       
  2809 
       
  2810 
       
  2811 /**
       
  2812  * IsADescendent()
       
  2813  */
       
  2814 TInt CMsvIndexAdapter::IsADescendent(TMsvId aAscendentId, TMsvId aDescendentId, TBool& aDescendent)
       
  2815 	{
       
  2816 	__ASSERT_DEBUG((KMsvRootIndexEntryId != aAscendentId) && (KMsvRootIndexEntryId != aDescendentId), PanicServer(EMsvDescendentArgumentsRoot));
       
  2817 	__ASSERT_DEBUG(aAscendentId!=aDescendentId, PanicServer(EMsvDescendentArgumentsEqual));
       
  2818 	
       
  2819 	aDescendent=EFalse;
       
  2820 	while (KMsvRootIndexEntryId != aDescendentId)
       
  2821 		{
       
  2822 		CMsvCacheEntry* entry;	
       
  2823 		TRAPD(err, FindEntryL(aDescendentId, entry));
       
  2824 		if (err)
       
  2825 			{
       
  2826 			return KErrNotFound;
       
  2827 			}
       
  2828 		if (aDescendentId==aAscendentId)
       
  2829 			{
       
  2830 			aDescendent=ETrue;
       
  2831 			break;
       
  2832 			}
       
  2833 		aDescendentId=entry->Entry().Parent();
       
  2834 		}
       
  2835 		
       
  2836 	return KErrNone;
       
  2837 	}
       
  2838 	
       
  2839 
       
  2840 
       
  2841 
       
  2842 /**
       
  2843  * EntryExists()
       
  2844  */
       
  2845 TBool CMsvIndexAdapter::EntryExists(TMsvId aId)
       
  2846 	{
       
  2847 	// First search the entry in cache, 
       
  2848 	// if cache is not empty...
       
  2849 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  2850 	if(KMsvRootIndexEntryId == aId)
       
  2851 		{
       
  2852 		return true;
       
  2853 		}
       
  2854 #endif
       
  2855 	if(!iFolderListHeader.IsEmpty())
       
  2856 		{
       
  2857 		CMsvCacheVisibleFolder* folderNode = NULL;
       
  2858 		TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  2859 		dqIter.SetToFirst(); 
       
  2860 		
       
  2861 		while((folderNode = dqIter++)!=NULL)
       
  2862 			{
       
  2863 			if(aId == folderNode->GetFolderId())
       
  2864 				{
       
  2865 				return ETrue;
       
  2866 				}
       
  2867 			if(folderNode->EntryExists(aId))
       
  2868 				{
       
  2869 				return ETrue;
       
  2870 				}
       
  2871 			}
       
  2872 		}
       
  2873 	
       
  2874 	TBool entryExists = EFalse;
       
  2875 	if(iDbAdapter)
       
  2876 		{
       
  2877 		TRAP_IGNORE(entryExists = iDbAdapter->EntryExistsL(aId));
       
  2878 		}
       
  2879 	else
       
  2880 		{
       
  2881 		return EFalse;
       
  2882 		}
       
  2883 	if(!entryExists)
       
  2884 		{
       
  2885 		return EFalse;	
       
  2886 		}
       
  2887 	return ETrue;
       
  2888 	}
       
  2889 	
       
  2890 
       
  2891 
       
  2892 
       
  2893 /**
       
  2894  * ChangeTemporaryData()
       
  2895  */
       
  2896 TInt CMsvIndexAdapter::ChangeTemporaryData(const TMsvEntry& aNewEntryContents)
       
  2897 	{
       
  2898 	//__DEBUG_INVARIANT_ONEXIT;
       
  2899 	
       
  2900 	CMsvCacheEntry* entry;	
       
  2901 
       
  2902 	// find the entry in the index
       
  2903 	TRAPD(err, FindEntryL(aNewEntryContents.Id(), entry));
       
  2904 	if (err)
       
  2905 		{
       
  2906 		return KErrNotFound;
       
  2907 		}
       
  2908 
       
  2909 	// Can only change a locked entry and not one marked as read only
       
  2910 	if (!entry->IsEntryLocked() || entry->Entry().StandardFolder())
       
  2911 		{
       
  2912 		return KErrAccessDenied;
       
  2913 		}
       
  2914 
       
  2915 	// Check if just changing temporary flags (ie those not stored on file)
       
  2916 	entry->Entry().iData=aNewEntryContents.iData;
       
  2917 
       
  2918 	return KErrNone;	
       
  2919 	}
       
  2920 	
       
  2921 
       
  2922 
       
  2923 
       
  2924 /**
       
  2925  * ChangeAttributes()
       
  2926  */
       
  2927 TInt CMsvIndexAdapter::ChangeAttributes(CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
       
  2928 	{
       
  2929 	TRAPD(leave, DoChangeAttributesL(aSelection, aSetAttributes, aClearAttributes));
       
  2930 	return leave;
       
  2931 	}
       
  2932 	
       
  2933 
       
  2934 
       
  2935 void CMsvIndexAdapter::DoChangeAttributesL(CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
       
  2936 	{
       
  2937 	// Leave if the message store is not currently available
       
  2938 	User::LeaveIfError(iErrorState);
       
  2939 
       
  2940 	CArrayFixSeg<TInt32>* newData = new(ELeave)CArrayFixSeg<TInt32>(KMsvChangeAttributesListGranularity);
       
  2941 	CleanupStack::PushL(newData);
       
  2942 	CArrayFixSeg<TInt32>* newPcSyncCount = new(ELeave)CArrayFixSeg<TInt32>(KMsvChangeAttributesListGranularity);
       
  2943 	CleanupStack::PushL(newPcSyncCount);
       
  2944 
       
  2945 	newData->ResizeL(aSelection.Count(), 0);
       
  2946 	newPcSyncCount->ResizeL(aSelection.Count(), 0);
       
  2947 
       
  2948 	TInt count=aSelection.Count();
       
  2949 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  2950 	CMsvCacheEntry* entry = NULL;	
       
  2951 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  2952 	TMsvId newVisibleFolderId = NULL;
       
  2953 	if(iDbAdapter)
       
  2954 		{
       
  2955 		iDbAdapter->BeginTransactionL();
       
  2956 		}
       
  2957 	else
       
  2958 		{
       
  2959 		User::Leave(ErrorState());	
       
  2960 		}
       
  2961 	while(count--)
       
  2962 		{
       
  2963 		// find the entry in the index
       
  2964 		dqIter.SetToFirst();
       
  2965 		while((folderNode = dqIter++)!=NULL)
       
  2966 			{
       
  2967 			if(folderNode->GetEntry(aSelection.At(count), entry))
       
  2968 				{
       
  2969 				newVisibleFolderId = folderNode->GetFolderId();
       
  2970 				break;
       
  2971 				}
       
  2972 			}
       
  2973 		if (entry == NULL)
       
  2974 			{
       
  2975 			User::Leave(KErrNotFound);
       
  2976 			}
       
  2977 		// can only change a locked entry and not one marked as read only
       
  2978 		if (!entry->IsEntryLocked() || entry->Entry().StandardFolder())
       
  2979 			{
       
  2980 			User::Leave(KErrAccessDenied);
       
  2981 			}
       
  2982 			
       
  2983 		// work out the new attributes
       
  2984 		TBool persistedFlagsChanged;
       
  2985 		if (!NewAttributes(entry->Entry(), newData->At(count), newPcSyncCount->At(count), aSetAttributes, aClearAttributes, persistedFlagsChanged))
       
  2986 			{
       
  2987 			// attributes don't need changing
       
  2988 			aSelection.Delete(count);
       
  2989 			newData->Delete(count);
       
  2990 			newPcSyncCount->Delete(count);
       
  2991 			continue;
       
  2992 			}
       
  2993 		if(persistedFlagsChanged)
       
  2994 			{
       
  2995 			TMsvEntry tEntry = entry->Entry();
       
  2996 			tEntry.iData = newData->At(count);
       
  2997 			tEntry.iPcSyncCount = newPcSyncCount->At(count);
       
  2998 			TInt err = KErrNone;
       
  2999 			if(iDbAdapter)
       
  3000 				{
       
  3001 				TRAP(err, iDbAdapter->UpdateEntryL(tEntry, newVisibleFolderId, EFalse));
       
  3002 				}
       
  3003 			else
       
  3004 				{
       
  3005 				User::Leave(ErrorState());	
       
  3006 				}
       
  3007 			if(err)
       
  3008 				{
       
  3009 				iDbAdapter->RollbackTransactionL();
       
  3010 				User::Leave(err);
       
  3011 				}
       
  3012 			}
       
  3013 		}
       
  3014 	if(iDbAdapter)
       
  3015 		{
       
  3016 		iDbAdapter->CommitTransactionL();
       
  3017 		}
       
  3018 	else
       
  3019 		{
       
  3020 		User::Leave(ErrorState());	
       
  3021 		}	
       
  3022 	
       
  3023 	count=aSelection.Count();
       
  3024 	while(count--)
       
  3025 		{
       
  3026 		// find the entry in the index
       
  3027 		CMsvCacheEntry* entryPtr = NULL;
       
  3028 		dqIter.SetToFirst();
       
  3029 		while((folderNode = dqIter++)!=NULL)
       
  3030 			{
       
  3031 			if(folderNode->GetEntry(aSelection.At(count), entryPtr))
       
  3032 				{
       
  3033 				break;
       
  3034 				}
       
  3035 			}
       
  3036 #if defined(_DEBUG)
       
  3037 		TBool found = (NULL != entryPtr);
       
  3038 		__ASSERT_DEBUG(found, PanicServer(EMsvChangeAttEmtryNotFound));
       
  3039 #endif
       
  3040 		entryPtr->Entry().iData=newData->At(count);
       
  3041 		entryPtr->Entry().iPcSyncCount=newPcSyncCount->At(count);
       
  3042 		}
       
  3043 	CleanupStack::PopAndDestroy(2, newData);
       
  3044 	if (!iIdle->IsActive())
       
  3045 		{
       
  3046 		iIdle->Start(TCallBack(BackGroundOperations, this));	
       
  3047 		}
       
  3048 		
       
  3049 	}
       
  3050 
       
  3051 /**
       
  3052  * NewAttributes
       
  3053 */	
       
  3054 TBool CMsvIndexAdapter::NewAttributes(const TMsvEntry& aEntry, TInt32& aNewData, TInt32& aNewPcSyncCount, TUint aSetAttributes, TUint aClearAttributes, TBool& aPersistedFlagsChanged)
       
  3055 	{
       
  3056 	aNewData = aEntry.iData;
       
  3057 	aNewPcSyncCount = aEntry.iPcSyncCount;
       
  3058 
       
  3059 	// KMsvPcSyncCountAttribute is a dummy flag that is used to increment/decrement the PC Sync Count
       
  3060 	// The visibility attribute is actually recorded as an 'invisible' flag in the index
       
  3061 	if (aSetAttributes)
       
  3062 		{
       
  3063 		if (aSetAttributes & KMsvPcSyncCountAttribute)
       
  3064 			{
       
  3065 			aNewPcSyncCount++;
       
  3066 			aSetAttributes &= ~KMsvPcSyncCountAttribute;
       
  3067 			}
       
  3068 		
       
  3069 		const TInt32 mask = KMsvSendStateMax << KMsvSendingStateShift;
       
  3070 		if (aSetAttributes & mask)
       
  3071 			{
       
  3072 			aNewData &= ~mask;
       
  3073 			}
       
  3074 			
       
  3075 
       
  3076 		aNewData |= aSetAttributes;
       
  3077 
       
  3078 		if (aSetAttributes & KMsvVisibilityAttribute)
       
  3079 			{
       
  3080 			aNewData &= ~TMsvEntry::KMsvEntryInvisibleFlag;
       
  3081 			}
       
  3082 		if (aSetAttributes & KMsvPendingDeleteAttribute)
       
  3083 			{
       
  3084 			aNewData |= TMsvEntry::KMsvEntryPendingDeleteFlag;
       
  3085 			}
       
  3086 		}
       
  3087 
       
  3088 	if (aClearAttributes)
       
  3089 		{
       
  3090 		if (aClearAttributes & KMsvPcSyncCountAttribute)
       
  3091 			{
       
  3092 			aNewPcSyncCount--;
       
  3093 			aClearAttributes &= ~KMsvPcSyncCountAttribute;
       
  3094 			}
       
  3095 
       
  3096 		aNewData &= ~aClearAttributes;
       
  3097 
       
  3098 		if (aClearAttributes&KMsvVisibilityAttribute)
       
  3099 			{
       
  3100 			aNewData |= TMsvEntry::KMsvEntryInvisibleFlag;
       
  3101 			}
       
  3102 			
       
  3103 		if (aClearAttributes&KMsvPendingDeleteAttribute)
       
  3104 			{
       
  3105 			aNewData &= ~TMsvEntry::KMsvEntryPendingDeleteFlag;
       
  3106 			}
       
  3107 			
       
  3108 		}
       
  3109 
       
  3110 	aPersistedFlagsChanged = (aNewData&TMsvEntry::KMsvEntryPersistedFlags)!=(aEntry.iData&TMsvEntry::KMsvEntryPersistedFlags) ||
       
  3111 								aNewPcSyncCount != aEntry.iPcSyncCount;
       
  3112 	return aNewData != aEntry.iData || aNewPcSyncCount != aEntry.iPcSyncCount;
       
  3113 	}
       
  3114 
       
  3115 /**
       
  3116  * UpdateDates
       
  3117 */
       
  3118 void CMsvIndexAdapter::UpdateDates(CMsvCacheEntry& aEntry, TBool aSetCreatedDate)
       
  3119 	{
       
  3120 	TTime now;
       
  3121 	now.UniversalTime();
       
  3122 	TMsvTime time;
       
  3123 	time.SetTime(now);
       
  3124 	aEntry.SetLastChangeDate(time);
       
  3125 	
       
  3126 	if (aSetCreatedDate)
       
  3127 		{
       
  3128 		aEntry.SetCreatedDate(time);
       
  3129 		}
       
  3130 	}
       
  3131 
       
  3132 
       
  3133 
       
  3134 
       
  3135 /**
       
  3136  * GetInternalEntry()
       
  3137  */
       
  3138 TInt CMsvIndexAdapter::GetInternalEntry(TMsvId aId, CMsvCacheEntry*& aEntry)
       
  3139 	{
       
  3140 	CMsvCacheEntry* entry=NULL;
       
  3141 	TRAPD(err, FindEntryL(aId, entry));
       
  3142 	if(err!=KErrNone)
       
  3143 		{
       
  3144 		return err;
       
  3145 		}
       
  3146 	if(entry==NULL)
       
  3147 		{
       
  3148 		return KErrNotFound;
       
  3149 		}
       
  3150 	aEntry=entry;
       
  3151 	return KErrNone;
       
  3152 	}
       
  3153 
       
  3154 	
       
  3155 /**
       
  3156  * Progress()
       
  3157 */ 
       
  3158 TMsvIndexProgress& CMsvIndexAdapter::Progress()
       
  3159 	{
       
  3160 	return iProgress;
       
  3161 	}
       
  3162 	
       
  3163 
       
  3164 /**
       
  3165  * EntryTreeInfo()
       
  3166  */
       
  3167 TInt CMsvIndexAdapter::EntryTreeInfo(TMsvId aId, TMsvServerEntryInfo& aEntryInfo)
       
  3168 	{
       
  3169 	aEntryInfo.Reset();
       
  3170 	aEntryInfo.iId = aId;
       
  3171 
       
  3172 	if( aId != KMsvRootIndexEntryId )
       
  3173 		{
       
  3174 		// Search up the tree to find which service the specified entry is under.
       
  3175 		// Also, record the highest owning folder for the entry.
       
  3176 		TMsvId id = aId;
       
  3177 		CMsvCacheEntry* entry =NULL;
       
  3178 		TRAPD(err, FindEntryL(id, entry));
       
  3179 		if(err)
       
  3180 			return KErrNotFound;
       
  3181 		
       
  3182 		id = entry->Entry().iId; //Id may be masked in cache
       
  3183 		aEntryInfo.iId = id;
       
  3184 		
       
  3185 		// Get info for the entry.
       
  3186 		aEntryInfo.iEntryOwnerId	= entry->EntryOwnerId();
       
  3187 		aEntryInfo.iMtm				= entry->Entry().iMtm;
       
  3188 		aEntryInfo.iType			= entry->Entry().iType;
       
  3189 		
       
  3190 		if( aEntryInfo.iType == KUidMsvFolderEntry )
       
  3191 			{
       
  3192 			// This is a folder - record as this may be needed.
       
  3193 			aEntryInfo.iTopFolder = id;
       
  3194 			}
       
  3195 		
       
  3196 		TBool found = (aEntryInfo.iType == KUidMsvServiceEntry);
       
  3197 		while( !found )
       
  3198 			{
       
  3199 			// Move up the tree and get the next entry...
       
  3200 			id = entry->Entry().Parent();
       
  3201 			TRAPD(err, FindEntryL(id, entry));
       
  3202 			if(err)
       
  3203 			 return KErrNotFound;
       
  3204 			
       
  3205 			TUid type = entry->Entry().iType;
       
  3206 			if( type == KUidMsvServiceEntry )
       
  3207 				{
       
  3208 				// Ok, we've found the owning service - stop looking.
       
  3209 				found = ETrue;
       
  3210 				}
       
  3211 			else if( type == KUidMsvFolderEntry )
       
  3212 				{
       
  3213 				// This is a folder - record as this may be needed.
       
  3214 				aEntryInfo.iTopFolder = id;
       
  3215 				}
       
  3216 			else 
       
  3217 				{
       
  3218 				// This is a message or attachment entry - this implies that the
       
  3219 				// original entry was part of an existing message. Set the owner
       
  3220 				// ID to the highest parent.
       
  3221 				aEntryInfo.iPartOfMessage	= ETrue;
       
  3222 				aEntryInfo.iParentOwnerId	= entry->EntryOwnerId();
       
  3223 				}
       
  3224 			}
       
  3225 		// Record the service and MTM...
       
  3226 		aEntryInfo.iService = id;
       
  3227 
       
  3228 		aEntryInfo.iServiceMtm = entry->Entry().iMtm;
       
  3229 		}
       
  3230 	else
       
  3231 		{
       
  3232 		// This is the root entry! Mark the service as being the local service.
       
  3233 		aEntryInfo.iType		= KUidMsvRootEntry;
       
  3234 		aEntryInfo.iMtm			= KUidMsvLocalServiceMtm;
       
  3235 		aEntryInfo.iService		= KMsvLocalServiceIndexEntryId;
       
  3236 		aEntryInfo.iServiceMtm	= KUidMsvLocalServiceMtm;
       
  3237 		aEntryInfo.iTopFolder	= KMsvRootIndexEntryId;
       
  3238 		}
       
  3239 	return KErrNone;
       
  3240 	}
       
  3241 	
       
  3242 
       
  3243 
       
  3244 
       
  3245 /**
       
  3246  * CommitNonCommitedEntries()
       
  3247  */
       
  3248 void CMsvIndexAdapter::CommitNonCommitedEntries()
       
  3249 	{
       
  3250 	// 1. Commit transaction in DB.
       
  3251 	if(iDbAdapter)
       
  3252 		{
       
  3253 		TRAPD(err, iDbAdapter->CommitTransactionL());
       
  3254 		if(err)
       
  3255 		    {
       
  3256 		    RollbackAdditions();
       
  3257 		    RollbackChanges();
       
  3258 		    return;
       
  3259 		    }
       
  3260 		}
       
  3261 
       
  3262 	// 2. Update changed entries completely.
       
  3263 	TInt count = iNonCommittedChangedEntryList.Count();
       
  3264 	while(count)
       
  3265 		{
       
  3266 		TNonCommittedChangedEntries changedEntry = iNonCommittedChangedEntryList[--count];
       
  3267 		CMsvCacheVisibleFolder* oldVisibleFolderNode = changedEntry.iOldVisibleFolderNode;
       
  3268         // Removing entry from old visible folder.
       
  3269         if(changedEntry.iNewVisibleFolderNode &&
       
  3270            oldVisibleFolderNode->GetFolderId() != changedEntry.iNewVisibleFolderNode->GetFolderId())
       
  3271             {
       
  3272             // Will never leave.
       
  3273             TRAP_IGNORE(changedEntry.iOldVisibleFolderNode->DeleteEntryL(changedEntry.iEntry->GetId()));
       
  3274             }
       
  3275         
       
  3276         // Removing child entries from old visible folder.
       
  3277         if(changedEntry.iDescendentList)
       
  3278             {
       
  3279             for(TInt index=(changedEntry.iDescendentList->Count()-2); index>=0; index--)
       
  3280                 {
       
  3281                 // Can leave with KErrNotFound.
       
  3282                 TRAP_IGNORE(oldVisibleFolderNode->DeleteEntryL(changedEntry.iDescendentList->At(index)));
       
  3283                 }
       
  3284             delete changedEntry.iDescendentList;            
       
  3285             }
       
  3286     
       
  3287         // Add child id to new parent child array.
       
  3288         if(changedEntry.iNewParentEntry && (changedEntry.iNewParentEntry->ChildIdArray()))
       
  3289             {
       
  3290             // This will not leave, as memory is already reserved.
       
  3291             TRAP_IGNORE(changedEntry.iNewParentEntry->ChildIdArray()->AppendL(changedEntry.iEntry->GetId()));
       
  3292             }
       
  3293         
       
  3294         // Remove child from old parent's child array.
       
  3295         if(changedEntry.iOldParentEntry)
       
  3296             {
       
  3297             RArray<TMsvId>* oldParentChildArr = changedEntry.iOldParentEntry->ChildIdArray();
       
  3298             if(oldParentChildArr)
       
  3299                 {
       
  3300                 TInt pos = oldParentChildArr->Find(changedEntry.iEntry->GetId());
       
  3301                 if(pos != KErrNotFound)
       
  3302                     {
       
  3303                     oldParentChildArr->Remove(pos);
       
  3304                     }
       
  3305                 }
       
  3306             }
       
  3307     
       
  3308         // Update owner flag of parent entries.
       
  3309         if(changedEntry.iResetOldParentOwnerFlag)
       
  3310             {
       
  3311             changedEntry.iOldParentEntry->Entry().SetOwner(EFalse);
       
  3312             }
       
  3313         if(changedEntry.iNewParentEntry)
       
  3314             {
       
  3315             changedEntry.iNewParentEntry->Entry().SetOwner(ETrue);
       
  3316             }
       
  3317 		}
       
  3318 
       
  3319 	// 3. Reset non-committed entry list.
       
  3320 	iNonCommittedAddedEntryList.ResetAndDestroy();
       
  3321 	iNonCommittedChangedEntryList.Reset();
       
  3322 	}
       
  3323 
       
  3324 
       
  3325 
       
  3326 /**
       
  3327  * RollbackAdditions()
       
  3328  */
       
  3329 void CMsvIndexAdapter::RollbackAdditions()
       
  3330 	{
       
  3331 	// 1. Rollback transaction in DB.
       
  3332 	if(iDbAdapter)
       
  3333 		{
       
  3334 		TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
       
  3335 		}
       
  3336 	
       
  3337 	// 2. Delete added entry from cache.
       
  3338 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  3339 	TInt count = iNonCommittedAddedEntryList.Count();
       
  3340 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  3341 	while(count)
       
  3342 		{
       
  3343 		--count;
       
  3344 		dqIter.SetToFirst();
       
  3345 	    while ((folderNode = dqIter++) != NULL)
       
  3346 	        {
       
  3347 	        if(iNonCommittedAddedEntryList[count]->iVisibleFolder == folderNode->GetFolderId())
       
  3348 	           	{
       
  3349 	           	iNonCommittedAddedEntryList[count]->entry->LockEntry();
       
  3350 	        	// Error can cause if the entry does not exist. Ignore.
       
  3351 	        	TRAP_IGNORE(folderNode->DeleteEntryL(iNonCommittedAddedEntryList[count]->entry->GetId()));
       
  3352 	        	break;
       
  3353 	        	}
       
  3354 	        };
       
  3355 		}
       
  3356 	
       
  3357 	// 3. Reset non-committed entry list.
       
  3358 	iNonCommittedAddedEntryList.ResetAndDestroy();
       
  3359 	}
       
  3360 
       
  3361 
       
  3362 
       
  3363 
       
  3364 
       
  3365 /**
       
  3366  * RollbackChanges()
       
  3367  */
       
  3368 void CMsvIndexAdapter::RollbackChanges()
       
  3369 	{
       
  3370 	// 1. Rollback transaction in DB.
       
  3371 	if(iDbAdapter)
       
  3372 		{
       
  3373 		TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
       
  3374 		}
       
  3375 	
       
  3376 	// 2. Undo changed entry in cache.
       
  3377 	TInt count = iNonCommittedChangedEntryList.Count();
       
  3378 	while(count)
       
  3379 		{
       
  3380 		TNonCommittedChangedEntries changedEntry = iNonCommittedChangedEntryList[--count];
       
  3381 		CMsvCacheEntry* oldEntry = changedEntry.iEntry;
       
  3382 
       
  3383 		// If the visible folder Id of the entry is changed, 
       
  3384 		// oldEntry represents the entry under new visible folder node.
       
  3385 		// Get the actual old entry from old visible folder node.
       
  3386 		if(changedEntry.iNewVisibleFolderNode)
       
  3387 		    {
       
  3388 		    // This will be non leaving as entry is already present.
       
  3389 		    if(changedEntry.iOldVisibleFolderNode->GetEntry(oldEntry->GetId(), oldEntry))
       
  3390 				{
       
  3391 				// Remove added entry from new visible node. 
       
  3392 				// This function will never leave in the current 
       
  3393 				// scenario, hence ignoring the error.
       
  3394 				TRAP_IGNORE(changedEntry.iNewVisibleFolderNode->DeleteEntryL(oldEntry->GetId()));
       
  3395 				}
       
  3396 		    }
       
  3397         oldEntry->SetEntryOwnerId(changedEntry.iBkpEntry->EntryOwnerId());
       
  3398         oldEntry->RollBackCopyEntry(changedEntry.iBkpEntry->Entry());
       
  3399         iFreePoolInstance->ReleaseEntryWithoutTransaction(changedEntry.iBkpEntry);
       
  3400         
       
  3401         if(changedEntry.iDescendentList)
       
  3402             {
       
  3403             delete changedEntry.iDescendentList;
       
  3404             }
       
  3405  		}
       
  3406         
       
  3407 	// 3. Reset non-committed entry list.
       
  3408 	iNonCommittedChangedEntryList.Reset();
       
  3409 	}
       
  3410 
       
  3411 
       
  3412 
       
  3413 
       
  3414 CMsvIndexAdapter::TMsvServerEntryInfo::TMsvServerEntryInfo()
       
  3415 	{
       
  3416 	iId				= KMsvNullIndexEntryIdValue;
       
  3417 	iTopFolder		= KMsvNullIndexEntryIdValue;
       
  3418 	iService		= KMsvNullIndexEntryIdValue;
       
  3419 	iMtm			= KUidMsvNullEntry;
       
  3420 	iType			= KUidMsvNullEntry;
       
  3421 	iServiceMtm		= KUidMsvNullEntry;
       
  3422 	iEntryOwnerId	= KMsvServerId.iId; 
       
  3423 	iParentOwnerId	= KMsvServerId.iId;
       
  3424 	iPartOfMessage	= EFalse;	
       
  3425 	}
       
  3426 
       
  3427 
       
  3428 
       
  3429 
       
  3430 void CMsvIndexAdapter::TMsvServerEntryInfo::Reset()
       
  3431 	{
       
  3432 	iId				= KMsvNullIndexEntryIdValue;
       
  3433 	iTopFolder		= KMsvNullIndexEntryIdValue;
       
  3434 	iService		= KMsvNullIndexEntryIdValue;
       
  3435 	iMtm			= KUidMsvNullEntry;
       
  3436 	iType			= KUidMsvNullEntry;
       
  3437 	iServiceMtm		= KUidMsvNullEntry;
       
  3438 	iEntryOwnerId	= KMsvServerId.iId; 
       
  3439 	iParentOwnerId	= KMsvServerId.iId;
       
  3440 	iPartOfMessage	= EFalse;	
       
  3441 	}	
       
  3442 
       
  3443 
       
  3444 /**
       
  3445 Need to see the posibilty of getting this first from cache
       
  3446 */
       
  3447 TBool CMsvIndexAdapter::GetNextSiblingL(TMsvId aId,TMsvId aParentId,TMsvId& aNextSiblingId)
       
  3448 	{
       
  3449 	TBool flag = EFalse;
       
  3450 	if(iDbAdapter)
       
  3451 		{
       
  3452 		flag = iDbAdapter->GetNextSiblingL(aId, aParentId, aNextSiblingId);
       
  3453 		}
       
  3454 	else
       
  3455 		{
       
  3456 		User::Leave(ErrorState());	
       
  3457 		}
       
  3458 	return flag;
       
  3459 	}
       
  3460 
       
  3461 
       
  3462 /**
       
  3463 Need to see the posibilty of getting this first from cache
       
  3464 */
       
  3465 TBool CMsvIndexAdapter::GetFirstChildIdL(TMsvId aParentId,TMsvId& aFirstChild)
       
  3466 	{
       
  3467 	TBool flag = EFalse;
       
  3468 	if(iDbAdapter)
       
  3469 		{
       
  3470 		flag = iDbAdapter->GetFirstChildIdL(aParentId, aFirstChild);
       
  3471 		}
       
  3472 	else
       
  3473 		{
       
  3474 		User::Leave(ErrorState());	
       
  3475 		}
       
  3476 	return flag;
       
  3477 	}
       
  3478 
       
  3479 
       
  3480 /**
       
  3481  * SetLocalServiceComplete
       
  3482  * @param TUint: Drive Id of the local service folder node.
       
  3483  *
       
  3484  * Code changes for PREQ 557.
       
  3485  * Sets the localservice visiblefolder.
       
  3486  */	
       
  3487 void CMsvIndexAdapter::SetLocalServiceComplete()
       
  3488 	{
       
  3489 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  3490 	dqIter.SetToFirst();
       
  3491 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  3492 
       
  3493 	while((folderNode = dqIter++)!=NULL)
       
  3494 		{
       
  3495 		if(KMsvLocalServiceIndexEntryIdValue == folderNode->GetFolderId())
       
  3496 			{
       
  3497 			folderNode->SetComplete(ETrue);
       
  3498 			break;
       
  3499 			}
       
  3500 		}
       
  3501 	}
       
  3502 
       
  3503 	
       
  3504 /**
       
  3505  *BackGroundOperations()
       
  3506  *@param  aPtr 	A TAny*
       
  3507  *@return TBool ETrue if the background operation needs to be rescheduled.
       
  3508  *				EFalse if the background operation need not be rescheduled.
       
  3509  */
       
  3510 TBool CMsvIndexAdapter::BackGroundOperations(TAny* aPtr)
       
  3511 	{
       
  3512 	return ((CMsvIndexAdapter*)aPtr)->DoBackGroundOperations();
       
  3513 	}
       
  3514 
       
  3515 
       
  3516 
       
  3517 
       
  3518 
       
  3519 /**
       
  3520  *DoBackGroundOperations()
       
  3521  *@param  None
       
  3522  *@return TBool ETrue if the background operation needs to be rescheduled.
       
  3523  *				EFalse if the background operation need not be rescheduled.
       
  3524  */
       
  3525 TBool CMsvIndexAdapter::DoBackGroundOperations()
       
  3526 	{
       
  3527 	TInt stopBackgroundOperation = EFalse;
       
  3528 	TRAPD(err, DoBackGroundOperationsL(stopBackgroundOperation));
       
  3529 	if(KErrNone == err && !stopBackgroundOperation)
       
  3530 		{
       
  3531 		return ETrue;
       
  3532 		}
       
  3533 	return EFalse;	
       
  3534 	}
       
  3535 
       
  3536 
       
  3537 
       
  3538 
       
  3539 
       
  3540 /**
       
  3541  *DoBackGroundOperations()
       
  3542  *This is the background operation state machine, this will perform a set
       
  3543  *of operations in each of the iteration.
       
  3544  *
       
  3545  *@param  None
       
  3546  *@return void
       
  3547  */
       
  3548 void CMsvIndexAdapter::DoBackGroundOperationsL(TBool& aStopBackgroundOperation)
       
  3549 	{
       
  3550 	iFreePoolInstance->RoutineFreePoolCleanUpL();
       
  3551 	switch(iBackgroundOperationState)
       
  3552 		{
       
  3553 		case ERemoveDeletedEntries:
       
  3554 			{
       
  3555 			iBackgroundOperationState = EAllocateMemoryOperation;
       
  3556 			DoRemoveDeletedEntriesL();
       
  3557 			break;
       
  3558 			}
       
  3559 		case EAllocateMemoryOperation:
       
  3560 			{
       
  3561 			iBackgroundOperationState = ECheckBlockSize;
       
  3562 			if(CheckAndAllocateMemoryL())
       
  3563 				{
       
  3564 				iBackgroundOperationPerformed = 0;
       
  3565 				break;	
       
  3566 				}
       
  3567 			iBackgroundOperationPerformed++;	
       
  3568 			}
       
  3569 		case ECheckBlockSize:
       
  3570 			{
       
  3571 			iBackgroundOperationState = ENoOperation;	
       
  3572 			SplitBlockL();
       
  3573 			break;
       
  3574 			}
       
  3575 		case ENoOperation:
       
  3576 		default:
       
  3577 			{
       
  3578 			iBackgroundOperationState = ERemoveDeletedEntries;
       
  3579 			// The background operation has run multiple times, without doing
       
  3580 			// much work, so it can be stopped temporarily.
       
  3581 			if(iBackgroundOperationPerformed >= 5)
       
  3582 				{
       
  3583 				iBackgroundOperationPerformed = 0;
       
  3584 				aStopBackgroundOperation = ETrue;
       
  3585 				}
       
  3586 				
       
  3587 			break;
       
  3588 			}		
       
  3589 		}
       
  3590 
       
  3591 	}
       
  3592 
       
  3593 
       
  3594 
       
  3595 /**
       
  3596  *CheckAndAllocateMemory
       
  3597  *Will check the state of the free pool and allocate memory if required.
       
  3598  *Allocation will be done if 70% of the CMsvCacheEntries created are used.
       
  3599  *
       
  3600  *@return  TBool    ETrue,  if allocation has been done.
       
  3601  *		   			EFalse, if no allocation is done.			
       
  3602  */
       
  3603 TBool CMsvIndexAdapter::CheckAndAllocateMemoryL()
       
  3604 	{
       
  3605 	if(iFreePoolInstance->IsAllocationRequiredL())
       
  3606 		{
       
  3607 		iFreePoolInstance->AllocateMemoryL();
       
  3608 		return ETrue;
       
  3609 		}
       
  3610 	return EFalse;	
       
  3611 	}
       
  3612 	
       
  3613 
       
  3614 
       
  3615 	
       
  3616 /**
       
  3617  *SplitBlockL
       
  3618  *Will sort and split the blocks of CMsvCacheEntries.
       
  3619  *
       
  3620  *@return  void     		
       
  3621  */	
       
  3622 void CMsvIndexAdapter::SplitBlockL()
       
  3623 	{
       
  3624 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  3625 	dqIter.SetToFirst();
       
  3626 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  3627 	while((folderNode = dqIter++)!=NULL)
       
  3628 		{
       
  3629 		folderNode->SplitBlockL();
       
  3630 		}
       
  3631 	}
       
  3632 
       
  3633 
       
  3634 
       
  3635 /**
       
  3636  *ForceDeleteEntry
       
  3637  *Deletes the TMsvEntry even if it is not in the cache.This does not require 
       
  3638  *the entry to be locked.
       
  3639  *
       
  3640  *@param aId  TMsvId, id ofthe entry to be deleted.
       
  3641  *@return TInt Any of the system wide error codes.
       
  3642  */
       
  3643 TInt CMsvIndexAdapter::ForceDeleteEntry(TMsvId aId)
       
  3644 	{
       
  3645 	TRAPD(leave, DoForceDeleteEntryL(aId));
       
  3646 	return leave;
       
  3647 	}
       
  3648 
       
  3649 
       
  3650 
       
  3651 /**
       
  3652  *DoForceDeleteEntryL
       
  3653  *Called from ForceDeleteEntry
       
  3654  *
       
  3655  *@param aId  TMsvId, id ofthe entry to be deleted.
       
  3656  *@return void 
       
  3657  */
       
  3658 void CMsvIndexAdapter::DoForceDeleteEntryL(TMsvId aId)
       
  3659 	{
       
  3660 	User::LeaveIfError(iErrorState);
       
  3661 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  3662 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  3663 	
       
  3664 	if(!iDbAdapter)
       
  3665 		{
       
  3666 		User::Leave(ErrorState());
       
  3667 		}
       
  3668 	CMsvCacheEntry* entry = NULL;
       
  3669 	TBool releaseEntry = FindEntryL(aId, entry, EFalse);
       
  3670 	TMsvId parentId = entry->Entry().Parent();
       
  3671 	TRAPD(err, iDbAdapter->DeleteEntryL(aId));
       
  3672 	// If the entry does not exists in cache,
       
  3673 	// we need to release the entry explicitly.
       
  3674 	if(releaseEntry)
       
  3675 		{
       
  3676 		iFreePoolInstance->ReleaseEntry(entry, ETrue);
       
  3677 		User::LeaveIfError(err);
       
  3678 		}
       
  3679 	else
       
  3680 		{
       
  3681 		User::LeaveIfError(err);
       
  3682 		// Otherwise remove the entry from cache.
       
  3683 		dqIter.SetToFirst();
       
  3684 		while((folderNode = dqIter++)!=NULL)
       
  3685 			{
       
  3686 			TRAPD(err, folderNode->DeleteEntryL(aId, ETrue));	
       
  3687 			if(KErrNone == err)
       
  3688 				{
       
  3689 			 	break;
       
  3690 			 	}
       
  3691 			}
       
  3692 		}
       
  3693 	//Find the parent entry in cache and check for any children.
       
  3694 	//If there are no more children under the parent, then
       
  3695 	//reset the owner flag in cache and database.
       
  3696 	CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
       
  3697 	CleanupStack::PushL(children);
       
  3698 	releaseEntry = FindEntryL(parentId, entry, EFalse);
       
  3699 	TRAP(err, 
       
  3700 		GetChildrenIdL(parentId, *children);
       
  3701 		if(0 == children->Count() && entry->Entry().Owner())
       
  3702 			{
       
  3703 			iDbAdapter->UpdateOwnerStatusL(parentId, entry->Entry(), EFalse);
       
  3704 			entry->Entry().SetOwner(EFalse);
       
  3705 			}
       
  3706 		);
       
  3707 	if(releaseEntry)
       
  3708 		{
       
  3709 		iFreePoolInstance->ReleaseEntry(entry, ETrue);
       
  3710 		}
       
  3711 	User::LeaveIfError(err);
       
  3712 	CleanupStack::PopAndDestroy(); //children
       
  3713 	}
       
  3714 
       
  3715 
       
  3716 
       
  3717 /**
       
  3718  *DeleteSelectionUsingTransaction
       
  3719  *Deletes a selection of TMsvEntries.This will also delete enteries that are not locked.
       
  3720  *
       
  3721  *@param aSelection  CMsvEntrySelection&, selection of the TMsvEntries.
       
  3722  @param TInt Any of the system wide error codes.
       
  3723  */
       
  3724 
       
  3725 TInt CMsvIndexAdapter::DeleteSelectionUsingTransaction(const CMsvEntrySelection& aSelection)
       
  3726 	{
       
  3727 	TRAPD(leave, DoDeleteSelectionUsingTransactionL(aSelection));
       
  3728 	return leave;
       
  3729 	}
       
  3730 
       
  3731 
       
  3732 /**
       
  3733  *DoDeleteSelectionUsingTransactionL
       
  3734  *Called from DeleteSelectionUsingTransaction.
       
  3735  *
       
  3736  *@param aSelection  CMsvEntrySelection&, selection of the TMsvEntries.
       
  3737  @param void
       
  3738  */
       
  3739 void CMsvIndexAdapter::DoDeleteSelectionUsingTransactionL(const CMsvEntrySelection& aSelection)
       
  3740 	{
       
  3741     User::LeaveIfError(iErrorState);
       
  3742     if(!iDbAdapter)
       
  3743         {
       
  3744         User::Leave(iErrorState);
       
  3745         }
       
  3746     
       
  3747     CMsvCacheVisibleFolder* folderNode = NULL;
       
  3748     TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  3749     const TInt count = aSelection.Count();
       
  3750     
       
  3751     if(!count)
       
  3752         {
       
  3753         return;
       
  3754         }   
       
  3755         
       
  3756     CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
       
  3757     CleanupStack::PushL(children);
       
  3758     CMsvCacheEntry* entry = NULL;
       
  3759     TBool releaseEntry = FindEntryL(aSelection.At(0), entry, EFalse);
       
  3760     TMsvId parentId = entry->Entry().Parent();
       
  3761     if(releaseEntry)
       
  3762         {
       
  3763         iFreePoolInstance->ReleaseEntry(entry, ETrue);
       
  3764         }
       
  3765 
       
  3766     // Find the parent in the cache - we may need to update its owner status flag both in cache and DB.
       
  3767     TBool updateTheParent = ETrue;
       
  3768     TRAPD(err, releaseEntry = FindEntryL(parentId, entry, EFalse)); // can't let it leave - need to delete the child in any case.
       
  3769     if(err == KErrNotFound)
       
  3770         {
       
  3771         updateTheParent = EFalse;
       
  3772         if(releaseEntry)
       
  3773             {
       
  3774             iFreePoolInstance->ReleaseEntry(entry, ETrue);
       
  3775             }
       
  3776         }
       
  3777     else
       
  3778         {
       
  3779         // Get parent's children.
       
  3780         GetChildrenIdL(parentId, *children); // can leave - we'll let it leave as there's nothing to be rolled back now.
       
  3781         if(children->Count() > 1)
       
  3782             updateTheParent = EFalse;
       
  3783         }
       
  3784         
       
  3785     // Perform DB operations:
       
  3786     //      - Delete the entry.
       
  3787     //      - Update owner status flag of the parent.
       
  3788     iDbAdapter->DeleteEntryL(aSelection); // can leave - we'll let it leave as there's nothing to be rolled back now.
       
  3789     if(updateTheParent)
       
  3790         {
       
  3791         TRAP(err, iDbAdapter->UpdateOwnerStatusL(parentId, entry->Entry(), EFalse));
       
  3792         }
       
  3793     // Leave if DB operations fail. Cache is not touched.
       
  3794     if(err)
       
  3795         {
       
  3796         TRAP_IGNORE(iDbAdapter->RollbackTransactionL()); //
       
  3797         User::Leave(err);
       
  3798         }
       
  3799     else
       
  3800         {
       
  3801         if(updateTheParent)
       
  3802             {
       
  3803             entry->Entry().SetOwner(EFalse);
       
  3804             }
       
  3805         // Do the cache operations. These don't require any memory allocation and cannot fail.
       
  3806         for (TInt index=0; index<count; ++index)
       
  3807             {
       
  3808             // If the entry is a visible folder, then delete the node.
       
  3809             dqIter.SetToFirst(); 
       
  3810             while((folderNode = dqIter++)!=NULL)
       
  3811                 {
       
  3812                 if(folderNode->GetFolderId() == aSelection.At(index))
       
  3813                     {
       
  3814                     folderNode->iDlink.Deque();
       
  3815                     delete folderNode;
       
  3816                     break;
       
  3817                     }
       
  3818                 }
       
  3819             
       
  3820             // Delete the entry from under its parent visible folder.
       
  3821             dqIter.SetToFirst();
       
  3822             while((folderNode = dqIter++)!=NULL)
       
  3823                 {
       
  3824                 TRAPD(err, folderNode->DeleteEntryL(aSelection.At(index), ETrue));  
       
  3825                 if(KErrNone == err) 
       
  3826                     {
       
  3827                     break;
       
  3828                     }
       
  3829                 }
       
  3830             }
       
  3831         }
       
  3832     
       
  3833     // Update SearchSort delta cache.
       
  3834     TMsgType aType(EDeletedMsg);
       
  3835     if(CMSvSearchSortCacheManager::Instance()->iManagerEntry != NULL)
       
  3836         {   
       
  3837         if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0)
       
  3838             {
       
  3839             for(TInt ii =0; ii < aSelection.Count() ; ii ++)
       
  3840                 {
       
  3841                 CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aSelection[ii],aType);
       
  3842                 }
       
  3843             }
       
  3844         }
       
  3845 
       
  3846     CleanupStack::PopAndDestroy(); //children
       
  3847 	}
       
  3848 
       
  3849 
       
  3850 
       
  3851 /**
       
  3852  * BeginTransaction()
       
  3853  * 
       
  3854  * Starts a new DB transaction.
       
  3855  */
       
  3856 void CMsvIndexAdapter::BeginTransaction()
       
  3857 	{
       
  3858 	if(iDbAdapter)
       
  3859 		{
       
  3860 		TRAP_IGNORE(iDbAdapter->BeginTransactionL());
       
  3861 		}
       
  3862 	}
       
  3863 
       
  3864 
       
  3865 
       
  3866 /**
       
  3867  * CommitTransaction()
       
  3868  * 
       
  3869  * Commits an already opened transaction.
       
  3870  */
       
  3871 void CMsvIndexAdapter::CommitTransaction()
       
  3872 	{
       
  3873 	if(iDbAdapter)
       
  3874 		{
       
  3875 		TRAP_IGNORE(iDbAdapter->CommitTransactionL());
       
  3876 		}
       
  3877 	}
       
  3878 	
       
  3879 
       
  3880 
       
  3881 /**
       
  3882  * DoRemoveDeletedEntriesL()
       
  3883  * 
       
  3884  * Deletes all the entries whose PcSyncCount is 0 and delete flag is set.
       
  3885  */
       
  3886 TBool CMsvIndexAdapter::DoRemoveDeletedEntriesL()
       
  3887 	{
       
  3888 	CMsvCacheEntry* parent = NULL;
       
  3889 	CMsvCacheEntry* entry = NULL;
       
  3890 	CMsvCacheEntry* siblingEntry = NULL;
       
  3891 	TMsvId siblingId = KMsvNullIndexEntryId;
       
  3892 	TMsvId visibleFolder = KMsvNullIndexEntryId;
       
  3893 	TMsvId firstchildId = KMsvNullIndexEntryId;
       
  3894 	TInt commitCount = 1;
       
  3895 	
       
  3896 	// Find deleted folder
       
  3897 	FindEntryL(KMsvDeletedEntryFolderEntryId, parent, ETrue);
       
  3898 
       
  3899 	CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
       
  3900 	CleanupStack::PushL(selection);
       
  3901 
       
  3902 	// All deleted entries are a child of deleted folder
       
  3903 	if(iDbAdapter->GetFirstChildIdL(parent->Entry().Id(),firstchildId))
       
  3904 		{
       
  3905 		iDbAdapter->GetEntryL(firstchildId, entry, visibleFolder);
       
  3906 		}
       
  3907 					
       
  3908 	while(entry && commitCount > 0)
       
  3909 		{
       
  3910 		if (entry->Entry().PcSyncCount() <= 0)
       
  3911 			{
       
  3912 			// Add entry to list of things to be deleted
       
  3913 			__ASSERT_DEBUG(entry->Entry().Deleted(), PanicServer(EMsvDeletedFlagNotSet));
       
  3914 			
       
  3915 			User::LeaveIfError(LockEntryAndStore(entry->Entry().Id()));
       
  3916 			selection->AppendL(entry->Entry().Id());
       
  3917 			// Will the next entry be deleted?
       
  3918 			if(iDbAdapter->GetNextSiblingL(entry->Entry().Id(), parent->Entry().Id(), siblingId))
       
  3919 				{
       
  3920 				iDbAdapter->GetEntryL(siblingId, siblingEntry, visibleFolder);
       
  3921 				if(siblingEntry->Entry().PcSyncCount() > 0)
       
  3922 					{
       
  3923 					commitCount--;
       
  3924 					}
       
  3925 				}
       
  3926 			else
       
  3927 			    break;
       
  3928 			}
       
  3929 		iFreePoolInstance->ReleaseEntryWithoutTransaction(entry);
       
  3930 		entry = siblingEntry;
       
  3931 		}
       
  3932 
       
  3933 	if (selection->Count() > 0)
       
  3934 		{
       
  3935 		User::LeaveIfError(DeleteSelection(*selection));
       
  3936 		}
       
  3937 	CleanupStack::PopAndDestroy(); // selection
       
  3938 	
       
  3939 	// Possibly more to delete if we did not get to the end of the child list
       
  3940 	TBool retVal = entry != NULL;
       
  3941 	iFreePoolInstance->ReleaseEntryWithoutTransaction(entry);
       
  3942 	return retVal;
       
  3943 	}
       
  3944 
       
  3945 
       
  3946 
       
  3947 
       
  3948 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  3949 
       
  3950 /**
       
  3951  * GetChildrenAllL()
       
  3952  *
       
  3953  * Code added for PREQ 557.
       
  3954  *
       
  3955  * The function is similar to function GetChildrenL(), but
       
  3956  * additionally it fetches entries from all the drive in the
       
  3957  * preferred drive list.
       
  3958  */
       
  3959 void CMsvIndexAdapter::GetChildrenAllL(TMsvId aId, CArrayPtr<const TMsvEntry>& aSelection, const TMsvSelectionOrdering& aOrdering, TUid aMtm, TBool aFilterByOwnerId, TSecureId aOwnerId)
       
  3960 	{
       
  3961 	TMsvPreferredDrive driveEntry;
       
  3962 	CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
       
  3963 	for(TInt index=0; index<driveList->Count(); ++index)
       
  3964 		{
       
  3965 		driveEntry = (*driveList)[index];
       
  3966 		if(EMsvMessageStoreAvailableStatus == driveEntry.status)
       
  3967 			{
       
  3968 			GetChildrenL(MaskTMsvId(driveEntry.driveId, aId), aSelection, aOrdering, aMtm, aFilterByOwnerId, aOwnerId);
       
  3969 			}
       
  3970 		}
       
  3971 	}
       
  3972 
       
  3973 
       
  3974 
       
  3975 
       
  3976 /**
       
  3977  * GetChildrenIdAll()
       
  3978  *
       
  3979  * Code added for PREQ 557.
       
  3980  *
       
  3981  * The function is similar to function GetChildrenId(), but
       
  3982  * additionally it fetches entries from all the drive in the
       
  3983  * preferred drive list.
       
  3984  */
       
  3985 TInt CMsvIndexAdapter::GetChildrenIdAll(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection)
       
  3986 	{
       
  3987 	TSecureId dummy = KMsvServerId.iId;
       
  3988 	return GetChildrenIdAll(aId, aFilter, aSelection, EFalse, dummy);
       
  3989 	}
       
  3990 	
       
  3991 	 
       
  3992 
       
  3993 // Overloaded.
       
  3994 TInt CMsvIndexAdapter::GetChildrenIdAll(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection, TBool aFilterByOwnerId, TSecureId aOwnerId)
       
  3995 	{
       
  3996 	TInt err = KErrNone;
       
  3997 	TMsvPreferredDrive driveEntry;
       
  3998 	CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
       
  3999 	for(TInt index=0; index<driveList->Count(); ++index)
       
  4000 		{
       
  4001 		driveEntry = (*driveList)[index];
       
  4002 		if(EMsvMessageStoreAvailableStatus == driveEntry.status)
       
  4003 			{
       
  4004 			err = GetChildrenId(MaskTMsvId(driveEntry.driveId, aId), aFilter, aSelection, aFilterByOwnerId, aOwnerId);
       
  4005 			if(KErrNone != err)
       
  4006 				{
       
  4007 				return err;
       
  4008 				}
       
  4009 			}
       
  4010 		}
       
  4011 	return KErrNone;
       
  4012 	}
       
  4013 	
       
  4014 
       
  4015 
       
  4016 /**
       
  4017  * RemoveDriveL()
       
  4018  * 
       
  4019  * This function is added in PREQ 557.
       
  4020  * @param TUint: The drive priority, which is also the index of drive 
       
  4021  *               entry in message server data structure.
       
  4022  * @param TBool: If the drive still remains in the preferred drive list.
       
  4023  * @return None.
       
  4024  * 
       
  4025  */
       
  4026 void CMsvIndexAdapter::RemoveDriveL(TUint aDriveId, TUint aDriveIndex, TBool aIsStdFolderVisible /*=ETrue */)
       
  4027 	{
       
  4028 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  4029 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  4030 
       
  4031 	// Browse through the folder list.
       
  4032     dqIter.SetToFirst();
       
  4033     while ((folderNode = dqIter++) != NULL)
       
  4034         {
       
  4035         // If the folder is from the same drive.
       
  4036         // Caution: If the current drive is removed, 
       
  4037         // this will also include root and localService.
       
  4038         if(folderNode->GetDrive() == aDriveId)
       
  4039         	{
       
  4040        				folderNode->iDlink.Deque();
       
  4041        				delete folderNode;
       
  4042         			}
       
  4043         }	// while ((folderNode = dqIter++) != NULL)
       
  4044     
       
  4045     // If current drive is removed, 
       
  4046     // Remove localService entry as well.
       
  4047 
       
  4048 	// Detach the database and remove maxId entry.   	
       
  4049     if(!aIsStdFolderVisible)
       
  4050     	{
       
  4051     	iDbAdapter->DetachDBL(aDriveId);
       
  4052     	iMaxMsvIdList[aDriveId] = NULL;
       
  4053 
       
  4054 		CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aDriveIndex, KMsvInvalidDriveId);
       
  4055 		CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvDriveDiskNotAvailableStatus);
       
  4056 		}
       
  4057 	}
       
  4058 
       
  4059 
       
  4060 
       
  4061 
       
  4062 
       
  4063 /**
       
  4064  * AddDriveL()
       
  4065  * 
       
  4066  * This function is added in PREQ 557.
       
  4067  * @param TUint: The drive priority, which is also the index of drive 
       
  4068  *               entry in message server data structure.
       
  4069  * 
       
  4070  */
       
  4071 void CMsvIndexAdapter::AddDriveL(TUint aDrivePriority)
       
  4072 	{
       
  4073 	// Assign a new drive id.
       
  4074 	TUint driveId = GetNextAvailableDriveId();
       
  4075 	CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aDrivePriority, driveId);
       
  4076 	
       
  4077 	// Attach the database.
       
  4078 	TMsvId maxId;
       
  4079 	TMsvPreferredDrive driveEntry;
       
  4080 	CMsvPreferredDriveList::GetDriveList()->DriveInfoL(aDrivePriority, driveEntry);
       
  4081 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)	
       
  4082 	TRAPD(err, iDbAdapter->AttachDBL(driveEntry.driveNum, driveId, maxId, &iServer.MessageDBAdapter()));
       
  4083 #else
       
  4084 	TRAPD(err, iDbAdapter->AttachDBL(driveEntry.driveNum, driveId, maxId));
       
  4085 #endif
       
  4086 	WrapDBErrorL(err);
       
  4087 	
       
  4088 	// Insert the max Id in the list.
       
  4089 	iMaxMsvIdList[driveId] = ((maxId >= MaskTMsvId(driveId, KFirstFreeEntryId))? (maxId+1) : MaskTMsvId(driveId, KFirstFreeEntryId));
       
  4090 	}
       
  4091 
       
  4092 
       
  4093 
       
  4094 
       
  4095 /**
       
  4096  * ChangeDriveL()
       
  4097  * 
       
  4098  * This function is added in PREQ 557.
       
  4099  * @param TUint: The drive priority, which is also the index of drive 
       
  4100  *               entry in message server data structure.
       
  4101  * @param TBool: If the previous drive still remains in the preferred drive list.
       
  4102  * @return None.
       
  4103  * 
       
  4104  */
       
  4105 void CMsvIndexAdapter::ChangeDriveL(TUint aNewDriveIndex, TBool aIsStdFolderVisible /*= ETrue*/)
       
  4106 	{
       
  4107 	// Rule1: Remove all non-standard folder node of current drive.
       
  4108 	TInt oldCurrentDriveIndex = CMsvPreferredDriveList::GetDriveList()->CurrentDriveIndex();
       
  4109 	RemoveDriveL(KCurrentDriveId, oldCurrentDriveIndex, EFalse);
       
  4110 
       
  4111 	// If old drive should be visible, re-attach the drive.
       
  4112 	// This assigns a new drive id to the old current drive.
       
  4113 	if(aIsStdFolderVisible)
       
  4114 		{
       
  4115 		CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(oldCurrentDriveIndex, EMsvMessageStoreAvailableStatus);
       
  4116 		AddDriveL(oldCurrentDriveIndex);
       
  4117 		}
       
  4118 
       
  4119 	
       
  4120 	// Clear search sort cache db table
       
  4121 	TRAPD(err, GetDbAdapter()->ClearDBContentsL());
       
  4122 	WrapDBErrorL(err);
       
  4123 	
       
  4124 	
       
  4125 	// 3. Flush up entries from new current drive, 
       
  4126 	// if it is already attached.
       
  4127 	
       
  4128 	TMsvPreferredDrive driveEntry;
       
  4129 	CMsvPreferredDriveList::GetDriveList()->DriveInfoL(aNewDriveIndex, driveEntry);	
       
  4130 	if(KMsvInvalidDriveId != driveEntry.driveId)
       
  4131 		{
       
  4132 		RemoveDriveL(driveEntry.driveId, aNewDriveIndex, EFalse);
       
  4133 		}
       
  4134 	
       
  4135 
       
  4136 	// Assign a new drive Id to the drive.
       
  4137 	CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aNewDriveIndex, KCurrentDriveId);
       
  4138 	CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aNewDriveIndex, EMsvMessageStoreAvailableStatus);
       
  4139 	
       
  4140 
       
  4141 	// Assign a new drive Id to the drive.
       
  4142 	CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aNewDriveIndex, KCurrentDriveId);
       
  4143 	CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aNewDriveIndex, EMsvMessageStoreAvailableStatus);
       
  4144 	// --------- Attach the database and update MaxId.		
       
  4145 	TMsvId maxId;
       
  4146 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
  4147 	TRAP(err, iDbAdapter->AttachDBL(driveEntry.driveNum, KCurrentDriveId, maxId, &iServer.MessageDBAdapter()));
       
  4148 #else
       
  4149 	TRAP(err, iDbAdapter->AttachDBL(driveEntry.driveNum, KCurrentDriveId, maxId));
       
  4150 #endif
       
  4151 	WrapDBErrorL(err);
       
  4152 	
       
  4153 	// Insert the max Id in the list.
       
  4154 	iMaxMsvIdList[KCurrentDriveId] = ((maxId >= MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId))? (maxId+1) : MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId));		
       
  4155 
       
  4156 
       
  4157 	// ------- Create a root node and its children.
       
  4158 	TMsvId folderId = MaskTMsvId(KCurrentDriveId, KMsvRootIndexEntryId);
       
  4159 	
       
  4160 	// Add local service folder node in the folder list.
       
  4161 	iRootNode = CMsvCacheVisibleFolder::NewL(folderId);
       
  4162 	iFolderListHeader.AddFirst(*iRootNode);
       
  4163 	
       
  4164 	// Fetch children of root folder to cache.
       
  4165 	RPointerArray<CMsvCacheEntry> childEntryList;
       
  4166 	CleanupClosePushL(childEntryList);
       
  4167 	
       
  4168 	TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
       
  4169 	WrapDBErrorL(err);
       
  4170 	iRootNode->AddEntryListL(childEntryList, ETrue);
       
  4171 	childEntryList.Reset();	
       
  4172 
       
  4173 	
       
  4174 	// ------- Create a local service node and its children.
       
  4175 	folderId = MaskTMsvId(KCurrentDriveId, KMsvLocalServiceIndexEntryId);
       
  4176 	
       
  4177 	// Add local service folder node in the folder list.
       
  4178 	CMsvCacheVisibleFolder* localServiceFolder = CMsvCacheVisibleFolder::NewL(folderId);
       
  4179 	iFolderListHeader.AddFirst(*localServiceFolder);
       
  4180 	
       
  4181 	TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
       
  4182 	WrapDBErrorL(err);
       
  4183 	localServiceFolder->AddEntryListL(childEntryList, ETrue);
       
  4184 
       
  4185 	CleanupStack::PopAndDestroy();   // childEntryList.	
       
  4186 	}
       
  4187 
       
  4188 
       
  4189 
       
  4190 /**
       
  4191  * GetNextAvailableDriveId()
       
  4192  * 
       
  4193  * This function is added in PREQ 557.
       
  4194  * @param None: 
       
  4195  * @return TUint: The next available drive Id.
       
  4196  * 
       
  4197  */
       
  4198 TUint CMsvIndexAdapter::GetNextAvailableDriveId()
       
  4199 	{
       
  4200 	TMsvPreferredDrive driveEntry;
       
  4201 	TUint driveId = iFirstFreeDriveId;
       
  4202 	for(TUint index=0; index<8; index++)
       
  4203 		{
       
  4204 		TBool driveIdFound = EFalse;
       
  4205 		CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
       
  4206 		for(TInt index=0; index<driveList->Count(); ++index)
       
  4207 			{
       
  4208 			driveEntry = (*driveList)[index];
       
  4209 			if(driveId == driveEntry.driveId)
       
  4210 				{
       
  4211 				driveIdFound = ETrue;
       
  4212 				break;
       
  4213 				}
       
  4214 			}
       
  4215 		if(EFalse == driveIdFound)
       
  4216 			{
       
  4217 			iFirstFreeDriveId = ((driveId)%7 ? (driveId+1) : 2);
       
  4218 			return driveId;
       
  4219 			}
       
  4220 		driveId = ((driveId)%7 ? (driveId+1) : 2);
       
  4221 		}
       
  4222 	return KErrNone;
       
  4223 	}
       
  4224 	
       
  4225 	
       
  4226 
       
  4227 /**
       
  4228  * ReloadCacheL()
       
  4229  * 
       
  4230  * This function is used by backup and restore functionality
       
  4231  * when it finds that DB being restored is changed. The function
       
  4232  * destroys the cache of the current drive and recreates it.
       
  4233  */
       
  4234 void CMsvIndexAdapter::ReloadCacheL()
       
  4235 	{
       
  4236 	TUint currDriveIndex = CMsvPreferredDriveList::GetDriveList()->CurrentDriveIndex();
       
  4237 	TDriveNumber currDriveNum = CMsvPreferredDriveList::GetDriveList()->CurrentDriveNumber();
       
  4238 
       
  4239 	// Attach the database.
       
  4240 	TMsvId maxId;
       
  4241 #if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
       
  4242 	TRAPD(err, iDbAdapter->AttachDBL(currDriveNum, KCurrentDriveId, maxId, &iServer.MessageDBAdapter()));
       
  4243 #else
       
  4244 	TRAPD(err, iDbAdapter->AttachDBL(currDriveNum, KCurrentDriveId, maxId));
       
  4245 #endif
       
  4246 	WrapDBErrorL(err);
       
  4247 	
       
  4248 	// Update the entry in drive list.
       
  4249 	CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(currDriveIndex, EMsvMessageStoreAvailableStatus);
       
  4250 
       
  4251 	// Insert the max Id in the list.
       
  4252 	iMaxMsvIdList[KCurrentDriveId] = ((maxId >= MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId))? (maxId+1) : MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId));		
       
  4253 
       
  4254 	TMsvId folderId = MaskTMsvId(KCurrentDriveId, KMsvRootIndexEntryId);
       
  4255 	
       
  4256 	// Add local service folder node in the folder list.
       
  4257 	iRootNode = CMsvCacheVisibleFolder::NewL(folderId);
       
  4258 	iFolderListHeader.AddFirst(*iRootNode);
       
  4259 	
       
  4260 	// Fetch children of root folder to cache.
       
  4261 	RPointerArray<CMsvCacheEntry> childEntryList;
       
  4262 	CleanupClosePushL(childEntryList);
       
  4263 	
       
  4264 	// Updating children under root node.	
       
  4265 	TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
       
  4266 	WrapDBErrorL(err);
       
  4267 	iRootNode->AddEntryListL(childEntryList, ETrue);
       
  4268 	childEntryList.Reset();	
       
  4269 
       
  4270 	// Create a local service node and its children.
       
  4271 	folderId = MaskTMsvId(KCurrentDriveId, KMsvLocalServiceIndexEntryId);
       
  4272 	
       
  4273 	// Add local service folder node in the folder list.
       
  4274 	CMsvCacheVisibleFolder* localServiceFolder = CMsvCacheVisibleFolder::NewL(folderId);
       
  4275 	iFolderListHeader.AddFirst(*localServiceFolder);
       
  4276 	
       
  4277 	// Fetch children of localService folder to cache.
       
  4278 	TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
       
  4279 	WrapDBErrorL(err);
       
  4280 	localServiceFolder->AddEntryListL(childEntryList, ETrue);
       
  4281 
       
  4282 	CleanupStack::PopAndDestroy();   // childEntryList.
       
  4283 	}
       
  4284 #endif 		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4285 
       
  4286 
       
  4287 
       
  4288 
       
  4289 #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  4290 #ifdef _DEBUG
       
  4291 void CMsvIndexAdapter::PrintL()
       
  4292 	{
       
  4293 	_LIT8(KFolderId, "FOLDER ID: ");
       
  4294 	_LIT8(KDriveId, "      DRIVE ID: ");
       
  4295 	_LIT8(KComplete, "      COMPLETE FLAG: ");
       
  4296 	_LIT8(KFalse, "FALSE.");
       
  4297 	_LIT8(KTrue, "TRUE.");
       
  4298 	
       
  4299 	RFileLogger logger;
       
  4300 	CleanupClosePushL(logger);
       
  4301 	if (logger.Connect() == KErrNone)
       
  4302 		{
       
  4303 		logger.CreateLog(_L("msgs"), _L("Cache.txt"), EFileLoggingModeAppend);
       
  4304 		logger.SetDateAndTime(EFalse, EFalse);
       
  4305 		logger.Write(_L(" Message Index Cache Structure."));
       
  4306 		logger.Write(_L("--------------------------------"));
       
  4307 		logger.Write(_L(""));
       
  4308 		}
       
  4309 	
       
  4310 	CMsvCacheVisibleFolder* folderNode = NULL;
       
  4311 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
       
  4312 
       
  4313 	dqIter.SetToFirst();
       
  4314 	while((folderNode = dqIter++)!=NULL)
       
  4315 		{
       
  4316 		RBuf8 text;
       
  4317 		CleanupClosePushL(text);
       
  4318 		text.CreateL(100);
       
  4319 		text.Append(KFolderId);
       
  4320 		text.AppendNum(folderNode->GetFolderId());
       
  4321 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
       
  4322 		text.Append(KDriveId);
       
  4323 		text.AppendNum(folderNode->GetDrive());
       
  4324 #endif
       
  4325 		text.Append(KComplete);
       
  4326 		if(folderNode->IsComplete())
       
  4327 			{
       
  4328 			text.Append(KTrue);
       
  4329 			}
       
  4330 		else
       
  4331 			{
       
  4332 			text.Append(KFalse);
       
  4333 			}
       
  4334 		logger.Write(text);
       
  4335 		CleanupStack::PopAndDestroy();  // text
       
  4336 		folderNode->Print(logger);
       
  4337 		logger.Write(_L(""));		
       
  4338 		}
       
  4339 	logger.CloseLog();
       
  4340 	CleanupStack::PopAndDestroy();  // logger
       
  4341 	}
       
  4342 #endif			// #ifdef _DEBUG	
       
  4343 #endif			// #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
       
  4344