diff -r 000000000000 -r 8e480a14352b messagingfw/msgsrvnstore/server/src/CMsvAttachmentManager.cpp --- /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 +#include + +#include "CMsvAttachmentManager.h" +#include +#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; iiIsActive() ) + 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> *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; iiSetFilePathL(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; iiId() == 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> *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; iiType() == 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; + } +