messagingfw/msgsrvnstore/server/src/MSVMOVE.CPP
changeset 62 db3f5fa34ec7
parent 0 8e480a14352b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/MSVMOVE.CPP	Wed Nov 03 22:41:46 2010 +0530
@@ -0,0 +1,572 @@
+// 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 "MSVMOVE.H"
+#include "MSVSERV.H"
+#include "MSVPANIC.H"
+#include "MSVUTILS.H"
+#include "msvindexadapter.h"
+
+const TInt KFileWildCard='*';
+
+//**********************************
+// CMsvMove
+//**********************************
+
+// static
+CMsvMove* CMsvMove::NewL(CMsvServer& aServer)
+//
+//
+//
+	{
+	CMsvMove* self = new(ELeave) CMsvMove(aServer);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+CMsvMove::CMsvMove(CMsvServer& aServer)
+: CActive(EPriorityStandard), iServer(aServer), iLockedIndex(-2)
+//
+//
+//
+	{}
+
+
+CMsvMove::~CMsvMove()
+//
+//
+//
+	{
+	Cancel();
+	Reset();
+	delete iFileMan;
+	delete iDescendents;
+	}
+
+
+void CMsvMove::Reset()
+//
+// NOTE called by d'tor
+//
+	{
+	if (iDescendents && iLockedIndex!=-2)
+		{
+		TInt count = iDescendents->Count();
+		while (count-- > iLockedIndex)
+			{
+			iServer.IndexAdapter().ReleaseEntryAndStore(iDescendents->At(count));
+			}
+
+		iDescendents->Reset();
+		}
+	iLockedIndex=-2;
+
+	delete iTargetPath;
+	iTargetPath=NULL;
+	}
+
+
+void CMsvMove::ConstructL()
+//
+//
+//
+	{
+	iFileMan = CFileMan::NewL(iServer.FileSession());
+	iDescendents = new(ELeave) CMsvEntrySelection;
+	CActiveScheduler::Add(this);
+	}
+
+
+void CMsvMove::RunL()
+//
+//
+//
+	{
+	TInt error = iStatus.Int();
+	if (error==KErrNone)
+		TRAP(error, DoRunL());
+	if (error)
+		{
+		CleanupFiles(iTargetService);
+		iDescendents->Reset();
+		User::RequestComplete(iObserverStatus, error);
+		}
+	}
+
+
+void CMsvMove::DoRunL()
+//
+//
+//
+	{
+	if (iState==EIndex)
+		{
+        // If the entry is not a visible folder and it's visible
+        // folder id is changed, the caller should update the 
+		// visible folder id of all descendents.
+		if(!iCurrentEntry->VisibleFolderFlag())
+			{
+	        User::LeaveIfError(iServer.IndexAdapter().MoveEntry(iSourceId, iTargetId, iDescendents));   
+            }
+	    else
+	        {
+	        User::LeaveIfError(iServer.IndexAdapter().MoveEntry(iSourceId, iTargetId)); 
+	        }
+		
+		CleanupFiles(iSourceService);
+		iServer.IndexAdapter().GetEntry(iSourceId, iCurrentEntry); // error ignored as entry exists
+		iDescendents->Reset();
+		User::RequestComplete(iObserverStatus, KErrNone);
+		return;
+		}
+
+	FindNextStep();
+	StartNextStep();
+	}
+
+
+
+void CMsvMove::CleanupFiles(TMsvId aService)
+	{
+	// delete the unwanted copies
+	if (iSourceService!=iTargetService)
+		{
+		TInt count=iDescendents->Count();
+		while (count--)
+			{
+			TFileName filename(iServer.Context().MessageFolder());
+			TMsvId id = iDescendents->At(count);
+			// BFs
+			MsvUtils::ConstructEntryName(aService, id, filename, MsvUtils::EFolder);
+			iFileMan->Delete(filename, CFileMan::ERecurse); // error ignored
+			// BF
+			iServer.FileSession().RmDir(filename); // error ignored
+			// Store
+			filename = iServer.Context().MessageFolder();
+			MsvUtils::ConstructEntryName(aService, id, filename, MsvUtils::EStore);
+			iFileMan->Delete(filename); // error ignored
+			}
+		}
+
+	// release the locks
+	TInt count = iDescendents->Count();
+	while (count--)
+		{
+		iServer.IndexAdapter().ReleaseEntryAndStore(iDescendents->At(count)); // error ignored
+		}
+
+	iLockedIndex=-2;
+	}
+
+
+void CMsvMove::DoCancel()
+//
+// CANNOT cancel the fileman operation - so we just have to wait for it to complete normally
+//
+	{
+	User::RequestComplete(iObserverStatus, KErrCancel);
+	}
+
+
+void CMsvMove::StartL(TMsvId aId, TMsvId aTarget, TRequestStatus& aObserverStatus)
+//
+//
+//
+	{
+	// Fail now if the index says it's not available
+	User::LeaveIfError(iServer.IndexAdapter().ErrorState());
+	Reset();
+
+	// check the source and target exists and which service they are under
+	User::LeaveIfError(iServer.IndexAdapter().OwningService(aId, iSourceService));
+	User::LeaveIfError(iServer.IndexAdapter().OwningService(aTarget, iTargetService));
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+	// Movement of entries across drives not supported.
+	if(GetDriveId(aId) != GetDriveId(aTarget))
+		{
+		User::Leave(KErrNotSupported);
+		}
+#endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+	// get the index entry
+	iSourceId = aId;
+	iServer.IndexAdapter().GetEntry(iSourceId, iCurrentEntry); // error ignored as entry exists
+	iParentId = iCurrentEntry->Parent();
+	iTargetId = aTarget;
+	iDescendents->AppendL(iSourceId);
+	iNextDescendent=1;
+
+	__ASSERT_DEBUG(iCurrentEntry->Parent()!=iTargetId, PanicServer(EMsvMtmMovingToSameParent));
+
+	// check if the entry has children
+	if (iCurrentEntry->Owner())
+		{
+		// check for moving into a descendent
+		TBool descendent;
+		iServer.IndexAdapter().IsADescendent(aId, aTarget, descendent); // error ignored as both entry exists
+		if (descendent)
+			User::Leave(KErrArgument);
+
+		// get id of all the descendents
+		User::LeaveIfError(iServer.IndexAdapter().ExpandSelectionRecursively(*iDescendents));
+		}
+
+	// check all the entries can be moved
+	CheckEntriesL();
+
+	// determine whether the store/files actually need copying
+	iState = (iSourceService==iTargetService ? EIndex : EFolder);
+
+	// set up the file copying
+	if (iState!=EIndex)
+		{
+		TFileName targetPath(iServer.Context().MessageFolder());
+		MsvUtils::ConstructEntryName(iTargetService, iTargetService, targetPath, MsvUtils::EPath);
+
+		iTargetPath = targetPath.AllocL();
+		iServer.FileSession().MkDirAll(targetPath);
+		User::LeaveIfError(iServer.IndexAdapter().GetEntry(iDescendents->At(0), iCurrentEntry));
+
+		// make sure the first step is valid
+		TInt result = MsvUtils::HasDirectory(iServer.FileSession(), iServer.Context().MessageFolder(), iSourceService, iCurrentEntry->Id());
+		User::LeaveIfError(result);
+
+		if (!result)
+			FindNextStep();
+		}
+
+	StartNextStep();
+
+	iObserverStatus = &aObserverStatus;
+	*iObserverStatus = KRequestPending;
+	}
+
+
+void CMsvMove::FindNextStep()
+//
+//
+//
+	{
+	__ASSERT_DEBUG(iState!=EIndex, PanicServer(EMsvIncorrectStateInFindNextStep));
+
+	FOREVER
+		{
+		// we have copied the files, check if then entry has a store
+		if (iState==EFolder && MsvUtils::HasStore(iServer.FileSession(), iServer.Context().MessageFolder(), iSourceService, iCurrentEntry->Id()))
+			{
+			iState=EStore;
+			break;
+			}
+		TInt count = iDescendents->Count();
+
+		// are there any entries left to check
+		if (iNextDescendent==count)
+			{
+			iState=EIndex;
+			break;
+			}
+
+		// find the next descendent which still exists
+		FOREVER
+			{
+			TBool error = EFalse;
+			error = iServer.IndexAdapter().GetEntry(iDescendents->At(iNextDescendent++), iCurrentEntry);
+			if (error==KErrNone)
+				{
+				break;
+				}
+			}
+
+			iState = EFolder;
+			if (MsvUtils::HasDirectory(iServer.FileSession(), iServer.Context().MessageFolder(), iSourceService, iCurrentEntry->Id()))
+				break;
+			
+		}
+	}
+
+
+void CMsvMove::StartNextStep()
+//
+//
+//
+	{
+	TInt error;
+	switch (iState)
+		{
+		case EFolder:
+			error = SetupFileCopy();
+			break;
+		case EStore:
+			error = SetupStoreCopy();
+			break;
+		default:
+			error=KErrNone;
+		}
+
+	if (iStatus!=KRequestPending)
+		{
+		// either the store/file copy has failed or the state is EIndex
+		iStatus=KRequestPending;
+		TRequestStatus* st = &iStatus;
+		User::RequestComplete(st, error);
+		}
+
+	SetActive();
+	}
+
+
+void CMsvMove::CheckEntriesL()
+//
+//
+//
+	{
+	iLockedIndex = iDescendents->Count();
+	while (iLockedIndex)
+		{
+		TMsvId id = iDescendents->At(iLockedIndex-1);
+
+		// lock the entry
+		User::LeaveIfError(iServer.IndexAdapter().LockEntryAndStore(id));
+		iLockedIndex--;
+
+		// check noone is reading the store (reading the store now doesn't
+		// keep the file open, therefore we can't rely on checking the file to stop
+		// deleting while reading
+		TBool reading=EFalse;
+		User::LeaveIfError(iServer.IndexAdapter().IsStoreReadingLocked(id,reading));
+		if(reading) User::Leave(KErrInUse);
+
+		// get the entry
+		TMsvEntry* entry;
+		User::LeaveIfError(iServer.IndexAdapter().GetEntry(id, entry));
+		// check the store
+		TFileName filename;
+		iServer.GetEntryName(id, filename, EFalse);
+		TBool open;
+		TInt error = iServer.FileSession().IsFileOpen(filename, open);
+		if (error != KErrNotFound && error!=KErrPathNotFound)
+			{
+			if (error != KErrNone)
+				User::Leave(error);
+			if (open)
+				User::Leave(KErrInUse);
+			}
+
+		// check any files
+		CDir* dir;
+		error = iServer.GetFileDirectoryListing(id, filename, dir);
+		if (error == KErrNone)
+			{
+			CleanupStack::PushL(dir);
+			User::LeaveIfError(iServer.FileSession().SetSessionPath(filename));
+			TInt fCount=dir->Count();
+			if (fCount--)
+				{
+				TBool open;
+				User::LeaveIfError(iServer.FileSession().IsFileOpen((*dir)[fCount].iName, open));
+				if (open)
+					User::Leave(KErrInUse);
+				}
+			CleanupStack::PopAndDestroy(); // dir
+			}
+		else if (error != KErrPathNotFound)
+			User::Leave(error);
+		}
+	}
+
+
+TInt CMsvMove::SetupStoreCopy()
+//
+//
+//
+	{
+	TFileName storeName;
+	iServer.GetEntryName(iCurrentEntry->Id(), storeName, EFalse);
+
+	TFileName targetPath(*iTargetPath);
+	TBuf<1> dir;
+	dir.NumFixedWidth(iCurrentEntry->Id()&0xf, EHex, 1);
+	targetPath.Append(dir);
+	_LIT(KDirSep,"\\");
+	targetPath.Append(KDirSep);
+	iServer.FileSession().MkDirAll(targetPath); // ignore errors, if it failed to create the directory the next line will fail
+	return iFileMan->Copy(storeName, targetPath, CFileMan::EOverWrite, iStatus);
+	}
+
+
+TInt CMsvMove::SetupFileCopy()
+//
+//
+//
+	{
+	// construct source directory
+	TFileName sourceFileDirectory;
+	iServer.GetEntryName(iCurrentEntry->Id(), sourceFileDirectory, ETrue);
+	sourceFileDirectory.Append(KFileWildCard);
+	// construct target directory
+	TFileName targetFileDirectory(*iTargetPath);
+	TBuf<KFileNameFixedWidth> dir;
+	dir.NumFixedWidth(iCurrentEntry->Id()&0xf, EHex, 1);
+	targetFileDirectory.Append(dir);
+	_LIT(KDirSep,"\\");
+	targetFileDirectory.Append(KDirSep);
+	dir.NumFixedWidth(iCurrentEntry->Id(), EHex, KFileNameFixedWidth);
+	targetFileDirectory.Append(dir);
+	targetFileDirectory.Append(KMsvBinaryFolderExt);
+	// setup the copy
+	return iFileMan->Copy(sourceFileDirectory, targetFileDirectory, CFileMan::EOverWrite|CFileMan::ERecurse, iStatus);
+	}
+
+
+
+void CMsvMove::StartL(TMsvId aId, TMsvId aTarget)
+//
+//
+//
+	{
+	// Fail now if the index says it's not available
+	User::LeaveIfError(iServer.IndexAdapter().ErrorState());
+
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+	// Movement of entries across drives not supported.
+	if(GetDriveId(aId) != GetDriveId(aTarget))
+		{
+		User::Leave(KErrNotSupported);
+		}
+#endif		// #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+
+	// check the spource and target exists and which service they are under
+	User::LeaveIfError(iServer.IndexAdapter().OwningService(aId, iSourceService));
+	User::LeaveIfError(iServer.IndexAdapter().OwningService(aTarget, iTargetService));
+	__ASSERT_ALWAYS(iSourceService==iTargetService, PanicServer(EMsvMovingentryAccrossServices));
+
+	// get the index entry
+	iSourceId = aId;
+	iServer.IndexAdapter().GetEntry(iSourceId, iCurrentEntry); // error ignored as entry exists
+	iParentId = iCurrentEntry->Parent();
+	iTargetId = aTarget;
+
+	iDescendents->Reset();
+	iDescendents->AppendL(iSourceId);
+	iNextDescendent=1;
+
+	__ASSERT_DEBUG(iCurrentEntry->Parent()!=iTargetId, PanicServer(EMsvMtmMovingToSameParent));
+
+	// check if the entry has children
+	if (iCurrentEntry->Owner())
+		{
+		// check for moving into a descendent
+		TBool descendent;
+		iServer.IndexAdapter().IsADescendent(aId, aTarget, descendent); // error ignored as both entry exists
+		if (descendent)
+			User::Leave(KErrArgument);
+
+		// get id of all the descendents
+		User::LeaveIfError(iServer.IndexAdapter().ExpandSelectionRecursively(*iDescendents));
+		}
+
+	// check all the entries can be moved
+	CheckEntriesL();
+
+	// move the entry
+	if(!iCurrentEntry->VisibleFolderFlag())
+	    {
+	    User::LeaveIfError(iServer.IndexAdapter().MoveEntry(iSourceId, iTargetId, iDescendents));   
+	    }
+	else 
+	    {
+	    User::LeaveIfError(iServer.IndexAdapter().MoveEntry(iSourceId, iTargetId)); 
+	    }
+	
+	// release the locks
+	TInt count = iDescendents->Count();
+	while (count--)
+		{
+		iServer.IndexAdapter().ReleaseEntryAndStore(iDescendents->At(count)); // error ignored
+		}
+
+	iLockedIndex=-2;
+	}
+
+//**********************************
+// CMsvMoveEntries
+//**********************************
+
+// static
+CMsvMoveEntries* CMsvMoveEntries::NewL(CMsvServer& aServer)
+//
+//
+//
+	{
+	CMsvMoveEntries* self = new(ELeave) CMsvMoveEntries();
+	CleanupStack::PushL(self);
+	self->ConstructL(aServer);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+CMsvMoveEntries::CMsvMoveEntries() :
+	CMsvCopyMoveEntriesBase()
+//
+//
+//
+	{}
+
+
+CMsvMoveEntries::~CMsvMoveEntries()
+//
+//
+//
+	{
+	delete iMove;
+	}
+
+
+void CMsvMoveEntries::ConstructL(CMsvServer& aServer)
+//
+//
+//
+	{
+	iMove = CMsvMove::NewL(aServer);
+	CMsvCopyMoveEntriesBase::ConstructL();
+	}
+
+
+void CMsvMoveEntries::DoCancel()
+//
+//
+//
+	{
+	iMove->Cancel();
+	User::RequestComplete(iObserverStatus, KErrCancel);
+	}
+
+
+void CMsvMoveEntries::DoStartL(TMsvId aSourceId, TMsvId aTargetId, TRequestStatus& aObserverStatus)
+//
+//
+//
+	{
+	iMove->StartL(aSourceId, aTargetId, aObserverStatus);
+	}