email/pop3andsmtpmtm/clientmtms/src/SMTCMTM.CPP
changeset 0 72b543305e3a
child 76 60a8a215b0ec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/clientmtms/src/SMTCMTM.CPP	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1068 @@
+// 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:
+// Client MTM for the SMTP protocol
+// 
+//
+
+#include <bautils.h>	// BaflUtils::NearestLanguageFile()
+#include <txtrich.h>	// CRichText
+
+#include <barsc.h>		//RResourceFile
+#include <barsread.h>
+
+#include <msvstore.h>	// CMsvStore
+#include <mtmdef.h>		//KUidMtmQueryxxx & TMsvPartList flags
+#include <imcm.rsg>
+#include <mmsvattachmentmanager.h>
+#include <cmsvmimeheaders.h>
+#include <cemailaccounts.h>
+#include "CImAttachmentWaiter.h"
+#include "cmsvsmtpsendoperation.h"
+#include "MIUTHDR.H"	//CImHeader
+#include "SMTCMTM.H"
+#include "MIUT_ERR.H"
+#include "IMCMMAIN.H"
+#include "IMCMUTIL.H"
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 
+#include <mtmuidsdef.hrh>
+#include "timrfc822datefield.h" 
+#include "miut_errconsts.h"
+#include "msvconsts.h"
+#include "cimmessagepart.h"
+#endif
+
+#include <msvenhancesearchsortutil.h>
+
+#if defined (_UNICODE)
+	#define KUidMsgInternetMailEditorDLL	0x10003C53  // (268450899)
+#else
+	#define KUidMsgInternetMailEditorDLL	0x100011AC  // (268439980)
+#endif
+
+/**
+@internalTechnology
+*/
+
+EXPORT_C CSmtpClientMtm* CSmtpClientMtm::NewL(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession)
+	{
+	CSmtpClientMtm* self = new(ELeave) CSmtpClientMtm(aRegisteredMtmDll, aMsvSession);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CSmtpClientMtm::CSmtpClientMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession)
+	: CBaseMtm(aRegisteredMtmDll, aMsvSession)
+	{
+	__DECLARE_NAME(_S("CSmtpClientMtm"));
+	}
+
+void CSmtpClientMtm::ConstructL()
+	{
+	iWait=CMsvOperationActiveSchedulerWait::NewLC();
+	CleanupStack::Pop();	// iWait
+
+	iImSmtpSettings = new (ELeave) CImSmtpSettings;
+	iHeader = CImHeader::NewLC();
+	CleanupStack::Pop();	// iHeader
+
+	//open the resource file
+	RResourceFile resourceFile;
+	OpenResourceFileL(resourceFile, Session().FileSession());
+	CleanupClosePushL(resourceFile);
+
+	HBufC8* buf = resourceFile.AllocReadLC(EMAIL_ADDRESS_FORMATTING_STRING);
+	TResourceReader reader;
+	reader.SetBuffer(buf);
+	iEmailAddressFormatString = (reader.ReadTPtrC()).AllocL();
+	CleanupStack::PopAndDestroy(2); // resourceFile (Close resourceFile), buf
+	}
+
+CSmtpClientMtm::~CSmtpClientMtm()
+/** Destructor. */
+	{
+	delete iWait;
+	delete iImSmtpSettings;
+	delete iHeader;
+	delete iSubject;
+	delete iEmailAddressFormatString;
+	delete iEntrySelection;
+	delete iImEmailOperation;
+	delete iAttachmentWaiter;
+	delete iEmailMessage;
+	}
+
+void CSmtpClientMtm::ResetData()
+	{
+	// The client MTM owns a number of objects which are used to store data
+	// from service settings and messages.
+	iAddresseeList->Reset();
+	iImSmtpSettings->Reset();
+	
+	delete iSubject;
+	iSubject = NULL;
+
+	iHeader->Reset();
+	Body().Reset();	// discard old contents of CRichText object
+	}
+
+void CSmtpClientMtm::SaveMessageL()
+/** Commits cached changes to the current message context to the storage controlled 
+by the Message Server. */
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(ESmtcMTMNoCMsvEntrySet));
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue, gPanic(ESmtcMTMNotAMessageEntry));
+	
+	StoreEmailMessageL();
+	}
+
+void CSmtpClientMtm::StoreEmailMessageL()
+	{
+	__ASSERT_DEBUG(KUidMsvMessageEntryValue==iMsvEntry->Entry().iType.iUid, gPanic(ESmtcMTMNotAMessageEntry));
+	CMsvStore* store = iMsvEntry->EditStoreL();
+	CleanupStack::PushL(store);
+
+	// Save the Email header stream...
+	iHeader->SetSubjectL(SubjectL());
+	const TInt numberOfRecipients=iAddresseeList->Count();
+	// put all addressees in the To: field...
+	for (TInt n=0 ; n < numberOfRecipients ; ++n)
+		{
+		// validation done by ValidateMessage()
+		switch(iAddresseeList->Type(n))
+			{
+		case EMsvRecipientTo:
+			iHeader->ToRecipients().AppendL(AddresseeList()[n]);
+			break;
+		case EMsvRecipientCc:
+			iHeader->CcRecipients().AppendL(AddresseeList()[n]);
+			break;
+		case EMsvRecipientBcc:
+			iHeader->BccRecipients().AppendL(AddresseeList()[n]);
+			break;
+			}
+		}
+
+	iHeader->StoreL(*store);
+	store->CommitL();
+
+	// NB the From field will be set by server MTM when the email message is sent
+
+	CleanupStack::PopAndDestroy();
+
+	TMsvEntry messageEntry=iMsvEntry->Entry();
+	CImEmailMessage* emailMessage = CImEmailMessage::NewLC(*iMsvEntry);
+
+	// now store the body text
+	emailMessage->StoreBodyTextL(messageEntry.Id(), Body(), iWait->iStatus);
+	iWait->Start();		// wait for the asynch operation to complete
+	
+	// 
+	// I have stored away all the email data,
+	// now update the TMsventry that represents
+	// the email to ensure that it is up to date
+	//
+	TInt32 totalSizeOfAllAttachments = GetAttachmentSizeL(*emailMessage, messageEntry.Id());
+
+	messageEntry.iSize = iHeader->DataSize() + Body().DocumentLength() + totalSizeOfAllAttachments;
+	messageEntry.iDescription.Set(iHeader->Subject());
+	messageEntry.iDate.UniversalTime();
+
+	// fix for DEF051564 - SMTP client MTM CreateMessageL not creating message in correct state
+	//
+	// since CreateMessageL creates message as in preparation and non-visible, the SaveMessageL
+	// must now make it visible and not in preparation
+	messageEntry.SetVisible(ETrue);
+	messageEntry.SetInPreparation(EFalse);
+
+	if (iHeader->ToRecipients().Count()>0)
+		messageEntry.iDetails.Set(iHeader->ToRecipients()[0]);
+	else if (iHeader->CcRecipients().Count())
+		messageEntry.iDetails.Set(iHeader->CcRecipients()[0]);
+	else if (iHeader->BccRecipients().Count())
+		messageEntry.iDetails.Set(iHeader->BccRecipients()[0]);
+	//else do nothing as there are no recipients yet!
+
+	if (totalSizeOfAllAttachments>0)
+		messageEntry.SetAttachment(ETrue);
+
+	// if there are multiple recipients then set the flag
+	if ((iHeader->ToRecipients().Count() + iHeader->CcRecipients().Count() + iHeader->BccRecipients().Count()) >=2)
+		messageEntry.SetMultipleRecipients(ETrue);
+
+	// update the contents of the message entry
+	iMsvEntry->ChangeL(messageEntry);
+
+	CleanupStack::PopAndDestroy();	// emailMessage
+	}
+
+EXPORT_C void CSmtpClientMtm::StoreSettingsL()
+/** Stores the current service settings from the object's cache in to the Central 
+Repository for the current entry.
+
+The current entry must be a service. */
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvServiceEntryValue, gPanic(ESmtcMTMNotAServiceEntry));
+
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+  	TSmtpAccount id;
+	account->GetSmtpAccountL(iMsvEntry->Entry().Id(), id);
+	account->SaveSmtpSettingsL(id, *iImSmtpSettings);
+	CleanupStack::PopAndDestroy(account);    
+	}
+
+EXPORT_C void CSmtpClientMtm::RestoreSettingsL()
+/** Loads into the object's cache the service settings from the Central Repository
+for the current entry. */
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvServiceEntryValue, gPanic(ESmtcMTMNotAServiceEntry));
+
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+  	TSmtpAccount id;
+	account->GetSmtpAccountL(iMsvEntry->Entry().Id(), id);
+	account->LoadSmtpSettingsL(id, *iImSmtpSettings);
+	CleanupStack::PopAndDestroy(account);    
+	}
+
+void CSmtpClientMtm::LoadMessageL()
+/** Loads the cache with the message data for the current context. */
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(ESmtcMTMNoCMsvEntrySet));
+	switch (iMsvEntry->Entry().iType.iUid)
+		{
+		case KUidMsvServiceEntryValue:
+			RestoreSettingsL();
+			break;
+		case KUidMsvMessageEntryValue:
+			RestoreEmailMessageL();
+			break;
+		};
+	}	
+
+void CSmtpClientMtm::RestoreEmailMessageL()
+	{
+
+	// Get a reference to TMsvEnhanceSearchSortUtil  instance set by CMsvSearchsortOpOnHeaderBody class
+	// If advanced search and sort is being performed than do not load the message header and body.
+	// These are loaded when the search criteria is known in DoFindL()
+	// For API's other than CMsvSearchsortOpOnHeaderBody-> FindInHeaderBodyL(), a call to LoadMessageL()
+	// loads the body and the header.
+
+	TMsvEnhanceSearchSortUtil* searchsortutil = (TMsvEnhanceSearchSortUtil*)(GetExtensionData());
+	if ( searchsortutil == NULL )
+		{
+		CMsvStore* msvStore = iMsvEntry->ReadStoreL();
+		CleanupStack::PushL(msvStore);
+
+		// message must have a CImHeader stream...if it's not there leave as there's something wrong
+		iHeader->RestoreL(*msvStore);
+
+		TPtrC subject = iHeader->Subject();
+		TPtrC to;
+		if (iHeader->ToRecipients().Count())
+			to.Set(iHeader->ToRecipients()[0]);
+		else if (iHeader->CcRecipients().Count())
+			to.Set(iHeader->CcRecipients()[0]);
+		else if (iHeader->BccRecipients().Count())
+			to.Set(iHeader->BccRecipients()[0]);
+	//else do nothing as there are no recipients!
+
+		SetSubjectL(subject);
+		SetAddresseeListL();
+
+		// Get the attachments and the body text...
+		TMsvEntry messageEntry=iMsvEntry->Entry();
+
+		CleanupStack::PopAndDestroy(); // msvStore
+		CImEmailMessage* emailMessage = CImEmailMessage::NewLC(*iMsvEntry);
+
+		GetBodyTextL(*emailMessage, messageEntry.Id());
+		TInt32 totalSizeOfAllAttachments = GetAttachmentSizeL(*emailMessage, messageEntry.Id());
+
+		messageEntry.iSize = iHeader->DataSize() + Body().DocumentLength() + totalSizeOfAllAttachments;
+		messageEntry.iDescription.Set(subject);
+		messageEntry.iDetails.Set(to);
+
+	// update the contents of the message entry
+		iMsvEntry->ChangeL(messageEntry);
+	
+		CleanupStack::PopAndDestroy(); // emailMessage
+	
+		}
+	}
+
+
+void CSmtpClientMtm::GetBodyTextL(CImEmailMessage& aMessage, TMsvId aMsvId)
+	{
+	CRichText* messageText = CRichText::NewL(iParaFormatLayer, iCharFormatLayer);
+	CleanupStack::PushL(messageText);
+
+	aMessage.GetBodyTextL(aMsvId, CImEmailMessage::EThisMessageOnly, *messageText,*iParaFormatLayer,*iCharFormatLayer);
+
+	Body().Reset();
+	Body().AppendTakingSolePictureOwnershipL(*messageText);
+
+	CleanupStack::PopAndDestroy();
+	}
+
+TInt32 CSmtpClientMtm::GetAttachmentSizeL(CImEmailMessage& aMessage, TMsvId aMsvId)
+	{
+	// Calculate the total size of all attachments associated with this message
+	TInt total=0;
+	aMessage.GetAttachmentsListL(iWait->iStatus, aMsvId, CImEmailMessage::EAllAttachments,CImEmailMessage::EThisMessageOnly);
+	iWait->Start();		// wait for the asynch operation to complete
+	TInt numAttachments=aMessage.AttachmentManager().AttachmentCount();
+	for (TInt n=0 ; n<numAttachments ; ++n)
+		{
+		CMsvAttachment* attachment = aMessage.AttachmentManager().GetAttachmentInfoL(n);
+		total+=attachment->Size();
+		delete attachment;
+		}
+	return total;
+	}
+
+CMsvOperation* CSmtpClientMtm::ReplyL(TMsvId aDestination, TMsvPartList aPartList, TRequestStatus& aCompletionStatus)
+/** Creates a reply message to the current message context. 
+
+@return	If successful, this is an asynchronously completing reply operation. 
+If failed, this is a completed operation, with status set to the relevant error code. 
+@param aDestination The entry to which to assign the reply 
+@param aPartList Defines the parts that are to be copied from the original message into the reply 
+@param aCompletionStatus The request status to be completed when the operation has finished 
+*/
+	{
+	TMsvEmailTypeList msvEmailTypeList = 0;
+	TUid messageType = KUidMsgTypeSMTP;
+	return CImEmailOperation::CreateReplyL(aCompletionStatus, Session(), iMsvEntry->EntryId(), aDestination, aPartList, msvEmailTypeList, messageType);
+	}
+
+CMsvOperation* CSmtpClientMtm::ForwardL(TMsvId aDestination, TMsvPartList aPartList, TRequestStatus& aCompletionStatus)
+/** Creates a forwarded message from the current message context. 
+
+@return	If successful, this is an asynchronously completing forward message operation. 
+If failed, this is a completed operation, with status set to the relevant error code. 		
+@param aDestination The entry to which to assign the forwarded message 
+@param aPartList Defines the parts that are to be copied from the original message into the forwarded message 
+@param aCompletionStatus The request status to be completed when the operation has finished 
+*/
+	{
+	TMsvEmailTypeList msvEmailTypeList = 0;
+	TUid messageType = KUidMsgTypeSMTP;
+	return CImEmailOperation::CreateForwardL(aCompletionStatus, Session(), iMsvEntry->EntryId(), aDestination, aPartList, msvEmailTypeList, messageType);
+	}
+
+EXPORT_C void CSmtpClientMtm::SetSubjectL(const TDesC& aSubject)
+/** Sets the message context's subject text.
+
+@param aSubject Subject text */
+	{
+	HBufC* newSubject= aSubject.AllocL();
+	delete iSubject;
+	iSubject = newSubject;	
+	}
+
+EXPORT_C const TPtrC CSmtpClientMtm::SubjectL() const
+/** Gets the message context's subject text.
+
+@return Subject text */
+	{
+	// NB won't ever leave
+	return (iSubject) ? TPtrC(*iSubject) : TPtrC();
+	}
+
+TMsvPartList CSmtpClientMtm::ValidateMessage(TMsvPartList aPartList)
+/** Validates the current message context.
+
+The addresses for the message are checked to be well-formed email addresses.
+
+@param aPartList Indicates the message parts for which validation is requested 
+@return If valid, KErrNone If invalid, identifies the invalid part(s). The 
+error value is the bitmask of the TMsvPartList IDs for each invalid part */
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(ESmtcMTMNoCMsvEntrySet));
+
+	TMsvPartList failed(0);
+	if (aPartList & KMsvMessagePartRecipient)
+		{
+		if (iAddresseeList->Count() == 0)
+			failed |= KMsvMessagePartRecipient;
+		else
+			{
+			// check the recipient list for valid 'addresses'
+			for (TInt ii=0; ii < iAddresseeList->Count(); ++ii)
+				{
+				if (((*iAddresseeList)[ii].Length() == 0) || !ValidateAddress((*iAddresseeList)[ii]))
+					{
+					failed |= KMsvMessagePartRecipient;
+					break;
+					}
+				}
+			}
+		}
+	return failed;
+	}
+
+TBool CSmtpClientMtm::ValidateAddress(const TPtrC& anAddress)
+	{
+	return iTImMessageField.ValidInternetEmailAddress(anAddress);
+	}
+
+TMsvPartList CSmtpClientMtm::DoFindL(const TDesC& aTextToFind, TMsvPartList aPartList)
+	{
+	CImClientMTMUtils* clientMTMUtils = CImClientMTMUtils::NewL();
+	CleanupStack::PushL(clientMTMUtils);
+
+	TMsvPartList retList = KMsvMessagePartNone;
+	
+	// Get a reference to TMsvEnhanceSearchSortUtil instance set by CMsvSearchsortOpOnHeaderBody class	
+	TMsvEnhanceSearchSortUtil* searchsortutil = (TMsvEnhanceSearchSortUtil*)(GetExtensionData());
+	
+	// searchsortuitl variable will not be NULL for Advanced Search and Sort called from CMsvSearchsortOpOnHeaderBody
+ 	// For the old implementation, it will be NULL
+	if(searchsortutil != NULL)
+		{
+		// Get the searchsort setting flags
+		TUint32 searchsortsetting=searchsortutil->GetSearchSortSetting();
+		
+		// The body was not loaded in LoadMessageL()
+ 		// If 2 search query options are on the body or on the header, than it sets EMessagePartBodyLoaded flag
+ 		// or EMessagePartHeaderLoaded of searchsortsetting
+		if(aPartList & KMsvMessagePartBody && !(searchsortsetting & EMessagePartBodyLoaded))  	
+   			{
+   			// Restore the body
+   			
+			Body().Reset();	
+			// Get the attachments and the body text...
+			TMsvEntry messageEntry=iMsvEntry->Entry();
+			CImEmailMessage* emailMessage = CImEmailMessage::NewLC(*iMsvEntry);
+			GetBodyTextL(*emailMessage, messageEntry.Id());
+			CleanupStack::PopAndDestroy(); // emailMessage
+			searchsortutil->SetSearchSortSetting(EMessagePartBodyLoaded);
+			}
+		else if (!(searchsortsetting & EMessagePartHeaderLoaded))
+			{
+			// Restore the header
+			CMsvStore* msvStore = iMsvEntry->ReadStoreL();
+			CleanupStack::PushL(msvStore);
+
+			// message must have a CImHeader stream...if it's not there leave as there's something wrong
+			iHeader->RestoreL(*msvStore);
+
+			TPtrC subject = iHeader->Subject();
+			TPtrC to;
+			if (iHeader->ToRecipients().Count())
+				to.Set(iHeader->ToRecipients()[0]);
+			else if (iHeader->CcRecipients().Count())
+				to.Set(iHeader->CcRecipients()[0]);
+			else if (iHeader->BccRecipients().Count())
+				to.Set(iHeader->BccRecipients()[0]);
+			//else do nothing as there are no recipients!
+
+			SetSubjectL(subject);
+			SetAddresseeListL();
+
+			// Get the attachments and the body text...
+			TMsvEntry messageEntry=iMsvEntry->Entry();
+
+			CleanupStack::PopAndDestroy(); // msvStore
+			searchsortutil->SetSearchSortSetting(EMessagePartHeaderLoaded);
+			}
+			
+		// Issue a request to FindL
+		clientMTMUtils->FindL(aTextToFind, Body(), *iHeader, aPartList, retList);
+		
+		/* Copy the sort data if sorting is specified.
+		 The operations being performed could be only be sort or it could be search and sort
+		 If the operation is search and sort than copy the sort data only if the
+		 search operation succeeded	*/
+		 
+		if ((searchsortsetting & EMessagePartSort ) || (((searchsortsetting & EMessagePartSearchSort) && (searchsortsetting & EMessagePartLastQueryOption) && (retList))))
+   			{
+   			/* Copy the data to be sorted from the header stream.
+   			   This done by setting iExtensionData to point to the field being copied */
+   			   
+	   		if (iHeader)
+   				{
+   				if (searchsortsetting & EMessagePartToSort )
+   					{
+   					SetExtensionData((TAny*)&iHeader->ToRecipients());
+	   				}
+   				else if(searchsortsetting & EMessagePartCcSort)
+   					{
+   					SetExtensionData((TAny*)&iHeader->CcRecipients());
+   					}
+   				else if(searchsortsetting & EMessagePartBccSort)
+ 	 	  			{
+    				SetExtensionData((TAny*)&iHeader->BccRecipients());
+    				}
+    			else if(searchsortsetting & EMessagePartFromSort)
+    				{
+    				SetExtensionData((TAny*)(iHeader->From().Ptr()));
+    				}
+				else if(searchsortsetting & EMessagePartSubjectSort)
+					{
+					SetExtensionData((TAny*)(iHeader->Subject().Ptr()));
+					}
+    			}
+   			}
+		}
+	else
+		{
+
+		clientMTMUtils->FindL(aTextToFind, Body(), *iHeader, aPartList, retList);	
+		}
+    CleanupStack::PopAndDestroy(clientMTMUtils); 
+	return retList;
+	}
+
+TMsvPartList CSmtpClientMtm::Find(const TDesC& aTextToFind, TMsvPartList aPartList)
+/** Searches the specified message part(s) for the plain-text version of the text 
+to be found.
+
+@param aTextToFind The plain-text version of the text to be found. 
+@param aPartList Indicates the message parts which should be searched. 
+@return If the text was not found, or searching is unsupported, 0. If the text 
+was found, a bitmask of the TMsvPartList IDs for each part in which the text 
+was present. */
+	{
+ 	TMsvPartList retList = KMsvMessagePartNone;
+ 	TRAPD(ret, retList = DoFindL(aTextToFind, aPartList));
+   	return retList;
+	}
+
+void CSmtpClientMtm::AddAddresseeL(const TDesC& aRealAddress)
+/** Adds an addressee for the current context.
+
+@param aRealAddress String representing an address to be added to the list 
+for the current message */
+	{
+	iAddresseeList->AppendL(EMsvRecipientTo, aRealAddress);
+	}
+
+void CSmtpClientMtm::SetAddresseeListL()
+	{
+	// fill in the addressee list from the contents of iHeader
+	// copy all of the recipient addresses into the addressee list
+
+	iAddresseeList->Reset();
+	TInt numberOfRecipients=iHeader->ToRecipients().Count();
+	TInt n;
+	for (n=0 ; n < numberOfRecipients ; ++n)
+		{
+		TPtrC addressWithoutAlias = iTImMessageField.GetValidInternetEmailAddressFromString(iHeader->ToRecipients()[n]);
+		AddAddresseeL(EMsvRecipientTo, addressWithoutAlias);
+		}
+
+	numberOfRecipients=iHeader->CcRecipients().Count();
+	for (n=0 ; n < numberOfRecipients ; ++n)
+		{
+		TPtrC addressWithoutAlias = iTImMessageField.GetValidInternetEmailAddressFromString(iHeader->CcRecipients()[n]);
+		AddAddresseeL(EMsvRecipientCc, addressWithoutAlias);
+		}
+
+	// there shouldn't be any Bcc: addresses in an incoming email
+	// but add them anyway?
+	numberOfRecipients=iHeader->BccRecipients().Count();
+	for (n=0 ; n < numberOfRecipients ; ++n)
+		{
+		TPtrC addressWithoutAlias = iTImMessageField.GetValidInternetEmailAddressFromString(iHeader->BccRecipients()[n]);
+		AddAddresseeL(EMsvRecipientBcc, addressWithoutAlias);
+		}
+	}
+
+void CSmtpClientMtm::AddAddresseeL(const TDesC& aRealAddress, const TDesC& aAlias)
+/** Adds an addressee with an alias for the current context.
+
+@param aRealAddress String representing an address to be added to the list 
+for the current message 
+@param aAlias Alias information */
+	{
+	HBufC* emailAddress = HBufC::NewLC(aRealAddress.Length()+aAlias.Length()+iEmailAddressFormatString->Length()-4);
+	emailAddress->Des().Format(*iEmailAddressFormatString,&aAlias,&aRealAddress);
+	iAddresseeList->AppendL(EMsvRecipientTo, *emailAddress);
+	CleanupStack::PopAndDestroy();	// emailAddress
+	}
+
+void CSmtpClientMtm::RemoveAddressee(TInt aIndex)
+/** Removes an address from the current address list.
+
+@param aIndex Index of address to be removed */
+	{
+	if (iAddresseeList->Count() > aIndex)
+		iAddresseeList->Delete(aIndex);
+	}
+
+void CSmtpClientMtm::AddAddresseeL(TMsvRecipientType aType, const TDesC& aRealAddress)
+	{
+	iAddresseeList->AppendL(aType, aRealAddress);
+	}
+
+void CSmtpClientMtm::AddAddresseeL(TMsvRecipientType aType, const TDesC& aRealAddress, const TDesC& aAlias)
+	{
+	HBufC* emailAddress = HBufC::NewLC(aRealAddress.Length()+aAlias.Length()+iEmailAddressFormatString->Length()-4);
+	emailAddress->Des().Format(*iEmailAddressFormatString,&aAlias,&aRealAddress);
+	iAddresseeList->AppendL(aType, *emailAddress);
+	CleanupStack::PopAndDestroy(emailAddress);
+	}
+	
+void CSmtpClientMtm::ContextEntrySwitched()
+	{
+	ResetData();
+	}
+
+TInt CSmtpClientMtm::QueryCapability(TUid aCapability, TInt& aResponse)
+/** Queries if the MTM supports a particular capability, specified by a UID.
+
+@param aCapability UID of capability to be queried 
+@param aResponse Response value. The format of the response varies according 
+to the capability. 
+@return KErrNone: aCapability is a recognised value and a response is returned 
+KErrNotSupported: aCapability is not a recognised value */
+	{
+	TInt error = KErrNone;
+	switch (aCapability.iUid)
+		{
+	// Supported:
+	case KUidMtmQueryMaxBodySizeValue:
+	case KUidMtmQueryMaxTotalMsgSizeValue:
+		aResponse = KMaxTInt;
+		break;
+	case KUidMsvMtmQueryEditorUidValue:
+		aResponse = KUidMsgInternetMailEditorDLL;
+		break;
+	case KUidMtmQuerySupportedBodyValue:
+		aResponse = KMtm7BitBody + KMtm8BitBody + KMtm16BitBody + KMtmBinaryBody;
+		break;
+	case KUidMtmQuerySupportSubjectValue:
+	case KUidMtmQuerySupportAttachmentsValue:
+	case KUidMtmQueryCanSendMsgValue:
+	case KUidMtmQuerySupportsRecipientTypeValue:
+	case KUidMtmQuerySendAsMessageSendSupportValue:
+		break;
+	// All others - Not Supported:
+	default:
+		error = KErrNotSupported;
+		}
+	return error;
+	}
+
+EXPORT_C void CSmtpClientMtm::SetSettingsL(const CImSmtpSettings& aSettings)
+/** Copies the specified service settings to the cached service settings.
+
+@param aSettings New service settings */
+	{
+	iImSmtpSettings->CopyL(aSettings);
+	}
+
+EXPORT_C const CImSmtpSettings& CSmtpClientMtm::Settings() const
+/** Gets the current cached service settings.
+
+@return The current cached service settings */
+	{
+	__ASSERT_DEBUG(iImSmtpSettings!=NULL, User::Invariant());
+	return *iImSmtpSettings;
+	}
+
+void CSmtpClientMtm::InvokeSyncFunctionL(TInt aFunctionId, const CMsvEntrySelection& aSelection, TDes8& aParameter)
+/** Invokes a synchronous SMTP-specific operation.
+
+@param aFunctionId Specifies which operation to perform. The only valid ID is KSMTPMTMIsConnected.
+@param aSelection A selection of messages for the operation.
+@param aParameter Not used
+*/
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(ESmtcMTMNoCMsvEntrySet));
+
+	TInt error = KErrNone;
+	switch (aFunctionId)
+		{
+		case KSMTPMTMIsConnected:
+			{
+			TPckgBuf<TImSmtpProgress> progress;
+			Session().TransferCommandL(aSelection, KSMTPMTMIsConnected, aParameter, progress);
+			aParameter.Copy(progress);
+			return;
+			}
+		default:
+			error=KErrNotSupported;
+			__ASSERT_DEBUG(EFalse,gPanic(ESmtcUnknownSyncFunction));
+		}
+
+	User::LeaveIfError(error);
+	}
+
+CMsvOperation* CSmtpClientMtm::InvokeAsyncFunctionL(TInt aFunctionId, const CMsvEntrySelection& aSelection,
+													TDes8& aParameter, TRequestStatus& aCompletionStatus)
+/** Invokes asynchronous SMTP-specific operations.
+
+@param aFunctionId Specifies which operation to perform e.g. connect, copy 
+new mail etc. The specific operations are defined by the TSmtpCmds enumeration. 
+@param aSelection A selection of messages that need to be copied/moved to a 
+local folder. The first entry in this selection MUST be the service. 
+@param aParameter Not used
+@param aCompletionStatus The status when the operation completes. 
+@leave KErrNotFound The selection of email to be moved or copied is empty
+@leave KErrNotSupported The specified operation is not recognised
+@return If successful, this is an asynchronously completing operation. If failed, 
+this is a completed operation, with status set to the relevant error code. 
+@see TSmtpCmds */
+	{
+	switch(aFunctionId)
+		{
+	case KMTMStandardFunctionsSendMessage:
+		return CMsvSmtpProgressOperation::NewL(Session(), aSelection, KSMTPMTMSendOnNextConnection, aParameter, aCompletionStatus);
+	case KSMTPMTMSendOnNextConnection:
+		return (Session().TransferCommandL(aSelection, aFunctionId, aParameter, aCompletionStatus));
+	case KSMTPMTMCreateNewEmailMessage:
+	case KSMTPMTMCreateReplyEmailMessage:
+	case KSMTPMTMCreateForwardEmailMessage:
+	case KSMTPMTMCreateForwardAsAttachmentEmailMessage:
+	case KSMTPMTMCreateReceiptEmailMessage:
+		{
+		TImCreateMessageOptions createMessageOptions;	
+		TPckgC<TImCreateMessageOptions> paramPack(createMessageOptions);
+		paramPack.Set(aParameter);
+		switch (aFunctionId)
+			{
+		case KSMTPMTMCreateNewEmailMessage:
+			return iImEmailOperation->CreateNewL(aCompletionStatus, iMsvEntry->Session(), aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KSMTPMTMCreateReplyEmailMessage:
+			return iImEmailOperation->CreateReplyL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KSMTPMTMCreateForwardEmailMessage:
+			return iImEmailOperation->CreateForwardL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KSMTPMTMCreateForwardAsAttachmentEmailMessage:
+			return iImEmailOperation->CreateForwardAsAttachmentL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KSMTPMTMCreateReceiptEmailMessage:
+			return iImEmailOperation->CreateReceiptL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+			}
+		}
+	break;
+	default:
+		User::Leave(KErrNotSupported);
+		};
+	return NULL;
+	}
+
+// Attachment functions to support the SendAs API
+
+EXPORT_C void CSmtpClientMtm::AddAttachmentL(const TDesC& aFilePath, const TDesC8& aMimeType, TUint aCharset, TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue, gPanic(ESmtcMTMNotAMessageEntry));
+
+	if( iAttachmentWaiter == NULL )
+		{
+		iAttachmentWaiter = CImAttachmentWaiter::NewL();
+		}	
+
+	if (iEmailMessage == NULL)
+		{		
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	else if (iEmailMessage->EmailEntryId() != iMsvEntry->EntryId())
+		{
+		delete iEmailMessage;
+		iEmailMessage = NULL;
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+
+	CMsvAttachment* attachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	CleanupStack::PushL(attachmentInfo);
+	
+	attachmentInfo->SetMimeTypeL(aMimeType);
+	TParse fileNameParser;
+	User::LeaveIfError(fileNameParser.Set(aFilePath, NULL, NULL));
+	attachmentInfo->SetAttachmentNameL(fileNameParser.NameAndExt());
+	if( aCharset!=0 )
+		{
+		CMsvMimeHeaders* headers = CMsvMimeHeaders::NewLC();
+		headers->SetMimeCharset(aCharset);
+		headers->StoreL(*attachmentInfo);
+		CleanupStack::PopAndDestroy(headers);
+		}
+
+	iEmailMessage->AttachmentManager().AddAttachmentL(aFilePath, attachmentInfo, iAttachmentWaiter->iStatus);
+	CleanupStack::Pop(attachmentInfo);// ownership passed to attachment manager
+	
+	iAttachmentWaiter->StartWaitingL(aStatus, iEmailMessage, EFalse);
+	}
+	
+EXPORT_C void CSmtpClientMtm::AddAttachmentL(RFile& aFile, const TDesC8& aMimeType, TUint aCharset, TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue, gPanic(ESmtcMTMNotAMessageEntry));
+
+	if( iAttachmentWaiter == NULL )
+		{
+		iAttachmentWaiter = CImAttachmentWaiter::NewL();
+		}
+	
+	if (iEmailMessage == NULL)
+		{		
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	else if (iEmailMessage->EmailEntryId() != iMsvEntry->EntryId())
+		{
+		delete iEmailMessage;
+		iEmailMessage = NULL;
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+
+	CMsvAttachment* attachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	CleanupStack::PushL(attachmentInfo);
+	
+	attachmentInfo->SetMimeTypeL(aMimeType);
+	TFileName fileName;	
+	aFile.Name(fileName);
+	attachmentInfo->SetAttachmentNameL(fileName);
+	if( aCharset!=0 )
+		{
+		CMsvMimeHeaders* headers = CMsvMimeHeaders::NewLC();
+		headers->SetMimeCharset(aCharset);
+		headers->StoreL(*attachmentInfo);
+		CleanupStack::PopAndDestroy(headers);
+		}
+	
+	iEmailMessage->AttachmentManager().AddAttachmentL(aFile, attachmentInfo, iAttachmentWaiter->iStatus);
+	CleanupStack::Pop(attachmentInfo);// ownership passed to attachment manager	
+
+	iAttachmentWaiter->StartWaitingL(aStatus, iEmailMessage, EFalse);
+	}
+	
+EXPORT_C void CSmtpClientMtm::AddLinkedAttachmentL(const TDesC& aFilePath, const TDesC8& aMimeType, TUint aCharset, TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue, gPanic(ESmtcMTMNotAMessageEntry));
+
+	if( iAttachmentWaiter == NULL )
+		{
+		iAttachmentWaiter = CImAttachmentWaiter::NewL();
+		}
+
+	if (iEmailMessage == NULL)
+		{		
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	else if (iEmailMessage->EmailEntryId() != iMsvEntry->EntryId())
+		{
+		delete iEmailMessage;
+		iEmailMessage = NULL;
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	
+	CMsvAttachment* attachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvLinkedFile);
+	CleanupStack::PushL(attachmentInfo);
+	
+	attachmentInfo->SetMimeTypeL(aMimeType);
+	
+	TParse fileNameParser;
+	User::LeaveIfError(fileNameParser.Set(aFilePath, NULL, NULL));
+	attachmentInfo->SetAttachmentNameL(fileNameParser.NameAndExt());
+
+	if( aCharset!=0 )
+		{
+		CMsvMimeHeaders* headers = CMsvMimeHeaders::NewLC();
+		headers->SetMimeCharset(aCharset);
+		headers->StoreL(*attachmentInfo);
+		CleanupStack::PopAndDestroy(headers);
+		}
+	
+	iEmailMessage->AttachmentManager().AddLinkedAttachmentL(aFilePath, attachmentInfo, iAttachmentWaiter->iStatus);
+	CleanupStack::Pop(attachmentInfo);// ownership passed to attachment manager	
+
+	iAttachmentWaiter->StartWaitingL(aStatus, iEmailMessage, EFalse);
+	}
+	
+EXPORT_C void CSmtpClientMtm::AddEntryAsAttachmentL(TMsvId aAttachmentId, TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue, gPanic(ESmtcMTMNotAMessageEntry));
+
+	if( iAttachmentWaiter == NULL )
+		{
+		iAttachmentWaiter = CImAttachmentWaiter::NewL();
+		}
+
+	if (iEmailMessage == NULL)
+		{		
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	else if (iEmailMessage->EmailEntryId() != iMsvEntry->EntryId())
+		{
+		delete iEmailMessage;
+		iEmailMessage = NULL;
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	
+	CMsvAttachment* attachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvMessageEntry);
+	CleanupStack::PushL(attachmentInfo);
+
+	iEmailMessage->AttachmentManager().AddEntryAsAttachmentL(aAttachmentId, attachmentInfo, iAttachmentWaiter->iStatus);
+	CleanupStack::Pop(attachmentInfo);// ownership passed to attachment manager	
+	
+	iAttachmentWaiter->StartWaitingL(aStatus, iEmailMessage, EFalse);
+	}
+
+EXPORT_C void CSmtpClientMtm::CreateAttachmentL(const TDesC& aFileName, RFile& aAttachmentFile, const TDesC8& aMimeType, TUint aCharset, TRequestStatus& aStatus)
+	{
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue, gPanic(ESmtcMTMNotAMessageEntry));
+	
+	if( iAttachmentWaiter == NULL )
+		{
+		iAttachmentWaiter = CImAttachmentWaiter::NewL();
+		}
+
+	if (iEmailMessage == NULL)
+		{		
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+	else if (iEmailMessage->EmailEntryId() != iMsvEntry->EntryId())
+		{
+		delete iEmailMessage;
+		iEmailMessage = NULL;
+		iEmailMessage = CImEmailMessage::NewL(*iMsvEntry);
+		}
+
+	CMsvAttachment* attachmentInfo = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	CleanupStack::PushL(attachmentInfo);
+
+	attachmentInfo->SetAttachmentNameL(aFileName);
+	attachmentInfo->SetMimeTypeL(aMimeType);
+	
+	if( aCharset!=0 )
+		{
+		CMsvMimeHeaders* headers = CMsvMimeHeaders::NewLC();
+		headers->SetMimeCharset(aCharset);
+		headers->StoreL(*attachmentInfo);
+		CleanupStack::PopAndDestroy(headers);
+		}
+
+	iEmailMessage->AttachmentManager().CreateAttachmentL(aFileName, aAttachmentFile, attachmentInfo, iAttachmentWaiter->iStatus);
+	CleanupStack::Pop(attachmentInfo);// ownership passed to attachment manager	
+	
+	iAttachmentWaiter->StartWaitingL(aStatus, iEmailMessage, EFalse);
+	}
+
+
+EXPORT_C void CSmtpClientMtm::CreateMessageL(TMsvId aServiceId)
+/** Creates a new message entry as a child of the current context.
+
+@param aServiceId ID of the service to own the entry. */
+	{
+	// fix for DEF051564 - SMTP client MTM CreateMessageL not creating message in correct state
+	TMsvEmailTypeList emailTypeList = KMsvEmailTypeListInvisibleMessage | KMsvEmailTypeListMessageInPreparation;
+
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+	
+	CImSmtpSettings* smtpSettings = new (ELeave) CImSmtpSettings;
+	CleanupStack::PushL(smtpSettings);
+  	TSmtpAccount id;
+	account->GetSmtpAccountL(aServiceId, id);
+	account->LoadSmtpSettingsL(id, *smtpSettings);
+	
+	switch (smtpSettings->BodyEncoding())
+		{
+		case EMsgOutboxMHTMLAsMIME:
+		case EMsgOutboxMHTMLAlternativeAsMIME:
+			emailTypeList |= KMsvEmailTypeListMHTMLMessage;
+			break;
+		case EMsgOutboxDefault:
+		case EMsgOutboxNoAlgorithm:
+		case EMsgOutboxMIME:
+			break;
+		}
+	CleanupStack::PopAndDestroy(2, account); // smtpSettings, account
+	
+	// Now invoke the create new mail operation.
+	// Note that it is wrapped up to make the asynchronous call synchronous.
+	CMsvOperationActiveSchedulerWait* waiter=CMsvOperationActiveSchedulerWait::NewLC();
+	CImEmailOperation* createNewMailOp = CImEmailOperation::CreateNewL(waiter->iStatus, iMsvEntry->Session(), iMsvEntry->Entry().Id(), aServiceId, KMsvMessagePartBody|KMsvMessagePartAttachments, emailTypeList, KUidMsgTypeSMTP);
+	CleanupStack::PushL(createNewMailOp);
+	waiter->Start();
+
+	// The the entry is expected to be set to the new message.
+	TMsvId temp;	
+	TPckgC<TMsvId> paramPack(temp);
+	const TDesC8& progBuf = createNewMailOp->ProgressL();	
+	paramPack.Set(progBuf);
+	TMsvId messageId = paramPack();
+	iMsvEntry->SetEntryL(messageId);
+	
+	CMsvStore* store = iMsvEntry->ReadStoreL();
+	CleanupStack::PushL(store);
+	iHeader->RestoreL(*store);
+
+	CleanupStack::PopAndDestroy(3, waiter); // waiter, createNewMailOp, store	
+	}
+	
+/**
+Gets the default SMTP service.
+
+@return
+The default service
+
+@leave 
+KErrNotFound If default service setting does not exist.
+*/
+EXPORT_C TMsvId CSmtpClientMtm::DefaultServiceL() const
+	{
+	// Get default service Id from CenRep
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+	TSmtpAccount id;
+	TInt error = account->DefaultSmtpAccountL(id);
+	if (error == KErrNotFound)
+		{
+		User::Leave(error);
+		}
+	
+	CleanupStack::PopAndDestroy(account); 	   
+	return id.iSmtpService;		
+	}
+
+/**
+Removes the default SMTP service.
+*/		
+EXPORT_C void CSmtpClientMtm::RemoveDefaultServiceL()
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+/**
+Sets the default SMTP service.
+
+@param	aService
+The default service
+*/		
+EXPORT_C void CSmtpClientMtm::ChangeDefaultServiceL(const TMsvId& aService)
+	{
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+	TSmtpAccount id;
+	account->GetSmtpAccountL(aService, id);
+	account->SetDefaultSmtpAccountL(id);
+	CleanupStack::PopAndDestroy(account); 	   		
+	}
+	
+/**
+Cancels the current attachment operation.
+*/	
+EXPORT_C void CSmtpClientMtm::CancelAttachmentOperation()
+	{
+ 	if ( iAttachmentWaiter)
+		 {
+		 iAttachmentWaiter->Cancel();
+		 }
+
+	if ( iWait )
+		 {
+		 iWait->Cancel();
+		 }
+	}
+