--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntsrv/src/CCntBackupRestoreAgent.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,417 @@
+// Copyright (c) 2005-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:
+//
+
+#include "connect/sbdefs.h" // For conn::EBURNormal etc.
+#include <utf.h> // For CnvUtfConverter::ConvertFromUnicodeToUtf8().
+
+#include "CCntBackupRestoreAgent.h"
+#include "CIniFileManager.h"
+#include "CCntDbManagerController.h"
+#include "CCntServer.h" // For KCntNullConnectionId.
+#include "CCntLogger.h"
+
+
+const TInt CCntBackupRestoreAgent::KMaxFileNameLength = 256;
+
+_LIT(KSqLiteFilePrefix, "SQLite__");
+
+/** Object factory method for CCntBackupRestoreAgent.
+*/
+CCntBackupRestoreAgent* CCntBackupRestoreAgent::NewL(RFs& aFs, CCntDbManagerController& aDbMgrCtrlr)
+ {
+ CCntBackupRestoreAgent* self = new(ELeave) CCntBackupRestoreAgent(aFs, aDbMgrCtrlr);
+ return self;
+ }
+
+
+/** Destructor.
+*/
+CCntBackupRestoreAgent::~CCntBackupRestoreAgent()
+ {
+ Cancel();
+ iBackupRestoreNotification.Close();
+ }
+
+
+/** Process any initial notification and start monitoring for changes in the
+ Backup/Restore property used by the SBEngine component.
+*/
+void CCntBackupRestoreAgent::StartL()
+ {
+ TInt newState = 0;
+
+ // Check to see if a Backup/Restore is currently in progress.
+ if (iBackupRestoreNotification.Get(newState) != KErrNotFound)
+ {
+ ProcessInitialStateL(newState);
+ }
+
+ SetActive();
+ }
+
+
+/** First phase default constructor.
+*/
+CCntBackupRestoreAgent::CCntBackupRestoreAgent(RFs& aFs, CCntDbManagerController& aDbMgrCtrlr)
+ : CActive(CActive::EPriorityStandard), iFs(aFs), iDbMgrCtrlr(aDbMgrCtrlr)
+ {
+ CActiveScheduler::Add(this);
+
+ iEvent.iType = EContactDbObserverEventNull; // Changed as required.
+ iEvent.iContactId = KNullContactId; // Always this value.
+ iEvent.iConnectionId = KCntNullConnectionId; // Always this value.
+
+ // Attach and subscribe to the Backup/Restore property used by the SBEngine
+ // component.
+ iBackupRestoreNotification.Attach(KUidSystemCategory, conn::KUidBackupRestoreKey);
+ iBackupRestoreNotification.Subscribe(iStatus);
+ }
+
+
+/** Indicates if a Backup operation is currently in progress.
+ @return ETrue if operation in progress else EFalse.
+*/
+TBool CCntBackupRestoreAgent::BackupInProgress() const
+ {
+ return (iCurrentState & (conn::EBURBackupPartial | conn::EBURBackupFull));
+ }
+
+
+/** Indicates if a Restore operation is currently in progress.
+ @return ETrue if operation in progress else EFalse.
+*/
+TBool CCntBackupRestoreAgent::RestoreInProgress() const
+ {
+ return (iCurrentState & (conn::EBURRestorePartial | conn::EBURRestoreFull));
+ }
+
+
+/** Create a new XML backup registration file for the file aFileName. The file
+ will be created on the same drive as aFileName in the Contacts Model private
+ data directory.
+
+ @param aFileName File name including drive letter i.e. <drive>:<file>.
+*/
+void CCntBackupRestoreAgent::CreateBackupRegistrationFileL(const TDesC& aFileName)
+ {
+ _LIT8(KXmlFilePart1, "<?xml version=\"1.0\" standalone=\"yes\"?>\r\n"
+ "<backup_registration>\r\n"
+ " <passive_backup base_backup_only=\"yes\">\r\n"
+ " <include_file name=\"");
+ _LIT8(KXmlFilePart2, "\"/>\r\n"
+ " </passive_backup>\r\n"
+ "</backup_registration>\r\n");
+
+ // Find out the drive held in aFileName. If a drive letter is not present
+ // then the method leaves.
+ TParsePtrC parseFileName(aFileName);
+ User::LeaveIfError(parseFileName.DrivePresent());
+
+ TPath privatePath;
+ User::LeaveIfError(iFs.PrivatePath(privatePath));
+ User::LeaveIfError(iFs.SetSessionPath(parseFileName.Drive()));
+ User::LeaveIfError(iFs.SetSessionPath(privatePath));
+
+ // If the path does not exist create it.
+ TInt err = iFs.MkDirAll(privatePath);
+
+ if (err != KErrAlreadyExists && err != KErrNone)
+ {
+ User::Leave(err);
+ }
+
+ HBufC* newFileName = CreateBackupRegistrationFileNameLC(parseFileName.NameAndExt());
+ TPtr newFileNamePtr(newFileName->Des());
+
+ // Create registration file.
+ RFile file;
+ CleanupClosePushL(file);
+
+ err = file.Create(iFs, *newFileName, EFileWrite);
+
+ // Registration file already exists so we're done.
+ if (err == KErrAlreadyExists)
+ {
+ CleanupStack::PopAndDestroy(2, newFileName); // file, newFileName
+ return;
+ }
+
+ if (err)
+ {
+ User::Leave(err);
+ }
+
+ HBufC* nameAndExt = NULL;
+ nameAndExt = HBufC::NewLC(KSqLiteFilePrefix().Length() + parseFileName.NameAndExt().Length());
+ if (parseFileName.NameAndExt().Compare(KContactsIniFileName) != 0)
+ {
+ nameAndExt->Des().Append(KSqLiteFilePrefix);
+ }
+ nameAndExt->Des().Append(parseFileName.NameAndExt());
+
+ // Convert filename and extension to UTF8 before writing to file.
+ HBufC8* fileNameAndExt8 = HBufC8::NewLC(nameAndExt->Length());
+ TPtr8 pFileNameAndExt8(fileNameAndExt8->Des());
+
+ User::LeaveIfError(CnvUtfConverter::ConvertFromUnicodeToUtf8(pFileNameAndExt8,
+ *nameAndExt));
+
+ // Write data into file.
+ User::LeaveIfError(file.Write(KXmlFilePart1()));
+ User::LeaveIfError(file.Write(pFileNameAndExt8));
+ User::LeaveIfError(file.Write(KXmlFilePart2()));
+ User::LeaveIfError(file.Flush());
+
+ CleanupStack::PopAndDestroy(4, newFileName); // fileNameAndExt8, file, nameAndExt, newFileName
+ }
+
+
+/** Delete the XML backup registration file associated with the filename. The
+ registration file will be found on the same drive as aFileName.
+
+ @param aFileName File name including drive letter i.e. <drive>:<file>.
+*/
+void CCntBackupRestoreAgent::DeleteBackupRegistrationFileL(const TDesC& aFileName)
+ {
+ TParsePtrC parseFileName(aFileName);
+
+ // Find out the drive held in aFileName. If a drive letter is not present
+ // then the method leaves.
+ User::LeaveIfError(parseFileName.DrivePresent());
+
+ TPath privatePath;
+ User::LeaveIfError(iFs.PrivatePath(privatePath));
+ User::LeaveIfError(iFs.SetSessionPath(parseFileName.Drive()));
+ User::LeaveIfError(iFs.SetSessionPath(privatePath));
+
+ HBufC* regFileName = CreateBackupRegistrationFileNameLC(parseFileName.NameAndExt());
+ TPtrC regFileNamePtr(regFileName->Des());
+
+ // Check if registration file exists and if so delete it.
+ TEntry entry;
+ TInt err = iFs.Entry(regFileNamePtr, entry);
+
+ if((err == KErrNone) && !entry.IsDir())
+ {
+ User::LeaveIfError(iFs.Delete(regFileNamePtr));
+ }
+
+ CleanupStack::PopAndDestroy(regFileName);
+ }
+
+
+/** Handle change in value of the property KUidBackupRestoreKey (used to notify
+ subscribers of Backup/Restore events).
+ @see CActive
+*/
+void CCntBackupRestoreAgent::RunL()
+ {
+ // Resubscribe before dealing with the current notification.
+ iBackupRestoreNotification.Subscribe(iStatus);
+ SetActive();
+
+ TInt newState = 0;
+
+ // Flag updated. Decide what to do in ReceivedNotificationL().
+ if (iBackupRestoreNotification.Get(newState) != KErrNotFound)
+ {
+ ReceivedNotificationL(newState);
+ }
+ }
+
+
+/** Recover if RunL() leaves.
+ @see CActive
+*/
+TInt CCntBackupRestoreAgent::RunError(TInt /*aError*/)
+ {
+
+ DEBUG_PRINT1(__VERBOSE_DEBUG__,_L("[CNTMODEL] CCntBackupRestoreAgent::RunError(): RunL() has left!\n"));
+
+ return (KErrNone);
+ }
+
+
+/**
+ @see CActive
+*/
+void CCntBackupRestoreAgent::DoCancel()
+ {
+ iBackupRestoreNotification.Cancel();
+ }
+
+
+/** Determines what operation is starting or has completed and calls the
+ relevant observer function.
+
+ @param aNewState Flags indicating what the new Backup/Restore state is:
+
+ 1. No Backup/Restore is taking place = EBURNormal | ENoBackup
+ 2. Backup operation starting = (EBURBackupFull || EBURBackupPartial) &&
+ EBackupBase
+ 3. Restore operation starting = (EBURRestoreFull || EBURRestorePartial) &&
+ EBackupBase
+*/
+void CCntBackupRestoreAgent::ReceivedNotificationL(TInt aNewState)
+ {
+ // We are starting a a new operation...
+ // Was there a previous Restore which failed to complete?
+ if (!(aNewState & (conn::EBURNormal | conn::EBURUnset)) && RestoreInProgress())
+ {
+ iCurrentState = aNewState;
+ RestoreCompletedL(KErrAbort);
+ }
+
+ // A Base Backup or Restore taking place.
+ if (aNewState & (conn::EBURBackupPartial | conn::EBURBackupFull) )
+ {
+ // Backup is taking place (either partial or full)
+ iCurrentState = aNewState;
+ BackupBeginningL();
+ }
+ else if (aNewState & (conn::EBURRestorePartial | conn::EBURRestoreFull))
+ {
+ // Restore is taking place (either partial or full)
+ iCurrentState = aNewState;
+ RestoreBeginningL();
+ }
+ else if (aNewState & (conn::EBURNormal | conn::EBURUnset))
+ {
+ // The state has changed to no Backup/Restore. Decide which operation
+ // has just completed.
+ if (BackupInProgress())
+ {
+ iCurrentState = aNewState;
+ BackupCompletedL();
+ }
+ else if (RestoreInProgress())
+ {
+ iCurrentState = aNewState;
+ RestoreCompletedL(KErrNone);
+ }
+ }
+ }
+
+
+void CCntBackupRestoreAgent::ProcessInitialStateL(TInt aNewState)
+ {
+ // A Base Backup or Restore is taking place.
+ if (aNewState & (conn::EBURBackupPartial | conn::EBURBackupFull) )
+ {
+ // Backup is taking place (either partial or full).
+ BackupBeginningL();
+ }
+ else if (aNewState & (conn::EBURRestorePartial | conn::EBURRestoreFull))
+ {
+ // Restore is taking place (either partial or full).
+ RestoreBeginningL();
+ }
+ iCurrentState = aNewState;
+ }
+
+
+void CCntBackupRestoreAgent::BackupBeginningL()
+ {
+ iEvent.iType = EContactDbObserverEventBackupBeginning;
+ iDbMgrCtrlr.HandleBackupRestoreEventL(iEvent);
+ iDbMgrCtrlr.IniFileManager().SaveIniFileSettingsIfRequestedL();
+ }
+
+
+void CCntBackupRestoreAgent::BackupCompletedL()
+ {
+ iEvent.iType = EContactDbObserverEventBackupRestoreCompleted;
+ iDbMgrCtrlr.HandleBackupRestoreEventL(iEvent);
+ // In case Store has been waiting for backup to finish. Now attempt to
+ // perform deferred operation.
+ iDbMgrCtrlr.IniFileManager().RetryStoreOperation();
+ }
+
+
+void CCntBackupRestoreAgent::RestoreBeginningL()
+ {
+ iEvent.iType = EContactDbObserverEventRestoreBeginning;
+ iDbMgrCtrlr.HandleBackupRestoreEventL(iEvent);
+ iDbMgrCtrlr.IniFileManager().SaveIniFileSettingsIfRequestedL();
+ }
+
+
+void CCntBackupRestoreAgent::RestoreCompletedL(TInt aRestoreResult)
+ {
+ if (aRestoreResult == KErrNone)
+ {
+ iDbMgrCtrlr.IniFileManager().StartRestoreIniFileSettings();
+ iEvent.iType = EContactDbObserverEventBackupRestoreCompleted;
+ iDbMgrCtrlr.HandleBackupRestoreEventL(iEvent);
+ }
+ else
+ {
+ iEvent.iType = EContactDbObserverEventRestoreBadDatabase;
+ iDbMgrCtrlr.HandleBackupRestoreEventL(iEvent);
+ // A restore of the Contacts Model initialisation file failed so save
+ // initialisation file.
+ iDbMgrCtrlr.IniFileManager().ScheduleSaveIniFileSettings(CIniFileManager::ESaveAll);
+ }
+ }
+
+
+/** Create an XML backup registration file name using aFileName.
+
+ @param aFileName File name without drive letter.
+*/
+HBufC* CCntBackupRestoreAgent::CreateBackupRegistrationFileNameLC(const TDesC& aFileName)
+ {
+ _LIT(KContactsBackupFileName, "backup_registration");
+ _LIT(KContactsBackupFileExtension, ".xml");
+
+ const TInt newFileNameLength = KContactsBackupFileName().Length() +
+ KSqLiteFilePrefix().Length() +
+ aFileName.Length() + KContactsBackupFileExtension().Length();
+
+ if (newFileNameLength > KMaxFileNameLength)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ HBufC* newFileName = HBufC::NewL(newFileNameLength);
+ CleanupStack::PushL(newFileName);
+
+ TPtr newFileNamePtr(newFileName->Des());
+
+ // New filename will be of the form backup_registration<aFileName>.xml.
+ // If aFileName has an extension then the '.' will be replaced with '_'.
+ newFileNamePtr.Append(KContactsBackupFileName);
+
+ // if the it is the cntModel.ini file
+ // then do not append it in the file name
+ // this ensures that there is one file
+ // with the name backup_registration.xml file
+ // which is required for the Backup & Restore engine.
+ if (aFileName.Compare(KContactsIniFileName) != 0)
+ {
+ newFileNamePtr.Append(KSqLiteFilePrefix);
+ newFileNamePtr.Append(aFileName);
+ }
+
+
+ TInt dotPos = newFileNamePtr.LocateReverse('.');
+ if (dotPos != KErrNotFound )
+ {
+ newFileNamePtr[dotPos] = '_';
+ }
+ newFileNamePtr.Append(KContactsBackupFileExtension);
+
+ return newFileName;
+ }