messagingfw/msgsrvnstore/server/src/cmessageconvertermanager.cpp
changeset 22 bde600d88860
parent 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/cmessageconvertermanager.cpp	Fri Jun 04 10:32:16 2010 +0100
@@ -0,0 +1,479 @@
+// Copyright (c) 2008-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: 
+//
+
+
+/**
+ * HEADER FILES
+ */
+
+#include "cmsvversion0version1converter.h"
+#include "cmsvversion1version2converter.h"
+//#include "cmsvconverterwaiter.h"
+
+
+// literals
+#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+	_LIT(KMessagingDBName, "\\messaging.db");
+#else
+	_LIT(KMessagingDBName,"[1000484B]messaging.db");
+	_LIT(KMessagingDBFilePath,"\\Private\\1000484b\\Mail2\\");
+#endif
+
+
+/**
+NewL()
+Constructs a new message converter object. This is singleton instatiation.	
+   
+@param aDriveNumber:
+@return None
+@internalComponent
+*/
+CMessageConverterManager* CMessageConverterManager::NewL(TDriveNumber aDriveNumber)
+
+	{
+	CMessageConverterManager* self = new(ELeave) CMessageConverterManager(aDriveNumber);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/**
+StartConversion()
+Fetches the drive number requested for conversion, constructs converter manager object
+and initiates the conversion for that drive.
+
+@param aDrive: Requested Drive for conversion.
+@return TInt: System wide error codes.
+@internalComponent
+*/
+TInt CMessageConverterManager::StartConversion(TAny* aDrive)
+	{
+    __UHEAP_MARK;
+     CTrapCleanup* cleanup = CTrapCleanup::New();
+   	if(!cleanup) 
+    	{ 
+   		return KErrNoMemory; 
+        } 
+      
+    
+    TInt err= KErrNone;
+    TDriveNumber driveNum = *(static_cast<const TDriveNumber*>(aDrive));
+	CMessageConverterManager* self = NULL;
+	TRAP(err, self = CMessageConverterManager::NewL(driveNum));  
+	
+	// do the conversion
+	if(!err)
+		{
+		CleanupStack::PushL(self);
+		TRAP(err , self->DoConversionL());
+		CleanupStack::PopAndDestroy();
+		}
+	
+	delete  cleanup;
+	__UHEAP_MARKEND;
+	
+	return err;
+	}
+
+/**
+CMessageConverterManager()
+Default constructor
+
+@param None
+@return None
+@internalComponent
+*/
+CMessageConverterManager::CMessageConverterManager(TDriveNumber aDriveNumber):iDrive(aDriveNumber)
+	{
+	}
+
+/**
+ConstructL()
+Second phase constructor.
+
+@param aDriveNumber:
+@param conversionResume:
+@return None
+@internalComponent
+*/
+void CMessageConverterManager::ConstructL()
+	{
+	User::LeaveIfError(ifsSession.Connect()); 
+	iConversionTablePresent = ETrue;
+	iDeleteDatabase = -1;
+	iInitialVersion = -1;
+	}
+
+/**
+ ~CMessageConverterManager()
+   Destructor
+   
+ @param None
+ @return None
+ @internalComponent
+ */
+CMessageConverterManager::~CMessageConverterManager()
+	{
+	delete iMessageDbAdapter;
+	delete iDbAdapter;
+	
+	if(iDeleteDatabase == 0)
+		{
+		TRAP_IGNORE(RollBackVersion0Version1ConversionL());
+		}
+	else if(iDeleteDatabase == 1)
+		{
+		TRAP_IGNORE(RollBackVersion1Version2ConversionL());
+		}
+	
+	}
+
+/**
+DoConversionL()
+Initialises message store conversion and starts conversion between the required versions.	
+
+@param None
+@return None
+@internalComponent
+*/
+void CMessageConverterManager::DoConversionL()
+	{
+	// Start from beginning or Resume
+	InitialiseMessageStoreConversionL();
+	
+	switch(iConversionVersion)
+		{
+		case 1:  // version 0 version 1 conversion
+			//Start from beginning or resume Resume v0 to v1
+			{
+			iInitialVersion = 0;
+			
+			RFile file;
+			TInt error = file.Open(ifsSession, iFilePath, EFileShareAny|EFileWrite);
+			
+			// check disk space
+			TVolumeInfo info;
+			ifsSession.Volume(info,iDrive);
+			
+			TInt indexFileSize;
+			file.Size(indexFileSize);
+			
+			TInt reqDiskSpace;
+			reqDiskSpace = indexFileSize * 2;
+		
+			file.Close();
+			ifsSession.Close();		
+			
+			if(reqDiskSpace * 2 < info.iFree)
+				{
+													
+				iIndexFileConverter = CMsvVersion0Version1Converter::NewL(*iDbAdapter,iDrive,iConversionResume);
+				CleanupStack::PushL(iIndexFileConverter);
+								
+				TRAP(error,iIndexFileConverter->ConvertMessageStoreL());
+				
+				if(error != KErrNone)
+					{
+					iDeleteDatabase = 0;
+					User::Leave(error);
+					}
+								
+				if(iConversionResume)
+					{
+					iConversionResume = EFalse;
+					}
+				CleanupStack::PopAndDestroy();  //iIndexFileConverter
+		
+				iDbAdapter->ChangeVersionL(1);  //We have a version 1 db now
+				}
+			else // disk check failed. Lets leave conversion status table if there is one.
+				{
+				User::Leave(KErrDiskFull);
+				}
+			}
+	
+		case 2:	// version 1 version 2 conversion
+			{
+			if(iInitialVersion !=0 )
+				{
+				iInitialVersion = 1;
+				}
+				
+			iMessageConverter = CMsvVersion1Version2Converter::NewL(*iDbAdapter,*iMessageDbAdapter,iDrive,iConversionResume);
+			CleanupStack::PushL(iMessageConverter);
+					
+			TRAPD(error,iMessageConverter->ConvertMessageStoreL());
+			if(error)
+				{
+				if(iInitialVersion == 1)
+					{
+					iDeleteDatabase = 1;
+					}
+				else
+					{
+					iDeleteDatabase = 0;
+					}
+				User::Leave(error);
+				}
+						
+			CleanupStack::PopAndDestroy(iMessageConverter);  //iMessageConverter
+			
+			iDbAdapter->ChangeVersionL(2);
+			}
+		}
+		// We are done. Delete the status table.
+		iDbAdapter->RemoveConversionStatusTableL();
+		
+		// remove index file
+		RemoveIndexFileL(iDrive);
+	}
+
+/**
+InitialiseMessageStoreConversionL()
+Checks if the conversion is to be resumed. If yes, than identifies the message store version
+to be converted.
+If its a new conversion request than it creates the necessary tables and initiases the adapter
+classes accordingly.
+
+@param None
+@return None
+@internalComponent
+*/	
+void CMessageConverterManager::InitialiseMessageStoreConversionL()
+	{
+	TParse parse;
+	TPtrC drive = TDriveUnit(iDrive).Name();
+	parse.Set(KMessagingDBName, &drive, NULL);
+	iDBFileName = parse.FullName();
+	
+	iFilePath.Append(drive);
+	iFilePath.Append(KIndexFilePath);
+	
+	iConversionResume = ResumeConversionL();
+	/*
+	iConversionResume can have the following conditions set.
+	ETrue  -  Conversion is to be resumed. 
+	EFalse -  New conversion Request.
+	*/		
+	if(iConversionResume)
+		{
+		if(iConversionTablePresent)
+			{
+			iDbAdapter = CMsvDBAdapter::OpenL(iDBFileName);	// open the db	
+			
+			// get resumption point from conversion resume table.
+			iDbAdapter->GetConversionStatusL(iResumeStatus); 
+
+			if(iResumeStatus.targetVersion == 1)
+				{
+				iConversionVersion = 1;
+				}
+			else
+				{
+				iConversionVersion = 2;
+				}
+			}
+		else
+			{
+			// new request for version 1 version 2 conversion.
+			// Index file already migrated to SQlite DB.
+			iDbAdapter = CMsvDBAdapter::OpenL(iDBFileName);	// open the db	
+			iDbAdapter->CreateConversionStatusTableL();
+			iConversionVersion = 2;
+			iConversionResume = EFalse;
+			}
+		}
+	else
+		{
+		// New request for version 1 version 2 conversion.
+		// Index file still in file.
+		
+		CMsvDBAdapter::CreateDBL(iDrive);
+		iDbAdapter = CMsvDBAdapter::OpenL(iDBFileName);
+		iDbAdapter->ConstructSortTableL();
+		iDbAdapter->CreateConversionStatusTableL();
+		iConversionVersion = 1;
+		}
+	iDbAdapter->InitializeL();
+	// change to invalid versionss
+	iDbAdapter->ChangeVersionL(-1);
+	// Get a handle to message adapter	
+	iMessageDbAdapter = CMsvMessageDBAdapter::NewL(iDbAdapter,ETrue);	
+	// Our handles are created . and we are good to start
+	}
+
+/**
+ResumeConversionL()
+Checks if the conversion is to be resumed by looking for conversion status table.
+
+@param None
+@return TBool :Boolean flag specifying if conversion is to be resumed.
+@internalComponent
+*/	
+TBool CMessageConverterManager::ResumeConversionL()
+	{
+	// DB exists, Check for conversion Status Table
+	_LIT16(KFindConversionStatusTableQuery, "SELECT COUNT(*) FROM SQLITE_MASTER WHERE NAME LIKE 'ConversionStatus';");
+	
+	RSqlDatabase temp;
+	CleanupClosePushL(temp);
+
+	TRAPD(err , temp.OpenL(iDBFileName));
+	
+	if(err == KErrNone)
+		{
+		// Database found. Check if are resuming.		
+		RBuf16 headerTableQuery;
+		CleanupClosePushL(headerTableQuery);
+		headerTableQuery.CreateL(80);
+
+		headerTableQuery.Append(KFindConversionStatusTableQuery);
+			
+		TInt count = 0;
+		TSqlScalarFullSelectQuery query(temp);
+		count = query.SelectIntL(headerTableQuery);
+		
+		headerTableQuery.Close();
+		temp.Close();
+		CleanupStack::PopAndDestroy(); //headerTableQuery
+		CleanupStack::PopAndDestroy(); // temp
+		
+		if(count != 1)
+			{
+			 // we did not find the status table. version 1 version 2 conversion
+			iConversionTablePresent = EFalse;			
+			}
+		// version 1 version 2 resume.
+		return ETrue;	
+		}
+	// database is not present. This is version 0 to version 1 conversion
+	temp.Close();
+	CleanupStack::PopAndDestroy(); // temp
+	return EFalse;
+	}
+	
+/**
+RemoveIndexFileL()
+Removes the index file. This a called once the conversion completes successfully for a drive.
+
+@param aDrive: Drive Number.
+@return None
+*/	
+void CMessageConverterManager::RemoveIndexFileL(TDriveNumber aDrive)
+	{
+	RFs fs;
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);		
+	TPtrC drive(TDriveUnit(aDrive).Name());
+		
+	RBuf path;
+	CleanupClosePushL(path);	
+	path.CreateL(KMaxPath);
+		
+	path.Append(drive);
+	path.Append(KIndexFilePath);
+
+	TInt error = fs.Delete(path);			
+	CleanupStack::PopAndDestroy(2); // path	
+	}
+
+/**
+RollBackVersion0Version1ConversionL()
+Rolls back any changes done during version 0 to version 1 conversion
+
+@param None: 
+@return None
+@internalComponent
+*/	
+void CMessageConverterManager::RollBackVersion0Version1ConversionL()
+	{
+	RFs fs;
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);		
+	
+	TPtrC drive(TDriveUnit(iDrive).Name());
+	
+	RBuf path;
+	CleanupClosePushL(path);	
+	path.CreateL(KMaxPath);
+	
+	path.Append(drive);
+	
+	#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+		path.Append(KMessagingDBName);
+	#else
+		{
+		path.Append(KMessagingDBFilePath);
+		path.Append(KMessagingDBName);
+		}
+	#endif
+	//TInt err = fs.Delete(path);			
+	TInt err = RSqlDatabase::Delete(path);
+	CleanupStack::PopAndDestroy(2); // path	,fs
+
+	fs.Close();	
+	}
+
+/**
+RollBackVersion1Version2ConversionL()
+Rolls back any changes done during version 1 to version 2 conversion
+
+@param None: 
+@return None
+@internalComponent
+*/	
+void CMessageConverterManager::RollBackVersion1Version2ConversionL()
+	{
+	RSqlDatabase temp;
+	CleanupClosePushL(temp);
+	
+	TPtrC drive(TDriveUnit(iDrive).Name());
+	
+	RBuf path;
+	CleanupClosePushL(path);	
+	path.CreateL(KMaxPath);
+	
+	path.Append(drive);
+	
+	#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
+		path.Append(KMessagingDBName);
+	#else
+		{
+		path.Append(KMessagingDBFilePath);
+		path.Append(KMessagingDBName);
+		}
+	#endif
+
+	temp.OpenL(path);
+	
+	// lets delete the tables we have created.
+	
+	_LIT16(KDropTableQuerySmtp, "DROP table if exists Header_268439592;");
+	_LIT16(KDropTableQueryPop, "DROP table if exists Header_268439593;");
+	_LIT16(KDropTableQueryImap, "DROP table if exists Header_268439594;");
+	_LIT16(KDropTableQuerySms, "DROP table if exists Header_268439596;");
+	_LIT16(KDropTableQueryConversionStatus, "DROP table if exists ConversionStatus;");
+			
+	TInt err = temp.Exec(KDropTableQuerySmtp);
+	err = temp.Exec(KDropTableQueryPop);
+	err = temp.Exec(KDropTableQueryImap);
+	err = temp.Exec(KDropTableQuerySms);
+	err = temp.Exec(KDropTableQueryConversionStatus);	
+	
+	temp.Close();
+	CleanupStack::PopAndDestroy(2); // temp	
+	}