phonebookengines/contactsmodel/cntsrv/src/CCntBackupRestoreAgent.cpp
changeset 0 e686773b3f54
--- /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;
+	}