--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/msvindexadapter.cpp Fri Jun 04 10:32:16 2010 +0100
@@ -0,0 +1,4341 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#ifdef _DEBUG
+#undef _NO_SERVER_LOGGING_
+#endif
+
+/**
+ * User Includes
+ */
+#include "MSVSERV.H"
+#include "MSVARRAY.H"
+#include "msvdbadapter.h"
+#include "msvcacheentry.h"
+#include "msvindexadapter.h"
+#include "msventryfreepool.h"
+#include "msvcachevisiblefolder.h"
+#include "msvsearchsortdeltacache.h"
+#include "msvsearchsortcachemanager.h"
+
+/**
+ *System Includes
+ */
+#include <msvuids.h>
+#include <msvstd.h>
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include "msvconsts.h"
+#endif
+
+/**
+ * MACRO DEFINITIONS
+ */
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ #define INITIAL_NUM_ENTRIES 10
+#else
+ #define INITIAL_NUM_ENTRIES 13
+#endif
+
+/**
+ * CONSTANT DEFINITIONS
+ */
+const TInt KMsvMtmListGranularity=8;
+const TInt KMsvChangeAttributesListGranularity=32;
+
+
+
+/**
+ * FUNCTION DEFINITIONS
+ */
+
+
+
+/**
+ * CMsvIndexAdapter()
+ */
+CMsvIndexAdapter::CMsvIndexAdapter(CMsvServer& aServer)
+ :CActive(EPriorityStandard), iServer(aServer), iFolderListHeader(CMsvCacheVisibleFolder::iOffset)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+
+
+
+/**
+ * ~CMsvIndexAdapter()
+ */
+CMsvIndexAdapter::~CMsvIndexAdapter()
+ {
+
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Destroying CMsvIndexAdapter object."));
+#endif
+
+ Cancel();
+
+ // 1. Close the database.
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Closing the database."));
+#endif
+ if(iDbAdapter != NULL)
+ delete iDbAdapter;
+
+ // 2. Delete Cache.
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Destroying Cache."));
+#endif
+
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+
+ dqIter.SetToFirst();
+ while ((folderNode = dqIter++) != NULL)
+ {
+ folderNode->iDlink.Deque();
+ delete folderNode;
+ }
+
+ iFreePoolInstance->ReleaseEntry(iRootEntry);
+ iRootEntry = NULL;
+
+ // 3. Delete internal data structure.
+ iNonCommittedAddedEntryList.ResetAndDestroy();
+ iNonCommittedChangedEntryList.Reset();
+ iNonCommittedAddedEntryList.Close();
+ iNonCommittedChangedEntryList.Close();
+
+ // 4. Flush extra memory in entry freepool.
+ if(iFreePoolInstance != NULL)
+ {
+ iFreePoolInstance->FlushExcessMemory();
+ }
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // Added for 557.
+ iMaxMsvIdList.Close();
+#endif
+
+ delete iIdle;
+ }
+
+
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+/**
+ * NewL()
+ * @return The newly created index adapter object.
+ *
+ * Function added as part of PREQ 557.
+ * It returns an instance of CMsvIndexAdapter class.
+ */
+CMsvIndexAdapter* CMsvIndexAdapter::NewL(CMsvServer& aServer)
+ {
+ CMsvIndexAdapter *self = new(ELeave) CMsvIndexAdapter(aServer);
+ CleanupStack::PushL(self);
+
+ self->ConstructL();
+
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+
+
+/**
+ * ConstructL()
+ *
+ * Function added as part of PREQ 557.
+ * The function is called from NewL().
+ * 1. Create the DB adapter object.
+ * 2. Initialize freepool object.
+ * 3. Create the root entry in cache.
+ * 4. Browse through the preferred drive list.
+ * i. For each drive in the preferred drive list the function
+ * assigns a unique drive-id (0< Id <8).
+ * ii. Attach the DB to the primary database.
+ * iii. Update the maxId of the database to MaxId table.
+ * iv. If the database is not compatible or corrupt, update the
+ * appropriate drive status in CMsvServer data structure.
+ * v. Fetch children of root entry and Local-Service entry from the DB to the cache.
+ */
+void CMsvIndexAdapter::ConstructL()
+ {
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Inside ConstructL()..."));
+#endif
+
+ // Create database adapter object.
+ iDbAdapter = CMsvDBAdapter::NewL();
+
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("The database object is created succesfully."));
+#endif
+
+ iProgress.iCompleted = 0;
+ iProgress.iTotal = iProgress.iRemaining = INITIAL_NUM_ENTRIES;
+
+ // Initialize freepool object.
+ iFreePoolInstance = CMsvEntryFreePool::Instance();
+ iFreePoolInstance->SetEssentialParam(&iFolderListHeader, this);
+
+ // Drive id zero will be synonym of KCurrentDriveId. Drive
+ // id of a drive (including current) drive will never be zero.
+ // Drive of the current drive will always by KCurrentDriveId.
+ TUint driveId = KCurrentDriveId;
+
+ // Since driveId starts from 1, the first
+ // entry in iMaxMsvIdList is not used.
+ // Enter a dummy entry in location zero.
+ iMaxMsvIdList.InsertL(0, 0);
+
+ iProgress.iCompleted++;
+ iProgress.iRemaining--;
+ iProgress.iId = KMsvRootIndexEntryId;
+
+ // For each drive in the preferred drive list, perform followings...
+ // 1. Check if a valid message store is available.
+ // 2. If not, skip the drive.
+ // 3. Assign a new drive Id to the drive and
+ // update the entry in preferred drive list.
+ // 4. Attach the drive database to the primary DB.
+ // 5. Update the max Id list.
+ // 6. For current drive, fetch the children of root entry into cache.
+ // 7. Fetch children of localService into cache.
+ CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
+ TUint curDriveIndex = driveList->CurrentDriveIndex();
+ for(TInt index=curDriveIndex; index<driveList->Count(); index++)
+ {
+ TMsvPreferredDrive driveEntry;
+ driveList->DriveInfoL(index, driveEntry);
+
+ if(EMsvMessageStoreAvailableStatus == driveEntry.status)
+ {
+ // Assign a unique drive-id.
+ driveList->UpdateDriveIdL(index, driveId);
+
+ // Attach the database.
+ TMsvId maxId;
+ iDbAdapter->AttachDBL(driveEntry.driveNum, driveId, maxId);
+
+ // Insert the max Id in the list.
+ iMaxMsvIdList.InsertL( ((maxId >= MaskTMsvId(driveId, KFirstFreeEntryId))? (maxId+1): MaskTMsvId(driveId, KFirstFreeEntryId)), driveId);
+ driveId++;
+ }
+ iProgress.iCompleted++;
+ iProgress.iRemaining--;
+ }
+
+ iFirstFreeDriveId = (driveId%8)? (driveId%8): 2;
+
+ // Initializing remaining entries in MaxMsvId list.
+ for(TInt index=driveId; index<8; index++)
+ {
+ iMaxMsvIdList.InsertL(NULL, index);
+ }
+
+ // For current drive fetch children of root entries also.
+ RPointerArray<CMsvCacheEntry> childEntryList;
+ CleanupClosePushL(childEntryList);
+ // Create root entry node in the cache. A root folder node will never
+ // be swapped out of cache. The children of root entry will be the
+ // children of root entry in the current drive.
+ // Root id is masked to set the driveId in the folder node.
+ iRootNode = CMsvCacheVisibleFolder::NewL(MaskTMsvId(KCurrentDriveId, KMsvRootIndexEntryId));
+ iFolderListHeader.AddFirst(*iRootNode);
+ iRootNode->SetComplete(ETrue);
+ iDbAdapter->GetChildrenL(KMsvRootIndexEntryId, childEntryList);
+ iRootNode->AddEntryListL(childEntryList, ETrue);
+ childEntryList.Reset();
+
+ // Fetch child of LocalServices.
+ CMsvCacheVisibleFolder* localServiceFolder = CMsvCacheVisibleFolder::NewL(MaskTMsvId(KCurrentDriveId, KMsvLocalServiceIndexEntryId));
+ iFolderListHeader.AddFirst(*localServiceFolder);
+ iDbAdapter->GetChildrenL(KMsvLocalServiceIndexEntryId, childEntryList);
+ localServiceFolder->AddEntryListL(childEntryList, ETrue);
+ CleanupStack::PopAndDestroy(1); //childEntryList
+
+ // Create root entry.
+ iRootEntry = iFreePoolInstance->EntryL(); //taking it from the freepool.
+ iRootEntry->Entry().iType = KUidMsvRootEntry;
+ iRootEntry->Entry().iDate.UniversalTime();
+ iRootEntry->Entry().SetId(KMsvRootIndexEntryId);
+ iRootEntry->Entry().SetParent(KErrNotFound);
+ iRootEntry->Entry().SetOwner(ETrue);
+ iRootEntry->Entry().iSize = 0;
+
+ // Update progress
+ iProgress.iCompleted = iProgress.iTotal;
+ iProgress.iRemaining = 0;
+ iProgress.iId = KMsvRootIndexEntryId;
+
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Cache initialized succesfully."));
+#endif
+
+ iIdle = CIdle::NewL(CActive::EPriorityIdle);
+ CompleteSelf();
+ }
+
+
+
+/**
+GetInPreparationIds
+*/
+void CMsvIndexAdapter::GetInPreparationIds(CMsvEntrySelection& aSelection, TUint aDriveId /*DEFAULT = 0 */)
+ {
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->GetInPreparationIdL(aSelection, aDriveId));
+ }
+ }
+
+
+#else // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+/**
+ * NewL()
+ * @param TFileName: DB File Name.
+ * @return The newly created index adapter.
+ *
+ * It returns an instance of CMsvIndexAdapter class.
+ */
+CMsvIndexAdapter* CMsvIndexAdapter::NewL(CMsvServer& aServer, const TFileName& aDbFileName)
+ {
+ CMsvIndexAdapter *self = new(ELeave) CMsvIndexAdapter(aServer);
+ CleanupStack::PushL(self);
+
+ self->ConstructNewL(aDbFileName);
+
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+
+
+/**
+ * OpenL()
+ * @param TFileName: DB File Name.
+ * @return The newly created index adapter.
+ *
+ * It returns an instance of CMsvIndexAdapter class.
+ */
+CMsvIndexAdapter* CMsvIndexAdapter::OpenL(CMsvServer& aServer, const TFileName& aDbFileName)
+ {
+ CMsvIndexAdapter *self = new(ELeave) CMsvIndexAdapter(aServer);
+ CleanupStack::PushL(self);
+
+ self->ConstructOpenL(aDbFileName);
+
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+
+
+/**
+ * ConstructNewL()
+ *
+ * The function is called from NewL().
+ * 1. Check if a database with the passed name already exists.
+ * 1.1. If yes, open the database.
+ * 1.2. If no, create a new database with the same name.
+ * 2. Creates entry cache.
+ * 3. If a new database is created, create root entry also.
+ */
+void CMsvIndexAdapter::ConstructNewL(const TFileName& aDbFileName)
+ {
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Creating CMsvIndexAdapter instance..."));
+#endif
+
+ // Delete the database first, if it already exists.
+ CMsvDBAdapter::DeleteDB(aDbFileName);
+
+ // Get the instance of free pool.
+ iFreePoolInstance = CMsvEntryFreePool::Instance();
+
+ // Create the new database with the same name.
+ // If this leaves, nothing can be done and let NewL() leave.
+ iDbAdapter = CMsvDBAdapter::NewL(aDbFileName);
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("A new database %s is created..."), &aDbFileName);
+#endif
+
+ iProgress.iTotal = iProgress.iRemaining = 1; //root
+ // Create root entry.
+ CreateInitialSetOfEntriesL();
+
+
+#ifndef _NO_SERVER_LOGGING_
+// iServer.Log(_L("Cache initialized succesfully."));
+#endif
+
+ iNextCreateId = KFirstFreeEntryId;
+ iIdle = CIdle::NewL(CActive::EPriorityIdle);
+ CompleteSelf();
+ }
+
+
+
+
+
+/**
+ * ConstructOpenL()
+ *
+ * The function is called from NewL().
+ * 1. Check if a database with the passed name already exists.
+ * 1.1. If yes, open the database.
+ * 1.2. If no, create a new database with the same name.
+ * 2. Creates entry cache.
+ * 3. If a new database is created, it then read message resource file
+ * and creates entry as mentioned in cache and database.
+ */
+void CMsvIndexAdapter::ConstructOpenL(const TFileName& aDbFileName)
+ {
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Creating CMsvIndexAdapter instance..."));
+#endif
+
+ // Get the instance of free pool
+ iFreePoolInstance = CMsvEntryFreePool::Instance();
+
+ // Open the database.
+ iDbAdapter = CMsvDBAdapter::OpenL(aDbFileName);
+
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Opening database %s is succesful."), &aDbFileName);
+#endif
+
+ iProgress.iTotal = iProgress.iRemaining = INITIAL_NUM_ENTRIES;
+ CreateInitialCacheL();
+
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Cache initialized succesfully."));
+#endif
+
+ TMsvId tmpNextId = NULL;
+ iDbAdapter->GetMaxTMsvIdL(tmpNextId);
+ iNextCreateId = (tmpNextId >= KFirstFreeEntryId)? (tmpNextId+1) : KFirstFreeEntryId;
+
+ iIdle = CIdle::NewL(CActive::EPriorityIdle);
+ CompleteSelf();
+ }
+
+
+
+
+/**
+ * CreateInitialSetOfEntries()
+ *
+ * The function is called from ConstructL(), whenever a new DB is created.
+ * The function creates root entry into database and cache.
+ */
+void CMsvIndexAdapter::CreateInitialSetOfEntriesL()
+ {
+
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Inside CreateInitialSetOfEntriesL(): Creating standard entries for new DB."));
+#endif
+
+ // 1. Initialize the instance of free pool.
+ iFreePoolInstance->SetEssentialParam(&iFolderListHeader, this);
+
+ // 2. Creating root entry into database.
+ iRootEntry = iFreePoolInstance->EntryL(); //taking it from the freepool.
+ iRootEntry->Entry().iType = KUidMsvRootEntry;
+ iRootEntry->Entry().iDate.UniversalTime();
+ iRootEntry->Entry().SetId(KMsvRootIndexEntryId);
+ iRootEntry->Entry().SetParent(KErrNotFound);
+ iRootEntry->Entry().iSize = 0;
+
+ TMsvId visibleFolderId = KMsvRootIndexEntryId;
+ iDbAdapter->CreateEntryL(iRootEntry->Entry(), visibleFolderId);
+
+ // 3. Add root entry to cache as well
+ CMsvCacheVisibleFolder* rootFolder = CMsvCacheVisibleFolder::NewL(KMsvRootIndexEntryId);
+ iFolderListHeader.AddFirst(*rootFolder);
+ rootFolder->SetComplete(ETrue);
+
+ // Update progress
+ iProgress.iCompleted++;
+ iProgress.iRemaining--;
+ iProgress.iId = KMsvRootIndexEntryId;
+ }
+
+
+
+
+
+/**
+ * CreateInitialCache()
+ *
+ * The function is called from NewL(), whenever an existing DB is opened.
+ * It creates the intial cache. It creates root entry in cache and fetches
+ * child of root from DB and push them into cache. It then fetches child
+ * entries of LocalServices and push them too into cache.
+ *
+ * >>>> The function can be enhanced to load children of additional folders
+ * to cache along with the above standard folders. These additional folders
+ * can be mentioned by licensees in msgs.ini file.
+ */
+void CMsvIndexAdapter::CreateInitialCacheL()
+ {
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Inside CreateInitialCache(): Initializing Cache."));
+#endif
+
+ //1. Initialize the instance of free pool.
+ iFreePoolInstance->SetEssentialParam(&iFolderListHeader, this);
+
+ // 2. Add root entry to cache.
+ CMsvCacheVisibleFolder* rootFolder = CMsvCacheVisibleFolder::NewL(KMsvRootIndexEntryId);
+ iFolderListHeader.AddFirst(*rootFolder);
+ // 2.1 Update progress
+ iProgress.iCompleted++;
+ iProgress.iRemaining--;
+ iProgress.iId = KMsvRootIndexEntryId;
+
+ // 3. Fetch child of root entries from DB.
+ RPointerArray<CMsvCacheEntry> childrenOfRoot;
+ iDbAdapter->GetChildrenL(KMsvRootIndexEntryId, childrenOfRoot);
+
+ // 3.1 Get the root entry from DB.
+ CMsvCacheEntry *rootEntry = NULL;
+ TMsvId visibleFolder = NULL;
+ iDbAdapter->GetEntryL(KMsvRootIndexEntryId, rootEntry, visibleFolder);
+ // 3.2 Copy the TMsvEntry of root from CMsvCacheEntry.
+ //Mem::Copy(&iRootEntry->Entry(), &rootEntry->Entry(), sizeof(TMsvEntry));
+ iRootEntry = rootEntry;
+ // 3.3 Release the cache entry back to the freepool.
+ //iFreePoolInstance->ReleaseEntry(rootEntry);
+
+ // 4. Add children to cache.
+ rootFolder->AddEntryListL(childrenOfRoot, ETrue);
+ // 4.1 Update progress
+ iProgress.iCompleted += 4;
+ iProgress.iRemaining -= 4;
+ iProgress.iId = KMsvLocalServiceIndexEntryId;
+
+ // 5. Set the visible folder as complete
+ rootFolder->SetComplete(ETrue);
+
+
+ // 6. Fetch child of LocalServices
+ childrenOfRoot.Reset();
+ iDbAdapter->GetChildrenL(KMsvLocalServiceIndexEntryId, childrenOfRoot);
+
+ CMsvCacheVisibleFolder* localFolder = CMsvCacheVisibleFolder::NewL(KMsvLocalServiceIndexEntryId);
+ iFolderListHeader.AddFirst(*localFolder);
+
+ // 7. Add children to cache.
+ localFolder->AddEntryListL(childrenOfRoot);
+ // 7.1 Update progress
+ iProgress.iCompleted = iProgress.iTotal;
+ iProgress.iRemaining = 0;
+ iProgress.iId = KMsvGlobalInBoxIndexEntryId;
+
+ // 8. Set the visible folder as complete
+ localFolder->SetComplete(ETrue);
+ childrenOfRoot.Close();
+ }
+
+
+
+/**
+GetInPreparationIds
+*/
+void CMsvIndexAdapter::GetInPreparationIds(CMsvEntrySelection& aSelection)
+ {
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->GetInPreparationIdL(aSelection));
+ }
+ }
+
+
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+/**
+ *CompleteSelf
+ *This will make sure that Runl is called.
+ */
+void CMsvIndexAdapter::CompleteSelf()
+ {
+ iStatus=KRequestPending;
+ SetActive();
+ TRequestStatus* st=&iStatus;
+ User::RequestComplete(st, KErrNone);
+ }
+
+
+
+/**
+ * RunL()
+ */
+void CMsvIndexAdapter::RunL()
+ {
+ // Set the state for the background state machine.
+ iBackgroundOperationState = ERemoveDeletedEntries;
+ iBackgroundOperationPerformed = 0;
+ }
+
+
+
+
+/**
+ * DoCancel()
+ */
+void CMsvIndexAdapter::DoCancel()
+ {
+ iIdle->Cancel();
+ }
+
+
+
+
+/**
+ * AddEntry()
+ */
+TInt CMsvIndexAdapter::AddEntry(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId)
+ {
+ TRAPD(err, DoAddEntryL(aEntry, aOwnerId, aAutoAssignId));
+ return err;
+ }
+
+
+/**
+ * AddEntryNoCommit()
+ */
+TInt CMsvIndexAdapter::AddEntryNoCommit(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId)
+ {
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->BeginTransactionL());
+ }
+ else
+ {
+ return ErrorState();
+ }
+ TRAPD(err, DoAddEntryL(aEntry, aOwnerId, aAutoAssignId, EFalse));
+ if(err)
+ {
+ RollbackAdditions();
+ }
+ return err;
+ }
+
+
+
+/**
+ * DoAddEntryL()
+ *
+ * Add the entry to the index and then the file.
+ * If either fails the function leaves. Creates
+ * its own copy of TMsvEntry (SetEntryL() code).
+ * This can be optimized further.
+ */
+void CMsvIndexAdapter::DoAddEntryL(TMsvEntry& aEntry, TSecureId aOwnerId, TBool aAutoAssignId, TBool aCommitToDb)
+ {
+ // Leave if the message store is not currently available.
+ User::LeaveIfError(iErrorState);
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // get and set the unique id
+ if (aAutoAssignId)
+ {
+ aEntry.SetId(NextId(GetDriveId(aEntry.Parent())));
+ }
+
+ if (aEntry.iType == KUidMsvServiceEntry)
+ {
+ if(KMsvLocalServiceIndexEntryId == UnmaskTMsvId(aEntry.iId))
+ {
+ aEntry.iServiceId = KMsvLocalServiceIndexEntryId;
+ }
+ else
+ {
+ aEntry.iServiceId = aEntry.Id();
+ }
+ }
+#else // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if (aAutoAssignId)
+ {
+ aEntry.SetId(NextId());
+ }
+
+ if (aEntry.iType == KUidMsvServiceEntry)
+ {
+ aEntry.iServiceId = aEntry.Id();
+ }
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+ CMsvCacheEntry* parentEntry = NULL;
+ FindEntryL(aEntry.Parent(), parentEntry);
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(UnmaskTMsvId(aEntry.iId) == KMsvDeletedEntryFolderEntryId)
+ {
+ aEntry.SetVisibleFolderFlag(ETrue);
+ }
+ else
+#endif
+ {
+ // If entry is set to visible while creation, then set the visible folder
+ // flag to ETrue, this will not change for the lifetime of an TMsvEntry.
+ if(parentEntry->Entry().VisibleFolderFlag())
+ {
+ if( (aEntry.Visible()) &&
+ (aEntry.iType == KUidMsvFolderEntry || aEntry.iType == KUidMsvServiceEntry)
+ )
+ {
+ aEntry.SetVisibleFolderFlag(ETrue);
+ }
+ else
+ {
+ aEntry.SetVisibleFolderFlag(EFalse);
+ }
+ }
+ else
+ {
+ aEntry.SetVisibleFolderFlag(EFalse);
+ }
+ }
+
+ aEntry.SetOwner(EFalse);
+ TMsvId visibleFolderId;
+ if(!GetVisibleFolderId(aEntry.Parent(), visibleFolderId))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ // Add entry to cache.
+ CMsvCacheEntry* newCacheEntry = NULL;
+ newCacheEntry = iFreePoolInstance->EntryL();
+ // Set the owner ID of the entry - the SID of the owning process.
+ newCacheEntry->SetEntryOwnerId(aOwnerId);
+
+ CMsvCacheVisibleFolder* visibleFolder = NULL;
+ TRAPD(err, newCacheEntry->SetEntryL(aEntry);
+ visibleFolder = AddEntryToCacheL(visibleFolderId, newCacheEntry);
+ );
+ if(err)
+ {
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(newCacheEntry);
+ User::Leave(err);
+ }
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TRAP(err,
+ if(aCommitToDb)
+ iDbAdapter->BeginTransactionL();
+ iDbAdapter->CreateEntryL(aEntry, visibleFolderId);
+ // Set the owner flag of parent entry if not already done.
+ // For standard entry created from indexContext, parent Id will not be masked.
+ iDbAdapter->UpdateOwnerStatusL(MaskTMsvId(GetDriveId(aEntry.iId), aEntry.Parent()), parentEntry->Entry(), ETrue);
+ if(aCommitToDb)
+ iDbAdapter->CommitTransactionL();
+ );
+#else
+ TRAP(err,
+ if(aCommitToDb)
+ iDbAdapter->BeginTransactionL();
+ iDbAdapter->CreateEntryL(aEntry, visibleFolderId);
+ // Set the owner flag of parent entry if not already done.
+ // For standard entry created from indexContext, parent Id will not be masked.
+ iDbAdapter->UpdateOwnerStatusL(aEntry.Parent(), parentEntry->Entry(), ETrue);
+ if(aCommitToDb)
+ iDbAdapter->CommitTransactionL();
+ );
+#endif
+ if(err & KSqlErrConstraint != err)
+ {
+ if(aCommitToDb)
+ iDbAdapter->RollbackTransactionL();
+ // This will not leave...
+ TRAP_IGNORE(visibleFolder->DeleteEntryL(newCacheEntry->GetId()));
+ User::Leave(err);
+ }
+ parentEntry->Entry().SetOwner(ETrue);
+
+ if(!aCommitToDb)
+ {
+ // Add entry to the list of non-committed entries.
+ CNonCommittedAddedEntries* nonCommittedAddedEntries = new(ELeave)CNonCommittedAddedEntries(visibleFolderId, newCacheEntry);
+ CleanupStack::PushL(nonCommittedAddedEntries);
+ iNonCommittedAddedEntryList.AppendL(nonCommittedAddedEntries);
+ CleanupStack::Pop(nonCommittedAddedEntries);
+ }
+
+ if(aEntry.iType.iUid == KUidMsvMessageEntryValue && CMSvSearchSortCacheManager::Instance()->iManagerEntry != NULL)
+ {
+ TMsgType aType(ENewMsg);
+ if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0)
+ {
+ CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aEntry.Id(),aType);
+ }
+ }
+ }
+
+
+
+
+/**
+ * GetVisibleFolderId()
+ *
+ * Returns ETrue, if the parent entry exists. Otherwise returns EFalse.
+ * IN: Parent Id of the entry, whose immediate visible folder has to be found.
+ * OUT: Visible folder Id.
+ */
+TBool CMsvIndexAdapter::GetVisibleFolderId(TMsvId aParentId, TMsvId& aVisibleFolderId)
+ {
+ // If the entry is either a root entry (parent=KErrNotFound) or
+ // child of root entry its visibleFolderId will be root entry itself.
+ if((KErrNotFound == aParentId) || (KMsvRootIndexEntryId == aParentId))
+ {
+ aVisibleFolderId = KMsvRootIndexEntryId;
+ return ETrue;
+ }
+
+ // Get the visible flag of parent entry.
+
+ // If parent entry is visible, then immediateVisibleFolder of child
+ // should be parent Id. And if it is invisible then child's immediateVisibleFolder
+ // should be same as parent's immediateVisibleFolder.
+ // First check in cache.
+ if(!iFolderListHeader.IsEmpty())
+ {
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ // Check if the current folder node is parent.
+ if( aParentId == folderNode->GetFolderId() )
+ {
+ aVisibleFolderId = aParentId;
+ return ETrue;
+ }
+ }
+ dqIter.SetToFirst();
+ CMsvCacheEntry* entry;
+ while((folderNode = dqIter++)!=NULL)
+ {
+ // Check if the current folder node is parent.
+ if(folderNode->GetEntry(aParentId, entry))
+ {
+ if(entry->Entry().VisibleFolderFlag())
+ {
+ aVisibleFolderId = aParentId;
+ }
+ else
+ {
+ //If the visible folder is not the parent, then
+ //the current folder must be the visible folder,
+ //as otherwise the parent would have been under another
+ //folder node.
+ aVisibleFolderId = folderNode->GetFolderId();
+ }
+ return ETrue;
+ }
+ }
+ }
+
+ // Entry cannot be found in cache,
+ // Now search in DB.
+ TInt err = KErrNone;
+ if(iDbAdapter)
+ {
+ TRAP(err, iDbAdapter->GetVisibleFolderIdL(aParentId, aVisibleFolderId));
+ }
+ else
+ {
+ return EFalse;
+ }
+ if(KErrNone == err)
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+
+
+
+/**
+ * DeleteEntry()
+ */
+TInt CMsvIndexAdapter::DeleteEntry(TMsvId aId)
+ {
+ CMsvEntrySelection* selection = NULL;
+
+ TRAPD(error, selection = new(ELeave)CMsvEntrySelection; selection->AppendL(aId););
+ if(KErrNone == error)
+ {
+ error = DeleteSelection(*selection);
+ }
+
+ TMsgType aType(EDeletedMsg);
+ if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0 && error == KErrNone)
+ {
+ CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aId,aType);
+ }
+
+ delete selection;
+ return error;
+ }
+
+
+
+
+
+/**
+ * DeleteSelection
+ * Deletes a selection of entries.
+ *
+ * @param aSelection Selection of TMsvIds of the entries to be deleted
+ * @return TInt System-wide error code.
+ */
+TInt CMsvIndexAdapter::DeleteSelection(const CMsvEntrySelection& aSelection)
+ {
+ TInt count = aSelection.Count();
+
+ if(!iDbAdapter)
+ {
+ return ErrorState();
+ }
+ // Only start a transaction if there are more than 1 entries to be deleted.
+ if(count > 1)
+ {
+ TRAP_IGNORE(iDbAdapter->BeginTransactionL());
+ }
+ // If the transaction is opened, deleted
+ // entry will be released temporarily.
+ iFreePoolInstance->BeginTransaction();
+ TInt error = KErrNone;
+ TRAP(error, DoDeleteSelectionL(aSelection));
+ if (error)
+ {
+ if(count > 1)
+ {
+ TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
+ }
+ iFreePoolInstance->RollbackTransaction();
+ }
+ else
+ {
+ if(count > 1)
+ {
+ TRAP_IGNORE(iDbAdapter->CommitTransactionL());
+ }
+ iFreePoolInstance->CommitTransaction();
+ }
+ return error;
+ }
+
+
+
+
+
+/**
+ * DoDeleteSelectionL
+ */
+void CMsvIndexAdapter::DoDeleteSelectionL(const CMsvEntrySelection& aSelection)
+ {
+ User::LeaveIfError(iErrorState);
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ const TInt count = aSelection.Count();
+ if(count <= 0)
+ {
+ return;
+ }
+
+ CMsvCacheEntry* entry = NULL;
+ TBool releaseEntry = FindEntryL(aSelection.At(0), entry, EFalse);
+ TMsvId parentId = entry->Entry().Parent();
+ if(releaseEntry)
+ {
+ iFreePoolInstance->ReleaseEntry(entry, ETrue);
+ }
+ CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+
+ for (TInt index=0; index<count; ++index)
+ {
+ dqIter.SetToFirst();
+ TBool found = EFalse;
+ while((folderNode = dqIter++)!=NULL)
+ {
+ TRAPD(err, folderNode->DeleteEntryL(aSelection.At(index)));
+ if(err != KErrNotFound && err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ else if(err == KErrNone)
+ {
+ found = ETrue;
+ break;
+ }
+ }
+ if(!found)
+ {
+ if(iDbAdapter)
+ {
+ if(iDbAdapter->EntryExistsL(aSelection.At(index)))
+ {
+ User::Leave(KErrAccessDenied);
+ }
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ User::Leave(KErrNotFound);
+ }
+
+ if(iDbAdapter)
+ {
+ iDbAdapter->DeleteEntryL(aSelection.At(index));
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ }
+ //Find the parent entry in cache and check for any children.
+ //If there are no more children under the parent, then
+ //reset the owner flag in cache and database.
+ TRAPD(err, releaseEntry = FindEntryL(parentId, entry, EFalse));
+ //If parent was also deleted then nothing left to do.
+ if(err == KErrNotFound)
+ {
+ CleanupStack::PopAndDestroy(); //children
+ return;
+ }
+ TRAP(err,
+ GetChildrenIdL(parentId, *children);
+ if(0 == children->Count() && entry->Entry().Owner())
+ {
+ if(iDbAdapter)
+ {
+ iDbAdapter->UpdateOwnerStatusL(parentId, entry->Entry(), EFalse);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ entry->Entry().SetOwner(EFalse);
+ }
+ );
+ // Release the entry, since it is not added to cache.
+ if(releaseEntry)
+ {
+ iFreePoolInstance->ReleaseEntry(entry, ETrue);
+ }
+ User::LeaveIfError(err);
+ CleanupStack::PopAndDestroy(); //children
+ }
+
+
+
+
+
+/**
+ * ExpandSelectionRecursively()
+ * Expands a selection to include all the descendents of the entries. They are order
+ * in such a way that they can be deleted in order, children first
+ *
+ * @param aSelection CMsvEntrySelection, which contains the TMsvIds of the entry passed.
+ * @return TInt System wide error code.
+ */
+TInt CMsvIndexAdapter::ExpandSelectionRecursively(CMsvEntrySelection& aSelection)
+ {
+ TInt error = KErrNone;
+ iOrigEntryPos=0;
+ iRecursionSelection=&aSelection;
+ TInt count = aSelection.Count();
+ while (iOrigEntryPos < count)
+ {
+ TMsvId entryId = aSelection.At(iOrigEntryPos);
+ if( !EntryExists(entryId) )
+ {
+ error = KErrNotFound;
+ aSelection.Delete(iOrigEntryPos);
+ }
+ else
+ {
+ // if the entry has children
+ CMsvEntrySelection* children = NULL;
+ TRAPD(err, children = new (ELeave)CMsvEntrySelection);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+ TInt leave = KErrNone;
+ TRAP(leave, GetChildrenIdL(entryId, *children));
+ if(KErrNone != leave)
+ {
+ delete children;
+ return leave;
+ }
+ TInt count = children->Count();
+ for(TInt index=0; index<count; ++index)
+ {
+ iRecursionIndex = iOrigEntryPos;
+ TRAP(leave, DoExpandSelectionRecursivelyL(children->At(index)));
+ if(KErrNone != leave)
+ {
+ delete children;
+ return leave;
+ }
+ }
+ delete children;
+ ++iOrigEntryPos;
+ }
+ }
+ return error;
+ }
+
+
+
+
+
+/**
+ * DoExpandSelectionRecursivelyL
+ * Expands a selection to include all the descendents of the entry with TMsvId aId.
+ *
+ * @param aId TMsvId of the entire
+ * @return void
+ */
+void CMsvIndexAdapter::DoExpandSelectionRecursivelyL(TMsvId aId)
+ {
+ // include this entry
+ iRecursionSelection->InsertL(iRecursionIndex,aId);
+ iOrigEntryPos++;
+
+ // if aEntry has children
+ CMsvEntrySelection* children = new (ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+
+ GetChildrenIdL(aId, *children);
+
+ TInt count = children->Count();
+ for(TInt index=0; index<count; ++index)
+ {
+ DoExpandSelectionRecursivelyL(children->At(index));
+ }
+
+ CleanupStack::PopAndDestroy(1, children); //children
+ }
+
+
+
+/**
+ * GetChildrenId()
+ * @param TMsvId: Id os the parent.
+ * @param CMsvEntrySelection: List of child Ids.
+ *
+ * This function should be used only by ExpandSelectionRecursively()
+ * and DoExpandSelectionRecursivelyL().
+ * --- 557 ---
+ * If aId is an standard id ensure that it is masked. If the aId is
+ * not masked the function will return children from current drive.
+ */
+void CMsvIndexAdapter::GetChildrenIdL(TMsvId aId, CMsvEntrySelection& aSelection)
+ {
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(IsStandardId(aId))
+ {
+ TUint driveId = GetDriveId(aId);
+ TMsvId unmaskedId = UnmaskTMsvId(aId);
+
+ dqIter.SetToFirst();
+ // Look for the entry in cache.
+ if(!iFolderListHeader.IsEmpty())
+ {
+ while(NULL != (folderNode = dqIter++))
+ {
+ if((unmaskedId == folderNode->GetFolderId()) && (driveId == folderNode->GetDrive()))
+ {
+ if(!folderNode->GetChildrenIdL(aSelection))
+ {
+ if(iDbAdapter)
+ {
+ iDbAdapter->GetChildrenIdL(aId, aSelection);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ }
+ return;
+ }
+ }
+ }
+ if(iDbAdapter)
+ {
+ iDbAdapter->GetChildrenIdL(aId, aSelection);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ return;
+ }
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+ dqIter.SetToFirst();
+ // Look for the entry in cache.
+ if(!iFolderListHeader.IsEmpty())
+ {
+ // Check if aId is one of the visible folder,
+ // already present in the cache.
+ while(NULL != (folderNode = dqIter++))
+ {
+ if(aId == folderNode->GetFolderId())
+ {
+ // Fetch children. Returns EFalse if unable
+ // to get them.
+ if(!folderNode->GetChildrenIdL(aSelection))
+ {
+ if(iDbAdapter)
+ {
+ // Childrens not fetched. Get them from DB.
+ iDbAdapter->GetChildrenIdL(aId, aSelection);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ }
+ return;
+ }
+ }
+
+ // Entry is not present in the visibleFolder list.
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ if(NULL != entry->ChildIdArray())
+ {
+ RArray<TMsvId>* childId = entry->ChildIdArray();
+ TInt size = childId->Count();
+ TInt index = 0;
+ while(index < size)
+ {
+ aSelection.AppendL((*childId)[index++]);
+ }
+ return;
+ }
+ else
+ {
+ if(iDbAdapter)
+ {
+ iDbAdapter->GetChildrenIdL(aId, aSelection);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ RArray<TMsvId>* childId = new(ELeave) RArray<TMsvId>;
+ TInt size = aSelection.Count();
+ TInt index = 0;
+ while(index < size)
+ {
+ TInt err = childId->Append(aSelection[index++]);
+ if(KErrNone != err)
+ {
+ childId->Reset();
+ childId->Close();
+ delete childId;
+ User::Leave(err);
+ }
+ }
+ entry->SetChildIdArray(childId);
+ return;
+ }
+ }
+ }
+
+ // Could not find parent entry in cache.
+ // Check in DB now.
+ if(iDbAdapter)
+ {
+ iDbAdapter->GetChildrenIdL(aId, aSelection);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ }
+
+
+
+
+/**
+ * ChangeEntry
+ * Change the contents of a TMsvEntry.
+ *
+ */
+TInt CMsvIndexAdapter::ChangeEntry(const TMsvEntry& aEntry, TSecureId aOwnerId, TBool aForcedUpdate)
+ {
+ TRAPD(err, DoChangeEntryL(aEntry, aOwnerId, EFalse, aForcedUpdate, ETrue));
+ return err;
+ }
+
+
+/**
+ * ChangeEntryNoCommit
+ */
+TInt CMsvIndexAdapter::ChangeEntryNoCommit(const TMsvEntry& aEntry, TSecureId aOwnerId, TBool aForcedUpdate)
+ {
+ if(!iDbAdapter)
+ {
+ return ErrorState();
+ }
+
+ TRAP_IGNORE(iDbAdapter->BeginTransactionL());
+ TRAPD(err, DoChangeEntryL(aEntry, aOwnerId, EFalse, aForcedUpdate, EFalse));
+ if(err)
+ {
+ RollbackChanges();
+ }
+ return err;
+ }
+
+
+/**
+ * ChangeEntryInternal()
+ */
+TInt CMsvIndexAdapter::ChangeEntryInternal(const TMsvEntry& aEntry, TSecureId aOwnerId)
+ {
+ TRAPD(err, DoChangeEntryL(aEntry, aOwnerId, ETrue, EFalse, ETrue));
+ return err;
+ }
+
+
+
+/**
+ * DoChangeEntryL
+ */
+void CMsvIndexAdapter::DoChangeEntryL(const TMsvEntry& aNewEntryContents, TSecureId aOwnerId, TBool aChangeStandardFolder, TBool aForcedUpdate, TBool aCommitToFile)
+ {
+ // Leave if the message store is not currently available
+ User::LeaveIfError(iErrorState);
+
+ // 1. Handle root entry differently.
+ if(aNewEntryContents.Id() == KMsvRootIndexEntryId)
+ {
+ TMsvEntry& entry = const_cast<TMsvEntry&> (aNewEntryContents);
+ iDbAdapter->UpdateEntryL(entry, KMsvRootIndexEntryId, EFalse);
+ iRootEntry->Entry() = entry;
+ return;
+ }
+
+ // 2. Find entry in cache.
+ CMsvCacheEntry* oldEntry = NULL;
+ CMsvCacheVisibleFolder* oldFolderNode = NULL;
+ GetVisibleFolderDetailsL(aNewEntryContents.Id(), oldEntry, oldFolderNode);
+
+ // 3. Validate entry.
+ // If the entry is not present in cache, it means it is not locked.
+ // Can only change a locked entry and not one marked as a standard
+ // folder unless aChangeStandardFolder is true.
+ if( (!oldEntry->IsEntryLocked()) || (aChangeStandardFolder==EFalse && oldEntry->Entry().StandardFolder()) )
+ {
+ User::Leave(KErrAccessDenied);
+ }
+
+ // Reserving space in changed entry list array.
+ if(!aCommitToFile)
+ {
+ iNonCommittedChangedEntryList.ReserveL(iNonCommittedChangedEntryList.Count()+1);
+ }
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // We do not support movement of entry to a folder present in a different drive.
+ if( oldEntry->Entry().Parent() != KErrNotFound && //-1 will appear to be masked. disregard this.
+ GetDriveId(aNewEntryContents.Id()) != GetDriveId(oldEntry->Entry().Parent()))
+ {
+ User::Leave(KErrNotSupported);
+ }
+#endif
+
+ TMsvId oldParentId = oldEntry->Entry().Parent();
+ TMsvId oldVisibleFolderId = oldFolderNode->GetFolderId();
+
+ // Check if the parent id is also changed.
+ CMsvCacheEntry* oldParentEntry = NULL;
+ CMsvCacheEntry* newParentEntry = NULL;
+ TBool resetOldParentOwnerFlag = EFalse;
+ CMsvEntrySelection* descendentList = NULL;
+ TMsvId newParentId = aNewEntryContents.Parent();
+ CMsvCacheVisibleFolder* newVisibleFolderNode = NULL;
+ if(oldParentId != newParentId)
+ {
+ // YES, PARENT ID IS CHANGED.
+ // These steps are similar to MoveEntry()
+ newVisibleFolderNode = DoChangeEntryPreambleL(oldEntry,
+ newParentId,
+ oldParentEntry,
+ newParentEntry,
+ oldVisibleFolderId,
+ resetOldParentOwnerFlag,
+ descendentList
+ );
+ } // if(oldParentId != newParentId)
+ TMsvId newVisibleFolderId = newVisibleFolderNode ? newVisibleFolderNode->GetFolderId() : oldVisibleFolderId;
+ // Update entry in cache.
+ TBool changedPrivateInfo;
+ CMsvCacheEntry* bkpEntry = NULL;
+ TRAPD(err, bkpEntry = iFreePoolInstance->EntryL();
+ bkpEntry->SetEntryL(oldEntry->Entry());
+ bkpEntry->SetEntryOwnerId(oldEntry->EntryOwnerId());
+ oldEntry->CopyEntryL(aNewEntryContents, changedPrivateInfo);
+ );
+ if(err)
+ {
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(bkpEntry);
+ if(newVisibleFolderNode)
+ newVisibleFolderNode->DeleteEntryL(oldEntry->GetId());
+ User::Leave(err);
+ }
+
+ UpdateDates(*oldEntry, EFalse);
+ if(aForcedUpdate || changedPrivateInfo && aOwnerId != KMsvServerId )
+ {
+ oldEntry->SetEntryOwnerId(aOwnerId);
+ }
+
+ TRAP(err,
+ if(aCommitToFile)
+ iDbAdapter->BeginTransactionL();
+ // Update the actual entry
+ if(oldParentId != newParentId)
+ {
+ iDbAdapter->UpdateEntryL(oldEntry->Entry(), newVisibleFolderId);
+ }
+ else
+ {
+ iDbAdapter->UpdateEntryL(oldEntry->Entry(), newVisibleFolderId, EFalse);
+ }
+ // Reset old parent owner flag.
+ if(resetOldParentOwnerFlag)
+ iDbAdapter->UpdateOwnerStatusL(oldParentId, oldParentEntry->Entry(), EFalse);
+ // Set new parent owner flag.
+ if(newParentEntry && (!newParentEntry->Entry().Owner()))
+ iDbAdapter->UpdateOwnerStatusL(newParentId, newParentEntry->Entry(), ETrue);
+ // Update the child entries visibleFolderId in DB.
+ if(descendentList)
+ iDbAdapter->UpdateVisibleFolderL(descendentList, newVisibleFolderId);
+ if(aCommitToFile)
+ iDbAdapter->CommitTransactionL();
+ );
+ if(err)
+ {
+ if(aCommitToFile)
+ TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
+ oldEntry->SetEntryOwnerId(bkpEntry->EntryOwnerId());
+ oldEntry->CopyEntryL(bkpEntry->Entry(), changedPrivateInfo);
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(bkpEntry);
+ if(newVisibleFolderNode)
+ newVisibleFolderNode->DeleteEntryL(oldEntry->GetId());
+ User::Leave(err);
+ }
+ // Nothing should fail after this. Ensure that
+ // all leaving function after this does not leave.
+ if(aCommitToFile)
+ {
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(bkpEntry);
+ DoChangeEntryPostamble(oldFolderNode, newVisibleFolderId, oldEntry->GetId(), descendentList, newParentEntry, oldParentEntry, resetOldParentOwnerFlag);
+ if(descendentList)
+ {
+ CleanupStack::PopAndDestroy(descendentList);
+ }
+ } // if(aCommitToFile)
+ else
+ {
+ // Store relevant data for later commit.
+ TNonCommittedChangedEntries entryDetails(oldFolderNode,
+ newVisibleFolderNode,
+ oldEntry,
+ bkpEntry,
+ oldParentEntry,
+ newParentEntry,
+ descendentList,
+ resetOldParentOwnerFlag);
+ iNonCommittedChangedEntryList.Append(entryDetails);
+ if(descendentList)
+ CleanupStack::Pop(descendentList);
+ }
+
+ // Update entry in SearchSort delta cache.
+ if(aNewEntryContents.iType.iUid == KUidMsvMessageEntryValue && CMSvSearchSortCacheManager::Instance()->iManagerEntry != NULL)
+ {
+ TMsgType aType(EUpdatedMsg);
+ if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0)
+ {
+ CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aNewEntryContents.Id(), aType);
+ }
+ }
+ }
+
+
+
+// Used only by DoChangeEntryL()
+CMsvCacheVisibleFolder* CMsvIndexAdapter::DoChangeEntryPreambleL(CMsvCacheEntry*& aOldEntry, TMsvId aNewParentId, CMsvCacheEntry*& aOldParentEntry, CMsvCacheEntry*& aNewParentEntry, TMsvId aOldVisibleFolderId, TBool& aResetOldParentOwnerFlag, CMsvEntrySelection*& aDescendentList)
+ {
+ // YES, PARENT ID IS CHANGED.
+ // These steps are similar to MoveEntry()
+ TBool des;
+ IsADescendent(aOldEntry->Entry().Id(), aNewParentId, des);
+ if (des)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Fetch the parent entries.
+ FindEntryL(aOldEntry->Entry().Parent(), aOldParentEntry);
+ FindEntryL(aNewParentId, aNewParentEntry);
+
+ // Check if the owner flag of the old parent needs to be reset.
+ CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+ GetChildrenIdL(aOldEntry->Entry().Parent(), *children);
+ if(1 == children->Count() && aOldParentEntry->Entry().Owner())
+ {
+ aResetOldParentOwnerFlag = ETrue;
+ }
+ CleanupStack::PopAndDestroy(); //children
+
+ // If required, pre-allocate memory for child array of newParentEntry.
+ if(aNewParentEntry->ChildIdArray())
+ {
+ // This to ensure that future append does not fail.
+ aNewParentEntry->ChildIdArray()->ReserveL(aNewParentEntry->ChildIdArray()->Count() + 1);
+ }
+
+ // Find the visibleFolder of new parent.
+ TMsvId newVisibleFolderId = NULL;
+ if(!GetVisibleFolderId(aNewParentId, newVisibleFolderId))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ // Check if the visible folders are different.
+ CMsvCacheVisibleFolder* newVisibleFolderNode = NULL;
+ if(aOldVisibleFolderId != newVisibleFolderId)
+ {
+ // If the visible folders are different, check if
+ // child entries also needs to be moved.
+ if(!aOldEntry->Entry().VisibleFolderFlag())
+ {
+ // If yes, create a descendent list of the entry.
+ aDescendentList = new(ELeave) CMsvEntrySelection;
+ CleanupStack::PushL(aDescendentList);
+ aDescendentList->AppendL(aOldEntry->GetId());
+ User::LeaveIfError(ExpandSelectionRecursively(*aDescendentList));
+ }
+
+ // Add duplicate entry under new visible folder. Removing
+ // entry from old visible folder is done later.
+ CMsvCacheEntry* newCacheEntry = iFreePoolInstance->EntryL();
+ TRAPD(err, newCacheEntry->DupNDestroyL(aOldEntry);
+ newVisibleFolderNode = AddEntryToCacheL(newVisibleFolderId, newCacheEntry);
+ );
+ if(err)
+ {
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(newCacheEntry);
+ User::Leave(err);
+ }
+ aOldEntry = newCacheEntry;
+ } // if(oldVisibleFolderId != newVisibleFolderId) }
+ return newVisibleFolderNode;
+ }
+
+
+
+// Used only by DoChangeEntryL()
+void CMsvIndexAdapter::DoChangeEntryPostamble(CMsvCacheVisibleFolder* aOldFolderNode, TMsvId aNewVisibleFolderId, TMsvId aEntryId, CMsvEntrySelection* aDescendentList, CMsvCacheEntry* aNewParentEntry, CMsvCacheEntry* aOldParentEntry, TBool aResetOldParentOwnerFlag)
+ {
+ // Removing entry from old visible folder.
+ if(aOldFolderNode->GetFolderId() != aNewVisibleFolderId)
+ {
+ // Will never leave.
+ //aOldFolderNode->DeleteEntryL(oldEntry->GetId());
+ TRAP_IGNORE(aOldFolderNode->DeleteEntryL(aEntryId));
+ }
+
+ // Removing child entries from old visible folder.
+ if(aDescendentList)
+ {
+ for(TInt index=(aDescendentList->Count()-2); index>=0; index--)
+ {
+ // Can leave with KErrNotFound.
+ TRAP_IGNORE(aOldFolderNode->DeleteEntryL(aDescendentList->At(index)));
+ }
+ }
+
+ // Add child id to new parent child array.
+ if(aNewParentEntry && aNewParentEntry->ChildIdArray())
+ {
+ // This will not leave, as memory is already reserved.
+ TRAP_IGNORE(aNewParentEntry->ChildIdArray()->AppendL(aEntryId));
+ }
+
+ // Remove child from old parent's child array.
+ if(aOldParentEntry)
+ {
+ RArray<TMsvId>* oldParentChildArr = aOldParentEntry->ChildIdArray();
+ if(oldParentChildArr)
+ {
+ TInt pos = oldParentChildArr->Find(aEntryId);
+ if(pos != KErrNotFound)
+ {
+ oldParentChildArr->Remove(pos);
+ }
+ }
+ }
+
+ // Update owner flag of parent entries.
+ if(aResetOldParentOwnerFlag)
+ {
+ aOldParentEntry->Entry().SetOwner(EFalse);
+ }
+ if(aNewParentEntry)
+ {
+ aNewParentEntry->Entry().SetOwner(ETrue);
+ }
+ }
+
+
+
+
+/**
+ * GetEntry()
+ */
+TInt CMsvIndexAdapter::GetEntry(TMsvId aId, TMsvEntry*& aEntry)
+ {
+ TSecureId dummy;
+ return GetEntry(aId, aEntry, dummy);
+ }
+
+
+
+/**
+ * GetEntryNoCache()
+ * If aAddToCache is EFalse, entry will not be added to cache,
+ * if the entry is fetched from DB. The user of this function
+ * should ensure that it releses the memory occupied by entry
+ * to the freepool.
+ */
+TInt CMsvIndexAdapter::GetEntryNoCache(TMsvId aId, TMsvEntry* aEntry)
+ {
+ if(KMsvRootIndexEntryId == aId)
+ {
+ *aEntry = iRootEntry->Entry();
+ return KErrNone;
+ }
+
+ TBool aIsDanglingEntry = EFalse;
+ CMsvCacheEntry* serverEntry=NULL;
+ TRAPD(err, aIsDanglingEntry = FindEntryL(aId, serverEntry, EFalse));
+
+ if (err == KErrNone)
+ {
+ *aEntry = serverEntry->Entry();
+ // If entry is not present in cache,
+ // it should be handled carefully.
+ if(aIsDanglingEntry)
+ {
+ // Release CMsvCacheEntry to freepool.
+ iFreePoolInstance->ReleaseEntry(serverEntry, ETrue);
+ }
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+
+
+
+/**
+ * GetEntry()
+ */
+TInt CMsvIndexAdapter::GetEntry(TMsvId aId, TMsvEntry*& aEntry, TSecureId& aOwnerId)
+ {
+ if(KMsvRootIndexEntryId == aId)
+ {
+ aEntry = &iRootEntry->Entry();
+ aOwnerId = 0;
+ return KErrNone;
+ }
+
+ CMsvCacheEntry* serverEntry=NULL;
+ TRAPD(err, FindEntryL(aId, serverEntry));
+
+ if (err == KErrNone)
+ {
+ aEntry = &serverEntry->Entry();
+ aOwnerId = serverEntry->EntryOwnerId();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+
+
+/**
+ * FindEntryInCache()
+ * @param aId: Entry Id.
+ * @return aEntry: CMsvCacheEntry
+ * @return bool: ETrue if entry found, otherwise EFalse.
+ *
+ * Find an entry only in cache and return the entry.
+ */
+TBool CMsvIndexAdapter::FindEntryInCache(TMsvId aId, CMsvCacheEntry*& aEntry)
+ {
+ if(KMsvRootIndexEntryId == aId)
+ {
+ aEntry = iRootEntry;
+ return ETrue;
+ }
+
+ // If cache is not empty.
+ if(!iFolderListHeader.IsEmpty())
+ {
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(folderNode->GetEntry(aId, aEntry))
+ {
+ return ETrue;
+ }
+ }
+ }
+ aEntry = NULL;
+ return EFalse;
+ }
+
+
+
+/**
+ * FindEntryL()
+ *
+ * WARNING:
+ * Returns CMsvCacheEntry which is still owned by Cache. so aEntry should
+ * never be deleted by the caller.
+ *
+ * If the entry is fetched from DB and not added to cache, the function
+ * returns ETrue, indicating that aEntry should be release to the freepool
+ * by the caller.
+ */
+TBool CMsvIndexAdapter::FindEntryL(TMsvId aId, CMsvCacheEntry*& aEntry, TBool aAddToCache /*DEFAULT=ETrue */)
+ {
+ // First search the entry in cache,
+ if(FindEntryInCache(aId, aEntry))
+ {
+ return EFalse;
+ }
+
+ // Entry cannot be found in cache,
+ // Now search in DB.
+ TMsvId visibleEntryId;
+ if(iDbAdapter)
+ {
+ iDbAdapter->GetEntryL(aId, aEntry, visibleEntryId);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+
+ if(aAddToCache)
+ {
+ // Add entry to cache.
+ AddEntryToCacheL(visibleEntryId, aEntry);
+ }
+ else
+ {
+ // If the entry is not added to cache, we need not start
+ // the background operation. We can return ETrue saying
+ // entry is dangling and needs to be freed.
+ return ETrue;
+ }
+ if (!iIdle->IsActive())
+ {
+ iIdle->Start(TCallBack(BackGroundOperations, this));
+ }
+ return EFalse;
+ }
+
+
+
+
+/**
+ * AddEntryNoVisibleL()
+ */
+void CMsvIndexAdapter::AddEntryNoVisibleL(CMsvCacheEntry* aEntry)
+ {
+ TMsvId visibleFolder;
+ if(GetVisibleFolderId(aEntry->Entry().Parent(), visibleFolder))
+ {
+ AddEntryToCacheL(visibleFolder, aEntry);
+ }
+ }
+
+
+
+/**
+ * AddEntryToCacheL()
+ */
+CMsvCacheVisibleFolder* CMsvIndexAdapter::AddEntryToCacheL(TMsvId aVisibleEntryId, CMsvCacheEntry* aEntry)
+ {
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TUint driveId = GetDriveId(aEntry->GetId());
+ if(IsStandardId(aEntry->GetId()))
+ {
+ aEntry->Entry().SetId(UnmaskTMsvId(aEntry->GetId()));
+ }
+#endif
+ // First search the visibleEntry in cache,
+ // if cache is not empty...
+ if(!iFolderListHeader.IsEmpty())
+ {
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+
+ while((folderNode = dqIter++)!=NULL)
+ {
+ TMsvId folderId = folderNode->GetFolderId();
+ if(aVisibleEntryId == folderId)
+ {
+ // Visible folder exists.
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // For standard entries also check for driveId.
+ if(IsStandardId(aVisibleEntryId))
+ {
+ if(driveId == folderNode->GetDrive())
+ {
+ folderNode->AddEntryL(aEntry);
+ return folderNode;
+ }
+ }
+ else
+#endif
+ {
+ // Add entry to this folder.
+ folderNode->AddEntryL(aEntry);
+ return folderNode;
+ }
+ }
+ }
+ }
+
+ // Visible folder not found in the folder list.
+ // Create the visible folder and add it to the
+ // beginning of the list.
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(MaskTMsvId(GetDriveId(aEntry->GetId()), aVisibleEntryId));
+#else
+ CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(aVisibleEntryId);
+#endif
+ iFolderListHeader.AddFirst(*newFolder);
+
+ // Now add entry to the visible folder
+ newFolder->AddEntryL(aEntry);
+ return newFolder;
+ }
+
+
+
+/**
+ * GetChildrenL()
+ */
+void CMsvIndexAdapter::GetChildrenL(TMsvId aId, CArrayPtr<const TMsvEntry>& aSelection, const TMsvSelectionOrdering& aOrdering, TUid aMtm)
+ {
+ TSecureId dummy = KMsvServerId.iId;
+ GetChildrenL(aId, aSelection, aOrdering, aMtm, EFalse, dummy);
+ }
+
+
+
+/**
+ * GetChildrenL()
+ */
+void CMsvIndexAdapter::GetChildrenL(TMsvId aId, CArrayPtr<const TMsvEntry>& aSelection, const TMsvSelectionOrdering& aOrdering, TUid aMtm, TBool aFilterByOwnerId, TSecureId aOwnerId)
+ {
+ CMsvEntryFilter* filter = CMsvEntryFilter::NewLC();
+ filter->SetOrder(aOrdering);
+ filter->SetSortMtm(aMtm);
+ CMsvEntryArray* entries = DoGetChildrenL(aId, *filter, aFilterByOwnerId, aOwnerId);
+ CleanupStack::PushL(entries);
+
+ TInt count = entries->Count();
+ for (TInt ii=0; ii<count; ii++)
+ {
+ aSelection.AppendL(entries->At(ii));
+ }
+ CleanupStack::PopAndDestroy(2, filter); // filter and entries
+ }
+
+
+
+
+/**
+ * DoGetChildrenL
+ */
+CMsvEntryArray* CMsvIndexAdapter::DoGetChildrenL(TMsvId aId, const CMsvEntryFilter& aFilter, TBool aFilterByOwnerId, TSecureId aOwnerId)
+ {
+ // Check if entry for aId exists...
+ CMsvCacheEntry* entry=NULL;
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TUint driveId = GetDriveId(aId);
+ TMsvId unmaskedId = UnmaskTMsvId(aId);
+ if(IsStandardId(aId))
+ {
+ FindEntryL(unmaskedId, entry);
+ }
+ else
+#endif
+ {
+ FindEntryL(aId, entry);
+ }
+
+ TBool isParentAVisibleFolder = EFalse;
+ if(entry->Entry().VisibleFolderFlag())
+ {
+ isParentAVisibleFolder = ETrue;
+ }
+
+ CArrayFixFlat<TUid>* mtmList = new(ELeave) CArrayFixFlat<TUid>(KMsvMtmListGranularity);
+ CleanupStack::PushL(mtmList);
+ if (KUidMsvNullEntry != aFilter.SortMtm())
+ {
+ mtmList->AppendL(aFilter.SortMtm());
+ }
+
+ RPointerArray<CMsvCacheEntry> selection;
+ CleanupClosePushL(selection);
+
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ CMsvEntryArray* entries = CMsvEntryArray::NewLC(*mtmList);
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+ if(IsStandardId(aId))
+ {
+ // Look for the entry in cache.
+ if(!iFolderListHeader.IsEmpty())
+ {
+ dqIter.SetToFirst();
+ // Check if aId is one of the visible folder,
+ // already present in the cache.
+ while(NULL != (folderNode = dqIter++))
+ {
+ if((folderNode->GetFolderId() == unmaskedId) && (folderNode->GetDrive() == driveId))
+ {
+ folderNode->GetChildrenL(aId, iDbAdapter, selection);
+ FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
+ CleanupStack::Pop(entries); // Fetch entries from stack. It will be destroyed by caller.
+ CleanupStack::PopAndDestroy(2);
+ return entries;
+ }
+ }
+ }
+ }
+ else
+ {
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+ // Look for the entry in cache.
+ if(!iFolderListHeader.IsEmpty())
+ {
+ dqIter.SetToFirst();
+ // Check if aId is one of the visible folder,
+ // already present in the cache.
+ while(NULL != (folderNode = dqIter++))
+ {
+ if(aId == folderNode->GetFolderId())
+ {
+ if(iDbAdapter == NULL)
+ {
+ User::Leave(ErrorState());
+ }
+ folderNode->GetChildrenL(aId, iDbAdapter, selection);
+ FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
+ CleanupStack::Pop(entries); // Fetch entries from stack. It will be destroyed by caller.
+ CleanupStack::PopAndDestroy(2);
+ return entries;
+ }
+ }
+
+ // If the parent is not a visible folder
+ // check if it is child of one of the visible folder.
+ if(EFalse == isParentAVisibleFolder)
+ {
+ dqIter.SetToFirst();
+ while(NULL != (folderNode = dqIter++))
+ {
+ TBool retVal=EFalse;
+ TRAPD(err, retVal = folderNode->GetChildrenL(aId, iDbAdapter, selection))
+
+ // aId not found under current visibleFolder.
+ if(KErrNotFound == err)
+ {
+ continue;
+ }
+
+ // aId found under current visibleFolder.
+ if(retVal)
+ {
+ // Children is fetched succesfully.
+ FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
+ CleanupStack::Pop(entries); // Fetch entries from stack. It will be destroyed by caller.
+ CleanupStack::PopAndDestroy(2);
+ return entries;
+ }
+ else
+ {
+ // aId itself is a visibleFolder.
+ isParentAVisibleFolder = ETrue;
+ break;
+ }
+ }
+ }
+ }
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ }
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+ // Could not find parent entry in cache.
+ // Check in DB now.
+ TInt err = KErrNone;
+ if(iDbAdapter)
+ {
+ TRAP(err, iDbAdapter->GetChildrenL(aId, selection));
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ if(err)
+ {
+ User::Leave(KErrNotFound);
+ }
+ FilterChildrenListL(aId, selection, *entries, aFilter, aFilterByOwnerId, aOwnerId);
+
+ // Check if the entire entry list can be added to cache.
+ // This is important in a situation when all childs of a
+ // folder cannot be accomodated in cache. In such scenario
+ // only entries with higher TMsvId will be added to cache.
+ TInt excessEntries = iFreePoolInstance->ExcessMemoryAllocated();
+ TBool isCompleteChildren = ETrue;
+ if(excessEntries)
+ {
+ isCompleteChildren = EFalse;
+ }
+ while(excessEntries)
+ {
+ if(selection.Count())
+ {
+ iFreePoolInstance->RecordExcessMemoryL(selection[0]);
+ selection.Remove(0);
+ }
+ --excessEntries;
+ }
+
+ // Add children to cache.
+ TMsvId visibleFolderId;
+ if(!isParentAVisibleFolder)
+ {
+ if(!GetVisibleFolderId(aId, visibleFolderId))
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+ else
+ {
+ visibleFolderId = aId;
+ }
+
+ TBool isEntryAdded = EFalse;
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(visibleFolderId == folderNode->GetFolderId())
+ {
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(IsStandardId(visibleFolderId))
+ {
+ if(GetDriveId(aId) == folderNode->GetDrive())
+ {
+ isEntryAdded=ETrue;
+ folderNode->AddEntryListL(selection, (isCompleteChildren && isParentAVisibleFolder));
+ }
+ }
+ else
+#endif
+ {
+ isEntryAdded=ETrue;
+ folderNode->AddEntryListL(selection, (isCompleteChildren && isParentAVisibleFolder));
+ }
+ }
+ }
+
+ if(!isEntryAdded)
+ {
+ // If aId is the visibleFolder itself then pass
+ // aIsCompleteChildOfFolder as ETrue.
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // Standard Id can be unmasked.
+ CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(MaskTMsvId(GetDriveId(aId), visibleFolderId));
+#else
+ CMsvCacheVisibleFolder* newFolder = CMsvCacheVisibleFolder::NewL(visibleFolderId);
+#endif
+ iFolderListHeader.AddFirst(*newFolder);
+ newFolder->AddEntryListL(selection, (isCompleteChildren && isParentAVisibleFolder));
+ }
+
+ CleanupStack::Pop(entries); // Fetch entries from stack. It will be destroyed by caller.
+ CleanupStack::PopAndDestroy(2);
+
+ //Start the background operations, if not running.
+ if (!iIdle->IsActive())
+ {
+ iIdle->Start(TCallBack(BackGroundOperations, this));
+ }
+
+ return entries;
+ }
+
+
+
+
+/**
+ * GetChildrenId()
+ */
+TInt CMsvIndexAdapter::GetChildrenId(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection)
+ {
+ TSecureId dummy = KMsvServerId.iId;
+ return GetChildrenId(aId, aFilter, aSelection, EFalse, dummy);
+ }
+
+/**
+ * GetChildrenId()
+ */
+TInt CMsvIndexAdapter::GetChildrenId(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection, TBool aFilterByOwnerId, TSecureId aOwnerId)
+ {
+ CMsvEntryArray* entries = NULL;
+ TInt err = KErrNone;
+ TRAP(err, entries=DoGetChildrenL(aId, aFilter, aFilterByOwnerId, aOwnerId));
+ if(err)
+ {
+ delete entries;
+ return err;
+ }
+
+ TInt count = entries->Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ TRAP(err, aSelection.AppendL(entries->At(i)->Id()));
+ }
+ delete entries;
+ return err;
+ }
+
+
+
+/**
+ * FilterChildrenListL
+ */
+void CMsvIndexAdapter::FilterChildrenListL(TMsvId aId, RPointerArray<CMsvCacheEntry> aChacheEntry, CMsvEntryArray& aEntryArray, const CMsvEntryFilter& aFilter, TBool aFilterByOwnerId, TSecureId aOwnerId)
+ {
+ TBool getInvisibleEntries = aFilter.Order().ShowInvisibleEntries();
+ TInt count = aChacheEntry.Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ TMsvEntry entry = aChacheEntry[i]->Entry();
+ TBool vis = aChacheEntry[i]->Entry().Visible();
+ if ((aChacheEntry[i]->Entry().Visible() || getInvisibleEntries) &&
+ (aFilter.Service() == KMsvNullIndexEntryId || aChacheEntry[i]->Entry().iServiceId == aFilter.Service()) &&
+ (aFilter.Mtm() == KNullUid || aChacheEntry[i]->Entry().iMtm == aFilter.Mtm()) &&
+ (aFilter.Type() == KNullUid || aChacheEntry[i]->Entry().iType == aFilter.Type()) &&
+ (aFilter.LastChangeDate().Int64() == 0 || aChacheEntry[i]->LastChangeDate() >= aFilter.LastChangeDate()))
+ {
+ // Add the entry if -
+ // 1. Not filtering by owner ID OR
+ // 2. Filtering by owner ID, but entry owner ID matches OR
+ // 3. Entry is a standard folder OR
+ // 4. Entrt is a service entry.
+ if( !aFilterByOwnerId ||
+ aChacheEntry[i]->EntryOwnerId() == aOwnerId ||
+ aChacheEntry[i]->Entry().StandardFolder() ||
+ aChacheEntry[i]->Entry().iType == KUidMsvServiceEntry )
+ {
+ aEntryArray.AppendL(&aChacheEntry[i]->Entry());
+ }
+ }
+ }
+
+ if (aEntryArray.Count())
+ {
+ if (aId==KMsvRootIndexEntryId)
+ {
+ aEntryArray.SortL(TMsvSelectionOrdering(KMsvNoGrouping, aFilter.Order().Sorting()));
+ }
+ else
+ {
+ aEntryArray.SortL(aFilter.Order());
+ }
+ }
+ }
+
+
+
+
+/**
+ * LockEntry()
+ */
+TInt CMsvIndexAdapter::LockEntry(TMsvId aId)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aId, entry))
+ if (err)
+ {
+ return KErrNotFound;
+ }
+
+ return entry->LockEntry();
+ }
+
+
+
+/**
+ * ReleaseEntry()
+ */
+TInt CMsvIndexAdapter::ReleaseEntry(TMsvId aId)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ entry->ReleaseEntry();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+
+
+
+/**
+ * IsEntryLocked()
+ */
+TInt CMsvIndexAdapter::IsEntryLocked(TMsvId aId, TBool& aLocked)
+ {
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aId, entry));
+ if(KErrNone != err)
+ {
+ aLocked = EFalse;
+ return err;
+ }
+
+ aLocked = entry->IsEntryLocked();
+ return KErrNone;
+ }
+
+
+
+
+
+/**
+ * LockStore()
+ */
+TInt CMsvIndexAdapter::LockStore(TMsvId aId)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aId, entry));
+ if (err)
+ {
+ return KErrNotFound;
+ }
+
+ return entry->LockStore();
+ }
+
+
+
+
+/**
+ * ReleaseStore()
+ */
+TInt CMsvIndexAdapter::ReleaseStore(TMsvId aId)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ entry->ReleaseStore();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+
+
+
+/**
+ * IsStoreLocked()
+ */
+TInt CMsvIndexAdapter::IsStoreLocked(TMsvId aId, TBool& aLocked)
+ {
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aId, entry));
+ if(KErrNone != err)
+ {
+ aLocked = EFalse;
+ return err;
+ }
+ aLocked = entry->IsStoreLocked();
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * IsEntryAndStoreLocked()
+ */
+TInt CMsvIndexAdapter::IsEntryOrStoreLocked(TMsvId aId)
+ {
+ CMsvCacheEntry* entry = NULL;
+ TBool locked = EFalse;
+ if(FindEntryInCache(aId, entry))
+ {
+ locked = entry->IsEntryOrStoreLocked();
+ }
+ if(locked)
+ {
+ return KErrLocked;
+ }
+ else
+ {
+ return KErrNone;
+ }
+ }
+
+
+
+/**
+ * LockEntryAndStore()
+ */
+TInt CMsvIndexAdapter::LockEntryAndStore(TMsvId aId)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aId, entry));
+ if (err)
+ {
+ return KErrNotFound;
+ }
+
+ return entry->LockEntryAndStore();
+ }
+
+
+
+
+/**
+ * ReleaseEntryAndStore()
+ */
+TInt CMsvIndexAdapter::ReleaseEntryAndStore(TMsvId aId)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ entry->ReleaseEntryAndStore();
+ return KErrNone;
+ }
+ else
+ {
+ return KErrNotFound;
+ }
+ }
+
+
+
+
+/**
+ * IsEntryOrStoreLocked()
+ */
+TInt CMsvIndexAdapter::IsEntryOrStoreLocked(TMsvId aId, TBool& aLocked)
+ {
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ aLocked = entry->IsEntryOrStoreLocked();
+ }
+ else
+ {
+ aLocked = EFalse;
+ }
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * IsStoreReadingLocked()
+ */
+TInt CMsvIndexAdapter::IsStoreReadingLocked(TMsvId aId, TBool& aLocked)
+ {
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ aLocked = entry->IsStoreReadingLocked();
+ }
+ else
+ {
+ aLocked = EFalse;
+ }
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * IncStoreReaderCount()
+ */
+TInt CMsvIndexAdapter::IncStoreReaderCount(TMsvId aId)
+ {
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aId, entry));
+ if (err)
+ {
+ return KErrNotFound;
+ }
+
+ entry->IncStoreReaderCount();
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * DecStoreReaderCount()
+ */
+TInt CMsvIndexAdapter::DecStoreReaderCount(TMsvId aId)
+ {
+ CMsvCacheEntry* entry = NULL;
+ if(FindEntryInCache(aId, entry))
+ {
+ entry->DecStoreReaderCount();
+ }
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * OwningService()
+ */
+TInt CMsvIndexAdapter::OwningService(TMsvId aId, TMsvId& aService)
+ {
+ aService = aId;
+ if (aId!=KMsvRootIndexEntryId)
+ {
+ FOREVER
+ {
+ CMsvCacheEntry* entry = NULL;
+ TRAPD(err, FindEntryL(aService, entry));
+ if (err)
+ {
+ return KErrNotFound;
+ }
+
+ if (KUidMsvServiceEntry==entry->Entry().iType)
+ {
+ break;
+ }
+ aService = entry->Entry().Parent();
+ }
+ }
+
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * IsLocal()
+ */
+TInt CMsvIndexAdapter::IsLocal(TMsvId aId, TBool& aLocal)
+ {
+ TInt errVal = KErrNone;
+ aLocal = ETrue;
+
+ if (aId!=KMsvRootIndexEntryId)
+ {
+ TMsvId service;
+ errVal = OwningService(aId, service);
+ aLocal = (KMsvLocalServiceIndexEntryId==service);
+ }
+
+ return errVal;
+ }
+
+
+
+
+/**
+ * MoveEntry
+ * Moves a entry with TMsvId as aId to a folder with target id as aTarget
+ *
+ * @param aId TMsvId of the entry to be moved.
+ * @param aTarget TMsvId of the parent folder.
+ * @param aDescendents List of descendents id, if the caller also wants to move descendents
+ * in cache and DB. The last id in the descendent list must be the entry id itself.
+ * @return TInt System-wide error code.
+ */
+TInt CMsvIndexAdapter::MoveEntry(TMsvId aId, TMsvId aTarget, CMsvEntrySelection* aDescendents /* DEFAULT=NULL */)
+ {
+ TRAPD(err, DoMoveEntryL(aId, aTarget, aDescendents));
+ return err;
+ }
+
+
+
+/**
+ * DoMoveEntryL()
+ * Called from MoveEntry()
+ * */
+void CMsvIndexAdapter::DoMoveEntryL(TMsvId aId, TMsvId aTarget, CMsvEntrySelection* aDescendents /* DEFAULT=NULL */)
+ {
+ // Leave if the message store is not currently available.
+ User::LeaveIfError(iErrorState);
+
+ CMsvCacheEntry* entry = NULL;
+ CMsvCacheVisibleFolder* oldFolderNode = NULL;
+ TMsvId oldVisibleFolderId = KMsvNullIndexEntryIdValue;
+
+ // 1. Find the entry in cache.
+ GetVisibleFolderDetailsL(aId, entry, oldFolderNode);
+
+ // 2. Validate entry.
+ TBool des;
+ __ASSERT_DEBUG(entry->IsEntryAndStoreLocked(), PanicServer(EMsvMovingUnlockedEntry));
+ __ASSERT_DEBUG(entry->Entry().Parent() != aTarget, PanicServer(EMsvMovingWithinSameEntry));
+ IsADescendent(entry->Entry().Id(), aTarget, des);
+ if (des)
+ {// we need to put changes in another method.
+ User::Leave(KErrArgument);
+ }
+
+ // 3. Fetch the parent entries.
+ CMsvCacheEntry* oldParentEntry = NULL;
+ CMsvCacheEntry* newParentEntry = NULL;
+ TMsvId oldParentId = entry->Entry().Parent();
+ FindEntryL(oldParentId, oldParentEntry);
+ FindEntryL(aTarget, newParentEntry);
+
+ // 4. Check if the owner flag of the old parent needs to be reset.
+ TBool resetOldParentOwnerFlag = EFalse;
+ CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+ GetChildrenIdL(oldParentId, *children);
+ if(1 == children->Count() && oldParentEntry->Entry().Owner())
+ {
+ // Just set this flag, this is updated in step 14.
+ resetOldParentOwnerFlag = ETrue;
+ }
+ CleanupStack::PopAndDestroy(); //children
+
+ // 5. If required, pre-allocate memory for child array of newParentEntry.
+ // This is later updated in step 12.
+ RArray<TMsvId>* newParentChildArr = newParentEntry->ChildIdArray();
+ if(newParentChildArr)
+ {
+ // This to ensure that future append does not fail.
+ newParentChildArr->ReserveL(newParentChildArr->Count() + 1);
+ }
+
+ // Step 6 & 7 is performed in this function.
+ TBool isChildEntriesNeedsUpdation = EFalse;
+ CMsvCacheVisibleFolder* newVisibleFolderNode = UpdateCacheForMoveEntryL(aTarget,
+ entry,
+ oldFolderNode,
+ aDescendents,
+ isChildEntriesNeedsUpdation);
+
+ TMsvId newVisibleFolderId = newVisibleFolderNode? newVisibleFolderNode->GetFolderId(): oldFolderNode->GetFolderId();
+
+ // 8. Update the entry.
+ UpdateDates(*entry, EFalse);
+ entry->Entry().SetParent(aTarget);
+
+ // 9. Update the DB.
+ TRAPD(err,
+ iDbAdapter->BeginTransactionL();
+ // Update the actual entry
+ iDbAdapter->UpdateEntryL(entry->Entry(), newVisibleFolderId);
+ // Reset old parent owner flag.
+ if(resetOldParentOwnerFlag)
+ iDbAdapter->UpdateOwnerStatusL(oldParentId, oldParentEntry->Entry(), EFalse);
+ // Set new parent owner flag.
+ if(!newParentEntry->Entry().Owner())
+ iDbAdapter->UpdateOwnerStatusL(aTarget, newParentEntry->Entry(), ETrue);
+ // Update the child entries visibleFolderId in DB.
+ if(isChildEntriesNeedsUpdation)
+ iDbAdapter->UpdateVisibleFolderL(aDescendents, newVisibleFolderId);
+ iDbAdapter->CommitTransactionL();
+ );
+
+ if(err)
+ {
+ TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
+ // Undo step 8.
+ entry->Entry().SetParent(oldParentId);
+ // Undo step 7.
+ if(newVisibleFolderNode)
+ newVisibleFolderNode->DeleteEntryL(aId);
+ if(isChildEntriesNeedsUpdation)
+ {
+ for(TInt index=(aDescendents->Count()-2); index>=0; index--)
+ {
+ newVisibleFolderNode->DeleteEntryL(aDescendents->At(index));
+ }
+ }
+ User::Leave(err);
+ }
+
+ // Nothing should fail after this. Ensure that
+ // all leaving function after this does not leave.
+
+ // 10. Continuing step 7.1.
+ // Removing entry from old visible folder.
+ if(oldVisibleFolderId != newVisibleFolderId)
+ {
+ oldFolderNode->DeleteEntryL(aId);
+ }
+
+ // 11. Continuing step 7.2.
+ // Removing child entries from old visible folder.
+ if(isChildEntriesNeedsUpdation)
+ {
+ for(TInt index=(aDescendents->Count()-2); index>=0; index--)
+ {
+ oldFolderNode->DeleteEntryL(aDescendents->At(index));
+ }
+ }
+
+ // 12. Add child id to new parent child array.
+ if(newParentChildArr)
+ {
+ // This will not leave, as memory is already reserved.
+ newParentChildArr->AppendL(aId);
+ }
+
+ // 13. Remove child from old parent's child array.
+ RArray<TMsvId>* oldParentChildArr = oldParentEntry->ChildIdArray();
+ if(oldParentChildArr)
+ {
+ TInt pos = oldParentChildArr->Find(aId);
+ if(pos != KErrNotFound)
+ {
+ oldParentChildArr->Remove(pos);
+ }
+ }
+
+ // 14. Update owner flag of parent entries.
+ if(resetOldParentOwnerFlag)
+ {
+ oldParentEntry->Entry().SetOwner(EFalse);
+ }
+ newParentEntry->Entry().SetOwner(ETrue);
+ }
+
+
+
+
+void CMsvIndexAdapter::GetVisibleFolderDetailsL(TMsvId aEntryId, CMsvCacheEntry*& aEntry, CMsvCacheVisibleFolder*& aVisibleFolder)
+ {
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+ while((aVisibleFolder = dqIter++)!=NULL)
+ {
+ if(aVisibleFolder->GetEntry(aEntryId, aEntry))
+ {
+ break;
+ }
+ }
+ if(aEntry==NULL)
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+
+
+
+
+CMsvCacheVisibleFolder* CMsvIndexAdapter::UpdateCacheForMoveEntryL(TMsvId aNewParentId,
+ CMsvCacheEntry*& aOrigEntry,
+ CMsvCacheVisibleFolder* aOldVisibleFolderNode,
+ CMsvEntrySelection* aDescendents,
+ TBool& aIsChildEntriesNeedsUpdation)
+ {
+ // 6. Find the visible folder of new parent.
+ TMsvId newVisibleFolderId = aOldVisibleFolderNode->GetFolderId();
+ if(!GetVisibleFolderId(aNewParentId, newVisibleFolderId))
+ {
+ User::Leave(KErrNotFound);
+ }
+
+ // 7. Check if the visible folders are different.
+ CMsvCacheVisibleFolder* newVisibleFolderNode = NULL;
+ if(aOldVisibleFolderNode->GetFolderId() != newVisibleFolderId)
+ {
+ // 7.1. If the visible folders are different, add duplicate
+ // entry under new visible folder. Removing entry from old
+ // visible folder is done in step 10 of DoMoveEntryL().
+ CMsvCacheEntry* newCacheEntry = iFreePoolInstance->EntryL();
+ TRAPD(err, newCacheEntry->DupNDestroyL(aOrigEntry);
+ newVisibleFolderNode = AddEntryToCacheL(newVisibleFolderId, newCacheEntry);
+ );
+ if(err)
+ {
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(newCacheEntry);
+ User::Leave(err);
+ }
+
+ // 7.2. Check if child entries also needs to be moved.
+ aOrigEntry = newCacheEntry;
+ if(aDescendents && !aOrigEntry->Entry().VisibleFolderFlag())
+ {
+ aIsChildEntriesNeedsUpdation = ETrue;
+
+ // Add duplicate child entry under new visible folder.
+ // Removing child entries from old visible folder is done in step 11.
+ CMsvCacheEntry* childEntry = NULL;
+ CMsvCacheEntry* dupChildEntry = NULL;
+ for(TInt index=(aDescendents->Count()-2); index>=0; index--)
+ {
+ if(aOldVisibleFolderNode->GetEntry(aDescendents->At(index), childEntry))
+ {
+ dupChildEntry = NULL;
+ // Create the duplicate of original entry.
+ TRAP(err, dupChildEntry = iFreePoolInstance->EntryL();
+ dupChildEntry->DupNDestroyL(childEntry);
+ // Add under new visible folder node.
+ newVisibleFolderNode->AddEntryL(dupChildEntry);
+ );
+ if(err)
+ {
+ // Delete should not be leaving...
+ newVisibleFolderNode->DeleteEntryL(aOrigEntry->GetId()); // Undo step 7.1
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(dupChildEntry); // Undo current entry
+ // Undo remaining entries.
+ for(TInt numEntries=index+1; numEntries<=(aDescendents->Count()-2); numEntries++)
+ {
+ newVisibleFolderNode->DeleteEntryL(aDescendents->At(numEntries));
+ }
+ User::Leave(err);
+ }
+ } // if(oldFolderNode->GetEntry(aDescendents->At(index), childEntry))
+ } // for()
+ } // if(aDescendents && !entry->Entry().VisibleFolderFlag())
+ }
+ return newVisibleFolderNode;
+ }
+
+
+
+
+/**
+ * IsADescendent()
+ */
+TInt CMsvIndexAdapter::IsADescendent(TMsvId aAscendentId, TMsvId aDescendentId, TBool& aDescendent)
+ {
+ __ASSERT_DEBUG((KMsvRootIndexEntryId != aAscendentId) && (KMsvRootIndexEntryId != aDescendentId), PanicServer(EMsvDescendentArgumentsRoot));
+ __ASSERT_DEBUG(aAscendentId!=aDescendentId, PanicServer(EMsvDescendentArgumentsEqual));
+
+ aDescendent=EFalse;
+ while (KMsvRootIndexEntryId != aDescendentId)
+ {
+ CMsvCacheEntry* entry;
+ TRAPD(err, FindEntryL(aDescendentId, entry));
+ if (err)
+ {
+ return KErrNotFound;
+ }
+ if (aDescendentId==aAscendentId)
+ {
+ aDescendent=ETrue;
+ break;
+ }
+ aDescendentId=entry->Entry().Parent();
+ }
+
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * EntryExists()
+ */
+TBool CMsvIndexAdapter::EntryExists(TMsvId aId)
+ {
+ // First search the entry in cache,
+ // if cache is not empty...
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ if(KMsvRootIndexEntryId == aId)
+ {
+ return true;
+ }
+#endif
+ if(!iFolderListHeader.IsEmpty())
+ {
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(aId == folderNode->GetFolderId())
+ {
+ return ETrue;
+ }
+ if(folderNode->EntryExists(aId))
+ {
+ return ETrue;
+ }
+ }
+ }
+
+ TBool entryExists = EFalse;
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(entryExists = iDbAdapter->EntryExistsL(aId));
+ }
+ else
+ {
+ return EFalse;
+ }
+ if(!entryExists)
+ {
+ return EFalse;
+ }
+ return ETrue;
+ }
+
+
+
+
+/**
+ * ChangeTemporaryData()
+ */
+TInt CMsvIndexAdapter::ChangeTemporaryData(const TMsvEntry& aNewEntryContents)
+ {
+ //__DEBUG_INVARIANT_ONEXIT;
+
+ CMsvCacheEntry* entry;
+
+ // find the entry in the index
+ TRAPD(err, FindEntryL(aNewEntryContents.Id(), entry));
+ if (err)
+ {
+ return KErrNotFound;
+ }
+
+ // Can only change a locked entry and not one marked as read only
+ if (!entry->IsEntryLocked() || entry->Entry().StandardFolder())
+ {
+ return KErrAccessDenied;
+ }
+
+ // Check if just changing temporary flags (ie those not stored on file)
+ entry->Entry().iData=aNewEntryContents.iData;
+
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * ChangeAttributes()
+ */
+TInt CMsvIndexAdapter::ChangeAttributes(CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
+ {
+ TRAPD(leave, DoChangeAttributesL(aSelection, aSetAttributes, aClearAttributes));
+ return leave;
+ }
+
+
+
+void CMsvIndexAdapter::DoChangeAttributesL(CMsvEntrySelection& aSelection, TUint aSetAttributes, TUint aClearAttributes)
+ {
+ // Leave if the message store is not currently available
+ User::LeaveIfError(iErrorState);
+
+ CArrayFixSeg<TInt32>* newData = new(ELeave)CArrayFixSeg<TInt32>(KMsvChangeAttributesListGranularity);
+ CleanupStack::PushL(newData);
+ CArrayFixSeg<TInt32>* newPcSyncCount = new(ELeave)CArrayFixSeg<TInt32>(KMsvChangeAttributesListGranularity);
+ CleanupStack::PushL(newPcSyncCount);
+
+ newData->ResizeL(aSelection.Count(), 0);
+ newPcSyncCount->ResizeL(aSelection.Count(), 0);
+
+ TInt count=aSelection.Count();
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ CMsvCacheEntry* entry = NULL;
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TMsvId newVisibleFolderId = NULL;
+ if(iDbAdapter)
+ {
+ iDbAdapter->BeginTransactionL();
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ while(count--)
+ {
+ // find the entry in the index
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(folderNode->GetEntry(aSelection.At(count), entry))
+ {
+ newVisibleFolderId = folderNode->GetFolderId();
+ break;
+ }
+ }
+ if (entry == NULL)
+ {
+ User::Leave(KErrNotFound);
+ }
+ // can only change a locked entry and not one marked as read only
+ if (!entry->IsEntryLocked() || entry->Entry().StandardFolder())
+ {
+ User::Leave(KErrAccessDenied);
+ }
+
+ // work out the new attributes
+ TBool persistedFlagsChanged;
+ if (!NewAttributes(entry->Entry(), newData->At(count), newPcSyncCount->At(count), aSetAttributes, aClearAttributes, persistedFlagsChanged))
+ {
+ // attributes don't need changing
+ aSelection.Delete(count);
+ newData->Delete(count);
+ newPcSyncCount->Delete(count);
+ continue;
+ }
+ if(persistedFlagsChanged)
+ {
+ TMsvEntry tEntry = entry->Entry();
+ tEntry.iData = newData->At(count);
+ tEntry.iPcSyncCount = newPcSyncCount->At(count);
+ TInt err = KErrNone;
+ if(iDbAdapter)
+ {
+ TRAP(err, iDbAdapter->UpdateEntryL(tEntry, newVisibleFolderId, EFalse));
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ if(err)
+ {
+ iDbAdapter->RollbackTransactionL();
+ User::Leave(err);
+ }
+ }
+ }
+ if(iDbAdapter)
+ {
+ iDbAdapter->CommitTransactionL();
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+
+ count=aSelection.Count();
+ while(count--)
+ {
+ // find the entry in the index
+ CMsvCacheEntry* entryPtr = NULL;
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(folderNode->GetEntry(aSelection.At(count), entryPtr))
+ {
+ break;
+ }
+ }
+#if defined(_DEBUG)
+ TBool found = (NULL != entryPtr);
+ __ASSERT_DEBUG(found, PanicServer(EMsvChangeAttEmtryNotFound));
+#endif
+ entryPtr->Entry().iData=newData->At(count);
+ entryPtr->Entry().iPcSyncCount=newPcSyncCount->At(count);
+ }
+ CleanupStack::PopAndDestroy(2, newData);
+ if (!iIdle->IsActive())
+ {
+ iIdle->Start(TCallBack(BackGroundOperations, this));
+ }
+
+ }
+
+/**
+ * NewAttributes
+*/
+TBool CMsvIndexAdapter::NewAttributes(const TMsvEntry& aEntry, TInt32& aNewData, TInt32& aNewPcSyncCount, TUint aSetAttributes, TUint aClearAttributes, TBool& aPersistedFlagsChanged)
+ {
+ aNewData = aEntry.iData;
+ aNewPcSyncCount = aEntry.iPcSyncCount;
+
+ // KMsvPcSyncCountAttribute is a dummy flag that is used to increment/decrement the PC Sync Count
+ // The visibility attribute is actually recorded as an 'invisible' flag in the index
+ if (aSetAttributes)
+ {
+ if (aSetAttributes & KMsvPcSyncCountAttribute)
+ {
+ aNewPcSyncCount++;
+ aSetAttributes &= ~KMsvPcSyncCountAttribute;
+ }
+
+ const TInt32 mask = KMsvSendStateMax << KMsvSendingStateShift;
+ if (aSetAttributes & mask)
+ {
+ aNewData &= ~mask;
+ }
+
+
+ aNewData |= aSetAttributes;
+
+ if (aSetAttributes & KMsvVisibilityAttribute)
+ {
+ aNewData &= ~TMsvEntry::KMsvEntryInvisibleFlag;
+ }
+ if (aSetAttributes & KMsvPendingDeleteAttribute)
+ {
+ aNewData |= TMsvEntry::KMsvEntryPendingDeleteFlag;
+ }
+ }
+
+ if (aClearAttributes)
+ {
+ if (aClearAttributes & KMsvPcSyncCountAttribute)
+ {
+ aNewPcSyncCount--;
+ aClearAttributes &= ~KMsvPcSyncCountAttribute;
+ }
+
+ aNewData &= ~aClearAttributes;
+
+ if (aClearAttributes&KMsvVisibilityAttribute)
+ {
+ aNewData |= TMsvEntry::KMsvEntryInvisibleFlag;
+ }
+
+ if (aClearAttributes&KMsvPendingDeleteAttribute)
+ {
+ aNewData &= ~TMsvEntry::KMsvEntryPendingDeleteFlag;
+ }
+
+ }
+
+ aPersistedFlagsChanged = (aNewData&TMsvEntry::KMsvEntryPersistedFlags)!=(aEntry.iData&TMsvEntry::KMsvEntryPersistedFlags) ||
+ aNewPcSyncCount != aEntry.iPcSyncCount;
+ return aNewData != aEntry.iData || aNewPcSyncCount != aEntry.iPcSyncCount;
+ }
+
+/**
+ * UpdateDates
+*/
+void CMsvIndexAdapter::UpdateDates(CMsvCacheEntry& aEntry, TBool aSetCreatedDate)
+ {
+ TTime now;
+ now.UniversalTime();
+ TMsvTime time;
+ time.SetTime(now);
+ aEntry.SetLastChangeDate(time);
+
+ if (aSetCreatedDate)
+ {
+ aEntry.SetCreatedDate(time);
+ }
+ }
+
+
+
+
+/**
+ * GetInternalEntry()
+ */
+TInt CMsvIndexAdapter::GetInternalEntry(TMsvId aId, CMsvCacheEntry*& aEntry)
+ {
+ CMsvCacheEntry* entry=NULL;
+ TRAPD(err, FindEntryL(aId, entry));
+ if(err!=KErrNone)
+ {
+ return err;
+ }
+ if(entry==NULL)
+ {
+ return KErrNotFound;
+ }
+ aEntry=entry;
+ return KErrNone;
+ }
+
+
+/**
+ * Progress()
+*/
+TMsvIndexProgress& CMsvIndexAdapter::Progress()
+ {
+ return iProgress;
+ }
+
+
+/**
+ * EntryTreeInfo()
+ */
+TInt CMsvIndexAdapter::EntryTreeInfo(TMsvId aId, TMsvServerEntryInfo& aEntryInfo)
+ {
+ aEntryInfo.Reset();
+ aEntryInfo.iId = aId;
+
+ if( aId != KMsvRootIndexEntryId )
+ {
+ // Search up the tree to find which service the specified entry is under.
+ // Also, record the highest owning folder for the entry.
+ TMsvId id = aId;
+ CMsvCacheEntry* entry =NULL;
+ TRAPD(err, FindEntryL(id, entry));
+ if(err)
+ return KErrNotFound;
+
+ id = entry->Entry().iId; //Id may be masked in cache
+ aEntryInfo.iId = id;
+
+ // Get info for the entry.
+ aEntryInfo.iEntryOwnerId = entry->EntryOwnerId();
+ aEntryInfo.iMtm = entry->Entry().iMtm;
+ aEntryInfo.iType = entry->Entry().iType;
+
+ if( aEntryInfo.iType == KUidMsvFolderEntry )
+ {
+ // This is a folder - record as this may be needed.
+ aEntryInfo.iTopFolder = id;
+ }
+
+ TBool found = (aEntryInfo.iType == KUidMsvServiceEntry);
+ while( !found )
+ {
+ // Move up the tree and get the next entry...
+ id = entry->Entry().Parent();
+ TRAPD(err, FindEntryL(id, entry));
+ if(err)
+ return KErrNotFound;
+
+ TUid type = entry->Entry().iType;
+ if( type == KUidMsvServiceEntry )
+ {
+ // Ok, we've found the owning service - stop looking.
+ found = ETrue;
+ }
+ else if( type == KUidMsvFolderEntry )
+ {
+ // This is a folder - record as this may be needed.
+ aEntryInfo.iTopFolder = id;
+ }
+ else
+ {
+ // This is a message or attachment entry - this implies that the
+ // original entry was part of an existing message. Set the owner
+ // ID to the highest parent.
+ aEntryInfo.iPartOfMessage = ETrue;
+ aEntryInfo.iParentOwnerId = entry->EntryOwnerId();
+ }
+ }
+ // Record the service and MTM...
+ aEntryInfo.iService = id;
+
+ aEntryInfo.iServiceMtm = entry->Entry().iMtm;
+ }
+ else
+ {
+ // This is the root entry! Mark the service as being the local service.
+ aEntryInfo.iType = KUidMsvRootEntry;
+ aEntryInfo.iMtm = KUidMsvLocalServiceMtm;
+ aEntryInfo.iService = KMsvLocalServiceIndexEntryId;
+ aEntryInfo.iServiceMtm = KUidMsvLocalServiceMtm;
+ aEntryInfo.iTopFolder = KMsvRootIndexEntryId;
+ }
+ return KErrNone;
+ }
+
+
+
+
+/**
+ * CommitNonCommitedEntries()
+ */
+void CMsvIndexAdapter::CommitNonCommitedEntries()
+ {
+ // 1. Commit transaction in DB.
+ if(iDbAdapter)
+ {
+ TRAPD(err, iDbAdapter->CommitTransactionL());
+ if(err)
+ {
+ RollbackAdditions();
+ RollbackChanges();
+ return;
+ }
+ }
+
+ // 2. Update changed entries completely.
+ TInt count = iNonCommittedChangedEntryList.Count();
+ while(count)
+ {
+ TNonCommittedChangedEntries changedEntry = iNonCommittedChangedEntryList[--count];
+ CMsvCacheVisibleFolder* oldVisibleFolderNode = changedEntry.iOldVisibleFolderNode;
+ // Removing entry from old visible folder.
+ if(changedEntry.iNewVisibleFolderNode &&
+ oldVisibleFolderNode->GetFolderId() != changedEntry.iNewVisibleFolderNode->GetFolderId())
+ {
+ // Will never leave.
+ TRAP_IGNORE(changedEntry.iOldVisibleFolderNode->DeleteEntryL(changedEntry.iEntry->GetId()));
+ }
+
+ // Removing child entries from old visible folder.
+ if(changedEntry.iDescendentList)
+ {
+ for(TInt index=(changedEntry.iDescendentList->Count()-2); index>=0; index--)
+ {
+ // Can leave with KErrNotFound.
+ TRAP_IGNORE(oldVisibleFolderNode->DeleteEntryL(changedEntry.iDescendentList->At(index)));
+ }
+ delete changedEntry.iDescendentList;
+ }
+
+ // Add child id to new parent child array.
+ if(changedEntry.iNewParentEntry && (changedEntry.iNewParentEntry->ChildIdArray()))
+ {
+ // This will not leave, as memory is already reserved.
+ TRAP_IGNORE(changedEntry.iNewParentEntry->ChildIdArray()->AppendL(changedEntry.iEntry->GetId()));
+ }
+
+ // Remove child from old parent's child array.
+ if(changedEntry.iOldParentEntry)
+ {
+ RArray<TMsvId>* oldParentChildArr = changedEntry.iOldParentEntry->ChildIdArray();
+ if(oldParentChildArr)
+ {
+ TInt pos = oldParentChildArr->Find(changedEntry.iEntry->GetId());
+ if(pos != KErrNotFound)
+ {
+ oldParentChildArr->Remove(pos);
+ }
+ }
+ }
+
+ // Update owner flag of parent entries.
+ if(changedEntry.iResetOldParentOwnerFlag)
+ {
+ changedEntry.iOldParentEntry->Entry().SetOwner(EFalse);
+ }
+ if(changedEntry.iNewParentEntry)
+ {
+ changedEntry.iNewParentEntry->Entry().SetOwner(ETrue);
+ }
+ }
+
+ // 3. Reset non-committed entry list.
+ iNonCommittedAddedEntryList.ResetAndDestroy();
+ iNonCommittedChangedEntryList.Reset();
+ }
+
+
+
+/**
+ * RollbackAdditions()
+ */
+void CMsvIndexAdapter::RollbackAdditions()
+ {
+ // 1. Rollback transaction in DB.
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
+ }
+
+ // 2. Delete added entry from cache.
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TInt count = iNonCommittedAddedEntryList.Count();
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ while(count)
+ {
+ --count;
+ dqIter.SetToFirst();
+ while ((folderNode = dqIter++) != NULL)
+ {
+ if(iNonCommittedAddedEntryList[count]->iVisibleFolder == folderNode->GetFolderId())
+ {
+ iNonCommittedAddedEntryList[count]->entry->LockEntry();
+ // Error can cause if the entry does not exist. Ignore.
+ TRAP_IGNORE(folderNode->DeleteEntryL(iNonCommittedAddedEntryList[count]->entry->GetId()));
+ break;
+ }
+ };
+ }
+
+ // 3. Reset non-committed entry list.
+ iNonCommittedAddedEntryList.ResetAndDestroy();
+ }
+
+
+
+
+
+/**
+ * RollbackChanges()
+ */
+void CMsvIndexAdapter::RollbackChanges()
+ {
+ // 1. Rollback transaction in DB.
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->RollbackTransactionL());
+ }
+
+ // 2. Undo changed entry in cache.
+ TInt count = iNonCommittedChangedEntryList.Count();
+ while(count)
+ {
+ TNonCommittedChangedEntries changedEntry = iNonCommittedChangedEntryList[--count];
+ CMsvCacheEntry* oldEntry = changedEntry.iEntry;
+
+ // If the visible folder Id of the entry is changed,
+ // oldEntry represents the entry under new visible folder node.
+ // Get the actual old entry from old visible folder node.
+ if(changedEntry.iNewVisibleFolderNode)
+ {
+ // This will be non leaving as entry is already present.
+ if(changedEntry.iOldVisibleFolderNode->GetEntry(oldEntry->GetId(), oldEntry))
+ {
+ // Remove added entry from new visible node.
+ // This function will never leave in the current
+ // scenario, hence ignoring the error.
+ TRAP_IGNORE(changedEntry.iNewVisibleFolderNode->DeleteEntryL(oldEntry->GetId()));
+ }
+ }
+ oldEntry->SetEntryOwnerId(changedEntry.iBkpEntry->EntryOwnerId());
+ oldEntry->RollBackCopyEntry(changedEntry.iBkpEntry->Entry());
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(changedEntry.iBkpEntry);
+
+ if(changedEntry.iDescendentList)
+ {
+ delete changedEntry.iDescendentList;
+ }
+ }
+
+ // 3. Reset non-committed entry list.
+ iNonCommittedChangedEntryList.Reset();
+ }
+
+
+
+
+CMsvIndexAdapter::TMsvServerEntryInfo::TMsvServerEntryInfo()
+ {
+ iId = KMsvNullIndexEntryIdValue;
+ iTopFolder = KMsvNullIndexEntryIdValue;
+ iService = KMsvNullIndexEntryIdValue;
+ iMtm = KUidMsvNullEntry;
+ iType = KUidMsvNullEntry;
+ iServiceMtm = KUidMsvNullEntry;
+ iEntryOwnerId = KMsvServerId.iId;
+ iParentOwnerId = KMsvServerId.iId;
+ iPartOfMessage = EFalse;
+ }
+
+
+
+
+void CMsvIndexAdapter::TMsvServerEntryInfo::Reset()
+ {
+ iId = KMsvNullIndexEntryIdValue;
+ iTopFolder = KMsvNullIndexEntryIdValue;
+ iService = KMsvNullIndexEntryIdValue;
+ iMtm = KUidMsvNullEntry;
+ iType = KUidMsvNullEntry;
+ iServiceMtm = KUidMsvNullEntry;
+ iEntryOwnerId = KMsvServerId.iId;
+ iParentOwnerId = KMsvServerId.iId;
+ iPartOfMessage = EFalse;
+ }
+
+
+/**
+Need to see the posibilty of getting this first from cache
+*/
+TBool CMsvIndexAdapter::GetNextSiblingL(TMsvId aId,TMsvId aParentId,TMsvId& aNextSiblingId)
+ {
+ TBool flag = EFalse;
+ if(iDbAdapter)
+ {
+ flag = iDbAdapter->GetNextSiblingL(aId, aParentId, aNextSiblingId);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ return flag;
+ }
+
+
+/**
+Need to see the posibilty of getting this first from cache
+*/
+TBool CMsvIndexAdapter::GetFirstChildIdL(TMsvId aParentId,TMsvId& aFirstChild)
+ {
+ TBool flag = EFalse;
+ if(iDbAdapter)
+ {
+ flag = iDbAdapter->GetFirstChildIdL(aParentId, aFirstChild);
+ }
+ else
+ {
+ User::Leave(ErrorState());
+ }
+ return flag;
+ }
+
+
+/**
+ * SetLocalServiceComplete
+ * @param TUint: Drive Id of the local service folder node.
+ *
+ * Code changes for PREQ 557.
+ * Sets the localservice visiblefolder.
+ */
+void CMsvIndexAdapter::SetLocalServiceComplete()
+ {
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+ CMsvCacheVisibleFolder* folderNode = NULL;
+
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(KMsvLocalServiceIndexEntryIdValue == folderNode->GetFolderId())
+ {
+ folderNode->SetComplete(ETrue);
+ break;
+ }
+ }
+ }
+
+
+/**
+ *BackGroundOperations()
+ *@param aPtr A TAny*
+ *@return TBool ETrue if the background operation needs to be rescheduled.
+ * EFalse if the background operation need not be rescheduled.
+ */
+TBool CMsvIndexAdapter::BackGroundOperations(TAny* aPtr)
+ {
+ return ((CMsvIndexAdapter*)aPtr)->DoBackGroundOperations();
+ }
+
+
+
+
+
+/**
+ *DoBackGroundOperations()
+ *@param None
+ *@return TBool ETrue if the background operation needs to be rescheduled.
+ * EFalse if the background operation need not be rescheduled.
+ */
+TBool CMsvIndexAdapter::DoBackGroundOperations()
+ {
+ TInt stopBackgroundOperation = EFalse;
+ TRAPD(err, DoBackGroundOperationsL(stopBackgroundOperation));
+ if(KErrNone == err && !stopBackgroundOperation)
+ {
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+
+
+
+/**
+ *DoBackGroundOperations()
+ *This is the background operation state machine, this will perform a set
+ *of operations in each of the iteration.
+ *
+ *@param None
+ *@return void
+ */
+void CMsvIndexAdapter::DoBackGroundOperationsL(TBool& aStopBackgroundOperation)
+ {
+ iFreePoolInstance->RoutineFreePoolCleanUpL();
+ switch(iBackgroundOperationState)
+ {
+ case ERemoveDeletedEntries:
+ {
+ iBackgroundOperationState = EAllocateMemoryOperation;
+ DoRemoveDeletedEntriesL();
+ break;
+ }
+ case EAllocateMemoryOperation:
+ {
+ iBackgroundOperationState = ECheckBlockSize;
+ if(CheckAndAllocateMemoryL())
+ {
+ iBackgroundOperationPerformed = 0;
+ break;
+ }
+ iBackgroundOperationPerformed++;
+ }
+ case ECheckBlockSize:
+ {
+ iBackgroundOperationState = ENoOperation;
+ SplitBlockL();
+ break;
+ }
+ case ENoOperation:
+ default:
+ {
+ iBackgroundOperationState = ERemoveDeletedEntries;
+ // The background operation has run multiple times, without doing
+ // much work, so it can be stopped temporarily.
+ if(iBackgroundOperationPerformed >= 5)
+ {
+ iBackgroundOperationPerformed = 0;
+ aStopBackgroundOperation = ETrue;
+ }
+
+ break;
+ }
+ }
+
+ }
+
+
+
+/**
+ *CheckAndAllocateMemory
+ *Will check the state of the free pool and allocate memory if required.
+ *Allocation will be done if 70% of the CMsvCacheEntries created are used.
+ *
+ *@return TBool ETrue, if allocation has been done.
+ * EFalse, if no allocation is done.
+ */
+TBool CMsvIndexAdapter::CheckAndAllocateMemoryL()
+ {
+ if(iFreePoolInstance->IsAllocationRequiredL())
+ {
+ iFreePoolInstance->AllocateMemoryL();
+ return ETrue;
+ }
+ return EFalse;
+ }
+
+
+
+
+/**
+ *SplitBlockL
+ *Will sort and split the blocks of CMsvCacheEntries.
+ *
+ *@return void
+ */
+void CMsvIndexAdapter::SplitBlockL()
+ {
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ dqIter.SetToFirst();
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ while((folderNode = dqIter++)!=NULL)
+ {
+ folderNode->SplitBlockL();
+ }
+ }
+
+
+
+/**
+ *ForceDeleteEntry
+ *Deletes the TMsvEntry even if it is not in the cache.This does not require
+ *the entry to be locked.
+ *
+ *@param aId TMsvId, id ofthe entry to be deleted.
+ *@return TInt Any of the system wide error codes.
+ */
+TInt CMsvIndexAdapter::ForceDeleteEntry(TMsvId aId)
+ {
+ TRAPD(leave, DoForceDeleteEntryL(aId));
+ return leave;
+ }
+
+
+
+/**
+ *DoForceDeleteEntryL
+ *Called from ForceDeleteEntry
+ *
+ *@param aId TMsvId, id ofthe entry to be deleted.
+ *@return void
+ */
+void CMsvIndexAdapter::DoForceDeleteEntryL(TMsvId aId)
+ {
+ User::LeaveIfError(iErrorState);
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+
+ if(!iDbAdapter)
+ {
+ User::Leave(ErrorState());
+ }
+ CMsvCacheEntry* entry = NULL;
+ TBool releaseEntry = FindEntryL(aId, entry, EFalse);
+ TMsvId parentId = entry->Entry().Parent();
+ TRAPD(err, iDbAdapter->DeleteEntryL(aId));
+ // If the entry does not exists in cache,
+ // we need to release the entry explicitly.
+ if(releaseEntry)
+ {
+ iFreePoolInstance->ReleaseEntry(entry, ETrue);
+ User::LeaveIfError(err);
+ }
+ else
+ {
+ User::LeaveIfError(err);
+ // Otherwise remove the entry from cache.
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ TRAPD(err, folderNode->DeleteEntryL(aId, ETrue));
+ if(KErrNone == err)
+ {
+ break;
+ }
+ }
+ }
+ //Find the parent entry in cache and check for any children.
+ //If there are no more children under the parent, then
+ //reset the owner flag in cache and database.
+ CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+ releaseEntry = FindEntryL(parentId, entry, EFalse);
+ TRAP(err,
+ GetChildrenIdL(parentId, *children);
+ if(0 == children->Count() && entry->Entry().Owner())
+ {
+ iDbAdapter->UpdateOwnerStatusL(parentId, entry->Entry(), EFalse);
+ entry->Entry().SetOwner(EFalse);
+ }
+ );
+ if(releaseEntry)
+ {
+ iFreePoolInstance->ReleaseEntry(entry, ETrue);
+ }
+ User::LeaveIfError(err);
+ CleanupStack::PopAndDestroy(); //children
+ }
+
+
+
+/**
+ *DeleteSelectionUsingTransaction
+ *Deletes a selection of TMsvEntries.This will also delete enteries that are not locked.
+ *
+ *@param aSelection CMsvEntrySelection&, selection of the TMsvEntries.
+ @param TInt Any of the system wide error codes.
+ */
+
+TInt CMsvIndexAdapter::DeleteSelectionUsingTransaction(const CMsvEntrySelection& aSelection)
+ {
+ TRAPD(leave, DoDeleteSelectionUsingTransactionL(aSelection));
+ return leave;
+ }
+
+
+/**
+ *DoDeleteSelectionUsingTransactionL
+ *Called from DeleteSelectionUsingTransaction.
+ *
+ *@param aSelection CMsvEntrySelection&, selection of the TMsvEntries.
+ @param void
+ */
+void CMsvIndexAdapter::DoDeleteSelectionUsingTransactionL(const CMsvEntrySelection& aSelection)
+ {
+ User::LeaveIfError(iErrorState);
+ if(!iDbAdapter)
+ {
+ User::Leave(iErrorState);
+ }
+
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+ const TInt count = aSelection.Count();
+
+ if(!count)
+ {
+ return;
+ }
+
+ CMsvEntrySelection* children = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(children);
+ CMsvCacheEntry* entry = NULL;
+ TBool releaseEntry = FindEntryL(aSelection.At(0), entry, EFalse);
+ TMsvId parentId = entry->Entry().Parent();
+ if(releaseEntry)
+ {
+ iFreePoolInstance->ReleaseEntry(entry, ETrue);
+ }
+
+ // Find the parent in the cache - we may need to update its owner status flag both in cache and DB.
+ TBool updateTheParent = ETrue;
+ TRAPD(err, releaseEntry = FindEntryL(parentId, entry, EFalse)); // can't let it leave - need to delete the child in any case.
+ if(err == KErrNotFound)
+ {
+ updateTheParent = EFalse;
+ if(releaseEntry)
+ {
+ iFreePoolInstance->ReleaseEntry(entry, ETrue);
+ }
+ }
+ else
+ {
+ // Get parent's children.
+ GetChildrenIdL(parentId, *children); // can leave - we'll let it leave as there's nothing to be rolled back now.
+ if(children->Count() > 1)
+ updateTheParent = EFalse;
+ }
+
+ // Perform DB operations:
+ // - Delete the entry.
+ // - Update owner status flag of the parent.
+ iDbAdapter->DeleteEntryL(aSelection); // can leave - we'll let it leave as there's nothing to be rolled back now.
+ if(updateTheParent)
+ {
+ TRAP(err, iDbAdapter->UpdateOwnerStatusL(parentId, entry->Entry(), EFalse));
+ }
+ // Leave if DB operations fail. Cache is not touched.
+ if(err)
+ {
+ TRAP_IGNORE(iDbAdapter->RollbackTransactionL()); //
+ User::Leave(err);
+ }
+ else
+ {
+ if(updateTheParent)
+ {
+ entry->Entry().SetOwner(EFalse);
+ }
+ // Do the cache operations. These don't require any memory allocation and cannot fail.
+ for (TInt index=0; index<count; ++index)
+ {
+ // If the entry is a visible folder, then delete the node.
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ if(folderNode->GetFolderId() == aSelection.At(index))
+ {
+ folderNode->iDlink.Deque();
+ delete folderNode;
+ break;
+ }
+ }
+
+ // Delete the entry from under its parent visible folder.
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ TRAPD(err, folderNode->DeleteEntryL(aSelection.At(index), ETrue));
+ if(KErrNone == err)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ // Update SearchSort delta cache.
+ TMsgType aType(EDeletedMsg);
+ if(CMSvSearchSortCacheManager::Instance()->iManagerEntry != NULL)
+ {
+ if(CMSvSearchSortCacheManager::Instance()->iManagerEntry->Count()>0)
+ {
+ for(TInt ii =0; ii < aSelection.Count() ; ii ++)
+ {
+ CMsvSearchSortDeltaCache::Instance()->EntryInDeltaCache(aSelection[ii],aType);
+ }
+ }
+ }
+
+ CleanupStack::PopAndDestroy(); //children
+ }
+
+
+
+/**
+ * BeginTransaction()
+ *
+ * Starts a new DB transaction.
+ */
+void CMsvIndexAdapter::BeginTransaction()
+ {
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->BeginTransactionL());
+ }
+ }
+
+
+
+/**
+ * CommitTransaction()
+ *
+ * Commits an already opened transaction.
+ */
+void CMsvIndexAdapter::CommitTransaction()
+ {
+ if(iDbAdapter)
+ {
+ TRAP_IGNORE(iDbAdapter->CommitTransactionL());
+ }
+ }
+
+
+
+/**
+ * DoRemoveDeletedEntriesL()
+ *
+ * Deletes all the entries whose PcSyncCount is 0 and delete flag is set.
+ */
+TBool CMsvIndexAdapter::DoRemoveDeletedEntriesL()
+ {
+ CMsvCacheEntry* parent = NULL;
+ CMsvCacheEntry* entry = NULL;
+ CMsvCacheEntry* siblingEntry = NULL;
+ TMsvId siblingId = KMsvNullIndexEntryId;
+ TMsvId visibleFolder = KMsvNullIndexEntryId;
+ TMsvId firstchildId = KMsvNullIndexEntryId;
+ TInt commitCount = 1;
+
+ // Find deleted folder
+ FindEntryL(KMsvDeletedEntryFolderEntryId, parent, ETrue);
+
+ CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+
+ // All deleted entries are a child of deleted folder
+ if(iDbAdapter->GetFirstChildIdL(parent->Entry().Id(),firstchildId))
+ {
+ iDbAdapter->GetEntryL(firstchildId, entry, visibleFolder);
+ }
+
+ while(entry && commitCount > 0)
+ {
+ if (entry->Entry().PcSyncCount() <= 0)
+ {
+ // Add entry to list of things to be deleted
+ __ASSERT_DEBUG(entry->Entry().Deleted(), PanicServer(EMsvDeletedFlagNotSet));
+
+ User::LeaveIfError(LockEntryAndStore(entry->Entry().Id()));
+ selection->AppendL(entry->Entry().Id());
+ // Will the next entry be deleted?
+ if(iDbAdapter->GetNextSiblingL(entry->Entry().Id(), parent->Entry().Id(), siblingId))
+ {
+ iDbAdapter->GetEntryL(siblingId, siblingEntry, visibleFolder);
+ if(siblingEntry->Entry().PcSyncCount() > 0)
+ {
+ commitCount--;
+ }
+ }
+ else
+ break;
+ }
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(entry);
+ entry = siblingEntry;
+ }
+
+ if (selection->Count() > 0)
+ {
+ User::LeaveIfError(DeleteSelection(*selection));
+ }
+ CleanupStack::PopAndDestroy(); // selection
+
+ // Possibly more to delete if we did not get to the end of the child list
+ TBool retVal = entry != NULL;
+ iFreePoolInstance->ReleaseEntryWithoutTransaction(entry);
+ return retVal;
+ }
+
+
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+/**
+ * GetChildrenAllL()
+ *
+ * Code added for PREQ 557.
+ *
+ * The function is similar to function GetChildrenL(), but
+ * additionally it fetches entries from all the drive in the
+ * preferred drive list.
+ */
+void CMsvIndexAdapter::GetChildrenAllL(TMsvId aId, CArrayPtr<const TMsvEntry>& aSelection, const TMsvSelectionOrdering& aOrdering, TUid aMtm, TBool aFilterByOwnerId, TSecureId aOwnerId)
+ {
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
+ for(TInt index=0; index<driveList->Count(); ++index)
+ {
+ driveEntry = (*driveList)[index];
+ if(EMsvMessageStoreAvailableStatus == driveEntry.status)
+ {
+ GetChildrenL(MaskTMsvId(driveEntry.driveId, aId), aSelection, aOrdering, aMtm, aFilterByOwnerId, aOwnerId);
+ }
+ }
+ }
+
+
+
+
+/**
+ * GetChildrenIdAll()
+ *
+ * Code added for PREQ 557.
+ *
+ * The function is similar to function GetChildrenId(), but
+ * additionally it fetches entries from all the drive in the
+ * preferred drive list.
+ */
+TInt CMsvIndexAdapter::GetChildrenIdAll(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection)
+ {
+ TSecureId dummy = KMsvServerId.iId;
+ return GetChildrenIdAll(aId, aFilter, aSelection, EFalse, dummy);
+ }
+
+
+
+// Overloaded.
+TInt CMsvIndexAdapter::GetChildrenIdAll(TMsvId aId, const CMsvEntryFilter& aFilter, CMsvEntrySelection& aSelection, TBool aFilterByOwnerId, TSecureId aOwnerId)
+ {
+ TInt err = KErrNone;
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
+ for(TInt index=0; index<driveList->Count(); ++index)
+ {
+ driveEntry = (*driveList)[index];
+ if(EMsvMessageStoreAvailableStatus == driveEntry.status)
+ {
+ err = GetChildrenId(MaskTMsvId(driveEntry.driveId, aId), aFilter, aSelection, aFilterByOwnerId, aOwnerId);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+ }
+ }
+ return KErrNone;
+ }
+
+
+
+/**
+ * RemoveDriveL()
+ *
+ * This function is added in PREQ 557.
+ * @param TUint: The drive priority, which is also the index of drive
+ * entry in message server data structure.
+ * @param TBool: If the drive still remains in the preferred drive list.
+ * @return None.
+ *
+ */
+void CMsvIndexAdapter::RemoveDriveL(TUint aDriveId, TUint aDriveIndex, TBool aIsStdFolderVisible /*=ETrue */)
+ {
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+
+ // Browse through the folder list.
+ dqIter.SetToFirst();
+ while ((folderNode = dqIter++) != NULL)
+ {
+ // If the folder is from the same drive.
+ // Caution: If the current drive is removed,
+ // this will also include root and localService.
+ if(folderNode->GetDrive() == aDriveId)
+ {
+ folderNode->iDlink.Deque();
+ delete folderNode;
+ }
+ } // while ((folderNode = dqIter++) != NULL)
+
+ // If current drive is removed,
+ // Remove localService entry as well.
+
+ // Detach the database and remove maxId entry.
+ if(!aIsStdFolderVisible)
+ {
+ iDbAdapter->DetachDBL(aDriveId);
+ iMaxMsvIdList[aDriveId] = NULL;
+
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aDriveIndex, KMsvInvalidDriveId);
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvDriveDiskNotAvailableStatus);
+ }
+ }
+
+
+
+
+
+/**
+ * AddDriveL()
+ *
+ * This function is added in PREQ 557.
+ * @param TUint: The drive priority, which is also the index of drive
+ * entry in message server data structure.
+ *
+ */
+void CMsvIndexAdapter::AddDriveL(TUint aDrivePriority)
+ {
+ // Assign a new drive id.
+ TUint driveId = GetNextAvailableDriveId();
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aDrivePriority, driveId);
+
+ // Attach the database.
+ TMsvId maxId;
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList::GetDriveList()->DriveInfoL(aDrivePriority, driveEntry);
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ TRAPD(err, iDbAdapter->AttachDBL(driveEntry.driveNum, driveId, maxId, &iServer.MessageDBAdapter()));
+#else
+ TRAPD(err, iDbAdapter->AttachDBL(driveEntry.driveNum, driveId, maxId));
+#endif
+ WrapDBErrorL(err);
+
+ // Insert the max Id in the list.
+ iMaxMsvIdList[driveId] = ((maxId >= MaskTMsvId(driveId, KFirstFreeEntryId))? (maxId+1) : MaskTMsvId(driveId, KFirstFreeEntryId));
+ }
+
+
+
+
+/**
+ * ChangeDriveL()
+ *
+ * This function is added in PREQ 557.
+ * @param TUint: The drive priority, which is also the index of drive
+ * entry in message server data structure.
+ * @param TBool: If the previous drive still remains in the preferred drive list.
+ * @return None.
+ *
+ */
+void CMsvIndexAdapter::ChangeDriveL(TUint aNewDriveIndex, TBool aIsStdFolderVisible /*= ETrue*/)
+ {
+ // Rule1: Remove all non-standard folder node of current drive.
+ TInt oldCurrentDriveIndex = CMsvPreferredDriveList::GetDriveList()->CurrentDriveIndex();
+ RemoveDriveL(KCurrentDriveId, oldCurrentDriveIndex, EFalse);
+
+ // If old drive should be visible, re-attach the drive.
+ // This assigns a new drive id to the old current drive.
+ if(aIsStdFolderVisible)
+ {
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(oldCurrentDriveIndex, EMsvMessageStoreAvailableStatus);
+ AddDriveL(oldCurrentDriveIndex);
+ }
+
+
+ // Clear search sort cache db table
+ TRAPD(err, GetDbAdapter()->ClearDBContentsL());
+ WrapDBErrorL(err);
+
+
+ // 3. Flush up entries from new current drive,
+ // if it is already attached.
+
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList::GetDriveList()->DriveInfoL(aNewDriveIndex, driveEntry);
+ if(KMsvInvalidDriveId != driveEntry.driveId)
+ {
+ RemoveDriveL(driveEntry.driveId, aNewDriveIndex, EFalse);
+ }
+
+
+ // Assign a new drive Id to the drive.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aNewDriveIndex, KCurrentDriveId);
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aNewDriveIndex, EMsvMessageStoreAvailableStatus);
+
+
+ // Assign a new drive Id to the drive.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveIdL(aNewDriveIndex, KCurrentDriveId);
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aNewDriveIndex, EMsvMessageStoreAvailableStatus);
+ // --------- Attach the database and update MaxId.
+ TMsvId maxId;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ TRAP(err, iDbAdapter->AttachDBL(driveEntry.driveNum, KCurrentDriveId, maxId, &iServer.MessageDBAdapter()));
+#else
+ TRAP(err, iDbAdapter->AttachDBL(driveEntry.driveNum, KCurrentDriveId, maxId));
+#endif
+ WrapDBErrorL(err);
+
+ // Insert the max Id in the list.
+ iMaxMsvIdList[KCurrentDriveId] = ((maxId >= MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId))? (maxId+1) : MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId));
+
+
+ // ------- Create a root node and its children.
+ TMsvId folderId = MaskTMsvId(KCurrentDriveId, KMsvRootIndexEntryId);
+
+ // Add local service folder node in the folder list.
+ iRootNode = CMsvCacheVisibleFolder::NewL(folderId);
+ iFolderListHeader.AddFirst(*iRootNode);
+
+ // Fetch children of root folder to cache.
+ RPointerArray<CMsvCacheEntry> childEntryList;
+ CleanupClosePushL(childEntryList);
+
+ TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
+ WrapDBErrorL(err);
+ iRootNode->AddEntryListL(childEntryList, ETrue);
+ childEntryList.Reset();
+
+
+ // ------- Create a local service node and its children.
+ folderId = MaskTMsvId(KCurrentDriveId, KMsvLocalServiceIndexEntryId);
+
+ // Add local service folder node in the folder list.
+ CMsvCacheVisibleFolder* localServiceFolder = CMsvCacheVisibleFolder::NewL(folderId);
+ iFolderListHeader.AddFirst(*localServiceFolder);
+
+ TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
+ WrapDBErrorL(err);
+ localServiceFolder->AddEntryListL(childEntryList, ETrue);
+
+ CleanupStack::PopAndDestroy(); // childEntryList.
+ }
+
+
+
+/**
+ * GetNextAvailableDriveId()
+ *
+ * This function is added in PREQ 557.
+ * @param None:
+ * @return TUint: The next available drive Id.
+ *
+ */
+TUint CMsvIndexAdapter::GetNextAvailableDriveId()
+ {
+ TMsvPreferredDrive driveEntry;
+ TUint driveId = iFirstFreeDriveId;
+ for(TUint index=0; index<8; index++)
+ {
+ TBool driveIdFound = EFalse;
+ CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
+ for(TInt index=0; index<driveList->Count(); ++index)
+ {
+ driveEntry = (*driveList)[index];
+ if(driveId == driveEntry.driveId)
+ {
+ driveIdFound = ETrue;
+ break;
+ }
+ }
+ if(EFalse == driveIdFound)
+ {
+ iFirstFreeDriveId = ((driveId)%7 ? (driveId+1) : 2);
+ return driveId;
+ }
+ driveId = ((driveId)%7 ? (driveId+1) : 2);
+ }
+ return KErrNone;
+ }
+
+
+
+/**
+ * ReloadCacheL()
+ *
+ * This function is used by backup and restore functionality
+ * when it finds that DB being restored is changed. The function
+ * destroys the cache of the current drive and recreates it.
+ */
+void CMsvIndexAdapter::ReloadCacheL()
+ {
+ TUint currDriveIndex = CMsvPreferredDriveList::GetDriveList()->CurrentDriveIndex();
+ TDriveNumber currDriveNum = CMsvPreferredDriveList::GetDriveList()->CurrentDriveNumber();
+
+ // Attach the database.
+ TMsvId maxId;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+ TRAPD(err, iDbAdapter->AttachDBL(currDriveNum, KCurrentDriveId, maxId, &iServer.MessageDBAdapter()));
+#else
+ TRAPD(err, iDbAdapter->AttachDBL(currDriveNum, KCurrentDriveId, maxId));
+#endif
+ WrapDBErrorL(err);
+
+ // Update the entry in drive list.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(currDriveIndex, EMsvMessageStoreAvailableStatus);
+
+ // Insert the max Id in the list.
+ iMaxMsvIdList[KCurrentDriveId] = ((maxId >= MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId))? (maxId+1) : MaskTMsvId(KCurrentDriveId, KFirstFreeEntryId));
+
+ TMsvId folderId = MaskTMsvId(KCurrentDriveId, KMsvRootIndexEntryId);
+
+ // Add local service folder node in the folder list.
+ iRootNode = CMsvCacheVisibleFolder::NewL(folderId);
+ iFolderListHeader.AddFirst(*iRootNode);
+
+ // Fetch children of root folder to cache.
+ RPointerArray<CMsvCacheEntry> childEntryList;
+ CleanupClosePushL(childEntryList);
+
+ // Updating children under root node.
+ TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
+ WrapDBErrorL(err);
+ iRootNode->AddEntryListL(childEntryList, ETrue);
+ childEntryList.Reset();
+
+ // Create a local service node and its children.
+ folderId = MaskTMsvId(KCurrentDriveId, KMsvLocalServiceIndexEntryId);
+
+ // Add local service folder node in the folder list.
+ CMsvCacheVisibleFolder* localServiceFolder = CMsvCacheVisibleFolder::NewL(folderId);
+ iFolderListHeader.AddFirst(*localServiceFolder);
+
+ // Fetch children of localService folder to cache.
+ TRAP(err, iDbAdapter->GetChildrenL(folderId, childEntryList));
+ WrapDBErrorL(err);
+ localServiceFolder->AddEntryListL(childEntryList, ETrue);
+
+ CleanupStack::PopAndDestroy(); // childEntryList.
+ }
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+#ifdef _DEBUG
+void CMsvIndexAdapter::PrintL()
+ {
+ _LIT8(KFolderId, "FOLDER ID: ");
+ _LIT8(KDriveId, " DRIVE ID: ");
+ _LIT8(KComplete, " COMPLETE FLAG: ");
+ _LIT8(KFalse, "FALSE.");
+ _LIT8(KTrue, "TRUE.");
+
+ RFileLogger logger;
+ CleanupClosePushL(logger);
+ if (logger.Connect() == KErrNone)
+ {
+ logger.CreateLog(_L("msgs"), _L("Cache.txt"), EFileLoggingModeAppend);
+ logger.SetDateAndTime(EFalse, EFalse);
+ logger.Write(_L(" Message Index Cache Structure."));
+ logger.Write(_L("--------------------------------"));
+ logger.Write(_L(""));
+ }
+
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(iFolderListHeader);
+
+ dqIter.SetToFirst();
+ while((folderNode = dqIter++)!=NULL)
+ {
+ RBuf8 text;
+ CleanupClosePushL(text);
+ text.CreateL(100);
+ text.Append(KFolderId);
+ text.AppendNum(folderNode->GetFolderId());
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ text.Append(KDriveId);
+ text.AppendNum(folderNode->GetDrive());
+#endif
+ text.Append(KComplete);
+ if(folderNode->IsComplete())
+ {
+ text.Append(KTrue);
+ }
+ else
+ {
+ text.Append(KFalse);
+ }
+ logger.Write(text);
+ CleanupStack::PopAndDestroy(); // text
+ folderNode->Print(logger);
+ logger.Write(_L(""));
+ }
+ logger.CloseLog();
+ CleanupStack::PopAndDestroy(); // logger
+ }
+#endif // #ifdef _DEBUG
+#endif // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+