email/imap4mtm/imapmailstore/src/cattachmentqueueentry.cpp
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/imap4mtm/imapmailstore/src/cattachmentqueueentry.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,380 @@
+// Copyright (c) 2006-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 <mmsvattachmentmanager.h>
+#include <mmsvattachmentmanagersync.h>
+#include <imcvtext.h>
+#include <miuthdr.h>
+#include "cattachmentqueueentry.h"
+#include "cimaputils.h"
+#include "cimaplogger.h"
+
+/**
+Used to sort chunks of data by chunk number.
+@param aChunkAttachmentInfo1 	the first chunk in the comparision
+@param aChunkAttachmentInfo2 	the second chunk in the comparision
+@return TInt					the difference between the first chunks number and the second chunks number.
+*/	
+TInt CAttachmentQueueEntry::CompareChunks(const CChunkAttachmentInfo& aChunkAttachmentInfo1, const CChunkAttachmentInfo& aChunkAttachmentInfo2)
+	{
+	return aChunkAttachmentInfo1.iChunkNumber-aChunkAttachmentInfo2.iChunkNumber;	
+	}
+
+/**
+Constructor.
+*/
+CChunkAttachmentInfo::CChunkAttachmentInfo(TInt aChunkNumber,HBufC8* aData)
+:iChunkNumber(aChunkNumber),iData(aData)
+	{
+	}
+
+/**
+Destructor.
+*/	
+CChunkAttachmentInfo::~CChunkAttachmentInfo()
+	{
+	delete iData;
+	}
+		
+/**
+Constructor.
+*/
+CAttachmentQueueEntry::CAttachmentQueueEntry(TInt aTotalChunks,CImapMailStore& aParent,CMsvServerEntry& aServerEntry,CImapSettings& aImapSettings,CFetchBodyInfo& aFetchBodyInfo,TInt aLogId,MMailStoreObserver& aObserver)
+	: CQueueEntryBase(aFetchBodyInfo.PartId(),EAttachment,aParent,aServerEntry,aObserver),
+	iTotalChunks(aTotalChunks),
+	iEncoding(aFetchBodyInfo.ContentTransferEncoding()),
+	iImapSettings(aImapSettings),
+	iCaf(aFetchBodyInfo.Caf()),
+	iLogId(aLogId)
+	{
+	}
+	
+/**
+Destructor.
+*/
+CAttachmentQueueEntry::~CAttachmentQueueEntry()
+	{
+	iFile.Close();
+	iDataArray.ResetAndDestroy();
+	delete iStoreUtilities;
+	delete iDecodedData;
+	iDataArray.Close();
+	}
+
+/**
+Factory constructors.
+*/
+CAttachmentQueueEntry* CAttachmentQueueEntry::NewL(TInt aTotalChunks,CImapMailStore& aParent,CMsvServerEntry& aServerEntry,CImapSettings& aImapSettings,CFetchBodyInfo& aFetchBodyInfo,TInt aLogId,MMailStoreObserver& aObserver)
+	{
+	CAttachmentQueueEntry* self=new(ELeave)CAttachmentQueueEntry(aTotalChunks,aParent,aServerEntry,aImapSettings,aFetchBodyInfo,aLogId,aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();	
+	CleanupStack::Pop();
+	return self;
+	}
+	
+void CAttachmentQueueEntry::ConstructL()
+	{
+	BaseConstructL();
+	iServerEntry.SetEntry(iId);	
+	//create an attachment ready for downloading	
+	CreateAttachmentL(iServerEntry);
+	//charsetId is not used by attachments
+	TUint charsetId=0;
+	iStoreUtilities=CStoreUtilities::NewL(iEncoding,charsetId, CImapUtils::GetRef().Fs());
+	}
+
+/**
+Adds a chunk of attachment data to the data array and sorts the array
+@param aData 			the attachment data, ownership  is taken.
+@param aChunkNumber 	the order number in which the chunk makes up the whole data.
+@return 
+*/	
+void CAttachmentQueueEntry::AddChunkL(HBufC8* aData,TInt aChunkNumber)
+	{
+	__LOG_FORMAT((iLogId, "CAttachmentQueueEntry::AddChunkL chunk number = %d",aChunkNumber));
+	CleanupStack::PushL(aData);
+	__ASSERT_DEBUG(aChunkNumber<iTotalChunks,TImapServerPanic::ImapPanic(TImapServerPanic::EMailStoreDataChunkOutOfRange));
+	
+ 	CChunkAttachmentInfo* chunkInfo = new(ELeave) CChunkAttachmentInfo(aChunkNumber,aData); 	
+ 	CleanupStack::PushL(chunkInfo);
+	TLinearOrder<CChunkAttachmentInfo>compareChunks(CompareChunks);
+   	iDataArray.InsertInOrderL(chunkInfo,compareChunks);
+    CleanupStack::Pop(2,aData);
+    
+    if(!IsActive())
+		{
+  	  	CompleteSelf();	
+		}
+	}
+	
+/**
+Creates and stores an CMsvAttachment object and an empty file as a place holder for an attachment
+	    that is not currently being downloaded.
+@param 	aServerEntry entry used to access the store.
+		aFile used to create the attachment file.
+@return
+*/
+void CAttachmentQueueEntry::CreateAttachmentInfoL(CMsvServerEntry& aServerEntry,RFile& aFile)
+	{
+	CMsvStore* store = aServerEntry.EditStoreL();
+	CleanupStack::PushL(store);
+
+	MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+
+	TInt attachmentCount=attachmentMgr.AttachmentCount();
+	// if we are just regestering that the attachment exists we dont need to do any more. 
+	// need to do anything	
+	if(attachmentCount!=0)
+		{
+		CleanupStack::PopAndDestroy(store);
+		return;
+		}
+	
+	MMsvAttachmentManagerSync& attachmentMgrSync = store->AttachmentManagerExtensionsL();
+	// Now create the attachment entry
+	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	CleanupStack::PushL(attachment);
+	
+	// Need to create the MIME-type information - first get the MIME headers
+	//check if their present if not leave the mime type blank
+	if(store->IsPresentL(KUidMsgFileMimeHeader))
+		{
+		CImMimeHeader* mimeHeaders = CImMimeHeader::NewLC();
+		mimeHeaders->RestoreL(*store);
+
+		HBufC8* buf = HBufC8::NewLC(mimeHeaders->ContentSubType().Length() + mimeHeaders->ContentType().Length() + 1);
+		TPtr8 ptr(buf->Des());
+		ptr.Copy(mimeHeaders->ContentType());
+		ptr.Append(KImcvForwardSlash);
+		ptr.Append(mimeHeaders->ContentSubType());
+		//set the mime time
+		attachment->SetMimeTypeL(ptr);
+		CleanupStack::PopAndDestroy(2, mimeHeaders);	
+		}
+
+	//set flags	
+	attachment->SetAttachmentNameL(aServerEntry.Entry().iDetails);	
+	attachment->SetComplete(EFalse);
+	//if not downloading then set the size here
+	attachment->SetSize(aServerEntry.Entry().iSize);
+	//Creates an empty file representing the attachment, used by MMsvAttachmentManagerSync
+	attachmentMgrSync.CreateAttachmentL(aServerEntry.Entry().iDetails,aFile,attachment);
+ 	// ownership passed to attachment manager
+	CleanupStack::Pop(attachment);	
+	//commit changes
+	store->CommitL();
+	CleanupStack::PopAndDestroy(store);
+	}
+	
+/**
+Creates and stores a CMsvAttachment object and file representing the attachment being downloaded.
+@param 	aServerEntry entry used to access the store.			
+@return
+*/
+void CAttachmentQueueEntry::CreateAttachmentL(CMsvServerEntry& aServerEntry)
+	{
+	__LOG_FORMAT((iLogId, "CAttachmentQueueEntry::CreateAttachmentL"));
+	
+	CMsvStore* store = aServerEntry.EditStoreL();
+	CleanupStack::PushL(store);
+
+	MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+
+	TInt attachmentCount=attachmentMgr.AttachmentCount();
+
+	//delete existing attachments
+	for(TInt i=0;i<attachmentCount;++i)
+		{
+		// Remove [0] as array is shuffled. Once index [n] is removed n+1 becomes n
+		store->AttachmentManagerExtensionsL().RemoveAttachmentL(0);
+		}
+	if(attachmentCount)
+		{
+		store->CommitL();	
+		}	
+
+	MMsvAttachmentManagerSync& attachmentMgrSync = store->AttachmentManagerExtensionsL();
+	// Now create the attachment entry
+	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	CleanupStack::PushL(attachment);
+	
+	// Need to create the MIME-type information - first get the MIME headers
+	//check if their present if not leave the mime type blank
+	if(store->IsPresentL(KUidMsgFileMimeHeader))
+		{
+		CImMimeHeader* mimeHeaders = CImMimeHeader::NewLC();
+		mimeHeaders->RestoreL(*store);
+
+		HBufC8* buf = HBufC8::NewLC(mimeHeaders->ContentSubType().Length() + mimeHeaders->ContentType().Length() + 1);
+		TPtr8 ptr(buf->Des());
+		ptr.Copy(mimeHeaders->ContentType());
+		ptr.Append(KImcvForwardSlash);
+		ptr.Append(mimeHeaders->ContentSubType());
+		//set the mime time
+		attachment->SetMimeTypeL(ptr);
+		CleanupStack::PopAndDestroy(2, mimeHeaders);	
+		}
+
+	//set flags	
+	attachment->SetAttachmentNameL(aServerEntry.Entry().iDetails);	
+	attachment->SetComplete(EFalse);
+	
+	//is caf interested in this attachment?
+	
+	if(iCaf!=NULL && iCaf->Registered())
+		{
+		iCaf->PrepareProcessingL(); // Init the CAF import file session
+		RFile startFile;
+		TFileName suggestedFileName;
+		if(iCaf->GetSuggestedAttachmentFileName(suggestedFileName) == KErrNone) // CAF agent may provide a filename
+			{
+			attachmentMgrSync.CreateAttachmentL(suggestedFileName,startFile,attachment);
+			}
+		else
+			{
+			attachmentMgrSync.CreateAttachmentL(aServerEntry.Entry().iDetails,startFile,attachment);
+			}
+			
+		iCaf->StartProcessing(iImapSettings.DefaultAttachmentName(),attachment->FilePath(),aServerEntry,startFile); // Init the CAF session
+		startFile.Close();
+		}
+	else
+		{
+		// Normal behaviour
+		attachmentMgrSync.CreateAttachmentL(aServerEntry.Entry().iDetails,iFile,attachment);
+		}
+
+	CleanupStack::Pop(attachment);	
+	//commit changes
+	store->CommitL();
+	CleanupStack::PopAndDestroy(store);
+		
+	}
+	
+void CAttachmentQueueEntry::DoCancel()
+	{
+	//there is no way to cancel the RFile::Write() request.	
+	delete iDecodedData;
+	iDecodedData=NULL;
+	}
+	
+	
+void CAttachmentQueueEntry::CancelRequest()
+	{
+	//any error is ingnored
+	TRAP_IGNORE(CancelRequestL());	
+	}
+	
+void CAttachmentQueueEntry::CancelRequestL()
+	{
+	if (iCaf && iCaf->Processing())
+		{
+		iCaf->EndProcessingL();
+		}
+	else
+		{
+		iFile.Flush();
+		iFile.Close();
+		}
+
+	CMsvStore* store = iServerEntry.EditStoreL(); 
+	CleanupStack::PushL(store);
+	// Could be multiple attachments in the folder.
+	TInt attachmentCount = store->AttachmentManagerL().AttachmentCount();
+	for(TInt i=0;i<attachmentCount;i++)
+		{
+		// Remove [0] as array is shuffled. Once index [n] is removed n+1 becomes n
+		store->AttachmentManagerExtensionsL().RemoveAttachmentL(0);
+		}
+	if(attachmentCount)
+		{
+		store->CommitL();	
+		}
+	CleanupStack::PopAndDestroy(store);
+	//create attachment info
+	CreateAttachmentInfoL(iServerEntry,iFile);	
+	}
+	
+TInt CAttachmentQueueEntry::RunError(TInt aError)
+	{
+	delete iDecodedData;
+	iDecodedData=NULL;
+	iDataArray.Close();
+	return CQueueEntryBase::RunError(aError);
+	}
+	
+/**
+Uses an RFile object to asynchronously write the attachment data to the file system.
+@param 	 
+@return
+*/
+void CAttachmentQueueEntry::RunL()
+	{	
+	
+	//if we have just saved a chunk of data to the file store then we can delete the chunk.
+	if(iReadyToRemoveChunk)
+		{
+		delete iDecodedData;
+		iDecodedData=NULL;
+		iReadyToRemoveChunk=EFalse;	
+		}
+		
+	//if we have finished then we close the file and call back to the observer
+	if(iNextExpectedChunk==iTotalChunks)
+		{
+		
+		if(iCaf!=NULL && iCaf->Processing())
+			{
+			__LOG_FORMAT((iLogId, "CAttachmentQueueEntry::RunL finished caf processing..."));
+			iCaf->EndProcessingL();		
+			}
+		else
+			{
+			__LOG_FORMAT((iLogId, "CAttachmentQueueEntry::RunL storing attachment..."));
+			iFile.Close();	
+			}
+		
+		StoreComplete(KErrNone);
+		//request can be removed from the queue
+		iParent.RemoveFromQueueAndDelete(this);	
+		}
+	//if we have an item of contiguous data in the data array then write it to the file asynchronously
+	else if(iDataArray.Count()>0 && iDataArray[0]->iChunkNumber==iNextExpectedChunk )
+		{
+		++iNextExpectedChunk;
+		//is this the last chunk?
+		TBool lastChunk=(iNextExpectedChunk==iTotalChunks);
+		//decode the data
+		iDecodedData=iStoreUtilities->DecodeL(*(iDataArray[0]->iData),lastChunk);
+		
+		if(iCaf!=NULL && iCaf->Processing())
+			{
+			iCaf->WriteData(*iDecodedData);
+			CompleteSelf();
+			}
+		else
+			{
+			iFile.Write(*iDecodedData,iStatus);		
+			SetActive();
+			}
+		//delete the origninal encoded chunk
+		CChunkAttachmentInfo* chunkInfo=iDataArray[0];
+		iDataArray.Remove(0);
+		delete chunkInfo;	
+			
+		iReadyToRemoveChunk=ETrue;
+		}
+	}