messagingfw/msgsrvnstore/server/src/CMsvAttachmentManager.cpp
changeset 0 8e480a14352b
child 22 d2c4c66342f3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/CMsvAttachmentManager.cpp	Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,682 @@
+// Copyright (c) 2004-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 <msvstore.h>
+#include <f32file.h>
+
+#include "CMsvAttachmentManager.h"
+#include <mmsvstoremanager.h>
+#include "CCopyOneFile.h"
+#include "CMsvAttachmentRename.h"
+#include "TMsvServerStoreManager.h"
+
+const TUid KMsvEntryAttachmentInfo={0x10202D55};
+_LIT(KTxtRenameLockFile, "_Rename_._");
+
+CMsvAttachmentManager* CMsvAttachmentManager::NewL(CMsvStore& aStore, MMsvStoreManager& aStoreManager, const TMsvId aEntryId, RFs& aFs, TBool aReadOnly)
+	{
+	CMsvAttachmentManager* me = new(ELeave) CMsvAttachmentManager(aStore, aStoreManager, aEntryId, aFs, aReadOnly);
+	CleanupStack::PushL(me);
+	me->ConstructL();
+	CleanupStack::Pop(me);
+	return me;
+	}
+	
+CMsvAttachmentManager::CMsvAttachmentManager(CMsvStore& aStore, MMsvStoreManager& aStoreManager, const TMsvId aEntryId, RFs& aFs, TBool aReadOnly)
+	:CActive(EPriorityStandard), iStore(aStore), iStoreManager(aStoreManager), iEntryId(aEntryId), iFs(aFs), iReadOnly(aReadOnly)
+	{
+	CActiveScheduler::Add(this);
+	}
+	
+void CMsvAttachmentManager::ConstructL()
+	{
+	// Only need the CCopyOneFile if attachment is not readonly
+	if( !iReadOnly )
+		iCopyOneFile = CCopyOneFile::NewL(iFs);
+	
+	// Populate the array of attachments from store file that contains all of the data
+	RestoreL();
+	}
+	
+CMsvAttachmentManager::~CMsvAttachmentManager()
+	{
+	Cancel();
+	
+	// if we have any added attachments, these must be deleted as they have not been committed
+	TInt addedAttachmentCount = iAddedAttachments.Count();
+	for( TInt ii=0; ii<addedAttachmentCount; ++ii )
+		{
+		iStoreManager.DeleteAttachment(iEntryId, *iAddedAttachments[ii]); // ignore return code
+		}
+		
+	iAddedAttachments.ResetAndDestroy();
+	iDeletedAttachments.ResetAndDestroy();	
+	iAttachments.ResetAndDestroy();
+	iRenamed.ResetAndDestroy();
+	delete iCopyOneFile;
+	}
+
+void CMsvAttachmentManager::RunL()
+	{
+	User::LeaveIfError(iStatus.Int());
+	
+	User::RequestComplete(iReportStatus, KErrNone);
+	}
+	
+void CMsvAttachmentManager::DoCancel()
+	{
+	__ASSERT_DEBUG(iCopyOneFile!=NULL, User::Invariant());
+	
+	if( iCopyOneFile->IsActive() )
+		iCopyOneFile->Cancel();
+	}
+
+TInt CMsvAttachmentManager::RunError(TInt aError)
+	{
+	// Asynchronous request only occur when an attachment is added
+	// so delete the last added attachment
+	TInt count = iAttachments.Count();
+	--count;
+	if (count > 0)
+		{
+		delete iAttachments[count];
+		iAttachments.Remove(count);
+		}
+
+	count = iAddedAttachments.Count();
+	--count;
+	if (count > 0)
+		{
+		delete iAddedAttachments[count];
+		iAddedAttachments.Remove(count);
+		}
+	User::RequestComplete(iReportStatus, aError);
+	return KErrNone;
+	}
+
+void CMsvAttachmentManager::CompleteSelf()
+	{
+	iStatus=KRequestPending;
+	SetActive();
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	}
+	
+void CMsvAttachmentManager::RestoreL()
+	{
+	// Before loading, ensure that array is flushed out, all changes since last
+	// store commit will be lost
+	iAttachments.ResetAndDestroy();
+	iDeletedAttachments.ResetAndDestroy();
+	
+	// if any added attachment file were added since the last commit, these must be removed
+	TInt addedAttachmentCount = iAddedAttachments.Count();
+	for( TInt ii=0; ii<addedAttachmentCount; ++ii )
+		{
+		iStoreManager.DeleteAttachment(iEntryId, *iAddedAttachments[ii]); // ignore return error
+		}
+	// All the added attachments have been cleaned up, reset the list
+	iAddedAttachments.ResetAndDestroy();
+	
+	// Only load the attachment info stream if one exists
+	if(iStore.IsPresentL(KMsvEntryAttachmentInfo))
+		{	
+		RMsvReadStream readStream;
+		readStream.OpenLC(iStore, KMsvEntryAttachmentInfo);
+		
+		// Read the data...
+		// 1. the number of attachments
+		TInt attachmentCount = readStream.ReadInt32L();
+		
+		TFileName attachmentFilePath;
+		
+		// 2. populate the attachment array contents
+		// for every object create and populate it from the stream
+		for(TInt ii=0; ii<attachmentCount; ++ii)
+			{
+			// create empty attachment object, doesn't matter what type as the
+			// correct attachment type is set when it is internalised
+			CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+			CleanupStack::PushL(attachment);
+			readStream >> *attachment;
+			if( attachment->IsPathRequired() )
+				{
+				// The attachment path needs to be dynamically set, only get the file path if needed
+				if( attachmentFilePath.Length()==0 )
+					{
+					iStoreManager.AttachmentFilePathL(iEntryId, attachmentFilePath);
+					}
+				
+				TParse fullPath;
+				User::LeaveIfError(fullPath.Set(attachmentFilePath, &attachment->FilePath(), NULL));
+				attachment->SetFilePathL(fullPath.FullName());
+				}
+				
+			User::LeaveIfError(iAttachments.Append(attachment));
+			CleanupStack::Pop(attachment);
+			}
+			
+		// 3. attachment id generator
+		iIdGenerator = readStream.ReadUint32L();
+		
+		CleanupStack::PopAndDestroy(&readStream);
+		}
+		
+	// Restore any rename info from the rename lock file
+	TInt err = InternaliseRenameLockL();
+	if( err==KErrNone )
+		{
+		// lock file exists
+		TInt currentIndex = iRenamed.Count();
+		while( currentIndex>0 )
+			{
+			// We have some files that have been renamed and need to
+			// be renamed back to the old name, these are renamed in
+			// reverse order in case any one single attachment was
+			// renamed twice before committing.
+			--currentIndex;
+			CMsvAttachmentRename* renameInfo = iRenamed[currentIndex];
+			iStoreManager.RenameAttachment(iEntryId, renameInfo->NewName(), renameInfo->OldName()); // ignore errors
+			}
+			
+		iRenamed.ResetAndDestroy();
+		
+		// delete the lock file as it no longer needed
+		iStoreManager.DeleteAttachment(iEntryId, KTxtRenameLockFile); // ignore return error
+		}
+	}
+	
+void CMsvAttachmentManager::HandleCommitComplete()
+	{
+	// The attachments have been commited, the cache of added files can be removed
+	iAddedAttachments.ResetAndDestroy();
+	
+	// Any attachment files that are marked for delete, must be deleted from the message store
+	TInt deleteAttachmentCount = iDeletedAttachments.Count();
+	for( TInt ii=0; ii<deleteAttachmentCount; ++ii )
+		{
+		iStoreManager.DeleteAttachment(iEntryId, *iDeletedAttachments[ii]); // ignore errors
+		}
+	iDeletedAttachments.ResetAndDestroy();
+	
+	// Remove the rename info as changes have been committed
+	iStoreManager.DeleteAttachment(iEntryId, KTxtRenameLockFile); // ignore return error
+	iRenamed.ResetAndDestroy();
+	}
+	
+void CMsvAttachmentManager::StoreL()
+	{
+	__ASSERT_DEBUG(iReadOnly==EFalse, User::Invariant());
+	
+	TInt attachmentCount = iAttachments.Count();
+	
+	// If there are no attachments, remove the stream
+	if(attachmentCount==0)
+		{
+		iStore.Remove(KMsvEntryAttachmentInfo);
+		}
+	else
+		{
+		RMsvWriteStream writeStream;
+		writeStream.AssignLC(iStore, KMsvEntryAttachmentInfo);
+		
+		// Write the data...
+		// 1. the number of attachments
+		writeStream.WriteInt32L(attachmentCount);
+		
+		// 2. save the attachment array contents
+		// for every object create and populate it from the stream
+		for(TInt ii=0; ii<attachmentCount; ++ii)
+			{
+			CMsvAttachment* attachment = iAttachments[ii];
+			writeStream << *attachment;
+			}
+		
+		// 3. attachment id generator
+		writeStream.WriteUint32L(iIdGenerator);
+		
+		writeStream.CommitL();
+		CleanupStack::PopAndDestroy(&writeStream);
+		}
+	}
+
+TMsvAttachmentId CMsvAttachmentManager::GenerateAttachmentId()
+	{
+	return ++iIdGenerator;
+	}
+	
+void CMsvAttachmentManager::CreateAttachmentInStoreLC(TDes& aFileName, RFile& aFile, CMsvAttachment* aAttachmentInfo, TBool aIsShareProtected)
+	{
+	if( aFileName.CompareF(KTxtRenameLockFile)==0 )
+		{
+		// Cant add attachments using the same name as the rename lock file
+		User::Leave(KErrBadName);
+		}
+	
+	if(aIsShareProtected)
+		{
+		iStoreManager.CreateShareProtectedAttachmentForWriteL(iEntryId, aFileName, aFile);
+		}
+	else
+		{				
+		iStoreManager.CreateAttachmentForWriteL(iEntryId, aFileName, aFile);
+		}
+	
+	CleanupClosePushL(aFile);
+	
+	HBufC* addedFilePath = aFileName.AllocLC();
+	User::LeaveIfError(iAddedAttachments.Append(addedFilePath));
+	CleanupStack::Pop(addedFilePath);
+	
+	// initailise attachment info and take ownership
+	aAttachmentInfo->SetFilePathL(aFileName);
+	User::LeaveIfError(iAttachments.Append(aAttachmentInfo));
+	aAttachmentInfo->SetId(GenerateAttachmentId());
+	}
+
+void CMsvAttachmentManager::AddAttachmentL(const TDesC& aFilePath, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	__ASSERT_ALWAYS(aAttachmentInfo->Type() == CMsvAttachment::EMsvFile, User::Invariant());
+
+	RFile fileToCopy;
+	User::LeaveIfError(fileToCopy.Open(iFs, aFilePath, EFileRead|EFileShareReadersOnly));
+	CleanupClosePushL(fileToCopy);
+	
+	TFileName fileName;
+	User::LeaveIfError(fileToCopy.Name(fileName));
+	
+	RFile newFileHandle;
+	CreateAttachmentInStoreLC(fileName, newFileHandle, aAttachmentInfo, EFalse);
+
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	
+	iCopyOneFile->Copy(fileToCopy, newFileHandle, iStatus);
+	CleanupStack::Pop(2, &fileToCopy); // newFileHandle, fileToCopy
+	SetActive();
+	}
+		
+void CMsvAttachmentManager::AddAttachmentL(RFile& aFileHandle, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	__ASSERT_ALWAYS(aAttachmentInfo->Type() == CMsvAttachment::EMsvFile, User::Invariant());
+	
+	TFileName fileName;
+	User::LeaveIfError(aFileHandle.Name(fileName));
+	
+	RFile newFileHandle;
+	CreateAttachmentInStoreLC(fileName, newFileHandle, aAttachmentInfo, EFalse);
+	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	
+	iCopyOneFile->Copy(aFileHandle, newFileHandle, iStatus);
+	CleanupStack::Pop(&newFileHandle);
+	SetActive();
+	}
+
+void CMsvAttachmentManager::AddLinkedAttachmentL(const TDesC& aFilePath, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	__ASSERT_ALWAYS(aAttachmentInfo->Type() == CMsvAttachment::EMsvLinkedFile, User::Invariant());
+	
+	// initailise attachment info and take ownership
+	aAttachmentInfo->SetFilePathL(aFilePath);
+	User::LeaveIfError(iAttachments.Append(aAttachmentInfo));
+	aAttachmentInfo->SetId(GenerateAttachmentId());
+	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	CompleteSelf();
+	}
+	
+void CMsvAttachmentManager::AddEntryAsAttachmentL(TMsvId aEntryId, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	__ASSERT_ALWAYS(aAttachmentInfo->Type() == CMsvAttachment::EMsvMessageEntry, User::Invariant());
+	
+	// initailise attachment info and take ownership
+	User::LeaveIfError(iAttachments.Append(aAttachmentInfo));
+	aAttachmentInfo->SetId(GenerateAttachmentId());
+	aAttachmentInfo->SetEntryAttachmentId(aEntryId);
+	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	User::RequestComplete(iReportStatus, KErrNone);
+	}
+	
+void CMsvAttachmentManager::CreateAttachmentL(const TDesC& aFileName, RFile& aAttachmentFile, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	CreateAttachmentL(aFileName, aAttachmentFile, aAttachmentInfo);
+	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	CompleteSelf();
+	}
+	
+	
+TInt CMsvAttachmentManager::AttachmentCount() const
+	{
+	return iAttachments.Count();
+	}
+	
+CMsvAttachment* CMsvAttachmentManager::GetAttachmentInfoL(TInt aIndex)
+	{
+	// Create a deep copy the CMsvAttachment object to pass back to the client
+	CMsvAttachment* currentAttachment = iAttachments[aIndex];
+	
+	return CMsvAttachment::NewL(*currentAttachment);
+	}
+
+CMsvAttachment* CMsvAttachmentManager::GetAttachmentInfoL(TMsvAttachmentId aId)
+	{
+	return GetAttachmentInfoL(IndexPositionOfAttachmentL(aId));
+	}
+
+void CMsvAttachmentManager::ModifyAttachmentInfoL(CMsvAttachment* aAttachmentInfo)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	// Get the index position of the attachment info with the same Id
+	TInt attachmentIndex = IndexPositionOfAttachmentL(aAttachmentInfo->Id());
+	__ASSERT_ALWAYS(aAttachmentInfo->Type()==iAttachments[attachmentIndex]->Type(), User::Invariant());
+	
+	// Insert the replaced attachment info object into the same position and then
+	// remove the old one
+	User::LeaveIfError(iAttachments.Insert(aAttachmentInfo, attachmentIndex));
+	++attachmentIndex;
+	delete iAttachments[attachmentIndex];
+	iAttachments.Remove(attachmentIndex);
+	}
+	
+void CMsvAttachmentManager::ModifyAttachmentInfoL(CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	ModifyAttachmentInfoL(aAttachmentInfo);	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	CompleteSelf();
+	}
+
+RFile CMsvAttachmentManager::GetAttachmentFileL(TInt aIndex)
+	{
+	CMsvAttachment* attachment = iAttachments[aIndex];
+	
+	// Make sure that the attachment is a file attachment
+	if( attachment->Type() == CMsvAttachment::EMsvMessageEntry )
+		User::Leave(KErrNotSupported);
+	
+	RFile attachmentFile;
+	
+	if( attachment->Type() == CMsvAttachment::EMsvFile )
+		{		
+		iStoreManager.OpenAttachmentL(iEntryId, attachment->FilePath(), attachmentFile);
+		}
+	else // attachment->iType == ELinkedFile
+		{
+		RFs fs;
+		fs.Connect();
+		fs.ShareProtected();
+		User::LeaveIfError(attachmentFile.Open(fs, attachment->FilePath(), EFileRead | EFileShareReadersOnly));
+		}
+	
+	// handle to attachment file allocated, return to caller
+	return attachmentFile;
+	}
+
+RFile CMsvAttachmentManager::GetAttachmentFileL(TMsvAttachmentId aId)
+	{
+	return GetAttachmentFileL(IndexPositionOfAttachmentL(aId));
+	}
+
+RFile CMsvAttachmentManager::GetAttachmentFileForWriteL(TInt aIndex)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	CMsvAttachment* attachment = iAttachments[aIndex];
+	
+	// Make sure that the attachment is a file attachment
+	if( attachment->Type() == CMsvAttachment::EMsvMessageEntry )
+		User::Leave(KErrNotSupported);
+	
+	RFile attachmentFile;
+	
+	if( attachment->Type() == CMsvAttachment::EMsvFile )
+		{		
+		iStoreManager.OpenAttachmentForWriteL(iEntryId, attachment->FilePath(), attachmentFile);
+		}
+	else // attachment->iType == ELinkedFile
+		{
+		RFs fs;
+		fs.Connect();
+		fs.ShareProtected();
+		User::LeaveIfError(attachmentFile.Open(fs, attachment->FilePath(), EFileWrite));
+		}
+	
+	// handle to attachment file allocated, return to caller
+	return attachmentFile;
+	}
+
+RFile CMsvAttachmentManager::GetAttachmentFileForWriteL(TMsvAttachmentId aId)
+	{
+	return GetAttachmentFileForWriteL(IndexPositionOfAttachmentL(aId));
+	}
+	
+void CMsvAttachmentManager::RemoveAttachmentL(TInt aIndex, TRequestStatus& aStatus)
+	{
+	RemoveAttachmentL(aIndex);
+	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	CompleteSelf();
+	}
+	
+void CMsvAttachmentManager::RemoveAttachmentL(TMsvAttachmentId aId, TRequestStatus& aStatus)
+	{
+	RemoveAttachmentL(IndexPositionOfAttachmentL(aId), aStatus);
+	}
+
+TInt CMsvAttachmentManager::IndexPositionOfAttachmentL(TMsvAttachmentId aId) const
+	{
+	TInt foundPosition = KErrNotFound;
+	TInt attachmentCount = iAttachments.Count();
+	// Go through the attachment list to find the attachment by its id
+	for( TInt ii=0; ii<attachmentCount; ++ii )
+		{
+		if( iAttachments[ii]->Id() == aId )
+			{
+			foundPosition = ii;
+			break;
+			}
+		}
+		
+	// Leave with KErrNotFound if the attachment id is not found
+	User::LeaveIfError(foundPosition);
+	
+	// return the index position of attachment
+	return foundPosition;
+	}
+
+void CMsvAttachmentManager::CancelRequest()
+	{
+	Cancel();
+	User::RequestComplete(iReportStatus, KErrCancel);
+	}
+	
+void CMsvAttachmentManager::CreateAttachmentL(const TDesC& aFileName, RFile& aAttachmentFile, CMsvAttachment* aAttachmentInfo)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	__ASSERT_ALWAYS(aAttachmentInfo->Type() == CMsvAttachment::EMsvFile, User::Invariant());
+	
+	// File name must be provided
+	if( aFileName.Length() == 0 || aAttachmentFile.SubSessionHandle() != KNullHandle)
+		User::Leave(KErrArgument);
+	
+	TFileName fileName = aFileName;
+	
+	CreateAttachmentInStoreLC(fileName, aAttachmentFile, aAttachmentInfo, EFalse);
+	CleanupStack::Pop(&aAttachmentFile);
+	}
+
+void CMsvAttachmentManager::CreateShareProtectedAttachmentL(const TDesC& aFileName, RFile& aAttachmentFile, CMsvAttachment* aAttachmentInfo)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	__ASSERT_ALWAYS(aAttachmentInfo->Type() == CMsvAttachment::EMsvFile, User::Invariant());
+	
+	// File name must be provided
+	if( aFileName.Length() == 0 || aAttachmentFile.SubSessionHandle() != KNullHandle)
+		User::Leave(KErrArgument);
+	
+	TFileName fileName = aFileName;
+	
+	CreateAttachmentInStoreLC(fileName, aAttachmentFile, aAttachmentInfo, ETrue);
+	CleanupStack::Pop(&aAttachmentFile);
+	}
+	
+TInt CMsvAttachmentManager::InternaliseRenameLockL()
+	{
+	iRenamed.ResetAndDestroy();
+	
+	// if the rename lock file exists internalise it
+	RFile renameLockFile;
+	TRAPD(err, iStoreManager.OpenAttachmentL(iEntryId, KTxtRenameLockFile, renameLockFile));
+	if( err==KErrNone )
+		{
+		// got the rename lock file
+		RFileReadStream renameReadStream(renameLockFile);
+		renameReadStream.PushL();
+		TInt renamedCount = renameReadStream.ReadInt32L();
+		for( TInt ii=0; ii<renamedCount; ++ii )
+			{
+			CMsvAttachmentRename* renameInfo = CMsvAttachmentRename::NewLC();
+			renameReadStream >> *renameInfo;
+			iRenamed.AppendL(renameInfo);
+			CleanupStack::Pop(renameInfo);
+			}
+		CleanupStack::PopAndDestroy(); // renameReadStream
+		}
+	else if( err==KErrNotFound || err==KErrPathNotFound )
+		{
+		err = KErrNotFound; // rename lock file not found
+		}
+	else
+		{
+		User::Leave(err);
+		}
+		
+	return err; 
+	}
+	
+void CMsvAttachmentManager::ExternaliseRenameLockL()
+	{
+	__ASSERT_DEBUG(iRenamed.Count()>0, User::Invariant());
+	
+	// Get the rename lock file to store the rename information
+	RFile renameLockFile;
+	TFileName lockFileName(KTxtRenameLockFile());
+	iStoreManager.ReplaceAttachmentForWriteL(iEntryId, lockFileName, renameLockFile);
+	RFileWriteStream renameWriteStream(renameLockFile);
+	renameWriteStream.PushL();
+	
+	// Externalise the count and each rename file info object
+	TInt renamedCount = iRenamed.Count();
+	renameWriteStream.WriteInt32L(renamedCount);
+	for( TInt ii=0; ii<renamedCount; ++ii )
+		{
+		renameWriteStream << *(iRenamed[ii]);
+		}
+	
+	renameWriteStream.CommitL();	
+	CleanupStack::PopAndDestroy(); // renameWriteStream
+	}
+	
+void CMsvAttachmentManager::DoAttachmentRenameL(TInt aIndex, const TDesC& aNewName)
+	{
+	if(iReadOnly)
+		{
+		User::Leave(KErrAccessDenied);
+		}
+	
+	CMsvAttachment* renameAttachment = iAttachments[aIndex];	
+	__ASSERT_ALWAYS(renameAttachment->Type() == CMsvAttachment::EMsvFile, User::Invariant());	
+	
+	// Build the attachment rename infomation and store in array
+	TPtrC oldFilePath(renameAttachment->FilePath());
+	CMsvAttachmentRename* renameInfo = CMsvAttachmentRename::NewLC(oldFilePath, aNewName);
+	iRenamed.AppendL(renameInfo);
+	CleanupStack::Pop(renameInfo);
+	
+	// Save the rename infomation
+	ExternaliseRenameLockL();
+	
+	// Rename and update the attachment info
+	TParse newFilePath;
+	User::LeaveIfError(newFilePath.Set(aNewName, &oldFilePath, NULL));
+	User::LeaveIfError(iStoreManager.RenameAttachment(iEntryId, oldFilePath, aNewName));
+	renameAttachment->SetFilePathL(newFilePath.FullName());
+	}
+	
+void CMsvAttachmentManager::RenameAttachmentL(TInt aIndex, const TDesC& aNewName)
+	{
+    DoAttachmentRenameL(aIndex, aNewName);
+	}
+
+void CMsvAttachmentManager::RenameAttachmentL(TInt aIndex, const TDesC& aNewName, TRequestStatus& aStatus)
+	{
+	DoAttachmentRenameL(aIndex, aNewName);
+	
+	aStatus=KRequestPending;
+	iReportStatus=&aStatus;
+	User::RequestComplete(iReportStatus, KErrNone);			
+	}
+
+void CMsvAttachmentManager::RemoveAttachmentL(TInt aIndex)
+	{
+	if(iReadOnly)
+		User::Leave(KErrAccessDenied);
+	
+	// If the attachment is a file attachment, we need remove the attachment object
+	// and mark the file for deletion so that it is deleted only when SaveL is called.
+	// This ensures that if the store is reverted, the attachment files are still in
+	// the message store
+	CMsvAttachment* deleteAttachment = iAttachments[aIndex];
+	
+	// only need to mark the file for deletion if it is an attachment stored in the
+	// message server, ie. dont delete linked attachments
+	if( deleteAttachment->Type() == CMsvAttachment::EMsvFile )
+		{
+		HBufC* deleteFilePath = deleteAttachment->FilePath().AllocLC();
+		User::LeaveIfError(iDeletedAttachments.Append(deleteFilePath));
+		CleanupStack::Pop(deleteFilePath);
+		} 
+	
+	iAttachments.Remove(aIndex);
+	delete deleteAttachment;
+	}
+