messagingfw/msgsrvnstore/server/src/MSVCOPY.CPP
changeset 22 bde600d88860
parent 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/MSVCOPY.CPP	Fri Jun 04 10:32:16 2010 +0100
@@ -0,0 +1,584 @@
+// Copyright (c) 1998-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 <e32base.h>
+
+#include "MSVIDS.H"
+#include "MSVCOPY.H"
+#include "MSVSERV.H"
+#include "MSVUTILS.H"
+
+#include "MSVPANIC.H"
+
+#include "CCopyOneFile.h"
+#include "CCopyFiles.h"
+#include "msvindexadapter.h"
+#include "msvcacheentry.h"
+
+//**********************************
+// CMsvCopyEntry
+//**********************************
+
+// static
+CMsvCopyEntry* CMsvCopyEntry::NewL(CMsvServer& aServer)
+	{
+	CMsvCopyEntry* self = new(ELeave) CMsvCopyEntry(aServer);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+CMsvCopyEntry::CMsvCopyEntry(CMsvServer& aServer)
+: CActive(EPriorityStandard), iServer(aServer)
+	{}
+
+
+CMsvCopyEntry::~CMsvCopyEntry()
+	{
+	Cancel();
+	delete iCopyOneFile;
+	delete iCopyFiles;
+	delete iFromName;
+	delete iToName;
+	}
+
+void CMsvCopyEntry::ConstructL()
+	{
+	iCopyOneFile = CCopyOneFile::NewL(iServer.FileSession());
+	iCopyFiles = CCopyFiles::NewL(iServer.FileSession());
+	iFromName= new (ELeave) TFileName;
+	iToName= new (ELeave) TFileName;
+
+	CActiveScheduler::Add(this);
+	}
+
+
+void CMsvCopyEntry::DoCancel()
+	{
+	// only one will be active but that doesn't matter
+	iCopyOneFile->Cancel();
+	iCopyFiles->Cancel();
+	Completed(KErrCancel);
+	}
+
+
+void CMsvCopyEntry::NextState()
+	{
+	switch(iState)
+		{
+		case EEntryCreated:
+			iState=ECopyingStore;
+			break;
+		case ECopyingStore:
+			iState=ECopyingFolder;
+			break;
+		case ECopyingFolder:
+			iState=ECompleted;
+			break;
+		default:
+			__ASSERT_DEBUG(EFalse,PanicServer(EMsvCopyEntryFailureBadState));
+			iState=ECompleted;
+			break;
+		}
+	}
+
+
+void CMsvCopyEntry::RunL()
+	{
+	TInt error=iStatus.Int();
+	if(error==KErrNone)
+		{
+		NextState();
+
+		switch(iState)
+			{
+			case ECopyingStore:
+				CopyStoreFile();
+				break;
+			case ECopyingFolder:
+				CopyFolder();
+				break;
+			case ECompleted:
+				Completed(KErrNone);
+				break;
+			default:
+				__ASSERT_DEBUG(EFalse,PanicServer(EMsvCopyEntryFailureBadState));
+				Completed(KErrNone);
+				break;
+			}
+		}
+	else
+		Completed(error);
+	}
+
+
+void CMsvCopyEntry::CopyStoreFile()
+	{
+	iServer.GetEntryName(iOrigEntryId, *iFromName, EFalse);
+	TUint unused;
+	TInt err = iServer.FileSession().Att(*iFromName, unused);
+	if (err == KErrNotFound || err == KErrPathNotFound)
+		{
+		TRequestStatus* status = &iStatus;
+		TInt ret = KErrNone;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+		// We know that there's no entry in the file store. Let's see if this
+		// really is an error or if there's an entry in the DB store.
+		TRAPD(dbErr, iServer.MessageDBAdapter().CopyHeaderEntryL(iOrigEntry->iMtm, iOrigEntryId, iNewEntry->Id()));
+		if(KErrNotFound == dbErr) // The entry didn't have a header table entry.
+			dbErr = KErrNone;
+		ret = dbErr;
+#endif
+		User::RequestComplete(status, ret);
+		}
+	else
+		{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+		// There is an entry for iOrigEntry in the file store. Copy header
+		// table entries if any.
+		TRAPD(dbErr, iServer.MessageDBAdapter().CopyHeaderEntryL(iOrigEntry->iMtm, iOrigEntryId, iNewEntry->Id()));
+		if(KErrNotFound == dbErr) // The entry didn't have a header table entry.
+			dbErr = KErrNone;
+		
+		if(dbErr) // There was infact an error thrown from the DB - self-complete with that.
+			{
+			TRequestStatus *status=&iStatus;
+			User::RequestComplete(status,dbErr);
+			SetActive();
+			return;
+			}
+		// There was no error thrown from the DB. Go on to copy file store entries.
+#endif
+		iServer.GetEntryName(iNewEntry->Id(), *iToName, EFalse);
+		TInt error=iServer.FileSession().MkDirAll(*iToName);
+		if(error!=KErrNone && error != KErrAlreadyExists)
+			{
+			TRequestStatus *status=&iStatus;
+			User::RequestComplete(status,error);
+			}
+		else
+			{
+			iCopyOneFile->Copy(*iFromName,*iToName,iStatus);
+			}
+		}
+	SetActive();
+	}
+
+
+void CMsvCopyEntry::CopyFolder()
+	{
+	TMsvId service;
+	iServer.IndexAdapter().OwningService(iOrigEntryId, service); // error ignored because we know the original exists
+	TInt result = MsvUtils::HasDirectory(iServer.FileSession(), iServer.Context().MessageFolder(), service, iOrigEntryId);
+	if (result < 0)
+		Completed(result);
+	else if(result)
+		{
+		iServer.GetEntryName(iOrigEntryId, *iFromName, ETrue);
+		iServer.GetEntryName(iNewEntry->Id(), *iToName, ETrue);
+		iCopyFiles->CopyDir(*iFromName,*iToName,iStatus);
+		SetActive();
+		}
+	else
+		{
+		TRequestStatus *status=&iStatus;
+		User::RequestComplete(status,KErrNone);
+		SetActive();
+		}
+	}
+
+
+void CMsvCopyEntry::StartL(TMsvId aOrigEntryId, TMsvId aTargetId, TRequestStatus& aObserverStatus)
+//
+//
+//
+	{
+	// Fail now if the index says it's not available
+	User::LeaveIfError(iServer.IndexAdapter().ErrorState());
+	__ASSERT_DEBUG(!IsActive() && (iState==ENotYetStarted || iState==ECompleted), PanicServer(EMsvActiveCopyEntryReset));
+	iState = ENotYetStarted;
+	iOrigEntryId = aOrigEntryId;
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+	// Copying of entries across drives not supported.
+	if(GetDriveId(aOrigEntryId) != GetDriveId(aTargetId))
+		{
+		User::Leave(KErrNotSupported);
+		}
+#endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+	// get the complete index entry to copy
+	TMsvEntry* entryPtr;
+	TSecureId ownerId;
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	User::LeaveIfError(iServer.IndexAdapter().GetEntry(iOrigEntryId, iOrigEntry, ownerId));
+	entryPtr = iOrigEntry;
+#else	
+	User::LeaveIfError(iServer.IndexAdapter().GetEntry(iOrigEntryId, entryPtr, ownerId));
+#endif
+
+	// create a new entry with the new parent, and add the new entry to the index
+	TMsvEntry newEntry = *entryPtr;
+	newEntry.SetParent(aTargetId);
+	User::LeaveIfError(iServer.IndexAdapter().AddEntry(newEntry, ownerId, ETrue));
+
+	// get the new entry from  the index
+	iServer.IndexAdapter().GetEntry(newEntry.Id(), iNewEntry); // will not fail, the entry exists
+	iState = EEntryCreated;
+
+	iObserverStatus = &aObserverStatus;
+	*iObserverStatus = KRequestPending;
+
+	TRequestStatus *status=&iStatus;
+	User::RequestComplete(status,KErrNone);
+	SetActive();
+	}
+
+
+void CMsvCopyEntry::Completed(TInt aError)
+	{
+	// remove the entry if we failed
+	if(aError!=KErrNone && iState!=ENotYetStarted)
+		iServer.RemoveEntry(iNewEntry->Id());
+
+	// inform the observer
+	User::RequestComplete(iObserverStatus, aError);
+	}
+
+
+//**********************************
+// CMsvCopy
+//**********************************
+
+// static
+CMsvCopy* CMsvCopy::NewL(CMsvServer& aServer)
+//
+//
+//
+	{
+	CMsvCopy* self = new(ELeave) CMsvCopy(aServer);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+CMsvCopy::CMsvCopy(CMsvServer& aServer)
+: CActive(EPriorityStandard), iServer(aServer)
+//
+//
+//
+	{}
+
+
+CMsvCopy::~CMsvCopy()
+//
+//
+//
+	{
+	Cancel();
+	delete iRecursionList;
+	delete iFailedEntryParents;
+	delete iCopyEntry;
+	}
+
+
+void CMsvCopy::ConstructL()
+//
+//
+//
+	{
+	iRecursionList = new(ELeave) CMsvEntrySelection;
+	iFailedEntryParents = new(ELeave) CMsvEntrySelection;
+	iCopyEntry = CMsvCopyEntry::NewL(iServer);
+	CActiveScheduler::Add(this);
+	}
+
+
+void CMsvCopy::DoCancel()
+//
+//
+//
+	{
+	iCopyEntry->Cancel();
+	Completed();
+	}
+
+
+void CMsvCopy::StartL(TMsvId aOrigEntryId, TMsvId aTargetId, TRequestStatus& aObserverStatus, TBool aDescendentCopying)
+//
+//
+//
+	{
+	// Fail now if the index says it's not available
+	User::LeaveIfError(iServer.IndexAdapter().ErrorState());
+	iFailedEntryParents->Reset();
+	iDescendentCopying = aDescendentCopying;
+	iDescendentId = KMsvNullIndexEntryId;
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+	// Copying of entries across drives not supported.
+	if(GetDriveId(aOrigEntryId) != GetDriveId(aTargetId))
+		{
+		User::Leave(KErrNotSupported);
+		}
+#endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+	// check the target exists
+	TBool entryExists = EFalse;
+	entryExists = iServer.IndexAdapter().EntryExists(aTargetId);
+	if (!entryExists)
+		User::Leave(KErrNotFound);
+	iOrigTargetId = aTargetId;
+
+	// get the index entry
+	iOrigSourceId = aOrigEntryId;
+	TMsvEntry* entryPtr;
+	User::LeaveIfError(iServer.IndexAdapter().GetEntry(iOrigSourceId, entryPtr));
+	iFailedEntryParents->AppendL(iOrigSourceId);
+
+	// check the entries can be copied
+	iServer.IndexAdapter().ExpandSelectionRecursively(*iFailedEntryParents);
+	User::LeaveIfError(iServer.CheckEntries(*iFailedEntryParents));
+	iFailedEntryParents->ResizeL(0); // the memory is not freed, so all the entries can be added again
+
+	// set the recursion variables
+	iError = KErrNone;
+	iTopLevelId = KMsvNullIndexEntryId;
+	iTempSourceId = iOrigSourceId;
+	iTempTargetId = iOrigTargetId;
+
+	// start the recursive copy
+	iCopyEntry->StartL(iOrigSourceId, iOrigTargetId, iStatus);
+	SetActive();
+
+	iObserverStatus = &aObserverStatus;
+	*iObserverStatus = KRequestPending;
+	}
+
+
+void CMsvCopy::RunL()
+//
+//
+//
+	{
+	// was this the top level
+	TBool topLevel = (iTopLevelId == KMsvNullIndexEntryId);
+	if (topLevel)
+		{
+		if (iStatus!=KErrNone)
+			{
+			User::RequestComplete(iObserverStatus, iStatus.Int());
+			return;
+			}
+		iTopLevelId = iCopyEntry->NewEntryId();
+		if (iDescendentCopying && iDescendentId==KMsvNullIndexEntryId)
+			iDescendentId = iTopLevelId;
+		}
+
+	// copy next entry
+	TRAPD(leave, DoRunL(topLevel));
+	if (leave)
+		{
+		// system error failure rather than couldn't copy a locked entry, so completed
+		if (iFailedEntryParents->Find(iTempTargetId)==KErrNotFound)
+			iFailedEntryParents->AppendL(iTempTargetId); // will not fail as space has been reserved
+		if (iError==KErrNone)
+			iError=leave;
+		Completed();
+		}
+	}
+
+
+void CMsvCopy::DoRunL(TBool aTopLevel)
+//
+//
+//
+	{
+	// record the success/failure of the copy
+	TMsvId newEntryId = KMsvNullIndexEntryId;
+	TBool  failed = (iStatus!=KErrNone);
+	if (failed)
+		{
+		if (iError==KErrNone)
+			iError = iStatus.Int();
+		iFailedEntryParents->AppendL(iTempTargetId); // a child of this entry was not copied
+		}
+	else
+		newEntryId = iCopyEntry->NewEntryId();
+
+	// get the  entry
+	
+	CMsvCacheEntry* sEntry;
+	User::LeaveIfError(iServer.IndexAdapter().GetInternalEntry(iTempSourceId, sEntry));
+
+	TMsvId firstSiblingId;
+    if(!aTopLevel && iServer.IndexAdapter().GetNextSiblingL(iTempSourceId,sEntry->Entry().Parent(),firstSiblingId)) 
+    	{
+    	iRecursionList->AppendL(firstSiblingId);
+        iRecursionList->AppendL(iTempTargetId);
+    	}
+  
+  	TMsvId firstChildId;
+  	if (!failed && iServer.IndexAdapter().GetFirstChildIdL(iTempSourceId,firstChildId)
+  		&& (!iDescendentCopying || firstChildId<iDescendentId))
+  		{
+        iRecursionList->AppendL(firstChildId);
+        iRecursionList->AppendL(newEntryId);
+        }
+     
+	if (iRecursionList->Count()==0)
+		{
+		// no more to copy
+		Completed();
+		return;
+		}
+	// get the next one to copy
+	iTempSourceId = iRecursionList->At(0);
+	iTempTargetId = iRecursionList->At(1);
+	iRecursionList->Delete(0,2);
+
+	// start the copy
+	iCopyEntry->StartL(iTempSourceId, iTempTargetId, iStatus);
+	SetActive();
+	}
+
+
+void CMsvCopy::Completed()
+//
+//
+//
+	{
+	if (iError)
+		{
+		if (iDeleteAllOnFailure)
+			iServer.RemoveEntry(iTopLevelId);
+		else
+			{
+			__ASSERT_DEBUG(iFailedEntryParents->Count(), PanicServer(EMsvCopyErrorButNoIds));
+			// cleanup the code
+			TInt index=iFailedEntryParents->Count();
+			while (index--)
+				{
+				TMsvId id = iFailedEntryParents->At(index);
+				TBool entryExists = EFalse;
+				entryExists = iServer.IndexAdapter().EntryExists(id);
+				if (!entryExists)
+					break;
+
+				// recurse back up tree to find the top entry or folder/service
+				TMsvEntry* entry;
+				TMsvEntry* parent;
+				iServer.IndexAdapter().GetEntry(id, entry); // errror ignored as entry exists
+				iServer.IndexAdapter().GetEntry(entry->Parent(), parent); // errror ignored as entry exists
+				while (entry->Id()!=iTopLevelId && (parent->iType!=KUidMsvFolderEntry || parent->iType!=KUidMsvServiceEntry))
+					{
+					entry = parent;
+					iServer.IndexAdapter().GetEntry(entry->Parent(), parent); // error ignored as entry exists
+					}
+				// remove the entries
+				iServer.RemoveEntry(entry->Id());
+				}
+			}
+		}
+
+	// inform the observer
+	User::RequestComplete(iObserverStatus, iError);
+	}
+
+//**********************************
+// CMsvCopyEntries
+//**********************************
+
+// static
+CMsvCopyEntries* CMsvCopyEntries::NewL(CMsvServer& aServer)
+//
+//
+//
+	{
+	CMsvCopyEntries* self = new(ELeave) CMsvCopyEntries();
+	CleanupStack::PushL(self);
+	self->ConstructL(aServer);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+CMsvCopyEntries::CMsvCopyEntries() :
+	CMsvCopyMoveEntriesBase()
+//
+//
+//
+	{}
+
+
+CMsvCopyEntries::~CMsvCopyEntries()
+//
+//
+//
+	{
+	delete iCopy;
+	delete iNewEntries;
+	}
+
+
+void CMsvCopyEntries::ConstructL(CMsvServer& aServer)
+//
+//
+//
+	{
+	iCopy = CMsvCopy::NewL(aServer);
+	iCopy->DeleteAllOnFailure();
+	iNewEntries = new(ELeave) CMsvEntrySelection;
+
+	CMsvCopyMoveEntriesBase::ConstructL();
+	}
+
+
+void CMsvCopyEntries::DoCancel()
+//
+//
+//
+	{
+	iCopy->Cancel();
+	User::RequestComplete(iObserverStatus, KErrCancel);
+	}
+
+
+void CMsvCopyEntries::DoStartL(TMsvId aSourceId, TMsvId aTargetId, TRequestStatus& aObserverStatus)
+//
+//
+//
+	{
+	// Reserve space for new entry id
+	iNewEntries->SetReserveL(CompletedIds().Count() + 1);
+
+	// Perform the copy
+	iCopy->StartL(aSourceId, aTargetId, aObserverStatus, ETrue);
+	}
+
+
+void CMsvCopyEntries::RunL()
+	{
+	// If no error occured remember the new entry's id
+	if (iStatus == KErrNone)
+		iNewEntries->AppendL(iCopy->NewEntryId());
+
+	CMsvCopyMoveEntriesBase::RunL();
+	}