email/imap4mtm/imapsyncmanager/src/cimapfolder.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 52 12db4185673b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/imap4mtm/imapsyncmanager/src/cimapfolder.cpp	Fri Jun 04 10:25:39 2010 +0100
@@ -0,0 +1,2372 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "cimapfolder.h"
+#include "cimapsyncmanager.h"
+#include "cimapsession.h"
+#include "cimaprfc822headerfields.h"
+#include "cimapbodystructure.h"
+#include "cimapfolderinfo.h"
+#include "cimapfolderindex.h"
+#include "cimaplogger.h"
+#include <numberconversion.h>
+#include <imcvcodc.h>
+#include <miutconv.h>
+#include "cimapmimeheaderfields.h"
+#include "cimapcharconv.h"
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
+#include "cimconvertheader.h"
+#include "cimconvertcharconv.h"
+#endif
+
+// For first stage download (to view in folder list)
+_LIT8(KImapFetchHeaderToEnd, "%d:*");
+_LIT8(KImapFetchHeaderRange,"%d:%d");
+_LIT8(KImapFetchHeaderUIDRange,"UID %d:%d");
+_LIT8(KImapFetchHeaderRangeSearch,"%d:%d %S");
+_LIT8(KImapSmallHeaderFields,"Received Date Subject From Priority X-MSMail-Priority X-Priority Importance");
+//_LIT8(KImapLargeHeaderFields,"Received Date Subject From Reply-to To Cc Bcc Message-ID Priority %S");
+
+_LIT(KQuoteChar, "\\");
+_LIT(KIMAP_INBOX, "INBOX");
+
+_LIT8(KImapTxtImage, "IMAGE");
+_LIT8(KImapTxtAudio, "AUDIO");
+_LIT8(KImapTxtVideo, "VIDEO");
+_LIT8(KImapTxtApplication, "APPLICATION");
+_LIT8(KImapTxtRelated, "RELATED");
+_LIT8(KImapTxtAlternative, "ALTERNATIVE");
+_LIT8(KImapTxtMixed, "MIXED");
+_LIT8(KImapTxtHtml, "HTML");
+_LIT8(KImapTxtAttachment, "ATTACHMENT");
+_LIT8(KImapTxtCalendar, "CALENDAR");
+_LIT8(KImapTxtXVCalendar, "X-VCALENDAR");
+_LIT8(KImapTxtDeliveryStatus, "DELIVERY-STATUS");
+_LIT8(KImapTxtBase64, "BASE64");
+
+// IMAP Priority fields
+//_LIT8(KImapPriorityFieldsSearch, "Priority Priority X-MSMail-Priority Precedence Importance");
+
+// Constants
+const TInt KImapUidSearchSize = 400;
+const TInt KImapMaxIntChars = 11; // the maximum number of characters needed to represent a 32-bit unsigned integer as a string.
+
+
+// Efficient and SAFE way of comparing TBools which might have different integers representing TRUE
+inline TBool BoolsAreEqual( TBool aA, TBool aB )
+	{
+	return ((aA && aB) || (!aA && !aB));
+	}
+	
+inline TBool BoolsAreNotEqual( TBool aA, TBool aB )
+	{
+	return ((!aA || !aB) && (aA || aB));
+	}
+
+/**
+Constructor
+*/
+CImapFolder::CImapFolder(CImapSyncManager& aSyncMan, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings)
+: CMsgActive(EPriorityStandard), 
+iSyncManager(aSyncMan),
+iServerEntry(aServerEntry),
+iImapSettings(aImapSettings),
+iHeaderConverter(CImapUtils::GetRef().Charconv().HeaderConverter())
+	{
+	}
+
+/**
+Destructor
+*/
+CImapFolder::~CImapFolder()
+	{
+	iMatchingMessageIds.Reset();
+	iDeletedMessageIds.Reset();
+	iMissingMessageIds.Reset();
+	delete iSelection;
+	iFolderIndex->Reset();
+	iMessageFlagInfoArray.Reset();
+	delete iFolderIndex;
+	delete iCachedEntryData;
+	delete iClearSeenList;
+	delete iSetSeenList;
+	iFullFolderPath.Close();
+	}
+
+/**
+Static factory constructor
+
+@param aSyncMan
+Reference to the owning Sync Manager (for access to offline control object)
+@param aEmailServerEntry
+The folder entry on the Message server that will be use to construct this folder object
+@return The constructed CImapFolder object pushed onto the cleanup stack
+*/
+EXPORT_C CImapFolder* CImapFolder::NewLC(CImapSyncManager& aSyncMan, CMsvServerEntry& aServerEntry, TMsvEmailEntry& aEmailEntry, CImapSettings& aImapSettings, const TDesC& aFullFolderPath)
+	{
+	CImapFolder* self=new (ELeave) CImapFolder(aSyncMan, aServerEntry, aImapSettings);
+	CleanupStack::PushL(self);
+
+	// Non-trivial constructor
+	self->ConstructL(aServerEntry, aEmailEntry, aFullFolderPath);
+	return self;
+	}
+
+/**
+Static factory constructor with cleanup
+
+@param aSyncMan
+Reference to the owning Sync Manager (for access to offline control object)
+@param aEmailServerEntry
+The folder entry on the Message server that will be use to construct this folder object
+@return The constructed CImapFolder object
+*/
+EXPORT_C CImapFolder* CImapFolder::NewL(CImapSyncManager& aSyncMan, CMsvServerEntry& aServerEntry, TMsvEmailEntry& aEmailEntry, CImapSettings& aImapSettings, const TDesC& aFullFolderPath)
+	{
+	CImapFolder* self=NewLC(aSyncMan, aServerEntry, aEmailEntry, aImapSettings, aFullFolderPath);
+	CleanupStack::Pop();
+	return self;
+	}
+
+/**
+The non-trival constructor
+
+@param aEmailServerEntry
+The folder entry on the Message server that will be use to construct this folder object
+*/
+void CImapFolder::ConstructL(CMsvServerEntry& /*aServerEntry*/, TMsvEmailEntry& aEmailEntry, const TDesC& aFullFolderPath)
+	{
+	iSessionFolderInfo = NULL;
+	iMailboxId = aEmailEntry.Id();
+	iMailboxSize = aEmailEntry.RemoteFolderEntries();
+	iFolderIndex = new (ELeave) CImapFolderIndex();
+	iSelection   = new (ELeave) CMsvEntrySelection();
+	iSyncLimit = KImImapSynchroniseAll;
+
+	// Set the Path of folder object
+	SetFullFolderPathL(aFullFolderPath) ;
+	
+	// We're an active object...
+	CActiveScheduler::Add(this);
+	}
+
+/**
+Sets the full path name of the folder from the service entry downwards. Layout as on the remote IMAP Server.
+Should only be use by the CImapSyncManager.
+
+@param aFullFolderPath
+The new path to use as the full path of the folder.
+*/
+void CImapFolder::SetFullFolderPathL(const TDesC& aFullFolderPath)
+	{
+	iFullFolderPath.Close(); // discard any previous data
+	iFullFolderPath.CreateL(aFullFolderPath);
+	}
+
+/**
+Processing message loop for the active object. Called by the active scheduler.
+*/
+void CImapFolder::DoRunL()
+	{
+	// Finish if any server errors.
+	if(iStatus.Int()!=KErrNone)
+		{
+		Complete(iStatus.Int());
+		return;
+		}
+
+	switch(iNextAction)
+		{
+	case CImapSyncManager::ESyncNew:
+		{
+		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Starting SynchroniseNewL");				
+		SynchroniseNewL();
+		return;
+		}
+	case CImapSyncManager::ESyncFlags:
+		{
+		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Syncing flags for local messages");
+
+		// Whenever iSavedSession->FetchBodyStructureAndHeadersL() is called, this is the next step 
+		// (although this step can be reached without calling FetchBodyStructureAndHeadersL())
+		// This means that OnFetchLD() may have been called, in which case there are 
+		// outstanding BULK entry operations that need to be completed here.
+		iServerEntry.CompleteBulk();
+
+		// If there were message flags that has been changed locally and need upadting on the remote server
+		// then do those first.
+		if(iSetSeenList)
+			{
+			if(ProcessSeenFlagsL(ESetSeenFlag))
+				{
+				return;
+				}
+			}
+
+		if(iClearSeenList)
+			{
+			if(ProcessSeenFlagsL(EClearSeenFlag))
+				{
+				return;
+				}
+			}
+
+		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Syncing flags for remote messages");
+		// Creates the list of old messages then update the flags for them
+		GetMessageChildrenL(iMailboxId, iSelection);
+		MakeSortedFolderIndexL(ETrue);
+	
+		if(iSelection->Count() > 0)
+			{
+			iHighestUid = (*iFolderIndex)[iSelection->Count()-1].iUid;
+			}
+		else
+			{
+			iHighestUid = 0;
+			}
+
+		TInt localcount = iFolderIndex->Size();
+		iMatchingMessageIds.Reset();
+		for(TInt localloop = 0; localloop < localcount; ++localloop)
+			{
+			TMsvId localid = (*iFolderIndex)[localloop].iUid;
+			iMatchingMessageIds.Append(localid);
+			}
+			
+		iMessageFlagInfoArray.Reset();
+		
+		HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(iMatchingMessageIds);
+		
+		// Call the FETCHFLAGS function in the session
+		iNextAction = CImapSyncManager::EEndSyncFlags;
+		iSavedSession->FetchFlagsL(iStatus, *sequenceSetOnHeap, iMessageFlagInfoArray);
+		SetActive();
+		CleanupStack::PopAndDestroy(sequenceSetOnHeap);
+		}
+		break;		
+	case CImapSyncManager::EEndSyncFlags:
+		{
+		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Call to get the remote flags completed");
+		// Loop through the messages array and update the flags for each UID returned
+		// Get a clean version of the folder children
+		TInt resultscount = iMessageFlagInfoArray.Count();
+		for(TInt resultsloop = 0; resultsloop < resultscount; ++resultsloop)
+			{
+			TMessageFlagInfo *messageinfo = &(iMessageFlagInfoArray[resultsloop]);
+
+			TInt localmsgcount = iFolderIndex->Size();
+			// For each returned Uid go through the list of local index to find the matching TMsvId.
+			for(TInt localloop = 0; localloop < localmsgcount; ++localloop)
+				{
+				if((*iFolderIndex)[localloop].iUid == messageinfo->MessageUid())
+					{
+					SetEntryL((*iFolderIndex)[localloop].iMsvId);
+					TMsvEmailEntry entry = iServerEntry.Entry();
+
+					TBool messageInfoSeen = messageinfo->QueryFlag(TMessageFlagInfo::ESeen);
+					TBool oldEntrySeen = entry.SeenIMAP4Flag();
+
+					// Are we configured to update the \seen flag on the server?
+					// If so then we need to translate "read\unread" flags into "\\seen" or not "\\seen"
+					if (iImapSettings.UpdatingSeenFlags())
+						{
+						// Make a note to update the servers \Seen flag if "read\unread" has CHANGED on the client
+						// and is different to the server's version
+						if (BoolsAreEqual(entry.Unread(), messageInfoSeen) && BoolsAreEqual(oldEntrySeen, messageInfoSeen))
+							{
+							if (entry.Unread())
+								{
+								AppendClearSeenL(entry.UID());
+								}
+							else
+								{
+								AppendSetSeenL(entry.UID());
+								}								
+							}
+						}
+
+					entry.SetSeenIMAP4Flag(messageInfoSeen);
+					entry.SetFlaggedIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::EFlagged));
+					entry.SetDeletedIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::EDeleted));
+					entry.SetDraftIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::EDraft));
+					entry.SetRecentIMAP4Flag(messageinfo->QueryFlag(TMessageFlagInfo::ERecent));
+					
+					// Are we configured to update the \seen flag on the server?
+					if (iImapSettings.UpdatingSeenFlags())
+						{
+						// Now copy the inverse of the \Seen flag down to the phone's Unread flag 
+						//  except when LastSyncSeen is set (ie when the client version is more up to date)
+						//  This means that the client Read status ALWAYS reflects the IMAP \Seen state
+						if (BoolsAreEqual(entry.Unread(), messageInfoSeen) 		&& BoolsAreNotEqual(oldEntrySeen, messageInfoSeen))
+							{
+							// Phone and server disagree on whether the message has been read.
+							// And the seen flag on the server is different to that on the phone.
+							// Which means that a change has happened on the server that the phone was not aware of.
+							// So server is more up to date, and we take its value.
+							entry.SetUnread(!messageInfoSeen);
+							}
+						}
+					
+					ChangeEntryBulkL(entry); // completed after the outer for loop
+					break;
+					}
+				} // end of inner for loop
+			}
+			
+		iServerEntry.CompleteBulk();
+		
+		iNextAction = CImapSyncManager::ESyncProcessSeenFlagsAndComplete;
+		SetActive();
+		CompleteSelf();
+		}
+		break;		
+	case CImapSyncManager::ESyncProcessSeenFlagsAndComplete:
+		{
+		// If there were message flags that has been changed locally and need upadting on the remote server
+		// then do those now.
+		if(iSetSeenList)
+			{
+			if(ProcessSeenFlagsL(ESetSeenFlag))
+				{
+				return;
+				}
+			}
+
+		if(iClearSeenList)
+			{
+			if(ProcessSeenFlagsL(EClearSeenFlag))
+				{
+				return;
+				}
+			}
+			
+		SyncCompleteL();
+		Complete(iStatus.Int());
+		}
+		break;
+	case CImapSyncManager::ESyncSearch:
+		{
+		if(iStatus == KErrNone) 
+			{
+			if(iSyncState == CImapSyncManager::ESyncSearch)
+				{
+				// Process the seach results to see if any messages ids are left.
+				if(CheckAndProgressMessageSyncL())
+					{
+					// More messages and the search command has been sent so just return.
+					return;
+					}
+				}
+				
+			// If the sync action is syncing old messages then go through the list of found ids
+			// match it with the folder index and build a list of messages that are no longer on the server.
+			if(iSyncState == CImapSyncManager::ESyncOld)
+				{
+				// At this point the remote command to search out folder UIDs has completed. This
+				// list will contain all UIDs for messages in the remote folder. This may be too
+				// many, and if so, the list is truncated to only include the N most recent 
+				// messages in accordance with the synchronisation limit.
+
+				TInt syncThresh = GetSyncThreshold();
+				__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Syncing old. syncThresh = %d", syncThresh));
+
+				// Perform the check on the message ids to make sure that only messages that are within
+				// the sync limit will be left in iDeletedMessageIds.
+				CheckMessagesInRangeL(syncThresh);
+				
+				// Check the delete ids list and delete messages according to what's in the list	
+				TInt deletedcount = iDeletedMessageIds.Count();
+				// Remove message from the local server
+				for(TInt deleteloop = 0; deleteloop < deletedcount; ++deleteloop)
+					{
+					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) deleting.", (*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId));
+					DeleteMessageL((*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId);
+					}
+
+				// Trim the list down to the most recent UIDs consistant with the sync limit.
+				if(iMatchingMessageIds.Count() > syncThresh)
+					{
+					for(TInt i = 0; i < syncThresh; ++i)
+						{
+						iMatchingMessageIds.Remove(0);
+						}
+					}
+
+				// Get a clean version of the folder children
+				GetMessageChildrenL(iMailboxId, iSelection);
+				
+				//update the progress object
+				iMsgsToDo = iMatchingMessageIds.Count();
+				
+				MakeSortedFolderIndexL(ETrue);
+			
+				if(iSelection->Count() > 0)
+					{
+					iHighestUid = (*iFolderIndex)[iSelection->Count()-1].iUid;
+					}
+				else
+					{
+					iHighestUid = 0;
+					}
+
+				// At this point, the remote command to fetch all old messages has completed. 
+				// Now we can look at fetching all new messages. 'iHighestUid' will contain the
+				// highest UID of the old messages. The top entry in 'iSearchList' will contain
+				// the highest UID in the remote folder. This gives us the range of UID to fetch
+				// for new messages.
+
+				// First check are there any new messages to fetch? If 'iHighestUid' is the highest
+				// UID locally and remotely, then we finished sync'ing when we completed the old
+				// sync.
+				if(iMatchingMessageIds.Count() == 0)
+					{
+					__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Search List is empty");				
+					}
+				else if(iHighestUid < iMatchingMessageIds[iMatchingMessageIds.Count()-1])
+					{
+					TUint32 uidLow = iHighestUid;
+					TUint32 uidHigh = iMatchingMessageIds[iMatchingMessageIds.Count()-1];
+
+					// Only want new messages.
+					uidLow++;
+
+					// Are there only new messages (and no old)?
+					if(iHighestUid == 0)
+						{
+						// Set this to ensure range is correct.
+						uidLow = iMatchingMessageIds[0];
+						}
+					
+					// Perform the new sync.
+					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Synchronising new messages with range %d:%d", uidLow, uidHigh));
+					SynchroniseRangeL(uidLow, uidHigh);
+					return;
+					}
+
+				iSyncState = CImapSyncManager::ESyncNew;	
+				}
+
+			if((iSyncState == CImapSyncManager::ESyncNew) && (iImapSettings.SearchString().Length() == 0))
+				{
+				// Check for missing UIDs, ie. holes in the messages that we should have.
+				CheckForMissingMessagesUidsL();
+
+				// If there were any "missing" messages found during the sync that we should have
+				// mirrored previously, get these now.
+				if(iMissingMessageIds.Count() != 0)
+					{
+					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Missing messages detected %d", iMissingMessageIds.Count()));
+					HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(iMissingMessageIds);
+					// Call the FETCH function in the session
+					iSavedSession->FetchBodyStructureAndHeadersL(iStatus, sequenceSetOnHeap->Des(), KImapSmallHeaderFields(), *this);
+					CleanupStack::PopAndDestroy(sequenceSetOnHeap);
+					SetActive();
+
+				 	iSyncState = CImapSyncManager::EFolderSynchronise;
+				 	iNextAction = CImapSyncManager::ESyncFlags;
+					return;
+					}
+
+				if(iSyncLimit <= KImImapSynchroniseAll)
+					{
+					__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Starting SynchroniseNewL");				
+					SynchroniseNewL();
+					return;
+					}
+				
+				// If we haven't returned yet, then no new messages to sync
+				// so just sync the flags of existing messages.
+				iSyncState = CImapSyncManager::EFolderSynchronise;
+			 	iNextAction = CImapSyncManager::ESyncFlags;
+			 	SetActive();
+			 	CompleteSelf();
+				return;
+				}
+			else
+				{
+				SyncCompleteL();
+				Complete(iStatus.Int());
+				}
+			}
+		}
+		break;
+	case CImapSyncManager::EFolderExpunge:
+		{
+		// Call expunge to delete messages marked for delete
+		__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: calling EXPUNGE in folder %S", &iFullFolderPath));
+
+		iSyncState = CImapSyncManager::EFolderExpunge;
+		iNextAction = CImapSyncManager::EFolderLocalExpunge;
+		iSavedSession->ExpungeL(iStatus);
+		SetActive();
+		}
+		break;
+	case CImapSyncManager::EFolderClose:
+		{
+		//Permanently removes all messages that have the deleted flag set
+		//from the currently selected mailbox
+		iSyncState = CImapSyncManager::EFolderClose;
+		iNextAction = CImapSyncManager::EFolderReSelect;
+		iSavedSession->CloseL(iStatus);
+		SetActive();
+		}
+		break;
+	case CImapSyncManager::EFolderReSelect:
+		{
+		//Selecting a mailbox so that messages in the mailbox can be accessed. 
+		iSyncState = CImapSyncManager::EFolderReSelect;
+		iNextAction = CImapSyncManager::EFolderLocalExpunge;
+		SelectL(iStatus, *iSavedSession);
+		SetActive();
+		}
+		break;
+	case CImapSyncManager::EFolderLocalExpunge:
+		{
+		// delete local messages locally
+		__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: local message delete in folder %S", &iFullFolderPath));
+		
+		// Check the delete ids list and delete messages according to what's in the list	
+		TInt deletedcount = iDeletedMessageIds.Count();
+		// Remove message from the local server
+		for(TInt deleteloop = 0; deleteloop < deletedcount; ++deleteloop)
+			{
+			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) deleting.", (*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId));
+			DeleteMessageL((*iFolderIndex)[iDeletedMessageIds[deleteloop]].iMsvId);
+			}
+			
+		// clear the count of expunged messages to prevent a sync triggering
+		CImapFolderInfo* folderInfo = iSavedSession->SelectedFolderInfo();
+		if (folderInfo->ExpungedMessages().Count()==deletedcount)
+			{
+			folderInfo->ResetExpungedMessages();
+
+			// store updated remote mailbox size.
+			iMailboxSize = folderInfo->Exists();
+			SetEntryL(iMailboxId);
+			TMsvEmailEntry entry = iServerEntry.Entry();
+			entry.SetRemoteFolderEntries(folderInfo->Exists());
+			ChangeEntryL(entry);
+			}
+
+		iSyncState = CImapSyncManager::EFolderLocalExpunge;
+		iNextAction = CImapSyncManager::ENotSyncing;
+		}
+		// fall through...
+	case CImapSyncManager::ENotSyncing:
+		{
+		iSyncState = CImapSyncManager::ENotSyncing;
+		Complete(iStatus.Int());
+		}
+		break;
+	default:
+		break;
+		}
+	}
+
+/**
+Processing of the returned message ids after the completion of the IMAP SEARCH command.
+If there are more messages ids to be look at then the SEARCH commands will be call again.
+This call could set this folder object active
+
+@return ETrue if the call has resulted in the folder object being made Active.
+*/
+TBool CImapFolder::CheckAndProgressMessageSyncL()
+	{
+	iFolderPosition += KImapUidSearchSize;
+
+	__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Session Search command completed: %d", iFolderPosition));
+
+	// Check to see if we have all the messages.
+	if(iFolderPosition >= iMailboxSize)
+		{
+		__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: UID search complete");
+
+		//update the progress object
+		iMsgsToDo = iMatchingMessageIds.Count();
+
+		iSyncState = CImapSyncManager::ESyncOld;
+		// We have the full list of remote UIDs - fall through.
+		}
+	else
+		{
+		// Should be able to hit this code if KImapUidSearchSize is reduced to < the size
+		// of the remote mailbox (iMailboxSize)
+		// SearchString non 0 means a refined UID SEARCH is required
+		
+		if(iImapSettings.SearchString().Length() != 0)
+			{
+			// Refined search required
+			// Still uses the indexes but appends user specified search criteria
+			RBuf8 tempstr;
+			tempstr.CleanupClosePushL();
+					
+			TPtrC8 searchstr = iImapSettings.SearchString();
+			
+			TInt tempstrLen = KImapFetchHeaderRangeSearch().Length() + KImapMaxIntChars + KImapMaxIntChars + searchstr.Length();
+ 			tempstr.CreateL(tempstrLen);			
+			tempstr.Format(KImapFetchHeaderRangeSearch, iFolderPosition+1, Min(iMailboxSize,iFolderPosition+KImapUidSearchSize), &searchstr);
+			
+			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Refined UID search - get next manageable block of UIDs: %S", &tempstr));
+			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
+			
+			// Go active
+			SetActive();
+			
+			CleanupStack::PopAndDestroy(&tempstr);
+			return ETrue;
+			}
+		else
+			{
+			// Normal unrefined SEARCH. Will pull back all the UIDs between indexes
+			// Perform a UID search on this folder.
+			RBuf8 tempstr;
+			tempstr.CleanupClosePushL();
+				
+			TInt tempstrLen = KImapFetchHeaderRange().Length() + KImapMaxIntChars + KImapMaxIntChars;
+			tempstr.CreateL(tempstrLen);
+			tempstr.Format(KImapFetchHeaderRange, iFolderPosition+1, Min(iMailboxSize,iFolderPosition+KImapUidSearchSize));
+			
+			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Unrefined UID search - get next manageable block of UIDs: %S", &tempstr));
+			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
+			
+			// Go active
+			SetActive();
+			
+			CleanupStack::PopAndDestroy(&tempstr);
+			return ETrue;
+			}
+		}
+	return EFalse;
+	}
+
+/**
+Sets number of messages to be sync. If there is a search string or the sync limit is outside
+the mailbox size then everything will be sync. i.e. the sync limit will be set to 0.
+
+*/
+TInt CImapFolder::GetSyncThreshold()
+	{
+	// If no UID Search string defined then the old logic is used
+	if((iImapSettings.SearchString().Length() == 0) && (iSyncLimit > KImImapSynchroniseAll))
+		{	
+		if(iSyncLimit < iMailboxSize)
+			{
+			return (iMailboxSize - iSyncLimit);
+			}
+		}
+
+	return 0;
+	}
+
+/**
+Go through the list of found message ids and work out if each message is within the sync limit
+as defined by the user. If a message isn't within the limit it will be removed if it hasn't been fetched.
+
+@param aSyncThreshold
+The number of messages that will define the sync limit
+*/
+void CImapFolder::CheckMessagesInRangeL(TInt aSyncThreshold)
+	{
+	// At this stage (prior to truncation), we have a full list of all the message
+	// UIDs in the remote folder. We also have a list of all UIDs for messages in
+	// the local folder. With these lists, we can establish which local messages
+	// have been orphaned and which have not using the following rules.
+
+	// * If the remote message is no longer there:
+	//		(1) Then the local message is orphaned (always).
+	// * If the remote message is still there and it is not one of the N most recent:
+	//		(2) If the local message has body parts do nothing. - This Check has been removed as per new CMail UI.
+	//		(3) If the local message does not have body parts, then it is orphaned
+	//		    unless is is a message we have selected for download.
+	// * If the remote message is still there and it is one of the N most recent:
+	//		(4) Do nothing.
+
+	// Search through the local folder list while checking the remote folder list.
+
+	TInt localcount = iFolderIndex->Size();
+	TInt resultscount = iMatchingMessageIds.Count();
+
+	iFolderPosition = 0;
+
+	iDeletedMessageIds.Reset();
+	
+	for(TInt localloop = 0; localloop < localcount; ++localloop)
+		{
+		// Go through the list of index, if can't find matching in found ids then mark for delete.
+		TInt resultsloop = 0;//listprogress;
+		TBool removeThis = EFalse;
+		TBool folderPositionFound = EFalse;
+
+		while(resultsloop < resultscount)
+			{
+			TUint remoteUid = iMatchingMessageIds[resultsloop];
+			TUint localUid = (*iFolderIndex)[localloop].iUid;
+
+			// Check the synclimit
+			TBool inSyncRange = (resultsloop >= aSyncThreshold);
+			if((remoteUid > localUid) || (remoteUid > iHighestUid))
+				{
+				break;
+				}
+			if(remoteUid == localUid)
+				{
+				// Found id, sets new lower limit then exit loop
+				folderPositionFound = ETrue;
+				
+				// Check for if message is in the syncrange
+				if(!inSyncRange)
+					{
+					// Here the remote uid matches the local uid, but the message falls outside
+					// of the N most recent messages. See cases (2) & (3).
+					SetEntryL((*iFolderIndex)[localloop].iMsvId);
+					TMsvEmailEntry message(iServerEntry.Entry());
+					// Does message have any downloaded parts?
+					// The local message does not have any body parts and
+					// is not selected for download, so it is orphaned.
+					// See case (3) above.
+					__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) is only header and not selected for download, deleting", (*iFolderIndex)[localloop].iMsvId));
+					removeThis = ETrue;
+					iOrphanedMessages++;
+					}
+				break;
+				}
+
+			++resultsloop;
+			}
+		if(!folderPositionFound || removeThis)
+			{
+			// Saved the index position of the message to be deleted from the local view
+			__LOG_FORMAT((iSavedSession->LogId(), "ImapFolder: Local message (%d) marked for deleting, loop = %d", (*iFolderIndex)[localloop].iMsvId, localloop));
+			iDeletedMessageIds.Append(localloop);
+			}
+		else
+			{
+				iMsgsDone++;
+			}
+			
+		}
+	
+	}
+	
+
+/**
+Go through the list of found remote message ids and work out if each message header has been fetched or not.
+Messages that are missing from the local index will be added to a list of messages to be fetch.
+*/
+void CImapFolder::CheckForMissingMessagesUidsL()
+	{
+	iMissingMessageIds.Reset();
+
+	if(iFolderIndex->Size() == 0)
+		{
+		return;
+		}
+		
+	TInt remotecount = iMatchingMessageIds.Count();
+
+	for(TInt remoteloop = 0; remoteloop < remotecount; ++remoteloop)
+		{
+		TUint remoteUid = iMatchingMessageIds[remoteloop];
+
+		if(iFolderIndex->FindMsg(remoteUid) == 0)
+			{
+			iMissingMessageIds.Append(remoteUid);
+			}
+		}
+	}
+/**
+Cancels any outstanding asynchronous service requests.
+*/
+void CImapFolder::DoCancel()
+	{
+	iSavedSession->Cancel();
+	CMsgActive::DoCancel();
+	}
+
+/**
+Called when the requested operation is completed.
+Cleans up data members used only during synchronisation
+*/
+void CImapFolder::DoComplete(TInt& /*aStatus*/)
+	{
+	iCachedEntryData->Reset();
+	iSelection->Reset();
+	iFolderIndex->Reset();
+	iMatchingMessageIds.Reset();
+	iDeletedMessageIds.Reset();
+	iMessageFlagInfoArray.Reset();
+
+	// iSessionFolderInfo is not owned by this class,
+	// Set to NULL as it should never be assumed to exist.
+	iSessionFolderInfo = NULL;
+	}
+
+/**
+Returns the full mailbox path description from the Message server
+
+@return Pointer to the descriptor object
+*/
+EXPORT_C TDesC& CImapFolder::FullFolderPathL()
+	{
+	if(iFullFolderPath.Length() == 0)
+		{
+		HBufC16* temp = MakePathL(ETrue);
+		iFullFolderPath.Close();
+		iFullFolderPath.Assign(temp);
+		}
+
+	return iFullFolderPath;
+	}
+
+/**
+Returns the mailbox uid from the Message server
+
+@return The mailbox UID;
+*/
+EXPORT_C TMsvId CImapFolder::MailboxId()
+	{
+	return iMailboxId;
+	}
+
+/**
+Issue the IMAP select command to select this folder using the supplied session.
+The session must already have been opened and connected.
+
+NOTE:  The client TRequestStatus is passed through to the CImapSession.
+       Therefore a CImapSession::Cancel() must be called to cancel the
+       SELECT operation.
+NOTE:  UpdateSessionFolderInfoL() should be called following completion
+	   of the select operation. And definitely prior to synchronising
+	   the folder (see below)
+
+@param aStatus 
+The status request object to be use to send the completion signal. 
+This is passed through to the session object.
+@param aSession 
+The session to be use for the SELECT command
+*/
+EXPORT_C void CImapFolder::SelectL(TRequestStatus& aStatus, CImapSession& aSession, TBool aSelectInbox)
+	{
+	// Construct the info object for the select command then just pass it on.
+	CImapFolderInfo* folderInfo = CImapFolderInfo::NewL();
+	CleanupStack::PushL(folderInfo);
+	folderInfo->SetMsvId(iMailboxId);
+	folderInfo->SetNameL(FullFolderPathL());
+	
+	// Issue the SELECT - the session takes immediate 
+	// ownership of the folder info object.
+	CleanupStack::Pop(folderInfo);
+	aSession.SelectL(aStatus, folderInfo, aSelectInbox);
+	}
+
+
+/**
+Issue the IMAP select command to select this folder using the supplied session.
+The session must already have been opened and connected.
+
+NOTE:  The client TRequestStatus is passed through to the CImapSession.
+       Therefore a CImapSession::Cancel() must be called to cancel the 
+       EXAMINE operation.
+NOTE:  UpdateSessionFolderInfoL() should be called following completion
+	   of the EXAMINE operation.
+
+@param aStatus 
+The status request object to be use to send the completion signal. 
+This is passed through to the session object.
+@param aSession 
+The session to be use for the EXAMINE command
+*/
+EXPORT_C void CImapFolder::ExamineL(TRequestStatus& aStatus, CImapSession& aSession)
+	{
+	// Construct the info object for the select command then just pass it on.
+	CImapFolderInfo* folderInfo = CImapFolderInfo::NewL();
+	CleanupStack::PushL(folderInfo);
+	folderInfo->SetMsvId(iMailboxId);
+	folderInfo->SetNameL(FullFolderPathL());
+	
+	// Issue the EXAMINE - the session takes immediate 
+	// ownership of the folder info object.
+	CleanupStack::Pop(folderInfo);
+	aSession.ExamineL(aStatus, folderInfo);
+	}
+
+/**
+Updates the remote folder mirror with status information about the folder 
+on the remote server. Called at the start of the synchronisation process.
+
+Panics if the folder is not selected folder on the passed session.
+
+NOTE: MUST be called prior to synchronising (done internally)
+
+NOTE: updates the context of the CMsvServerEntry to the folder.
+
+@param aSession - the session that has SELECTed this folder
+*/
+EXPORT_C void CImapFolder::UpdateSessionFolderInfoL(CImapSession& aSession)
+	{
+	iSessionFolderInfo = aSession.SelectedFolderInfo();
+	if(iSessionFolderInfo)
+		{
+		__ASSERT_ALWAYS(iSessionFolderInfo->MsvId()==iMailboxId, User::Invariant());
+		
+		iMailboxSize = iSessionFolderInfo->Exists();
+		// Need to be save away. NOT Done on Session.
+		SetEntryL(iMailboxId);
+		TMsvEmailEntry entry = iServerEntry.Entry();
+		entry.SetRemoteFolderEntries(iSessionFolderInfo->Exists());
+		if(entry.UID() != iSessionFolderInfo->UidValidity())
+			{
+			entry.SetValidUID(EFalse);
+			}
+		entry.SetRecentIMAP4Flag(iSessionFolderInfo->Recent());
+		entry.SetUnreadIMAP4Flag(iSessionFolderInfo->Unseen());
+		ChangeEntryL(entry);
+		}
+	}
+
+/**
+This can be called at any time with a given IMAP session to find out if the folder has 
+changed in any way since the last sync.
+
+Panics if the folder is not selected folder on the passed session.
+
+@return
+Returns true if any of Exists, Recent or Expunged counts are non-zero.
+*/
+EXPORT_C TBool CImapFolder::Changed(CImapSession& aSession)
+	{
+	iSessionFolderInfo = aSession.SelectedFolderInfo();
+	if(iSessionFolderInfo)
+		{
+		__ASSERT_ALWAYS(iSessionFolderInfo->MsvId()==iMailboxId, User::Invariant());
+
+		// True if the exists count has changed
+		// or if recent or expunged counts are non-zero
+		TBool existChanged = (iMailboxSize != iSessionFolderInfo->Exists());
+		TBool flagChanged = iSessionFolderInfo->MessageFlagsChanged();
+		TBool otherChanged = (existChanged || 
+			     				iSessionFolderInfo->Recent() || 
+			     				iSessionFolderInfo->ExpungedMessages().Count());
+			     				
+		iFlagChangedOnly = (flagChanged && !(otherChanged));
+		
+		return ( otherChanged || flagChanged );
+		}
+	return EFalse;
+	}
+
+/**
+Clears the counts that indicate that an event has occurred on the remote server
+for the selected folder since the last sync operation.
+
+This method is called during synchronisation such that subsequent changes are
+identified.
+*/
+void CImapFolder::ClearChangeCounts()
+	{
+	if(iSessionFolderInfo)
+		{
+		// Do not clear exists count 
+		iSessionFolderInfo->SetRecent(0);
+		iSessionFolderInfo->ResetExpungedMessages();
+		iSessionFolderInfo->SetMessageFlagsChanged(EFalse);
+		}
+	iFlagChangedOnly = EFalse;
+	}
+
+/** 
+Set the current entry context on the Message server
+
+@param aId
+The entry id to set in the Message server
+@leave KErrNotFound if the entry does not exist or KErrLocked if the entry is locked.
+*/
+void CImapFolder::SetEntryL(const TMsvId aId)
+	{
+	User::LeaveIfError(iServerEntry.SetEntry(aId));
+	}
+
+/**
+Sets the context's index entry to the specified values on the Message server
+
+@param  aEntry
+The new details for the entry.
+@leave KErrAccessDenied - the entry is read only (deleted entry, standard folder, or locked); 
+KErrNotSupported - aEntry is invalid or the ID specified in aEntry is not the same as the context ID
+or no context has been set for the object; 
+KErrNoMemory - a memory allocation failed. 
+*/
+void CImapFolder::ChangeEntryL(const TMsvEntry& aEntry)
+	{
+	User::LeaveIfError(iServerEntry.ChangeEntry(aEntry));
+	}
+
+/**
+Change entry in bulk mode (i.e no index file commit. no notify)
+
+@param  aEntry
+The new details for the entry.
+@leave KErrAccessDenied - the entry is read only (deleted 
+entry, standard folder, or locked); 
+KErrNotSupported - aEntry is invalid or the 
+ID specified in aEntry is not the same as the context ID or no context has been 
+set for the object; 
+KErrNoMemory - a memory allocation failed.
+*/
+void CImapFolder::ChangeEntryBulkL(const TMsvEntry& aEntry)
+	{
+	User::LeaveIfError(iServerEntry.ChangeEntryBulk(aEntry));
+	}
+
+/**
+Get a list of ids of the children from the current context of the message server.
+
+@param aSelection
+A reference to the email entries selection object which will be filled with the ids of the child entries.
+@leave Error from CMsvServerEntry::GetChildren.
+*/
+void CImapFolder::GetChildrenL(CMsvEntrySelection& aSelection)
+	{
+	User::LeaveIfError(iServerEntry.GetChildren(aSelection));
+	}
+
+/**
+Delete a local message.
+
+@param aMessage
+The TMsvId of the message to be removed from the message server.
+*/
+EXPORT_C void CImapFolder::DeleteMessageL(const TMsvId aMessage)
+	{
+ 	if(aMessage == KMsvNullIndexEntryId)
+		{
+		// Attempted delete of null entry
+ 		return;
+		}
+	// Delete message and all subparts: first, move to parent
+	SetEntryL(aMessage);
+
+	SetEntryL(iServerEntry.Entry().Parent());
+
+	// Do not leave when entry is in use 
+	TInt err (iServerEntry.DeleteEntry(aMessage));
+	if(err == KErrInUse)
+		{
+		// Dont leave if err = KErrInUse
+		}
+	else
+		{
+		User::LeaveIfError(err);
+		}
+	}
+
+/**
+Add a message UID to the list of messages that should have the SEEN flag sets during the SYNC FLAGS stage.
+
+@param aMessage
+The UID of the message to be added to the list of messages to have the SEEN flag set.
+*/
+EXPORT_C void CImapFolder::AppendSetSeenL(const TUint32 aMessage)
+	{
+	if(iSetSeenList)
+		{
+		iSetSeenList->AppendL(aMessage);
+		}
+	else
+		{
+		iSetSeenList = new(ELeave) RArray<TUint>(4);
+		iSetSeenList->AppendL(aMessage);
+		}
+	}
+	
+/**
+Add a message UID to the list of messages that should have the SEEN flag cleared during the SYNC FLAGS stage.
+
+@param aMessage
+The UID of the message to be added to the list of messages to have the SEEN flag cleared.
+*/
+EXPORT_C void CImapFolder::AppendClearSeenL(const TUint32 aMessage)
+	{
+	if(iClearSeenList)
+		{
+		iClearSeenList->AppendL(aMessage);
+		}
+	else
+		{
+		iClearSeenList = new(ELeave) RArray<TUint>(4);
+		iClearSeenList->AppendL(aMessage);
+		}
+	}
+
+/**
+Get MESSAGE ONLY children of a folder. Ignore shadows as they are not going to be synced against the server
+*/
+void CImapFolder::GetMessageChildrenL(const TMsvId aFolder, CMsvEntrySelection* aChildren)
+	{	
+	aChildren->Reset();
+	// Get *all* the children
+	SetEntryL(aFolder);
+	GetChildrenL(*aChildren);
+
+	delete iCachedEntryData;
+	iCachedEntryData = NULL;
+
+	iCachedEntryData = new(ELeave) RArray<TMsvCacheData>(5);
+
+	// Go through them, checking to see if they're messages and removing ones that aren't
+	TInt pos = 0;
+	while(pos < aChildren->Count())
+		{
+		TMsvEntry* entryPtr;
+		TMsvId id = (*aChildren)[pos];
+		User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
+
+		// Is it a message? And is it real (not shadow)
+		if(entryPtr->iType != KUidMsvMessageEntry ||
+			entryPtr->iRelatedId != KMsvNullIndexEntryId )
+			{
+			// No, remove it
+			aChildren->Delete(pos,1);
+			}
+		else
+			{
+			//cache two parts of the TMsvEntry data to avoid having to refind it later
+			TMsvCacheData data;
+			data.iOrphan = ((TMsvEmailEntry)(*entryPtr)).Orphan();
+			data.iUid = ((TMsvEmailEntry)(*entryPtr)).UID();
+			iCachedEntryData->AppendL(data);
+			// Next entry
+			pos++;
+			}
+		}
+	}
+
+/**
+Populates the entry selection with messages that are eligible for auto-fetch.
+Auto fetch is performed as a second synchronisation stage, following the header
+synchronisation. Eligible messages are synchronised according to defined 
+download rules. Note that this method does not filter the returned entry
+selection according to these rules.
+
+@return TInt - number of meesages in the updated selection
+*/
+EXPORT_C TInt CImapFolder::GetFetchMessageChildrenL(CMsvEntrySelection& aSelection)
+	{	
+	aSelection.Reset();
+	// Get *all* the children
+	SetEntryL(iMailboxId);
+	GetChildrenL(aSelection);
+
+	// Go through them, checking to see if they're messages and removing ones that aren't
+	TInt pos = 0;
+	TMsvEntry* entryPtr;
+	while(pos < aSelection.Count())
+		{
+		TMsvId id = (aSelection)[pos];
+		User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
+
+		// Remove entry from the selection if:
+		//   It is not a message
+		//   It is not real (ie it is a shadow entry)
+		//   If has been previously fetched.
+		TBool previouslyFetched = ((TMsvEmailEntry*)entryPtr)->ValidUID();
+		if(entryPtr->iType != KUidMsvMessageEntry ||
+			entryPtr->iRelatedId != KMsvNullIndexEntryId ||
+			previouslyFetched)
+			{
+			aSelection.Delete(pos,1);
+			}
+		else
+			{
+			++pos;
+			}
+		}
+	
+	return aSelection.Count();
+	}
+
+/**
+Transfers the current selection into the iFolderIndex, and sorts it by UID.
+*/
+void CImapFolder::MakeSortedFolderIndexL(TBool aUseCachedEntryData)
+	{
+		
+	TInt noofchildren = iSelection->Count();
+	
+	// Reset folder index
+	iFolderIndex->SetSizeL(noofchildren);
+	TInt acounter = 0;
+
+	if(!aUseCachedEntryData)
+		{ //can't rely on iCachedEntryData
+		TMsvEntry* entryPtr;
+		TMsvId id;
+		for(acounter = 0; acounter < noofchildren; acounter++)
+			{
+			// Save UID/TMsvId of this entry
+			id = (*iSelection)[acounter];
+			User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
+			(*iFolderIndex)[acounter].iUid = ((TMsvEmailEntry)(*entryPtr)).UID();
+			(*iFolderIndex)[acounter].iMsvId = id;
+			}
+		}
+	else
+		{
+		for(acounter = 0; acounter < noofchildren; acounter++)
+			{
+			// Save UID/TMsvId of this entry
+			(*iFolderIndex)[acounter].iUid = (*iCachedEntryData)[acounter].iUid;
+			(*iFolderIndex)[acounter].iMsvId = (*iSelection)[acounter];
+			}
+		}
+
+	// Sort it by UID
+	iFolderIndex->Sort();
+
+	// Check for any duplicate UIDs (ie, a dud netscape server)
+	TMsvEntry* entryPtr;
+	TMsvEntry* nextEntryPtr;
+	for(acounter = 1; acounter < noofchildren; acounter++)
+		{
+		if((*iFolderIndex)[acounter].iUid != 0 && (*iFolderIndex)[acounter].iUid == (*iFolderIndex)[acounter-1].iUid)
+			{
+			if(!aUseCachedEntryData)
+				{
+				// Get the TMsvEntry for the message/folder
+				User::LeaveIfError(iServerEntry.GetEntryFromId((*iFolderIndex)[acounter].iMsvId,entryPtr));
+				User::LeaveIfError(iServerEntry.GetEntryFromId((*iFolderIndex)[acounter-1].iMsvId,nextEntryPtr));
+				// Check if type of TMsvEntry and type of next TMsvEntry are both Messages
+				if( entryPtr->iType.iUid == nextEntryPtr->iType.iUid && entryPtr->iType.iUid == KUidMsvMessageEntryValue)
+					{
+					User::Leave(KErrCorrupt);
+					}
+				}
+			else
+				{
+				User::Leave(KErrCorrupt);
+				}
+			}
+			
+		}
+	}
+
+/**
+Synchronise the local view of the contents with that of the remote folder. 
+If the folder is not the currently in SELECTED state on the CImapSesssion, 
+the first step should be to issue a SELECT command via the IMAP Session
+*/
+EXPORT_C void CImapFolder::SynchroniseL(TRequestStatus& aStatus, CImapSession& aSession, TBool aNewOnly, TInt aDeleteOption)
+	{
+	__LOG_TEXT(aSession.LogId(), "SyncMan: Starting full IMAP Sync");
+	
+	//initialise counters
+	iMsgsDone=0;
+	iMsgsToDo=0;
+	
+	iHeadersFetched=0;
+	iOrphanedMessages=0;
+	iRemoteMessagesDeleteTagged=0;
+	
+	// Saved the calling status request
+	iSavedSession = &aSession;
+	iDeleteOption = aDeleteOption;
+	
+	// Set the Synchronisation states
+	iSyncState = CImapSyncManager::ESynchronise;
+	iNextAction = CImapSyncManager::ESynchronise;
+	iMatchingMessageIds.Reset();
+	
+	// Update the remote folder info and clear the change indication counts
+	UpdateSessionFolderInfoL(*iSavedSession);
+	ClearChangeCounts();
+
+	// Some pre-bits that need doing - get the children & count them
+	// Get the folder info for the selected folder
+	SetEntryL(iMailboxId);
+	TMsvEmailEntry message = iServerEntry.Entry();
+	GetMessageChildrenL(iMailboxId, iSelection);
+	TInt noofchildren = iSelection->Count();
+
+	// Check if new flags for the current selection should be cleared.
+	ClearNewFlagsIfRequiredL();
+		
+	/*
+	First of all check the UIDVALIDITY of the mirror and the 
+	remote folder match - this is indicated by message.ValidUID() returning true.
+	If not, we have to delete everything in the local mirror and start again.
+	We also do this if there are 0 messages in the remote mailbox (0 EXISTS)
+	and there are messages locally
+	*/
+	if(!message.ValidUID() || iMailboxSize == 0)
+		{
+		/*
+		They don't match: do we have local children?
+		If we were doing a new-only sync, change this to a full sync as the 
+		UIDVALIDITY shows major changes.
+		*/
+		aNewOnly = EFalse;
+
+		if(noofchildren)
+			{
+		    // We've got local children then delete them
+			for(TInt a = 0; a < noofchildren; a++)
+				{
+				// We should be skipping locally generated messages. i.e. Offline operations
+				DeleteMessageL((*iSelection)[a]);
+				}
+
+			// Reset the number of children as this may have changed.
+			GetMessageChildrenL(iMailboxId, iSelection);
+			noofchildren = iSelection->Count();
+			}
+
+		// Match the remote's UIDVALIDITY: 
+		// reset the context as it may have been used by the deletion process.
+		SetEntryL(iMailboxId);
+		if(!message.ValidUID())
+			{
+			// Do the change if necessary
+			message.SetUID(iSessionFolderInfo->UidValidity());
+			message.SetValidUID(ETrue);
+			ChangeEntryL(message);
+			}
+		}
+
+	// Any remote messages? If not, complete now as there's nothing else to do
+	if(iMailboxSize == 0)
+		{
+		// This folder is now sync'ed
+		// No need to set seen flags as no messages in remote mailbox
+		SyncCompleteL(); 
+		Queue(aStatus);
+		Complete(KErrNone);
+		return;
+		}
+
+	// Start the synchronise with sync'ing old messages: are there any
+	// messages in our mirror folder?
+ 	iSyncState = CImapSyncManager::ESyncOld; //EImapStateSynchroniseWait;
+	iNextAction = CImapSyncManager::ESyncOld;
+
+	iSomeUnread = EFalse;
+	iHighestUid = 0;
+
+	// Any children?
+	iFolderIndex->Reset();
+	if(noofchildren > 0) 
+		{
+		// Children exist, we need to do an old-sync to check all the messages
+		// are still there.
+		
+		// Build an index of UIDs/TMsvIds currently in the mirror folder, and
+		// sort this by UID: this is the order in which we expect the fetch to
+		// return UIDs - any missing have been deleted on the server. They may
+		// well not be in UID order in the index because locally-appended
+		// messages will not have been added to the index in UID order.
+		TRAPD(err,MakeSortedFolderIndexL(ETrue));
+		if(err != KErrNone)
+			{
+			// Children exist, need to do old sync
+			Queue(aStatus);
+			Complete(err);
+			return;
+			}
+
+		// Find the highest UID in the index
+		iHighestUid = (*iFolderIndex)[noofchildren-1].iUid;
+		}
+
+	// Retrieve folder synchronisation limit.
+	if(iSyncManager.EntryIsInbox(iServerEntry.Entry()))
+		{
+		// Leave iSyncLimit at the maximum if a Search String is set
+		// If no Search String is set and this is the inbox, then use the inbox sync limit.
+		if(iImapSettings.SearchString().Length() == 0)
+			{
+			iSyncLimit = iImapSettings.InboxSynchronisationLimit();	
+			}
+		}
+	else
+		{
+		// Otherwise use the folder sync limit.
+		// Leave iSyncLimit at the maximum if a Search String is set
+		if(iImapSettings.SearchString().Length() == 0)
+			{
+			iSyncLimit = iImapSettings.MailboxSynchronisationLimit();
+			}
+		}
+	
+	// Call function to create and send the search command for the remote server message ids
+	// if there wasn't a command sent then a full sync is needed.
+	if(CreateAndSendUIDSearchStringL(aStatus))
+		{
+		return;
+		}
+		
+	if(noofchildren > 0) 
+		{
+		// A complete list of the message ids on the remote server is needed.
+		if(!aNewOnly && iHighestUid > 0)
+			{
+			// Do old sync
+			iSyncState = CImapSyncManager::ESyncOld;
+			iNextAction = CImapSyncManager::ESyncSearch;
+			
+			iFolderPosition = 0;
+			// If a UID Search String is used it looks like this is FULL sync only 
+			// so leave as is
+			RBuf8 tempstr;
+			tempstr.CleanupClosePushL();
+			
+			TInt tempstrLen = KImapFetchHeaderUIDRange().Length() + KImapMaxIntChars; // KImapFetchHeaderUIDRange provides enough room for "1"
+			tempstr.CreateL(tempstrLen);
+			tempstr.Format(KImapFetchHeaderUIDRange, 1, iHighestUid);
+
+			__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder SynchroniseL : Sending Search for old messages with no synclimits: %S", &tempstr));
+			
+			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
+			// Go active and note that a send has been queued
+			Queue(aStatus);
+			SetActive();
+			
+			CleanupStack::PopAndDestroy(&tempstr);
+			return;
+			}
+		}
+
+	// There was no need to search for old ids hence do new sync
+	SynchroniseNewL();
+	Queue(aStatus);
+	}
+
+/**
+Find the messages available on the remote server by creating and send the string of messages
+to be search for by the session SearchL command.
+
+@param aStatus
+Reference to the request status object to be use for the Search command.
+@return ETrue if the search command has been sent and the folder object has been made Active.
+*/
+TBool CImapFolder::CreateAndSendUIDSearchStringL(TRequestStatus& aStatus)
+	{
+	// Get the user defined UID SEARCH string and if there is one
+	// do a refined search.
+	if(iImapSettings.SearchString().Length() != 0)
+		{
+		iSyncState = CImapSyncManager::ESyncSearch;
+		iNextAction = CImapSyncManager::ESyncSearch;
+		
+		iFolderPosition = 0;
+
+		// Refined search
+		RBuf8 tempstr;
+		tempstr.CleanupClosePushL();
+		
+		TPtrC8 searchstr = iImapSettings.SearchString();
+		
+		TInt tempstrLen = KImapFetchHeaderRangeSearch().Length() + KImapMaxIntChars + searchstr.Length(); // KImapFetchHeaderRangeSearch provides enough room for "1"
+		tempstr.CreateL(tempstrLen);		
+		tempstr.Format(KImapFetchHeaderRangeSearch, 1, Min(iMailboxSize,KImapUidSearchSize), &searchstr);
+		
+		__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder SynchroniseL : Sending Search for old messages with search string: %S", &searchstr));
+		iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
+		
+		// Go active and note that a send has been queued
+		Queue(aStatus);
+		SetActive();
+		
+		CleanupStack::PopAndDestroy(&tempstr);
+		return ETrue;
+		}
+	else
+		{
+		// if no search string we use the old behaviour
+		// Check the folder synchronisation limit.
+		if(iSyncLimit > KImImapSynchroniseNone)
+			{
+			// Limited folder synchronisation, perform a UID search.
+			iSyncState = CImapSyncManager::ESyncSearch;
+			iNextAction = CImapSyncManager::ESyncSearch;
+			
+			iFolderPosition = 0;
+
+			// Perform a UID search on this folder.
+			RBuf8 tempstr;
+			tempstr.CleanupClosePushL();
+						
+			TInt tempstrLen = KImapFetchHeaderRange().Length() + KImapMaxIntChars; // KImapFetchHeaderRange provides enough room for "1"
+			tempstr.CreateL(tempstrLen);			
+			tempstr.Format(KImapFetchHeaderRange, 1, Min(iMailboxSize,KImapUidSearchSize));
+			
+			__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder SynchroniseL : Sending Search for old messages with synclimits: %S", &tempstr));
+			iSavedSession->SearchL(iStatus, tempstr, iMatchingMessageIds);
+			
+			// Go active and note that a send has been queued
+			Queue(aStatus);
+			SetActive();
+			
+			CleanupStack::PopAndDestroy(&tempstr);			
+			return ETrue;
+			}
+		else if(iSyncLimit == KImImapSynchroniseNone)
+			{
+			// No synchronisation required.
+			// This folder is now sync'ed
+			SyncCompleteL();
+			Queue(aStatus);
+			iSyncState = CImapSyncManager::ENotSyncing;
+			// iSyncLimit=KImImapSynchroniseNone, no sync required
+			Complete(KErrNone);
+			return ETrue;
+			}
+		// iSyncLimit <= KImImapSynchroniseAll so Full synchronisation required - fall through.
+		}
+	return EFalse;
+	}
+	
+/**
+Synchronise new messages for a given range.
+*/
+void CImapFolder::SynchroniseRangeL(const TUint32 aLowUid,const TUint32 aHighUid)
+	{
+  
+ 	iSyncState = CImapSyncManager::EFolderSynchronise;
+ 	iNextAction = CImapSyncManager::ESyncFlags;
+	iFolderPosition = 0;
+
+	// First, resize folder index to hold all messages in the folder,
+	// as opposed to the old sync list. This will preserve the old
+	// contents of the index, which is what we want as it's up-to-date
+	// and correct.
+	iFolderIndex->SetSizeL(iMailboxSize);
+	
+	// Create list of priority fields to request
+	// If a UID search string has been specified, the we should create the UID FETCH
+	// string from the UID integer list.
+	if(iImapSettings.SearchString().Length() != 0)
+		{
+		HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(iMatchingMessageIds);
+		iSavedSession->FetchBodyStructureAndHeadersL(iStatus, *sequenceSetOnHeap, KImapSmallHeaderFields(), *this);
+		CleanupStack::PopAndDestroy(sequenceSetOnHeap);
+		}
+	else
+		{
+		RBuf8 tempstr;
+		tempstr.CleanupClosePushL();
+		
+		TInt tempstrLen = KImapFetchHeaderRange().Length() + KImapMaxIntChars + KImapMaxIntChars;
+		tempstr.CreateL(tempstrLen);		
+		tempstr.Format(KImapFetchHeaderRange, aLowUid, aHighUid);
+		
+		iSavedSession->FetchBodyStructureAndHeadersL(iStatus, tempstr, KImapSmallHeaderFields(), *this);
+		
+		CleanupStack::PopAndDestroy(&tempstr);
+		}
+	SetActive();
+	}
+
+/**
+Synchronise new mesasges from current highest UID to end.
+*/
+void CImapFolder::SynchroniseNewL()
+	{
+	iSyncState = CImapSyncManager::ESyncNew;
+	iNextAction = CImapSyncManager::ESyncFlags;
+	iFolderPosition = 0;
+
+	// First, resize folder index to hold all messages in the folder,
+	// as opposed to the old sync list. This will preserve the old
+	// contents of the index, which is what we want as it's up-to-date
+	// and correct.
+	iFolderIndex->SetSizeL(iMailboxSize);
+
+	// Fetch just the header of the new mails
+	RBuf8 tempstr;
+	tempstr.CleanupClosePushL();
+	
+	TInt tempstrLen = KImapFetchHeaderToEnd().Length() + KImapMaxIntChars;
+	tempstr.CreateL(tempstrLen);		
+	tempstr.Format(KImapFetchHeaderToEnd, iHighestUid + 1);
+	
+	iSavedSession->FetchBodyStructureAndHeadersL(iStatus, tempstr, KImapSmallHeaderFields(), *this);
+	SetActive();
+	
+	CleanupStack::PopAndDestroy(&tempstr);
+	}
+
+/**
+Update iDate in iMailboxId to show the time now (last sync time)
+*/
+void CImapFolder::SyncCompleteL()
+	{
+	__LOG_TEXT(iSavedSession->LogId(), "ImapFolder: Starting SyncCompleteL");
+	// Find entry
+	SetEntryL(iMailboxId);
+	TMsvEmailEntry message = iServerEntry.Entry();
+
+	// Find 'now'
+	message.iDate.UniversalTime();
+
+	// Check to see if there has been a change in the number of messages in the remote folder.
+	TBool folderSizeChanged = (message.RemoteFolderEntries()!=iMailboxSize);
+
+	// Set 'unread' flag on folder if there are any unread messages within it
+	if(message.Unread() != iSomeUnread || !message.Visible() || folderSizeChanged)
+		{
+		// Update flags
+		message.SetUnread(iSomeUnread);
+		message.SetVisible(ETrue);
+		message.SetRemoteFolderEntries(iMailboxSize);
+ 		ChangeEntryBulkL(message); // completed at the end of this method
+		}
+
+	// we need to ensure the hierarchy of folders containing this one
+	// is now visible. Note previously this incorrectly only did this
+	// when we were not in DisconncetedUserMode
+	do
+		{
+		// Move up one
+		SetEntryL(message.Parent());
+		message=iServerEntry.Entry();
+
+		// Ensure visibility
+		if(!message.Visible())
+			{
+			message.SetVisible(ETrue);
+			ChangeEntryBulkL(message); // completed at the end of this method
+			}
+		}
+	while(message.iType!=KUidMsvServiceEntry);
+	
+
+	// commit any outstanding entries to the index file to complete the bulk
+	// synchronization operation
+	iServerEntry.CompleteBulk();
+	
+	// Set the current id to null so that we aren't locking any folders
+	SetEntryL(KMsvNullIndexEntryId);
+	}
+
+/**
+Reset subscription flags for all children, and recurse into folders
+*/
+void CImapFolder::ResetSubscriptionFlagsL(const TMsvId aFolder)
+	{
+	// Do this one
+	SetEntryL(aFolder);
+	TMsvEmailEntry entry = iServerEntry.Entry();
+
+	// A folder or service? If not, return
+	if(entry.iType != KUidMsvServiceEntry &&
+		entry.iType != KUidMsvFolderEntry)
+		{
+		return;
+		}
+
+	// Reset flag if needed
+	if(entry.Subscribed())
+		{
+		// Reset flag and save
+		entry.SetSubscribed(EFalse);
+		ChangeEntryL(entry);
+		}
+
+	// Any children?
+	CMsvEntrySelection *children = new (ELeave) CMsvEntrySelection;
+	CleanupStack::PushL(children);
+	GetChildrenL(*children);
+	if(children->Count())
+		{
+		// Do each in turn
+		for(TInt child = 0; child < children->Count(); child++)
+			ResetSubscriptionFlagsL((*children)[child]);
+		}
+	CleanupStack::PopAndDestroy();
+	}
+
+/**
+Performs any outstanding offline delete operations
+
+deletes from the remote server any messages marked /deleted locally.
+*/
+EXPORT_C void CImapFolder::SyncDeletesL(TRequestStatus& aStatus, CImapSession& aSession)
+	{
+	iSavedSession = &aSession;
+
+	SetEntryL(iMailboxId);
+	GetMessageChildrenL(iMailboxId, iSelection);
+	TRAPD(err,MakeSortedFolderIndexL(ETrue));
+	if(err!=KErrNone)
+		{
+		Queue(aStatus);
+		Complete(err);
+		return;
+		}
+	TInt pos = 0;
+	TInt deleted = 0;
+
+	// Build command
+	HBufC8* command=HBufC8::NewLC(256);
+	RArray<TUint>	deletingMessageIds;
+	
+	// Start command
+	//command->Des().Append(_L8("UID STORE "));
+	
+	iDeletedMessageIds.Reset();
+	iMessageFlagInfoArray.Reset();
+
+	while(pos < iFolderIndex->Size())
+		{
+		// Look for messages with deleted flag set
+		SetEntryL((*iFolderIndex)[pos].iMsvId);
+		if(((TMsvEmailEntry)iServerEntry.Entry()).DeletedIMAP4Flag())
+			{
+			__LOG_FORMAT((aSession.LogId(), "Message id %x marked as deleted",iServerEntry.Entry().Id()));
+			++iRemoteMessagesDeleteTagged;
+			
+			// Append to the delete list
+			TInt64 uid=(TUint)((TMsvEmailEntry)iServerEntry.Entry()).UID();
+			deletingMessageIds.Append(uid);
+			// index of local message in iFolderIndex to be deleted
+			iDeletedMessageIds.Append(pos);
+			++deleted;
+			}
+
+		// Next message
+		pos++;
+		}
+
+	// Anything deleted?
+	if(deleted)
+		{
+		// Append flags & send command
+		_LIT8(KDeleteFlag,"+FLAGS");
+		_LIT8(KDeleteItem,"(\\Deleted)");
+		command->Des().Append(KDeleteFlag);
+		
+		HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(deletingMessageIds);
+		// Call the STORE function in the session
+		aSession.StoreL(iStatus, *sequenceSetOnHeap, KDeleteFlag(), KDeleteItem(), ETrue, iMessageFlagInfoArray);
+		CleanupStack::PopAndDestroy(sequenceSetOnHeap);
+		
+		Queue(aStatus);
+		SetActive();
+		iSyncState = CImapSyncManager::EFolderEarlyExpunge;
+				
+		if (iImapSettings.UseExpunge())
+			{
+			iNextAction = CImapSyncManager::EFolderExpunge;
+			}
+		else
+			{
+			iNextAction = CImapSyncManager::EFolderClose;
+			}
+		}
+	else
+		{
+		// Nothing to do just complete
+		Queue(aStatus);
+		Complete(KErrNone);
+		}
+
+	// Get rid of command buffer
+	CleanupStack::PopAndDestroy(command);
+	}
+
+/**
+Enquote a string (being sent as a string literal) if required
+*/
+EXPORT_C void CImapFolder::DoQuoteL(HBufC16*& aBuffer)
+	{
+	// Null string? Nothing to do
+	if(!aBuffer->Length() || !aBuffer->Des().Length())
+		{
+		return;
+		}
+
+	// Anything needing quoting in there?
+	if(aBuffer->Des().Locate('\\') == KErrNotFound &&
+		aBuffer->Des().Locate('\"') == KErrNotFound)
+		{
+		return;
+		}
+
+	// Run through string, inserting quote characters as needed
+	for(TInt a = 0; a<aBuffer->Des().Length(); a++)
+		{
+		if(aBuffer->Des()[a] == '\\' || aBuffer->Des()[a] == '\"')
+			{
+			HBufC16 *newbuf = aBuffer->ReAllocL(aBuffer->Des().Length()+1);
+
+			// Been moved due to realloc?
+			if(newbuf != aBuffer)
+				{
+				// In all cases when DoQuoteL() is called, the buffer is on the top of
+				// the cleanup stack: change this to indicate the correct entry
+				CleanupStack::Pop();
+				CleanupStack::PushL(aBuffer = newbuf);
+				}
+
+			aBuffer->Des().Insert(a, KQuoteChar);
+			a++;
+			}
+		}
+	}
+
+
+/**
+Implementation of the observer function for the session fetch command. For each call
+creates the required entry tree.
+*/
+void CImapFolder::OnFetchLD(CImapFetchResponse* aImapFetchResponse)
+	{
+	// Take ownership of parameter
+	CleanupStack::PushL(aImapFetchResponse);
+	
+	CImapRfc822HeaderFields* headerinfo = aImapFetchResponse->HeaderFields();
+	CImapBodyStructure* bodystructure = aImapFetchResponse->BodyStructure();
+	
+	//update the progress object
+	++iMsgsDone;
+	++iHeadersFetched;
+
+	if(headerinfo)
+		{
+		TUint remoteUid = aImapFetchResponse->MessageUid();
+		if(iFolderIndex->Size() > 0)
+			{
+			if(iFolderIndex->FindMsg(remoteUid) != 0)
+				{
+				CleanupStack::PopAndDestroy(aImapFetchResponse);
+				return;
+				}
+			}
+		// Create an email entry in this folder.
+		SetEntryL(iMailboxId);
+
+		// Skeleton for new entry
+		TMsvEmailEntry entry;
+		TFileName attachmentFilename;	//	Attachment filename
+
+		entry.iSize = 0;
+		entry.iType = KUidMsvMessageEntry;
+		entry.iMtm = KUidMsgTypeIMAP4;
+		entry.iServiceId = iImapSettings.ServiceId();
+		entry.SetValidUID(EFalse);		// reuse ValidUID Flag record if the message has ever been fetched
+		entry.SetComplete(EFalse);
+		entry.SetUnread(ETrue);
+		entry.SetNew(ETrue);
+		entry.SetUID(aImapFetchResponse->MessageUid());
+
+		// Set from line in TMsvEntry
+		const TDesC8& temp2 = headerinfo->FieldValue(CImapRfc822HeaderFields::EImapFrom);
+		HBufC* decodedFromBuffer = HBufC::NewLC(temp2.Length());
+		TPtr decodedFromPtr(decodedFromBuffer->Des());
+
+		iHeaderConverter.DecodeHeaderFieldL(temp2, decodedFromPtr);
+		entry.iDetails.Set(decodedFromPtr);
+		
+		// Set subject in TMsvEntry
+		const TDesC8& temp3 = headerinfo->FieldValue(CImapRfc822HeaderFields::EImapSubject); 
+		HBufC* decodedSubjectBuffer = HBufC::NewLC(temp3.Length());
+		TPtr decodedSubjectPtr(decodedSubjectBuffer->Des());
+
+		iHeaderConverter.DecodeHeaderFieldL(temp3, decodedSubjectPtr);
+		entry.iDescription.Set(decodedSubjectPtr);
+
+		// Set the Date
+		entry.iDate = headerinfo->Date();
+
+		// Set the priority field
+		entry.SetPriority(headerinfo->PriorityL());
+
+		if (bodystructure)
+			{
+			SetMessageFlagsL(entry, bodystructure);
+			}
+
+		// Set the flags
+		TBool messageInfoSeen = aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::ESeen);
+
+		entry.SetSeenIMAP4Flag(messageInfoSeen);
+		entry.SetAnsweredIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EAnswered));
+		entry.SetFlaggedIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EFlagged));
+		entry.SetDeletedIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EDeleted));
+		entry.SetDraftIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::EDraft));
+		entry.SetRecentIMAP4Flag(aImapFetchResponse->MessageFlagInfo().QueryFlag(TMessageFlagInfo::ERecent));
+		
+		// Are we configured to update the \seen flag on the server?
+		if (iImapSettings.UpdatingSeenFlags())
+			{
+			// Now copy the inverse of the \Seen flag down to the clients Unread flag
+			if (messageInfoSeen)
+				{
+				entry.SetUnread(EFalse);
+				}
+			}
+		
+		// note that an unread message has been spotted.
+		if(!entry.SeenIMAP4Flag() || entry.RecentIMAP4Flag())
+			{
+			iSomeUnread	= ETrue;
+			}
+		
+		// If sync'ing to download rules is disabled, mark that message as
+		// "fetched"  using the re-used ValidUID flag. This prevents the
+		// message from being sync'd according to download rules if rules
+		// are subsequently enabled.
+		if(!iImapSettings.UseSyncDownloadRules())
+			{
+			entry.SetValidUID(ETrue);
+			}
+
+		// Create message
+		User::LeaveIfError(iServerEntry.CreateEntryBulk(entry));
+		// The matching CompleteBulk() is called in OnFetchCommit() and the ESyncFlags section of the DoRunL()
+		// that is called after FetchBodyStructureAndHeadersL() has completed.
+		__ASSERT_DEBUG(iNextAction == CImapSyncManager::ESyncFlags, User::Invariant());
+		CleanupStack::PopAndDestroy(decodedSubjectBuffer);
+		CleanupStack::PopAndDestroy(decodedFromBuffer);
+		}
+		
+	CleanupStack::PopAndDestroy(aImapFetchResponse);
+	}
+	
+void CImapFolder::OnFetchCommit()
+	{
+	iServerEntry.CompleteBulk();
+	}
+
+/**
+Set or clear the \\Seen flags on the server
+
+@param aUpdateMode
+ETrue -> Sets the flag
+@return False if no messages need to be processed
+*/
+TBool CImapFolder::ProcessSeenFlagsL(TSeenFlagUpdateMode aUpdateMode)
+	{
+	RArray<TUint>* pendingList;
+	TBool settingFlag = (aUpdateMode == ESetSeenFlag);
+
+	// Point pendingList to the correct list
+	pendingList = (settingFlag ? iSetSeenList: iClearSeenList);
+	
+	// Exit if nothing to process
+	if(!pendingList->Count())
+		{
+		return EFalse;
+		}
+	
+	__LOG_FORMAT((iSavedSession->LogId(), "CImapFolder : ProcessSeenFlags(%d)", aUpdateMode));
+
+	_LIT8(KStoreFlagsSetCommand, "+FLAGS");
+	_LIT8(KStoreFlagsClearCommand, "-FLAGS");
+	_LIT8(KStoreFlagsSeenCommand,"(\\Seen)");
+	
+	iMessageFlagInfoArray.Reset();
+
+	HBufC8* sequenceSetOnHeap = CImapSession::CreateSequenceSetLC(*pendingList);
+
+	// Call the STORE function in the session
+	if(settingFlag)
+		{
+		iSavedSession->StoreL(iStatus, *sequenceSetOnHeap, KStoreFlagsSetCommand(), KStoreFlagsSeenCommand(), ETrue, iMessageFlagInfoArray);
+		}
+	else
+		{
+		iSavedSession->StoreL(iStatus, *sequenceSetOnHeap, KStoreFlagsClearCommand(), KStoreFlagsSeenCommand(), ETrue, iMessageFlagInfoArray);
+		}
+	
+	CleanupStack::PopAndDestroy(sequenceSetOnHeap);
+	
+	SetActive();
+
+	// Reset the list
+	pendingList->Reset();
+
+	return ETrue;
+	}
+
+/**
+Construct a full mailbox path for the folder object
+This is expensive in memory movement terms, as it works UP the path,
+inserting new data at the start. This is based on the principle that it's
+more expensive to find an entry in the index with SetEntryL() than it is to
+move some bytes about, otherwise we'd find the path upwards then create the
+string downwards.
+*/
+EXPORT_C HBufC16* CImapFolder::MakePathL(const TBool aIncludeLeaf)
+	{
+	// Making a path: we start with nothing
+	HBufC16 *path = HBufC16::NewLC(256);
+	TBool skipfirst = ETrue;
+	TMsvId traverse = iMailboxId;
+
+	// Move to the entry
+	User::LeaveIfError(iServerEntry.SetEntry(traverse));
+
+	// Skipping the leaf?
+	if(!aIncludeLeaf && iServerEntry.Entry().iType != KUidMsvServiceEntry)
+		{
+		// Up a level before we generate the path
+		traverse = iServerEntry.Entry().Parent();
+		User::LeaveIfError(iServerEntry.SetEntry(traverse));
+		}
+
+	// Check and see if we are dealing with the INBOX, in which case return immediately
+	if (iSyncManager.EntryIsInbox(iServerEntry.Entry()))
+		{
+		path->Des().Insert(0,KIMAP_INBOX);
+		CleanupStack::Pop(path);
+		return path;
+		}
+
+	// While we can still go up within this service...
+	while(iServerEntry.Entry().iType != KUidMsvServiceEntry)
+		{
+		// Make sure the path maxlength is still ok with the added folder name and an extra separator character
+		if((path->Length() + iServerEntry.Entry().iDetails.Length() + 1) > path->Des().MaxLength())
+			{
+			HBufC16* newpath = path->ReAllocL(path->Length() + iServerEntry.Entry().iDetails.Length() + 1);
+			if(path != newpath)
+				{
+				CleanupStack::Pop(path);
+				path = newpath;
+				CleanupStack::PushL(path);
+				}
+			}
+
+		// Add the name of this component to the path
+		if(!skipfirst)
+			{
+			path->Des().Insert(0,iImapSettings.PathSeparator());
+			}
+		else
+			{
+			skipfirst = EFalse;
+			}
+
+		// Ensure uppercase 'INBOX' is used in folder name. This allows case
+		// sensitive searches to be used later.
+		if (iSyncManager.EntryIsInbox(iServerEntry.Entry()))
+			{
+			path->Des().Insert(0,KIMAP_INBOX);
+			}
+		else
+			{
+			path->Des().Insert(0,iServerEntry.Entry().iDetails);
+			}
+
+		// Go up a level
+		SetEntryL(traverse = iServerEntry.Entry().Parent());
+		}
+	
+	// Add the path at the very start, if it exists
+	if(iImapSettings.FolderPath().Length())
+		{
+		// Make sure the path maxlength is still ok with the added folder path and an extra separator character
+		if((path->Length() + iImapSettings.FolderPath().Length() + 1) > path->Des().MaxLength())
+			{
+			HBufC16* newpath = path->ReAllocL(path->Length() + iImapSettings.FolderPath().Length() + 1);
+			if(path != newpath)
+				{
+				CleanupStack::Pop(path);
+				path = newpath;
+				CleanupStack::PushL(path);
+				}
+			}
+
+		// Anything there already? If not, don't bother with the separator
+		if(path->Des().Length()) 
+			{
+			path->Des().Insert(0,iImapSettings.PathSeparator());	
+			}
+		
+		RBuf tempstr;
+		tempstr.CleanupClosePushL();
+		tempstr.CreateL(iImapSettings.FolderPath().Length());
+		
+		tempstr.Copy(iImapSettings.FolderPath());
+		path->Des().Insert(0, tempstr);
+		
+		CleanupStack::PopAndDestroy(&tempstr);
+		}
+
+	// Pop it off cleanup stack
+	CleanupStack::Pop(path);
+
+	// Return the path
+	return(path);
+	}
+
+void CImapFolder::CompleteSelf()
+	{
+// Complete self.
+	TRequestStatus* status = &iStatus;
+	iStatus = KRequestPending;
+	User::RequestComplete(status, KErrNone);
+	}
+
+/**
+Returns updated progress information on outstanding synchronisation operations.
+*/
+EXPORT_C void CImapFolder::Progress(TImap4SyncProgress& aProgress)
+	{
+	//copy values from member progress ob into aProgress
+	aProgress.iMsgsDone=iMsgsDone;
+	aProgress.iMsgsToDo=iMsgsToDo;
+	
+	aProgress.iHeadersFetched = iHeadersFetched;	
+	aProgress.iOrphanedMessages = iOrphanedMessages;
+	aProgress.iRemoteMessagesDeleteTagged = iRemoteMessagesDeleteTagged;
+	
+	if(iImapSettings.SearchString().Length() != 0)
+		{
+		aProgress.iMsgsToDo=iMailboxSize;	
+		}
+	else
+		{
+		aProgress.iMsgsToDo=(iSyncLimit<=0)?iMailboxSize:Min(iMailboxSize,iSyncLimit);	
+		}
+	aProgress.iMsgsDone = Min(iMsgsDone,aProgress.iMsgsToDo);	
+		
+	}
+
+/**
+Sets various flags in the message entry by doing a quick scan of the
+bodystructure. This routine is intended to be relatively straightforward
+so as not to impact performance during the sync phase too much.
+
+@param aEntry Entry to set flags for
+@param aBodyStructure Message body structure 
+*/
+void CImapFolder::SetMessageFlagsL(TMsvEmailEntry& aEntry, CImapBodyStructure* aBodyStructure)
+	{
+	TBool hasAttachments(EFalse);
+	TBool hasHtml(EFalse);
+	TBool afterRelated(EFalse);
+	TBool afterAlternative(EFalse);
+	TBool htmlAfterAltRel(EFalse);
+	TBool hasICalendar(EFalse);
+	TBool hasVCalendar(EFalse);
+	TInt size(0);
+
+	// Check if top level of message contains attachment type
+	if ((aBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeBasic) &&
+	    ((aBodyStructure->Type().CompareF(KImapTxtImage) == 0) ||
+	     (aBodyStructure->Type().CompareF(KImapTxtAudio) == 0) ||
+	     (aBodyStructure->Type().CompareF(KImapTxtVideo) == 0) ||
+	     (aBodyStructure->Type().CompareF(KImapTxtApplication) == 0)))
+		{
+		hasAttachments = ETrue;
+		}
+
+	RPointerArray<CImapBodyStructure> bodyStructureStack;
+	bodyStructureStack.AppendL(aBodyStructure);
+
+	TInt count;
+
+	// A body structure stack is maintained. This avoids the use of recursion
+	// when processing the embedded body structure list at each level, and also
+	// maintains the order of processing that the old IMAP implementation used.
+	// As nobody could explain exactly why the old code used this order, it was
+	// felt that it was safer that the new implementation matched the old.
+	while (bodyStructureStack.Count() > 0)
+		{
+		GetFlagsForBodyStructurePart(bodyStructureStack[0], hasAttachments, hasHtml, afterRelated, afterAlternative, htmlAfterAltRel, hasICalendar, hasVCalendar, size);
+
+		for (count = 0; count < bodyStructureStack[0]->EmbeddedBodyStructureList().Count(); ++count)
+			{
+			bodyStructureStack.AppendL(bodyStructureStack[0]->EmbeddedBodyStructureList()[count]);
+			}
+
+		bodyStructureStack.Remove(0);
+		}
+
+	aEntry.SetAttachment(hasAttachments);
+	aEntry.SetMHTMLEmail(hasHtml || htmlAfterAltRel);
+	aEntry.SetICalendar(hasICalendar);
+	aEntry.SetVCalendar(hasVCalendar);
+	aEntry.iSize = size;
+	bodyStructureStack.Reset();
+	}
+
+/**
+Gets a set of flags for a body structure part
+
+@param aBodyStructure Body structure part
+@param aHasAttachments Flag to indicate if message contains attachments
+@param aHasHtml Flag to indicate if message has HTML part
+@param aAfterRelated Flag to indicate a multipart/related part has been found
+@param aAfterAlternative Flag to indicate a multipart/alternative part has been found
+@param aHtmlAfterAltRel Flag to indicate a HTML part has been found after a multipart/related or multipart/alternative part
+@param aHasICalendar Flag to indicate message contains ICalendar
+@param aHasVCalendar Flag to indicate message contains VCalendar
+@param aSize Running total of size of message
+*/
+void CImapFolder::GetFlagsForBodyStructurePart(CImapBodyStructure* aBodyStructure,
+                                               TBool& aHasAttachments, TBool& aHasHtml,
+                                               TBool& aAfterRelated, TBool& aAfterAlternative,
+                                               TBool& aHtmlAfterAltRel, TBool& aHasICalendar,
+                                               TBool& aHasVCalendar, TInt& aSize)
+	{
+	switch (aBodyStructure->BodyStructureType())
+		{
+		case CImapBodyStructure::ETypeMultipart:
+			{
+			if (aBodyStructure->SubType().CompareF(KImapTxtRelated) == 0)
+				{
+				aAfterRelated = ETrue;
+				}
+			else if (aBodyStructure->SubType().CompareF(KImapTxtAlternative) == 0)
+				{
+				aAfterAlternative = ETrue;
+				}
+			else if (aBodyStructure->SubType().CompareF(KImapTxtMixed) == 0)
+				{
+				aHasAttachments = ETrue;
+				}
+			
+			break;
+			}
+
+		case CImapBodyStructure::ETypeText:
+			{
+			if (aBodyStructure->SubType().CompareF(KImapTxtHtml) == 0)
+				{
+				if (aBodyStructure->ExtDispositionName().CompareF(KImapTxtAttachment) != 0)
+					{
+					aHasHtml = ETrue;
+					}
+
+				if (aAfterRelated || aAfterAlternative)
+					{
+					aHtmlAfterAltRel = ETrue;
+					}
+				}
+			else if (aBodyStructure->SubType().CompareF(KImapTxtCalendar) == 0)
+				{
+				aHasICalendar = ETrue;
+				}
+			else if (aBodyStructure->SubType().CompareF(KImapTxtXVCalendar) == 0)
+				{
+				aHasVCalendar = ETrue;
+				}
+
+			break;
+			}
+
+		case CImapBodyStructure::ETypeMessageRfc822:
+			{
+			return;
+			}
+
+		default:
+			{
+			if (aBodyStructure->SubType().CompareF(KImapTxtDeliveryStatus) == 0)
+				{
+				aHasAttachments = ETrue;
+				}
+
+			break;
+			}
+		}
+
+	// Add size of this body part to the running total
+	TInt size(0);
+	TLex8 lex(aBodyStructure->BodySizeOctets());
+	lex.Val(size);
+
+	// For Base64, use the pre encoding data size
+	if (aBodyStructure->BodyEncoding().CompareF(KImapTxtBase64) == 0)
+		{
+		size = (size * 3) / 4;
+		}
+
+	aSize += size;
+	}
+
+/**
+Checks if we need to clear the new flags on the messages in the folder,
+and if so clears them.
+@pre Current selection (iSelection) contains all the messages in the folder.
+*/
+void CImapFolder::ClearNewFlagsIfRequiredL()
+	{
+	if (iSyncManager.EntryIsInbox(iServerEntry.Entry()))
+		{
+		if (iSyncManager.InboxClearNewFlags())
+			{
+			__LOG_TEXT(iSavedSession->LogId(), "CImapFolder: Clearing new flags (inbox)");
+			
+			// Change attributes on the current selection
+			User::LeaveIfError(iServerEntry.ChangeAttributes(*iSelection, 0, KMsvNewAttribute));
+
+			// Set the flag to False to indicate that we have cleared the flags
+			// on the inbox, and so any subsequent synchronise of the inbox
+			// will not clear them again.
+			iSyncManager.ResetInboxClearNewFlags();
+			}
+		}
+	else
+		{
+		if (iSyncManager.NonInboxClearNewFlags())
+			{
+			__LOG_TEXT(iSavedSession->LogId(), "CImapFolder: Clearing new flags (non inbox)");
+
+			// Change attributes on the current selection
+			User::LeaveIfError(iServerEntry.ChangeAttributes(*iSelection, 0, KMsvNewAttribute));
+			
+			// Note that we do not clear the flag here as it will be required
+			// for any subsequent non inbox folders that are yet to be synced.
+			}
+		}
+	}
+
+/**
+Sets the folder matched flag
+
+@param aFolderMatched Value to set flag to
+*/
+void CImapFolder::SetFolderMatched(TBool aFolderMatched)
+	{
+	iFolderMatched = aFolderMatched;
+	}
+
+/**
+Gets the folder matched flag
+
+@return Folder matched flag value
+*/
+TBool CImapFolder::FolderMatched()
+	{
+	return iFolderMatched;
+	}
+
+/**
+Performs comparison between two folders by comparing their folder names.
+
+@param aFirst The first folder to compare
+@param aSecond The second folder to compare
+
+@return The result of calling Compare on the folder names
+*/
+TInt CImapFolder::CompareByFolderName(const CImapFolder& aFirst, const CImapFolder& aSecond)
+// static method
+	{
+	return aFirst.iFullFolderPath.Compare(aSecond.iFullFolderPath);
+	}