email/pop3andsmtpmtm/clientmtms/src/POPCMTM.CPP
changeset 0 72b543305e3a
child 76 60a8a215b0ec
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/clientmtms/src/POPCMTM.CPP	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1378 @@
+// 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 POP3 protocol
+// 
+//
+
+#include <bautils.h>	// BaflUtils
+#include <mtmdef.h>		//KUidMtmQueryxxx & TMsvPartList flags
+
+#include <barsc.h>		//RResourceFile
+#include <barsread.h>
+#include <msvftext.h>
+#include <cemailaccounts.h>
+
+#include "POPCMTM.H"
+#include "POP3SET.H"		//CImPop3Settings
+#include <imcm.rsg>
+#include "MIUT_ERR.H"
+#include "IMCMMAIN.H"
+#include "IMCMUTIL.H"
+#include <autosend.h>
+#include <msvenhancesearchsortutil.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
+#include <mtmuidsdef.hrh>
+#include "miut_errconsts.h"
+#include "cimmessagepart.h"
+#endif
+
+#if defined (_UNICODE)
+	#define KUidMsgInternetMailEditorDLL	0x10003C53  // (268450899)
+#else
+	#define KUidMsgInternetMailEditorDLL	0x100011AC  // (268439980)
+#endif
+
+_LIT(KMsvAutoSendExe, "Autosend.exe");
+const TUid KMsvAutoSendExeUid = {0x1000A402}; //268477442
+
+/**
+@internalTechnology 
+*/
+
+EXPORT_C CPop3ClientMtm* CPop3ClientMtm::NewL(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession)
+	{
+	CPop3ClientMtm* self = new(ELeave) CPop3ClientMtm(aRegisteredMtmDll, aMsvSession);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop();
+	return self;
+	}
+
+CPop3ClientMtm::CPop3ClientMtm(CRegisteredMtmDll& aRegisteredMtmDll, CMsvSession& aMsvSession)
+: CBaseMtm(aRegisteredMtmDll, aMsvSession)
+	{
+	__DECLARE_NAME(_S("CPop3ClientMtm"));
+	}
+
+void CPop3ClientMtm::ConstructL()
+	{
+	iImPop3Settings = new (ELeave) CImPop3Settings;
+	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
+	}
+
+CPop3ClientMtm::~CPop3ClientMtm()
+/** Destructor. */
+	{
+	delete iEmailAddressFormatString;
+	delete iImPop3Settings;
+	delete iImPOP3GetMail;
+	delete iHeader;
+	}
+
+void CPop3ClientMtm::SaveMessageL()
+/** Client MTM base class function, with an empty implementation. */
+	{
+	}
+
+void CPop3ClientMtm::LoadMessageL()
+/** Loads the cache with the message data for the current context. */
+	{
+	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 FindL()
+		// For API's other than CMsvSearchsortOpOnHeaderBody-> FindInHeaderBodyL(), a call to LoadMessageL()
+		// loads the body and the header.
+				
+			TMsvEnhanceSearchSortUtil* searchsortutil = (TMsvEnhanceSearchSortUtil*)(GetExtensionData());
+			if ( searchsortutil == NULL )
+				{
+				// Load message Body
+				CMsvStore* msvStore = iMsvEntry->ReadStoreL();
+				CleanupStack::PushL(msvStore);
+			
+		   		if (! msvStore->IsPresentL(KUidMsgFileIMailHeader) )
+		    		{
+		    		CleanupStack::PopAndDestroy(); //store
+		    		return;
+		    		}
+
+				//Restore the header
+				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 CPop3ClientMtm::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!=NULL,gPanic(EPopcMTMNoCMsvEntrySet));
+	
+	// check that current context is a service entry - Assuming that StoreL() is ONLY used to write to Service Entry. True?!
+	__ASSERT_DEBUG(iMsvEntry->Entry().iType==KUidMsvServiceEntry,gPanic(EPopcMTMNotAServiceEntry));
+
+	CEmailAccounts* account = CEmailAccounts::NewLC();
+	TPopAccount id;
+	account->GetPopAccountL(iMsvEntry->Entry().Id(), id);
+	account->SavePopSettingsL(id, *iImPop3Settings);
+	CleanupStack::PopAndDestroy(account);    
+	}
+
+EXPORT_C void CPop3ClientMtm::RestoreSettingsL()
+/** Loads into the object's cache the service settings from the Central Repository for
+the current entry.
+
+The current entry must be a service. */
+	{
+	if (iMsvEntry->Entry().iType==KUidMsvServiceEntry)
+		{
+		CEmailAccounts* account = CEmailAccounts::NewLC();
+		TPopAccount id;
+		account->GetPopAccountL(iMsvEntry->Entry().Id(), id);
+		account->LoadPopSettingsL(id, *iImPop3Settings);
+		CleanupStack::PopAndDestroy(account);    
+		}
+	}
+
+void CPop3ClientMtm::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);
+	}
+
+CMsvOperation* CPop3ClientMtm::ReplyL(TMsvId aDestination, TMsvPartList aPartList, TRequestStatus& aCompletionStatus)
+/** Creates a reply message to the current message context.
+
+The reply is an SMTP message.
+
+@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 iImEmailOperation->CreateReplyL(aCompletionStatus, Session(), iMsvEntry->EntryId(), aDestination, aPartList, msvEmailTypeList, messageType);
+	}
+
+CMsvOperation* CPop3ClientMtm::ForwardL(TMsvId aDestination, TMsvPartList aPartList, TRequestStatus& aCompletionStatus)
+/** Creates a forwarded message from the current message context.
+
+The forwarded message is an SMTP message.
+
+@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 iImEmailOperation->CreateForwardL(aCompletionStatus, Session(), iMsvEntry->EntryId(), aDestination, aPartList, msvEmailTypeList, messageType);
+	}
+
+TUint CPop3ClientMtm::ValidateMessage(TMsvPartList /*aPartList*/)
+	/** Client MTM base class function, with an empty implementation.
+	
+	@param aPartList Unused
+	@return Unused */
+	{
+	return KMsvMessagePartRecipient;
+	}
+
+TBool CPop3ClientMtm::ValidateAddress(const TPtrC& anAddress)
+	{
+	return iTImMessageField.ValidInternetEmailAddress(anAddress);
+	}
+
+TMsvPartList CPop3ClientMtm::DoFindL(const TDesC& aTextToFind, TMsvPartList aPartList)
+   	{
+   	CImClientMTMUtils* clientMTMUtils = CImClientMTMUtils::NewL();
+   	CleanupStack::PushL(clientMTMUtils);
+   
+   	TMsvPartList retList = KMsvMessagePartNone;
+    
+ 	// For POP3 mail we need to search the entry as well as the header. This is because the header stream might not be present.
+ 	CMsvFindText* findText = CMsvFindText::NewLC();
+  
+  	// 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
+ 		TInt32 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
+ 		// of searchsortsetting
+ 		if(aPartList & KMsvMessagePartBody && !(searchsortsetting & EMessagePartBodyLoaded))  	
+   			{
+   			// Restore Body
+   			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))
+   			{
+ 			// Restore header
+			CMsvStore* msvStore = iMsvEntry->ReadStoreL();
+  			CleanupStack::PushL(msvStore);
+			
+		   	if (! msvStore->IsPresentL(KUidMsgFileIMailHeader) )
+		    	{
+		    	CleanupStack::PopAndDestroy(); //store
+		    	return 0;
+		    	}
+
+			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 only originator and description is available 
+   	   			{ 
+   		    	if(searchsortsetting & EMessagePartFromSort)
+   		    		{
+   		    		SetExtensionData((TAny*)&iMsvEntry->Entry().iDetails);
+   		    		}
+ 				else if(searchsortsetting & EMessagePartSubjectSort)
+ 					{
+ 					SetExtensionData((TAny*)&iMsvEntry->Entry().iDescription);		
+ 					}
+  				}
+   			}
+   		
+   		}
+   	else // Old implementation for search
+   		{
+
+		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 CPop3ClientMtm::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 CPop3ClientMtm::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(aRealAddress);
+	}
+
+void CPop3ClientMtm::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(aRealAddress);
+	CleanupStack::PopAndDestroy();	// emailAddress
+	}
+
+void CPop3ClientMtm::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 CPop3ClientMtm::ContextEntrySwitched()
+	{
+	iImPop3Settings->Reset();
+	iHeader->Reset();
+	Body().Reset();	
+	}
+
+TInt CPop3ClientMtm::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;
+	// Supported
+	switch (aCapability.iUid)
+		{
+	case KUidMtmQueryMaxBodySizeValue:
+	case KUidMtmQueryMaxTotalMsgSizeValue:
+		aResponse = KMaxTInt;
+		break;
+	case KUidMsvMtmQueryEditorUidValue:
+		aResponse = KUidMsgInternetMailEditorDLL;
+		break;
+	case KUidMtmQuerySupportedBodyValue:
+		aResponse = KMtm7BitBody + KMtm8BitBody + KMtm16BitBody + KMtmBinaryBody;
+		break;
+	case KUidMtmQuerySupportAttachmentsValue:
+	case KUidMtmQueryCanReceiveMsgValue:		
+		break;
+	// All others - Not Supported:
+	default:
+		error = KErrNotSupported;
+		}
+	return error;
+	}
+
+EXPORT_C void CPop3ClientMtm::SetSettingsL(const CImPop3Settings& aSettings)
+/** Copies the specified service settings to the cached service settings.
+
+@param aSettings New service settings */
+	{
+	iImPop3Settings->CopyL(aSettings);
+	}
+
+EXPORT_C const CImPop3Settings& CPop3ClientMtm::Settings() const
+/** Gets the current cached service settings.
+
+@return The current cached service settings */
+	{
+	return *iImPop3Settings;
+	}
+
+void CPop3ClientMtm::InvokeSyncFunctionL(TInt aFunctionId, const CMsvEntrySelection& aSelection, TDes8& aParameter)
+/** Invokes synchronous POP3-specific operations.
+
+@param aFunctionId ID of the requested operation. The only supported operation 
+is KPOP3MTMIsConnected.
+@param aSelection Selection of message entries. This is used if the operation 
+requires message entries to work on. 
+@param aParameter Buffer containing input and output parameters. The format 
+of this is specific to the operation. */
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EPopcMTMNoCMsvEntrySet));
+
+	TInt error = KErrNone;
+	switch (aFunctionId)
+		{
+		case KPOP3MTMIsConnected:
+			{
+			CMsvOperationActiveSchedulerWait* synchOperation;
+			synchOperation=CMsvOperationActiveSchedulerWait::NewLC();
+			CMsvOperation* operation = Session().TransferCommandL(aSelection, KPOP3MTMIsConnected, aParameter, synchOperation->iStatus);
+			synchOperation->Start();
+			CleanupStack::PushL(operation);
+			error = operation->iStatus.Int();
+			CleanupStack::PopAndDestroy(2);	// synchOperation, operation
+
+			TPop3Progress progress;
+			progress.iErrorCode = error;
+
+			TPckgBuf<TPop3Progress> resultPackage(progress);
+			aParameter.Copy(resultPackage);
+			return;
+			}
+		default:
+			error=KErrNotSupported;
+			__ASSERT_DEBUG(EFalse,gPanic(EPopcUnknownSyncFunction));
+		}
+
+	User::LeaveIfError(error);
+	}
+
+CMsvOperation* CPop3ClientMtm::InvokeAsyncFunctionL(TInt aFunctionId,
+													const CMsvEntrySelection& aSelection,
+												    TDes8& aParameter, 
+												    TRequestStatus& aCompletionStatus)
+/** Invokes asynchronous POP3-specific operations.
+
+@param aFunctionId Specifies which operation to perform e.g. connect, copy 
+new mail etc. The specific operations are defined by the TPop3Cmds 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 Contains information such as the destination folder ID for 
+Get Mail operations. For get mail type functionality, this information must 
+be packaged as a TImPop3GetMailInfo package buffer. 
+@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 TImPop3GetMailInfo
+@see TPop3Cmds */
+	{
+	__ASSERT_DEBUG(iMsvEntry!=NULL,gPanic(EPopcMTMNoCMsvEntrySet));
+
+	
+
+	switch(aFunctionId)
+		{
+		case KPOP3MTMConnect:
+		case KPOP3MTMDisconnect:
+		case KPOP3MTMCancelOfflineOperations:
+			if (aFunctionId==KPOP3MTMConnect)
+				{
+				RestoreSettingsL();
+				if (iImPop3Settings->AutoSendOnConnect()) 
+					{
+					TRAPD(err,SendOnNextConnectionL());  //ignore the error and continue with connecting
+					}
+				}
+			return (Session().TransferCommandL(aSelection, aFunctionId, aParameter, aCompletionStatus));
+		case KPOP3MTMCopyNewMailWhenAlreadyConnected:
+		case KPOP3MTMMoveNewMailWhenAlreadyConnected:
+		case KPOP3MTMCopyMailSelectionWhenAlreadyConnected:
+		case KPOP3MTMMoveMailSelectionWhenAlreadyConnected:
+		case KPOP3MTMCopyAllMailWhenAlreadyConnected:
+		case KPOP3MTMMoveAllMailWhenAlreadyConnected:
+			{
+			__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvServiceEntryValue, gPanic(EPopcMTMNotAServiceEntry));
+			TPckgBuf<TImPop3GetMailInfo> optionsBuf;
+			optionsBuf.Copy(aParameter);
+			const TImPop3GetMailInfo& options=optionsBuf();
+
+			CMsvEntrySelection *entrySelection=NULL;
+			TBool newMailOnly=EFalse;			
+			switch (aFunctionId)
+				{
+				case KPOP3MTMCopyNewMailWhenAlreadyConnected:
+				case KPOP3MTMMoveNewMailWhenAlreadyConnected:
+					newMailOnly=ETrue;
+				case KPOP3MTMCopyAllMailWhenAlreadyConnected:
+				case KPOP3MTMMoveAllMailWhenAlreadyConnected:
+					{
+					entrySelection=FilteredChildrenLC(newMailOnly,options.iMaxEmailSize);
+					}
+					break;
+				case KPOP3MTMCopyMailSelectionWhenAlreadyConnected:
+				case KPOP3MTMMoveMailSelectionWhenAlreadyConnected:
+					{
+					entrySelection=FilteredSelectionLC(options.iMaxEmailSize,aSelection);
+					}
+					break;
+				default:
+					User::Leave(KErrNotSupported);
+				}
+			// only need to do copy/move if the selection is not empty
+			CMsvOperation *op=NULL;
+			if (entrySelection->Count()>0)
+				{
+				if ((aFunctionId == KPOP3MTMCopyNewMailWhenAlreadyConnected) ||
+					(aFunctionId == KPOP3MTMCopyMailSelectionWhenAlreadyConnected) ||
+					(aFunctionId == KPOP3MTMCopyAllMailWhenAlreadyConnected))
+					{
+					op=iMsvEntry->CopyL(*entrySelection, options.iDestinationFolder, aCompletionStatus);
+					}
+				else if ((aFunctionId == KPOP3MTMMoveNewMailWhenAlreadyConnected) ||
+					(aFunctionId == KPOP3MTMMoveMailSelectionWhenAlreadyConnected) ||
+					(aFunctionId == KPOP3MTMMoveAllMailWhenAlreadyConnected))
+					{
+					op=iMsvEntry->MoveL(*entrySelection, options.iDestinationFolder, aCompletionStatus);
+					}
+				}
+			else
+				op=CMsvCompletedOperation::NewL(Session(), KUidMsgTypePOP3, KNullDesC8, iMsvEntry->Entry().iServiceId, aCompletionStatus);
+			CleanupStack::PopAndDestroy(entrySelection);
+			return op;
+			}
+
+		case KPOP3MTMPopulate:
+		case KPOP3MTMPopulateNew:
+		case KPOP3MTMPopulateAll:
+			{
+			__ASSERT_DEBUG(iMsvEntry->Entry().iType.iUid==KUidMsvServiceEntryValue, gPanic(EPopcMTMNotAServiceEntry));
+			TImPop3PopulateOptions options;
+			TImPop3PopulateOptions::UnpackL(aParameter,options);
+
+			CMsvEntrySelection *entrySelection;
+			if(aFunctionId==KPOP3MTMPopulateNew || aFunctionId==KPOP3MTMPopulateAll)
+				{
+				entrySelection=FilteredChildrenLC(aFunctionId==KPOP3MTMPopulateNew,options.MaxEmailSize());				
+				}
+			else
+				{
+				entrySelection=FilteredSelectionLC(options.MaxEmailSize(),aSelection);
+				}
+
+			CMsvOperation *op=NULL;
+			if (entrySelection->Count()>0)
+				{
+				entrySelection->InsertL(0,aSelection[0]);
+				op=(Session().TransferCommandL(*entrySelection, KPOP3MTMPopulate, aParameter, aCompletionStatus));
+				}
+			else
+				op=CMsvCompletedOperation::NewL(Session(), KUidMsgTypePOP3, KNullDesC8, iMsvEntry->Entry().iServiceId, aCompletionStatus);
+			
+			CleanupStack::PopAndDestroy(entrySelection);
+			return op;
+			}		
+
+		case KPOP3MTMConnectAndCopyNewMailAndStayOnline:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndCopyNewMailAndStayOnline);
+		case KPOP3MTMConnectAndCopyNewMailAndDisconnect:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndCopyNewMailAndDisconnect);
+		case KPOP3MTMConnectAndMoveNewMailAndStayOnline:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndMoveNewMailAndStayOnline);
+		case KPOP3MTMConnectAndMoveNewMailAndDisconnect:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndMoveNewMailAndDisconnect);
+		case KPOP3MTMConnectAndCopyMailSelectionAndStayOnline:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndCopyMailSelectionAndStayOnline);
+		case KPOP3MTMConnectAndCopyMailSelectionAndDisconnect:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndCopyMailSelectionAndDisconnect);
+		case KPOP3MTMConnectAndMoveMailSelectionAndStayOnline:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndMoveMailSelectionAndStayOnline);
+		case KPOP3MTMConnectAndMoveMailSelectionAndDisconnect:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndMoveMailSelectionAndDisconnect);
+		case KPOP3MTMConnectAndCopyAllMailAndStayOnline:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndCopyAllMailAndStayOnline);
+		case KPOP3MTMConnectAndCopyAllMailAndDisconnect:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndCopyAllMailAndDisconnect);
+		case KPOP3MTMConnectAndMoveAllMailAndStayOnline:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndMoveAllMailAndStayOnline);
+		case KPOP3MTMConnectAndMoveAllMailAndDisconnect:
+			return iImPOP3GetMail->GetMailL(*this, aCompletionStatus, aSelection, aParameter, CImPOP3GetMail::EConnectAndMoveAllMailAndDisconnect);
+		case KPOP3MTMCreateNewEmailMessage:
+		case KPOP3MTMCreateReplyEmailMessage:
+		case KPOP3MTMCreateForwardEmailMessage:
+		case KPOP3MTMCreateForwardAsAttachmentEmailMessage:
+		case KPOP3MTMCreateReceiptEmailMessage:
+			{
+			TImCreateMessageOptions createMessageOptions;	
+			TPckgC<TImCreateMessageOptions> paramPack(createMessageOptions);
+			paramPack.Set(aParameter);
+			switch (aFunctionId)
+				{
+			case KPOP3MTMCreateNewEmailMessage:
+				return iImEmailOperation->CreateNewL(aCompletionStatus, iMsvEntry->Session(), aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+			case KPOP3MTMCreateReplyEmailMessage:
+				return iImEmailOperation->CreateReplyL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+			case KPOP3MTMCreateForwardEmailMessage:
+				return iImEmailOperation->CreateForwardL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+			case KPOP3MTMCreateForwardAsAttachmentEmailMessage:
+				return iImEmailOperation->CreateForwardAsAttachmentL(aCompletionStatus, iMsvEntry->Session(), aSelection[1], aSelection[0], paramPack().iMsvPartList, paramPack().iMsvEmailTypeList, paramPack().iMessageType);
+			case KPOP3MTMCreateReceiptEmailMessage:
+				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;	// shouldn't really get here!
+		}
+	}
+
+// Attachment functions to support the SendAs API
+
+// Attachment functions to support the SendAs API
+
+/** Unsupported client MTM base class function.
+
+@param aFilePath Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+ */
+EXPORT_C void CPop3ClientMtm::AddAttachmentL(const TDesC& /*aFilePath*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+/** Unsupported client MTM base class function.
+
+@param aFile Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+ */	
+EXPORT_C void CPop3ClientMtm::AddAttachmentL(RFile& /*aFile*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/** Unsupported client MTM base class function.
+
+@param aFilePath Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+ */
+EXPORT_C void CPop3ClientMtm::AddLinkedAttachmentL(const TDesC& /*aFilePath*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/** Unsupported client MTM base class function.
+
+@param aAttachmentId Unused
+@param aStatus Unused
+ */
+EXPORT_C void CPop3ClientMtm::AddEntryAsAttachmentL(TMsvId /*aAttachmentId*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+	
+/** Unsupported client MTM base class function.
+
+@param aFileName Unused
+@param aAttachmentFile Unused
+@param aMimeType Unused
+@param aCharset Unused
+@param aStatus Unused
+ */
+EXPORT_C void CPop3ClientMtm::CreateAttachmentL(const TDesC& /*aFileName*/, RFile& /*aAttachmentFile*/, const TDesC8& /*aMimeType*/, TUint /*aCharset*/, TRequestStatus& /*aStatus*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+EXPORT_C void CPop3ClientMtm::CreateMessageL(TMsvId /*aServiceId*/)
+/** Unsupported client MTM base class function.
+
+@param aServiceId Unused */
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+CMsvEntrySelection* CPop3ClientMtm::FilteredChildrenLC(TBool aNewOnly, TInt aMaxEmailSize)
+	{
+	CMsvEntrySelection *selection= new (ELeave) CMsvEntrySelection;
+	CleanupDeletePushL(selection);
+	
+	TInt count = iMsvEntry->Count();
+	// get a selection of messages which are new - i.e have new flag set
+	// and those which are smaller than iMaxEmailSize
+	for (TInt i=0; i<count; ++i)
+		{
+		const TMsvEmailEntry &entry = (*iMsvEntry)[i];
+		if (entry.iType==KUidMsvMessageEntry)
+			{
+			if ((!aNewOnly || entry.New()) &&
+				(entry.iSize <= aMaxEmailSize))
+				selection->AppendL(entry.Id());
+			}
+		}
+	return selection;
+	}
+
+CMsvEntrySelection* CPop3ClientMtm::FilteredSelectionLC(TInt aMaxEmailSize, const CMsvEntrySelection& aSelection)
+	{
+	CMsvEntrySelection *selection= new (ELeave) CMsvEntrySelection;
+	CleanupDeletePushL(selection);
+	TInt count = aSelection.Count();
+	
+	for (TInt i=1; i<count; ++i)
+		{
+		const TMsvEmailEntry &entry = iMsvEntry->ChildDataL((aSelection)[i]);
+		if ((entry.iType==KUidMsvMessageEntry)&&(entry.iSize <= aMaxEmailSize))
+			{
+			selection->AppendL(entry.Id());
+			}
+		}
+	return selection;
+	}
+
+/**
+Gets the default POP service.
+
+@return
+The default service
+
+@leave 
+KErrNotFound If default service setting does not exist.
+*/
+EXPORT_C TMsvId CPop3ClientMtm::DefaultServiceL() const
+	{
+	User::Leave(KErrNotSupported);
+	return KErrNotSupported;
+	}
+
+/**
+Removes the default POP service.
+*/	
+EXPORT_C void CPop3ClientMtm::RemoveDefaultServiceL()
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+/**
+Sets the default POP service.
+
+@param	aService
+The default service
+*/	
+EXPORT_C void CPop3ClientMtm::ChangeDefaultServiceL(const TMsvId& /*aService*/)
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+
+EXPORT_C CMsvOperation* CImPOP3GetMail::GetMailL(CPop3ClientMtm& aPop3ClientMtm, TRequestStatus& aObserverRequestStatus, const CMsvEntrySelection& aMsvEntrySelection, TDes8& aPop3GetMailInfo, TImPOP3GetMailType aPOP3GetMailType)
+/** Creates and begins a new POP3 get mail operation.
+
+@param aPop3ClientMtm A reference to the POP3 Client MTM that wants to perform 
+the Get Mail operation.
+@param aObserverRequestStatus The status to be completed when the get mail 
+operation has completed.
+@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.
+@param aPop3GetMailInfo A packaged TImPop3GetMailInfo object, which sets the 
+maximum message size and the destination folder ID.
+@param aPOP3GetMailType Type of operation to perform
+@return The new CImPOP3GetMail object through which the get operation can be 
+controlled. */
+	{
+	CImPOP3GetMail* self = new(ELeave) CImPOP3GetMail(aPop3ClientMtm.Session(), aObserverRequestStatus, aPop3ClientMtm, aPOP3GetMailType);
+	CleanupStack::PushL(self);
+	self->ConstructL(aMsvEntrySelection, aPop3GetMailInfo);
+	CleanupStack::Pop(); //self
+	return self;
+	}
+
+EXPORT_C CImPOP3GetMail::~CImPOP3GetMail()
+/** Destructor. */
+	{
+	Cancel();
+	delete iMsvEntrySelection;
+	delete iMsvOperation;
+	}
+
+EXPORT_C const TDesC8& CImPOP3GetMail::FinalProgress()
+/** Gets information about a completed operation.
+
+@return Packaged TPop3Progress holding progress information. 
+@see TPop3Progress */
+	{
+	__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
+		TPop3Progress prog;	
+		TPckgC<TPop3Progress> paramPack(prog);
+		paramPack.Set(opProgress);
+		TPop3Progress progress=paramPack();
+		if (iErrorProgress.iErrorCode != KErrNone)
+			{
+			progress.iTotalMsgs = iErrorProgress.iTotalMsgs;
+			progress.iMsgsToProcess = iErrorProgress.iMsgsToProcess;
+			progress.iBytesDone = iErrorProgress.iBytesDone;
+			progress.iTotalBytes = iErrorProgress.iTotalBytes;
+			progress.iErrorCode = iErrorProgress.iErrorCode;
+			progress.iPop3SubStateProgress = iErrorProgress.iPop3SubStateProgress;
+			}
+		else 
+			progress.iPop3SubStateProgress = progress.iPop3Progress;
+
+		switch(iPOP3GetMailType)
+			{
+			case EConnectAndCopyNewMailAndStayOnline:
+			case EConnectAndCopyNewMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopCopyNewMail;
+				break;
+			case EConnectAndMoveNewMailAndStayOnline:
+			case EConnectAndMoveNewMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopMoveNewMail;
+				break;
+			case EConnectAndCopyMailSelectionAndStayOnline:
+			case EConnectAndCopyMailSelectionAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopCopyMailSelection;
+				break;
+			case EConnectAndMoveMailSelectionAndStayOnline:
+			case EConnectAndMoveMailSelectionAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopMoveMailSelection;
+				break;
+			case EConnectAndCopyAllMailAndStayOnline:
+			case EConnectAndCopyAllMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopCopyAllMail;
+				break;
+			case EConnectAndMoveAllMailAndStayOnline:
+			case EConnectAndMoveAllMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopMoveAllMail;
+				break;
+			}
+		
+		iProgressBuf = progress;
+		}
+	return iProgressBuf;
+	}
+
+void CImPOP3GetMail::ResetProgress()
+	{
+	switch(iPOP3GetMailType)
+		{
+		case EConnectAndCopyNewMailAndStayOnline:
+		case EConnectAndCopyNewMailAndDisconnect:
+			iProgress.iPop3Progress = TPop3Progress::EPopCopyNewMail;
+			break;
+		case EConnectAndMoveNewMailAndStayOnline:
+		case EConnectAndMoveNewMailAndDisconnect:
+			iProgress.iPop3Progress = TPop3Progress::EPopMoveNewMail;
+			break;
+		case EConnectAndCopyMailSelectionAndStayOnline:
+		case EConnectAndCopyMailSelectionAndDisconnect:
+			iProgress.iPop3Progress = TPop3Progress::EPopCopyMailSelection;
+			break;
+		case EConnectAndMoveMailSelectionAndStayOnline:
+		case EConnectAndMoveMailSelectionAndDisconnect:
+			iProgress.iPop3Progress = TPop3Progress::EPopMoveMailSelection;
+			break;
+		case EConnectAndCopyAllMailAndStayOnline:
+		case EConnectAndCopyAllMailAndDisconnect:
+			iProgress.iPop3Progress = TPop3Progress::EPopCopyAllMail;
+			break;
+		case EConnectAndMoveAllMailAndStayOnline:
+		case EConnectAndMoveAllMailAndDisconnect:
+			iProgress.iPop3Progress = TPop3Progress::EPopMoveAllMail;
+		}
+	iProgress.iTotalMsgs = 0;
+	iProgress.iMsgsToProcess = 0;
+	iProgress.iBytesDone = 0;
+	iProgress.iTotalBytes = 0;
+	iProgress.iErrorCode = KErrNone;
+	}
+
+const TDesC8& CImPOP3GetMail::ProgressL()
+/** Gets information on the progress of the operation. 
+
+@return Packaged TPop3Progress holding progress information. 
+@see TPop3Progress */
+	{
+	const TDesC8& opProgress = iMsvOperation->ProgressL();
+
+	if (opProgress.Length())
+		{
+		// need to get Sub operation progress and put this into iPop3SubStateProgress
+		TPop3Progress prog;	
+		TPckgC<TPop3Progress> paramPack(prog);
+		paramPack.Set(opProgress);
+		TPop3Progress progress=paramPack();	
+
+		progress.iPop3SubStateProgress = progress.iPop3Progress;
+		switch(iPOP3GetMailType)
+			{
+			case EConnectAndCopyNewMailAndStayOnline:
+			case EConnectAndCopyNewMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopCopyNewMail;
+				break;
+			case EConnectAndMoveNewMailAndStayOnline:
+			case EConnectAndMoveNewMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopMoveNewMail;
+				break;
+			case EConnectAndCopyMailSelectionAndStayOnline:
+			case EConnectAndCopyMailSelectionAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopCopyMailSelection;
+				break;
+			case EConnectAndMoveMailSelectionAndStayOnline:
+			case EConnectAndMoveMailSelectionAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopMoveMailSelection;
+				break;
+			case EConnectAndCopyAllMailAndStayOnline:
+			case EConnectAndCopyAllMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopCopyAllMail;
+				break;
+			case EConnectAndMoveAllMailAndStayOnline:
+			case EConnectAndMoveAllMailAndDisconnect:
+				progress.iPop3Progress = TPop3Progress::EPopMoveAllMail;
+			}
+		iProgressBuf = progress;
+		}
+	return iProgressBuf;
+	}
+
+void CImPOP3GetMail::StoreProgressL()
+	{
+	const TDesC8& opProgress = iMsvOperation->ProgressL();
+
+	if (opProgress.Length())
+		{
+		TPop3Progress prog;	
+		TPckgC<TPop3Progress> paramPack(prog);
+		paramPack.Set(opProgress);
+		TPop3Progress progress=paramPack();	
+
+		iProgress.iTotalMsgs = progress.iTotalMsgs;
+		iProgress.iMsgsToProcess = progress.iMsgsToProcess;
+		iProgress.iBytesDone = progress.iBytesDone;
+		iProgress.iTotalBytes = progress.iTotalBytes;
+		iProgress.iPop3SubStateProgress = progress.iPop3Progress;
+		
+		// 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;
+			}
+		iProgressBuf = progress;
+		}
+	}
+
+void CImPOP3GetMail::DoCancel()
+	{
+	iMsvOperation->Cancel();
+	TRequestStatus* st = &iObserverRequestStatus;
+	User::RequestComplete(st, KErrCancel);
+	}
+
+CImPOP3GetMail::CImPOP3GetMail(CMsvSession& aMsvSession, TRequestStatus& aObserverRequestStatus, CPop3ClientMtm& aPop3ClientMtm, TImPOP3GetMailType aPOP3GetMailType)
+	: CMsvOperation(aMsvSession, EPriorityStandard, aObserverRequestStatus),
+	iPop3ClientMtm(aPop3ClientMtm),
+	iPOP3GetMailType(aPOP3GetMailType)
+	{
+	__DECLARE_NAME(_S("CImPOP3GetMail"));
+	}
+
+void CImPOP3GetMail::ConstructL(const CMsvEntrySelection& aMsvEntrySelection, TDes8& aPop3GetMailInfo)
+	{
+	iMsvEntrySelection = aMsvEntrySelection.CopyL();
+	
+	iPop3GetMailInfo.Copy(aPop3GetMailInfo);
+
+	CActiveScheduler::Add(this);
+	ResetProgress();
+	iState = EConnectToMailbox;
+	ChangeStateL();
+	iObserverRequestStatus = KRequestPending;
+	SetActive();
+	}
+
+void CImPOP3GetMail::Complete()
+	{
+	// complete the observer with error
+	TRequestStatus* status=&iObserverRequestStatus;
+	User::RequestComplete(status,KErrNone);
+	}
+
+void CImPOP3GetMail::SelectAndChangeToNextStateL()
+	{
+	SelectNextStateL();
+	ChangeStateL();
+	}
+
+void CImPOP3GetMail::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))
+			{
+			StoreProgressL();
+			}
+			
+		if (iProgress.iErrorCode != KErrNone)
+			{
+			// There has been an error in the previous operation - remember the error.
+			iErrorProgress.iTotalMsgs = iProgress.iTotalMsgs;
+			iErrorProgress.iMsgsToProcess = iProgress.iMsgsToProcess;
+			iErrorProgress.iBytesDone = iProgress.iBytesDone;
+			iErrorProgress.iTotalBytes = iProgress.iTotalBytes;
+			iErrorProgress.iErrorCode = iProgress.iErrorCode;
+
+			// reset progress error code
+			iProgress.iErrorCode = KErrNone;
+
+			// update the state that the error occured.
+			switch (iState)
+				{
+				case EConnectToMailbox:
+					iErrorProgress.iPop3SubStateProgress = TPop3Progress::EPopConnecting;
+					Complete();
+					return;
+				case ECopyNewMessages:
+				case ECopyAllMessages:
+				case ECopyMessageSelection:
+					iErrorProgress.iPop3SubStateProgress = TPop3Progress::EPopCopying;
+					// The next state is disconnect so continue!
+					break;
+				case EMoveNewMessages:
+				case EMoveAllMessages:
+				case EMoveMessageSelection:
+					iErrorProgress.iPop3SubStateProgress = TPop3Progress::EPopMoving;
+					// The next state is disconnect so continue!
+					break;
+				case EDisconnectFromMailbox:
+					iErrorProgress.iPop3SubStateProgress = TPop3Progress::EPopDisconnecting;
+					Complete();
+					return;
+				default:
+					Complete();
+					return;
+				}
+			}
+			
+			else if (iProgress.iPop3SubStateProgress == TPop3Progress::EPopDisconnected)
+			{
+			// Connection has dropped, so complete the operation
+			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 CImPOP3GetMail::SelectNextStateL()
+	{
+	switch (iState)
+		{
+		case EConnectToMailbox:
+			if (iProgress.iErrorCode == KErrNone)
+				{
+				switch(iPOP3GetMailType)
+					{
+					case EConnectAndCopyNewMailAndStayOnline:
+					case EConnectAndCopyNewMailAndDisconnect:
+						iState = ECopyNewMessages;
+						break;
+					case EConnectAndMoveNewMailAndStayOnline:
+					case EConnectAndMoveNewMailAndDisconnect:
+						iState = EMoveNewMessages;
+						break;
+					case EConnectAndCopyMailSelectionAndStayOnline:
+					case EConnectAndCopyMailSelectionAndDisconnect:
+						iState = ECopyMessageSelection;
+						break;
+					case EConnectAndMoveMailSelectionAndStayOnline:
+					case EConnectAndMoveMailSelectionAndDisconnect:
+						iState = EMoveMessageSelection;
+						break;
+					case EConnectAndCopyAllMailAndStayOnline:
+					case EConnectAndCopyAllMailAndDisconnect:
+						iState = ECopyAllMessages;
+						break;
+					case EConnectAndMoveAllMailAndStayOnline:
+					case EConnectAndMoveAllMailAndDisconnect:
+						iState = EMoveAllMessages;
+						break;
+					}
+				}
+			else 
+				iState = EDisconnectFromMailbox;
+			break;
+		case ECopyNewMessages:
+		case EMoveNewMessages:
+		case ECopyMessageSelection:
+		case EMoveMessageSelection:
+		case ECopyAllMessages:
+		case EMoveAllMessages:
+			if ((iPOP3GetMailType == EConnectAndCopyNewMailAndStayOnline) ||
+				(iPOP3GetMailType == EConnectAndMoveNewMailAndStayOnline) ||
+				(iPOP3GetMailType == EConnectAndCopyMailSelectionAndStayOnline) ||
+				(iPOP3GetMailType == EConnectAndMoveMailSelectionAndStayOnline) ||
+				(iPOP3GetMailType == EConnectAndCopyAllMailAndStayOnline) ||
+				(iPOP3GetMailType == EConnectAndMoveAllMailAndStayOnline))
+				{
+				iState = EFinished;
+				}
+			else
+				if ((iProgress.iErrorCode == KErrNone) && (iErrorProgress.iErrorCode == KErrNone) || (iProgress.iErrorCode == KErrDiskFull))
+					{
+   					iState = EDisconnectFromMailbox;
+					}
+				else
+					// The POPS MTM will already have disconnected if it has completed with an error
+					{
+					iState = EFinished;
+				}
+			break;
+		case EDisconnectFromMailbox:
+			iState = EFinished;
+			break;
+		default:
+			User::LeaveIfError(KErrNotSupported);
+			break;
+		}
+	}
+
+void CImPOP3GetMail::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 EDisconnectFromMailbox:
+			DisconnectFromMailboxL();
+			break;
+		case EFinished:
+			{
+			TRequestStatus* status=&iObserverRequestStatus;
+			User::RequestComplete(status,KErrNone);
+			}
+		}
+	}
+
+void CImPOP3GetMail::RequestComplete(TInt aError)
+	{
+	iStatus = KRequestPending;
+	TRequestStatus* status=&iStatus;
+	iStatus=KRequestPending;
+	User::RequestComplete(status,aError);
+	}
+
+void CImPOP3GetMail::ConnectToMailboxL()
+	{
+	ResetProgress();
+	iProgress.iPop3SubStateProgress = TPop3Progress::EPopConnecting;
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMConnect, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+	}
+
+void CImPOP3GetMail::CopyMoveNewMessagesL(TBool aCopy)
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	if (aCopy)
+		{
+		iProgress.iPop3SubStateProgress = TPop3Progress::EPopCopying;
+		iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMCopyNewMailWhenAlreadyConnected, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+		}
+	else
+		{
+		iProgress.iPop3SubStateProgress = TPop3Progress::EPopMoving;
+		iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMMoveNewMailWhenAlreadyConnected, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+		}
+	}
+
+void CImPOP3GetMail::CopyMoveMessageSelectionL(TBool aCopy)
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	if (aCopy)
+		{
+		iProgress.iPop3SubStateProgress = TPop3Progress::EPopCopying;
+		iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMCopyMailSelectionWhenAlreadyConnected, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+		}
+	else
+		{
+		iProgress.iPop3SubStateProgress = TPop3Progress::EPopMoving;
+		iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMMoveMailSelectionWhenAlreadyConnected, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+		}
+	}
+
+void CImPOP3GetMail::CopyMoveAllMessagesL(TBool aCopy)
+	{
+	ResetProgress();
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	if (aCopy)
+		{
+		iProgress.iPop3SubStateProgress = TPop3Progress::EPopCopying;
+		iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMCopyAllMailWhenAlreadyConnected, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+		}
+	else
+		{
+		iProgress.iPop3SubStateProgress = TPop3Progress::EPopMoving;
+		iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMMoveAllMailWhenAlreadyConnected, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+		}
+	}
+
+void CImPOP3GetMail::DisconnectFromMailboxL()
+	{
+	//don't reset progress so that no. of messages copied are still remembered
+	iProgress.iPop3SubStateProgress = TPop3Progress::EPopDisconnecting;
+	delete iMsvOperation;
+	iMsvOperation=NULL;
+	iMsvOperation=iPop3ClientMtm.InvokeAsyncFunctionL(KPOP3MTMDisconnect, *iMsvEntrySelection, iPop3GetMailInfo, iStatus);
+	}