email/pop3andsmtpmtm/clientmtms/src/IMPCMTM.CPP
changeset 0 72b543305e3a
child 76 60a8a215b0ec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/clientmtms/src/IMPCMTM.CPP	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1901 @@
+// 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:
+// IMAP4MTM.CPP
+// 
+//
+
+#include "IMPCMTM.H"
+#include "MIUT_ERR.H"
+
+#include <barsc.h>		//RResourceFile
+#include <barsread.h>
+#include <bautils.h>
+#include <txtrich.h>
+#include <msvutils.h>
+#include <cemailaccounts.h>
+
+#include "MIUTMSG.H"	//CImEmailOperation
+#include "CONSYNC.H"
+#include <imcm.rsg>
+#include "IMCMUTIL.H"
+#include <e32base.h>
+#include <autosend.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
+#include "miut_errconsts.h"
+#include "cimmessagepart.h"
+#include "timrfc822datefield.h"
+#include <mtmuidsdef.hrh>
+#endif
+
+#include <msvenhancesearchsortutil.h>
+
+_LIT(KMsvAutoSendExe, "Autosend.exe");
+const TUid KMsvAutoSendExeUid = {0x1000A402}; //268477442
+
+#define TODO//@
+
+
+//
+//  Session Observer for the Imap4 Client MTM  
+class CImap4ClientSessionObserver : public CBase , public MMsvSessionObserver
+	{
+public:
+	void HandleSessionEventL(TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3);
+	};
+
+void CImap4ClientSessionObserver::HandleSessionEventL(TMsvSessionEvent /*aEvent*/, TAny* /*aArg1*/, TAny* /*aArg2*/, TAny* /*aArg3*/)
+	{
+	}
+
+
+//
+//  CImap4ClientMtm methods.
+
+
+/**
+@internalTechnology
+*/
+/** IMAP4 client MTM factory function.
+
+This function is not called directly by messaging clients. To create a client MTM
+object, use CClientMtmRegistry::NewMtmL().
+
+@param aRegisteredMtmDll MTM registry information 
+@param aSession Message server session
+@return New IMAP4 client MTM object
+@see CClientMtmRegistry::NewMtmL()
+*/
+EXPORT_C CImap4ClientMtm* CImap4ClientMtm::NewL(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aSession)
+	{
+	CImap4ClientMtm* self = new (ELeave) CImap4ClientMtm(aRegisteredMtmDll, aSession);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CImap4ClientMtm::CImap4ClientMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aSession)
+: CBaseMtm(aRegisteredMtmDll, aSession)
+	{
+	}
+
+void CImap4ClientMtm::ConstructL()
+	{
+	iImap4ClientSessionObserver = new (ELeave) CImap4ClientSessionObserver;
+	iHeader = CImHeader::NewLC();
+	CleanupStack::Pop();	// iHeader
+
+	//open the resource file
+	RFs fs;
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+	//	Need to search for IMCM resource file on all drives -
+	//	it won't necessarily be on the same one as IMPC.DLL
+	//
+	TFileName fileName(KImEngineResourceFile);
+	MsvUtils::AddPathAndExtensionToResFileL(fileName);
+	BaflUtils::NearestLanguageFile( fs, fileName );		//	change to appropriate language
+
+	RResourceFile resourceFile;
+	resourceFile.OpenL(fs,fileName);
+	CleanupClosePushL(resourceFile);
+	HBufC8* buf = resourceFile.AllocReadLC(EMAIL_ADDRESS_FORMATTING_STRING);
+	TResourceReader reader;
+	reader.SetBuffer(buf);
+	iEmailAddressFormatString = (reader.ReadTPtrC()).AllocL();
+	CleanupStack::PopAndDestroy(3);// resourceFile (Close resourceFile), fs
+	}
+
+CImap4ClientMtm::~CImap4ClientMtm()
+/** Destructor. */
+	{
+	delete iImap4ClientSessionObserver;
+	delete iEmailAddressFormatString;
+	delete iHeader;
+	delete iMsvEntrySelection;
+	delete iImIMAP4GetMail;
+	delete iImEmailOperation;
+	}
+
+void CImap4ClientMtm::SaveMessageL()
+/** Empty implementation of base class function. 
+
+To edit an IMAP message, use CImEmailMessage.
+*/
+	{
+	}
+
+EXPORT_C void CImap4ClientMtm::StoreSettingsL()
+/** If the current context of the client MTM is an IMAP4 service, stores settings 
+in the Central Repository. 
+
+@panic IMCM 33 MTM has no current context (debug builds only)
+@panic IMCM 44 Current context is not a service (debug builds only)
+*/
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EImpcNoCMsvEntrySet));
+
+	// check that current context is a service entry
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType==KUidMsvServiceEntry,gPanic(EImpcMTMNotAServiceEntry));
+
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+  	TImapAccount id;
+	account->GetImapAccountL(iMsvEntry->Entry().Id(), id);
+	account->SaveImapSettingsL(id, iImImap4Settings);
+	CleanupStack::PopAndDestroy(account);    
+	}
+
+void CImap4ClientMtm::LoadMessageL()
+/** Loads the cache with the message data for the current message context. 
+
+The current context should be an IMAP service or a message. 
+If the current context is an IMAP service, then the function loads the service settings
+from the Central Repository. This is the same behaviour as RestoreSettingsL().
+*/
+	{
+	Body().Reset();
+	iHeader->Reset();
+	switch (iMsvEntry->Entry().iType.iUid)
+		{
+		case KUidMsvServiceEntryValue:
+			RestoreSettingsL();
+			break;
+		case KUidMsvMessageEntryValue:
+			{//restore header
+			if (!iMsvEntry->HasStoreL())
+				return;
+		
+				
+			// 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);
+				iHeader->RestoreL(*msvStore);
+				CleanupStack::PopAndDestroy();//store
+				CImEmailMessage* message=CImEmailMessage::NewLC(*iMsvEntry);
+				message->GetBodyTextL(iMsvEntry->Entry().Id(),CImEmailMessage::EThisMessageOnly,Body(),*iParaFormatLayer,*iCharFormatLayer);
+				CleanupStack::PopAndDestroy();//message	
+				break;
+				}
+			}
+		};
+	}
+
+EXPORT_C void CImap4ClientMtm::RestoreSettingsL()
+/** If the current context of the client MTM is on an IMAP4 service, restores settings 
+from the Central Repository. 
+
+The restored settings can be accessed through the Imap4Settings() function.
+
+@panic IMCM 33 MTM has no current context (debug builds only)
+*/
+    {
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EImpcNoCMsvEntrySet));
+
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+  	TImapAccount id;
+	account->GetImapAccountL(iMsvEntry->Entry().Id(), id);
+	account->LoadImapSettingsL(id, iImImap4Settings);
+	CleanupStack::PopAndDestroy(account);    
+	}
+
+CMsvOperation* CImap4ClientMtm::ReplyL(TMsvId aDestination, TMsvPartList aPartList, TRequestStatus& aCompletionStatus)
+/** Creates an SMTP reply message to the current message context.
+
+@param aDestination 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.
+@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. */
+	{
+	TMsvEmailTypeList msvEmailTypeList = 0;
+	TUid messageType = KUidMsgTypeSMTP;
+	return CImEmailOperation::CreateReplyL(aCompletionStatus, Session(), iMsvEntry->EntryId(), aDestination, aPartList, msvEmailTypeList, messageType);
+	}
+
+CMsvOperation* CImap4ClientMtm::ForwardL(TMsvId aDestination, TMsvPartList aPartList, TRequestStatus& aCompletionStatus)
+/** Creates an forwarded SMTP message from the current message context. 
+
+@param aDestination 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.
+@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. */
+	{
+	TMsvEmailTypeList msvEmailTypeList = 0;
+	TUid messageType = KUidMsgTypeSMTP;
+	return CImEmailOperation::CreateForwardL(aCompletionStatus, Session(), iMsvEntry->EntryId(), aDestination, aPartList, msvEmailTypeList, messageType);
+   }
+
+TUint CImap4ClientMtm::ValidateMessage(TUint aPartList)
+/** Validates the current message context.
+
+Only the message recipients and sender fields are checked for well-formed 
+addresses.
+
+@param aPartList Indicates the value of the message parts for which validation 
+is requested.
+@return Values of message parts. 
+
+@panic IMCM 33 MTM has no current context (debug builds only)
+*/
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EImpcNoCMsvEntrySet));
+	TBool retVal=0;
+	if (aPartList & KMsvMessagePartRecipient)
+		{
+		TBool valid = ETrue;
+		// check the recipient list for valid 'addresses' - ie no digits
+		for (TInt ii=0; ii < AddresseeList().Count(); ++ii)
+			if ( (valid = ValidateAddress((*iAddresseeList)[ii])) == EFalse)
+				continue;
+		retVal += (valid ? 0 : KMsvMessagePartRecipient);
+		}
+	if (aPartList & KMsvMessagePartOriginator)
+		{
+		// check the originator field for valid 'addresses' - ie no digits
+		if (!ValidateAddress(iMsvEntry->Entry().iDetails))
+			retVal += KMsvMessagePartOriginator;
+		}
+	return retVal;
+	}
+
+TBool CImap4ClientMtm::ValidateAddress(const TPtrC& anAddress)
+	{
+	return iTImMessageField.ValidInternetEmailAddress(anAddress);
+	}
+
+void CImap4ClientMtm::SendOnNextConnectionL()
+	{
+	TMsvId smtpServiceId = KMsvNullIndexEntryId;
+	TMsvId entry = iMsvEntry->Entry().Id();
+	if (iMsvEntry->Entry().iType.iUid==KUidMsvServiceEntryValue)
+		smtpServiceId = iMsvEntry->Entry().iRelatedId;
+	else if (iMsvEntry->Entry().iType.iUid==KUidMsvMessageEntryValue)
+		{
+		TMsvId id=iMsvEntry->Entry().iServiceId;
+		iMsvEntry->SetEntryL(iMsvEntry->Entry().iServiceId);		
+		smtpServiceId = iMsvEntry->Entry().iRelatedId;
+		iMsvEntry->SetEntryL(id);		
+		}
+
+	iMsvEntry->SetEntryL(KMsvGlobalOutBoxIndexEntryId);
+	CMsvEntrySelection* sel = iMsvEntry->ChildrenWithMtmL(KUidMsgTypeSMTP);
+	CleanupStack::PushL(sel);
+
+	// there is no need to start the autosend operation if there are no SMTP messages
+	// in the outbox
+
+	if(sel->Count())
+		{
+		TBuf<20> cmdString;
+		cmdString.Num(smtpServiceId, EDecimal);
+			RProcess p;
+			TInt error=p.Create(KMsvAutoSendExe, cmdString, TUidType(KNullUid, KNullUid, KMsvAutoSendExeUid));
+			if (error==KErrNone)
+				{
+				p.Resume();
+				p.Close();
+				}
+		}
+	CleanupStack::PopAndDestroy(sel);
+	iMsvEntry->SetEntryL(entry);
+	}
+
+TMsvPartList CImap4ClientMtm::DoFindL(const TDesC& aTextToFind, TMsvPartList aPartList)
+	{ 
+	CImClientMTMUtils* clientMTMUtils = CImClientMTMUtils::NewL();
+	CleanupStack::PushL(clientMTMUtils);
+
+	TMsvPartList retList = KMsvMessagePartNone;
+	CMsvFindText* findText = CMsvFindText::NewLC();
+ 
+  	
+	// Get a reference to TMsvEnhanceSearchSortUtil  instance set by CMsvSearchsortOpOnHeaderBody class
+		
+	TMsvEnhanceSearchSortUtil* searchsortutil = (TMsvEnhanceSearchSortUtil*)(GetExtensionData());
+	
+	if( searchsortutil != NULL )
+ 		{
+ 		// Get Advanced search sort setting flag
+ 		TInt32 searchsortsetting=searchsortutil->GetSearchSortSetting();
+ 		
+ 		/* If the search is on message body than Load message Body 
+ 		 If the search is on message header than Load the message header
+ 		 Also set searchsortsetting flag EMessagePartBodyLoaded or EMessagePartHeaderLoaded 
+ 		 in TMsvEnhanceSearchSortUtil class
+ 		 This ensures that the body or header is not loaded twice if 2 query options
+ 		 are on the body */
+ 		
+ 		if(aPartList & KMsvMessagePartBody && !(searchsortsetting & EMessagePartBodyLoaded))  	
+   			{
+   			CImEmailMessage* message=CImEmailMessage::NewLC(*iMsvEntry);
+			message->GetBodyTextL(iMsvEntry->Entry().Id(),CImEmailMessage::EThisMessageOnly,Body(),*iParaFormatLayer,*iCharFormatLayer);
+			CleanupStack::PopAndDestroy();//message
+			searchsortutil->SetSearchSortSetting(EMessagePartBodyLoaded);
+   			}
+   		else if(!(searchsortsetting & EMessagePartHeaderLoaded))
+   			{
+   			// Load the header
+			CMsvStore* msvStore = iMsvEntry->ReadStoreL();
+			CleanupStack::PushL(msvStore);
+			iHeader->RestoreL(*msvStore);
+			CleanupStack::PopAndDestroy();//store
+			searchsortutil->SetSearchSortSetting(EMessagePartHeaderLoaded);	
+   			}
+   			
+   		// Issue the Find request
+		clientMTMUtils->FindL(aTextToFind, Body(), *iHeader, aPartList, retList);
+		
+		/* If the search didn't succeed, than search in the details field of TMsvEntry class. It holds the From field
+		   If the search is on subject, than look in description field of TMsvEntry class.	*/
+		   
+		if(!retList)
+			{
+			if (aPartList & KMsvMessagePartFrom)
+				{
+				findText->FindTextL(aTextToFind, iMsvEntry->Entry().iDetails, aPartList) ? retList|=KMsvMessagePartOriginator : retList;	
+				}
+ 			if (aPartList & KMsvMessagePartSubject)
+ 				{
+ 				findText->FindTextL(aTextToFind, iMsvEntry->Entry().iDescription, aPartList) ? retList|=KMsvMessagePartDescription : 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 // Header not present. Copy sort data from TMsvEntry details and description field
+   	   			{
+	   		    if(searchsortsetting & EMessagePartFromSort)
+	   		    	{
+	   		    	SetExtensionData((TAny*)&iMsvEntry->Entry().iDetails);	
+	   		    	}
+	  			else if(searchsortsetting & EMessagePartSubjectSort)
+   					{
+   					SetExtensionData((TAny*)&iMsvEntry->Entry().iDescription);		
+   					}
+   	   			}
+   			}
+ 		}
+	else
+		{
+
+		// Old implementation for searching
+		clientMTMUtils->FindL(aTextToFind, Body(), *iHeader, aPartList, retList);
+		
+		if(!retList)
+			{
+			if (aPartList & KMsvMessagePartOriginator)
+				{
+				findText->FindTextL(aTextToFind, iMsvEntry->Entry().iDetails, aPartList) ? retList|=KMsvMessagePartOriginator : retList;	
+				}
+ 			if (aPartList & KMsvMessagePartDescription)
+ 				{
+ 				findText->FindTextL(aTextToFind, iMsvEntry->Entry().iDescription, aPartList) ? retList|=KMsvMessagePartDescription : retList;	
+ 				}
+			}
+		}
+	CleanupStack::PopAndDestroy(findText);
+	CleanupStack::PopAndDestroy(clientMTMUtils); 
+	return retList;
+	}
+
+TMsvPartList CImap4ClientMtm::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;
+	}
+
+TInt CImap4ClientMtm::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. See MTMDEF.HRH for 
+definition of UIDs. 
+@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;
+   const TInt KImap4MaxTextMessageSize = 0xFFFF;
+	switch (aCapability.iUid)
+		{
+	case KUidMtmQueryMaxBodySizeValue:
+	case KUidMtmQueryMaxTotalMsgSizeValue:
+		aResponse = KImap4MaxTextMessageSize;
+		break;
+	case KUidMtmQuerySupportedBodyValue:
+		aResponse = KMtm7BitBody + KMtm8BitBody + KMtm16BitBody + KMtmBinaryBody;
+		break;
+   // Supported
+	case KUidMtmQueryCanReceiveMsgValue:		
+   case KUidMtmQuerySupportAttachmentsValue:
+   case KUidMtmQuerySupportsFolderValue:
+		break;
+	// Not supported
+	case KUidMtmQueryOffLineAllowedValue:	
+	case KUidMtmQueryCanSendMsgValue:		
+	default:
+		aResponse = ETrue;
+		return KErrNotSupported;
+		}
+	return error;
+	}
+
+void CImap4ClientMtm::InvokeSyncFunctionL(TInt aFunctionId, const CMsvEntrySelection& aSelection, TDes8& aParameter)
+/** Invokes synchronous IMAP-specific operations.
+
+@param aFunctionId ID of the requested function. Supported IDs are #KIMAP4MTMIsConnected and #KIMAP4MTMBusy.
+@param aSelection Collection of function entries to invoke.
+@param aParameter Buffer containing input and output parameters. 
+
+@panic IMCM 33 MTM has no current context (debug builds only)
+@leave KErrNotSupported Function does not provide function specified by aFunctionId
+@see #KIMAP4MTMIsConnected 
+@see #KIMAP4MTMBusy
+*/
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EImpcNoCMsvEntrySet));
+	TInt error = KErrNone;
+	switch (aFunctionId)
+		{
+	case KIMAP4MTMIsConnected:
+   case KIMAP4MTMBusy:
+		{
+		CMsvOperationActiveSchedulerWait *wait = CMsvOperationActiveSchedulerWait::NewLC();
+		CMsvOperation* operation = Session().TransferCommandL(aSelection, aFunctionId, aParameter, wait->iStatus);
+		CleanupStack::PushL(operation);
+		wait->iStatus = KRequestPending;
+		wait->Start();
+      error = operation->iStatus.Int();
+		CleanupStack::PopAndDestroy(2); //operation, wait
+		// return the result via aParameter as a TInt packaged into a TDes8
+		TPckgBuf<TInt> resultPackage(error);
+		aParameter.Copy(resultPackage);
+      return;
+		}
+	default:
+		error=KErrNotSupported;
+		break;
+		}
+	User::LeaveIfError(error);
+	}
+
+CMsvOperation* CImap4ClientMtm::InvokeAsyncFunctionL(TInt aFunctionId,
+												const CMsvEntrySelection& aSelection, 
+												TDes8& aParameter, 
+												TRequestStatus& aCompletionStatus)
+/** Invokes asynchronous IMAP-specific operations.
+
+This provides support for a large number of IMAP-specific functions, including
+operations to:
+
+- Connect and logon to a remote server
+- Synchronise headers
+- Subscribe to mailboxes
+- Populate messages
+- Copy messages
+- Move messages
+- Create messages
+- Set offline behaviour
+
+For details of operations, see #TImap4Cmds.
+
+@param aFunctionId Specifies which operation to perform e.g. connect, copy 
+new mail etc. The specific operations are defined by the #TImap4Cmds enumeration. 
+@param aSelection A selection of messages. The use is dependant upon the command 
+specified by @c aFunctionID.
+@param aParameter Use is dependant upon the command specified by @c aFunctionID
+@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. 
+@panic IMCM 33 MTM has no current context (debug builds only)
+@see TImap4Cmds */
+	{
+    __ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EImpcNoCMsvEntrySet));
+	CMsvOperation* operation = NULL;
+	switch (aFunctionId)
+		{
+	case KIMAP4MTMConnect:
+	case KIMAP4MTMConnectAndSynchronise:
+	case KIMAP4MTMDisconnect:
+		if (aFunctionId!=KIMAP4MTMDisconnect)
+			{
+			RestoreSettingsL();
+			if (iImImap4Settings.AutoSendOnConnect()) //hope iImPop3Settings is restored by this stage
+				{
+				TRAPD(err,SendOnNextConnectionL());  //ignore the error and continue with connecting
+				}
+			}
+		operation = (Session().TransferCommandL(aSelection, aFunctionId, aParameter, aCompletionStatus));
+		break;
+	case KIMAP4MTMCancelBackgroundSynchronise:
+	case KIMAP4MTMStartBatch:
+	case KIMAP4MTMEndBatch:
+	case KIMAP4MTMBusy:
+	case KIMAP4MTMSelect:
+	case KIMAP4MTMSynchronise:
+	case KIMAP4MTMSyncTree:
+	case KIMAP4MTMSyncSubscription:
+	case KIMAP4MTMFullSync:
+	case KIMAP4MTMLocalSubscribe:
+	case KIMAP4MTMLocalUnsubscribe:
+	case KIMAP4MTMInboxNewSync:
+	case KIMAP4MTMFolderFullSync:
+	case KIMAP4MTMWaitForBackground:
+	case KIMAP4MTMRenameFolder:
+	case KIMAP4MTMUndeleteAll:
+	case KIMAP4MTMCancelOffLineOperations:
+	case KIMAP4MTMPopulate:
+		{
+		if(aFunctionId == KIMAP4MTMPopulate)
+			{
+			ConvertToPartialPopulate(aParameter);
+			return (Session().TransferCommandL(aSelection, aFunctionId, iImap4GetPartialMailInfo, aCompletionStatus));
+			}
+		operation = (Session().TransferCommandL(aSelection, aFunctionId, aParameter, aCompletionStatus));
+		}
+		break;
+	case KIMAP4MTMConnectAndSyncCompleteAfterConnect:
+	case KIMAP4MTMConnectAndSyncCompleteAfterFullSync:
+	case KIMAP4MTMConnectAndSyncCompleteAfterDisconnect:
+		{
+		TImapConnectionCompletionState connectAndSyncCompleteState = EAfterConnect;
+		switch (aFunctionId)
+			{
+			case KIMAP4MTMConnectAndSyncCompleteAfterConnect:
+				connectAndSyncCompleteState = EAfterConnect;
+				break;
+			case KIMAP4MTMConnectAndSyncCompleteAfterFullSync:
+				connectAndSyncCompleteState = EAfterFullSync;
+				break;
+			case KIMAP4MTMConnectAndSyncCompleteAfterDisconnect:
+				connectAndSyncCompleteState = EAfterDisconnection;
+				break;
+			default:
+				break;
+			}
+
+		MMsvImapConnectionObserver* connectionObserver;
+		TPckgC<MMsvImapConnectionObserver*> paramPack(connectionObserver);
+		paramPack.Set(aParameter);
+		connectionObserver = paramPack();
+
+		operation = CImapConnectAndSyncOp::NewL(Session(),
+												aSelection,
+												*this,
+												CActive::EPriorityStandard,
+												aCompletionStatus,
+												connectAndSyncCompleteState,
+												connectionObserver);
+		}
+		break;
+	case KIMAP4MTMCopyNewMailWhenAlreadyConnected:
+	case KIMAP4MTMCopyAllMailWhenAlreadyConnected:
+	case KIMAP4MTMCopyMailSelectionWhenAlreadyConnected:
+	case KIMAP4MTMMoveNewMailWhenAlreadyConnected:
+	case KIMAP4MTMMoveMailSelectionWhenAlreadyConnected:
+	case KIMAP4MTMMoveAllMailWhenAlreadyConnected:
+	case KIMAP4MTMPopulateNewMailWhenAlreadyConnected:
+	case KIMAP4MTMPopulateAllMailWhenAlreadyConnected:
+	case KIMAP4MTMPopulateMailSelectionWhenAlreadyConnected:
+		{
+		delete iMsvEntrySelection;
+		iMsvEntrySelection = new(ELeave) CMsvEntrySelection();
+		ConvertToPartialPopulate(aParameter);
+		switch (aFunctionId)
+			{
+			case KIMAP4MTMCopyNewMailWhenAlreadyConnected:
+			case KIMAP4MTMCopyAllMailWhenAlreadyConnected:
+			case KIMAP4MTMMoveNewMailWhenAlreadyConnected:
+			case KIMAP4MTMMoveAllMailWhenAlreadyConnected:
+			case KIMAP4MTMPopulateNewMailWhenAlreadyConnected:
+			case KIMAP4MTMPopulateAllMailWhenAlreadyConnected:
+				{
+				FilterAllOrNewMailsL(aFunctionId,aSelection,iImap4GetPartialMailInfo);
+				}
+				break;
+			case KIMAP4MTMCopyMailSelectionWhenAlreadyConnected:
+			case KIMAP4MTMMoveMailSelectionWhenAlreadyConnected:
+			case KIMAP4MTMPopulateMailSelectionWhenAlreadyConnected:
+				{
+				FilterMailSelectionL(aSelection,iImap4GetPartialMailInfo);
+				}
+				break;
+			}
+
+		// only need to do copy/move if the selection is not empty
+		if (iMsvEntrySelection->Count()>0)
+			{
+			return CopyMoveOrPopulateL(aFunctionId,iImap4GetPartialMailInfo,aCompletionStatus);
+			}
+		else
+			operation = CMsvCompletedOperation::NewL(Session(), KUidMsgTypeIMAP4, KNullDesC8, iMsvEntry->Entry().iServiceId, aCompletionStatus);	
+		}
+		break;
+	case KIMAP4MTMConnectAndCopyNewMailAndStayOnline:
+	case KIMAP4MTMConnectAndCopyNewMailAndDisconnect:
+	case KIMAP4MTMConnectAndCopyAllMailAndStayOnline:
+	case KIMAP4MTMConnectAndCopyAllMailAndDisconnect:
+	case KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline:
+	case KIMAP4MTMConnectAndCopyMailSelectionAndDisconnect:
+	case KIMAP4MTMConnectAndMoveNewMailAndStayOnline:
+	case KIMAP4MTMConnectAndMoveNewMailAndDisconnect:
+	case KIMAP4MTMConnectAndMoveAllMailAndStayOnline:
+	case KIMAP4MTMConnectAndMoveAllMailAndDisconnect:
+	case KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline:
+	case KIMAP4MTMConnectAndMoveMailSelectionAndDisconnect:
+	case KIMAP4MTMConnectAndPopulateNewMailAndStayOnline:
+	case KIMAP4MTMConnectAndPopulateNewMailAndDisconnect:
+	case KIMAP4MTMConnectAndPopulateAllMailAndStayOnline:
+	case KIMAP4MTMConnectAndPopulateAllMailAndDisconnect:
+	case KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline:
+	case KIMAP4MTMConnectAndPopulateMailSelectionAndDisconnect:
+		{
+		ConvertToPartialPopulate(aParameter);
+		return iImIMAP4GetMail->GetMailL(aFunctionId, *this, aSelection, iImap4GetPartialMailInfo, aCompletionStatus);
+		}
+	case KIMAP4MTMCreateNewEmailMessage:
+	case KIMAP4MTMCreateReplyEmailMessage:
+	case KIMAP4MTMCreateForwardEmailMessage:
+	case KIMAP4MTMCreateForwardAsAttachmentEmailMessage:
+	case KIMAP4MTMCreateReceiptEmailMessage:
+		{
+		TImCreateMessageOptions createMessageOptions;	
+		TPckgC<TImCreateMessageOptions> paramPack(createMessageOptions);
+		paramPack.Set(aParameter);
+		switch (aFunctionId)
+			{
+		case KIMAP4MTMCreateNewEmailMessage:
+			return iImEmailOperation->CreateNewL(aCompletionStatus, iMsvEntry->Session(), aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KIMAP4MTMCreateReplyEmailMessage:
+			return iImEmailOperation->CreateReplyL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KIMAP4MTMCreateForwardEmailMessage:
+			return iImEmailOperation->CreateForwardL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KIMAP4MTMCreateForwardAsAttachmentEmailMessage:
+			return iImEmailOperation->CreateForwardAsAttachmentL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		case KIMAP4MTMCreateReceiptEmailMessage:
+			return iImEmailOperation->CreateReceiptL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+		default:
+			User::Leave(KErrNotSupported);
+			return NULL;	// shouldn't really get here!
+			}
+		}
+	default:
+		User::Leave(KErrNotSupported);
+		return NULL;
+		}
+	return operation;
+}
+
+/** Converts the full download information to partial download informations with parameters 
+for partial download information set to  defaults. This package will later be interpreted by 
+server to check whether it is for full download or partial download.
+
+@param aParameter Contains information about full fetch of a message or
+partial fetch of a message .
+*/
+void CImap4ClientMtm::ConvertToPartialPopulate(TDes8& aParameter)
+	{
+	if(aParameter.Length() == sizeof(TImImap4GetPartialMailInfo))
+		{
+		iImap4GetPartialMailInfo.Copy(aParameter);
+		}
+	else
+		{
+		TImImap4GetMailInfo imap4GetMailInfo;	
+		TPckgC<TImImap4GetMailInfo> paramPack(imap4GetMailInfo);
+		paramPack.Set(aParameter);
+		// Copy TImImap4GetMailInfo information into TImImap4GetPartialMailInfo
+		TImImap4GetPartialMailInfo imap4GetPartialMailInfo;
+		imap4GetPartialMailInfo.iGetMailBodyParts = paramPack().iGetMailBodyParts;
+		imap4GetPartialMailInfo.iMaxEmailSize = paramPack().iMaxEmailSize;
+		imap4GetPartialMailInfo.iDestinationFolder = paramPack().iDestinationFolder;
+
+		// Set the remaining members to default so that the server can check 
+		// if these are defaults, then this package is for TImImap4GetMailInfo
+		imap4GetPartialMailInfo.iTotalSizeLimit	= KMaxTInt;
+		imap4GetPartialMailInfo.iBodyTextSizeLimit = KMaxTInt;
+		imap4GetPartialMailInfo.iAttachmentSizeLimit = KMaxTInt;
+		imap4GetPartialMailInfo.iPartialMailOptions = ENoSizeLimits;
+		
+		iImap4GetPartialMailInfo = imap4GetPartialMailInfo;
+		}
+	}
+
+/** Returns whether aParameter contains information for partial fetch of full fetch
+
+@param aParameter Contains information about full fetch of a message or
+partial fetch of a message .
+
+@return ETrue if aParamter contains information for partial fetch
+else EFalse indicates it has information for full download of a message
+*/
+TBool CImap4ClientMtm::IsPartialPopulate(TDes8& aParameter)
+	{
+	TBool isPartialPopulate = EFalse;
+	if(aParameter.Length() == sizeof(TImImap4GetPartialMailInfo))
+		{
+		TImImap4GetPartialMailInfo iImapGetPartialMailInfo;
+		TPckgC<TImImap4GetPartialMailInfo>	pkgPartial(iImapGetPartialMailInfo);
+		pkgPartial.Set(aParameter);
+
+		if(pkgPartial().iPartialMailOptions == ENoSizeLimits &&
+			pkgPartial().iTotalSizeLimit == KMaxTInt &&
+			pkgPartial().iBodyTextSizeLimit == KMaxTInt && 
+			pkgPartial().iAttachmentSizeLimit == KMaxTInt && 
+			(pkgPartial().iGetMailBodyParts == EGetImap4EmailHeaders || 
+			pkgPartial().iGetMailBodyParts == EGetImap4EmailBodyText ||
+			pkgPartial().iGetMailBodyParts == EGetImap4EmailBodyTextAndAttachments ||
+			pkgPartial().iGetMailBodyParts == EGetImap4EmailAttachments ||
+			pkgPartial().iGetMailBodyParts == EGetImap4EmailBodyAlternativeText))
+			{
+			isPartialPopulate = EFalse;
+			}
+		else
+			{
+			isPartialPopulate = ETrue;
+			}
+		}
+	else
+		{
+		isPartialPopulate = EFalse;
+		}
+	return isPartialPopulate;
+	}
+
+/** Copies or moves the selection only if the selection is not empty
+
+@param aFunctionId Specifies which operation to perform e.g. copy new mail, Move or Populate.
+The specific operations are defined by the TImap4Cmds enumeration. 
+@param aParameter Use is dependant upon the command specified by aFunctionID
+@param aCompletionStatus The status when the operation completes. 
+@return If successful, this is an asynchronously completing operation. If failed, 
+this is a completed operation, with status set to the relevant error code. 
+*/
+CMsvOperation* CImap4ClientMtm::CopyMoveOrPopulateL(TInt aFunctionId,TDes8& aParameter,TRequestStatus& aCompletionStatus)
+	{
+	// set entry to the parent of the selection of messages
+	// assumes the selection of messages have the same parent i.e. in the same folder
+	CMsvOperation* operation = NULL;
+	TMsvEmailEntry entry;
+	TMsvId service = KMsvNullIndexEntryId;
+	iMsvEntry->Session().GetEntry((*iMsvEntrySelection)[0], service, entry);
+	iMsvEntry->SetEntryL(entry.Parent());
+	
+	// Unpackage TImImap4GetPartialMailInfo
+	TImImap4GetPartialMailInfo imap4GetMailInfo;	
+	TPckgC<TImImap4GetPartialMailInfo> paramPack(imap4GetMailInfo);
+	paramPack.Set(aParameter);	
+
+	if ((aFunctionId == KIMAP4MTMCopyNewMailWhenAlreadyConnected) ||
+		(aFunctionId == KIMAP4MTMCopyMailSelectionWhenAlreadyConnected) ||
+		(aFunctionId == KIMAP4MTMCopyAllMailWhenAlreadyConnected))
+		{
+		return iMsvEntry->CopyL(*iMsvEntrySelection, paramPack().iDestinationFolder, aCompletionStatus);
+		}
+	else if ((aFunctionId == KIMAP4MTMMoveNewMailWhenAlreadyConnected) ||
+		(aFunctionId == KIMAP4MTMMoveMailSelectionWhenAlreadyConnected) ||
+		(aFunctionId == KIMAP4MTMMoveAllMailWhenAlreadyConnected))
+		{
+		return iMsvEntry->MoveL(*iMsvEntrySelection, paramPack().iDestinationFolder, aCompletionStatus);
+		}
+	else //KIMAP4MTMPopulateMailSelectionWhenAlreadyConnected,KIMAP4MTMPopulateNewMailWhenAlreadyConnected,KIMAP4MTMPopulateAllMailWhenAlreadyConnected
+		{
+		operation = Session().TransferCommandL(*iMsvEntrySelection, KIMAP4MTMPopulate, paramPack, aCompletionStatus);		
+		return operation;
+		}
+	}
+
+/** Filter the selection of messages for all mails or new mails
+
+@param aFunctionId Specifies which operation to perform e.g. connect, copy 
+new mail etc. The specific operations are defined by the TImap4Cmds enumeration. 
+@param aSelection A selection of messages. The use is dependant upon the command 
+specified by aFunctionID.
+@param aParameter Use is dependant upon the command specified by aFunctionID . 
+This can have information for full fetch or partial fetch of a message. 
+*/
+void CImap4ClientMtm::FilterAllOrNewMailsL(TInt aFunctionId,	const CMsvEntrySelection& aSelection,TDes8& aParameter)
+	{
+	iMsvEntry->SetEntryL(aSelection[1]); // set entry to the folder from which to copy/move
+	// get a selection of messages
+	CMsvEntrySelection* msvEntrySelection = iMsvEntry->ChildrenWithTypeL(KUidMsvMessageEntry);
+	CleanupStack::PushL(msvEntrySelection);
+	TMsvId messageId;
+	// get a selection of messages which are new - i.e have new flag set.
+	//	from the selection of messages under the service
+	for (TInt i=0; i<msvEntrySelection->Count(); i++)
+		{
+		messageId = (*msvEntrySelection)[i];
+		TMsvEmailEntry entry;
+		TMsvId service = KMsvNullIndexEntryId;
+		iMsvEntry->Session().GetEntry(messageId, service, entry);
+
+		TImImap4GetPartialMailInfo imap4GetPartialMailInfo;	
+		TPckgC<TImImap4GetPartialMailInfo> paramPack(imap4GetPartialMailInfo);
+		paramPack.Set(aParameter);
+			
+        TBool isComplete = ! ((entry.Complete() && entry.PartialDownloaded()) ||
+							 	(!entry.Complete() && 
+							 		(!entry.BodyTextComplete() 
+							 		|| (paramPack().iGetMailBodyParts ==  EGetImap4EmailBodyTextAndAttachments)) 
+							 		   && !entry.PartialDownloaded()));
+		if ((aFunctionId == KIMAP4MTMCopyNewMailWhenAlreadyConnected) ||
+			(aFunctionId == KIMAP4MTMMoveNewMailWhenAlreadyConnected) ||
+			(aFunctionId == KIMAP4MTMPopulateNewMailWhenAlreadyConnected))
+			{
+
+			if(aFunctionId == KIMAP4MTMPopulateNewMailWhenAlreadyConnected && IsPartialPopulate(aParameter) && !isComplete)
+				{
+				if ((entry.iType == KUidMsvMessageEntry) && (entry.New()))
+					iMsvEntrySelection->AppendL(messageId);
+				}
+			else
+				{
+				if ((entry.iType == KUidMsvMessageEntry) && (entry.New()) && (entry.iSize <= paramPack().iMaxEmailSize))
+					{
+					if ((isComplete && aFunctionId == KIMAP4MTMPopulateNewMailWhenAlreadyConnected) ||
+					 	(entry.Parent() == paramPack().iDestinationFolder && (aFunctionId == KIMAP4MTMMoveNewMailWhenAlreadyConnected || isComplete)))
+						{
+						// Selected entries are filtered from the original list if this is a 
+						// populate operation and the message is complete.
+						//
+						// Note that a copy to local operation where the destination folder is
+						// the same as the source folder is equivalent to a populate operation
+						// as the contents of the message are fetched to the local mirror folder
+						// and hence complete messages are removed from the list in this case.
+						//
+						// Move operations where the source and destination folder are the same
+						// are not supported and are also filtered from the original list.
+						}
+					else
+						{
+						iMsvEntrySelection->AppendL(messageId);
+						}
+					}
+				}
+			}
+		else // KIMAP4MTMCopyAllMailWhenAlreadyConnected, KIMAP4MTMMoveAllMailWhenAlreadyConnected, KIMAP4MTMPopulateAllMailWhenAlreadyConnected
+			{
+			
+			if(aFunctionId == KIMAP4MTMPopulateAllMailWhenAlreadyConnected && IsPartialPopulate(aParameter) && !isComplete)
+				{
+				if ((entry.iType == KUidMsvMessageEntry) && !entry.Complete())
+					iMsvEntrySelection->AppendL(messageId);
+				}
+			else
+				{
+				if ((entry.iType == KUidMsvMessageEntry) && (entry.iSize <= paramPack().iMaxEmailSize))
+					{
+					if ((isComplete && aFunctionId == KIMAP4MTMPopulateAllMailWhenAlreadyConnected) ||
+					 (entry.Parent() == paramPack().iDestinationFolder && (aFunctionId == KIMAP4MTMMoveAllMailWhenAlreadyConnected || isComplete)))
+						{
+						// Selected entries are filtered from the original list if this is a 
+						// populate operation and the message is complete.
+						//
+						// Note that a copy to local operation where the destination folder is
+						// the same as the source folder is equivalent to a populate operation
+						// as the contents of the message are fetched to the local mirror folder
+						// and hence complete messages are removed from the list in this case.
+						//
+						// Move operations where the source and destination folder are the same
+						// are not supported and are also filtered from the original list.
+						}
+					else
+						{
+						iMsvEntrySelection->AppendL(messageId);
+						}
+					}
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy(); //msvEntrySelection;
+	}	
+
+/** Filters the mails selected for partial fetch or full fetch of messages
+
+@param aSelection A selection of messages. The use is dependant upon the command 
+specified by aFunctionID.
+@param aParameter Use is dependant upon the command specified by aFunctionID . 
+This can have information for full fetch or partial fetch of a message. 
+*/
+void CImap4ClientMtm::FilterMailSelectionL(const CMsvEntrySelection& aSelection,TDes8& aParameter)
+	{
+	iMsvEntry->SetEntryL(aSelection[0]); // set entry to service
+	TMsvId messageId;
+	// get the selection of messages from aSelection (note first element of the
+	// CMsvEntrySelection is the service which is then followed by any messages
+	for (TInt i=0; i<aSelection.Count(); i++)
+		{
+		messageId = (aSelection)[i];
+		if (i>0) // since 1st element is the service
+			{
+			TMsvEmailEntry entry;
+			TMsvId service = KMsvNullIndexEntryId;			
+			User::LeaveIfError(iMsvEntry->Session().GetEntry(messageId, service, entry));
+			TImImap4GetPartialMailInfo imap4GetPartialMailInfo;	
+			TPckgC<TImImap4GetPartialMailInfo> paramPack(imap4GetPartialMailInfo);
+			paramPack.Set(aParameter);
+			
+			  TBool isComplete = ! ((entry.Complete() && entry.PartialDownloaded()) ||
+								 	(!entry.Complete() && 
+								 		(!entry.BodyTextComplete() 
+					 					|| (paramPack().iGetMailBodyParts ==  EGetImap4EmailBodyTextAndAttachments)) 
+					 		   			   && !entry.PartialDownloaded()));
+
+			if(IsPartialPopulate(aParameter) && !isComplete)
+				{
+				if ((entry.iType == KUidMsvMessageEntry))
+					iMsvEntrySelection->AppendL(messageId);	
+				}
+			else
+				{
+
+				if ((entry.iType == KUidMsvMessageEntry) && (entry.iSize <= paramPack().iMaxEmailSize))
+					{
+					if(entry.Parent() == paramPack().iDestinationFolder && isComplete)
+						{
+						// do not append if this is a populate operation and the message is complete
+						}
+					else
+						{
+						iMsvEntrySelection->AppendL(messageId);			
+						}
+					}
+				}
+			}
+		}
+	}
+
+void CImap4ClientMtm::HandleEntryEvent(TMsvEntryEvent /*aEvent*/, TAny* /*aArg1*/, TAny* /*aArg2*/, TAny* /*aArg3*/)
+	{    
+	}
+
+//
+// CImImap4Settings wrapper functions
+EXPORT_C void CImap4ClientMtm::SetImap4SettingsL(const CImImap4Settings& aSettings)
+/** Sets the IMAP4 email service settings.
+
+This can be called at any time to override any current email settings (if 
+they exist). However, new settings are only used by the MTM if they have been 
+stored and then a new IMAP4 email session has been started: i.e. settings 
+cannot be changed in mid-session.
+
+@param aSettings New IMAP4 service settings */
+    {
+    iImImap4Settings.CopyL(aSettings);
+    }
+
+EXPORT_C const CImImap4Settings& CImap4ClientMtm::Imap4Settings() const
+/** Gets the IMAP4 email service settings currently being used by the client MTM, 
+if they exist. 
+
+If no settings exist, then an empty settings object will be returned by this 
+function. Settings will only exist if a prior call has been made to the RestoreL() 
+function when the client MTM was positioned over an IMAP4 service in the message 
+store.
+
+@return IMAP4 service settings */
+    {
+    return iImImap4Settings;
+    }
+
+//
+// inherited from MUndoOffLine. This method is responsible for undoing
+// an offline operation.
+/**
+This function is not supported.
+
+@param aDeleted Unused
+@param aFolderId Unused
+*/
+void CImap4ClientMtm::UndoOffLineChangesL(const CImOffLineOperation& /*aDeleted*/, TMsvId /*aFolderId*/)
+//
+// This method receives an offline operation struct the user wishes to cancel.
+// The offline operation will already have been removed from the store of the
+// folder. All that needs to be done is actually undo the operation itself.
+// For instance, if an offline operation moved a message to another folder, this
+// is the time to move the message back.
+// This is probably best done by theserver dll, as the move has to be done without
+// doing it on the remote server.
+//
+    {
+    TODO//
+
+    }
+
+//
+// Returning a list of all the offline operations for a service entry.
+
+/**
+@internalTechnology
+*/
+
+EXPORT_C CImOperationQueueList* CImap4ClientMtm::QueueListL(CMsvEntry& aServiceEntry)
+	{
+	return CImOperationQueueList::NewL(aServiceEntry, this);
+	}
+
+void CImap4ClientMtm::AddAddresseeL(const TDesC& aRealAddress) 
+/** Message address function required by the base class, but not used for IMAP. 
+
+To modify message address information, use the address functions in CImHeader.
+
+@param aRealAddress Address. */
+    {
+    __ASSERT_DEBUG(iAddresseeList != NULL, gPanic(EImpcNoAddresseeList));
+    iAddresseeList->AppendL(aRealAddress);
+    }
+
+void CImap4ClientMtm::AddAddresseeL(const TDesC& aRealAddress, const TDesC& aAlias) 
+/** Message address function required by the base class, but not used for IMAP. 
+
+To modify message address information, use the address functions in CImHeader.
+
+@param aRealAddress Address.
+@param aAlias Alias information. */
+    {
+	 __ASSERT_DEBUG(iAddresseeList != NULL, gPanic(EImpcNoAddresseeList));
+	HBufC* emailAddress = HBufC::NewLC(aRealAddress.Length()+aAlias.Length()+iEmailAddressFormatString->Length()-4);
+	emailAddress->Des().Format(*iEmailAddressFormatString,&aAlias,&aRealAddress);
+	iAddresseeList->AppendL(aRealAddress);
+	CleanupStack::PopAndDestroy();	// emailAddress
+	}
+
+void CImap4ClientMtm::RemoveAddressee(TInt aIndex) 
+/** Message address function required by the base class, but not used for IMAP. 
+
+To modify message address information, use the address functions in CImHeader.
+
+@param aIndex Index of address to be removed. */
+    {
+    __ASSERT_DEBUG(iAddresseeList != NULL, gPanic(EImpcNoAddresseeList));
+    iAddresseeList->Delete(aIndex);
+    }
+
+void CImap4ClientMtm::ContextEntrySwitched() 
+    {
+    } 
+
+
+// Attachment functions to support the SendAs API
+
+/** Unsupported client MTM base class function.
+
+To modify message attachments, use CImEmailMessage.
+
+@param aFilePath Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+@leave KErrNotSupported Function not supported.
+ */
+EXPORT_C void CImap4ClientMtm::AddAttachmentL(const TDesC& /*aFilePath*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+/** Unsupported client MTM base class function.
+
+To modify message attachments, use CImEmailMessage.
+
+@param aFile Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+@leave KErrNotSupported Function not supported.
+ */	
+EXPORT_C void CImap4ClientMtm::AddAttachmentL(RFile& /*aFile*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/** Unsupported client MTM base class function.
+
+To modify message attachments, use CImEmailMessage.
+
+@param aFilePath Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+@leave KErrNotSupported Function not supported.
+ */
+EXPORT_C void CImap4ClientMtm::AddLinkedAttachmentL(const TDesC& /*aFilePath*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/** Unsupported client MTM base class function.
+
+To modify message attachments, use CImEmailMessage.
+
+@param aAttachmentId Unused
+@param aStatus Unused
+@leave KErrNotSupported Function not supported.
+ */
+EXPORT_C void CImap4ClientMtm::AddEntryAsAttachmentL(TMsvId /*aAttachmentId*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/** Unsupported client MTM base class function.
+
+To modify message attachments, use CImEmailMessage.
+
+@param aFileName Unused
+@param aAttachmentFile Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+@leave KErrNotSupported Function not supported.
+ */
+EXPORT_C void CImap4ClientMtm::CreateAttachmentL(const TDesC& /*aFileName*/, RFile& /*aAttachmentFile*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+EXPORT_C void CImap4ClientMtm::CreateMessageL(TMsvId /*aServiceId*/)
+/** Unsupported client MTM base class function.
+
+To create a new message, use CImEmailOperation.
+
+@param aServiceId Unused 
+@leave KErrNotSupported Function not supported.
+*/
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+/** Unsupported client MTM base class function.
+
+@return KErrNotSupported Function not supported.
+@leave KErrNotSupported Function not supported.
+*/
+EXPORT_C TMsvId CImap4ClientMtm::DefaultServiceL() const
+	{
+	User::Leave(KErrNotSupported);
+	return KErrNotSupported;
+	}
+	
+/** Unsupported client MTM base class function.
+
+@leave KErrNotSupported Function not supported.
+*/
+EXPORT_C void CImap4ClientMtm::RemoveDefaultServiceL()
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+/** Unsupported client MTM base class function.
+
+@param aService Unused
+@leave KErrNotSupported Function not supported.
+*/
+EXPORT_C void CImap4ClientMtm::ChangeDefaultServiceL(const TMsvId& /*aService*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+
+/*
+//	Imap4GetMail
+*/
+EXPORT_C CMsvOperation* CImImap4GetMail::GetMailL(TInt aFunctionId, CImap4ClientMtm& aImap4ClientMtm, const CMsvEntrySelection& aMsvEntrySelection, TDes8& aImap4GetMailInfo, TRequestStatus& aObserverRequestStatus)
+/** Creates and begins a new IMAP4 get mail operation.
+
+Note that the function should be, though is not, marked as static. The workaround
+is to call the function using a NULL CImImap4GetMail pointer:
+@code
+CImImap4GetMail* gm = NULL;
+CMsvOperation* gmOp = gm->GetMailL(id, mtm, sel, info, status);
+@endcode
+
+Alternatively, instead of using this class, call 
+CImap4ClientMtm::InvokeAsyncFunctionL() directly. Any functionality
+accessible through this class can also be accessed through that function. 
+
+@param aFunctionId Type of operation to perform, a TImap4Cmds value. Permitted commands are:
+
+Copy commands:
+
+- #KIMAP4MTMConnectAndCopyNewMailAndStayOnline
+- #KIMAP4MTMConnectAndCopyNewMailAndDisconnect
+- #KIMAP4MTMConnectAndCopyAllMailAndStayOnline
+- #KIMAP4MTMConnectAndCopyAllMailAndDisconnect
+- #KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline
+- #KIMAP4MTMConnectAndCopyMailSelectionAndDisconnect
+
+Move commands:
+
+- #KIMAP4MTMConnectAndMoveNewMailAndStayOnline
+- #KIMAP4MTMConnectAndMoveNewMailAndDisconnect
+- #KIMAP4MTMConnectAndMoveAllMailAndStayOnline
+- #KIMAP4MTMConnectAndMoveAllMailAndDisconnect
+- #KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline
+- #KIMAP4MTMConnectAndMoveMailSelectionAndDisconnect
+
+Populate commands:
+
+- #KIMAP4MTMConnectAndPopulateNewMailAndStayOnline
+- #KIMAP4MTMConnectAndPopulateNewMailAndDisconnect
+- #KIMAP4MTMConnectAndPopulateAllMailAndStayOnline
+- #KIMAP4MTMConnectAndPopulateAllMailAndDisconnect
+- #KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline
+- #KIMAP4MTMConnectAndPopulateMailSelectionAndDisconnect
+
+@param aImap4ClientMtm A reference to the IMAP4 Client MTM that wants to perform 
+the Get Mail operation.
+@param aMsvEntrySelection A selection of messages that need to be copied/moved 
+to a local folder. The first entry in this selection MUST be the service. 
+Other IDs can be appended to the selection depending on which operation is 
+to be performed. For the 'copy new', 'copy all', 'move new', 'move all', 'populate 
+new', 'populate all' situations, the folder from which the messages are to 
+be copied, moved or populated should be appended after the service ID. For 
+all the other situations (i.e. copying, moving or populating a selection of 
+messages), the selection of messages should be appended after the service 
+ID. Please note that the selection of messages MUST have the same parent i.e. 
+MUST be in the same folder.
+@param aImap4GetMailInfo A packaged TImImap4GetMailInfo object storing the 
+maximum message size, the destination folder ID, and what message parts are 
+required. For populate commands, this can be a packaged TImImap4GetPartialMailInfo 
+object, specifying separate size limits for body text and attachments.
+@param aObserverRequestStatus The status to be completed when the get mail 
+operation has completed.
+@return The new message operation object through which the get operation can 
+be controlled.
+
+@see TImap4Cmds
+@see TImImap4GetMailInfo 
+@see TImImap4GetPartialMailInfo
+*/
+	{
+	CImImap4GetMail* self = new(ELeave) CImImap4GetMail(aImap4ClientMtm.Session(), aImap4ClientMtm, aObserverRequestStatus);
+	CleanupStack::PushL(self);
+	self->ConstructL(aFunctionId, aMsvEntrySelection, aImap4GetMailInfo);
+	CleanupStack::Pop(); //self
+	return self;
+	}
+
+CImImap4GetMail::~CImImap4GetMail()
+/** Destructor. */
+	{
+	Cancel();
+	delete iMsvEntrySelection;
+	delete iMsvOperation;
+	}
+
+const TDesC8& CImImap4GetMail::FinalProgress()
+/** Gets information about a completed operation.
+
+@return Packaged TImap4GenericProgress holding progress information. 
+@panic IMCM 30 Operation has not completed
+@see TImap4GenericProgress */
+	{
+	__ASSERT_ALWAYS(!IsActive(), gPanic(EMiutActiveInFinalProgress));
+
+	const TDesC8& opProgress = iMsvOperation->FinalProgress();
+
+	if (opProgress.Length())
+		{
+		// if an error was encountered during the Get New Mail operation then need to 
+		// return this as part of the final progresse.  If no error was encoutered then
+		// return iProgress
+		TImap4GenericProgress prog;	
+		TPckgC<TImap4GenericProgress> paramPack(prog);
+		paramPack.Set(opProgress);
+		TImap4GenericProgress progress=paramPack();
+		if (iErrorProgress.iErrorCode != KErrNone)
+			{
+			progress.iMsgsToDo = iErrorProgress.iMsgsToDo;
+			progress.iBytesDone = iErrorProgress.iBytesDone;
+			progress.iErrorCode = iErrorProgress.iErrorCode;
+			progress.iImap4SubStateProgress = iErrorProgress.iImap4SubStateProgress;
+			}
+		else 
+			progress.iImap4SubStateProgress = progress.iState;
+
+		switch(iCommand)
+			{
+			case KIMAP4MTMConnectAndCopyNewMailAndStayOnline:
+			case KIMAP4MTMConnectAndCopyNewMailAndDisconnect:
+				progress.iState= TImap4GenericProgress::ECopyNewMail;
+				break;
+			case KIMAP4MTMConnectAndMoveNewMailAndStayOnline:
+			case KIMAP4MTMConnectAndMoveNewMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EMoveNewMail;
+				break;
+			case KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline:
+			case KIMAP4MTMConnectAndCopyMailSelectionAndDisconnect:
+				progress.iState = TImap4GenericProgress::ECopyMailSelection;
+				break;
+			case KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline:
+			case KIMAP4MTMConnectAndMoveMailSelectionAndDisconnect:
+				progress.iState = TImap4GenericProgress::EMoveMailSelection;
+				break;
+			case KIMAP4MTMConnectAndCopyAllMailAndStayOnline:
+			case KIMAP4MTMConnectAndCopyAllMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::ECopyAllMail;
+				break;
+			case KIMAP4MTMConnectAndMoveAllMailAndStayOnline:
+			case KIMAP4MTMConnectAndMoveAllMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EMoveAllMail;
+				break;
+			case KIMAP4MTMConnectAndPopulateNewMailAndStayOnline:
+			case KIMAP4MTMConnectAndPopulateNewMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EPopulateNewMail;
+				break;
+			case KIMAP4MTMConnectAndPopulateAllMailAndStayOnline:
+			case KIMAP4MTMConnectAndPopulateAllMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EPopulateAllMail;
+				break;
+			case KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline:
+			case KIMAP4MTMConnectAndPopulateMailSelectionAndDisconnect:
+				progress.iState = TImap4GenericProgress::EPopulateMailSelection;
+				break;
+			}
+		
+		iProgressBuf = progress;
+		}
+	return iProgressBuf;
+	}
+
+void CImImap4GetMail::ResetProgress()
+	{
+	switch(iCommand)
+		{
+		case KIMAP4MTMConnectAndCopyNewMailAndStayOnline:
+		case KIMAP4MTMConnectAndCopyNewMailAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::ECopyNewMail;
+			break;
+		case KIMAP4MTMConnectAndMoveNewMailAndStayOnline:
+		case KIMAP4MTMConnectAndMoveNewMailAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::EMoveNewMail;
+			break;
+		case KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline:
+		case KIMAP4MTMConnectAndCopyMailSelectionAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::ECopyMailSelection;
+			break;
+		case KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline:
+		case KIMAP4MTMConnectAndMoveMailSelectionAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::EMoveMailSelection;
+			break;
+		case KIMAP4MTMConnectAndCopyAllMailAndStayOnline:
+		case KIMAP4MTMConnectAndCopyAllMailAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::ECopyAllMail;
+			break;
+		case KIMAP4MTMConnectAndMoveAllMailAndStayOnline:
+		case KIMAP4MTMConnectAndMoveAllMailAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::EMoveAllMail;
+			break;
+		case KIMAP4MTMConnectAndPopulateNewMailAndStayOnline:
+		case KIMAP4MTMConnectAndPopulateNewMailAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::EPopulateNewMail;
+			break;
+		case KIMAP4MTMConnectAndPopulateAllMailAndStayOnline:
+		case KIMAP4MTMConnectAndPopulateAllMailAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::EPopulateAllMail;
+			break;
+		case KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline:
+		case KIMAP4MTMConnectAndPopulateMailSelectionAndDisconnect:
+			iProgress.iState = TImap4GenericProgress::EPopulateMailSelection;
+			break;
+		}
+	iProgress.iMsgsToDo = 0;
+	iProgress.iBytesDone = 0;
+	iProgress.iErrorCode = KErrNone;
+	}
+
+const TDesC8& CImImap4GetMail::ProgressL()
+/** Gets information on the progress of the operation. 
+
+@return Packaged TImap4GenericProgress holding progress information. 
+@see TImap4GenericProgress */
+	{
+	const TDesC8& opProgress = iMsvOperation->ProgressL();
+
+	if (opProgress.Length())
+		{
+		// need to get Sub operation progress and put this into iImap4SubStateProgress
+		TImap4GenericProgress prog;	
+		TPckgC<TImap4GenericProgress> paramPack(prog);
+		paramPack.Set(opProgress);
+		TImap4GenericProgress progress=paramPack();	
+
+		progress.iImap4SubStateProgress = progress.iState;
+		switch(iCommand)
+			{
+			case KIMAP4MTMConnectAndCopyNewMailAndStayOnline:
+			case KIMAP4MTMConnectAndCopyNewMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::ECopyNewMail;
+				break;
+			case KIMAP4MTMConnectAndMoveNewMailAndStayOnline:
+			case KIMAP4MTMConnectAndMoveNewMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EMoveNewMail;
+				break;
+			case KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline:
+			case KIMAP4MTMConnectAndCopyMailSelectionAndDisconnect:
+				progress.iState = TImap4GenericProgress::ECopyMailSelection;
+				break;
+			case KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline:
+			case KIMAP4MTMConnectAndMoveMailSelectionAndDisconnect:
+				progress.iState = TImap4GenericProgress::EMoveMailSelection;
+				break;
+			case KIMAP4MTMConnectAndCopyAllMailAndStayOnline:
+			case KIMAP4MTMConnectAndCopyAllMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::ECopyAllMail;
+				break;
+			case KIMAP4MTMConnectAndMoveAllMailAndStayOnline:
+			case KIMAP4MTMConnectAndMoveAllMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EMoveAllMail;
+				break;
+			case KIMAP4MTMConnectAndPopulateNewMailAndStayOnline:
+			case KIMAP4MTMConnectAndPopulateNewMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EPopulateNewMail;
+				break;
+			case KIMAP4MTMConnectAndPopulateAllMailAndStayOnline:
+			case KIMAP4MTMConnectAndPopulateAllMailAndDisconnect:
+				progress.iState = TImap4GenericProgress::EPopulateAllMail;
+				break;
+			case KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline:
+			case KIMAP4MTMConnectAndPopulateMailSelectionAndDisconnect:
+				progress.iState = TImap4GenericProgress::EPopulateMailSelection;
+				break;
+			}
+		iProgressBuf = progress;
+		}
+	return iProgressBuf;
+	}
+
+void CImImap4GetMail::StoreProgressL()
+	{
+	const TDesC8& opProgress = iMsvOperation->ProgressL();
+
+	if (opProgress.Length())
+		{
+		TImap4GenericProgress prog;	
+		TPckgC<TImap4GenericProgress> paramPack(prog);
+		paramPack.Set(opProgress);
+		TImap4GenericProgress progress=paramPack();	
+
+		iProgress.iMsgsToDo = progress.iMsgsToDo;
+		iProgress.iBytesDone = progress.iBytesDone;
+		iProgress.iState = progress.iState;
+		iProgress.iImap4SubStateProgress = progress.iState;
+		
+		// only write the error code if no error has previously been set
+		if ((iProgress.iErrorCode == KErrNone) && (iErrorProgress.iErrorCode == KErrNone))
+			{
+			if (iStatus.Int() != KErrNone)				
+				iProgress.iErrorCode = iStatus.Int();
+			else
+				iProgress.iErrorCode = progress.iErrorCode;
+			}
+		}
+	}
+
+void CImImap4GetMail::DoCancel()
+	{
+	iMsvOperation->Cancel();
+	TRequestStatus* st = &iObserverRequestStatus;
+	User::RequestComplete(st, KErrCancel);
+	}
+
+CImImap4GetMail::CImImap4GetMail(CMsvSession& aMsvSession, CImap4ClientMtm& aImap4ClientMtm, TRequestStatus& aObserverRequestStatus)
+	: CMsvOperation(aMsvSession, EPriorityStandard, aObserverRequestStatus),
+	iImap4ClientMtm(aImap4ClientMtm)
+	{
+	}
+
+void CImImap4GetMail::ConstructL(TInt aFunctionId, const CMsvEntrySelection& aMsvEntrySelection, TDes8& aImap4GetMailInfo)
+	{
+	iMsvEntrySelection = aMsvEntrySelection.CopyL();
+	
+	iImap4GetPartialMailInfo.Copy(aImap4GetMailInfo);
+	iCommand = aFunctionId;
+
+	CActiveScheduler::Add(this);
+	ResetProgress();
+	iState = EConnectToMailbox;
+	ChangeStateL();
+	iObserverRequestStatus = KRequestPending;
+	SetActive();
+	}
+
+void CImImap4GetMail::Complete()
+	{
+	// complete the observer with error
+	TRequestStatus* status=&iObserverRequestStatus;
+	User::RequestComplete(status,KErrNone);
+	}
+
+void CImImap4GetMail::SelectAndChangeToNextStateL()
+	{
+	SelectNextStateL();
+	ChangeStateL();
+	}
+
+void CImImap4GetMail::RunL()
+	{
+	TInt error = KErrNone;
+	if (iState != EFinished)
+		{
+		// store progress if connecting, copying/moving new/all/selected messages.
+		if ((iState == EConnectToMailbox) || (iState == ECopyNewMessages) ||
+			(iState == ECopyAllMessages) ||	(iState == ECopyMessageSelection) ||
+			(iState == EMoveNewMessages) || (iState == EMoveAllMessages) ||
+			(iState == EMoveMessageSelection) || (iState == EPopulateNewMessages) || 
+			(iState == EPopulateAllMessages) ||	(iState == EPopulateMessageSelection))
+			StoreProgressL();
+		if (iProgress.iErrorCode != KErrNone)
+			{
+			// There has been an error in the previous operation - remember the error.
+			iErrorProgress.iMsgsToDo = iProgress.iMsgsToDo;
+			iErrorProgress.iMsgsDone = iProgress.iMsgsDone;
+			iErrorProgress.iErrorCode = iProgress.iErrorCode;
+
+			// reset progress error code
+			iProgress.iErrorCode = KErrNone;
+
+			// update the state that the error occured.
+			switch (iState)
+				{
+				case EConnectToMailbox:
+					iErrorProgress.iImap4SubStateProgress = TImap4GenericProgress::EConnecting;
+					Complete();
+					return;
+				case ECopyNewMessages:
+				case ECopyAllMessages:
+				case ECopyMessageSelection:
+					iErrorProgress.iImap4SubStateProgress = TImap4GenericProgress::ECopying;
+					// The next state is disconnect so continue!
+					break;
+				case EMoveNewMessages:
+				case EMoveAllMessages:
+				case EMoveMessageSelection:
+					iErrorProgress.iImap4SubStateProgress = TImap4GenericProgress::EMoving;
+					// The next state is disconnect so continue!
+					break;
+				case EPopulateNewMessages:
+				case EPopulateAllMessages:
+				case EPopulateMessageSelection:
+					iErrorProgress.iImap4SubStateProgress = TImap4GenericProgress::EFetching;
+					// The next state is disconnect so continue!
+					break;
+				case EDisconnectFromMailbox:
+					iErrorProgress.iImap4SubStateProgress = TImap4GenericProgress::EDisconnecting;
+					Complete();
+					return;
+				default:
+					Complete();
+					return;
+				}
+			}
+		TRAP(error, SelectAndChangeToNextStateL());
+		if ((error == KErrNone) && (iState != EFinished))
+			SetActive();
+		else if (error != KErrNone)
+			{
+			// if iState == EFinished, then we don't need to complete - done previously
+			TRequestStatus* st = &iObserverRequestStatus;
+			User::RequestComplete(st, error);
+			}
+		}
+	}
+
+void CImImap4GetMail::SelectNextStateL()
+	{
+	switch (iState)
+		{
+		case EConnectToMailbox:
+			if (iProgress.iErrorCode == KErrNone)
+				{
+				switch(iCommand)
+					{
+					case KIMAP4MTMConnectAndCopyNewMailAndStayOnline:
+					case KIMAP4MTMConnectAndCopyNewMailAndDisconnect:
+						iState = ECopyNewMessages;
+						break;
+					case KIMAP4MTMConnectAndMoveNewMailAndStayOnline:
+					case KIMAP4MTMConnectAndMoveNewMailAndDisconnect:
+						iState = EMoveNewMessages;
+						break;
+					case KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline:
+					case KIMAP4MTMConnectAndCopyMailSelectionAndDisconnect:
+						iState = ECopyMessageSelection;
+						break;
+					case KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline:
+					case KIMAP4MTMConnectAndMoveMailSelectionAndDisconnect:
+						iState = EMoveMessageSelection;
+						break;
+					case KIMAP4MTMConnectAndCopyAllMailAndStayOnline:
+					case KIMAP4MTMConnectAndCopyAllMailAndDisconnect:
+						iState = ECopyAllMessages;
+						break;
+					case KIMAP4MTMConnectAndMoveAllMailAndStayOnline:
+					case KIMAP4MTMConnectAndMoveAllMailAndDisconnect:
+						iState = EMoveAllMessages;
+						break;
+					case KIMAP4MTMConnectAndPopulateNewMailAndStayOnline:
+					case KIMAP4MTMConnectAndPopulateNewMailAndDisconnect:
+						iState = EPopulateNewMessages;
+						break;
+					case KIMAP4MTMConnectAndPopulateAllMailAndStayOnline:
+					case KIMAP4MTMConnectAndPopulateAllMailAndDisconnect:
+						iState = EPopulateAllMessages;
+						break;
+					case KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline:
+					case KIMAP4MTMConnectAndPopulateMailSelectionAndDisconnect:
+						iState = EPopulateMessageSelection;
+						break;
+					}
+				}
+			else 
+				iState = EDisconnectFromMailbox;
+			break;
+		case ECopyNewMessages:
+		case ECopyAllMessages:
+		case ECopyMessageSelection:
+		case EMoveNewMessages:
+		case EMoveAllMessages:
+		case EMoveMessageSelection:
+		case EPopulateNewMessages:
+		case EPopulateAllMessages:
+		case EPopulateMessageSelection:
+			if ((iCommand == KIMAP4MTMConnectAndCopyNewMailAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndCopyAllMailAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndCopyMailSelectionAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndMoveNewMailAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndMoveAllMailAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndMoveMailSelectionAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndPopulateNewMailAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndPopulateAllMailAndStayOnline) ||
+				(iCommand == KIMAP4MTMConnectAndPopulateMailSelectionAndStayOnline))
+				{
+				iState = EFinished;
+				}
+			else
+				iState = EDisconnectFromMailbox;
+			break;
+		case EDisconnectFromMailbox:
+			iState = EFinished;
+			break;
+		default:
+			User::LeaveIfError(KErrNotSupported);
+			break;
+		}
+	}
+
+void CImImap4GetMail::ChangeStateL()
+	{
+	switch (iState)
+		{
+		case EConnectToMailbox:
+			ConnectToMailboxL();
+			break;
+		case ECopyNewMessages:
+			CopyMoveNewMessagesL(ETrue);
+			break;
+		case EMoveNewMessages:
+			CopyMoveNewMessagesL(EFalse);
+			break;
+		case ECopyMessageSelection:
+			CopyMoveMessageSelectionL(ETrue);
+			break;
+		case EMoveMessageSelection:
+			CopyMoveMessageSelectionL(EFalse);
+			break;
+		case ECopyAllMessages:
+			CopyMoveAllMessagesL(ETrue);
+			break;
+		case EMoveAllMessages:
+			CopyMoveAllMessagesL(EFalse);
+			break;
+		case EPopulateNewMessages:
+			PopulateNewMessagesL();
+			break;
+		case EPopulateAllMessages:
+			PopulateAllMessagesL();
+			break;
+		case EPopulateMessageSelection:
+			PopulateMessageSelectionL();
+			break;
+		case EDisconnectFromMailbox:
+			DisconnectFromMailboxL();
+			break;
+		case EFinished:
+			{
+			TRequestStatus* status=&iObserverRequestStatus;
+			User::RequestComplete(status,KErrNone);
+			}
+		}
+	}
+
+void CImImap4GetMail::RequestComplete(TInt aError)
+	{
+	iStatus = KRequestPending;
+	TRequestStatus* status=&iStatus;
+	User::RequestComplete(status,aError);
+	}
+
+void CImImap4GetMail::ConnectToMailboxL()
+	{
+	ResetProgress();
+	iProgress.iImap4SubStateProgress = TImap4GenericProgress::EConnecting;
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMConnect, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+	}
+
+void CImImap4GetMail::CopyMoveNewMessagesL(TBool aCopy)
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	if (aCopy)
+		{
+		iProgress.iImap4SubStateProgress = TImap4GenericProgress::ECopying;
+		iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMCopyNewMailWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+		}
+	else
+		{
+		iProgress.iImap4SubStateProgress = TImap4GenericProgress::EMoving;
+		iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMMoveNewMailWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+		}
+	}
+
+void CImImap4GetMail::CopyMoveMessageSelectionL(TBool aCopy)
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	if (aCopy)
+		{
+		iProgress.iImap4SubStateProgress = TImap4GenericProgress::ECopying;
+		iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMCopyMailSelectionWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+		}
+	else
+		{
+		iProgress.iImap4SubStateProgress = TImap4GenericProgress::EMoving;
+		iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMMoveMailSelectionWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+		}
+	}
+
+void CImImap4GetMail::CopyMoveAllMessagesL(TBool aCopy)
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	if (aCopy)
+		{
+		iProgress.iImap4SubStateProgress = TImap4GenericProgress::ECopying;
+		iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMCopyAllMailWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+		}
+	else
+		{
+		iProgress.iImap4SubStateProgress = TImap4GenericProgress::EMoving;
+		iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMMoveAllMailWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+		}
+	}
+
+void CImImap4GetMail::PopulateNewMessagesL()
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iProgress.iImap4SubStateProgress = TImap4GenericProgress::EFetching;
+	iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMPopulateNewMailWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+	}
+
+void CImImap4GetMail::PopulateAllMessagesL()
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iProgress.iImap4SubStateProgress = TImap4GenericProgress::EFetching;
+	iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMPopulateAllMailWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+	}
+
+void CImImap4GetMail::PopulateMessageSelectionL()
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iProgress.iImap4SubStateProgress = TImap4GenericProgress::EFetching;
+	iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMPopulateMailSelectionWhenAlreadyConnected, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+	}
+
+void CImImap4GetMail::DisconnectFromMailboxL()
+	{
+	//don't reset progress so that no. of messages copied are still remembered
+	iProgress.iImap4SubStateProgress = TImap4GenericProgress::EDisconnecting;
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iImap4ClientMtm.InvokeAsyncFunctionL(KIMAP4MTMDisconnect, *iMsvEntrySelection, iImap4GetPartialMailInfo, iStatus);
+	}
+