email/pop3andsmtpmtm/clientmtms/src/MIUTMSG.CPP
changeset 0 72b543305e3a
child 9 1d7827e39b52
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/clientmtms/src/MIUTMSG.CPP	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,7016 @@
+// 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:
+// MIUTMSG.CPP
+//
+
+#include <e32def.h>
+#include "MIUTMSG.H"
+#include "MIUT_ERR.H"
+#include "IMCMMAIN.H"
+#include "SMTPSET.H"	// CImSmtpSettings
+#include "MIUTRSLV.H"
+#include "MIUTCONV.H"
+#include "POP3SET.H"
+#include "IMAPSET.H"
+#include <msventry.h>
+#include <msvuids.h>
+#include <bautils.h>	// BaflUtils
+#include <barsread.h>	// TResourceReader
+#include <imcm.rsg>
+#include <cntdb.h>
+#include <vcard.h>
+#include <s32mem.h>
+#include <f32file.h>
+#include <apgcli.h> // for recognizeData
+#include <eikenv.h>
+#include <txtrich.h>
+#include <cmsvbodytext.h>
+#include <imcvcodc.h>
+#include <tz.h> //Converting from UTC to local time
+#include <tzconverter.h>
+#include <cmsvplainbodytext.h>
+#include <cmsvattachment.h>
+#include <cmsvmimeheaders.h>
+#include "cimattachmentmanager.h"
+#include <mmsvattachmentmanagersync.h>
+#include <cemailaccounts.h>
+#include "CIMPLAINBODYTEXT.H"
+#include <numberconversion.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
+#include "cimmessagepart.h"
+#include "miut_errconsts.h"
+#include "cimconvertcharconv.h"
+#include "cimconvertheader.h"
+#include <mtmuidsdef.hrh>
+#include "msvconsts.h"
+#endif
+
+const TInt KMaxChunkLength = 1000;
+const TInt KMiutAttachmentListGranularity=8;
+const TInt KVCardFilenameLength=25;
+const TUid KUidMsgTypePCMail = {0x1000412A};
+const TUid KMessageCharSetStreamUid = {0x101FD0E4};
+const TUint8 KMessageCharSetStreamVersion = 1;
+const TInt KRFC2231Encoded = 2;
+_LIT(KEllipsesString,",...");
+_LIT(KSeparatorString,", ");
+_LIT(KMhtmlUrlAmpersand, "&amp;");
+
+
+//
+//CImEmailMessage
+//
+
+/**
+Allocates and creates a new CImEmailMessage object.
+
+@param aEntry
+A CMsvEntry object that relates to a message server entry.
+This object is used by CImEmailMessage to perform operations on particular
+message server entries.  It does not matter what context aEntry happens to
+be focused on.
+
+@return
+A CImEmailMessage message object.
+
+@see CMsvEntry
+*/
+EXPORT_C CImEmailMessage* CImEmailMessage::NewL(CMsvEntry& aEntry)
+	{
+	CImEmailMessage* self = CImEmailMessage::NewLC(aEntry);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+/**
+Allocates and creates a new CImEmailMessage object, leaving the object on the 
+cleanup stack.
+
+@param aEntry
+A CMsvEntry object that relates to a message server entry.
+This object is used by CImEmailMessage to perform operations on particular
+message server entries.  It does not matter what context aEntry happens to
+be focused on.
+
+@return
+A CImEmailMessage object.
+
+@see CMsvEntry
+*/
+EXPORT_C CImEmailMessage* CImEmailMessage::NewLC(CMsvEntry& aEntry)
+	{
+	CImEmailMessage* self = new (ELeave) CImEmailMessage(aEntry);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+
+/** 
+Destructor.
+*/
+EXPORT_C CImEmailMessage::~CImEmailMessage()
+	{
+	Cancel();
+	delete iAttachmentNameList;
+	delete iCompleteSel;
+	delete iResultSel;
+	delete iUriResolver;
+	delete iStoreMessagePart;
+	delete iRemoveMessagePart;
+	iFs.Close();
+	delete iAttachmentManager;
+	delete iStore;
+	}
+
+
+CImEmailMessage::CImEmailMessage(CMsvEntry& aEntry)
+	: CMsgActive(EPriorityStandard), iClientEntry(aEntry)
+	{
+	}
+
+
+void CImEmailMessage::ConstructL()
+	{
+	iCompleteSel=new (ELeave) CMsvEntrySelection();
+	iResultSel=new (ELeave) CMsvEntrySelection();
+	iUriResolver = CImMhtmlUriResolver::NewL(iClientEntry);
+	iProgress = KMsvNullIndexEntryId;
+	User::LeaveIfError(iFs.Connect());
+	iAttachmentNameList = new (ELeave) CDesCArrayFlat(KMiutAttachmentListGranularity);
+	iEmailEntryId = iClientEntry.EntryId();
+	iAttachmentManager = CImAttachmentManager::NewL(*this,iClientEntry);
+	iAttachmentManager->LoadL();
+	iAttachmentState=ENoAttachment; 
+	CActiveScheduler::Add(this);	
+	}
+
+/** 
+Asynchronously retrieves the body text for a specified message. If the email's character
+set has been overridden by a prior call to SetCharacterSetL(), the body text is decoded
+with the new character set before it is inserted into the rich text object. A list containing
+the entry Ids for each body text part within the specified message is created during this call.
+The list can be retrieved after this call has completed by calling Selection().
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@param aMessageId
+The entry Id of the email message that the body text is to be retrieved from.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aEntryType
+Specifies whether to search just the email message (EThisMessageOnly), 
+or to search within any embedded messages it may contain (EThisMessageAndEmbeddedMessages).
+
+@param aRichText
+Upon completion, returns the aRichText object that contains the message body text of all text parts found
+for the message entry specified by aMessageId.  If the body text was not found,
+then aRichText will be unchanged.
+
+@param aParaLayer
+Paragraph format layer for the rich text object specified by aRichText.
+
+@param aCharLayer
+Character format layer for the rich text object specified by aRichText.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::GetBodyTextL(TRequestStatus& aStatus, TMsvId aMessageId, TImEmailEntryType aEntryType, CRichText& aRichText,CParaFormatLayer& aParaLayer, CCharFormatLayer& aCharLayer)
+	{
+	DoGetBodyTextInitL(aMessageId, aEntryType, aRichText, aParaLayer, aCharLayer);
+	Start(aStatus);
+	}
+
+
+/** 
+Retrieves the body text for a specified message. If the email's character
+set has been overridden by a prior call to SetCharacterSetL(), the body text is decoded
+with the new character set before it is inserted into the rich text object.
+A list containing the entry Ids for each body text part within the specified message
+is created during this call. The list can be retrieved by calling Selection().
+
+@param aMessageId
+The entry Id of the email message that the body text is to be retrieved from.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aEntryType
+Specifies whether to search just the email message (EThisMessageOnly), 
+or to search within any embedded messages it may contain (EThisMessageAndEmbeddedMessages).
+
+@param aRichText
+Returns the aRichText object that contains the message body text of all text parts found
+for the message entry specified by aMessageId.  If the body text was not found,
+then aRichText will be unchanged.
+
+@param aParaLayer
+Paragraph format layer for the rich text object specified by aRichText.
+
+@param aCharLayer
+Character format layer for the rich text object specified by aRichText.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::GetBodyTextL(TMsvId aMessageId, TImEmailEntryType aEntryType, CRichText& aRichText,CParaFormatLayer& aParaLayer, CCharFormatLayer& aCharLayer)
+	{
+	DoGetBodyTextInitL(aMessageId, aEntryType, aRichText, aParaLayer, aCharLayer);
+	StartL();
+	}
+
+void CImEmailMessage::DoGetBodyTextInitL(TMsvId aMessageId, TImEmailEntryType aEntryType, CRichText& aRichText,CParaFormatLayer& aParaLayer, CCharFormatLayer& aCharLayer)
+	{
+	CheckAndInitialiseL(aMessageId);
+
+	if (aEntryType==EThisMessageOnly)
+		iState=ETextForThisMsg;
+	else if (aEntryType==EThisMessageAndEmbeddedMessages)
+		iState=ETextForMsgDigest;
+	else
+		User::LeaveIfError(KErrNotSupported);
+	iEntryType=aEntryType;
+	iRichText=&aRichText;
+	iParaLayer=&aParaLayer;
+	iCharLayer=&aCharLayer;
+	iCompleteSel->AppendL(iParentMsgId);
+	// Get the new character set if it has been specified.
+	iCharacterSetId = GetOverrideCharacterSetL();
+	}
+
+
+EXPORT_C void CImEmailMessage::GetBodyTextEntryIdL(TRequestStatus& aStatus, TMsvId aMessageId, TImEmailEntryType aEntryType)
+	{
+	DoGetBodyTextEntryIdL(aMessageId, aEntryType);
+	Start(aStatus);
+	}
+	
+EXPORT_C void CImEmailMessage::GetBodyTextEntryIdL(TMsvId aMessageId, TImEmailEntryType aEntryType)
+	{
+	DoGetBodyTextEntryIdL(aMessageId, aEntryType);
+	StartL();
+	}
+	
+void CImEmailMessage::DoGetBodyTextEntryIdL(TMsvId aMessageId, TImEmailEntryType aEntryType)
+	{
+	CheckAndInitialiseL(aMessageId);
+
+	if (aEntryType==EThisMessageOnly)
+		iState=ETextEntryIdForThisMsg;
+	else if (aEntryType==EThisMessageAndEmbeddedMessages)
+		iState=ETextEntryIdMsgDigest;
+	else
+		User::LeaveIfError(KErrNotSupported);
+	
+	iEntryType=aEntryType;
+	iCompleteSel->AppendL(iParentMsgId);
+	}
+
+
+/**
+Asynchronously populates a list containing all the attachment entry Ids found that are of a specified
+type belonging to the specified message. After this function has completed, call AttachmentSelection()
+to get the list of found attachments. 
+
+If the email's character set has been overridden by a prior call
+to SetCharacterSetL(), the attachment names are decoded with the new character set.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@param aMessageId
+The entry Id of the email message that the body text is to be retrieved from.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aAttachmentType
+The type of attachment to find. Supported attachment 
+types are EAllAttachments, which would get all attachments for the message, 
+EVCards that would get all attachments that are VCards, EVCalendars that would 
+get VCalenders, EICalendar that would get ICalendars, and EVEntries which would get 
+attachments that are either VCards, VCalendars or ICalendars. EEncrypted, ESigned 
+and ESecure are currently not supported.
+
+@param aEntryType
+Specifies whether to search just the email message (EThisMessageOnly), 
+or to search within any embedded messages it may contain (EThisMessageAndEmbeddedMessages).
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+
+@leave KErrNotSupported
+aEntryType is not EThisMessageOnly or EThisMessageAndEmbeddedMessages. 
+*/
+EXPORT_C void CImEmailMessage::GetAttachmentsListL(TRequestStatus& aStatus, TMsvId aMessageId, TImAttachmentType aAttachmentType,TImEmailEntryType aEntryType)
+	{
+	DoGetAttachmentsListL(aMessageId, aAttachmentType, aEntryType);
+	Start(aStatus);
+	}
+
+
+/**
+Populates a list containing all the attachment entry Ids found that are of a specified
+type belonging to the specified message. After this function has completed, call AttachmentSelection()
+to get the list of found attachments. 
+
+If the email's character set has been overridden by a prior call
+to SetCharacterSetL(), the attachment names are decoded with the new character set.
+
+@param aMessageId
+The entry Id of the email message that the attachment list is to be populated.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aAttachmentType
+The type of attachment to find. Supported attachment 
+types are EAllAttachments, which would get all attachments for the message, 
+EVCards that would get all attachments that are VCards, EVCalendars that would 
+get VCalenders, EICalendar that would get ICalendars, and EVEntries which would get 
+attachments that are either VCards, VCalendars or ICalendars. EEncrypted, ESigned 
+and ESecure are currently not supported.
+
+@param aEntryType
+Specifies whether to search just the email message (EThisMessageOnly), 
+or to search within any embedded messages it may contain (EThisMessageAndEmbeddedMessages).
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+
+@leave KErrNotSupported
+aEntryType is not EThisMessageOnly or EThisMessageAndEmbeddedMessages. 
+*/
+EXPORT_C void CImEmailMessage::GetAttachmentsListL(TMsvId aMessageId, TImAttachmentType aAttachmentType,TImEmailEntryType aEntryType)
+	{
+	DoGetAttachmentsListL(aMessageId, aAttachmentType, aEntryType);
+	StartL();
+	}
+
+	
+void CImEmailMessage::DoGetAttachmentsListL(TMsvId aMessageId, TImAttachmentType aAttachmentType,TImEmailEntryType aEntryType)
+	{
+	CheckAndInitialiseL(aMessageId);
+
+
+	iAttachmentManager->AttachmentInfoSelection().ResetAndDestroy();
+	
+	iAttachmentType=aAttachmentType;
+	if (aEntryType==EThisMessageOnly)
+		iState=EAttachmentsForThisMsg;
+	else if (aEntryType==EThisMessageAndEmbeddedMessages)
+		iState=EAttachmentsForMsgDigest;
+	else
+		User::LeaveIfError(KErrNotSupported);
+	iEntryType=aEntryType;
+	iCompleteSel->AppendL(iParentMsgId);
+	}
+
+
+/**
+Asynchronously populates a list of embedded message entries contained within the specified message.
+Note that any embedded messages within embedded messages are not included in the list. 
+Call Selection() to get the results of the search after it has completed. 
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@param aMessageId
+The entry Id of the email message that will be searched for embedded messages.
+The entry must be of type KUidMsvMessageEntry.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::GetMessageDigestEntriesL(TRequestStatus& aStatus, TMsvId aMessageId)
+	{
+	CheckAndInitialiseL(aMessageId);
+	iState=EMsgDigestEntries;
+	iCompleteSel->AppendL(iParentMsgId);
+	Queue(aStatus);
+	TRequestStatus* status=&iStatus;
+	iStatus=KRequestPending;
+	User::RequestComplete(status,KErrNone);
+	SetActive();
+	}
+
+
+/**
+Asynchronously searches for the starting MHTML part embedded in a multipart/related email message.
+
+Used when retrieving specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+If the starting MHTML part cannot be located, then the first HTML part
+that occurs within the multipart/related message is located.
+
+The result of the search is retrieved by calling GetUniversalResourceIdentifierL() after this methods
+has completed.
+
+@param aMessageId
+The entry Id of the email message that will be searched.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::FindFirstHTMLPageL(TMsvId aMessageId, TRequestStatus& aStatus)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	iUriResolver->FindFirstL(aMessageId,ETrue,iStatus);
+	Queue(aStatus);
+	iState = EResolveURI;
+	SetActive();
+	}
+
+/**
+Asynchronously searches a message entry for an MHTML URI, and resolves it to the message entry that
+contains the message part specified by the URI.
+
+Used when retrieving specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+The result of the search is retrieved by calling GetUniversalResourceIdentifierL() after this method
+has completed.
+
+@param aMessageId
+The message Id of the body part that is to be searched for the URI.
+In the first instance, this value should be the starting MHTML entry Id that was located
+by calling FindFirstHTMLPageL().
+
+@param aBase
+The base URI to use when searching for aURI if aURI is relative.
+If aBase is empty, and aURI is relative, then the Content-location
+MIME header contained within the HTML part specified by aMessageId is used as a base.
+If the Content-location header does not exist or is not absolute, then
+just the relative aURI is searched for. 
+
+
+@param aURI
+The absolute or relative URI to resolve.  If aURI is absolute, then aBase is ignored
+and this method completes faster.  If aURI is relative, then aBase is used as a base
+to resolve the relative URI.  If aBase is empty and aURI is relative, then the 
+Content-location MIME header contained within the HTML part specified by aMessageId is
+used as the base.  If the Content-location header does not exist or is not absolute, then
+just the relative aURI is searched for.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::FindUniversalResourceIdentifierL(TMsvId aMessageId, const TDesC& aBase, const TDesC& aURI, TRequestStatus &aStatus)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvEmailHtmlEntry, gPanic(EEntryIsNotMessage));
+	iUriFileFound = EFalse;
+	iUriResolver->ResolveL(aURI, aBase, aMessageId,ETrue,iStatus);
+	Queue(aStatus);
+	iState = EResolveURI;
+	SetActive();
+	}
+
+/**
+Gets the results from FindUniversalResourceIdentifierL() or FindFirstHTMLPageL() 
+method calls when they have completed. 
+
+Used when retrieving specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+@pre
+FindUniversalResourceIdentifierL() or FindFirstHTMLPageL() must have been called
+prior and completed successfully.
+
+@param aLinkedEntryId
+Returns the message Id of the message entry that contains the resolved body part, providing 
+one is found. Note that you should keep a record of the returned message Id 
+as it is required for resolving any URI's that may be found in the resolved body part.
+
+@param aFileFound
+Returns ETrue if the URI has been resolved and the message entry containing the MHTML part has been
+located. Returns EFalse otherwise.
+
+@return
+If the URI is resolved, returns the full path specification and file name of the file containing the HTML,
+image, or other such content stored in the message store.  If no file can be located, the absolute URI is returned
+instead.
+*/
+EXPORT_C HBufC* CImEmailMessage::GetUniversalResourceIdentifierL(TMsvId& aLinkedEntryId, TBool& aFileFound) const
+	{
+	aLinkedEntryId = iUriResolver->LinkedEntryId();
+	aFileFound = iUriFileFound;
+	return iUriResolver->FileNameL();
+	}
+
+/**
+Asynchronously searches for the starting MHTML part embedded in a multipart/related email message.
+
+Used when retrieving specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+If the starting MHTML part cannot be located, then the first HTML part
+that occurs within the multipart/related message is located.
+
+The result of the search is retrieved by calling GetUniversalResourceIdentifierFileHandle() after this methods
+has completed.
+
+@param aMessageId
+The entry Id of the email message that will be searched.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::FindFirstHTMLPageFileHandleL(TMsvId aMessageId, TRequestStatus& aStatus)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	
+	iUriResolver->FindFirstL(aMessageId,EFalse,iStatus);
+	Queue(aStatus);
+	iState = EResolveURI;
+	SetActive();
+	}
+
+/**
+Asynchronously searches a message entry for an MHTML URI, and resolves it to the message entry that
+contains the message part specified by the URI.
+
+Used when retrieving specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+The result of the search is retrieved by calling GetUniversalResourceIdentifierFileHandle() after this method
+has completed.
+
+@param aMessageId
+The message Id of the body part that is to be searched for the URI.
+In the first instance, this value should be the starting MHTML entry Id that was located
+by calling FindFirstHTMLPageFileHandleL().
+
+@param aBase
+The base URI to use when searching for aURI if aURI is relative.
+If aBase is empty, and aURI is relative, then the Content-location
+MIME header contained within the HTML part specified by aMessageId is used as a base.
+If the Content-location header does not exist or is not absolute, then
+just the relative aURI is searched for. 
+
+
+@param aURI
+The absolute or relative URI to resolve.  If aURI is absolute, then aBase is ignored
+and this method completes faster.  If aURI is relative, then aBase is used as a base
+to resolve the relative URI.  If aBase is empty and aURI is relative, then the 
+Content-location MIME header contained within the HTML part specified by aMessageId is
+used as the base.  If the Content-location header does not exist or is not absolute, then
+just the relative aURI is searched for.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes.  aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::FindUniversalResourceIdentifierFileHandleL(TMsvId aMessageId, const TDesC& aBase, const TDesC& aURI, TRequestStatus &aStatus)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvEmailHtmlEntry, gPanic(EEntryIsNotMessage));
+	iUriFileFound = EFalse;
+	//Browsers always append "amp;", when "&" is found while writing URLs in HTML
+	//replacing "&amp;" with "&", before resolving the URLs
+	// eg : if the content location of the image is as below
+	// https://www.ttdm.symbian.com/tmtrack.dll?AttachmentPage&AttachmentID=552810/Morning.jpg
+	// then the browsers writes this to hmtl file by appending "amp;" after "&" because browsers
+	// treat "&" as special character. After apending, the content-location now looks as below
+	// https://www.ttdm.symbian.com/tmtrack.dll?AttachmentPage&amp;AttachmentID=552810/Morning.jpg
+	const TDesC& ampersand = KMhtmlUrlAmpersand;
+	TInt embedUrlIndex;
+	if((embedUrlIndex = aBase.Find(ampersand))!=KErrNotFound)
+		{
+		HBufC* embedUrl = aBase.AllocLC();
+		TPtr embedUrlPtr = embedUrl->Des();
+		embedUrlPtr.Delete(embedUrlIndex+1, 4);
+		iUriResolver->ResolveL(embedUrlPtr, embedUrlPtr, aMessageId,EFalse, iStatus);
+		CleanupStack::PopAndDestroy(); //embedUrl
+		}
+	else 
+		{
+		iUriResolver->ResolveL(aURI, aBase, aMessageId,EFalse, iStatus);
+		} 
+
+	Queue(aStatus);
+	iState = EResolveURI;
+	SetActive();
+	}
+	
+/**
+Gets the results from FindUniversalResourceIdentifierFileHandleL() or FindFirstHTMLPageFileHandleL() 
+method calls when they have completed. 
+
+Used when retrieving specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+@pre
+FindUniversalResourceIdentifierFileHandleL() or FindFirstHTMLPageFileHandleL() must have been called
+prior and completed successfully.
+
+@param aLinkedEntryId
+Returns the message Id of the message entry that contains the resolved body part, providing 
+one is found. Note that you should keep a record of the returned message Id 
+as it is required for resolving any URI's that may be found in the resolved body part.
+
+@param aFile
+Returns the file handle of the file containing the HTML,image, or other such 
+content stored in the message store if the URI has been resolved. If not then
+this argument is not valid. Ownership is transferred. The caller must close the file handle.
+
+@return
+If the URI is resolved, returns KErrNone. The output argument aFile is the file
+handle to the content. If no file is located the KErrNotFound is returned and 
+aFile is not valid.
+*/
+EXPORT_C TInt CImEmailMessage::GetUniversalResourceIdentifierFileHandle(TMsvId& aLinkedEntryId, RFile& aFile) const
+	{
+	aLinkedEntryId = iUriResolver->LinkedEntryId();
+	return iUriResolver->FileHandle(aFile);
+	}
+
+/**
+Returns a selection of entries. The entries are either the results of GetMessageDigestEntriesL(), 
+or of GetBodyTextL().
+
+@pre
+GetMessageDigestEntriesL() or GetBodyTextL() must be called prior and successfully completed.
+
+@return
+Selection of entries populated by GetMessageDigestEntriesL() or GetBodyTextL().
+*/
+EXPORT_C const CMsvEntrySelection& CImEmailMessage::Selection() const
+	{
+	return *iResultSel;
+	}
+	
+
+/**
+Returns a message entry Id as a type-safe package buffer (TPckg<TMsvId>).
+The meaning of the Id depends on the request as follows:
+
+AddAttachmentL(), AddMessageAsAttachmentL(), and AddRelatedPartL():
+While the attachment, message, or related part is being added, a null Id 
+(KMsvNullIndexEntryId); Once the attachment, message, or related part has been added, the entry Id
+of the newly created attachment, message, or related part.
+
+DeleteAttachmentL() and DeleteAttachedMessageL(): While the attachment or attached 
+message is being removed, a null Id (KMsvNullIndexEntryId); Once the attachment
+or attached message has been removed, the Id of the message from which the
+attachment or attached message was removed.
+
+StoreBodyTextL(): While the body text is being stored, a null Id (KMsvNullIndexEntryId);
+Once the text has been stored, the Id of the message for which the body text was 
+stored.
+
+@pre
+Call this method after the following asynchronous calls have completed to check progress.
+AddAttachmentL()
+AddMessageAsAttachmentL()
+AddRelatedPartL()
+DeleteAttachmentL()
+DeleteAttachedMessageL()
+StoreBodyTextL()
+
+@code
+// Example code demonstrating how to retrieve the progress.
+
+// Create and initialise a temporary TPckg object that can hold a message Id.
+TMsvId msgId;
+TPckg<TMsvId> param(msgId);
+
+// Copy the message Id returned from the ProgressL() call into the
+// temporary TPckg object.
+param.Copy(emailMsg->ProgressL());  // where emailMsg is of type CImEmailMessage.
+
+// Check the value of the returned message Id in the TPckg object.
+if (msgId != KMsvNullIndexEntryId)
+	{
+	// More code...
+	} 
+@endcode
+
+@return
+The entry Id as a type-safe packaged buffer (TPckg<TMsvId>).
+*/
+EXPORT_C const TDesC8& CImEmailMessage::ProgressL() const
+	{
+	return iProgress;
+	}
+	
+
+/**
+Adds a file to a specified message as a MIME multipart/related part. After the
+call has completed, calling ProgressL() will return the Id of the newly created
+related part entry.
+
+Used when adding specific parts of an MHTML message, such as inline images
+that are referenced as MHTML anchors within the HTML part of a message.  
+Refer to RFC 2557 - "MIME Encapsulation of Aggregate Documents, such as HTML (MHTML)" for information
+about MHTML email messages.
+
+@pre
+This function should only be used on messages created using CImEmailOperation.
+
+@param aMessageId
+The entry Id of the email message that the related part will be added to.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aAttachmentFullName
+The full path and file name of the related part file to be copied to the message store.
+If the file cannot be located, this call completes with KErrNotFound.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes. aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@param aRelatedPartId
+The entry Id of the MHTML message part that the file being added is referenced from.
+
+@param aContentId
+The Content-Id of the related part.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::AddRelatedPartL(TMsvId aMessageId, const TDesC& aAttachmentFullName, TRequestStatus& aStatus, TMsvId aRelatedPartId, const TDesC8& aContentId)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+
+	// adds 'object' with name aAttachmentFullName related to aRelatedPartId in Multipart/Related Folder
+	CImStoreMessagePart* temp = CImStoreMessagePart::AddRelatedPartL(iStatus, iClientEntry, aMessageId, aAttachmentFullName, aRelatedPartId, aContentId);
+	delete iStoreMessagePart;
+	iStoreMessagePart = temp;
+	Queue(aStatus);
+	iState = EStoreMessagePart;
+	SetActive();
+	}
+
+
+/** 
+Asynchronously stores a body text part for the specified message. After the call
+has completed, calling ProgressL() will return the Id of the message entry for
+which the body text was stored.
+ 
+@pre
+This function should only be used on messages created using CImEmailOperation.
+
+@param aMessageId
+The entry Id of the email message that the body text will be stored in.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aRichText
+A rich text object (CRichText) that contains the message body text.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes. aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::StoreBodyTextL(TMsvId aMessageId, CRichText& aRichText, TRequestStatus& aStatus)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	delete iStoreMessagePart;
+	iStoreMessagePart = NULL;
+	iStoreMessagePart = CImStoreMessagePart::StoreBodyTextL(iStatus, iClientEntry, aMessageId, aRichText);
+	Queue(aStatus);
+	iState = EStoreMessagePart;
+	SetActive();
+	}
+
+/** 
+Asynchronously stores a body text part for the specified message. After the call
+has completed, calling ProgressL() will return the Id of the message entry for
+which the body text was stored.
+ 
+@pre
+This function should only be used on messages created using CImEmailOperation.
+
+@param aMessageId
+The entry Id of the email message that the body text will be stored in.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aRichText
+A rich text object (CRichText) that contains the message body text.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes. aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@param aUsePlainTextStorage		
+if set to ETrue inidcates that the new message entry needs to be created as plain text
+if set to EFalse indicates that message will be created as richtext entry.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/	
+EXPORT_C void CImEmailMessage::StoreBodyTextL(TMsvId aMessageId, CRichText& aRichText, TRequestStatus& aStatus, TBool aUsePlainTextStorage)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	delete iStoreMessagePart;
+	iStoreMessagePart = NULL;
+	iStoreMessagePart = CImStoreMessagePart::StoreBodyTextL(iStatus, iClientEntry, aMessageId, aRichText, aUsePlainTextStorage);
+	Queue(aStatus);
+	iState = EStoreMessagePart;
+	SetActive();
+	}	
+	
+/** 
+Asynchronously stores a body text part for the specified message. A Mime header
+is created with the passed in the CImMimeHeader object passed.
+After the call has completed, calling ProgressL() will return the Id of 
+the message entry for which the body text was stored.
+ 
+@pre
+This function should only be used on messages created using CImEmailOperation.
+
+@param aMessageId
+The entry Id of the email message that the body text will be stored in.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aRichText
+A rich text object (CRichText) that contains the message body text.
+
+@param aMimeHeader
+A MIME header object (CImMimeHeader) that contains the content-type etc.
+
+@param aStatus
+Asynchronous status object (TRequestStatus) that is signalled when the operation
+completes. aStatus should be checked by the caller to ensure that the operation
+was successful.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::StoreBodyTextWithMimeHeaderL(TMsvId aMessageId, CRichText& aRichText, const CImMimeHeader& aMimeHeader, TRequestStatus& aStatus)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	delete iStoreMessagePart;
+	iStoreMessagePart = NULL;
+	iStoreMessagePart = CImStoreMessagePart::StoreBodyTextWithMimeHeaderL(iStatus, iClientEntry, aMessageId, aRichText, aMimeHeader);
+	Queue(aStatus);
+	iState = EStoreMessagePart;
+	SetActive();
+	}
+
+/**
+Returns the character set Id that the body text will be decoded in when it is 
+returned in the call to GetBodyTextL(). It also indicates whether the original
+character set has been overridden by calling SetCharacterSetL().
+
+@pre
+The store_8bit_body_text flag in imcm.rss should be enabled. This is done at build
+time by the manufacturer.
+
+@param aMessageId
+The entry Id of the email message that the character set Id is to be retrieved from.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aCharacterSetId
+Returns the character set Id that the message will be displayed when it is viewed.
+If aCharacterSetId is zero and aOverride is EFalse, the store_8bit_body_text flag
+in imcm.rss has not been enabled.  
+
+@param aOverride
+Returns ETrue if the message's original character set has been overridden (changed)
+via the call to SetCharacterSetL(). If aCharacterSetId is zero and aOverride is EFalse,
+the store_8bit_body_text flag in imcm.rss has not been enabled.
+
+@leave KErrNotFound
+aMessageId entry could not be located.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::GetCharacterSetL(TMsvId aMessageId, TUint& aCharacterSetId, TBool& aOverride)
+	{
+	CheckAndInitialiseL(aMessageId);
+	aCharacterSetId = GetOverrideCharacterSetL();
+	if (aCharacterSetId == 0)
+		{
+		// The user has not changed the character set.  Return the body text character set.
+		aOverride = EFalse;
+		iState = ETextForThisMsgGetCharacterSet;
+		iEntryType = EThisMessageOnly;
+		iCompleteSel->AppendL(aMessageId);
+		StartL();
+		aCharacterSetId = iCharacterSetId;
+		}
+	else
+		{
+		aOverride = ETrue;
+		}
+	}
+
+
+/**
+Stores the new character set that the message will be displayed as next time
+it is viewed.
+
+@pre
+The store_8bit_body_text flag in imcm.rss should be enabled. This is done at build
+time by the manufacturer.
+
+@param aMessageId
+The entry Id of the email message that the character set will be returned from.
+The entry must be of type KUidMsvMessageEntry.
+
+@param aCharacterSetId
+The character set Id to be stored in the message store.  Setting this value to
+zero will cause the message to be displayed in its original character set when
+it was viewed for the first time after it was downloaded.
+
+@leave KErrNotFound
+aMessageId entry can not be located in the message store, or the character set
+information can not be located. If the character set information cannot be
+located, it could be because it was not stored when downloaded. To enable this
+functionality set the store_8bit_body_text flag in imcm.rss.
+It is also possible that a call to StoreBodyTextL() has overwritten
+the original character set stored when the message was downloaded.
+
+@panic imcm 10
+aMessageId is not of type KUidMsvMessageEntry.
+*/
+EXPORT_C void CImEmailMessage::SetCharacterSetL(TMsvId aMessageId, TUint aCharacterSetId)
+	{
+	CheckAndInitialiseL(aMessageId);
+	CMsvStore* store = iClientEntry.EditStoreL();
+	CleanupStack::PushL(store);
+	
+	// If the character set is zero, remove the new character set stream so that the original
+	// character set from the body text will be returned when GetCharacterSetL is called.
+	if (aCharacterSetId == 0)
+		{
+		if (store->IsPresentL(KMessageCharSetStreamUid))
+			{
+			store->RemoveL(KMessageCharSetStreamUid);
+			store->CommitL();
+			}
+		CleanupStack::PopAndDestroy(store);
+		return;
+		}
+		
+	// Write the new character set to the store.
+	RMsvWriteStream out;
+	out.AssignLC(*store, KMessageCharSetStreamUid);
+	out.WriteUint8L(KMessageCharSetStreamVersion);
+	out.WriteUint32L(aCharacterSetId);
+	out.CommitL();
+	store->CommitL();
+	CleanupStack::PopAndDestroy(2, store); //out, store.
+	}
+
+
+void CImEmailMessage::CheckAndInitialiseL(TMsvId aMessageId)
+	{
+	iClientEntry.SetEntryNoCheckL(aMessageId);
+	const TMsvEmailEntry& entry=iClientEntry.Entry();
+	__ASSERT_ALWAYS(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	iParentMsgId=aMessageId;
+	iIsAMHTMLmessage=entry.MHTMLEmail();
+	iCharacterSetId = 0;
+	Reset();
+	}
+
+
+void CImEmailMessage::Reset()
+	{
+	iState=EIdle;
+	iCompleteSel->Reset();
+	iResultSel->Reset();
+	iAttachmentManager->AttachmentInfoSelection().ResetAndDestroy();
+	iAttachmentNameList->Reset();
+	}
+
+
+void CImEmailMessage::DoCancel()
+	{
+	Reset();
+	iUriResolver->Cancel();
+	if (iStoreMessagePart)
+		iStoreMessagePart->Cancel();
+	if (iRemoveMessagePart)
+		iRemoveMessagePart->Cancel();
+	CMsgActive::DoCancel();
+	}
+
+
+void CImEmailMessage::DoComplete(TInt& aStatus)
+	{//set back to the context the user passed in
+	TRAPD(error, iClientEntry.SetEntryL(iParentMsgId));
+    if(aStatus == KErrNone)
+	{
+	    aStatus = error;   	
+	}
+	}
+
+
+void CImEmailMessage::DoStateL()
+	{
+	switch (iState)
+		{
+	case EResolveURI:
+		iUriFileFound = (iStatus == KErrNone) ? ETrue : EFalse;
+		iState = EIdle;
+		return;
+	case EStoreMessagePart:
+		iProgress.Copy(iStoreMessagePart->ProgressL());
+		if(iAttachmentState == EAddAttachment || iAttachmentState == ECreateAttachment)
+			{
+			TMsvId attachmentId =  iProgress();
+			iAttachmentManager->AppendAttachmentArrayL(attachmentId);
+			// Once the file is attached to email, reseting the iAttachmentState
+			iAttachmentState = ENoAttachment;
+			}
+		iState = EIdle;
+		return;
+	case ERemoveMessagePart:
+		iProgress.Copy(iRemoveMessagePart->ProgressL());
+		if(iAttachmentState ==  EDeleteAttachment)
+			{
+			TMsvId deletedAttachmentId = iRemoveMessagePart->RemovedAttachmentId();
+			// check whether we currently have a cache of the attachments before
+			// trying to delete the one we have removed.
+			if(iAttachmentManager->AttachmentCount()!=0)
+				{			
+				iAttachmentManager->DeleteAttachmentInArrayL(deletedAttachmentId);
+				}
+			}
+		
+		iState = EIdle;
+		return;
+	case EFinished:
+		return;
+	case ETextForThisMsg:
+	case ETextForThisMsgGetCharacterSet:
+	case ETextForMsgDigest:
+	case ETextEntryIdForThisMsg:
+	case ETextEntryIdMsgDigest:
+	case EAttachmentsForThisMsg:
+	case EAttachmentsForMsgDigest:
+	case EMsgDigestEntries:
+		ChangeMessageContextL();
+		break;
+	default:
+		break;
+		};
+	}
+
+
+void CImEmailMessage::Start(TRequestStatus& aStatus)
+	{
+	Queue(aStatus);
+	TRequestStatus* status=&iStatus;
+	iStatus=KRequestPending;
+	User::RequestComplete(status,KErrNone);
+	SetActive();
+	}
+
+
+void CImEmailMessage::StartL()
+	{
+	TRAPD(error, do DoStateL(); while(iState != EIdle && iState != EFinished););
+	DoComplete(error);
+	User::LeaveIfError(error);
+	}
+
+
+void CImEmailMessage::DoRunL()
+	{
+	DoStateL();
+	if (iState != EIdle && iState != EFinished)
+		{
+		TRequestStatus* status=&iStatus;
+		iStatus=KRequestPending;
+		User::RequestComplete(status,KErrNone);
+		SetActive();
+		}
+	}
+
+
+/**
+This function takes the first id in iCompleteSel and sets the context to 
+that and appends its children to the same list and deletes the id(current) after it has finished with it.
+*/
+void CImEmailMessage::ChangeMessageContextL()
+	{
+	iClientEntry.SetEntryL((*iCompleteSel)[0]);
+	iEntry=iClientEntry.Entry();
+	TUid type=iEntry.iType;
+	TBool searchChildren=ETrue;
+	
+	switch (type.iUid)
+		{
+		case KUidMsvFolderEntryValue:
+			{
+			searchChildren=HandleDifferentFolderTypesL();
+			break;
+			}
+		case KUidMsvAttachmentEntryValue:
+			{
+			if (iState==EAttachmentsForThisMsg || iState==EAttachmentsForMsgDigest)
+				AttachmentInfoL();
+			break;
+			}
+		case KUidMsvEmailTextEntryValue:
+			{
+			switch (iState)
+				{
+				case ETextForThisMsg:
+				case ETextForMsgDigest:
+					{
+					iResultSel->AppendL((*iCompleteSel)[0]);
+					AssembleBodyTextL();
+					break;
+					}
+
+				case ETextEntryIdForThisMsg:
+				case ETextEntryIdMsgDigest:
+					{
+					iResultSel->AppendL((*iCompleteSel)[0]);
+					break;
+					}
+
+				case ETextForThisMsgGetCharacterSet:
+					{
+					if (GetBodyTextCharacterSetL())
+						{
+						// Found an 8 bit body text part.  The character set is the
+						// same for every 8 bit body text part so we can return immediately.
+						iCompleteSel->Reset();
+						iState=EFinished;
+						return;
+						}
+					break;
+					}
+				default:
+					{
+					break;
+					}
+				}
+			break;
+			}
+		case KUidMsvMessageEntryValue:
+			{
+			//check if user requested for this entry or digest entry and terminate accordingly.   
+			if ((*iCompleteSel)[0]!=iParentMsgId)
+				{
+				// we have a entry attachment, append this to the list of attachments
+				AppendEntryAttachmentInfoL();
+				if (iEntryType==EThisMessageOnly || iState==EMsgDigestEntries)
+					{
+					searchChildren=EFalse;
+					if (iState==EMsgDigestEntries)
+						iResultSel->AppendL((*iCompleteSel)[0]);
+					}
+				}
+			break;
+			}
+		default:
+			{
+			break;
+			}
+		};
+	
+	TInt index=iCompleteSel->Find(iEntry.Id());
+	iCompleteSel->Delete(index);
+	if (searchChildren)
+		CompareChildrenAndPopulateSelL();
+	if (!iCompleteSel->Count()) 
+		{
+		iState=EFinished;
+		return;
+		}
+	}
+
+
+void CImEmailMessage::CompareChildrenAndPopulateSelL()
+	{  
+	TKeyArrayFix uidKey(0,ECmpTUint32);
+	iClientEntry.SetSortTypeL(TMsvSelectionOrdering(KMsvNoGrouping,EMsvSortByNone,ETrue));
+	TInt count = iClientEntry.Count();
+
+	TMsvId id = KMsvNullIndexEntryId;
+	for (TInt i=0; i<count; ++i)
+ 		{
+		id = iClientEntry[i].Id();
+		if (iCompleteSel->Find(id) == KErrNotFound)
+			{			
+			iCompleteSel->InsertIsqL(id ,uidKey);
+			}
+ 		}
+	}
+
+
+void CImEmailMessage::AssembleBodyTextL()
+	{
+   	if (!iClientEntry.HasStoreL())
+   		return;
+   		
+	CMsvStore* store=iClientEntry.ReadStoreL();
+   	CleanupStack::PushL(store);
+	
+	if (store->HasBodyTextL())
+   		{
+		CRichText* bodyText=CRichText::NewL(iParaLayer,iCharLayer);	
+		CleanupStack::PushL(bodyText);
+		store->RestoreBodyTextL(*bodyText, iCharacterSetId);
+		iRichText->AppendTakingSolePictureOwnershipL(*bodyText);
+		CleanupStack::PopAndDestroy(bodyText);	
+		}
+	
+   	CleanupStack::PopAndDestroy(store);
+	}
+
+void CImEmailMessage::AttachmentInfoL()
+	{
+	switch (iAttachmentType)
+		{
+	case EAllAttachments: break;
+	case EVCards:
+		if (!iEntry.VCard()) return; break;
+	case EVCalendars:
+		if (!iEntry.VCalendar()) return; break;
+	case EICalendars:
+		if (!iEntry.ICalendar()) return; break;
+	case EVEntries: 
+		if (iEntry.VCard() || iEntry.VCalendar() || iEntry.ICalendar()) break; return;
+	case EEncrypted:
+		if (!iEntry.Encrypted()) return; break;
+	case ESigned:
+		if (!iEntry.Signed()) return; break;
+	case ESecure: 
+		if (iEntry.Encrypted() || iEntry.Signed()) break; return;
+	default: return;
+		};
+
+	AppendAttachmentL();
+	}
+
+/**
+Walking the tree attachments added as found.
+*/
+void CImEmailMessage::AppendAttachmentL()
+	{
+	if(iClientEntry.HasStoreL())
+		{
+		CMsvStore* store = iClientEntry.ReadStoreL();
+		CleanupStack::PushL(store);
+		MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+		// Modified to handle multiple attachments belonging to a single attachment entry
+		for(TInt i=0;i<attachmentMgr.AttachmentCount();i++)
+			{
+			CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(i);
+			CleanupStack::PushL(attachment);
+			attachment->SetSize(iEntry.iSize);
+			attachment->SetComplete(iEntry.Complete());
+			// For compatibility keep entry [0] as the TMsvId of the owning attachment entry
+			if(i == 0)
+				{
+				attachment->SetId(iClientEntry.EntryId());
+				}
+			else
+				{				
+				// Store the index and the owning attachment entry's TMsvId
+				attachment->SetIntAttributeL(KUidMsvEmailAttachmentEntryIndex,i);
+				attachment->SetIntAttributeL(KUidMsvEmailAttachmentEntryId,iClientEntry.EntryId());
+				attachment->SetId(iAttachmentManager->UniqueAttachmentId());
+				}
+			// Add to the per-message list of CMsvAttachments
+			User::LeaveIfError(iAttachmentManager->AttachmentInfoSelection().Append(attachment));
+			// Add the attachment id to the results
+			iResultSel->AppendL(iClientEntry.EntryId());
+			CleanupStack::Pop(attachment);				
+			}
+		CleanupStack::PopAndDestroy(store);	
+		}
+	AppendAttachmentNameL();
+	}
+
+
+/** 
+Retrieves the encoded mime header containing the encoded data for the attachment
+name and redecodes with the overriding character set if one has been given. If
+no overriding character set has been specified, a zero length entry is added.
+This indicates whether redcoding is required at retrieval time.
+*/
+void CImEmailMessage::AppendAttachmentNameL()
+	{
+	TMsvId originalId = iClientEntry.EntryId();
+	TUint  overrideCharset = 0;
+
+	iClientEntry.SetEntryL(iParentMsgId);
+	overrideCharset = GetOverrideCharacterSetL();
+
+	// Set iClientEntry back to original entry.
+	iClientEntry.SetEntryL(originalId);
+	
+	TFileName filename;
+	TPtrC filenamePtr(KNullDesC);
+	// If our override charset has been set.
+	if (overrideCharset != 0)
+		{
+		CImMimeHeader* mimeHeader = FindAttachmentMimeHeaderL();	
+		if (mimeHeader != NULL)
+			{
+			CleanupStack::PushL(mimeHeader);
+			// Decode mime header
+			FindFilenameDecodeL(*mimeHeader, filename, overrideCharset);
+
+			filenamePtr.Set(filename);
+			CleanupStack::PopAndDestroy(mimeHeader);
+			}
+		}
+	iAttachmentNameList->AppendL(filenamePtr);
+	}
+
+CImMimeHeader* CImEmailMessage::FindAttachmentMimeHeaderL()
+	{
+	TMsvId     originalId = iClientEntry.EntryId();
+	CMsvStore* store      = NULL;
+
+	// If the current entry in the message hierarchy has a store, look for the
+	// mime header there.
+	if (iClientEntry.HasStoreL())
+		{
+		store = iClientEntry.ReadStoreL();
+		CleanupStack::PushL(store);
+		if (!store->IsPresentL(KUidMsgFileMimeHeader))
+			{
+			CleanupStack::PopAndDestroy(store);
+			store = NULL;
+			}
+		}
+
+	if (store == NULL)
+		{
+		// Check the parent entry in the message hierarchy for the mime header
+		// but only if it is the message.
+		iClientEntry.SetEntryL(iClientEntry.Entry().Parent());
+		if (iClientEntry.Entry().iType == KUidMsvMessageEntry && 
+			iClientEntry.HasStoreL())
+			{
+			store = iClientEntry.ReadStoreL();
+			CleanupStack::PushL(store);
+			if(!store->IsPresentL(KUidMsgFileMimeHeader))
+				{
+				CleanupStack::PopAndDestroy(store);
+				store = NULL;
+				}
+			}
+		}
+
+	CImMimeHeader* mimeHeader = NULL;
+	if (store)
+		{
+		mimeHeader = CImMimeHeader::NewLC();
+		mimeHeader->RestoreL(*store);
+		// found the mime headers,
+		CMsvMimeHeaders* mimeHeaders = ConvertToMsvMimeHeadersL(mimeHeader);
+		CleanupStack::PushL(mimeHeaders);
+		// store the mimeheaders into the previously stored attachment  
+		TInt count = iAttachmentManager->AttachmentInfoSelection().Count();
+		if(count)
+			mimeHeaders->StoreL(*(iAttachmentManager->AttachmentInfoSelection()[count-1]));
+		CleanupStack::PopAndDestroy(mimeHeaders);
+		CleanupStack::Pop(mimeHeader);
+		CleanupStack::PopAndDestroy(store);
+		CleanupStack::PushL(mimeHeader);
+		}
+	if (iClientEntry.EntryId() != originalId)
+		iClientEntry.SetEntryL(originalId);
+
+	if (mimeHeader)
+		CleanupStack::Pop(mimeHeader);
+	return mimeHeader;
+	}
+
+
+
+	
+TInt CImEmailMessage::FindFilename(const CImMimeHeader& aMimeInfo, TPtrC8& aFilename)
+	{
+	_LIT8(KMimeName,"NAME");
+	_LIT8(KMimeNameRFC2231, "NAME*");
+	_LIT8(KMimeFilename, "FILENAME");
+	_LIT8(KMimeFilenameRFC2231, "FILENAME*");
+
+	// Look in content-type list
+	const CDesC8Array& ctype = aMimeInfo.ContentTypeParams();
+	TInt tuple = 0;
+
+	while (tuple < ctype.Count())
+		{
+		// Look for "name xxx"
+		if (ctype[tuple].CompareF(KMimeName) == 0)
+			{
+			// Got it: report that we found it
+			aFilename.Set(ctype[tuple + 1]);
+			return (KErrNone);
+			}
+		else if (ctype[tuple].CompareF(KMimeNameRFC2231) == 0)
+			{
+			// Got it: report that we found it
+			aFilename.Set(ctype[tuple + 1]);
+			return(KRFC2231Encoded);
+			}
+		tuple += 2;
+		}
+
+	// Not found in the content type, try content disposition
+	tuple = 0;
+	const CDesC8Array& cdisp = aMimeInfo.ContentDispositionParams();
+	while (tuple < cdisp.Count())
+		{
+		// Look for "filename xxx"
+		if (cdisp[tuple].CompareF(KMimeFilename) == 0)
+			{
+			// Got it: report that we found it
+			aFilename.Set(cdisp[tuple + 1]);
+			return(KErrNone);
+			}
+		else if (cdisp[tuple].CompareF(KMimeFilenameRFC2231) == 0)
+			{
+			// Got it: report that we found it
+			aFilename.Set(cdisp[tuple + 1]);
+			return (KRFC2231Encoded);
+			}
+
+		tuple += 2;
+		}
+
+	// Didn't find it
+	return(KErrNotFound);
+	}
+
+void CImEmailMessage::FindFilenameDecodeL(
+	const CImMimeHeader& aMimeInfo, TFileName& aFileName, TUint aCharset)
+	{
+	// Create everything needed for a CImConvertHeader.
+	RFs& fileSvrSession = iClientEntry.Session().FileSession();
+	CCnvCharacterSetConverter* characterConverter = CCnvCharacterSetConverter::NewL();
+	CleanupStack::PushL(characterConverter);
+	CImConvertCharconv* charConv = CImConvertCharconv::NewL(*characterConverter, fileSvrSession);
+	CleanupStack::PushL(charConv);
+	CImConvertHeader* headerConverter = CImConvertHeader::NewL(*charConv); 
+	CleanupStack::PushL(headerConverter);
+
+	// Make an attachment name
+	aFileName.Zero();
+
+	TPtrC8 origFileName;
+
+	// Look for filename in Content-Type list
+	TInt returnValue = FindFilename(aMimeInfo, origFileName);
+	
+	if (KErrNotFound != returnValue && KRFC2231Encoded != returnValue)
+		{
+		// Run it through the QP decoder
+		HBufC* decoded = HBufC::NewLC(origFileName.Length());
+		TPtr decoded_ptr(decoded->Des());
+		// Set the overriding charset.
+		headerConverter->SetOverrideCharset(aCharset);
+
+		/* if it starts =? then assume its RFC2047 encoding -
+		 * otherwise assume its plain text encoded in the system
+		 * charset and decode directly */
+		if (origFileName.Length() >= 2 && origFileName[0] == KImcvEquals && origFileName[1] == KImcvQuestionMark)
+			headerConverter->DecodeHeaderFieldL(origFileName, decoded_ptr);
+		else
+			{
+			if (charConv->PrepareToConvertToFromOurCharsetL(charConv->SystemDefaultCharset()))
+				{
+				// Character set conversion
+				TInt unconvertedChars;
+				TInt pos;
+				charConv->ConvertToOurCharsetL(origFileName, decoded_ptr, unconvertedChars, pos);
+				}
+			else
+				{
+				// Charset not available, don't decode.
+				decoded_ptr.Copy(origFileName);
+				}
+			}
+		aFileName.Copy(decoded_ptr);
+		CleanupStack::PopAndDestroy(); // decoded
+		}
+	CleanupStack::PopAndDestroy(3, characterConverter);
+	}
+
+TBool CImEmailMessage::HandleDifferentFolderTypesL()
+	{
+	/* This bit of code looks at the folder type and finds out how many children there are
+	 and depending on the type of the reqest (attachments/bodytext etc..) it selects only 
+	those type of children and ignores the others.  This avoids going through the whole tree. */
+	TImEmailFolderType folderType=iEntry.MessageFolderType();
+	
+	if(iIsAMHTMLmessage == EFalse && folderType==EFolderTypeRelated)
+		folderType=EFolderTypeMixed;
+
+	switch (folderType)
+		{
+	case EFolderTypeUnknown:
+	case EFolderTypeMixed:
+	case EFolderTypeParallel:
+	case EFolderTypeDigest:
+	case EFolderTypeRFC822:
+	case EFolderTypePartial:
+	case EFolderTypeDirectory:
+	case EFolderTypeExternal:
+		return ETrue;
+	case EFolderTypeRelated:  //doesn't apply for get- txt,attch,msgdigest
+		if (iState == EAttachmentsForThisMsg)
+			{
+			GetAttachmentsForRelatedFolderL();
+			return EFalse;	
+			}
+		else if (iState==EAttachmentsForMsgDigest || iState==EMsgDigestEntries)
+			{
+			return EFalse;
+			}
+
+		if (iState==ETextForThisMsg || iState==ETextForThisMsgGetCharacterSet || iState==ETextForMsgDigest
+			|| iState == ETextEntryIdForThisMsg || iState == ETextEntryIdMsgDigest)
+			{
+			GetTextForRelatedFolderL();
+			return EFalse;
+			}
+		return ETrue;
+	case EFolderTypeAlternative: // only applies for get text, get body text character set.
+		if (iState==EAttachmentsForThisMsg || iState==EAttachmentsForMsgDigest)
+			{
+			return ETrue;
+			}
+
+		if (iState==ETextForThisMsg || iState==ETextForThisMsgGetCharacterSet || iState==ETextForMsgDigest
+			|| iState == ETextEntryIdForThisMsg || iState == ETextEntryIdMsgDigest)
+			{
+			GetTextForAlternateFolderL();
+			}
+		return EFalse;
+		}
+	return ETrue;
+	}
+
+
+void CImEmailMessage::GetTextForAlternateFolderL()		
+	{
+	iClientEntry.SetSortTypeL(TMsvSelectionOrdering(KMsvNoGrouping,EMsvSortByNone,ETrue));
+	TInt count = iClientEntry.Count();
+	TInt typeindex=-1;  //for alternate we need the last id.
+	while (count--)
+		{
+		if (iClientEntry[count].iType.iUid==KUidMsvEmailTextEntryValue)  //ignore the rest of the types.  The last text entry is the best one.
+			{
+			typeindex=count;
+			break;
+			}
+		}
+	if (typeindex >-1) //means it found a txt entry
+		{
+		TKeyArrayFix uidKey(0,ECmpTUint32);
+		iCompleteSel->InsertIsqL(iClientEntry[typeindex].Id(),uidKey);
+		}
+	}
+
+
+void CImEmailMessage::GetTextForRelatedFolderL()		
+	{
+	iClientEntry.SetSortTypeL(TMsvSelectionOrdering(KMsvNoGrouping,EMsvSortByNone,ETrue));
+	CMsvEntrySelection* sel=iClientEntry.ChildrenL();
+	CleanupStack::PushL(sel);		
+	TInt count=sel->Count();
+	TMsvEmailEntry entry;
+	TKeyArrayFix uidKey(0,ECmpTUint32);
+	for (TInt i=0; i<count; i++)
+		{
+		entry=iClientEntry.ChildDataL((*sel)[i]);
+
+		if ((entry.iType.iUid==KUidMsvFolderEntryValue) || ((iState==ETextForMsgDigest || iState == ETextEntryIdMsgDigest)
+		&& (entry.iType.iUid==KUidMsvMessageEntryValue))) 
+			{
+			iCompleteSel->InsertIsqL((*sel)[i],uidKey);
+			};
+		}
+	CleanupStack::PopAndDestroy(); //sel
+	}
+
+
+void CImEmailMessage::GetAttachmentsForRelatedFolderL()
+	{
+	// This fixes a defect where forwarding an inline attachment failed. Before this
+	// fix, no attachments under multipart related were forwarded. 
+	// This routine will only forward attachments taht are directly under the multipart
+	// related folder.
+	TKeyArrayFix uidKey(0,ECmpTUint32);
+	iClientEntry.SetSortTypeL(TMsvSelectionOrdering(KMsvNoGrouping,EMsvSortByNone,ETrue));
+	for (TInt entry(0); entry < iClientEntry.Count(); entry++)
+		{
+		if (iClientEntry[entry].iType.iUid == KUidMsvAttachmentEntryValue)
+			{
+			iCompleteSel->InsertIsqL(iClientEntry[entry].Id(), uidKey);
+			}
+		}
+	}
+
+TBool CImEmailMessage::GetBodyTextCharacterSetL()
+	{
+	// Open body text entry store for reading.
+	CMsvStore* store = iClientEntry.ReadStoreL();
+	CleanupStack::PushL(store);
+
+ 	// check the body text entry store available if not return EFalse
+ 	if(!store->HasBodyTextL())
+ 		{
+ 		CleanupStack::PopAndDestroy(store); // store.	
+		return EFalse;
+ 		}
+
+	// Test if the old rich text body OR 16 bit plain body text is present. Return immediately if so, 
+	// We are looking for the new 8 bit body text format which has character set
+	// information stored with it. 
+	if (store->IsPresentL(KMsvEntryRichTextBody) || store->IsPresentL(KMsvPlainBodyText16))
+		{
+		CleanupStack::PopAndDestroy(store);
+		return EFalse;
+		}
+	// Check if body text is stored as 8 bit body text format
+	if(store->IsPresentL(KMsv8BitEncodedBodyData))
+		{
+		// The body text entry must be the new 8 bit format.
+		CMsvBodyText* bodyText = CMsvBodyText::NewLC();
+
+		// If there is no body text for this message RestoreL will leave
+		// In this case we will change that into returning EFalse so any
+		// attachments will display properly
+		TRAPD(err, bodyText->RestoreL(*store));
+		if (err == KErrNotFound)
+			{
+			CleanupStack::PopAndDestroy(2, store); // bodyText, store.	
+			return EFalse;
+			}
+	
+		iCharacterSetId = bodyText->CharacterSet();
+		
+		if (!iCharacterSetId)
+			{
+			iCharacterSetId = bodyText->DefaultCharacterSet();
+			}
+		CleanupStack::PopAndDestroy(bodyText);
+		}
+	else // Body text is stored as 8 bit plain text.
+		{
+		CMsvPlainBodyText* plainBodyText = store->InitialisePlainBodyTextForReadL(KMaxChunkLength);
+		CleanupStack::PushL(plainBodyText);
+		iCharacterSetId = plainBodyText->CharacterSet();
+		if(!iCharacterSetId)
+			{
+			iCharacterSetId = plainBodyText->DefaultCharacterSet();
+			}
+		CleanupStack::PopAndDestroy(plainBodyText);	
+		}
+	
+	CleanupStack::PopAndDestroy(store);
+	return ETrue;
+	}
+
+
+/**
+Returns the character set id of the email message entry if it exists.  This method assumes that the
+context is set to the top level message entry.
+*/	
+TUint CImEmailMessage::GetOverrideCharacterSetL()
+	{
+	TUint characterSetId = 0;
+	if (iClientEntry.HasStoreL())
+		{
+		CMsvStore* store  = iClientEntry.ReadStoreL();
+		CleanupStack::PushL(store);
+		if (store->IsPresentL(KMessageCharSetStreamUid))
+			{
+			RMsvReadStream in;
+			in.OpenLC(*store, KMessageCharSetStreamUid);
+			in.ReadUint8L(); // Version. 
+			characterSetId = in.ReadUint32L();
+			in.Close();
+			CleanupStack::PopAndDestroy(&in);
+			}
+		CleanupStack::PopAndDestroy(store);
+		}
+	return characterSetId;
+	}
+
+TMsvEntry CImEmailMessage::FindIdEntryL(TMsvId aMessageId)
+	{
+	TMsvId service;
+	TMsvEntry returnEntry;
+	iClientEntry.Session().GetEntry(aMessageId, service, returnEntry);
+	return returnEntry;
+	}
+	
+EXPORT_C MMsvAttachmentManager& CImEmailMessage::AttachmentManager() const
+	{
+	return *iAttachmentManager;
+	}
+	
+void CImEmailMessage::CheckEntryAndResetStoreMessageL(TMsvId aMessageId)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_DEBUG(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	
+	// reset the entry with which CImEmailMessage was created
+	iClientEntry.SetEntryL(iEmailEntryId);
+	
+	delete iStoreMessagePart;
+	iStoreMessagePart = NULL;
+	}
+	
+void CImEmailMessage::CheckEntryAndResetRemoveMessageL(TMsvId aMessageId)
+	{
+	TMsvEntry entry = FindIdEntryL(aMessageId);
+	__ASSERT_DEBUG(entry.iType==KUidMsvMessageEntry, gPanic(EEntryIsNotMessage));
+	
+	// reset the entry with which CImEmailMessage was created
+	iClientEntry.SetEntryL(iEmailEntryId);
+	
+	delete iRemoveMessagePart;
+	iRemoveMessagePart = NULL;
+	}	
+	
+void CImEmailMessage::DoSetActive(TRequestStatus& aStatus)
+	{
+	Queue(aStatus);
+	SetActive();	
+	}	
+
+void CImEmailMessage::AddAttachmentL(const TDesC& aFilePath, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetStoreMessageL(messageId);
+
+	iStoreMessagePart = CImStoreMessagePart::AddAttachmentL(messageId,aFilePath,iClientEntry, aAttachmentInfo,iStatus );
+	iState = EStoreMessagePart;
+	iAttachmentState = EAddAttachment;
+
+	DoSetActive(aStatus);
+	}
+
+void CImEmailMessage::AddAttachmentL(RFile& aFile, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetStoreMessageL(messageId);
+	
+	iStoreMessagePart = CImStoreMessagePart::AddAttachmentL(messageId,aFile,iClientEntry, aAttachmentInfo, iStatus);
+	iState = EStoreMessagePart;
+	iAttachmentState = EAddAttachment;
+	
+	DoSetActive(aStatus);
+	}
+	
+void CImEmailMessage::AddLinkedAttachmentL(const TDesC& aFilePath, CMsvAttachment* aAttachmentInfo,TRequestStatus& aStatus)
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetStoreMessageL(messageId);
+	
+	iStoreMessagePart = CImStoreMessagePart::AddLinkedAttachmentL(messageId,aFilePath,iClientEntry, aAttachmentInfo,iStatus);
+	iState = EStoreMessagePart;
+	iAttachmentState = EAddAttachment;
+	
+	DoSetActive(aStatus);
+	}
+	
+void CImEmailMessage::AddEntryAsAttachmentL(TMsvId aAttachmentEntryId, CMsvAttachment* aAttachmentInfo,TRequestStatus& aStatus)
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetStoreMessageL(messageId);
+		
+	iStoreMessagePart = CImStoreMessagePart::AddEntryAsAttachmentL(messageId,aAttachmentEntryId,iClientEntry,aAttachmentInfo,iStatus);
+	iState = EStoreMessagePart;
+	iAttachmentState = EAddAttachment;
+	
+	DoSetActive(aStatus);
+	}
+
+void CImEmailMessage::CreateAttachmentL(const TDesC& aFileName, RFile& aAttachmentFile, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetStoreMessageL(messageId);
+	
+	iStoreMessagePart = CImStoreMessagePart::CreateAttachmentL(messageId,aFileName,aAttachmentFile,iClientEntry, aAttachmentInfo,iStatus);
+	iState = EStoreMessagePart;
+	iAttachmentState = ECreateAttachment;
+	
+	DoSetActive(aStatus);
+	}
+	
+/**
+Returns a list of attachment information pointers (CMsvAttachment)
+populated by a call to GetAttachmentsListL().
+
+@pre
+The attachment information list must first be populated by calling GetAttachmentsListL().
+
+@return
+An array of attachment information objects (CMsvAttachment) representing the attachments
+contained within a particular message specified in the call to GetAttachmentsListL().
+*/
+const RPointerArray<CMsvAttachment>& CImEmailMessage::AttachmentInfoSelection() const
+	{
+	return iAttachmentManager->AttachmentInfoSelection();
+	}
+
+void CImEmailMessage::RemoveAttachmentL(TMsvAttachmentId aAttachmentId,TRequestStatus& aStatus) 
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetRemoveMessageL(messageId);
+	
+	iRemoveMessagePart = CImRemoveMessagePart::DeleteAttachmentL(iStatus, iClientEntry, messageId, aAttachmentId);
+	iState = ERemoveMessagePart;
+	iAttachmentState = EDeleteAttachment;
+	
+	DoSetActive(aStatus);
+	}
+	
+void CImEmailMessage::RemoveAttachedMessageL(TMsvAttachmentId aAttachmentId,TRequestStatus& aStatus) 
+	{
+	// get the message id
+	TMsvId messageId = iClientEntry.EntryId();
+	CheckEntryAndResetRemoveMessageL(messageId);
+	
+	iRemoveMessagePart = CImRemoveMessagePart::DeleteAttachmentL(iStatus, iClientEntry, messageId, aAttachmentId);
+	iState = ERemoveMessagePart;
+	iAttachmentState = EDeleteAttachment;
+	
+	DoSetActive(aStatus);
+	}
+	
+CMsvMimeHeaders* CImEmailMessage::ConvertToMsvMimeHeadersL(CImMimeHeader* aMimeHeader)
+	{
+	CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
+	CleanupStack::PushL(mimeHeaders);
+	
+	mimeHeaders->SetContentDescriptionL(aMimeHeader->ContentDescription());
+	mimeHeaders->SetContentBaseL(aMimeHeader->ContentBase());
+	mimeHeaders->SetContentLocationL(aMimeHeader->ContentLocation());
+	mimeHeaders->SetContentIdL(aMimeHeader->ContentID());
+	mimeHeaders->SetContentTypeL(aMimeHeader->ContentType());
+	mimeHeaders->SetContentDispositionL(aMimeHeader->ContentDisposition());
+	mimeHeaders->SetMimeCharset(aMimeHeader->MimeCharset());
+	mimeHeaders->SetRelativePathL(aMimeHeader->RelativePath());
+	mimeHeaders->SetContentSubTypeL(aMimeHeader->ContentSubType());
+	mimeHeaders->SetRelativePathL(aMimeHeader->RelativePath());
+	
+	CleanupStack::Pop(mimeHeaders);	
+	return mimeHeaders;
+	}
+	
+CImMimeHeader* CImEmailMessage::ConvertToImMimeHeadersL(CMsvMimeHeaders* aMimeHeaders)
+	{
+	CImMimeHeader* mimeHeader = CImMimeHeader::NewL();
+	CleanupStack::PushL(mimeHeader);
+	
+	mimeHeader->SetContentDescriptionL(aMimeHeaders->ContentDescription());
+	mimeHeader->SetContentBaseL(aMimeHeaders->ContentBase());
+	mimeHeader->SetContentLocationL(aMimeHeaders->ContentLocation());
+	mimeHeader->SetContentIDL(aMimeHeaders->ContentId());
+	mimeHeader->SetContentTypeL(aMimeHeaders->ContentType());
+	mimeHeader->SetContentDispositionL(aMimeHeaders->ContentDisposition());
+	mimeHeader->SetMimeCharset(aMimeHeaders->MimeCharset());
+	mimeHeader->SetRelativePathL(aMimeHeaders->RelativePath());
+	mimeHeader->SetContentSubTypeL(aMimeHeaders->ContentSubType());
+	mimeHeader->SetRelativePathL(aMimeHeaders->RelativePath());
+	CleanupStack::Pop(mimeHeader);	
+	return mimeHeader;
+	}	
+	
+void CImEmailMessage::AppendEntryAttachmentInfoL()
+	{
+	CMsvStore* store = iClientEntry.ReadStoreL();
+	CleanupStack::PushL(store);
+	MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+	// Modified to handle multiple attachments belonging to a single attachment entry
+	for(TInt i=0;i<attachmentMgr.AttachmentCount();i++)
+		{
+		CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(i);
+		CleanupStack::PushL(attachment);
+		attachment->SetSize(iEntry.iSize);
+		attachment->SetComplete(iEntry.Complete());
+		// For compatibility keep entry [0] as the TMsvId of the owning attachment entry
+		if(i == 0)
+			{
+			attachment->SetId(iClientEntry.EntryId());
+			}
+		else
+			{				
+			// Store the index and the owning attachment entry's TMsvId
+			attachment->SetIntAttributeL(KUidMsvEmailAttachmentEntryIndex,i);
+			attachment->SetIntAttributeL(KUidMsvEmailAttachmentEntryId,iClientEntry.EntryId());
+			attachment->SetId(iAttachmentManager->UniqueAttachmentId());
+			}
+		// Add to the per-message list of CMsvAttachments
+		User::LeaveIfError(iAttachmentManager->AttachmentInfoSelection().Append(attachment));
+		CleanupStack::Pop(attachment);				
+		}
+	CleanupStack::PopAndDestroy(store);		
+	}
+	
+TMsvId CImEmailMessage::EmailEntryId()
+	{
+	return iClientEntry.EntryId();
+	}
+
+/**
+This returns a object of CImPlainBodyText.This needs to be called when bodytext 
+needs to be restored in chunks for Read operation.
+@param aMessageId	The Message Id for which to get plain body text part.
+@param aEntryType   The TImEmailEntryType for this message.
+@return CMsvPlainBodyText
+*/
+EXPORT_C CImPlainBodyText* CImEmailMessage::OpenPlainBodyTextForReadL(TImEmailEntryType aEntryType, TInt aChunkLength)
+	{
+	CImPlainBodyText* plainBodyText = CImPlainBodyText::NewL(*this, iClientEntry, aEntryType, aChunkLength, EFalse);
+	return plainBodyText;
+	}
+
+/**
+This returns a object of CImPlainBodyText.This needs to be called when bodytext 
+needs to be created in chunks.
+@param aMessageId	  The id of the message whose bodytext needs to be edited.
+@return CImPlainBodyText
+*/	
+EXPORT_C CImPlainBodyText* CImEmailMessage::OpenPlainBodyTextForWriteL()
+	{
+	CImPlainBodyText* plainBodyText = CImPlainBodyText::NewL(*this, iClientEntry, CImEmailMessage::EThisMessageOnly, KMaxChunkLength, ETrue);
+	return plainBodyText;
+	}
+
+//
+// CImRemoveMessagePart
+//
+
+CImRemoveMessagePart* CImRemoveMessagePart::DeleteAttachmentL(TRequestStatus &aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, TMsvId aAttachmentId)
+	{
+	CImRemoveMessagePart* self = new(ELeave) CImRemoveMessagePart(aStatus, aMsvEntry, aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aAttachmentId);
+	CleanupStack::Pop(); //self
+	return self;
+	}
+
+CImRemoveMessagePart* CImRemoveMessagePart::DeleteAttachedMessageL(TRequestStatus &aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, TMsvId aAttachedMessageId)
+	{
+	// this does exactly the same as for DeleteAttachmentL() but this function is added to seperate deleting attachments/attached messages
+	CImRemoveMessagePart* self = new(ELeave) CImRemoveMessagePart(aStatus, aMsvEntry, aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aAttachedMessageId);
+	CleanupStack::Pop();
+	return self;
+	}
+
+CImRemoveMessagePart::~CImRemoveMessagePart()
+	{
+	Cancel();
+	delete iMsvOperation;
+	delete iMessageEntrySelection;
+	delete iEmailMessage;
+	}
+
+const TDesC8& CImRemoveMessagePart::FinalProgress()
+	{
+	__ASSERT_ALWAYS(!IsActive(), gPanic(EMiutActiveInFinalProgress));
+ 	const TDesC8* progress = &KNullDesC8();
+ 	TRAPD(leave, progress = &ProgressL());
+	__ASSERT_ALWAYS(leave == KErrNone, gPanic(EImcmFinalProgressFailed));
+	return *progress;	
+	}
+
+const TDesC8& CImRemoveMessagePart::ProgressL()
+	{
+	if (iState==EFinished)
+		iDataMember() = iMessageId;
+	return iDataMember;
+	}
+
+void CImRemoveMessagePart::DoCancel()
+	{
+	if (iMsvOperation)
+		iMsvOperation->Cancel();
+	if (iEmailMessage)
+		iEmailMessage->Cancel();
+	Recover();
+
+	TRequestStatus* st = &iObserverRequestStatus;
+	User::RequestComplete(st, KErrCancel);
+	}
+
+void CImRemoveMessagePart::SelectAndChangeToNextStateL()
+	{
+	SelectNextStateL();
+	ChangeStateL();
+	}
+
+void CImRemoveMessagePart::RunL()
+	{
+	if (iStatus.Int() != KErrNone)
+		{
+		ErrorRecovery(iStatus.Int());
+		return;
+		}
+	if ((iState == EMoveOtherEntryToParentOfFolder) || 
+		(iState == EDeleteAttachmentEntry) ||
+		(iState == EDeleteFolderEntry) ||
+		(iState == ECompleteRemoveMessagePart))
+		{
+		TInt sysProgressError = McliUtils::GetProgressErrorL(*iMsvOperation);
+		if (sysProgressError != KErrNone)
+			{
+			ErrorRecovery(sysProgressError);
+			return;
+			}
+		}
+	if (iState != EFinished)
+		{
+		TRAPD(error, SelectAndChangeToNextStateL());
+		if (error)
+			ErrorRecovery(error);
+		else if (iState != EFinished)
+			SetActive();
+		}
+	}
+
+CImRemoveMessagePart::CImRemoveMessagePart(TRequestStatus& aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId)
+	: CMsvOperation(aMsvEntry.Session(), EPriorityStandard, aStatus),
+	  iMsvEntry(aMsvEntry),
+	  iMessageId(aMessageId)
+	{
+	}
+
+void CImRemoveMessagePart::ConstructL(TMsvId aAttachmentId)
+	{
+	iDataMember = KMsvNullIndexEntryId;
+	iAttachmentId = aAttachmentId;
+	iFolderToDeleteId = KMsvNullIndexEntryId;
+	iEntryToMoveId = KMsvNullIndexEntryId;
+	iEmailMessage = CImEmailMessage::NewL(iMsvEntry);
+	
+	CActiveScheduler::Add(this);
+
+	TMsvId serviceId = KMsvNullIndexEntryId;
+	TMsvEmailEntry attachmentEntry;
+	iMsvEntry.Session().GetEntry(iAttachmentId, serviceId, attachmentEntry);
+	iAttachmentSize = attachmentEntry.iSize;
+	iState = ECheckAttachmentParentType;
+	ChangeStateL();
+
+	iObserverRequestStatus = KRequestPending;
+	SetActive();
+	}
+
+void CImRemoveMessagePart::ErrorRecovery(TInt error)
+	{
+	// if there is an error then leave message in a 'good' state
+	Recover();
+	
+	// complete the observer with error
+	TRequestStatus* status=&iObserverRequestStatus;
+	User::RequestComplete(status,error);
+	}
+
+void CImRemoveMessagePart::SelectNextStateL()
+	{
+	switch (iState)
+		{
+	// do move and then the delete because if the move fails, the message
+	// will still be in a good state
+	case ECheckAttachmentParentType:
+		{
+		// set entry to parent just in case GetAttachmentsListL changes context
+		TMsvId serviceId; // temp
+		TMsvEmailEntry attachmentEntry;
+		iMsvEntry.Session().GetEntry(iAttachmentId, serviceId, attachmentEntry);
+		iMsvEntry.SetEntryL(attachmentEntry.Parent());
+
+		iState = EDeleteAttachmentEntry;
+		}
+		break;
+	case EMoveOtherEntryToParentOfFolder:
+		iState = EDeleteFolderEntry;
+		break;
+	case EDeleteAttachmentEntry:
+		if (iFolderToDeleteId)
+			iState = EMoveOtherEntryToParentOfFolder;
+		else
+			iState = ECompleteRemoveMessagePart;
+		break;
+	case EDeleteFolderEntry:
+		iState = ECompleteRemoveMessagePart;
+		break;
+	case ECompleteRemoveMessagePart:
+		iState = EFinished;
+		break;
+	default:
+		User::LeaveIfError(KErrNotSupported);
+		}
+	}
+
+void CImRemoveMessagePart::ChangeStateL()
+	{
+	switch (iState)
+		{
+	case ECheckAttachmentParentType:
+		CheckAttachmentParentTypeL();
+		break;
+	case EMoveOtherEntryToParentOfFolder:
+		MoveOtherEntryToParentOfFolderL();
+		break;
+	case EDeleteAttachmentEntry:
+		DeleteAttachmentEntryL();
+		break;
+	case EDeleteFolderEntry:
+		DeleteFolderEntryL();
+		break;
+	case ECompleteRemoveMessagePart:
+		CompleteRemoveMessagePartL();
+		break;
+	case EFinished:
+		{
+		TRequestStatus* status=&iObserverRequestStatus;
+		User::RequestComplete(status,KErrNone);
+		}
+		}
+	}
+
+void CImRemoveMessagePart::RequestComplete(TInt aError)
+	{
+	iStatus = KRequestPending;
+	TRequestStatus* status=&iStatus;
+	iStatus=KRequestPending;
+	User::RequestComplete(status,aError);
+	}
+
+void CImRemoveMessagePart::Recover()
+	{
+	switch (iState)
+		{
+	case EDeleteFolderEntry:
+	case EDeleteAttachmentEntry:
+		// delete folder if one exists else delete attachment
+		if (iFolderToDeleteId)
+			iMsvEntry.Session().RemoveEntry(iFolderToDeleteId);
+		else
+			iMsvEntry.Session().RemoveEntry(iAttachmentId);
+		break;
+	case ECompleteRemoveMessagePart: // not fatal - details might be incorrect but delete already done
+	// for other states - original message not changed:
+	case EMoveOtherEntryToParentOfFolder:
+	case ECheckAttachmentParentType: 
+	case EFinished:	// operation completed anyway
+		break;
+		}
+	}
+
+void CImRemoveMessagePart::CheckAttachmentParentTypeL()
+	{
+	TMsvId serviceId; // temp
+	TMsvEmailEntry attachmentEntry;
+	iMsvEntry.Session().GetEntry(iAttachmentId, serviceId, attachmentEntry);
+	iMsvEntry.SetEntryL(attachmentEntry.Parent());
+
+	// get children of attachments parent
+	iMessageEntrySelection = iMsvEntry.ChildrenL();
+
+	TMsvEmailEntry parentEntry = iMsvEntry.Entry();
+	if (parentEntry.iType == KUidMsvFolderEntry)
+		{
+		// if there are 2 or less children, the other children need to be moved and then the folder deleted
+		if (iMessageEntrySelection->Count() <= 2)
+			iFolderToDeleteId = iMsvEntry.EntryId();
+		}
+	// if there are no other attachments then unset attachment flag in message
+	iEmailMessage->GetAttachmentsListL(iStatus, iMessageId, CImEmailMessage::EAllAttachments,CImEmailMessage::EThisMessageOnly);
+	}
+
+void CImRemoveMessagePart::MoveOtherEntryToParentOfFolderL()
+	{
+	// context on parent of attachment
+	// move entry to folder's parent
+	TInt i = iMessageEntrySelection->Count();
+	while (i--)
+		{
+		if ((*iMessageEntrySelection)[i] != iAttachmentId)
+			iEntryToMoveId = (*iMessageEntrySelection)[i];
+		}
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.MoveL(iEntryToMoveId, iMsvEntry.Entry().Parent(), iStatus);
+	}
+
+void CImRemoveMessagePart::DeleteAttachmentEntryL()
+	{
+	// context on parent of attachment
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.DeleteL(iAttachmentId, iStatus);
+	}
+
+void CImRemoveMessagePart::DeleteFolderEntryL()
+	{
+	// context on parent of attachment - i.e. folder
+	// move context to parent of folder before deleting folder
+	iMsvEntry.SetEntryL(iMsvEntry.Entry().Parent());
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.DeleteL(iFolderToDeleteId, iStatus);
+	}
+
+void CImRemoveMessagePart::CompleteRemoveMessagePartL()
+	{
+	iMsvEntry.SetEntryL(iMessageId);
+	TMsvEntry entry(iMsvEntry.Entry());
+
+	TInt count = iEmailMessage->AttachmentManager().AttachmentCount();
+	if (count)
+		{
+		entry.SetAttachment((count-1)); // minus one since we have removed attachment
+		}
+
+	// update the size
+	entry.iSize -= iAttachmentSize;
+
+	CMsvEntrySelection* selection = iMsvEntry.ChildrenWithTypeL(KUidMsvFolderEntry);
+	CleanupStack::PushL(selection);
+	CMsvStore* store = iMsvEntry.EditStoreL();
+	CleanupStack::PushL(store);
+
+	if (selection->Count()) // folder exist
+		{
+		TMsvEmailEntry childEntry = iMsvEntry.ChildDataL((*selection)[0]);
+	
+		CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+		mimeHeader->RestoreL(*store);
+		switch (childEntry.MessageFolderType())
+			{
+		case EFolderTypeAlternative:
+			mimeHeader->SetContentSubTypeL(KMimeAlternative);
+			break;
+		case EFolderTypeMixed:
+			mimeHeader->SetContentSubTypeL(KMimeMixed);
+			break;
+		case EFolderTypeRelated:
+			mimeHeader->SetContentSubTypeL(KMimeRelated);
+			break;
+		default:
+			User::Leave(KErrNotSupported);
+			}
+		mimeHeader->StoreL(*store);
+		store->CommitL();
+		CleanupStack::PopAndDestroy(); // mimeHeader
+		}
+	else if (store->IsPresentL(KUidMsgFileMimeHeader))
+		{
+		// if the child of the message is not a folder then the MimeHeader must be deleted
+		store->RemoveL(KUidMsgFileMimeHeader);
+		store->CommitL();
+		}
+	CleanupStack::PopAndDestroy(2); // selection, store
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry.ChangeL(entry, iStatus);
+	}
+	
+TMsvId CImRemoveMessagePart::RemovedAttachmentId()
+	{
+	return iAttachmentId;
+	}
+
+//
+// CImStoreMessagePart
+//
+
+CImStoreMessagePart* CImStoreMessagePart::AddAttachmentL(TMsvId aMessageId,const TDesC& aFilePath, CMsvEntry& aMsvEntry,CMsvAttachment* aAttachmentInfo,TRequestStatus& aStatus )
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry,aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aFilePath);
+	self->ConstructAttachmentInfo(aAttachmentInfo,EAddAttachment);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CImStoreMessagePart* CImStoreMessagePart::AddEntryAsAttachmentL(TMsvId aMessageId,TMsvId aAttachmentMessageId, CMsvEntry& aMsvEntry, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry, aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aAttachmentMessageId);
+	self->ConstructAttachmentInfo(aAttachmentInfo,EAddEntryAsAttachment);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CImStoreMessagePart* CImStoreMessagePart::AddAttachmentL(TMsvId aMessageId, RFile& aFile, CMsvEntry& aMsvEntry, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus) 	
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry,aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aFile);
+	self->ConstructAttachmentInfo(aAttachmentInfo,EAddAttachmentUsingFileHandle);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CImStoreMessagePart* CImStoreMessagePart::CreateAttachmentL(TMsvId aMessageId,const TDesC& aFileName, RFile& aAttachmentFile,CMsvEntry& aMsvEntry, CMsvAttachment* aAttachmentInfo, TRequestStatus& aStatus)	
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry,aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aAttachmentFile,aFileName);
+	self->ConstructAttachmentInfo(aAttachmentInfo,ECreateAttachment);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CImStoreMessagePart* CImStoreMessagePart::AddLinkedAttachmentL(TMsvId aMessageId,const TDesC& aFilePath, CMsvEntry& aMsvEntry,CMsvAttachment* aAttachmentInfo,TRequestStatus& aStatus )	
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry,aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aFilePath);
+	self->ConstructAttachmentInfo(aAttachmentInfo,EAddLinkedAttachment);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CImStoreMessagePart* CImStoreMessagePart::AddRelatedPartL(TRequestStatus &aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, const TDesC& aAttachmentFullName, TMsvId aRelatedPartId, const TDesC8& aContentId)
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry, aMessageId);
+	CleanupStack::PushL(self);
+	self->ConstructL(aAttachmentFullName, aRelatedPartId, aContentId);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CImStoreMessagePart* CImStoreMessagePart::StoreBodyTextL(TRequestStatus& aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, CRichText& aRichText, TBool aUsePlainTextStorage)
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry, aMessageId, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aRichText);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CImStoreMessagePart* CImStoreMessagePart::StoreBodyTextWithMimeHeaderL(TRequestStatus& aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, CRichText& aRichText, const CImMimeHeader& aMimeHeader, TBool aUsePlainTextStorage)
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry, aMessageId, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aRichText, aMimeHeader);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CImStoreMessagePart* CImStoreMessagePart::StorePlainBodyTextL(TRequestStatus& aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, TBool aUsePlainTextStorage)
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry, aMessageId, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(EMessagePartBody);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+
+	
+CImStoreMessagePart* CImStoreMessagePart::StorePlainBodyTextL(TRequestStatus& aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId,CImMimeHeader& aMimeHeader, TBool aUsePlainTextStorage)
+	{
+	CImStoreMessagePart* self = new(ELeave) CImStoreMessagePart(aStatus, aMsvEntry, aMessageId, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMimeHeader);
+	CleanupStack::Pop(self);
+	return self;
+	}
+		
+CImStoreMessagePart::~CImStoreMessagePart()
+	{
+	Cancel();
+	delete iMsvOperation;
+	delete iFileMan;
+	delete iMessageEntrySelection;
+	delete iAttachmentFullName;
+	delete iContentId;
+	delete iHtmlConverter;
+	delete iParaLayer;
+	delete iCharLayer;
+	delete iEmailMessage;
+	delete iRichText;
+	delete iStore;
+	delete iAttachmentInfo;
+	}
+
+const TDesC8& CImStoreMessagePart::FinalProgress()
+	{
+	__ASSERT_ALWAYS(!IsActive(), gPanic(EMiutActiveInFinalProgress));
+ 	const TDesC8* progress = &KNullDesC8();
+ 	TRAPD(leave, progress = &ProgressL());
+	__ASSERT_ALWAYS(leave == KErrNone, gPanic(EImcmFinalProgressFailed));
+	return *progress;	
+	}
+
+const TDesC8& CImStoreMessagePart::ProgressL()
+	{
+	if (iState==EFinished)
+		{
+		switch(iMessagePart)
+			{
+		case EMessagePartAttachment:
+		case EMessagePartMessageAttachment:
+			iDataMember() = iAttachmentId;
+			break;
+		case EMessagePartBody:
+			iDataMember() = iMessageId;
+			break;
+		default:
+			iDataMember() = KMsvNullIndexEntryId;
+			User::Leave(KErrNotSupported);
+			}
+		}
+	return iDataMember;
+	}
+
+void CImStoreMessagePart::DoCancel()
+	{
+	if (iMsvOperation)
+		iMsvOperation->Cancel();
+	if (iEmailMessage)
+		iEmailMessage->Cancel();
+
+	// If we are in a state where we are waiting for the attachment manager to
+	// complete us, then we need to cancel the attachment manager request
+	if ((iState == EStoreAttachment) || (iState == EAddEntryAttachment))
+		{
+		if (iStore != NULL)
+			{
+			MMsvAttachmentManager* attachmentMgr(NULL);
+
+			TRAPD(err, attachmentMgr = &(iStore->AttachmentManagerL()));
+
+			if (err == KErrNone)
+				{
+				attachmentMgr->CancelRequest();
+				}
+			}
+		}
+	else
+		{
+		// we are not waiting for the attachment manager to complete us,
+		// so the file handle needs to be closed by us.
+		if((iAttachmentInfo != NULL) && (iAttachmentCreateState == EAddAttachmentUsingFileHandle))
+			{
+			iFile.Close();
+			}
+		}
+
+	// Use ErrorRecovery routine to cleanup and complete the caller with KErrCancel
+	ErrorRecovery(KErrCancel);
+
+	}
+
+void CImStoreMessagePart::SelectAndChangeToNextStateL()
+	{
+	SelectNextStateL();
+	ChangeStateL();
+	}
+
+void CImStoreMessagePart::RunL()
+	{
+	if (iStatus.Int() != KErrNone)
+		{
+		ErrorRecovery(iStatus.Int());
+		return;
+		}
+	if ((iState == ECreateAttachmentEntry) || 
+		(iState == ECopyOrigMessageToMessage) || 
+		(iState == ECreateMultipartMixedFolderEntry) ||
+		(iState == ECreateMultipartRelatedFolderEntry) ||
+		(iState == ECreateMultipartAlternativeFolderEntry) ||
+		(iState == EMoveOriginalMessageEntryChildrenToNewFolder) ||
+		(iState == ECreateTextEntry) ||
+		(iState == EStoreRichText) ||
+		(iState == ECreateHTMLEntry) ||
+		(iState == ERemoveHTMLEntry && iHtmlId !=KMsvNullIndexEntryId) || 
+		(iState == EMoveTextToAlternativeFolder) ||
+		(iState == ECompleteStoreMessage))
+		{
+		TInt sysProgressError = McliUtils::GetProgressErrorL(*iMsvOperation);
+		if (sysProgressError != KErrNone)
+			{
+			ErrorRecovery(sysProgressError);
+			return;
+			}
+		}
+	if (iState != EFinished)
+		{
+		TRAPD(error, SelectAndChangeToNextStateL());
+		if (error)
+			ErrorRecovery(error);
+		else if (iState != EFinished)
+			SetActive();
+		}
+	}
+
+CImStoreMessagePart::CImStoreMessagePart(TRequestStatus& aStatus, CMsvEntry& aMsvEntry, TMsvId aMessageId, TBool aUsePlainTextStorage)
+	: CMsvOperation(aMsvEntry.Session(), EPriorityStandard, aStatus),
+	  iMsvEntry(aMsvEntry),
+	  iMessageId(aMessageId),
+	  iUsePlainTextStorage(aUsePlainTextStorage)
+	{
+	}
+
+void CImStoreMessagePart::OpenAndReadResourceFileL()
+	{
+	RResourceFile resourceFile;
+	OpenResourceFileL(resourceFile, iMsvSession.FileSession());
+	CleanupClosePushL(resourceFile);
+
+	if (iHtmlConverter)
+		iHtmlConverter->ReadDefaultAttachmentNameL(resourceFile);
+			
+	CleanupStack::PopAndDestroy(); // resourceFile (Close resourceFile)
+	}
+
+void CImStoreMessagePart::ConstructL()
+	{
+	iFlags = KStoreMessagePartClearFlag;
+	iDataMember = KMsvNullIndexEntryId;
+	iMixFolderId = KMsvNullIndexEntryId;
+	iAltFolderId = KMsvNullIndexEntryId;
+	iAttachmentId = KMsvNullIndexEntryId;
+	iTextId = KMsvNullIndexEntryId;
+	iHtmlId = KMsvNullIndexEntryId;
+
+	iFileMan = CFileMan::NewL(iMsvEntry.Session().FileSession());
+
+	iParaLayer = CParaFormatLayer::NewL();
+	iCharLayer = CCharFormatLayer::NewL();
+	iRichText = CRichText::NewL(iParaLayer, iCharLayer);
+	iEmailMessage = CImEmailMessage::NewL(iMsvEntry);
+	
+	CActiveScheduler::Add(this);
+
+	if (iRelatedPartId != KMsvNullIndexEntryId)
+		iState = EFindMultipartRelatedFolder;
+	else
+		iState = ECheckForSubfolder;
+	ChangeStateL();
+	
+
+	iObserverRequestStatus = KRequestPending;
+	SetActive();
+	}
+
+void CImStoreMessagePart::ConstructL(TImMessagePart aMessagePart)
+	{
+	iMessagePart = aMessagePart;
+	ConstructL();	
+	}
+	
+void CImStoreMessagePart::ConstructL(const TDesC& aAttachmentFullName)
+	{
+	iAttachmentFullName = aAttachmentFullName.AllocL();
+	iMessagePart = EMessagePartAttachment;
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructL(TMsvId aAttachmentMessageId)
+	{
+	iAttachmentMessageId = aAttachmentMessageId;
+	iMessagePart = EMessagePartMessageAttachment;
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructL(const TDesC& aAttachmentFullName, TMsvId aRelatedPartId, const TDesC8& aContentId)
+	{
+	iAttachmentFullName = aAttachmentFullName.AllocL();
+	iRelatedPartId = aRelatedPartId;
+	iMessagePart = EMessagePartAttachment;
+	iContentId = aContentId.AllocL();
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructL(CRichText& aRichText)
+	{
+	iRichTextToStore=&aRichText;
+	iMessagePart = EMessagePartBody;
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructL(CRichText& aRichText, const CImMimeHeader& aMimeHeader)
+	{
+	iRichTextToStore=&aRichText;
+	// We don't take ownership of the Mime header, we just 'flag' 
+	// its presence:
+	iMimeHeaderOfBodyText=const_cast<CImMimeHeader*>(&aMimeHeader);
+	iMessagePart = EMessagePartBody;
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructL(CImMimeHeader& aMimeHeader)
+	{
+	// We don't take ownership of the Mime header, we just 'flag' 
+	// its presence:
+	iMimeHeaderOfBodyText = &aMimeHeader;
+	iMessagePart = EMessagePartBody;
+	ConstructL();
+	}
+void CImStoreMessagePart::ConstructL(const TDesC& aAttachmentFullName, const TDesC8& aContentId)
+	{
+	iAttachmentFullName = aAttachmentFullName.AllocL();
+	iMessagePart = EMessagePartAttachment;
+	iContentId = aContentId.AllocL();
+	iStore=NULL;
+	ConstructL();
+	}
+	
+void CImStoreMessagePart::ConstructL(RFile& aFile)
+	{
+	iFile = aFile;
+	iFileHandle=&aFile;
+	iMessagePart = EMessagePartAttachment;
+	iIsAddByFileHandle = ETrue;
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructL(RFile& aFile,const TDesC& aAttachmentName)
+	{
+	iAttachmentFullName = aAttachmentName.AllocL();
+	iFileHandle=&aFile;
+	iMessagePart = EMessagePartAttachment;
+	iIsAddByFileHandle=ETrue;
+	ConstructL();
+	}
+
+void CImStoreMessagePart::ConstructAttachmentInfo(CMsvAttachment* aAttachmentInfo,TInt aAttachmentCreationState)
+	{
+	iAttachmentInfo = aAttachmentInfo;
+	iAttachmentCreateState = aAttachmentCreationState;
+	}
+	
+void CImStoreMessagePart::ErrorRecovery(TInt error)
+	{
+	iHtmlConverter->ResetStoreWithoutCommit();
+	// Close store if it is currently open for read or edit
+	if (iStore != NULL)
+		{
+		delete iStore;
+		iStore = NULL;
+		}
+	
+	// if there is an error then need to undo any changes
+	Recover();
+
+	// complete the observer with error
+	TRequestStatus* status=&iObserverRequestStatus;
+	User::RequestComplete(status,error);
+	}
+
+void CImStoreMessagePart::SelectNextStateL()
+	{
+	switch (iState)
+		{
+	case EFindMultipartRelatedFolder:
+		iState = ECheckForSubfolder;
+		break;
+	case ECheckForSubfolder:
+		// context on Message
+		if (iEmailMessage->Selection().Count())
+			iTextId = iEmailMessage->Selection().At(0);
+		SetTextPartExists(iEmailMessage->Selection().Count());
+		if (iMessagePart == EMessagePartAttachment)
+			{
+			if (iMessageEntrySelection->Count() && (iRelatedPartId == KMsvNullIndexEntryId) && (!MultipartMixedExists()))
+				// one item under message entry as we should have more than one entry under message entry
+				iState = ECreateMultipartMixedFolderEntry;
+			else if (iMessageEntrySelection->Count() && (iRelatedPartId != KMsvNullIndexEntryId) && (!MultipartRelatedExists())) 
+				{
+				// we want to add an attachment related to iRelatedPartId
+				if (MultipartMixedExists())
+					iMsvEntry.SetEntryL(iMixFolderId);
+				iState = ECreateMultipartRelatedFolderEntry;
+				}
+			else
+				{
+				// if multipart/related exists then set context to related
+				if (MultipartRelatedExists())
+					iMsvEntry.SetEntryL(iRelFolderId);
+				if (MultipartMixedExists())
+					iMsvEntry.SetEntryL(iMixFolderId);
+				iState = ECreateAttachmentEntry;
+				}
+			}
+		else if (iMessagePart == EMessagePartMessageAttachment)
+			{
+			if (iMessageEntrySelection->Count() && (iRelatedPartId == KMsvNullIndexEntryId) && (!MultipartMixedExists()))
+				// one item under message entry as we should have more than one entry under message entry
+				iState = ECreateMultipartMixedFolderEntry;
+			else 
+				iState = ECopyOrigMessageToMessage;
+			}
+		else if (iMessagePart == EMessagePartBody)
+			{
+	        if (HTMLMessage() && iHtmlConverter)
+	            {
+	            if (iTextId != KMsvNullIndexEntryId)
+		            {
+		            if (MultipartAlternativeExists())
+		                {
+		                // Alternative folder exists - continue as normal...
+		                iState = EStoreRichText;
+		                }
+	                else
+						{	
+						// This is an HTML message and the text entry already
+						// exists. Need to check that the text entry's parent
+						// is an alternative folder.
+						TMsvId serviceId = KMsvNullIndexEntryId;
+						TMsvEmailEntry entry;
+						// Get text entry...
+						iMsvEntry.Session().GetEntry(iTextId, serviceId, entry);
+						// ...and then its parent
+						iMsvEntry.Session().GetEntry(entry.Parent(), serviceId, entry);
+						if (entry.MessageFolderType() != EFolderTypeAlternative)
+							{
+						   // The situation is that a text entry exist, but there
+	                       // is no alternative folder for. This is probably cos
+                           // the message was originally plain, but has been changed
+                           // to be an HTML message. Create the alternative folder
+                           // under the text entry's parent.
+	                       if (iMsvEntry.EntryId() != entry.Id())
+		                       {
+		                       // Ensure that entry text entry's parent
+		                       iMsvEntry.SetEntryL(entry.Id());
+							   }
+			                  iState = ECreateMultipartAlternativeFolderEntry;
+		                   }
+						else
+						   {
+			              // Alternative folder exists - continue as normal...
+	                      iState = EStoreRichText;
+						   }
+						}
+					}
+				else
+					{
+					// No text entry exists - need to create an alternative folder
+					iState = ECreateMultipartAlternativeFolderEntry;
+					}
+				}
+			else if (iTextId != KMsvNullIndexEntryId)
+				iState = EStoreRichText;
+			else if (iMessageEntrySelection->Count() && (!MultipartMixedExists())) // one item under message entry
+				iState = ECreateMultipartMixedFolderEntry;
+			else
+				{
+				if (MultipartMixedExists())
+					iMsvEntry.SetEntryL(iMixFolderId);
+				iState = ECreateTextEntry;
+				}
+			}
+		break;
+	case ECreateMultipartMixedFolderEntry:
+		{
+		SetMultipartMixedCreated(ETrue);
+		iMixFolderId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iMsvEntry.SetEntryL(iMixFolderId);
+		switch (iMessagePart)
+			{
+		case EMessagePartAttachment:
+		case EMessagePartMessageAttachment:
+			if ((iRelatedPartId != KMsvNullIndexEntryId) && (!MultipartRelatedExists()))
+				iState = ECreateMultipartRelatedFolderEntry;
+			else if (iMessagePart == EMessagePartAttachment)
+				iState = ECreateAttachmentEntry;
+			else if (iMessagePart == EMessagePartMessageAttachment)
+				iState = ECopyOrigMessageToMessage;
+			break;
+		case EMessagePartBody:
+			if (HTMLMessage())
+				iState = ECreateMultipartAlternativeFolderEntry;
+			else
+				iState = ECreateTextEntry;
+			break;
+		default:
+			User::Leave(KErrNotSupported);
+			}
+		}
+		break;
+	case ECreateMultipartRelatedFolderEntry:
+		{
+		SetMultipartRelatedCreated(ETrue);
+		iRelFolderId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iMsvEntry.SetEntryL(iRelFolderId);
+		iState = ECreateAttachmentEntry;
+		}
+		break;
+	case ECreateAttachmentEntry:
+		{
+		SetAttachmentEntryCreated(ETrue);
+		iAttachmentId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iMsvEntry.SetEntryL(iAttachmentId);
+		// we only need to store the attachment if the path is provided - otherwise, only 
+		// the entry needs to be created so that the actual attachment can be added later.
+		if(iIsAddByFileHandle || iAttachmentFullName->Length())	
+			iState = EStoreAttachment;
+		else if (MultipartMixedCreated() || MultipartRelatedCreated())
+			iState = EMoveOriginalMessageEntryChildrenToNewFolder;
+		else
+			iState = ECompleteStoreMessage;
+		}
+		break;
+	case EStoreAttachment:
+		iStore->CommitL();
+	
+		delete iStore;
+		iStore = NULL;	
+		
+		if (MultipartMixedCreated() || MultipartRelatedCreated())
+			iState = EMoveOriginalMessageEntryChildrenToNewFolder;
+		else
+			iState = ECompleteStoreMessage;
+		break;
+	case ECopyOrigMessageToMessage:
+		{
+		iAttachmentId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iState = EAddEntryAttachment;
+		}
+		break;
+	case ECreateMultipartAlternativeFolderEntry:
+		{
+		iAltFolderId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iMsvEntry.SetEntryL(iAltFolderId);
+		SetMultipartAlternativeCreated(ETrue);
+		SetMultipartAlternativeExists(ETrue);
+		
+		// Text Entry was already created without alternative folder . 
+		// This is because of change in email settings from Plain (when creating the message) 
+		// to Formatted (when sending the message)
+		if(iTextId != KMsvNullIndexEntryId)
+			iState = EMoveTextToAlternativeFolder;
+		else 
+			iState = ECreateTextEntry;
+		}
+		break;
+	case EMoveTextToAlternativeFolder:
+		{
+		iState = EStoreRichText;
+		}
+		break;
+	case ECreateTextEntry:
+		if (iTextId == KMsvNullIndexEntryId)
+			{
+			iTextId = McliUtils::GetProgressIdL(*iMsvOperation);
+			}
+		iState = EStoreRichText;
+		break;
+	case EStoreRichText:
+		// a text part has been created ONLY if one did not exist previously
+		SetTextPartCreated(!TextPartExists());
+		if (TextPartExists() && MultipartAlternativeCreated())
+			{
+			// The text entry already existed, but an alternative folder had to
+			// created. This is probably due to the message being originally
+			// plain and then being changed to be an HTML message. Need to create
+			// the HTML entry.
+			iState = ECreateHTMLEntry;
+			}
+		else if (TextPartExists() && iHtmlConverter)
+			{
+			// create HTML alternative if HTML message and text part just created
+			iState = EPrepareToStoreHTMLEntryText;
+			}
+		else if (!HTMLMessage() && !TextPartCreated())
+			{
+			// The message is a non-HTML message, and this is not the first time
+			// that the message body has been stored. Need to remove an HTML 
+			// entry if it exists.
+			iState = ERemoveHTMLEntry;
+			}
+		else if (HTMLMessage() && (TextPartCreated() || MultipartAlternativeCreated()))
+			iState = ECreateHTMLEntry;
+		else if (MultipartMixedCreated())
+			iState = EMoveOriginalMessageEntryChildrenToNewFolder;
+		else
+			iState = ECompleteStoreMessage;
+		break;
+	case ECreateHTMLEntry:
+		{
+		iHtmlId = McliUtils::GetProgressIdL(*iMsvOperation);
+		// Store character set info in a MimeHeader.
+		iMsvEntry.SetEntryL(iHtmlId);
+		CMsvStore* store = iMsvEntry.EditStoreL();
+		CleanupStack::PushL(store);
+		CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+		mimeHeader->SetMimeCharset(KCharacterSetIdentifierUtf8);
+		mimeHeader->StoreL(*store);
+		store->CommitL();
+		CleanupStack::PopAndDestroy(2,store); //mimeHeader, store
+		iState = EPrepareToStoreHTMLEntryText;
+		}
+		break;
+	case EPrepareToStoreHTMLEntryText:
+		iFinishedConvertingHTML=EFalse;
+		if(iUsePlainTextStorage && iRestoreErr == KErrNoMemory)
+			{
+			// If iRestoreErr is KErrNoMemory then complete the store message operation.
+			iState = ECompleteStoreMessage;	
+			}
+		else
+			{
+			iState = iHtmlId ? EStoreHTMLEntryText : ECompleteStoreMessage;	
+			}
+		break;
+	case EStoreHTMLEntryText:
+		if (!iFinishedConvertingHTML)
+			break;
+		iState = EStoreHTMLTextInEntry;
+		iHtmlConverter->ResetStoreL();	
+		break;
+	case EStoreHTMLTextInEntry:
+		if (MultipartMixedCreated())
+			iState = EMoveOriginalMessageEntryChildrenToNewFolder;
+		else
+			iState = ECompleteStoreMessage;
+		break;
+	case EAddEntryAttachment:
+		{
+		iStore->CommitL();
+		delete iStore;
+		iStore = NULL;
+					
+		if (MultipartMixedCreated() || MultipartRelatedCreated())
+			iState = EMoveOriginalMessageEntryChildrenToNewFolder;
+		else
+			{
+			// AddEntryAsAttachmentL() was called in this state and resets iMsvEntry.
+			// Next state requires that it's set to the messageId
+			// DEF 050410
+			iMsvEntry.SetEntryL(iMessageId);
+			iState = ECompleteStoreMessage;
+			}
+		} break;
+	case ERemoveHTMLEntry:
+		{
+		iState = ECompleteStoreMessage;
+		} break;
+	case EMoveOriginalMessageEntryChildrenToNewFolder:
+		iState = ECompleteStoreMessage;
+		break;
+	case ECompleteStoreMessage:
+		iState = EFinished;
+		break;
+	default:
+		gPanic(EImcmUnknownState);
+		}
+	}
+
+void CImStoreMessagePart::ChangeStateL()
+	{
+	CMsvOperation* op;
+	switch (iState)
+		{
+	case EFindMultipartRelatedFolder:
+		FindMultipartRelatedFolderL();
+		break;
+	case ECheckForSubfolder:
+		CheckForSubfolderL();
+		break;
+	case ECreateMultipartMixedFolderEntry:
+		CreateMultipartMixedFolderEntryL();
+		break;
+	case ECreateMultipartRelatedFolderEntry:
+		CreateMultipartRelatedFolderEntryL();
+		break;
+	case ECreateAttachmentEntry:
+		CreateAttachmentEntryL();
+		break;
+	case EStoreAttachment:
+		{
+		// store the attachment
+		DoAttachmentStoreL();
+		}
+		break;
+	case ECopyOrigMessageToMessage:
+		CopyOrigMessageToMessageL();
+		break;
+	case ECreateMultipartAlternativeFolderEntry:
+		CreateMultipartAlternativeFolderEntryL();
+		break;
+	case EMoveTextToAlternativeFolder:
+		// This case arrives when the email settings was plain while the message was created and 
+		// the setting is changed to formatted (html) while sending.
+		MoveTextEntryToAltFolderL();
+		break;
+	case ECreateTextEntry:
+		CreateTextEntryL();
+		break;
+	case EStoreRichText:
+		StoreRichTextL();
+		break;
+	case ECreateHTMLEntry:
+		CreateHTMLEntryL();
+		break;
+	case EPrepareToStoreHTMLEntryText:
+		TRAP(iRestoreErr ,iHtmlConverter->PrepareToStoreHTMLEntryTextL(iHtmlId, iTextId));
+		// Do not leave if it is KErrNoMemory while creating HTML part for a message, since the 
+		// plainbody text part of message is already created and that be used to send the message.
+		if(iUsePlainTextStorage)
+			{
+			if(iRestoreErr != KErrNoMemory)
+				{
+				User::LeaveIfError(iRestoreErr);
+				}
+			}
+		else
+			{
+			User::LeaveIfError(iRestoreErr);
+			}
+		
+		RequestComplete(KErrNone);
+		break;
+	case EStoreHTMLEntryText:
+		iFinishedConvertingHTML = iHtmlConverter->StoreHTMLEntryTextAL(iStatus);
+		if (!iFinishedConvertingHTML)
+			RequestComplete(KErrNone);
+		break;
+	case EStoreHTMLTextInEntry:
+		op = iHtmlConverter->ChangeHTMLTextInEnrtyL(iStatus);
+		if (!op)
+			{
+			RequestComplete(KErrNone);
+			}
+		else
+			{
+			delete iMsvOperation;
+			iMsvOperation = op;
+			}
+		break;
+	case EAddEntryAttachment:
+		AddEntryAsAttachmentL();		
+		break;
+	case ERemoveHTMLEntry:
+		{
+		RemoveHTMLEntryL();
+		} break;
+	case EMoveOriginalMessageEntryChildrenToNewFolder:
+		MoveOriginalMessageEntryChildrenToNewFolderL();
+		break;
+	case ECompleteStoreMessage:
+		CompleteStoreMessagePartL();
+		break;
+	case EFinished:
+		{
+		TRequestStatus* status=&iObserverRequestStatus;
+		User::RequestComplete(status,KErrNone);
+		}
+		break;
+	default:
+		gPanic(EImcmUnknownState);
+		}
+	}
+
+void CImStoreMessagePart::RequestComplete(TInt aError)
+	{
+	iStatus = KRequestPending;
+	TRequestStatus* status=&iStatus;
+	iStatus=KRequestPending;
+	User::RequestComplete(status,aError);
+	}
+
+void CImStoreMessagePart::Recover()
+	{
+	switch (iState)
+		{
+	case ECreateHTMLEntry:
+	case EStoreRichText:
+	case ERemoveHTMLEntry:
+	case ECreateTextEntry:
+	case ECreateMultipartAlternativeFolderEntry:
+	case ECreateMultipartRelatedFolderEntry:
+	case EPrepareToStoreHTMLEntryText:
+	case EStoreHTMLEntryText:
+		if (MultipartMixedCreated()) // iMixFolderId set when folder created
+			iMsvEntry.Session().RemoveEntry(iMixFolderId);
+		else if (MultipartRelatedCreated())
+			iMsvEntry.Session().RemoveEntry(iRelFolderId);
+		else if (MultipartAlternativeCreated())
+			iMsvEntry.Session().RemoveEntry(iAltFolderId);
+		else if (TextPartCreated())
+			iMsvEntry.Session().RemoveEntry(iTextId);
+		break;
+	case EMoveOriginalMessageEntryChildrenToNewFolder:
+	case ECopyOrigMessageToMessage:
+	case EStoreAttachment:
+	case EMoveTextToAlternativeFolder:
+	case ECreateAttachmentEntry:
+		{
+		if (MultipartMixedCreated())
+			iMsvEntry.Session().RemoveEntry(iMixFolderId);
+		else if (MultipartRelatedCreated())
+			iMsvEntry.Session().RemoveEntry(iRelFolderId);
+		else if (MultipartAlternativeCreated())
+			iMsvEntry.Session().RemoveEntry(iAltFolderId);
+		else if (iAttachmentId != KMsvNullIndexEntryId)
+			iMsvEntry.Session().RemoveEntry(iAttachmentId);
+		}
+		break;
+	// for other states - original message not changed:
+	case ECompleteStoreMessage: // message details may be incorrect but structure is ok to send
+	case ECreateMultipartMixedFolderEntry:
+	case ECheckForSubfolder:
+	case EFindMultipartRelatedFolder:
+	case EFinished:	// operation completed anyway
+		break;
+	default:
+		// shouldn't get to this state
+		__ASSERT_DEBUG(EFalse, gPanic(EImcmUnknownState));
+		}
+	}
+
+TBool CImStoreMessagePart::HTMLMessage() const
+	{
+	return iFlags & KStoreMessagePartHTMLMessage;
+	}
+
+void CImStoreMessagePart::SetHTMLMessage(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartHTMLMessage) | (aFlag ? KStoreMessagePartHTMLMessage : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::MultipartMixedExists() const
+	{
+	return iFlags & KStoreMessagePartMultipartMixedExists;
+	}
+
+void CImStoreMessagePart::SetMultipartMixedExists(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartMultipartMixedExists) | (aFlag ? KStoreMessagePartMultipartMixedExists : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::MultipartMixedCreated() const
+	{
+	return iFlags & KStoreMessagePartMultipartMixedCreated;
+	}
+
+void CImStoreMessagePart::SetMultipartMixedCreated(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartMultipartMixedCreated) | (aFlag ? KStoreMessagePartMultipartMixedCreated : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::MultipartAlternativeExists() const
+	{
+	return iFlags & KStoreMessagePartMultipartAlternativeExists;
+	}
+
+void CImStoreMessagePart::SetMultipartAlternativeExists(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartMultipartAlternativeExists) | (aFlag ? KStoreMessagePartMultipartAlternativeExists : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::MultipartAlternativeCreated() const
+	{
+	return iFlags & KStoreMessagePartMultipartAlternativeCreated;
+	}
+
+void CImStoreMessagePart::SetMultipartAlternativeCreated(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartMultipartAlternativeCreated) | (aFlag ? KStoreMessagePartMultipartAlternativeCreated : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::MultipartRelatedExists() const
+	{
+	return iFlags & KStoreMessagePartMultipartRelatedExists;
+	}
+
+void CImStoreMessagePart::SetMultipartRelatedExists(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartMultipartRelatedExists) | (aFlag ? KStoreMessagePartMultipartRelatedExists : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::MultipartRelatedCreated() const
+	{
+	return iFlags & KStoreMessagePartMultipartRelatedCreated;
+	}
+
+void CImStoreMessagePart::SetMultipartRelatedCreated(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartMultipartRelatedCreated) | (aFlag ? KStoreMessagePartMultipartRelatedCreated : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::TextPartExists() const
+	{
+	return iFlags & KStoreMessagePartTextPartExists;
+	}
+
+void CImStoreMessagePart::SetTextPartExists(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartTextPartExists) | (aFlag ? KStoreMessagePartTextPartExists : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::TextPartCreated() const
+	{
+	return iFlags & KStoreMessagePartTextPartCreated;
+	}
+
+void CImStoreMessagePart::SetTextPartCreated(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartTextPartCreated) | (aFlag ? KStoreMessagePartTextPartCreated : KStoreMessagePartClearFlag);
+	}
+
+TBool CImStoreMessagePart::AttachmentEntryCreated() const
+	{
+	return iFlags & KStoreMessagePartAttachmentEntryCreated;
+	}
+
+void CImStoreMessagePart::SetAttachmentEntryCreated(TBool aFlag)
+	{
+	iFlags = (iFlags & ~KStoreMessagePartAttachmentEntryCreated) | (aFlag ? KStoreMessagePartAttachmentEntryCreated : KStoreMessagePartClearFlag);
+	}
+
+void CImStoreMessagePart::FindMultipartRelatedFolderL()
+	{
+	TMsvId serviceId = KMsvNullIndexEntryId;
+	TMsvEmailEntry entry;
+	iMsvEntry.Session().GetEntry(iRelatedPartId, serviceId, entry);
+	iMsvEntry.SetEntryL(entry.Parent());
+	entry = iMsvEntry.Entry();
+	switch (entry.MessageFolderType())
+		{
+	case EFolderTypeRelated:
+		iRelFolderId = entry.Id();
+		SetMultipartRelatedExists(ETrue);
+		break;
+	case EFolderTypeAlternative:
+		iAltFolderId = entry.Id();
+		iMsvEntry.Session().GetEntry(iAltFolderId, serviceId, entry);
+		iMsvEntry.SetEntryL(entry.Parent());
+		entry = iMsvEntry.Entry();
+		if (entry.MessageFolderType() == EFolderTypeRelated)
+			{
+			iRelFolderId = entry.Id();
+			SetMultipartRelatedExists(ETrue);
+			}
+		break;
+	default:
+		User::Leave(KErrNotSupported);
+		}
+	RequestComplete(KErrNone);
+	}
+
+void CImStoreMessagePart::CheckForSubfolderL()
+	{
+	/* 
+	//	Check whether the message entry has a multipart mixed folder under it.
+	*/
+	iMsvEntry.SetEntryL(iMessageId);
+	TMsvEmailEntry emailEntry = iMsvEntry.Entry();
+	SetHTMLMessage(emailEntry.MHTMLEmail());
+	if (HTMLMessage())
+		{
+		TRAPD(err,iHtmlConverter=CImHtmlConverter::NewL(iMsvEntry, *iParaLayer, *iCharLayer));
+ 		if (err)
+			{
+			if (err == KErrNoMemory)
+				User::Leave(KErrNoMemory);
+			else
+				gPanic(EImcmHtmlConverterNotFound);
+			}
+
+		// Need to check if the Html converter has been created as we only open the resource file
+		// to get the default html attachment name.
+		if (iHtmlConverter)
+			OpenAndReadResourceFileL();
+		}
+
+	iMessageEntrySelection = iMsvEntry.ChildrenL();
+	CMsvEntrySelection* entrySelection = iMsvEntry.ChildrenWithTypeL(KUidMsvFolderEntry);
+	CleanupStack::PushL(entrySelection);
+
+	if (entrySelection->Count())
+		{
+		__ASSERT_DEBUG(entrySelection->Count() == 1, gPanic(EImcmMessageEntryHasMoreThanOneFolder));
+		emailEntry = iMsvEntry.ChildDataL((*entrySelection)[0]);
+		if (emailEntry.MessageFolderType() == EFolderTypeMixed)
+			{
+			iMixFolderId = (*entrySelection)[0];
+			SetMultipartMixedExists(ETrue);
+			}
+		else if (emailEntry.MessageFolderType() == EFolderTypeRelated)
+			{
+			iRelFolderId = (*entrySelection)[0];
+			SetMultipartRelatedExists(ETrue);
+			}
+		else if (emailEntry.MessageFolderType() == EFolderTypeAlternative)
+			{
+			iAltFolderId = (*entrySelection)[0];
+			SetMultipartAlternativeExists(ETrue);
+			}
+		}
+
+	CleanupStack::PopAndDestroy(); // entrySelection
+	
+	iEmailMessage->GetBodyTextEntryIdL(iMessageId, CImEmailMessage::EThisMessageOnly);	
+	TBool isPlainText = EFalse;
+	if(iEmailMessage->Selection().Count())
+		{
+		TMsvId textId = iEmailMessage->Selection().At(0);	
+		iMsvEntry.SetEntryL(textId);// pointing to the text entry
+			
+		if(iMsvEntry.HasStoreL())
+			{
+			CMsvStore* bodyTextStore = iMsvEntry.ReadStoreL();
+			CleanupStack::PushL(bodyTextStore);
+			
+			// Check if the original message was stored as plain text.
+			if(iUsePlainTextStorage)
+				{
+				isPlainText = (bodyTextStore->IsPresentL(KMsvPlainBodyText16) || bodyTextStore->IsPresentL(KMsvPlainBodyText8));
+				}			
+			
+			// This is not a richtext message.	
+			if(isPlainText)
+				{
+				CMsvPlainBodyText* textOrig = bodyTextStore->InitialisePlainBodyTextForReadL(KMaxChunkLength);	
+				iSizeFwdReplyBody = textOrig->Size();
+				
+				delete textOrig;
+
+				// Need to release body text store before changing to a new entry
+				CleanupStack::PopAndDestroy(bodyTextStore);
+
+				iMsvEntry.SetEntryL(iMessageId);
+
+				TRequestStatus* myStatus=&iStatus;
+				iStatus=KRequestPending;
+				User::RequestComplete(myStatus,KErrNone);	
+				}
+			else
+				{
+				CleanupStack::PopAndDestroy(bodyTextStore);
+				iMsvEntry.SetEntryL(iMessageId);
+				iEmailMessage->GetBodyTextL(iStatus, iMessageId, CImEmailMessage::EThisMessageOnly, *iRichText, *iParaLayer, *iCharLayer);	
+				}
+			}
+		else
+			{
+			iMsvEntry.SetEntryL(iMessageId);
+			iEmailMessage->GetBodyTextL(iStatus, iMessageId, CImEmailMessage::EThisMessageOnly, *iRichText, *iParaLayer, *iCharLayer);	
+			}
+		}
+	else
+		{
+		iMsvEntry.SetEntryL(iMessageId);
+		iEmailMessage->GetBodyTextL(iStatus, iMessageId, CImEmailMessage::EThisMessageOnly, *iRichText, *iParaLayer, *iCharLayer);	
+		}	
+	}
+
+void CImStoreMessagePart::CreateMultipartMixedFolderEntryL()
+	{
+	iMsvEntry.SetEntryL(iMessageId);
+
+	TMsvEmailEntry entry;
+	entry.iType = KUidMsvFolderEntry;
+	entry.iMtm = iMsvEntry.Entry().iMtm;
+	entry.iServiceId = iMsvEntry.Entry().iServiceId;
+	entry.SetMessageFolderType(EFolderTypeMixed);
+	entry.iSize = 0;
+
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry.CreateL(entry, iStatus);
+	}
+
+void CImStoreMessagePart::CreateMultipartRelatedFolderEntryL()
+	{
+	TMsvEmailEntry entry;
+	entry.iType = KUidMsvFolderEntry;
+	entry.iMtm = iMsvEntry.Entry().iMtm;
+	entry.iServiceId = iMsvEntry.Entry().iServiceId;
+	entry.SetMessageFolderType(EFolderTypeRelated);
+	entry.iSize = 0;
+
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry.CreateL(entry, iStatus);
+	}
+
+void CImStoreMessagePart::CreateAttachmentEntryL()
+	{
+	// create the index entry
+	TMsvEntry entry;
+	entry.iMtm = iMsvEntry.Entry().iMtm;
+	entry.iServiceId = iMsvEntry.Entry().iServiceId;
+	entry.iType = KUidMsvAttachmentEntry;
+	entry.iDate.UniversalTime();
+	entry.SetAttachment(ETrue);
+	entry.SetInPreparation(ETrue);
+	TParse parse;
+	if(!iIsAddByFileHandle)
+		{
+	//if the attachment path is set then set details, otherwise just create the entry.
+	if (iAttachmentFullName->Length())
+		{
+		parse.Set(iAttachmentFullName->Des(), NULL, NULL);
+		entry.iDetails.Set(parse.NameAndExt());
+
+		// Set the size of the attachment
+		TEntry attEntry;
+		iMsvEntry.Session().FileSession().Entry(iAttachmentFullName->Des(), attEntry);
+		iAttachmentSize = attEntry.iSize;
+		entry.iSize = iAttachmentSize;
+		}
+		}
+	else if(iIsAddByFileHandle)
+		{
+		SetEntryDetailsL(entry);
+		}
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.CreateL(entry, iStatus);
+	}
+	
+void CImStoreMessagePart::DoAttachmentStoreL()
+	{
+	if(iRelatedPartId)
+		{
+		delete iAttachmentInfo;
+		iAttachmentInfo=NULL;
+		iAttachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+		iAttachmentCreateState = EAddAttachment;	
+		}
+	switch(iAttachmentCreateState)	
+		{
+	case ECreateAttachment:
+		{
+		CreateAttachmentL();
+		}
+		break;
+	case EAddAttachment:
+		{
+		AddAttachmentL();	
+		}
+	break;	
+	case EAddAttachmentUsingFileHandle:
+		{
+		AddAttachmentUsingFileHandleL();
+		}
+	break;	
+	case  EAddLinkedAttachment:
+		{
+		AddLinkedAttachmentL();	
+		}
+	break;
+	case EAddEntryAsAttachment:
+		{
+		AddEntryAsAttachmentL();
+		}
+	break;	
+	default:
+	__ASSERT_DEBUG(EFalse, User::Invariant());
+	break;
+		}
+	}
+	
+void CImStoreMessagePart::CreateAttachmentL()
+	{
+	
+	iStore = iMsvEntry.EditStoreL();
+	
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	attachmentMgr.CreateAttachmentL(iAttachmentFullName->Des(),(*iFileHandle),iAttachmentInfo,iStatus);
+	iAttachmentInfo=NULL; 
+	}
+	
+void CImStoreMessagePart::AddAttachmentL()
+	{
+	iStore = iMsvEntry.EditStoreL();
+	
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	attachmentMgr.AddAttachmentL(iAttachmentFullName->Des(),iAttachmentInfo,iStatus); 
+	iAttachmentInfo=NULL; 
+	}
+void CImStoreMessagePart::AddAttachmentUsingFileHandleL()	
+	{
+
+	iStore = iMsvEntry.EditStoreL();
+	
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	attachmentMgr.AddAttachmentL((*iFileHandle),iAttachmentInfo,iStatus);
+	iAttachmentInfo=NULL; 
+	}
+	
+void CImStoreMessagePart::AddLinkedAttachmentL()	
+	{
+
+	iStore = iMsvEntry.EditStoreL();
+	
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	attachmentMgr.AddLinkedAttachmentL(iAttachmentFullName->Des(),iAttachmentInfo,iStatus);
+	iAttachmentInfo=NULL; 
+	}
+	
+void CImStoreMessagePart::AddEntryAsAttachmentL()	
+	{
+
+	iMsvEntry.SetEntryL(iAttachmentId);
+	iStore = iMsvEntry.EditStoreL();
+	
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	attachmentMgr.AddEntryAsAttachmentL(iAttachmentMessageId,iAttachmentInfo,iStatus);
+	iAttachmentInfo=NULL; 
+	}
+
+TInt CImStoreMessagePart::CheckMimeInAttachmentInfoL(CMsvMimeHeaders& aMsvMimeHeaders)
+	{
+	if(!iMsvEntry.HasStoreL())
+		return KErrNotFound;
+	
+	CMsvStore* store  = iMsvEntry.ReadStoreL();
+	CleanupStack::PushL(store);
+	// get the attachment info
+	MMsvAttachmentManager& attachmentMgr = 	store->AttachmentManagerL();
+	TInt mimefound = KErrNotFound;
+	if(attachmentMgr.AttachmentCount())
+		{
+		// one attachment per attachment entry in email
+		CMsvAttachment* attachmentInfo = attachmentMgr.GetAttachmentInfoL(0);
+		CleanupStack::PushL(attachmentInfo);
+		TPtrC8 bufferPtr;
+		// check if attachment info had mimeheaders
+			mimefound =  attachmentInfo->GetDesC8Attribute(KUidMimeHeaders, bufferPtr);
+		
+		// mimeheaders found
+		if(mimefound == KErrNone)
+			aMsvMimeHeaders.RestoreL(*attachmentInfo);
+	
+		CleanupStack::PopAndDestroy(attachmentInfo);	
+		}
+	CleanupStack::PopAndDestroy(store); 
+	return mimefound;		
+	}
+	
+CImMimeHeader* CImStoreMessagePart::ProcessAttachmentMimeHeadersL()
+	{
+	CImMimeHeader* mimeHeader = NULL;
+	CMsvMimeHeaders* msvMimeHeaders = CMsvMimeHeaders::NewLC();
+	TInt err = CheckMimeInAttachmentInfoL(*msvMimeHeaders);
+	if(err == KErrNone)
+		{
+		// convert the CMsvMimeHeaders in attactment info to CImMimeHeader
+		mimeHeader = iEmailMessage->ConvertToImMimeHeadersL(msvMimeHeaders);
+		CleanupStack::PushL(mimeHeader);
+
+		CMsvStore* store = iMsvEntry.EditStoreL();
+		CleanupStack::PushL(store);
+		mimeHeader->StoreL(*store);
+		store->CommitL();				
+		CleanupStack::PopAndDestroy(store);
+		
+		CleanupStack::Pop(mimeHeader);//mimeHeader
+		}
+	CleanupStack::PopAndDestroy(msvMimeHeaders);
+	return mimeHeader;	
+	}	
+
+void CImStoreMessagePart::SetEntryDetailsL(TMsvEntry& aEntry)	
+	{
+	if(iAttachmentFullName)
+		{
+		// for create attachment name is set by user
+		aEntry.iDetails.Set(iAttachmentFullName->Des());
+		}
+	else
+		{
+		// adding the attachment using file handle. , get the name from handle
+		TFileName fileName;
+		User::LeaveIfError(iFileHandle->Name(fileName));
+		aEntry.iDetails.Set(fileName);
+		}
+	// get the size of the file from the handle	if add by file handle
+	if(iAttachmentCreateState != ECreateAttachment)
+		{
+		iFileHandle->Size(iAttachmentSize);
+		aEntry.iSize = iAttachmentSize;		
+		}
+	}		
+
+
+void CImStoreMessagePart::CopyOrigMessageToMessageL()
+	{
+	TMsvId serviceId;
+	TMsvEmailEntry entry;
+	iMsvEntry.Session().GetEntry(iAttachmentMessageId, serviceId, entry);
+	iMsvEntry.SetEntryL(entry.Parent());
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	
+	if (MultipartMixedCreated() || MultipartMixedExists())
+		iMsvOperation = iMsvEntry.CopyL(iAttachmentMessageId, iMixFolderId, iStatus);
+	else 
+		iMsvOperation = iMsvEntry.CopyL(iAttachmentMessageId, iMessageId, iStatus);
+	}
+
+void CImStoreMessagePart::CreateMultipartAlternativeFolderEntryL()
+	{
+	TMsvEmailEntry entry;
+	entry.iType = KUidMsvFolderEntry;
+	entry.iMtm = iMsvEntry.Entry().iMtm;
+	entry.iServiceId = iMsvEntry.Entry().iServiceId;
+	entry.SetMessageFolderType(EFolderTypeAlternative);
+	entry.iSize = 0;
+
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry.CreateL(entry, iStatus);
+	}
+
+void CImStoreMessagePart::CreateTextEntryL()
+	{
+	// create the index entry
+	TMsvEntry entry;
+	entry.iMtm = iMsvEntry.Entry().iMtm;
+	entry.iServiceId = iMsvEntry.Entry().iServiceId;
+	entry.iType = KUidMsvEmailTextEntry;
+	entry.iDate.UniversalTime();
+	entry.iSize = 0;
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.CreateL(entry, iStatus);
+	}
+
+void CImStoreMessagePart::StoreRichTextL()
+	{
+	if(iUsePlainTextStorage)
+		{
+		StorePlainTextL();
+		return;
+		}
+	
+	iMsvEntry.SetEntryL(iTextId);	//pointing to the text entry
+	CMsvStore* store = iMsvEntry.EditStoreL();
+	CleanupStack::PushL(store);
+	
+	store->StoreBodyTextL(*iRichTextToStore);
+	store->CommitL();
+	
+	// Store Mime header if we've got one
+	if ( iMimeHeaderOfBodyText )
+		{
+		iMimeHeaderOfBodyText->StoreL(*store);
+		store->CommitL();
+		iMimeHeaderOfBodyText = NULL;	// We never really took ownership of the object
+		}
+	
+	CleanupStack::PopAndDestroy(store);
+
+	// update size of text entry
+	TMsvEmailEntry entry(iMsvEntry.Entry());
+	// DocumentLength() gives no. of chars and since unicode we multiply by 2
+	entry.iSize = (iRichTextToStore->DocumentLength() * 2); 
+	
+	entry.iDate.UniversalTime();
+	
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.ChangeL(entry, iStatus);	
+	}
+
+
+void CImStoreMessagePart::StorePlainTextL()
+	{
+	TUint charset = 0;
+	TBool override = EFalse;
+
+	iEmailMessage->GetCharacterSetL(iMessageId,charset,override);
+	iMsvEntry.SetEntryL(iTextId);	//pointing to the text entry
+	CMsvStore* store = iMsvEntry.EditStoreL();
+	CleanupStack::PushL(store);
+	
+	iSizeOfBody = 0;
+	// If this method was called as a result of a call to CImEmailMessage::StoreBodyTextL
+	if(iRichTextToStore)
+		{
+		RFs& fileSvrSession = iMsvSession.FileSession();
+		
+		CCnvCharacterSetConverter* characterConverter = CCnvCharacterSetConverter::NewL();
+		CleanupStack::PushL(characterConverter);
+		
+		CImConvertCharconv* charConv = CImConvertCharconv::NewL(*characterConverter, fileSvrSession);
+		CleanupStack::PushL(charConv);
+		
+		TUint defaultCharset =	charConv->SystemDefaultCharset();
+	
+		CleanupStack::PopAndDestroy(2,characterConverter);
+		characterConverter = NULL;
+		charConv = NULL;
+		
+		// Body text is stored in MailStore as 16 bit so set iIs8Bit to EFalse.		
+		CMsvPlainBodyText* text = store->InitialisePlainBodyTextForWriteL(EFalse,charset,defaultCharset);	
+		CleanupStack::PushL(text);
+		
+		text->StoreRichTextAsPlainTextL(*iRichTextToStore);
+		text->CommitL();
+		
+		CleanupStack::PopAndDestroy(text);	
+		}
+	else // If this method was called as a result to a call to CImPlainBodyText::CommitL
+		{
+		// Delete the store since for Read operation we need to open in Read mode.
+		CleanupStack::PopAndDestroy(store);
+		store = NULL;
+		
+		store = iMsvEntry.ReadStoreL();
+		CleanupStack::PushL(store);	
+		// The plain bodytext storeoperation is completed when CImPlainBodyText::CommitL is called
+		// Find out the length of the body text here.
+		CMsvPlainBodyText* bodyText = store->InitialisePlainBodyTextForReadL(KMaxChunkLength);	
+		iSizeOfBody = bodyText->Size();
+		delete bodyText;
+			
+		CleanupStack::PopAndDestroy(store);
+		store = NULL;
+		// Open it in Edit mode so that store CommitL do not fail.
+		store = iMsvEntry.EditStoreL();
+		CleanupStack::PushL(store);	
+		}
+	
+	// Store Mime header if we've got one
+	if ( iMimeHeaderOfBodyText )
+		{
+		iMimeHeaderOfBodyText->StoreL(*store);
+		store->CommitL();
+		iMimeHeaderOfBodyText = NULL;	// We never really took ownership of the object
+		}
+	
+	CleanupStack::PopAndDestroy(store);
+
+	// update size of text entry
+	TMsvEmailEntry entry(iMsvEntry.Entry());
+	
+	// DocumentLength() gives no. of chars and since unicode we multiply by 2
+	if(iRichTextToStore)
+		{
+		entry.iSize = (iRichTextToStore->DocumentLength() * 2); 
+		iSizeOfBody = entry.iSize;
+		}
+	else
+		{
+		entry.iSize = iSizeOfBody;	
+		}
+		
+	entry.iDate.UniversalTime();
+	
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.ChangeL(entry, iStatus);	
+	}
+	
+	
+void CImStoreMessagePart::CreateHTMLEntryL()
+	{
+	iMsvEntry.SetEntryL(iAltFolderId);
+
+	TMsvEntry entry;
+	entry.iServiceId = iMsvEntry.Entry().iServiceId;
+	entry.iType = KUidMsvEmailHtmlEntry;
+	entry.iMtm = iMsvEntry.Entry().iMtm;
+	entry.iDate.UniversalTime();
+	entry.iSize = 0;
+	
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.CreateL(entry, iStatus);
+	}
+
+void CImStoreMessagePart::RemoveHTMLEntryL()
+	{
+	// Find the id for the HTML Entry - current entry is the text entry. Set 
+	// entry to the parent and verify that this is an EFolderTypeAlternative.
+	// Then search its children for an HTML entry.
+	iHtmlId = KMsvNullIndexEntryId;
+	iMsvEntry.SetEntryL(iMsvEntry.Entry().Parent());
+
+	if( ((TMsvEmailEntry) iMsvEntry.Entry()).MessageFolderType() != EFolderTypeAlternative )
+		{
+		// Self-complete to continue with state machine.
+		RequestComplete(KErrNone);
+		return;
+		}
+
+	TInt ii = iMsvEntry.Count();
+	while( ii-- )
+		{
+		if( iMsvEntry[ii].iType == KUidMsvEmailHtmlEntry )
+			{
+			iHtmlId = iMsvEntry[ii].Id();
+			break;
+			}
+		}
+
+	if( iHtmlId == KMsvNullIndexEntryId )
+		{
+		// There is no HTML entry - self-complete to continue with state machine.
+		RequestComplete(KErrNone);
+		return;
+		}
+
+	// Delete the HTML entry asynchronously.
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.DeleteL(iHtmlId, iStatus);
+	}
+
+void CImStoreMessagePart::MoveTextEntryToAltFolderL()
+	{
+	// moves the text entry to alternativelder entry
+	TMsvId serviceId = KMsvNullIndexEntryId;
+	TMsvEmailEntry entry;
+	iMsvEntry.Session().GetEntry(iTextId, serviceId, entry);
+	iMsvEntry.SetEntryL(entry.Parent());
+	
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry.MoveL(iTextId, iAltFolderId, iStatus);
+	}
+
+void CImStoreMessagePart::MoveOriginalMessageEntryChildrenToNewFolderL()
+	{
+	if (MultipartRelatedCreated())
+		{
+		// set entry to the multipart/related folders parent and copy the multipart alternative
+		// into the multipart/related.
+		TMsvId serviceId = KMsvNullIndexEntryId;
+		TMsvEmailEntry entry;
+		iMsvEntry.Session().GetEntry(iRelFolderId, serviceId, entry);
+		iMsvEntry.SetEntryL(entry.Parent());
+		delete iMsvOperation;
+		iMsvOperation = NULL;
+		iMsvOperation = iMsvEntry.MoveL(iAltFolderId, iRelFolderId, iStatus);
+		}
+	else //if MultipartMixedCreated()
+		{
+		iMsvEntry.SetEntryL(iMessageId);
+		delete iMsvOperation;
+		iMsvOperation = NULL;
+		iMsvOperation = iMsvEntry.MoveL(*iMessageEntrySelection, iMixFolderId, iStatus);
+		}
+	}
+
+void CImStoreMessagePart::CompleteStoreMessagePartL()
+	{
+	if (iMsvEntry.Entry().iType != KUidMsvMessageEntry)
+		iMsvEntry.SetEntryL(iMessageId);	//pointing to the message
+	
+	TMsvEmailEntry entry(iMsvEntry.Entry());
+
+	if (iMessagePart == EMessagePartAttachment)
+		{
+		entry.iSize += iAttachmentSize;
+		entry.SetAttachment(ETrue);
+		}
+	else if (iMessagePart == EMessagePartMessageAttachment)
+		{
+		TMsvId serviceId;
+		TMsvEmailEntry attachmentMessageEntry;
+		iMsvEntry.Session().GetEntry(iAttachmentMessageId, serviceId, attachmentMessageEntry);
+		entry.SetAttachment(ETrue);
+		entry.iSize += attachmentMessageEntry.iSize;
+		}
+	else if (iMessagePart == EMessagePartBody)
+		{
+		if(iUsePlainTextStorage)
+			{
+			entry.iSize -= iSizeFwdReplyBody; // first subtract length of original plain text.
+			entry.iSize += iSizeOfBody;
+			}
+		else
+			{
+			// DocumentLength() gives no. of chars and since unicode we multiply by 2
+			entry.iSize -= (iRichText->DocumentLength() * 2); // first subtract length of original RichText
+			entry.iSize += (iRichTextToStore->DocumentLength() * 2);
+			}
+		
+		
+		}
+	if (iHtmlConverter)
+		entry.iSize+=iHtmlConverter->Size();
+
+	entry.iDate.UniversalTime();
+
+	StoreMimeHeaderL();
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	entry.SetInPreparation(EFalse);
+	iMsvOperation = iMsvEntry.ChangeL(entry, iStatus);
+	}
+
+void CImStoreMessagePart::StoreMimeHeaderL()
+	{
+	CImMimeHeader* mimeHeader = NULL;
+	
+	if (MultipartMixedCreated() || MultipartAlternativeCreated() || MultipartRelatedCreated())
+		{
+		CMsvStore* store = iMsvEntry.EditStoreL();
+		CleanupStack::PushL(store);
+
+		mimeHeader = CImMimeHeader::NewLC();
+		CreateFolderMimeHeaderL(*mimeHeader);
+		mimeHeader->StoreL(*store);
+		store->CommitL();		
+		CleanupStack::PopAndDestroy(2); //mimeHeader, store
+		}
+	
+	if (iMessagePart==EMessagePartAttachment && iAttachmentId)
+		{
+		TMsvId oldId = iMsvEntry.Entry().Id();
+		iMsvEntry.SetEntryL(iAttachmentId);
+		mimeHeader = NULL;
+		mimeHeader = ProcessAttachmentMimeHeadersL();
+		// mimeheader not found in attachment info, hence create mime header
+		if (mimeHeader == NULL)
+			{
+			mimeHeader = CImMimeHeader::NewLC();
+			if (CreateAttachmentMimeHeaderL(*mimeHeader, iMsvEntry.Entry().iDetails))
+				{
+				CMsvStore* store = iMsvEntry.EditStoreL();
+				CleanupStack::PushL(store);
+				mimeHeader->StoreL(*store);
+				store->CommitL();			
+				CleanupStack::PopAndDestroy(store);
+				}
+			CleanupStack::PopAndDestroy(mimeHeader);
+			}
+		else
+			{
+			delete mimeHeader;
+			}
+		iMsvEntry.SetEntryL(oldId); // Reset
+		}
+	else if (iMessagePart==EMessagePartMessageAttachment && iAttachmentMessageId)
+		{
+		CMsvStore* store = iMsvEntry.EditStoreL();
+		CleanupStack::PushL(store);
+		mimeHeader = CImMimeHeader::NewLC();
+	
+		CreateMessageMimeHeaderL(*mimeHeader);
+		mimeHeader->StoreL(*store);
+		store->CommitL();
+		CleanupStack::PopAndDestroy(2); //mimeHeader, store
+		}
+	}
+
+void CImStoreMessagePart::CreateFolderMimeHeaderL(CImMimeHeader& aMimeHeader)
+	{
+	aMimeHeader.SetContentTypeL(KMimeMultipart);
+	if (MultipartMixedCreated())
+		aMimeHeader.SetContentSubTypeL(KMimeMixed);
+	else if (MultipartRelatedCreated())
+		aMimeHeader.SetContentSubTypeL(KMimeRelated);
+	else
+		aMimeHeader.SetContentSubTypeL(KMimeAlternative);
+	aMimeHeader.SetContentTransferEncodingL(KMimeQuotedPrintable);
+	}
+	
+void CImStoreMessagePart::CreateMessageMimeHeaderL(CImMimeHeader& aMimeHeader)
+	{
+	aMimeHeader.SetContentTypeL(KMimeMessage);
+	aMimeHeader.SetContentSubTypeL(KMimeRfc822);
+	}
+
+TBool CImStoreMessagePart::CreateAttachmentMimeHeaderL(CImMimeHeader& aMimeHeader, const TDesC& aDetails)
+/**
+Opens attachment file & extract initial text, pass into recognizer.
+If the file type is recognized, use the MIME string produced in 
+the MIMEheader object stored in the attachment entry.
+*/
+	{
+	if (!aDetails.Length())
+		return EFalse; // No file to check 
+	
+	RApaLsSession lsSession;
+	if (lsSession.Connect() != KErrNone)
+		{
+		// Unable to connect to Recognizer server.
+		return EFalse;
+		}
+	
+	CleanupClosePushL(lsSession);
+	TDataRecognitionResult result;
+	User::LeaveIfError(lsSession.RecognizeData(aDetails, TPtrC8(), result));
+
+	TPtrC8 mimeBuf8=result.iDataType.Des8();
+	if (!mimeBuf8.Length())
+		{
+		// No point passing the file handle to the recogniser for Create Attachment 
+		// as it will be zero length
+		if(iAttachmentCreateState != ECreateAttachment)
+			{
+			CMsvStore* store = iMsvEntry.ReadStoreL();
+			CleanupStack::PushL(store);
+			MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+			// as this is email attachment entry , it has one attachment per entry
+			RFile file = attachmentMgr.GetAttachmentFileL(0);
+			CleanupStack::PopAndDestroy(store);
+			CleanupClosePushL(file);
+
+			// pass the handle to the recogniser instead of filepath
+			User::LeaveIfError(lsSession.RecognizeData(file, result));
+			CleanupStack::PopAndDestroy(&file);
+
+	   		mimeBuf8.Set(result.iDataType.Des8());
+			}
+ 				
+		if (!mimeBuf8.Length())
+			{
+			CleanupStack::PopAndDestroy(); // lssession
+			return EFalse;
+			}
+		}
+
+	TInt locatePos = mimeBuf8.Locate(TChar('/'));
+	
+	if (locatePos != KErrNotFound)
+		{
+		aMimeHeader.SetContentTypeL(mimeBuf8.Left(locatePos));
+		aMimeHeader.SetContentSubTypeL(mimeBuf8.Mid(locatePos + 1));
+		}
+		
+	if (iRelatedPartId)
+		aMimeHeader.SetContentIDL(*iContentId);
+	
+	CleanupStack::PopAndDestroy(); // lssession
+	return ETrue; 
+	}
+
+//	---------------------------------------------------------------------
+//	Class to create receipts, replies, forwarded emails, and new emails
+//	---------------------------------------------------------------------
+
+/** Creates a new email message.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateNewL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(ENew);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a new email message with a specified priority and SMTP service.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aDestination The Id of the folder where the new message is to be created
+@param aSmtpServiceId The Id of the SMTP service entry to handle the email
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateNewL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aDestination, TMsvId aSmtpServiceId, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, aSmtpServiceId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(ENew);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+/** 
+Creates a new plain text email message with a specified priority and SMTP service.
+
+@param aObserverRequestStatus  	Asynchronous status word to complete when the 
+								operation completes
+@param aMsvSession 				Message server session to use
+@param aDestination 			The Id of the folder where the new message is to be created
+@param aSmtpServiceId 			The Id of the SMTP service entry to handle the email
+@param aPartList 				The body parts that are required in the new message. If a 
+								message with body text and attachments is required, then the KMsvMessagePartBody 
+								and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList 		Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+								KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+								If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType 				The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority 				The priority setting for the email- by default this must be EPriorityStandard.
+@param aUsePlainTextStorage		TBool, if set to ETrue inidcates that the new message entry needs to be created as plain text
+								if set to EFalse indicates that message will be created as richtext entry.
+@return CImEmailOperation		Operation object by which to control the operation 
+*/
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateNewL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aDestination, TMsvId aSmtpServiceId, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority, TBool aUsePlainTextStorage)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, aSmtpServiceId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(ENew);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+/** Creates a reply email message, overriding the default subject format string.
+
+The aFormatString parameter allows you to override the default string used 
+in the subject field of the new message (the default is the localised string 
+STRING_reply_formatting_string1 defined in the source file imcm.rls).
+
+Note that if you reply to an HTML message that does not contain a text/plain 
+alternative to the HTML, then the HTML part is copied as an attachment (still 
+an HTML entry) into the new message even if aPartList does not specify KMsvMessagePartAttachments. 
+This occurs because there is no other way of reading the original message 
+unless the user switches between the editor/viewer and the application. 
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to reply to
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text is required, then set KMsvMessagePartBody; if attachments 
+are required too, also set KMsvMessagePartAttachments. To reply to the originator 
+only, set KMsvMessagePartOriginator, otherwise a reply will be sent to all 
+recipients of the original message. If the subject field is not required, 
+then do not set KMsvMessagePartDescription.
+@param aFormatString A string to be inserted into the subject field in the 
+header before the subject, e.g. "Re: %S", sets the field to be "Re: " followed 
+by the original subject text
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReplyL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TDesC& aFormatString, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, aFormatString, EReply);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a reply email message.
+
+For details of how replies to HTML messages are handled, see the description 
+above for the first overload of this function.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to reply to
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReplyL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EReply);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a reply email message, specifying a message priority.
+
+For details of how replies to HTML messages are handled, see the description 
+above for the first overload of this function.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to reply to
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReplyL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EReply);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a reply email message, specifying a message priority.
+
+For details of how replies to HTML messages are handled, see the description 
+above for the first overload of this function.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to reply to
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@param aUsePlainTextStorage		TBool, if set to ETrue inidcates that the new message entry needs to be created as plain text
+								if set to EFalse indicates that message will be created as richtext entry.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReplyL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority, TBool aUsePlainTextStorage)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EReply);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+/** Creates a forwarded email message, overriding the default subject format string.
+
+The aFormatString parameter allows you to override the default string used 
+in the subject field of the new message (the default is the localised string 
+STRING_forward_formatting_string1 defined in the source file imcm.rls).
+
+Note that if you forward an HTML message that does not contain a text/plain 
+alternative to the HTML, then the HTML part is copied as an attachment (still 
+an HTML entry) into the new message even if aPartList does not specify KMsvMessagePartAttachments. 
+This occurs because there is no other way of reading the original message 
+unless the user switches between the editor/viewer and the application. 
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to forward
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aFormatString A string to be inserted into the subject field in the 
+header before the subject, e.g. "Fwd: %S", sets the field to be "Fwd: " followed 
+by the original subject text
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateForwardL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TDesC& aFormatString, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId,  aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, aFormatString, EForward);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a forwarded email message.
+
+For details of how forwarding HTML messages is handled, see the description 
+above for the first overload of this function.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to forward
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateForwardL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId,  aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EForward);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a forwarded email message, specifying the message priority and SMTP 
+service with which to send the message.
+
+For details of how forwarding HTML messages is handled, see the description 
+above for the first overload of this function.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to forward
+@param aDestination The Id of the folder where the new message is to be created
+@param aSmtpServiceId The Id of the SMTP service with which to send the new 
+message
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateForwardL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvId aSmtpServiceId, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, aSmtpServiceId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EForward);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+/** Creates a forwarded email message, specifying the message priority and SMTP 
+service with which to send the message.
+
+For details of how forwarding HTML messages is handled, see the description 
+above for the first overload of this function.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to forward
+@param aDestination The Id of the folder where the new message is to be created
+@param aSmtpServiceId The Id of the SMTP service with which to send the new 
+message
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@param aUsePlainTextStorage		TBool, if set to ETrue inidcates that the new message entry needs to be created as plain text
+								if set to EFalse indicates that message will be created as richtext entry.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateForwardL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvId aSmtpServiceId, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority, TBool aUsePlainTextStorage)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, aSmtpServiceId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EForward);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a forwarded email message.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to forward
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateForwardAsAttachmentL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EForwardAsAttachment);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a forwarded email message, specifying the message priority and SMTP 
+service with which to send the message.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the message to forward
+@param aSmtpServiceId The Id of the SMTP service with which to send the new 
+message
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateForwardAsAttachmentL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvId aSmtpServiceId, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, aSmtpServiceId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EForwardAsAttachment);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a email receipt message, overriding the default subject format string.
+
+The aFormatString parameter allows you to override the default string used 
+in the subject field of the new message (the default is the localised string 
+STRING_receipt_formatting_string1 defined in the source file imcm.rls).
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the original message for which the receipt is required
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aFormatString A string to be inserted into the subject field in the 
+header before the subject, e.g. "Receipt of message: %S", sets the field to 
+be "Receipt of message: " followed by the original subject text
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReceiptL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TDesC& aFormatString, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination,KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, aFormatString, EReceipt);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a email receipt message.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the original message for which the receipt is required
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReceiptL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EReceipt);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a email receipt message, specifying the message priority.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the original message for which the receipt is required
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReceiptL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EReceipt);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Creates a email receipt message, specifying the message priority.
+
+@param aObserverRequestStatus Asynchronous status word to complete when the 
+operation completes
+@param aMsvSession Message server session to use
+@param aMessageId The Id of the original message for which the receipt is required
+@param aDestination The Id of the folder where the new message is to be created
+@param aPartList The body parts that are required in the new message. If a 
+message with body text and attachments is required, then the KMsvMessagePartBody 
+and KMsvMessagePartAttachments parts have to be set.
+@param aMsvEmailTypeList Creation flags. This can be 0, or a bitmask of KMsvEmailTypeListMHTMLMessage, 
+KMsvEmailTypeListInvisibleMessage, and KMsvEmailTypeListMessageInPreparation. 
+If KMsvEmailTypeListMHTMLMessage is not set, a plain-text message is created.
+@param aMsgType The type of message to create e.g. KUidMsgTypeSMTP.
+@param aPriority The priority setting for the email
+@param aUsePlainTextStorage		TBool, if set to ETrue inidcates that the new message entry needs to be created as plain text
+								if set to EFalse indicates that message will be created as richtext entry.
+@return Operation object by which to control the operation */
+EXPORT_C CImEmailOperation* CImEmailOperation::CreateReceiptL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority, TBool aUsePlainTextStorage)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId, aPartList, aMsvEmailTypeList, aMsgType, aPriority, aUsePlainTextStorage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, EReceipt);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+CImEmailOperation* CImEmailOperation::CreateCopyL(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aMessageId, TMsvId aDestination, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType)
+	{
+	CImEmailOperation* self = new(ELeave) CImEmailOperation(aObserverRequestStatus, aMsvSession, aDestination, KMsvUnknownServiceIndexEntryId,  aPartList, aMsvEmailTypeList, aMsgType, EPriorityStandard, EFalse);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMessageId, ECopy);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+/** Destructor. */
+EXPORT_C CImEmailOperation::~CImEmailOperation()
+	{
+	Cancel();
+	delete iMsvOperation;
+	delete iFormatString;
+	delete iRichText;
+	delete iParaLayer;
+	delete iCharLayer;
+	delete iEmailMessage;
+	delete iNewHeader;
+	delete iFileMan;
+	delete iBodyHeaderFormatString;
+	delete iBodyHeaderDateTimeFormatString;
+	delete iBodyHeader;
+	iAttachmentInfoList.ResetAndDestroy();
+	iFile.Close();
+	delete iStore;
+	delete iMsvEntry;
+	delete iSignatureText;
+	delete iDefaultVCardNameFormatString;
+	delete iHtmlConverter;
+	delete iSmtpSettings;
+	delete iVcardStore;
+	delete iBodyHeaderToString;
+	delete iBodyHeaderCcString;
+	iOriginalHeader = NULL;
+	delete iOriginalHeader;
+	}
+
+/** Gets progress information for a completed operation.
+
+The function returns (in packaged form):
+
+for a successfully completed operation, the Id of the new message 
+
+if there was an error/problem while creating the message, a null Id (KMsvNullIndexEntryId). 
+The new message will also be deleted.
+
+@return A message Id as a TPckg<TMsvId> */
+EXPORT_C const TDesC8& CImEmailOperation::FinalProgress()
+	{
+	__ASSERT_ALWAYS(!IsActive(), gPanic(EMiutActiveInFinalProgress));
+ 	const TDesC8* progress = &KNullDesC8();
+ 	TRAPD(leave, progress = &ProgressL());
+	__ASSERT_ALWAYS(leave == KErrNone, gPanic(EImcmFinalProgressFailed));
+	return *progress;	
+	}
+
+/** Gets progress information.
+
+While the operation is in progress, a null Id (KMsvNullIndexEntryId) is returned. 
+For a completed operation, values are as described for FinalProgress().
+
+@return A message Id as a TPckg<TMsvId> */
+const TDesC8& CImEmailOperation::ProgressL()
+	{
+	if (iState==EFinished)
+		iDataMember() = iNewMessageId;
+	return iDataMember;
+	}
+
+void CImEmailOperation::DoCancel()
+	{
+	if (iMsvOperation)
+		iMsvOperation->Cancel();
+	if (iEmailMessage)
+		iEmailMessage->Cancel();
+	if (iNewMessageId!=KMsvNullIndexEntryId)
+		iMsvEntry->Session().RemoveEntry(iNewMessageId);
+
+	TRequestStatus* st = &iObserverRequestStatus;
+	User::RequestComplete(st, KErrCancel);
+	}
+
+void CImEmailOperation::SelectAndProcessNextStateL()
+	{
+	SelectNextStateL();
+	ProcessStateL();
+	}
+
+void CImEmailOperation::RunL()
+	{
+	if (iStatus.Int() != KErrNone)
+		{
+		ErrorRecovery(iStatus.Int());
+		return;
+		}
+	if ((iState == ECreateNewMessageEntry) || 
+		(iState == ECreateMultipartMixedFolderEntry) ||
+		(iState == ECreateTextEntry) ||
+		(iState == EStoreBody) ||
+		(iState == ECreateAttachmentEntry) || 
+		(iState == ECreateMultipartAlternativeFolderEntry) ||
+		(iState == ECreateHTMLEntry) ||
+		(iState == EStoreAttachment) ||
+		(iState == ECreateVCardAttachment) ||
+		(iState == ECompleteEmailOperation)
+		|| (iState == ECreateDefaultHtmlAttachment)	
+		|| (iState == EStoreHTMLTextInEntry)
+		) 
+		{
+		TInt progressError = McliUtils::GetProgressErrorL(*iMsvOperation);
+		if (progressError != KErrNone)
+			{
+			ErrorRecovery(progressError);
+			return;
+			}			
+		}
+	if (iState != EFinished)
+		{
+		TRAPD(error, SelectAndProcessNextStateL());
+		if (error)
+			{
+			ErrorRecovery(error);
+			return;
+			}
+		else if (iState != EFinished)
+			SetActive();
+		}
+	}
+
+CImEmailOperation::CImEmailOperation(TRequestStatus& aObserverRequestStatus, CMsvSession& aMsvSession, TMsvId aDestination, TMsvId aSmtpServiceId, TMsvPartList aPartList, const TMsvEmailTypeList& aMsvEmailTypeList, TUid aMsgType, TInt aPriority, TBool aUsePlainTextStorage)
+	: CMsvOperation(aMsvSession, aPriority, aObserverRequestStatus),
+	  iDestinationId(aDestination),
+	  iSmtpServiceId(aSmtpServiceId),
+	  iMsgType(aMsgType),
+	  iPartList(aPartList),
+	  iMsvEmailTypeList(aMsvEmailTypeList),
+	  iAttachmentFile(aMsvSession.FileSession()),
+	  iUsePlainTextStorage(aUsePlainTextStorage)
+	{
+	iMtm = iMsgType;
+	}
+
+void CImEmailOperation::ConstructL(TMsvId aMessageId, const TDesC& aFormatString, TImEmailOperation aOperation)
+	{
+    iOrigMessageId = aMessageId;
+	iFormatString = aFormatString.AllocL();
+	ConstructL(aOperation);
+	}
+
+void CImEmailOperation::ConstructL(TMsvId aMessageId, TImEmailOperation aOperation)
+	{
+    iOrigMessageId = aMessageId;
+	ConstructL(aOperation);
+	}
+
+void CImEmailOperation::ConstructL(TImEmailOperation aOperation)
+	{
+	iOperation = aOperation;
+	iMsvEntry = CMsvEntry::NewL(iMsvSession, iDestinationId, TMsvSelectionOrdering());
+	iSmtpSettings = new (ELeave) CImSmtpSettings;
+		
+	if( iMsgType == KUidMsgTypeSMTP )
+		{
+		// Restore the SMTP settings - check if the service has been supplied.
+		if( iSmtpServiceId == KMsvNullIndexEntryId || iSmtpServiceId == KMsvUnknownServiceIndexEntryId )
+			{
+			// Nope - the operation dictates where the SMTP settings are restored
+			// from.
+			switch( iOperation )
+				{
+			case EReply:
+			case EReceipt:
+ 			case EForward:
+			case EForwardAsAttachment:
+				{
+				// Restore from the original message.
+				TRAPD(error, SetSmtpServiceFromOriginalMessageL());
+
+				if( error != KErrNone )
+					{
+					// Failed to restore the SMTP settings from the original 
+					// message - use the SMTP settings from the default settings
+					// specified in the root entry.
+					SetSmtpServiceFromDefaultsL();
+					}
+				} break;
+			case ENew:
+			case ECopy:
+				{
+				// No SMTP service has been supplied - restore SMTP settings 
+				// from the default service specified in the root entry.
+				SetSmtpServiceFromDefaultsL();
+				} break;
+			default:
+				__ASSERT_DEBUG( EFalse, User::Invariant() );
+				break;
+				}
+			}
+		else
+			{
+			// Restore SMTP settings from the service supplied.
+			iMsvEntry->SetEntryL(iSmtpServiceId);
+			RestoreSmtpSettingsL();
+			}
+
+		}
+	else if( iMsgType == KUidMsgTypePCMail )
+		{
+		if( iOperation == EReply )
+			{
+			// reply via the same service as the original message
+			iMsvEntry->SetEntryL(iOrigMessageId);
+			iPCMailServiceId = iMsvEntry->Entry().iServiceId;
+			}
+		else if( iSmtpServiceId != KMsvNullIndexEntryId ) // iSmtpService may hold the PCMail Service Id!
+			iPCMailServiceId = iSmtpServiceId; 
+		else
+			iPCMailServiceId = KMsvUnknownServiceIndexEntryId;
+		}
+	
+	iNewHeader = CImHeader::NewLC();
+	CleanupStack::Pop(iNewHeader);
+	iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+
+	iParaLayer = CParaFormatLayer::NewL();
+	iCharLayer = CCharFormatLayer::NewL();
+	iRichText = CRichText::NewL(iParaLayer, iCharLayer);
+
+	iAttachmentInfoList.ResetAndDestroy();
+	if( iOrigMessageId != KMsvNullIndexEntryId )
+		{
+		iMsvEntry->SetEntryL(iOrigMessageId);
+		iOrigMessageHtml = static_cast<TMsvEmailEntry>(iMsvEntry->Entry()).MHTMLEmail();
+		}
+
+	if( iMsvEmailTypeList & KMsvEmailTypeListMHTMLMessage )
+		{
+		TRAPD(err, iHtmlConverter = CImHtmlConverter::NewL(*iMsvEntry, *iParaLayer, *iCharLayer));
+ 		if( err != KErrNone )
+			{
+			if( err == KErrNoMemory )
+				User::Leave(KErrNoMemory);
+			else
+				gPanic(EImcmHtmlConverterNotFound);
+			}
+		iCreateHtmlMessage = ETrue;
+		}
+
+	if( iMsgType == KUidMsgTypeSMTP && iOperation != ECopy )
+		CheckForSignatureOrVCardL();
+
+	if( iNeedToAddVCardAttachment || iCreateHtmlMessage || (iOperation!=ENew && iOperation!=ECopy) )
+		OpenAndReadResourceFileL();
+
+	CActiveScheduler::Add(this);
+
+	// The signature needs to be added to the richtext regardless of whether the
+	// body is included iSignatureText will only be set if the Signature flag is
+	// set in the SMTP settings and if there is a richtext stream.
+	if( iSignatureText )
+		iRichText->AppendTakingSolePictureOwnershipL(*iSignatureText);
+	
+
+	if( iOperation == ENew )
+		iState = ECreateNewMessageEntry;
+	ProcessStateL();
+
+	iObserverRequestStatus = KRequestPending;
+	SetActive();
+	}
+
+void CImEmailOperation::OpenAndReadResourceFileL()
+	{
+	RResourceFile resourceFile;
+	OpenResourceFileL(resourceFile, iMsvSession.FileSession());
+	CleanupClosePushL(resourceFile);
+
+	HBufC8* buf;
+	TResourceReader reader;
+	if( iFormatString == NULL )
+		{
+		if( (iOperation == EForward) || (iOperation == EForwardAsAttachment) )
+			{
+			buf = resourceFile.AllocReadLC(FORWARD_FORMATTING_STRING);
+			reader.SetBuffer(buf);
+			iFormatString = (reader.ReadTPtrC()).AllocL();
+			CleanupStack::PopAndDestroy(buf);
+			}
+		else if( iOperation == EReply )
+			{
+			buf = resourceFile.AllocReadLC(REPLY_FORMATTING_STRING);
+			reader.SetBuffer(buf);
+			iFormatString = (reader.ReadTPtrC()).AllocL();
+			CleanupStack::PopAndDestroy(buf);
+			}
+		else if( iOperation == EReceipt )
+			{
+			buf = resourceFile.AllocReadLC(RECEIPT_FORMATTING_STRING);
+			reader.SetBuffer(buf);
+			iFormatString = (reader.ReadTPtrC()).AllocL();
+			CleanupStack::PopAndDestroy(buf);
+			}
+		}
+	if( (iOperation == EForward) || (iOperation == EForwardAsAttachment) || (iOperation == EReply) )
+		{
+		RestoreOriginalHeaderL();
+		TInt format;
+		if( (iOperation == EForward) || (iOperation == EForwardAsAttachment) )
+			{
+			switch (iBodyHeaderFormat)
+				{
+				case EToAndCc:
+					format = FORWARD_BODY_HEADER_TOCC;
+					break;				
+				case EToOnly:
+					format = FORWARD_BODY_HEADER_TOONLY;
+					break;
+				case ECcOnly:
+					format = FORWARD_BODY_HEADER_CCONLY;
+					break;
+				case ENoToCcInfo:
+				default:
+					format = FORWARD_BODY_HEADER;
+					break;
+				}
+
+			}
+		else  // iOperation == EReply
+			{
+			switch (iBodyHeaderFormat)
+				{
+				case EToAndCc:
+					format = REPLY_BODY_HEADER_TOCC;
+					break;				
+				case EToOnly:
+					format = REPLY_BODY_HEADER_TOONLY;
+					break;
+				case ECcOnly:
+					format = REPLY_BODY_HEADER_CCONLY;
+					break;
+				case ENoToCcInfo:
+				default:
+					format = REPLY_BODY_HEADER;
+					break;
+				}
+			}
+		buf = resourceFile.AllocReadLC(format);
+		reader.SetBuffer(buf);
+		iBodyHeaderFormatString = (reader.ReadTPtrC()).AllocL();
+		CleanupStack::PopAndDestroy(buf);
+		
+		buf = resourceFile.AllocReadLC(BODY_HEADER_DATETIME_FORMAT);
+		reader.SetBuffer(buf);
+		iBodyHeaderDateTimeFormatString = (reader.ReadTPtrC()).AllocL();
+		CleanupStack::PopAndDestroy(buf);
+		}
+
+	if( iNeedToAddVCardAttachment )
+		{
+		buf = resourceFile.AllocReadLC(DEFAULT_VCARD_NAME);
+		reader.SetBuffer(buf);
+		iDefaultVCardNameFormatString = (reader.ReadTPtrC()).AllocL();
+		CleanupStack::PopAndDestroy(buf);
+		}
+	if( iHtmlConverter != NULL )
+		iHtmlConverter->ReadDefaultAttachmentNameL(resourceFile);
+
+	CleanupStack::PopAndDestroy(&resourceFile);
+	}
+
+void CImEmailOperation::SetSmtpServiceFromDefaultsL()
+	{
+  	// Get the default SMTP service Id from CenRep
+  	CEmailAccounts* account = CEmailAccounts::NewLC();		
+  	TSmtpAccount id;
+	TInt error = account->DefaultSmtpAccountL(id);
+	CleanupStack::PopAndDestroy(account); 	   
+  	
+  	if (error == KErrNone)
+  		{
+		iSmtpServiceId = id.iSmtpService;		
+  		iMsvEntry->SetEntryL(iSmtpServiceId);
+  		RestoreSmtpSettingsL();		
+  		}
+  	else if (error == KErrNotFound)
+  		{
+  		iSmtpServiceId = KMsvUnknownServiceIndexEntryId;
+  		}
+	}
+
+void CImEmailOperation::SetSmtpServiceFromOriginalMessageL()
+	{
+	__ASSERT_DEBUG( iOperation != ENew, User::Invariant() );
+
+	iMsvEntry->SetEntryL(iOrigMessageId);
+
+	__ASSERT_DEBUG(iMsvEntry->Entry().iServiceId != KMsvLocalServiceIndexEntryIdValue, gPanic(EMiutLocalServiceIdSet));
+
+	// Get iServiceId from original message and then move context to the service
+	// (e.g. POP).
+	iSmtpServiceId = iMsvEntry->Entry().iServiceId;
+	iMsvEntry->SetEntryL(iMsvEntry->Entry().iServiceId);
+
+	// Now move context to SMTP to access the SMTP settings.
+	iSmtpServiceId = iMsvEntry->Entry().iRelatedId;
+	iMsvEntry->SetEntryL(iSmtpServiceId);
+
+	RestoreSmtpSettingsL();
+	}
+
+void CImEmailOperation::RestoreSmtpSettingsL()
+	{
+  	CEmailAccounts* account = CEmailAccounts::NewLC();  	
+  	TSmtpAccount id;
+	account->GetSmtpAccountL(iMsvEntry->Entry().Id(), id);
+	account->LoadSmtpSettingsL(id, *iSmtpSettings);  	
+  	CleanupStack::PopAndDestroy(account);    
+	}
+
+void CImEmailOperation::ErrorRecovery(TInt error)
+	{
+	if (iNewMessageId!=KMsvNullIndexEntryId)
+		iMsvEntry->Session().RemoveEntry(iNewMessageId);
+	// complete the observer with error
+	TRequestStatus* status=&iObserverRequestStatus;
+	User::RequestComplete(status,error);
+	}
+
+void CImEmailOperation::SelectNextStateL()
+	{
+	switch( iState )
+		{
+	case ECreateNewHeader:
+		{
+		
+		if( iOperation & EAttachOriginal )
+			iState = ECreateNewMessageEntry;
+		else if( iPartList & KMsvMessagePartBody )
+			iState = EGetBodyText;
+		else if( iPartList & KMsvMessagePartAttachments )
+			iState = EGetAttachmentList;
+		else
+			iState = EGetMessageDigest;
+		} break;
+	case EGetBodyText:
+		{
+		// This may be an HTML message with no text alternative to the HTML if 
+		// there is no body text.
+		TInt sizeOfBody = 0;
+		TBool isPlainText = EFalse;
+		iEmailMessage->GetBodyTextEntryIdL(iOrigMessageId,CImEmailMessage::EThisMessageOnly);
+		// Check if the original message was stored as plain text or rich text.
+		if( iEmailMessage->Selection().Count() )
+			{
+			TMsvId textId = iEmailMessage->Selection().At(0);
+			iMsvEntry->SetEntryL(textId);	
+			CMsvStore* store = iMsvEntry->ReadStoreL();
+			CleanupStack::PushL(store);
+			
+			isPlainText = (store->IsPresentL(KMsvPlainBodyText16) || store->IsPresentL(KMsvPlainBodyText8));
+			CleanupStack::PopAndDestroy(store);
+			store = NULL;
+			}
+		
+		// The body text is not in richtext format, so don't populate it.	
+		if(isPlainText)
+			{
+			// Find out the size of the body text.
+			sizeOfBody = GetPlainBodyTextSizeL();
+			}
+		else
+			{
+			sizeOfBody = iRichText->DocumentLength();
+			sizeOfBody = sizeOfBody * 2;
+			}
+			
+		if( iOrigMessageHtml && (((sizeOfBody) - iRichTextSize) == 0) )
+			iHtmlNoTextAlt = ETrue;
+
+		if( iPartList & KMsvMessagePartAttachments )
+			iState = EGetAttachmentList;
+		else
+			iState = EGetMessageDigest;
+		} break;
+	case EGetAttachmentList:
+		{
+		// Need a copy of attachment list as the CImEmailMessage object may be reset
+		TInt count = iEmailMessage->AttachmentManager().AttachmentCount();
+		for(TInt index = 0; index < count ; index++)
+			{
+			CMsvAttachment* attachment = CMsvAttachment::NewL(*iEmailMessage->AttachmentInfoSelection()[index]);
+			CleanupStack::PushL(attachment);
+			User::LeaveIfError(iAttachmentInfoList.Append(attachment));
+			CleanupStack::Pop(attachment);
+			}
+		iState = EGetMessageDigest;
+		} break;
+	case EGetMessageDigest:
+		{
+		iEmbeddedMessagesToProcess = iEmailMessage->Selection().Count();
+		iState = ECreateNewMessageEntry;
+		} break;
+	case ECreateNewMessageEntry:
+		{
+		iNewMessageId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iState = ECheckMultipartMixedFolderRequired;
+		} break;
+	case ECheckMultipartMixedFolderRequired:
+		{
+		if(	NeedMultipartMixedFolder() )
+			iState = ECreateMultipartMixedFolderEntry;
+		else
+			iState = ECheckMultipartAlternativeFolderRequired;
+		} break;
+	case ECreateMultipartMixedFolderEntry:
+		{
+		iMultipartMixedFolderCreated = ETrue;
+		iMultipartMixedId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iState = ECheckMultipartAlternativeFolderRequired;
+		} break;
+	case ECheckMultipartAlternativeFolderRequired:
+		{
+		if( iCreateHtmlMessage )
+			iState = ECreateMultipartAlternativeFolderEntry;
+		else
+			iState = ECheckTextEntryRequired;
+		} break;
+	case ECreateMultipartAlternativeFolderEntry:
+		{
+		iMultipartAlternativeFolderCreated = ETrue;
+		iMultipartAlternativeId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iState = ECheckTextEntryRequired;
+		} break;
+	case ECheckTextEntryRequired:
+		{
+		if( (iMultipartMixedFolderCreated && ((iPartList & KMsvMessagePartBody) || iNeedToAddVCardAttachment || iSignatureText )) ||
+			(iMultipartAlternativeFolderCreated) ||
+			(iPartList & KMsvMessagePartBody) ||
+			((iPartList & KMsvMessagePartAttachments) && iOperation != ECopy && iTotalAttachments == 0) ||
+			(!(iPartList & KMsvMessagePartAttachments) && !(iPartList & KMsvMessagePartBody) && !iNeedToAddVCardAttachment && !iCreateHtmlMessage) )
+			{
+			// Hmmm, quite a convaluted way of working out if a text entry is needed!!
+			iState = ECreateTextEntry;
+			}
+		else
+			iState = ECheckVCardRequired;
+		} break;
+	case ECreateTextEntry:
+		{
+		iTextId = McliUtils::GetProgressIdL(*iMsvOperation);
+	
+		if( (iPartList & KMsvMessagePartBody && !(iOperation & EAttachOriginal)) || iSignatureText )
+			iState = EStoreBody;
+		else
+			iState = ECheckVCardRequired;
+		} break;
+	case EStoreBody:
+		{
+		iState = ECheckVCardRequired;
+		} break;
+	case ECheckVCardRequired:
+		{
+		if( iNeedToAddVCardAttachment && (iOperation != ECopy) )
+			iState = ECreateVCardAttachment;
+		else
+			iState = ECheckHTMLEntryRequired;
+		} break;
+	case ECreateVCardAttachment:
+		{
+		iVcardId = McliUtils::GetProgressIdL(*iMsvOperation);
+		iState = EAddVCardAttachment;
+		} break;
+	case EAddVCardAttachment:
+		{
+		iState = ECheckHTMLEntryRequired;
+		} break;
+	case ECheckHTMLEntryRequired:
+		{
+		if( iCreateHtmlMessage )
+			iState = ECreateHTMLEntry;
+		else
+			iState = ECheckAttachOriginalMessageRequired;
+		} break;
+	case ECreateHTMLEntry:
+		{
+		__ASSERT_DEBUG( iMultipartAlternativeFolderCreated, User::Invariant() );
+
+		iHtmlId = McliUtils::GetProgressIdL(*iMsvOperation);
+		TMsvId serviceId;
+		TMsvEmailEntry textEntry;
+		iMsvEntry->Session().GetEntry(iTextId, serviceId, textEntry);
+
+		// Store character set info in a MimeHeader.
+		iMsvEntry->SetEntryL(iHtmlId);
+		iState = ECreateDefaultHtmlAttachment;
+		iStore = iMsvEntry->EditStoreL();
+		} break;
+	case ECreateDefaultHtmlAttachment:
+		{
+		CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+		mimeHeader->SetMimeCharset(KCharacterSetIdentifierUtf8);
+		mimeHeader->StoreL(*iStore);
+		iStore->CommitL();
+		CleanupStack::PopAndDestroy(mimeHeader); 
+		iFile.Close();
+		delete iStore;
+		iStore=NULL;
+		
+		TMsvId serviceId;
+		TMsvEmailEntry textEntry;
+		iMsvEntry->Session().GetEntry(iTextId, serviceId, textEntry);
+		
+		iMsvEntry->SetEntryL(iMultipartAlternativeId);
+
+		if( iPartList & KMsvMessagePartBody && (textEntry.iSize > 0) && !(iOperation & EAttachOriginal) )
+			iState = EPrepareToStoreHTMLEntryText;
+		else 
+			iState = ECheckAttachOriginalMessageRequired;
+		}break;
+	case EPrepareToStoreHTMLEntryText:
+		{
+		iFinishedConvertingHTML = EFalse;
+		
+		if(iUsePlainTextStorage && iRestoreErr == KErrNoMemory)
+			{
+			// If iRestoreErr is KErrNoMemory then complete the store message operation.
+			iState = ECompleteEmailOperation;	
+			}
+		else
+			{
+			if( iHtmlId != KMsvNullIndexEntryId )
+				iState = EStoreHTMLEntryText;
+			else 
+				iState = ECheckAttachOriginalMessageRequired;
+			}
+		} break;
+	case EStoreHTMLEntryText:
+		{
+		if( iFinishedConvertingHTML )
+			{
+			iHtmlConverter->ResetStoreL();
+			iState = EStoreHTMLTextInEntry;	
+			}
+		// Otherwise stay in this state until the HTML has been converted.
+		} break;
+	case EStoreHTMLTextInEntry:
+		iState = ECheckAttachOriginalMessageRequired;
+		break;
+	case EAddMessageAttachmentInfo:
+		{
+		ResetStoreL();
+		iState = ECompleteEmailOperation;
+		}break;
+	case ECheckAttachOriginalMessageRequired:
+		{
+		if( (iOperation & EAttachOriginal) && (iPartList & KMsvMessagePartBody || iPartList & KMsvMessagePartAttachments) )
+			iState = EAttachOriginalMessage;
+		else
+			iState = ECheckHTMLPageRequired;
+		} break;
+	case EAttachOriginalMessage:
+		{
+		TPckgBuf<TMsvId> paramPack; 
+		paramPack.Copy(iMsvOperation->FinalProgress());
+		iAttachedMessageId = paramPack();
+		iMsvEntry->SetEntryL(iAttachedMessageId);
+		iState = EAddMessageAttachmentInfo;
+		} break;
+	case ECheckHTMLPageRequired:
+		{
+		TInt sizeOfBody = 0;
+		if(iUsePlainTextStorage && iOperation != ENew)
+			{
+			iEmailMessage->GetBodyTextEntryIdL(iNewMessageId, CImEmailMessage::EThisMessageOnly);
+			sizeOfBody = GetPlainBodyTextSizeL();
+			}
+		else
+			{
+			sizeOfBody = iRichText->DocumentLength();
+			sizeOfBody = sizeOfBody * 2;
+			}
+		if( iPartList & KMsvMessagePartBody && iOrigMessageHtml &&
+			(iOperation != ENew) &&	(((sizeOfBody) - iRichTextSize) == 0) )
+			iState = EFindHTMLPage;
+		else
+			iState = ECheckAttachmentsRequired;
+		} break;
+	case EFindHTMLPage:
+		{
+		iState = ECopyHTMLPartToAttachment;
+		} break;
+	case ECopyHTMLPartToAttachment:
+		{
+		iState = ECheckAttachmentsRequired;
+		} break;
+	case ECheckAttachmentsRequired:
+		{
+		if( iPartList & KMsvMessagePartAttachments && (iTotalAttachments > 0) && (iOperation != ENew) )
+			{
+			iFileMan = CFileMan::NewL(iMsvSession.FileSession());
+			iState = ECreateAttachmentEntry;
+			}
+		else
+			iState = ECheckEmbeddedMessagesRequired;
+		} break;
+	case ECreateAttachmentEntry:
+		{
+		iState = EStoreAttachment;
+		} break;
+	case EStoreAttachment:
+		{
+		ResetStoreL();
+		//	Are there more attachments to be added?
+		if( ++iAttachmentCount < iTotalAttachments )
+			iState = ECreateAttachmentEntry;
+		else 
+			iState = ECheckEmbeddedMessagesRequired;
+		} break;
+	case ECheckEmbeddedMessagesRequired:
+		{
+		if( iEmbeddedMessagesToProcess > 0 )
+			iState = EAddEmbeddedMessagesAsAttachments;
+		else
+			iState = ECompleteEmailOperation;
+		} break;
+	case EAddEmbeddedMessagesAsAttachments:
+		{
+		if(iEmbeddedMessagesToProcess > 0)
+   			{   			
+   			iState = EAddEmbeddedMessagesAsAttachments;
+   			}
+   		else
+   			{			
+   			iState = ECompleteEmailOperation;
+   			}
+		} break;
+	case ECompleteEmailOperation:
+		{
+		iState = EFinished;
+		} break;
+	default:
+		__ASSERT_DEBUG( EFalse, User::Invariant() );
+		break;
+		}
+	}
+
+void CImEmailOperation::ProcessStateL()
+	{
+	CMsvOperation* op = NULL;
+	switch( iState )
+		{
+	case ECreateNewHeader:
+		{
+		CreateNewHeaderL();
+		} break;
+	case EGetBodyText:
+		{
+		GetBodyTextL();
+		} break;
+	case EGetAttachmentList:
+		{
+		iEmailMessage->GetAttachmentsListL(iStatus, iOrigMessageId, CImEmailMessage::EAllAttachments, CImEmailMessage::EThisMessageOnly);
+		} break;
+	case EGetMessageDigest:
+		{
+		iEmailMessage->GetMessageDigestEntriesL(iStatus, iOrigMessageId);
+		} break;
+	case ECreateNewMessageEntry:
+		{
+		CreateNewMessageL(iDestinationId);
+		} break;
+	case ECreateMultipartMixedFolderEntry:
+		{
+		CreateMultipartMixedFolderEntryL();
+		} break;
+	case ECreateMultipartAlternativeFolderEntry:
+		{
+		CreateMultipartAlternativeFolderEntryL();
+		} break;
+	case ECreateTextEntry:
+		{
+		if (iMultipartAlternativeFolderCreated)
+			CreateTextEntryL(iMultipartAlternativeId);
+		else if (iMultipartMixedFolderCreated)
+			CreateTextEntryL(iMultipartMixedId);
+		else 
+			CreateTextEntryL(iNewMessageId);
+
+		} break;
+	case EStoreBody:
+		{
+		StoreBodyL();
+		} break;
+	case ECreateVCardAttachment:
+		{
+		CreateVCardAttachmentL();
+		} break;
+	case EAddVCardAttachment:
+		{
+		AddVCardAttachmentL();
+		} break;
+	case ECreateHTMLEntry:
+		{
+		CreateHTMLEntryL();
+		} break;
+	case EPrepareToStoreHTMLEntryText:
+		{
+		TRAP(iRestoreErr ,iHtmlConverter->PrepareToStoreHTMLEntryTextL(iHtmlId, iTextId));
+		// Do not leave if it is KErrNoMemory while creating HTML part for a message, since the 
+		// plainbody text part of message is already created and that be used to send the message.
+		if(iUsePlainTextStorage)
+			{
+			if(iRestoreErr != KErrNoMemory)
+				{
+				User::LeaveIfError(iRestoreErr);
+				}
+			}
+		else
+			{
+			User::LeaveIfError(iRestoreErr);
+			}	
+		RequestComplete(KErrNone);
+		} break;
+	case EStoreHTMLEntryText:
+		{
+		iFinishedConvertingHTML = iHtmlConverter->StoreHTMLEntryTextAL(iStatus);
+		if(!iFinishedConvertingHTML)
+			RequestComplete(KErrNone);
+		else
+			{			
+			iVCardAndHtmlSize += iHtmlConverter->Size();
+			}
+		} break;
+	case ECreateDefaultHtmlAttachment:
+		{
+		CreateDefaultAttachmentL();	
+		}break;
+	case EStoreHTMLTextInEntry:
+		op = iHtmlConverter->ChangeHTMLTextInEnrtyL(iStatus);
+		if(!op)
+			RequestComplete(KErrNone);	
+		else
+			{
+			delete iMsvOperation;
+			iMsvOperation = op;		
+			}
+		break;
+	case EAddMessageAttachmentInfo:
+		{
+		AddMessageAttachmentInfoL(iAttachedMessageId);
+		} break;	
+	case EAttachOriginalMessage:
+		{
+		AttachOriginalMessageToNewMessageL();
+		} break;
+	case EFindHTMLPage:
+		{
+		iEmailMessage->FindFirstHTMLPageL(iOrigMessageId, iStatus);
+		} break;
+	case ECopyHTMLPartToAttachment:
+		{
+		AppendHtmlAttachmentL();
+		} break;
+	case ECreateAttachmentEntry:
+		{
+		CreateAttachmentEntryL();
+		} break;
+	case EStoreAttachment:
+		{
+		StoreAttachmentL();
+		} break;
+	case EAddEmbeddedMessagesAsAttachments:
+		{
+		AddMessageAsAttachmentL();
+		} break;
+	case ECompleteEmailOperation:
+		{
+		CompleteEmailOperationL();
+		} break;
+	case EFinished:
+		{
+		TRequestStatus* status=&iObserverRequestStatus;
+		User::RequestComplete(status,KErrNone);
+		} break;
+	case ECheckMultipartMixedFolderRequired:
+	case ECheckMultipartAlternativeFolderRequired:
+	case ECheckTextEntryRequired:
+	case ECheckVCardRequired:
+	case ECheckHTMLEntryRequired:
+	case ECheckAttachOriginalMessageRequired:
+	case ECheckHTMLPageRequired:
+	case ECheckAttachmentsRequired:
+	case ECheckEmbeddedMessagesRequired:
+		{
+		RequestComplete(KErrNone);
+		} break;
+	default:
+		__ASSERT_DEBUG( EFalse, User::Invariant() );
+		break;
+		}
+	}
+
+void CImEmailOperation::RequestComplete(TInt aError)
+	{
+	iStatus = KRequestPending;
+	TRequestStatus* status=&iStatus;
+	iStatus=KRequestPending;
+	User::RequestComplete(status,aError);
+	}
+
+TMsvId CImEmailOperation::ServiceId()
+	{
+	// this functions returns the correct service id dependant on the Message Type.
+	if (iMsgType == KUidMsgTypePCMail)
+		return iPCMailServiceId;
+
+	return iSmtpServiceId;
+	}
+	
+void CImEmailOperation::CreateNewHeaderL()
+	{
+	//	1.	Create new header using the original message.
+	//	2.	Change header details depending on the operation required.
+	//	3.	Create the body header now since we have the original message
+	if (iOriginalHeader==NULL)
+		{
+		RestoreOriginalHeaderL();
+		}
+		
+	switch( iOperation )
+		{
+	case EForward:
+	case EForwardAsAttachment:
+		{
+		iOriginalHeader->CreateForwardL(*iNewHeader, *iFormatString);
+		} break;
+	case EReply:
+		{
+		if( (iPartList & KMsvMessagePartOriginator) && !(iPartList & KMsvMessagePartRecipient) )
+			iOriginalHeader->CreateReplyL(*iNewHeader, CImHeader::EOriginator, *iFormatString);
+		else
+			{
+			if( (iPartList & KMsvMessagePartOriginator) && (iPartList & KMsvMessagePartRecipient) )
+				iOriginalHeader->CreateReplyL(*iNewHeader, CImHeader::EAll, *iFormatString);
+			else
+				iOriginalHeader->CreateReplyL(*iNewHeader, CImHeader::ERecipients, *iFormatString);
+
+			// Remove the user's email address (if provisioned) from the To: and Cc: headers
+			// of the reply message.  But ensure there is at least one email
+			// address in the To: header to account for the scenario when the
+			// user may be replying to a message they sent themselves.
+			if (iSmtpSettings->EmailAddress().Length())
+   				{
+				TInt i = 0;
+				while (i < iNewHeader->ToRecipients().Count())
+   					{
+					if ((iNewHeader->ToRecipients().Count() > 1) && (iNewHeader->ToRecipients()[i]).FindF(iSmtpSettings->EmailAddress()) >= 0)
+						// Only delete if there is more than one recipient because we do 
+						// not want to create a reply with an empty To: header.
+   						iNewHeader->ToRecipients().Delete(i);
+					else
+						++i;
+   					}
+				
+				i = 0;
+				while (i < iNewHeader->CcRecipients().Count())
+   					{
+					if ((iNewHeader->CcRecipients()[i]).FindF(iSmtpSettings->EmailAddress()) >= 0)
+						iNewHeader->CcRecipients().Delete(i);
+					else
+						++i;
+   					}
+   				}
+			}
+		} break;
+	case ECopy:
+		{
+		delete iNewHeader;
+		iNewHeader = iOriginalHeader;
+		} break;
+	case EReceipt:
+		{
+		iOriginalHeader->CreateReceiptL(*iNewHeader, *iFormatString);
+		} break;
+	default:
+		__ASSERT_DEBUG( EFalse, User::Invariant() );
+		break;
+		}
+
+	if (iPartList & !KMsvMessagePartDescription)
+		iNewHeader->SetSubjectL(KNullDesC);
+
+	if ((iBodyHeaderFormatString != NULL ) && (iBodyHeaderFormatString->Find(KMiutFormatString)))
+		{
+		__ASSERT_DEBUG(iBodyHeaderDateTimeFormatString!=NULL, User::Invariant());
+		
+		TTime date = iMsvEntry->Entry().iDate;
+		
+		//Convert time to local time. 
+		RTz myTZoneServer; 
+		// Connect to the time zone server, leaves if fails to connect
+		User::LeaveIfError(myTZoneServer.Connect()); 
+		CleanupClosePushL(myTZoneServer);
+		// Create a converter object.
+		CTzConverter* myConverter = CTzConverter::NewL(myTZoneServer); 
+		CleanupStack::PushL(myConverter);
+		myConverter->ConvertToLocalTime(date); 
+		CleanupStack::PopAndDestroy(2);  //myTZoneServer,myConverter
+		
+		TBuf<KMaxLongDateFormatSpec+KMaxTimeFormatSpec+1> parsedDateTime;
+	        date.FormatL(parsedDateTime, *iBodyHeaderDateTimeFormatString);   
+
+		// Numberconvertion to the local phone language
+		TLocale localeInfo;
+		localeInfo.Refresh();
+		TDigitType dgType = localeInfo.DigitType();
+
+		NumberConversion::ConvertDigits(parsedDateTime, dgType);
+
+		TPtrC subject = iOriginalHeader->Subject();
+		TPtrC author = iOriginalHeader->From();
+		iOriginalHeader = NULL;
+		
+		switch (iBodyHeaderFormat)
+			{
+			case EToAndCc:
+				{
+				iBodyHeader = HBufC::NewL(subject.Length() + author.Length() + parsedDateTime.Length() + iBodyHeaderToString->Length() + iBodyHeaderCcString->Length() + iBodyHeaderFormatString->Length());
+				TPtr bodyHeaderPtr = iBodyHeader->Des();
+				bodyHeaderPtr.Format(TRefByValue<const TDesC>(*iBodyHeaderFormatString), &subject, &author, iBodyHeaderToString, iBodyHeaderCcString, &parsedDateTime);
+				} break;				
+			case EToOnly:
+				{
+				iBodyHeader = HBufC::NewL(subject.Length() + author.Length() + parsedDateTime.Length() + iBodyHeaderToString->Length() + iBodyHeaderFormatString->Length());
+				TPtr bodyHeaderPtr = iBodyHeader->Des();
+				bodyHeaderPtr.Format(TRefByValue<const TDesC>(*iBodyHeaderFormatString), &subject, &author, iBodyHeaderToString, &parsedDateTime);
+				} break;
+			case ECcOnly:
+				{
+				iBodyHeader = HBufC::NewL(subject.Length() + author.Length() + parsedDateTime.Length() + iBodyHeaderCcString->Length() + iBodyHeaderFormatString->Length());
+				TPtr bodyHeaderPtr = iBodyHeader->Des();
+				bodyHeaderPtr.Format(TRefByValue<const TDesC>(*iBodyHeaderFormatString), &subject, &author, iBodyHeaderCcString, &parsedDateTime);
+				} break;
+			case ENoToCcInfo:
+			default:
+				{
+				iBodyHeader = HBufC::NewL(subject.Length() + author.Length() + parsedDateTime.Length() + iBodyHeaderFormatString->Length());
+				TPtr bodyHeaderPtr = iBodyHeader->Des();
+				bodyHeaderPtr.Format(TRefByValue<const TDesC>(*iBodyHeaderFormatString), &subject, &author, &parsedDateTime);
+				}
+			} // switch (iBodyHeaderFormat)
+		}
+
+	RequestComplete(KErrNone);
+	}
+
+void CImEmailOperation::RestoreOriginalHeaderL()
+	{
+	__ASSERT_DEBUG(iOriginalHeader==NULL, User::Invariant());
+	iOriginalHeader = CImHeader::NewLC();
+	CleanupStack::Pop(iOriginalHeader);
+
+	// Restore the header from the original message.
+	iMsvEntry->SetEntryL(iOrigMessageId);
+	CMsvStore* store = iMsvEntry->ReadStoreL();
+	CleanupStack::PushL(store);
+	iOriginalHeader->RestoreL(*store);
+	CleanupStack::PopAndDestroy(store);
+	SetBodyHeaderFormatL();
+	}
+	
+void CImEmailOperation::SetBodyHeaderFormatL()
+	{
+	// determine if To: and CC: fields are to be included in reply/forwarded email
+	// body header. If so, prepare the string to be included.
+	if (iSmtpSettings->ToCcIncludeLimit() > 0)
+		{
+		if (iOriginalHeader->ToRecipients().Count()>0)
+			{
+			if (iOriginalHeader->CcRecipients().Count()>0)
+				{
+				iBodyHeaderFormat=EToAndCc;
+				CreateAddressListStringL(iBodyHeaderCcString, iOriginalHeader->CcRecipients());
+				}
+			else
+				{
+				iBodyHeaderFormat=EToOnly;
+				}
+			CreateAddressListStringL(iBodyHeaderToString, iOriginalHeader->ToRecipients());
+			}
+		else // no "to" recipients, any "cc"?
+			{
+			if (iOriginalHeader->CcRecipients().Count()>0)
+				{
+				iBodyHeaderFormat=ECcOnly;
+				CreateAddressListStringL(iBodyHeaderCcString, iOriginalHeader->CcRecipients());
+				}
+			else
+				{
+				iBodyHeaderFormat=ENoToCcInfo;
+				}
+			}
+		}
+	else
+		{
+		iBodyHeaderFormat=ENoToCcInfo;
+		}
+	}
+
+void CImEmailOperation::CreateAddressListStringL(HBufC*& aListBuffer, const CDesCArray& aAddressArray)
+	{
+	// Prepares a list of addresses to include in body header of reply/forwarded emails,
+	// truncated if exceeding the set limit.
+	// The original data may be either an array of individual addresses, or a single
+	// descriptor containing multiple comma separated addresses.
+	TBool truncate=EFalse;
+	TInt  length=0;
+	TInt  count=0;
+	TInt  limit=iSmtpSettings->ToCcIncludeLimit();
+	TInt  elements=aAddressArray.Count();
+	
+	if (elements==0)
+		return;
+
+	if (elements==1) // handle single string containing one or more addresses
+		{
+		// truncate the string if necessary
+		TInt lastChar=0;
+		truncate=iMessageField.TruncateAddressString(aAddressArray[0], limit, lastChar);
+		if (!truncate)
+			{
+			aListBuffer = HBufC::NewL(aAddressArray[0].Length());
+			TPtr addrStringPtr = aListBuffer->Des();
+			addrStringPtr.Append(aAddressArray[0]);
+			}
+		else
+			{
+			aListBuffer = HBufC::NewL(lastChar+KEllipsesString.iTypeLength); // room for the truncated list + ellipses
+			TPtr addrStringPtr = aListBuffer->Des();
+			TPtrC16 leftString=aAddressArray[0].Left(lastChar);
+			TInt temp1 = leftString.Length();
+			TInt temp2 = aListBuffer->Length();
+			addrStringPtr.Append(leftString);
+			addrStringPtr.Append(KEllipsesString);
+			}
+		}
+	else	// handle array of individual addresses.
+		{
+		// determine if list to be truncated
+		if (limit<elements)
+			{
+			count=limit;
+			truncate=ETrue;
+			}
+		else
+			{
+			count=elements;
+			}
+		
+		// calculate length required for the address string
+		TInt n;
+		for (n=0;n<count-1;++n)
+			{
+			length+=aAddressArray[n].Length()+KSeparatorString.iTypeLength;
+			}
+		length+=aAddressArray[n].Length();
+		if (truncate)
+			{
+			length+=KEllipsesString.iTypeLength;
+			}
+
+		delete aListBuffer;
+		aListBuffer = NULL;
+		aListBuffer = HBufC::NewL(length);
+		TPtr addrStringPtr = aListBuffer->Des();
+
+		// populate the address buffer
+		for (n=0;n<count-1;++n)
+			{
+			addrStringPtr.Append(aAddressArray[n]);
+			addrStringPtr.Append(KSeparatorString);
+			}
+		addrStringPtr.Append(aAddressArray[n]);			
+		if (truncate)
+			{
+			addrStringPtr.Append(KEllipsesString);
+			}
+		}
+	}
+	
+void CImEmailOperation::GetBodyTextL()
+	{
+	//	1.	Insert body header
+	//	2.	Get the Body Text from the original message
+
+	if (iBodyHeaderFormatString != NULL)
+		iRichText->InsertL(iRichText->DocumentLength(), *iBodyHeader);
+
+	// DocumentLength() gives no. of chars and since unicode we multiply by 2
+	iRichTextSize = (iRichText->DocumentLength() * 2);
+	
+	iEmailMessage->GetBodyTextEntryIdL(iOrigMessageId,CImEmailMessage::EThisMessageOnly);
+	TMsvId textId = 0;
+	TBool isPlainText = EFalse;
+	
+	// Check if the body text of the message restored here was stored as rich text or not.
+	if( iEmailMessage->Selection().Count() )
+		{
+		textId = iEmailMessage->Selection().At(0);
+		iMsvEntry->SetEntryL(textId);
+		CMsvStore* store = iMsvEntry->ReadStoreL();
+		CleanupStack::PushL(store);
+		// Check if the original message was stored as plain text.
+		if(iUsePlainTextStorage)
+			{
+			isPlainText = (store->IsPresentL(KMsvPlainBodyText16)|| store->IsPresentL(KMsvPlainBodyText8));
+			}		
+		CleanupStack::PopAndDestroy(store);
+		store = NULL;
+		}
+		
+	// If the original message was not rich text then need not populate bodytext here.
+	// Body text will be retrieved and stored when StoreBodyL is called .
+	if(isPlainText)
+		{
+		TRequestStatus* myStatus=&iStatus;
+		iStatus=KRequestPending;
+		User::RequestComplete(myStatus,KErrNone);	
+		}
+	else
+		{
+		iEmailMessage->GetBodyTextL(iStatus, iOrigMessageId, CImEmailMessage::EThisMessageOnly, *iRichText, *iParaLayer, *iCharLayer);
+		}
+	
+	
+	}
+
+TInt CImEmailOperation::RemoveIncompleteAttachments()
+	{
+	TInt completeAttachmentCount = 0;
+	while (completeAttachmentCount < iAttachmentInfoList.Count())
+		{
+		if (!(iAttachmentInfoList[completeAttachmentCount]->Complete()))
+			{
+			delete iAttachmentInfoList[completeAttachmentCount];
+			iAttachmentInfoList.Remove(completeAttachmentCount);
+			}
+		else
+			++completeAttachmentCount;
+		}
+	return iAttachmentInfoList.Count();	
+	}
+
+void CImEmailOperation::CreateEntryDetails(TMsvEmailEntry& entry)
+	{
+	entry.iMtm = iMsgType;
+	entry.iServiceId = ServiceId();
+	entry.iType = KUidMsvMessageEntry;
+	entry.iDate.UniversalTime();
+	if ((iOperation != ENew) && (iPartList & KMsvMessagePartAttachments))
+		iTotalAttachments = RemoveIncompleteAttachments();
+	entry.SetNew(ETrue);
+	if (iEmbeddedMessagesToProcess!=0)
+		entry.SetAttachment(ETrue);
+	entry.SetVisible(!(iMsvEmailTypeList & KMsvEmailTypeListInvisibleMessage));
+	entry.SetMHTMLEmail(iCreateHtmlMessage);
+	entry.SetInPreparation(iMsvEmailTypeList & KMsvEmailTypeListMessageInPreparation);
+	}
+
+void CImEmailOperation::CreateNewMessageL(TMsvId aDestinationId)
+	{
+	//	Create a new message so that the different sections can be added to it:
+	iMsvEntry->SetEntryL(aDestinationId);
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	TMsvEmailEntry entry;
+	CreateEntryDetails(entry);
+	iMsvOperation = iMsvEntry->CreateL(entry, iStatus);
+	}
+
+TBool CImEmailOperation::NeedMultipartMixedFolder() const
+	{
+	if( (iPartList & KMsvMessagePartAttachments && (iTotalAttachments > 0)) &&
+		(iPartList & KMsvMessagePartBody || iSignatureText || iCreateHtmlMessage || iOperation & EAttachOriginal) )
+		{
+		// In this case the operation is attaching 1 or more attachments. As there
+		// is either message body (signature text implies) or at least another
+		// attachment (HTML body or the original message) then a mixed folder is
+		// needed.
+		return ETrue;
+		}
+
+	if( iPartList & KMsvMessagePartAttachments && (iTotalAttachments > 0) )
+		{
+		// If this case is reached then although the message body is not required
+		// but it has attachment/s a mixed folder is needed.
+		return ETrue;
+		}
+
+	if( iOperation & EAttachOriginal && iPartList & KMsvMessagePartBody )
+		{
+		// In this case the operation was attaching the original message as an 
+		// attachment (e.g ForwardAsAttachment). As the message body is required
+		// then mixed folder needed.
+		return ETrue;
+		}
+
+	if( (iNeedToAddVCardAttachment || iHtmlNoTextAlt || iEmbeddedMessagesToProcess) && 
+		(iPartList & KMsvMessagePartBody || iPartList & KMsvMessagePartAttachments))
+		{
+		// A V-card is required or the body text is added as an attachment or 
+		// there are embedded messages to attach - all imply an attachment of
+		// some description. As the message body or the attachments are required
+		// then a mixed folder is needed.
+		return ETrue;
+		}
+	
+	if( iNeedToAddVCardAttachment )
+		{
+		//  Now this case is probably not needed - added here because a text 
+		// entry is always added. Therefore if defect sorted so that text entry
+		// onlu added when required this case can be removed.
+		return ETrue;
+		}
+
+	// Got here therefore no mixed folder needed.
+	return EFalse;
+	}
+
+void CImEmailOperation::CreateMultipartMixedFolderEntryL()
+	{
+	iMsvEntry->SetEntryL(iNewMessageId);
+	TMsvEmailEntry entry;
+	entry.iType = KUidMsvFolderEntry;
+	entry.iMtm = iMsvEntry->Entry().iMtm;
+	entry.iServiceId = iMsvEntry->Entry().iServiceId;
+	entry.SetMessageFolderType(EFolderTypeMixed);
+	entry.iSize = 0;
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry->CreateL(entry, iStatus);
+	}
+
+void CImEmailOperation::CreateTextEntryL(TMsvId aFolderId)
+	{
+	iMsvEntry->SetEntryL(aFolderId);
+	TMsvEntry entry;
+	entry.iType = KUidMsvEmailTextEntry;
+	entry.iMtm = iMsvEntry->Entry().iMtm;
+	entry.iServiceId = ServiceId();
+	entry.iDate.UniversalTime();
+	entry.iSize = 0;
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry->CreateL(entry, iStatus);
+	}
+
+void CImEmailOperation::StoreBodyL()
+	{
+	if(iUsePlainTextStorage)
+		{
+		StorePlainBodyL();
+		return;
+		}
+	iMsvEntry->SetEntryL(iTextId);	//pointing to the text entry
+	CMsvStore* store = iMsvEntry->EditStoreL();
+	CleanupStack::PushL(store);
+	
+	store->StoreBodyTextL(*iRichText);
+	store->CommitL();
+	
+	CleanupStack::PopAndDestroy(store);	
+	// update size of text entry
+	TMsvEmailEntry entry(iMsvEntry->Entry());
+
+	// DocumentLength() gives no. of chars and since unicode, multiply by 2
+	entry.iSize = (iRichText->DocumentLength() * 2);	
+	entry.iDate.UniversalTime();
+	
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry->ChangeL(entry, iStatus);	
+	}
+
+
+void CImEmailOperation::StorePlainBodyL()
+	{
+	TUint charset = 0;
+	TUint defaultCharset = 0;
+	TBool override = EFalse;
+	
+	RFs& fileSvrSession = iMsvSession.FileSession();
+	CCnvCharacterSetConverter* characterConverter = CCnvCharacterSetConverter::NewL();
+	CleanupStack::PushL(characterConverter);
+	
+	CImConvertCharconv* charConv = CImConvertCharconv::NewL(*characterConverter, fileSvrSession);
+	CleanupStack::PushL(charConv);
+	defaultCharset = charConv->SystemDefaultCharset();
+	CleanupStack::PopAndDestroy(2);
+	
+	
+	// To store the ids of all the text part of a email message.
+	RArray<TMsvId> textIdArray;
+	CleanupClosePushL (textIdArray);
+	
+	RPointerArray<CMsvPlainBodyText> plainTextArray;
+	TCleanupItem closePlainTextArray (CImEmailOperation::ClosePlainBodyTextArray, &plainTextArray);
+	CleanupStack::PushL(closePlainTextArray);
+	TInt origSize = 0;
+	
+	// Chunk storage mechanism is used and we are doing a replyto OR fwding a mail then 
+	// get the size of the message.
+	if(iOperation == EForward || iOperation == EReply)
+		{
+		iEmailMessage->GetCharacterSetL(iOrigMessageId,charset,override);
+		
+		iEmailMessage->GetBodyTextEntryIdL(iOrigMessageId,CImEmailMessage::EThisMessageOnly);
+		TInt count = iEmailMessage->Selection().Count();
+		for(TInt i=0; i<count; ++i)
+			{
+			User::LeaveIfError (textIdArray.Append( iEmailMessage->Selection().At(i) ));
+			}
+		TInt textIdCount = 	textIdArray.Count();
+		for(TInt i=0; i<textIdCount; ++i)
+			{
+			// Pointing to the text entry.
+			iMsvEntry->SetEntryL(textIdArray[i]);	
+			CMsvStore* bodyTextStore = iMsvEntry->ReadStoreL();
+			CleanupStack::PushL(bodyTextStore);
+		
+			plainTextArray.Append( bodyTextStore->InitialisePlainBodyTextForReadL(KMsvDecodeChunkLength));
+			origSize += plainTextArray[i]->Size();
+				
+			CleanupStack::PopAndDestroy(bodyTextStore);
+			bodyTextStore = NULL;
+			}
+		}
+	
+	iMsvEntry->SetEntryL(iTextId);	//pointing to the text entry
+	
+	CMsvStore* bodyTextStore = iMsvEntry->EditStoreL();
+	CleanupStack::PushL(bodyTextStore);
+	
+	// If chunk storage mechanism is used then get CMsvPlainBodyText.
+	// Body text is stored as 16 bit so set iIs8Bit to EFalse.When a message is created from
+	// the client side data is stored as 16 bit.
+	CMsvPlainBodyText* text = bodyTextStore->InitialisePlainBodyTextForWriteL(EFalse,charset,defaultCharset);	
+	CleanupStack::PushL(text);
+	
+	// Add signature if it exists.
+	if(iSignatureText)
+		{
+		TInt len = iSignatureText->DocumentLength();
+		HBufC16* signatureText = HBufC16::NewLC(len);
+		TPtr signatureTextPtr = signatureText->Des();
+		iSignatureText->Extract(signatureTextPtr, 0, len);
+		text->StoreChunkL(signatureTextPtr);
+		CleanupStack::PopAndDestroy(signatureText);
+		}
+	
+	if(iBodyHeader)
+		{
+		if(iOperation == EForward || iOperation == EReply)
+			{
+			text->StoreChunkL(iBodyHeader->Des());
+			}
+		}
+			
+	// If email is Fwd'ed or ReplyTo then need to read from the existing mail and add it to
+	// the newly created mail since this was not done in GetBodyTextL.
+	TInt plainTextCount = plainTextArray.Count();
+	for(TInt i=0; i<plainTextCount; ++i)
+		{
+		TInt size = plainTextArray[i]->Size();
+		while( size > 0)
+			{
+			TBuf <KMsvDecodeChunkLength> buf;
+			plainTextArray[i]->NextChunkL(buf);
+			text->StoreChunkL(buf);
+			size -= KMsvDecodeChunkLength;
+			}	
+		delete plainTextArray[i];
+		plainTextArray[i] = NULL;
+		}
+	text->CommitL();
+	CleanupStack::PopAndDestroy(4, &textIdArray);// text, bodyTextStore, plainTextArray
+	
+	TMsvEmailEntry entry(iMsvEntry->Entry());
+
+	entry.iSize = origSize;	
+	entry.iDate.UniversalTime();
+	
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry->ChangeL(entry, iStatus);	
+	}
+
+
+void CImEmailOperation::CheckForSignatureOrVCardL()
+   	{
+   	if (!iSmtpServiceId || iSmtpServiceId==KMsvUnknownServiceIndexEntryId)
+   		return; // No smtp service set.
+   
+	if( iSmtpSettings->AddVCardToEmail() )
+   		{
+		CContactDatabase* db = NULL;
+   		// check whether the actual VCard exists
+		TRAPD(error, db = CContactDatabase::OpenL());
+		if( error == KErrNone )
+			{
+			CleanupStack::PushL(db);
+			TContactItemId contactId = db->OwnCardId();
+			if( contactId != KNullContactId )
+				iNeedToAddVCardAttachment = ETrue;
+			CleanupStack::PopAndDestroy(db);
+			}
+		else
+			{
+			if( db )
+				delete db;
+			}
+   		}
+   	
+	if( iSmtpSettings->AddSignatureToEmail() )
+   		{
+		// Check the SMTP settings entry for the signature text.
+		iMsvEntry->SetEntryL(iSmtpServiceId);
+		CMsvStore* store = iMsvEntry->ReadStoreL();
+		CleanupStack::PushL(store);
+
+		if( store->IsPresentL(KMsvEntryRichTextBody) )
+			{
+   			iSignatureText=CRichText::NewL(iParaLayer,iCharLayer);	
+   			store->RestoreBodyTextL(*iSignatureText);
+			}
+		CleanupStack::PopAndDestroy(store);
+   		}
+   	else
+   		iSignatureText=NULL;
+   	}
+
+void CImEmailOperation::CreateVCardAttachmentL()
+	{
+	// Get the vcard from contact database, need owncard entry..
+
+	CContactDatabase* db = CContactDatabase::OpenL();
+	CleanupStack::PushL(db);
+	TContactItemId contactId = db->OwnCardId();
+	CContactIdArray *ids=CContactIdArray::NewLC();
+	ids->AddL(contactId);
+	if(contactId == KNullContactId)
+		{
+		CleanupStack::PopAndDestroy(2); // db, ids
+		RequestComplete(KErrNone);
+		return; // vcard not present, do nothing.
+		}
+	
+	// Retrieve vcard to a temp store. 
+
+	TUid uid;
+	uid.iUid=KUidVCardConvDefaultImpl;
+
+	delete iVcardStore;
+	iVcardStore=NULL;
+	iVcardStore=CBufStore::NewL(128);
+	RStoreWriteStream tmpWrite;
+	iVcardStoreId = tmpWrite.CreateLC(*iVcardStore);
+
+	db->ExportSelectedContactsL(uid,*ids, tmpWrite, CContactDatabase::ETTFormat);
+	tmpWrite.CommitL();
+	iVcardStore->CommitL();
+
+	// create attachment CMsvEntry entry
+	TBuf<KVCardFilenameLength> textDef;
+	CContactTextDef* contactTextDef = CContactTextDef::NewLC();
+	TLanguage language = User::Language();
+	if( language == ELangTaiwanChinese || 
+		language == ELangHongKongChinese || 
+		language == ELangPrcChinese )
+		{
+		contactTextDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName));
+		contactTextDef->AppendL(TContactTextDefItem(KUidContactFieldGivenName));
+		}
+	else
+		{
+		contactTextDef->AppendL(TContactTextDefItem(KUidContactFieldGivenName));
+		contactTextDef->AppendL(TContactTextDefItem(KUidContactFieldFamilyName));
+		}
+	contactTextDef->SetExactMatchOnly(ETrue);
+	db->ReadContactTextDefL(contactId,textDef,contactTextDef);
+	CleanupStack::PopAndDestroy(contactTextDef);
+	if (textDef.Length())
+		iFileName.Copy(textDef);
+	else
+		iFileName.Copy(*iDefaultVCardNameFormatString);
+	iFileName.Append(KMimeVCardExtension);
+
+	if (iMultipartMixedFolderCreated)
+		iMsvEntry->SetEntryL(iMultipartMixedId);
+	else 
+		iMsvEntry->SetEntryL(iNewMessageId);
+	CleanupStack::PopAndDestroy(3); // db, ids, tmpWrite,
+
+	CreateAttachmentEntryL(); //Async
+	}
+
+void CImEmailOperation::AddVCardAttachmentL()
+	{
+	iMsvEntry->SetEntryL(iVcardId);
+	if (!iFileName.Length())
+		{
+		RequestComplete(KErrNone);
+		return; // ergo no attachment.
+		}
+
+	// Put vcard into a file.
+	TFileName filePath;
+	CMsvStore* store = iMsvEntry->EditStoreL();
+	CleanupStack::PushL(store);
+		
+	MMsvAttachmentManagerSync& attachmentMgrSync = store->AttachmentManagerExtensionsL();
+	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	RFile file;
+	attachmentMgrSync.CreateAttachmentL(iFileName,file,attachment);
+	store->CommitL();
+	CleanupStack::PopAndDestroy(store);
+	
+	// set the file attachment file handle with write mode
+	iAttachmentFile.SetFileHandle(file,TImAttachmentFile::EImFileWrite);
+	RStoreReadStream dummy;
+	dummy.OpenLC(*iVcardStore,iVcardStoreId);
+	TInt size = (dummy.Source()->SizeL());
+	
+	HBufC8* textBuffer=HBufC8::NewLC(size);
+	TPtr8 bufPtr=textBuffer->Des();
+	dummy.ReadL(bufPtr,size);
+	iAttachmentFile.WriteFile(bufPtr);
+	iAttachmentFile.CloseFile();
+
+	delete iVcardStore;
+	iVcardStore=NULL;
+	CleanupStack::PopAndDestroy(2); // dummy, textBuffer
+
+	iMsvEntry->SetEntryL(iVcardId);
+	TMsvEmailEntry entry = iMsvEntry->Entry();
+	entry.iSize = size;
+	entry.iDetails.Set(iFileName);
+	entry.SetVCard(ETrue);
+	iVCardAndHtmlSize+=entry.iSize;
+
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry->ChangeL(entry, iStatus);
+	}
+
+void CImEmailOperation::CreateAttachmentEntryL()
+	{
+	if (iMultipartMixedFolderCreated)
+		iMsvEntry->SetEntryL(iMultipartMixedId);
+	else 
+		iMsvEntry->SetEntryL(iNewMessageId);
+
+	// create the index entry
+	TMsvEntry entry;
+	entry.iMtm = iMsgType;
+	entry.iServiceId = ServiceId();
+	entry.iType = KUidMsvAttachmentEntry;
+	entry.iDate.UniversalTime();
+	entry.SetAttachment(ETrue);
+
+	if (iAttachmentInfoList.Count())
+		{
+		// set the size and attachment name of the entry
+		CMsvAttachment* attachment = iAttachmentInfoList[iAttachmentCount];
+		entry.iSize = iAttachmentInfoList[iAttachmentCount]->Size();
+		if(iAttachmentInfoList[iAttachmentCount]->AttachmentName().Length() == 0)
+			{
+			TParse parseFile;
+			parseFile.Set(iAttachmentInfoList[iAttachmentCount]->FilePath(),NULL,NULL);
+			entry.iDetails.Set(parseFile.NameAndExt());
+			}
+		else 
+			{
+			entry.iDetails.Set(iAttachmentInfoList[iAttachmentCount]->AttachmentName());
+			}	
+		}
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry->CreateL(entry, iStatus);
+	}
+
+void CImEmailOperation::StoreAttachmentL()
+	{
+	RFile origAttachmentFile;
+	if (iAttachmentInfoList[iAttachmentCount]->Type() == CMsvAttachment::EMsvFile)
+		{
+		// Need to get a file handle for the original attachment.
+		TMsvId origAttachId = iAttachmentInfoList[iAttachmentCount]->Id();
+		iMsvEntry->SetEntryL(origAttachId);
+		CMsvStore* store = iMsvEntry->ReadStoreL();
+		CleanupStack::PushL(store);
+		MMsvAttachmentManager& origAttachmentMgr = store->AttachmentManagerL();
+
+		// This is an email attachment entry, so it only has one attachment per entry
+		origAttachmentFile = origAttachmentMgr.GetAttachmentFileL(0);
+		CleanupStack::PopAndDestroy(store);
+		CleanupClosePushL(origAttachmentFile);
+		}
+
+	TMsvId msvId = McliUtils::GetProgressIdL(*iMsvOperation);
+	iMsvEntry->SetEntryL(msvId);//pointing to the attachment
+	iStore = iMsvEntry->EditStoreL();
+
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	// Reset the Id to 1, email attachments have one entry 
+	iAttachmentInfoList[iAttachmentCount]->SetId(1);
+	CMsvAttachment* attachment = CMsvAttachment::NewL(*iAttachmentInfoList[iAttachmentCount]);
+
+	CleanupStack::PushL(attachment);
+
+ 	if(attachment->Type() == CMsvAttachment::EMsvFile)
+ 		{
+		attachmentMgr.AddAttachmentL(origAttachmentFile, attachment, iStatus);
+		CleanupStack::Pop(2, &origAttachmentFile);   // attachment, origAttachmentFile
+ 		}
+ 	else if(attachment->Type() == CMsvAttachment::EMsvLinkedFile)
+ 		{
+ 		attachmentMgr.AddLinkedAttachmentL(attachment->FilePath(), attachment, iStatus);
+ 		CleanupStack::Pop(attachment);
+ 		}
+ 	else if(attachment->Type() == CMsvAttachment::EMsvMessageEntry)
+ 		{
+ 		attachmentMgr.AddEntryAsAttachmentL(attachment->EntryAttachmentId(), attachment, iStatus);
+ 		CleanupStack::Pop(attachment);
+ 		}
+ 	else
+ 		{
+ 		// If we have hit this line then a new attachment type has been added
+ 		// so this function will need to be updated.
+ 		__ASSERT_DEBUG(0, gPanic(EImEmailOpUnknownAttachmentType));
+ 		}
+	}
+
+void CImEmailOperation::AddMessageAsAttachmentL()
+	{
+	TMsvId serviceId;
+	TMsvEmailEntry entry;
+
+	iMsvEntry->Session().GetEntry(iEmailMessage->Selection()[--iEmbeddedMessagesToProcess], serviceId, entry);
+	iMsvEntry->SetEntryL(entry.Parent());
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	if (iMultipartMixedFolderCreated)
+		iMsvOperation = iMsvEntry->CopyL(iEmailMessage->Selection()[iEmbeddedMessagesToProcess], iMultipartMixedId, iStatus);
+	else 
+		iMsvOperation = iMsvEntry->CopyL(iEmailMessage->Selection()[iEmbeddedMessagesToProcess], iNewMessageId, iStatus);
+	}
+
+void CImEmailOperation::CreateMultipartAlternativeFolderEntryL()
+	{
+	if (iMultipartMixedFolderCreated)
+		iMsvEntry->SetEntryL(iMultipartMixedId);
+	else 
+		iMsvEntry->SetEntryL(iNewMessageId);
+
+	TMsvEmailEntry entry;
+	entry.iType = KUidMsvFolderEntry;
+	entry.iMtm = iMsvEntry->Entry().iMtm;
+	entry.iServiceId = iMsvEntry->Entry().iServiceId;
+	entry.SetMessageFolderType(EFolderTypeAlternative);
+	entry.iSize = 0;
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry->CreateL(entry, iStatus);
+	}
+
+void CImEmailOperation::AppendHtmlAttachmentL()
+	{
+	TBool copyHtml = EFalse;
+	HBufC* temp = NULL;
+	temp = iEmailMessage->GetUniversalResourceIdentifierL(iHtmlId, copyHtml);
+	delete temp;
+	temp = NULL;
+	if (copyHtml)
+		{
+		iMsvEntry->SetEntryL(iHtmlId);
+		TMsvEmailEntry entry(iMsvEntry->Entry());
+			CMsvStore* store = iMsvEntry->ReadStoreL();
+			CleanupStack::PushL(store);
+			MMsvAttachmentManager& attachmentMgr = store->AttachmentManagerL();
+			if(attachmentMgr.AttachmentCount())
+				{
+				// as this is email attachment entry , it has one attachment per entry
+				CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
+				CleanupStack::PushL(attachment);
+				
+				attachment->SetSize(entry.iSize);
+				attachment->SetComplete(entry.Complete());
+				// def070915 - propagated fix
+				attachment->SetId(iHtmlId);
+				CleanupStack::Pop(attachment);
+				iAttachmentInfoList.Append(attachment);
+				++iTotalAttachments;
+				iPartList=iPartList|KMsvMessagePartAttachments;
+				}
+			CleanupStack::PopAndDestroy(store);	
+		}
+	RequestComplete(KErrNone);
+	}
+
+/**
+Creates another CImEmailOperation object that creates a copy of the original
+message as an attachment to this message.
+
+The partlist supplied to the current CImEmailOperation is passed to the new one
+but ensuring that the orginator and recipient lists are included in the copy.
+
+The copied message is attached as a child of the Multipart Mixed folder entry if
+it exists or as a child of this message's message entry.
+*/
+void CImEmailOperation::AttachOriginalMessageToNewMessageL()
+	{
+	TMsvPartList partList = iPartList | KMsvMessagePartRecipient | KMsvMessagePartOriginator;
+
+	TInt typeList = 0;
+	if( iOrigMessageHtml )
+		typeList |= KMsvEmailTypeListMHTMLMessage;
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	if( iMultipartMixedFolderCreated )
+		iMsvOperation = CImEmailOperation::CreateCopyL(iStatus, iMsvSession, iOrigMessageId, iMultipartMixedId, partList, typeList, iMsgType);
+	else 
+		iMsvOperation = CImEmailOperation::CreateCopyL(iStatus, iMsvSession, iOrigMessageId, iNewMessageId, partList, typeList, iMsgType);
+	}
+
+void CImEmailOperation::CompleteEmailOperationL()
+	{
+	//	1.	Set the Details (and Description if applicable)
+	//	2.	Set the Size = Size of Header + Size of Body + Size of Attachments
+	
+	iMsvEntry->SetEntryL(iNewMessageId);	//pointing to the message
+	TMsvEmailEntry entry(iMsvEntry->Entry());
+
+	// Set the service id and the related id if the message we have created is a PCMail
+	// Note that this only needs to be done for Reply as otherwise we don't know the service.
+	// The service id will already be set for New and Forward PCMails if the service id was passed
+	// into the Constructor.
+	if( iMsgType == KUidMsgTypePCMail )
+		entry.iServiceId = entry.iRelatedId = ServiceId();
+
+	// if there are multiple recipients then set the flag
+	if( (iNewHeader->ToRecipients().Count() + iNewHeader->CcRecipients().Count() + iNewHeader->BccRecipients().Count()) > 1 )
+		entry.SetMultipleRecipients(ETrue);
+
+	if( iNewHeader->ToRecipients().Count() )
+		entry.iDetails.Set(iNewHeader->ToRecipients()[0]);
+	else if( iNewHeader->CcRecipients().Count() )
+		entry.iDetails.Set(iNewHeader->CcRecipients()[0]);
+	else if( iNewHeader->BccRecipients().Count() )
+		entry.iDetails.Set(iNewHeader->BccRecipients()[0]);
+	//else do nothing as there are no recipients yet!
+
+	entry.iDescription.Set(iNewHeader->Subject());
+	entry.iDate.UniversalTime();
+	
+	TInt sizeOfHeader = iNewHeader->DataSize();
+	
+	// only add the size of the rich text if the body is required or a signature has been added
+	// as otherwise it is not added
+	TInt sizeOfBody = 0;
+	if( iSignatureText || (iPartList & KMsvMessagePartBody) )
+		{
+		if(iUsePlainTextStorage)
+			{
+			iEmailMessage->GetBodyTextEntryIdL(iNewMessageId,CImEmailMessage::EThisMessageOnly);
+			sizeOfBody = GetPlainBodyTextSizeL();
+			iMsvEntry->SetEntryL(iNewMessageId);
+			}
+		else
+			{
+			// DocumentLength() gives no. of chars and since unicode we multiply by 2
+			sizeOfBody = (iRichText->DocumentLength() * 2);
+			}
+			
+		}
+	
+	TInt sizeOfAttachments = 0;
+	if( (iOperation != ENew) && (iPartList & KMsvMessagePartAttachments) )
+		{
+		for( TInt i=0; i<iTotalAttachments; ++i )
+			{
+			sizeOfAttachments += iAttachmentInfoList[i]->Size();
+			}
+		}
+
+	TInt sizeOfAttachedMessage = 0;
+	if( iOperation & EAttachOriginal )
+		{
+		TMsvId serviceId;
+		TMsvEmailEntry attachedMessageEntry;
+		iMsvEntry->Session().GetEntry(iAttachedMessageId, serviceId, attachedMessageEntry);
+		sizeOfAttachedMessage = attachedMessageEntry.iSize;
+		}
+
+	entry.iSize = sizeOfHeader + sizeOfBody + sizeOfAttachments + sizeOfAttachedMessage + iVCardAndHtmlSize;
+
+	// For receipt messages set the sending state to KMsvSendStateWaiting as receipts can be sent
+	// immediately
+	// For all others messages, use the setting in the SMTP settings
+	if( iOperation == EReceipt )
+		entry.SetSendingState(KMsvSendStateWaiting);
+	else if( iMsgType == KUidMsgTypeSMTP && iOperation != ECopy )
+		{
+		TUint sendState = 0;
+		switch( iSmtpSettings->SendMessageOption() )
+			{
+		case ESendMessageImmediately: // No send state for this !!
+		case ESendMessageOnNextConnection:
+			sendState = KMsvSendStateWaiting;
+			break;
+		case ESendMessageOnRequest:
+		default:
+			sendState = KMsvSendStateUponRequest;
+			break;
+			}
+		entry.SetSendingState(sendState);
+		}
+
+	// If a VCard has been added then the attachment flag needs to be set
+	if( iVcardId || (iTotalAttachments > 0) )
+		{
+		entry.SetAttachment(ETrue);
+		}
+
+	if(iVcardId)
+		{
+		// The vcard is set on the actual email entry.
+		entry.SetVCard(ETrue);
+		}
+
+	if( iOperation != ECopy )
+		{
+		// Adding a receipt flag or adding body encoding to the header does not
+		// apply to ECopy operations.
+
+		// Add receipt flag if required (check SMTP settings)
+		if( (iMsgType == KUidMsgTypeSMTP) && (iOperation != EReceipt) && (iSmtpServiceId != KMsvUnknownServiceIndexEntryId) )
+			{
+			if( iSmtpSettings->RequestReceipts() )
+				{
+				if( iSmtpSettings->ReceiptAddress().Length() )
+					iNewHeader->SetReceiptAddressL(iSmtpSettings->ReceiptAddress());
+				else if( iSmtpSettings->ReplyToAddress().Length() )
+					iNewHeader->SetReceiptAddressL(iSmtpSettings->ReplyToAddress());
+				// else don't know who to send a receipt to - receipt will not be sent.
+				
+				if( iNewHeader->ReceiptAddress().Length() )
+					entry.SetReceipt(ETrue);
+				}
+			}
+
+		// Store the body encoding in the header from the SMTP account settings
+		// if the user is creating a plaintext message even though the settings
+		// specify HTML message, the body encoding is set to EMsgOutboxMIME
+		if( iCreateHtmlMessage )
+			iNewHeader->SetBodyEncoding(EMsgOutboxMHTMLAlternativeAsMIME);
+		else if( (iMsgType == KUidMsgTypeSMTP) || (iSmtpSettings->BodyEncoding() != EMsgOutboxMHTMLAlternativeAsMIME) )
+			iNewHeader->SetBodyEncoding(iSmtpSettings->BodyEncoding());	
+		else
+			iNewHeader->SetBodyEncoding(EMsgOutboxMIME);
+		}
+
+	CMsvStore* store = iMsvEntry->EditStoreL();
+	CleanupStack::PushL(store);
+	// store the header - this has not been done previously
+	iNewHeader->StoreL(*store);
+
+	if( iMultipartMixedFolderCreated || iMultipartAlternativeFolderCreated )
+		{
+		CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
+		mimeHeader->SetContentTypeL(KMimeMultipart);
+		if( iMultipartMixedFolderCreated )
+			mimeHeader->SetContentSubTypeL(KMimeMixed);
+		else
+			mimeHeader->SetContentSubTypeL(KMimeAlternative);
+		mimeHeader->SetContentTransferEncodingL(KMimeQuotedPrintable);
+		mimeHeader->StoreL(*store);
+		entry.iSize += mimeHeader->Size();
+		CleanupStack::PopAndDestroy(mimeHeader);
+		}
+	store->CommitL();
+	CleanupStack::PopAndDestroy(store);
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iMsvEntry->ChangeL(entry, iStatus);
+	}
+
+void CImEmailOperation::CreateHTMLEntryL()
+	{
+	iMsvEntry->SetEntryL(iMultipartAlternativeId);
+
+	TMsvEntry entry;
+	entry.iServiceId = ServiceId();
+	entry.iType = KUidMsvEmailHtmlEntry;
+	entry.iMtm = iMsvEntry->Entry().iMtm;
+	entry.iDate.UniversalTime();
+	entry.iSize = 0;
+
+	delete iMsvOperation;
+	iMsvOperation = NULL;
+	iMsvOperation = iMsvEntry->CreateL(entry, iStatus);
+	iHtmlId = iMsvEntry->Entry().Id();
+	}
+	
+void CImEmailOperation::AddMessageAttachmentInfoL(TMsvId aAttachmentMessageId)
+	{
+	iMsvEntry->SetEntryL(aAttachmentMessageId);
+	
+	iStore = iMsvEntry->EditStoreL();
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+
+	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvMessageEntry); 
+	CleanupStack::PushL(attachment);
+	attachmentMgr.AddEntryAsAttachmentL(aAttachmentMessageId,attachment,iStatus);
+	CleanupStack::Pop(attachment);
+	}
+void CImEmailOperation::CreateDefaultAttachmentL()
+	{
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	TFileName fileName;
+	ReadDefaultHtmlAttachmentNameL(fileName);
+	attachmentMgr.CreateAttachmentL(fileName,iFile,attachment,iStatus);
+	}
+
+void CImEmailOperation::ReadDefaultHtmlAttachmentNameL(TDes& aFileName)
+	{
+	RResourceFile resourceFile;
+	OpenResourceFileL(resourceFile, iMsvSession.FileSession());
+	CleanupClosePushL(resourceFile);
+	
+	TResourceReader reader;
+	HBufC8* buf = resourceFile.AllocReadLC( DEFAULT_ATTACHMENT_NAME );
+	reader.SetBuffer(buf);
+	
+	TPtrC attachmentName = reader.ReadTPtrC();
+	const TDesC& ext = KMimeHtmlExtension;
+	HBufC* defaultAttachmentName = HBufC::NewL(attachmentName.Length() + ext.Length());
+	CleanupStack::PushL(defaultAttachmentName);
+
+	defaultAttachmentName->Des().Copy(attachmentName);
+	defaultAttachmentName->Des().Append(ext);
+	aFileName.Append(*defaultAttachmentName);
+
+	CleanupStack::PopAndDestroy(3,&resourceFile ); //buf, defaultAttachmentName,resourceFile (Close resourceFile)
+	}
+	
+void CImEmailOperation::ResetStoreL()	
+	{
+	iStore->CommitL();
+	delete iStore;
+	iStore = NULL;
+	}
+
+/**
+Method that will be called when object in RPointerArray<CMsvPlainBodyText> is deleted.
+@param aPtr		Pointer to the RPointerArray.
+@return void.
+*/
+void CImEmailOperation::ClosePlainBodyTextArray( TAny* aPtr )
+	{
+	RPointerArray<CMsvPlainBodyText>* plainBodyTextArray = reinterpret_cast<RPointerArray<CMsvPlainBodyText>*> (aPtr);
+	plainBodyTextArray->ResetAndDestroy();
+	}
+
+/**
+Return the size of the body text for a email message.
+*/
+TInt CImEmailOperation::GetPlainBodyTextSizeL()
+	{
+	TInt count = iEmailMessage->Selection().Count();
+	TInt sizeOfBody = 0;		
+	for(TInt i=0; i< count ;++i)
+		{
+		iMsvEntry->SetEntryL(iEmailMessage->Selection().At(i));	//pointing to the text entry	
+		CMsvStore* bodyTextStore = iMsvEntry->ReadStoreL();
+		CleanupStack::PushL(bodyTextStore);
+			
+		CMsvPlainBodyText* plainBodyText = bodyTextStore->InitialisePlainBodyTextForReadL(KMaxChunkLength);
+		sizeOfBody += plainBodyText->Size();
+				
+		delete plainBodyText;
+		plainBodyText = NULL;
+			
+		CleanupStack::PopAndDestroy(bodyTextStore);
+		bodyTextStore = NULL;
+		}
+	return 	sizeOfBody;
+	}
+	
+void CImHtmlConverter::ResetStoreL()
+	{
+	if(iStore != NULL )
+		{
+		iStore->CommitL();
+		delete iStore;
+		iStore = NULL;
+		}
+	}
+	
+ void CImHtmlConverter::ResetStoreWithoutCommit()
+ 	{
+ 	if (this != NULL)
+	 	{
+	 	if(iStore != NULL )
+	 		{
+	 		delete iStore;
+	 		iStore = NULL;
+	 		}	
+	 	}
+  	}
+
+//-----------------------------------------------------------------
+
+//-----------------------------------------------------------------
+
+CImHtmlConverter* CImHtmlConverter::NewL(CMsvEntry& aMsvEntry, 
+								   CParaFormatLayer& aParaLayer, CCharFormatLayer& aCharLayer)
+	{
+	CImHtmlConverter* self = new (ELeave) CImHtmlConverter(aMsvEntry, aParaLayer, aCharLayer);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CImHtmlConverter::CImHtmlConverter(CMsvEntry& aMsvEntry, CParaFormatLayer& aParaLayer, CCharFormatLayer& aCharLayer)
+:iMsvEntry(aMsvEntry), iParaLayer(aParaLayer), iCharLayer(aCharLayer)
+{
+}
+
+void CImHtmlConverter::ConstructL()
+	{
+	_LIT8(KHtmlInMimeType, "epoc32/crichtext");
+	_LIT8(KHtmlOutMimeType, "text/html");
+
+	TDataType inMimeType(KHtmlInMimeType);
+	TDataType outMimeType(KHtmlOutMimeType);
+
+	iConverterList = CCnaConverterList::NewL();
+	iConverterList->UpdateL();
+
+	TUid uid = iConverterList->ConverterL(inMimeType, outMimeType);
+
+	iToHTMLConverter = iConverterList->NewConverterL(uid);
+	User::LeaveIfNull(iToHTMLConverter);
+	User::LeaveIfError(iToHTMLConverter->Capabilities() & CConverterBase::EConvertsFiles);
+	}
+
+void CImHtmlConverter::PrepareToStoreHTMLEntryTextL (TMsvId& aHtmlId, const TMsvId aTextId)
+	{
+	// 0. Check html entry exists.
+	if (!aHtmlId)
+		{
+		iMsvEntry.SetEntryL(iMsvEntry.Entry().Parent());	//pointing to the text entry
+		if ( ((TMsvEmailEntry)iMsvEntry.Entry()).MessageFolderType() != EFolderTypeAlternative)
+			return;
+		TInt i = iMsvEntry.Count();
+		while (i--)
+			{
+			if (aTextId!=iMsvEntry[i].Id())
+				{
+				aHtmlId=iMsvEntry[i].Id();
+				break;
+				}
+			}
+		}
+
+	if (aHtmlId <=0)
+		return;
+
+	// 1. Create file containing Rich text.
+
+	iMsvEntry.SetEntryL(aTextId);	//pointing to the text entry
+	TFileName filepath;
+// Create the file with Rich text in non secure version 
+
+	CMsvStore* store=NULL;
+    TRAPD(err,store=iMsvEntry.ReadStoreL());
+ 	if (err)
+		{
+		aHtmlId=0;
+	    User::Leave(err);
+		}
+	CleanupStack::PushL(store);
+
+	if ( !store->IsPresentL(KMsvEntryRichTextBody) && !store->IsPresentL(KMsvPlainBodyText16) && !store->IsPresentL(KMsvPlainBodyText8))
+		{
+		aHtmlId=0;
+		User::Leave(KErrNotFound); // Rich text not found
+		}
+
+	CRichText* bodyText=CRichText::NewL(&iParaLayer,&iCharLayer);
+	CleanupStack::PushL(bodyText);
+	store->RestoreBodyTextL(*bodyText);
+	
+	if (bodyText->PictureCount())
+		{
+		RMsvReadStream in;
+		in.OpenL(*store, KMsvEntryRichTextBody);
+		CEmbeddedStore* embeddedStore = CEmbeddedStore::FromL(in);
+	
+		// Create store resolver
+		CImStoreResolver* storeResolver = new(ELeave)CImStoreResolver(embeddedStore); // Takes ownership
+		CleanupStack::PushL(storeResolver);
+	
+		// Set the picture factory
+		__ASSERT_ALWAYS(CEikonEnv::Static(), gPanic(EImcmNoEikonEnvironment));
+		MPictureFactory* factory = CEikonEnv::Static()->PictureFactory();
+		bodyText->SetPictureFactory(factory, storeResolver);
+		bodyText->DetachFromStoreL(CPicture::EDetachFull);
+		CleanupStack::PopAndDestroy(storeResolver);
+		}
+	CleanupStack::Pop(bodyText);
+	delete iRichText;
+	iRichText = NULL;
+	iRichText = bodyText;
+	TPckgBuf<CRichText*> bufferRichText(iRichText); //text to be converted
+	iSourceStream.Open(bufferRichText);
+	
+	CleanupStack::PopAndDestroy(store);
+	// 2. Convert to HTML file
+	iMsvEntry.SetEntryL(aHtmlId);
+	iStore = iMsvEntry.EditStoreL();
+	MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+	iFile = attachmentMgr.GetAttachmentFileForWriteL(0);
+	// open the write stream setting with file handle
+	iTargetStream.Attach(iFile);
+	// Prepares for asyn conversion. 	
+	iHtmlId=aHtmlId;
+	iTextId=aTextId;
+	
+	iToHTMLConverter->ConvertObjectAL(iSourceStream,iTargetStream);
+	}
+	
+TBool CImHtmlConverter::StoreHTMLEntryTextAL(TRequestStatus& aStatus)
+	{
+	TBool finishedConvertingHTML = (!iToHTMLConverter->DoConvertL());
+			
+	if (finishedConvertingHTML)
+		{
+		TFileName filepath;
+		RDir dir;
+		TEntry entry;
+		TParse dirPath;
+		iToHTMLConverter->CancelConvert();
+		iSourceStream.Close();
+		iTargetStream.CommitL();
+		iTargetStream.Close();
+		iFile.Close();
+		ResetStoreL();
+
+		// Set to html attachment entry
+		iMsvEntry.SetEntryL(iHtmlId);
+		iStore = iMsvEntry.EditStoreL();
+		MMsvAttachmentManager& attachmentMgr = iStore->AttachmentManagerL();
+		
+		// Email Mtm will have one attachment per attachment entry , ehnce index 0
+		CMsvAttachment* attachment = attachmentMgr.GetAttachmentInfoL(0);
+		RFile file = attachmentMgr.GetAttachmentFileL(0);
+		CleanupStack::PushL(attachment);
+		TInt error = file.Size(iSize);
+		if(error == KErrNone)
+			attachment->SetSize(iSize);
+		file.Close();
+		TFileName filename = HtmlFilename(iMsvEntry, GetDefaultAttachmentName());
+		attachment->SetAttachmentNameL(filename);
+		CleanupStack::Pop(attachment); // ownership passed to attachment manager 
+		
+		attachmentMgr.ModifyAttachmentInfoL(attachment,aStatus);
+		return 	finishedConvertingHTML; // true
+		}
+	return finishedConvertingHTML; // false
+	}	
+	
+CMsvOperation*CImHtmlConverter::ChangeHTMLTextInEnrtyL(TRequestStatus& aStatus)
+	{
+	TMsvEmailEntry emailEntry = iMsvEntry.Entry();
+	
+	TFileName filename = HtmlFilename(iMsvEntry, GetDefaultAttachmentName());
+	emailEntry.iDetails.Set(filename);
+	emailEntry.iSize = iSize;	
+	return iMsvEntry.ChangeL(emailEntry, aStatus);	
+	}
+
+TFileName CImHtmlConverter::HtmlFilename(CMsvEntry& aEntry, TPtrC aFileName)
+	{
+	TFileName path;
+	TFileName name;
+	TMsvEntry entry = aEntry.Entry();	
+// this is not used at all , need to get rid of this 
+	if (entry.iDetails.Length())
+		name=entry.iDetails;
+	else if (aFileName.Length())
+		name.Copy(aFileName);
+	return name;
+	}
+
+void CImHtmlConverter::ReadDefaultAttachmentNameL(RResourceFile& resourceFile)
+	{	
+	TResourceReader reader;
+	HBufC8* buf;
+
+	buf = resourceFile.AllocReadLC( DEFAULT_ATTACHMENT_NAME );
+	reader.SetBuffer(buf);
+	TPtrC attachmentName = reader.ReadTPtrC();
+	const TDesC& ext = KMimeHtmlExtension;
+	iDefaultAttachmentName = HBufC::NewL(attachmentName.Length() + ext.Length());
+	iDefaultAttachmentName->Des().Copy(attachmentName);
+	iDefaultAttachmentName->Des().Append(ext);
+	CleanupStack::PopAndDestroy(); // buf
+	}
+
+TPtrC CImHtmlConverter::GetDefaultAttachmentName()
+	{
+	return (iDefaultAttachmentName) ? iDefaultAttachmentName->Des() : TPtrC();
+	}
+
+CImHtmlConverter::~CImHtmlConverter()
+	{
+	delete iToHTMLConverter;
+	delete iDefaultAttachmentName;
+	delete iConverterList;
+	delete iRichText;
+	iSourceStream.Close();
+	iTargetStream.Close();
+	iFile.Close();
+	delete iStore;
+	}
+
+TInt CImHtmlConverter::Size() const
+	{
+	return iSize;
+	}
+
+
+//**********************************
+// CImStoreResolver
+//**********************************
+
+CImStoreResolver::CImStoreResolver(CStreamStore* aStore)
+: iStore(aStore)
+	{
+	}
+
+CImStoreResolver::~CImStoreResolver()
+	{
+	delete iStore;
+	}
+
+const CStreamStore& CImStoreResolver::StreamStoreL(TInt) const
+	{
+	return *iStore;
+	}
+