--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/indexcontext.cpp Fri Jun 04 10:32:16 2010 +0100
@@ -0,0 +1,1085 @@
+// Copyright (c) 1999-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
+
+
+
+#include <s32file.h>
+#include <bautils.h>
+#include <barsc.h>
+
+#include <msgs.rsg>
+
+#include "indexcontext.h"
+#include "MSVSERV.H"
+#include "MSVUTILS.H"
+#include "MSVRBLD.H"
+
+// will this header be expoerted to epoc\include
+#include <sqldb.h>
+#include "msvindexadapter.h"
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ _LIT(KDBFileName,"\\messaging.db");
+#else
+ _LIT(KDBFileName,"[1000484B]messaging.db");
+#endif
+
+_LIT(KServerResourceFile,"\\resource\\messaging\\msgs.rsc");
+
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ _LIT(KStoreDeletedFile,"\\private\\1000484b\\storedeleted.tmp");
+#else
+ _LIT(KStoreDeletedFile,"storedeleted.tmp");
+#endif
+
+const TInt KMsvInitDelayTime = 0x00000001; // as soon as possible
+const TUid KUidMsvIndexFile = {0x10003C6B};
+extern const TInt KMsvIndexStoreVersionNumber = 1; // See MsvIndex.cpp
+//**********************************
+// CMsvIndexContext
+//**********************************
+
+CMsvIndexContext* CMsvIndexContext::NewL(CMsvServer& aServer, MMsvContextObserver& aObserver)
+ {
+ CMsvIndexContext* self = CMsvIndexContext::NewLC(aServer, aObserver);
+ CleanupStack::Pop();
+ return self;
+ }
+
+CMsvIndexContext* CMsvIndexContext::NewLC(CMsvServer& aServer, MMsvContextObserver& aObserver)
+ {
+ CMsvIndexContext* self = new(ELeave)CMsvIndexContext(aServer, aObserver);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+void CMsvIndexContext::ConstructL()
+ {
+ iUpdateEntryStreams = new(ELeave)CMsvEntrySelection;
+ iRemoveEntries = new(ELeave)CMsvEntrySelection;
+
+ TFileName fileName(KServerResourceFile);
+ MsvUtils::AddPathAndExtensionToResFileL(fileName);
+ BaflUtils::NearestLanguageFile(iServer.FileSession(), fileName);
+
+ // Load the initial index structure from resource file
+ RResourceFile resource;
+ resource.OpenL(iServer.FileSession(), fileName);
+ CleanupClosePushL(resource);
+
+ // Get ready to read resource
+
+ iBuf = resource.AllocReadL(R_SERVER_INDEX_STARTUP);
+
+ CleanupStack::PopAndDestroy(); //resource
+
+ }
+
+CMsvIndexContext::~CMsvIndexContext()
+ {
+ Cancel();
+ delete iBuf;
+ delete iIndexAdapter;
+ delete iUpdateEntryStreams;
+ delete iRemoveEntries;
+ }
+
+CMsvIndexContext::CMsvIndexContext(CMsvServer& aServer, MMsvContextObserver& aObserver)
+: CActive(EPriorityStandard), iServer(aServer), iObserver(aObserver)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+
+
+// CODE USED AFTER PREQ 557.
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+/**
+ * CreateIndex()
+ *
+ * Code added for PREQ 557.
+ */
+void CMsvIndexContext::CreateIndexL()
+ {
+ __ASSERT_DEBUG(iProgress.iState == TMsvIndexLoadProgress::EIndexNotLoaded, PanicServer(EMsvBadIndexState));
+
+ DoCreateIndexL();
+ IndexLoadingCompleted();
+ }
+
+
+
+void CMsvIndexContext::IndexLoadingCompleted()
+ {
+ iProgress.iError = KErrNone;
+
+ IndexLoaded(EMsvNullNotification);
+
+ // Tell the observer that we've finshed
+ iObserver.ContextComplete(KErrNone, iRunMailInit);
+ }
+
+
+
+
+/**
+ * DoCreateIndexL()
+ *
+ * Create the index adapter object.
+ * Code added in PREQ 557.
+ */
+void CMsvIndexContext::DoCreateIndexL()
+ {
+ // Remember stuff
+ iObserverStatus = NULL;
+ iRunMailInit = EFalse;
+
+ // Update drive status in preferred drive list.
+ TDriveState driveStatus = EMsvInvalidDriveStatus;
+ for(TUint index=0; index<CMsvPreferredDriveList::GetDriveList()->Count(); index++)
+ {
+ UpdateDriveStatusL(index, driveStatus);
+ }
+
+ // Look for the current drive.
+ // The first drive in the preferred drive list, whose
+ // status is either EMsvMessageStoreAvailable or
+ // EMsvMessageStoreUnavailable will be the current drive.
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList *driveList = CMsvPreferredDriveList::GetDriveList();
+ for(TInt currentDriveIndex=0; currentDriveIndex<driveList->Count(); ++currentDriveIndex)
+ {
+ driveEntry = (*driveList)[currentDriveIndex];
+ if( (EMsvMessageStoreAvailableStatus == driveEntry.status) ||
+ (EMsvMessageStoreUnavailableStatus == driveEntry.status)
+ )
+ {
+ // Set the current drive index to server.
+ CMsvPreferredDriveList::GetDriveList()->SetCurrentDriveIndex(currentDriveIndex);
+
+ TParse parse;
+ TPtrC drive(TDriveUnit(driveEntry.driveNum).Name());
+ parse.Set(KMsvDefaultIndexFile2(), &drive, NULL);
+ iMessageFolder = parse.DriveAndPath();
+
+ // If the drive already has a message store...
+ if(EMsvMessageStoreUnavailableStatus == driveEntry.status)
+ {
+ // Create the database and all standard table.
+ CMsvDBAdapter::CreateDBL(driveEntry.driveNum);
+
+ // Update the drive status.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(currentDriveIndex, EMsvMessageStoreAvailableStatus);
+
+ ResetAndCreateNewMailStoreL();
+ iRunMailInit = ETrue;
+
+ // Creating index adapter object.
+ iIndexAdapter = CMsvIndexAdapter::NewL(iServer);
+
+ // Get updated drive id.
+ CreateStandardEntriesFromResourceFileL(KCurrentDriveId);
+ iIndexAdapter->SetLocalServiceComplete();
+ }
+ else
+ {
+ // The drive already has a message store.
+
+ // Creating index adapter object.
+ iIndexAdapter = CMsvIndexAdapter::NewL(iServer);
+
+ ResetAndCreateNewMailStoreL(EFalse);
+ }
+ break;
+ }
+ }
+ }
+
+
+
+
+/**
+ * UpdateDriveStatusL()
+ * @param TUint: The index of the said drive in preferred
+ * drive list.
+ */
+void CMsvIndexContext::UpdateDriveStatusL(TUint aDriveIndex, TDriveState& aStoreStatus)
+ {
+ aStoreStatus = EMsvInvalidDriveStatus;
+ TBool deleteStore = EFalse;
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList::GetDriveList()->DriveInfoL(aDriveIndex, driveEntry);
+
+ // Check if the media is available in the drive.
+ TVolumeInfo volume;
+ if (iServer.FileSession().Volume(volume, driveEntry.driveNum) != KErrNone)
+ {
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvDriveDiskNotAvailableStatus);
+ aStoreStatus = EMsvDriveDiskNotAvailableStatus;
+ return;
+ }
+
+ // Validate the database. The function opens the database
+ // and check its version and returns appropriate error.
+ TRAPD(err, CMsvDBAdapter::ValidateDatabaseL(driveEntry.driveNum));
+
+ // If no error, database is available.
+ if(KErrNone == err)
+ {
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvMessageStoreAvailableStatus);
+ return;
+ }
+
+ // If the database is not found in the drive.
+ if(KErrNotFound == err)
+ {
+ // Check if index file exists.
+ RFile file;
+ TParse parse;
+ TPtrC drive(TDriveUnit(driveEntry.driveNum).Name());
+ parse.Set(KMsvDefaultIndexFile2, &drive, NULL);
+ TFileName indexFileName = parse.FullName();
+ err = file.Open(iServer.FileSession(), indexFileName, EFileShareAny|EFileWrite);
+ //file.Close();
+
+ // If index file exists, set drive status to NOT SUPPORTED.
+ if(KErrNone == err)
+ {
+ CPermanentFileStore* fileStoreIndex = NULL;
+ TRAPD(permError, fileStoreIndex = CPermanentFileStore::FromL(file));
+ if(KErrNone == permError)
+ {
+ // Check if the store is corrupt. If so then delete it.
+ if (fileStoreIndex->Type() != TUidType(KPermanentFileStoreLayoutUid, KUidMsvIndexFile))
+ {
+ deleteStore = ETrue;
+ }
+ }
+ // There was an error in getting a permanent filestore object.
+ // Mark the message store for deletion.
+ else
+ {
+ deleteStore = ETrue;
+ }
+
+ delete fileStoreIndex;
+
+ //If message store is corrupted, wipe it.
+ if(deleteStore)
+ {
+ TFileName mail2Folder = parse.DriveAndPath();
+ CFileMan* fileMan = CFileMan::NewL(iServer.FileSession());
+ // Remove the readonly attribute..
+ (void)fileMan->Attribs(mail2Folder, 0, KEntryAttReadOnly, TTime(0), CFileMan::ERecurse);
+ CleanupStack::PushL(fileMan);
+ //Check if the mailfolder exists..
+ TBool mail2FolderExists = BaflUtils::FileExists(iServer.FileSession(), mail2Folder);
+ if(mail2FolderExists)
+ {
+ // Remove old message store if exists..
+ User::LeaveIfError(fileMan->RmDir(mail2Folder));
+ }
+ CleanupStack::PopAndDestroy(fileMan);
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvMessageStoreUnavailableStatus);
+ aStoreStatus = EMsvMessageStoreCorruptStatus;
+
+ // Create store delete file in the respective drive.
+ CreateStoreDeleteFile(driveEntry.driveNum);
+ }
+ //Else only set status as EMsvMessageStoreNotSupportedStatus.
+ else
+ {
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvMessageStoreNotSupportedStatus);
+ aStoreStatus = EMsvMessageStoreNotSupportedStatus;
+ }
+
+ file.Close();
+ return;
+ }
+
+ // If index file does not exists, set drive status to STORE UNAVAILABLE.
+ if((KErrNotFound == err) || (KErrPathNotFound == err))
+ {
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvMessageStoreUnavailableStatus);
+ aStoreStatus = EMsvMessageStoreUnavailableStatus;
+ return;
+ }
+
+ User::Leave(err);
+ }
+
+ //If a database exists, but is corrupt.
+ if( (KSqlErrCorrupt == err) ||
+ (KSqlErrNotDb == err)
+ )
+ {
+ // If the database is corrupt, delete
+ // the database and old message store.
+
+ // Delete the database.
+ TParse parse;
+ TPtrC drive(TDriveUnit(driveEntry.driveNum).Name());
+ parse.Set(KDBFileName, &drive, NULL);
+ TFileName dBFile = parse.FullName();
+ RSqlDatabase::Delete(dBFile);
+
+ // Delete the message store. //ISSUE Can we use ResetAndCreateNewMailStore()?
+ parse.Set(KMsvDefaultIndexFile2, &drive, NULL);
+ TFileName mail2Folder = parse.DriveAndPath();
+ CFileMan* fileMan = CFileMan::NewL(iServer.FileSession());
+ // Remove the readonly attribute..
+ (void)fileMan->Attribs(mail2Folder, 0, KEntryAttReadOnly, TTime(0), CFileMan::ERecurse);
+ CleanupStack::PushL(fileMan);
+ //Check if the mailfolder exists..
+ TBool mail2FolderExists = BaflUtils::FileExists(iServer.FileSession(), mail2Folder);
+ if( mail2FolderExists)
+ {
+ // Remove old message store if exists..
+ User::LeaveIfError(fileMan->RmDir(mail2Folder));
+ }
+ CleanupStack::PopAndDestroy(fileMan);
+
+ // Update the drive status.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvMessageStoreUnavailableStatus);
+ aStoreStatus = EMsvMessageStoreCorruptStatus;
+
+ // Create store delete file in the respective drive.
+ CreateStoreDeleteFile(driveEntry.driveNum);
+ return;
+ }
+
+ //If the database version is not supported.
+ if(KErrNotSupported == err)
+ {
+ // If the drive as old version of database.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aDriveIndex, EMsvMessageStoreNotSupportedStatus);
+ aStoreStatus = EMsvMessageStoreNotSupportedStatus;
+ return;
+ }
+
+ // Do not return DB error.
+ if(err <= KSqlErrGeneral)
+ {
+ // If DB Error, return KErrGeneral.
+ User::LeaveIfError(KErrGeneral);
+ }
+ else
+ {
+ User::LeaveIfError(err);
+ }
+ }
+
+
+
+
+TInt CMsvIndexContext::ChangeDrive(TUint aNewDriveIndex, TRequestStatus& aStatus)
+ {
+ TInt err = ChangeDrive(aNewDriveIndex, ETrue, ETrue);
+
+ // Remember the status which we'll complete
+ aStatus = KRequestPending;
+ iObserverStatus = &aStatus;
+ return err;
+ }
+
+
+
+void CMsvIndexContext::ChangeDriveCompleted(TInt aError)
+ {
+ // Remember error
+ iProgress.iError = aError;
+
+ if (iObserverStatus)
+ {
+ User::RequestComplete(iObserverStatus, aError);
+ }
+ }
+
+
+
+/**
+ * ChangeDriveL()
+ * @param TUint: Index of the new current drive in the preferred drive list.
+ * @param TBool: True, if old drive is still present in the preferred drive list.
+ * False, otherwise.
+ *
+ */
+TInt CMsvIndexContext::ChangeDrive(TUint aNewDriveIndex, TBool aIsRemovePartial /*= ETrue*/, TBool aAsync /*=EFalse */)
+ {
+ TDriveNumber newDriveNumber;
+ TRAPD(err, DoChangeDriveL(aNewDriveIndex, aIsRemovePartial, newDriveNumber));
+
+ // Add a function ChangeDriveComplete() in server
+ // which should be called here. The function should
+ // run mailInit and recreate backup object.
+ iObserver.ChangeDriveComplete(err, iRunMailInit, newDriveNumber);
+
+ if(aAsync)
+ {
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus* st = &iStatus;
+ User::RequestComplete(st, err);
+ }
+ return err;
+ }
+
+
+
+void CMsvIndexContext::DoChangeDriveL(TUint aNewDriveIndex, TBool aIsRemovePartial, TDriveNumber& aNewDriveNumber)
+ {
+ iObserverStatus = NULL;
+ TMsvPreferredDrive driveEntry;
+ CMsvPreferredDriveList::GetDriveList()->DriveInfoL(aNewDriveIndex, driveEntry);
+
+ aNewDriveNumber = driveEntry.driveNum;
+ if(EMsvMessageStoreUnavailableStatus == driveEntry.status)
+ {
+ // Create the database and all standard table.
+ CMsvDBAdapter::CreateDBL(driveEntry.driveNum);
+
+ // Update the drive status.
+ CMsvPreferredDriveList::GetDriveList()->UpdateDriveStatusL(aNewDriveIndex, EMsvMessageStoreAvailableStatus);
+
+ TParse parse;
+ TPtrC drive(TDriveUnit(driveEntry.driveNum).Name());
+ parse.Set(KMsvDefaultIndexFile2(), &drive, NULL);
+ iMessageFolder = parse.DriveAndPath();
+
+ ResetAndCreateNewMailStoreL();
+ iRunMailInit = ETrue;
+
+ // Perform ChangeDrive operation.
+ iIndexAdapter->ChangeDriveL(aNewDriveIndex, aIsRemovePartial);
+
+ // Read initial entries from resources
+ CreateStandardEntriesFromResourceFileL(KCurrentDriveId);
+ iIndexAdapter->SetLocalServiceComplete();
+ }
+ else
+ {
+ // Update the message folder local variable.
+ TParse parse;
+ TPtrC drive(TDriveUnit(driveEntry.driveNum).Name());
+ parse.Set(KMsvDefaultIndexFile2(), &drive, NULL);
+ iMessageFolder = parse.DriveAndPath();
+
+ ResetAndCreateNewMailStoreL(EFalse);
+ // Perform ChangeDrive operation.
+ iIndexAdapter->ChangeDriveL(aNewDriveIndex, aIsRemovePartial);
+ iRunMailInit = EFalse;
+ }
+
+ // Create service directories in new drive.
+ TRAP_IGNORE(DoCreateServiceDirsL(KCurrentDriveId));
+
+ TRAP_IGNORE(LocalizeStandardFoldersL());
+ }
+
+
+
+
+void CMsvIndexContext::GetInPreparationIds(TUint aDriveId)
+ {
+ delete iRemoveEntries;
+ iRemoveEntries = new CMsvEntrySelection;
+
+ iIndexAdapter->GetInPreparationIds(*iRemoveEntries, aDriveId);
+ }
+
+
+
+
+/**
+ * CreateStandardEntriesFromResourceFileL()
+ * @param None:
+ *
+ * Will read messaging resource file and create entries.
+ */
+void CMsvIndexContext::CreateStandardEntriesFromResourceFileL(TUint aDriveId)
+ {
+ // Read initial entries from resources
+ TResourceReader reader;
+ reader.SetBuffer(iBuf);
+ const TInt numberOfEntries = reader.ReadInt16();
+
+ for (TInt index=0; index < numberOfEntries; ++index)
+ {
+ TMsvEntry newEntry;
+
+ // Values from resource file
+ newEntry.iId = MaskTMsvId(aDriveId, reader.ReadInt32());
+ newEntry.iParentId = reader.ReadInt32();
+ newEntry.iServiceId = reader.ReadInt32();
+ newEntry.iType.iUid = reader.ReadInt32();
+ newEntry.iMtm.iUid = reader.ReadInt32();
+ newEntry.iData = reader.ReadInt32();
+ newEntry.iDescription.Set(reader.ReadTPtrC());
+ newEntry.iDetails.Set(reader.ReadTPtrC());
+ newEntry.iDate.UniversalTime();
+ newEntry.iSize=0;
+
+ // Create the new entry.
+ // This is required to create associated service directory.
+ User::LeaveIfError(iServer.AddEntry(this, newEntry, KMsvServerId, EFalse));
+ }
+ }
+
+#else // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+
+void CMsvIndexContext::CreateIndexL(TInt aDrive, TRequestStatus& aStatus)
+ {
+ // Kick off index loading
+ CreateIndexL(aDrive, EFalse);
+ // Remember the status which we'll complete
+ aStatus = KRequestPending;
+ iObserverStatus = &aStatus;
+ }
+
+
+
+void CMsvIndexContext::CreateIndexL(TInt aDrive, TBool aSync)
+ {
+ __ASSERT_DEBUG(iProgress.iState == TMsvIndexLoadProgress::EIndexNotLoaded, PanicServer(EMsvBadIndexState));
+ __ASSERT_DEBUG(RFs::IsValidDrive(aDrive), PanicServer(EMsvInvalidDrive));
+
+ // Remember stuff
+ iConfig.iDrive = TDriveUnit(aDrive);
+ iObserverStatus = NULL;
+ iRunMailInit = EFalse;
+
+ // Set the drive for this index file
+ TParse parse;
+ TPtrC drive(iConfig.iDrive.Name());
+ parse.Set(KMsvDefaultIndexFile2(), &drive, NULL);
+
+ // Construct the message folder name etc
+ iMessageFolder = parse.DriveAndPath();
+ TFileName indexFileName = parse.FullName();
+ // Adding the new code
+ // Now we are creating the new database adapter.
+ // Find out if the db exists
+ // Construct the db file name
+ parse.Set(KDBFileName, &drive, NULL);
+ TFileName dBFile = parse.FullName();
+ RSqlDatabase db;
+ TRAPD(err,db.OpenL(dBFile));
+ TBool create=EFalse;
+
+ // Database may be corrupted, so delete the old database and create a new one.
+ if(err == KSqlErrCorrupt || err == KSqlErrNotDb )
+ {
+ RSqlDatabase::Delete(dBFile);
+ create = ETrue;
+ }
+ // Database is not present. We need to check if the store is an old one.
+ // If it is, we check if it is corrupt.
+ // If it is corrupt we can safely delete the store and create a new one
+ // in its place. If not, then we leave with KErrNotSupported stating that
+ // the old store is incompatible with this implementation of the message
+ // store which uses an SQL database for the index.
+ else if( err == KErrNotFound)
+ {
+ // Check if any of the old index files exist in the Mail2 folder.
+ TParse parse1;
+ parse1.Set(KMsvDefaultIndexFile, &drive, NULL); //old version of index file
+ if( BaflUtils::FileExists(iServer.FileSession(), parse1.FullName()) ||
+ BaflUtils::FileExists(iServer.FileSession(), indexFileName))
+ {
+ // Open index store.
+ RFile file;
+ TInt error = file.Open(iServer.FileSession(), indexFileName, EFileShareAny|EFileWrite);
+
+ // Check if we have an old 'legacy' version of the index file.
+ CPermanentFileStore* index = NULL;
+ TRAPD(permError, index = CPermanentFileStore::FromL(file));
+ CleanupStack::PushL(index);
+ if (KErrNone == permError)
+ {
+ // Check if the store is corrupt. If so then delete it.
+ if (index->Type() != TUidType(KPermanentFileStoreLayoutUid, KUidMsvIndexFile))
+ {
+ create = ETrue;
+ }
+ }
+ // There was an error in getting a permanent filestore object.
+ // Delete the message store.
+ else
+ {
+ create = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy(); //index
+ file.Close();
+
+ // If the old store is valid, then throw an error.
+ if(!create)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ }
+ //Index file does not exist in Mail2 folder. Go ahead with database creation.
+ else
+ {
+ create = ETrue;
+ }
+ }
+ else
+ {
+ db.Close();
+ User::LeaveIfError(err);
+ }
+
+ db.Close();
+
+ if(!create)
+ {
+ // Check for database version.
+ TRAP(err, CMsvDBAdapter::ValidateDatabaseL(dBFile));
+ User::LeaveIfError(err);
+
+ iIndexAdapter = CMsvIndexAdapter::OpenL(iServer, dBFile);
+ ResetAndCreateNewMailStoreL(EFalse);
+ }
+ else
+ {
+ iIndexAdapter = CMsvIndexAdapter::NewL(iServer, dBFile);
+ ResetAndCreateNewMailStoreL();
+ CreateStoreDeleteFile();
+ iRunMailInit = ETrue;
+
+ TResourceReader reader;
+ reader.SetBuffer(iBuf);
+ // Read initial entries from resources
+ const TInt numberOfEntries = reader.ReadInt16();
+ for (TInt index=0; index<numberOfEntries; ++index)
+ {
+ TMsvEntry newEntry;
+ // Values from resource file
+ newEntry.iId = reader.ReadInt32();
+ newEntry.iParentId = reader.ReadInt32();
+ newEntry.iServiceId = reader.ReadInt32();
+ newEntry.iType.iUid = reader.ReadInt32();
+ newEntry.iMtm.iUid = reader.ReadInt32();
+ newEntry.iData = reader.ReadInt32();
+ newEntry.iDescription.Set(reader.ReadTPtrC());
+ newEntry.iDetails.Set(reader.ReadTPtrC());
+ newEntry.iDate.UniversalTime();
+ newEntry.iSize=0;
+
+ // Create the new entry
+ // This is required to create associated service directory.
+ TInt error = iServer.AddEntry(this, newEntry, KMsvServerId, EFalse);
+ User::LeaveIfError(error);
+ }
+ iIndexAdapter->SetLocalServiceComplete();
+
+ }
+ if(aSync)
+ {
+ IndexLoadingCompleted(KErrNone);
+ }
+ else
+ {
+ iStatus = KRequestPending;
+ SetActive();
+ TRequestStatus* st = &iStatus;
+ User::RequestComplete(st, KErrNone);// do we need to propogate the error from adapter to here
+ }
+ }
+
+
+
+TInt CMsvIndexContext::LoadStoreConfig(TBool aLoad)
+//
+// In-between function to save the cost of a trap
+//
+ {
+ TRAPD(error, aLoad ? CMsvServer::CurrentConfigL(iServer.FileSession(), iConfig) : DoStoreConfigL());
+ return error;
+ }
+
+
+
+
+void CMsvIndexContext::DoStoreConfigL()
+ {
+ // we only want to store the config file if it has changed,
+ // we also don't care about UniqueIDs for the internal drive
+ if(iConfig.iDebug!=iConfig.iDebugAsLoaded ||
+ iConfig.iDrive!=iConfig.iDriveAsLoaded ||
+ (iConfig.iDrive!=iServer.FileSession().GetSystemDrive() && iConfig.iUniqueID!=iConfig.iUniqueIDAsLoaded))
+ {
+ TChar driveChar= iServer.FileSession().GetSystemDriveChar();
+ TBuf<2> systemDrive;
+ systemDrive.Append(driveChar);
+ systemDrive.Append(KDriveDelimiter);
+ TPath pathName(systemDrive);
+ pathName.Append(KServerINIFile);
+ CDictionaryFileStore *store=CDictionaryFileStore::OpenLC(iServer.FileSession(),pathName,KNullUid);
+ RDictionaryWriteStream stream;
+ stream.AssignLC(*store, KUidMsvMessageDriveStream);
+
+ stream.WriteUint8L(KMsvMessageDriveStreamVersionNumber); // version number
+ stream << iConfig.iDrive.Name();
+ stream.WriteUint32L(iConfig.iUniqueID);
+ stream.WriteInt8L(iConfig.iDebug);
+
+ stream.CommitL();
+ store->CommitL();
+ CleanupStack::PopAndDestroy(2,store); // stream, store
+ }
+ }
+
+
+
+void CMsvIndexContext::IndexLoadingCompleted(TInt aError)
+ {
+ // Remember error
+ iProgress.iError = aError;
+
+ // If there is no index at this point it's because the index loading is synchronous
+ if (!iIndexAdapter && !aError)
+ return;
+
+ // If there was an error, wipe the message folder and create a blank one
+ if (aError == KErrCorrupt || aError == KErrOverflow || aError == KErrNotFound || aError == KErrEof || aError == KErrNotSupported)
+ {
+#ifndef _NO_SERVER_LOGGING_
+ iServer.Log(_L("Index corrupted, starting rebuild (%d)"), aError);
+#endif
+ // Note: Following doesn't send any notifications
+ IndexFailedToLoad(KErrNone);
+
+ //Create a file to let the UI know that the store has been deleted.
+ CreateStoreDeleteFile();
+ }
+
+ // Get the drive Id
+ if (!aError)
+ {
+ TVolumeInfo volume;
+ aError = iServer.FileSession().Volume(volume, TInt(iConfig.iDrive));
+ if (!aError)
+ {
+ iConfig.iUniqueID = volume.iUniqueID;
+ }
+ }
+
+ // If we are not rebuilding, then inform clients of outcome
+ if (aError)
+ IndexFailedToLoad(aError);
+ else
+ IndexLoaded(EMsvNullNotification);
+
+ // Tell the observer that we've finshed
+ iObserver.ContextComplete(aError, iRunMailInit);
+
+ if (iObserverStatus)
+ User::RequestComplete(iObserverStatus, aError);
+ }
+
+
+
+void CMsvIndexContext::IndexFailedToLoad(TInt aError)
+//
+// The index has failed to load. Remove partially created in-memory index
+//
+ {
+ // Update progress
+ iProgress.iError = aError;
+ delete iIndexAdapter;
+ iIndexAdapter = NULL;
+ iProgress.iState = TMsvIndexLoadProgress::EIndexNotLoaded;
+ if (aError)
+ iServer.NotifyChanged(EMsvIndexFailedToLoad, KMsvNullIndexEntryId, aError);
+ }
+
+
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+
+
+
+void CMsvIndexContext::IndexLoaded(TMsvServerChangeNotificationType aNotification)
+//
+// The index has been successfully loaded
+//
+ {
+ iProgress.iState = TMsvIndexLoadProgress::EIndexComplete;
+ iProgress.iError = KErrNone;
+
+ // Remove any orphaned entries
+ __ASSERT_DEBUG(iRemoveEntries->Count()==0, PanicServer(EMsvRemovingOrphanedEntries));
+ iIndexAdapter->GetInPreparationIds(*iRemoveEntries);
+
+ // kick off the delay timer, this will allow the message server to make
+ // any changes it wants to the index on startup, currently it will
+ // remove any entries in iRemoveEntries and try and localize the standard folders.
+ if (!iServer.Delay().IsActive())
+ iServer.Delay().After(KMsvInitDelayTime);
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TRAP_IGNORE(DoCreateServiceDirsL(KCurrentDriveId));
+#else
+ TRAP_IGNORE(DoCreateServiceDirsL());
+#endif
+
+ // Queue notification - it will be sent before EMsvIndexLoaded
+ // when we can guarantee that index is fully loaded
+ if (aNotification != EMsvNullNotification)
+ iServer.QueueNotifyChanged(aNotification);
+ }
+
+void CMsvIndexContext::LocalizeStandardFoldersL()
+ {
+ // Get ready to read resource
+ TResourceReader reader;
+ reader.SetBuffer(iBuf);
+
+ // Read initial entries from resources
+ const TInt numberOfEntries = reader.ReadInt16();
+ for (TInt ii=0; ii<numberOfEntries; ii++)
+ {
+ TMsvEntry resourceEntry;
+
+ // Values from resource file
+ resourceEntry.iId = reader.ReadInt32();
+ resourceEntry.iParentId = reader.ReadInt32();
+ resourceEntry.iServiceId = reader.ReadInt32();
+ resourceEntry.iType.iUid = reader.ReadInt32();
+ resourceEntry.iMtm.iUid = reader.ReadInt32();
+ resourceEntry.iData = reader.ReadInt32();
+ resourceEntry.iDescription.Set(reader.ReadTPtrC());
+ resourceEntry.iDetails.Set(reader.ReadTPtrC());
+
+ // Add Universal time and initialise size
+ resourceEntry.iDate.UniversalTime();
+ resourceEntry.iSize=0;
+ TMsvEntry *entry;
+
+ // 557. Will by default pick entries from current drive.
+ TInt error = iIndexAdapter->GetEntry(resourceEntry.Id(),entry);
+ if(error ==KErrNone)
+ {
+ TMsvEntry newEntry= *entry;
+ TBool changed=EFalse;
+ if(newEntry.iDescription.Compare(resourceEntry.iDescription)!=0)
+ {
+ newEntry.iDescription.Set(resourceEntry.iDescription);
+ changed=ETrue;
+ }
+ if(newEntry.iDetails.Compare(resourceEntry.iDetails)!=0)
+ {
+ newEntry.iDetails.Set(resourceEntry.iDetails);
+ changed=ETrue;
+ }
+
+ // ignore the error we don't want to fail just because the
+ // inbox isn't in the right language, we will try again next
+ // time the server starts.
+ if(changed!=EFalse)
+ {
+ iIndexAdapter->LockEntry(newEntry.Id());
+ iIndexAdapter->ChangeEntryInternal(newEntry, KMsvServerId);
+ iIndexAdapter->ReleaseEntry(newEntry.Id());
+ }
+ }
+ else if( error == KErrNotFound )
+ {
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ resourceEntry.SetParent(MaskTMsvId(KCurrentDriveId, resourceEntry.iParentId));
+ resourceEntry.SetId(MaskTMsvId(KCurrentDriveId, resourceEntry.iId));
+#endif
+ // Create the new entry
+ iServer.AddEntry(this, resourceEntry, KMsvServerId, EFalse);
+ }
+ }
+ }
+
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+void CMsvIndexContext::DoCreateServiceDirsL(TUint aDriveId)
+#else
+void CMsvIndexContext::DoCreateServiceDirsL()
+#endif
+ {
+ CMsvEntryFilter* filter = CMsvEntryFilter::NewLC();
+ filter->SetOrder(TMsvSelectionOrdering(0, EMsvSortByNone, ETrue));
+
+ CMsvEntrySelection* selection = new(ELeave)CMsvEntrySelection;
+ CleanupStack::PushL(selection);
+ TInt err = KErrNone;
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ err = iIndexAdapter->GetChildrenId(MaskTMsvId(aDriveId, KMsvRootIndexEntryId), *filter, *selection);
+#else
+ err = iIndexAdapter->GetChildrenId(KMsvRootIndexEntryId, *filter, *selection);
+#endif
+
+ // make sure the service directories are there
+ if (err == KErrNone)
+ {
+ TInt count = selection->Count();
+ while (count--)
+ {
+ TFileName filename;
+ filename.Copy(iMessageFolder);
+
+ TMsvId id = selection->At(count);
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ MsvUtils::ConstructEntryName(UnmaskTMsvId(id), MaskTMsvId(aDriveId, id), filename, MsvUtils::EPath);
+#else
+ MsvUtils::ConstructEntryName(id, id, filename, MsvUtils::EPath);
+#endif
+
+ iServer.FileSession().MkDir(filename); // ignore any error
+ }
+ }
+
+ CleanupStack::PopAndDestroy(2); // selection, filter
+ }
+
+
+
+
+void CMsvIndexContext::DoCancel()
+ {
+ if (iIndexAdapter)
+ iIndexAdapter->Cancel();
+ if (iObserverStatus)
+ User::RequestComplete(iObserverStatus, KErrCancel);
+ }
+
+void CMsvIndexContext::RunL()
+ {
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ // In 557, ChangeDriveL() can be asynchronous,
+ // but CreateIndexL() will always be synchronous.
+ ChangeDriveCompleted(iStatus.Int());
+#else
+ IndexLoadingCompleted(iStatus.Int());
+#endif
+ }
+
+const TMsvIndexLoadProgress& CMsvIndexContext::Progress()
+ {
+ // Get the progress from the index first
+ if (iIndexAdapter)
+ iProgress.iIndex = iIndexAdapter->Progress();
+ return iProgress;
+ }
+
+
+
+TBool CMsvIndexContext::GetAndClearIndexCorruptFlagL()
+ {
+ RFs& fs=iServer.FileSession();
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TDriveNumber driveNum = CMsvPreferredDriveList::GetDriveList()->CurrentDriveNumber();
+ User::LeaveIfError(fs.SetSessionToPrivate(driveNum));
+#else
+ User::LeaveIfError(fs.SetSessionToPrivate(Config().iDrive));
+#endif // #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+ TInt error=fs.Delete(KStoreDeletedFile);
+ if(error !=KErrNone && error != KErrNotFound)
+ {
+ User::Leave(error);
+ }
+ // at this point error is either KErrNone if the file indicating the index
+ // was corrupt is present and has been deleted or KErrNotFound if the file
+ // was not present. The function returns ETrue if the file was present and
+ // therefore the index was corrupt and the user should be informed.
+ return error == KErrNone ? ETrue : EFalse;
+ }
+
+
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+void CMsvIndexContext::CreateStoreDeleteFile(TDriveNumber aDriveNum)
+#else
+void CMsvIndexContext::CreateStoreDeleteFile()
+#endif
+ {
+
+#if (!defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TDriveNumber aDriveNum = (TDriveNumber)(TInt) Config().iDrive;
+#endif
+
+ RFs& fs = iServer.FileSession();
+
+ TInt err = fs.SetSessionToPrivate(aDriveNum);
+ if(err == KErrNone)
+ {
+ RFile storeDeletedFile;
+ #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+ TParse parse;
+ TPtrC drive(TDriveUnit(aDriveNum).Name());
+ parse.Set(KStoreDeletedFile, &drive, NULL);
+ TFileName fileName = parse.FullName();
+ #else
+ TFileName fileName(KStoreDeletedFile);
+ #endif // #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+
+ err = storeDeletedFile.Replace(fs, fileName, EFileShareExclusive);
+ if(err == KErrNone)
+ {
+ _LIT8(KMsvIndexStoreDeleted,"StoreDeleted");
+ storeDeletedFile.Write(KMsvIndexStoreDeleted);
+ }
+ storeDeletedFile.Close();
+ }
+ }
+
+
+
+
+// Reset Mail Store(Mail2) so that old messages are deleted when new index file created..
+void CMsvIndexContext::ResetAndCreateNewMailStoreL(TBool aDelete)
+ {
+ CFileMan* fileMan = CFileMan::NewL(iServer.FileSession());
+ CleanupStack::PushL(fileMan);
+
+ if(aDelete)
+ {
+ //Check if the mailfolder exists..
+ if(BaflUtils::FileExists(iServer.FileSession(), iMessageFolder))
+ {
+ // Remove the readonly attribute..
+ (void)fileMan->Attribs(iMessageFolder,0, KEntryAttReadOnly, TTime(0), CFileMan::ERecurse);
+ // Remove old message store if exists..
+ User::LeaveIfError(fileMan->RmDir(iMessageFolder));
+ }
+ }
+
+ // Create the folder for the message store
+ TInt err = iServer.FileSession().MkDirAll(iMessageFolder);
+ if(err != KErrAlreadyExists)
+ {
+ User::LeaveIfError(err);
+ }
+ CleanupStack::PopAndDestroy(fileMan);
+ }