email/imap4mtm/imapsyncmanager/src/cimapsyncmanager.cpp
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/imap4mtm/imapsyncmanager/src/cimapsyncmanager.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,1566 @@
+// Copyright (c) 2006-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:
+// imapsyncmanager.cpp
+// 
+//
+
+
+#include "cimapsyncmanager.h"
+#include "cimapopsyncfoldertree.h"
+#include "cimapopsyncsubs.h"
+#include "cimapfolder.h"
+#include "cimapsessionconsts.h"
+#include "cimaplogger.h"
+
+#ifdef __IMAP_LOGGING
+#include <utf.h>
+#endif
+
+// Inbox mailbox name
+_LIT(KIMAP_INBOX, "INBOX");
+
+// Inbox mailbox name used for display purposes
+_LIT(KImapInboxDisplayName, "Inbox");
+
+/**
+Private default class constructor
+*/
+CImapSyncManager::CImapSyncManager(CMsvServerEntry& aEntry, CImapSettings& aImapSettings)
+:	CMsgActive(EPriorityStandard), 
+	iServerEntry(aEntry), 
+	iImapSettings(aImapSettings),
+	iInboxClearNewFlags(ETrue),
+	iNonInboxClearNewFlags(ETrue)
+	{
+	}
+
+/**
+Class destructor
+*/
+CImapSyncManager::~CImapSyncManager()
+	{
+	delete iFolderTreeSync;
+	delete iSyncSubs;
+	delete iSubscribeList;
+	delete iUnsubscribeList;
+	delete iInbox;
+	iFolderList.ResetAndDestroy();
+	}
+
+/**
+Static factory constructor
+
+@param aServiceId
+The TMsvId of the Imap service that is being accessed.
+@param aOffLine The CImapOfflineControl that provides access methods to pending offline operations
+@return The constructed CImapSuncManager object pushed onto the cleanup stack
+*/
+EXPORT_C CImapSyncManager* CImapSyncManager::NewLC(CMsvServerEntry& aEntry, CImapSettings& aImapSettings)
+	{
+	CImapSyncManager* self=new (ELeave) CImapSyncManager( aEntry, aImapSettings);
+	CleanupStack::PushL(self);
+
+	// Non-trivial constructor
+	self->ConstructL();
+	return self;
+	}
+
+/**
+Static factory constructor with cleanup
+
+@param aServiceId
+The TMsvId of the Imap service that is being accessed.
+@param aOffLine The CImapOfflineControl that provides access methods to pending offline operations
+@return The constructed CImapSuncManager object
+*/
+EXPORT_C CImapSyncManager* CImapSyncManager::NewL(CMsvServerEntry& aEntry, CImapSettings& aImapSettings)
+	{
+	CImapSyncManager* self=NewLC( aEntry, aImapSettings);
+	CleanupStack::Pop();
+	return self;
+	}
+
+/**
+The non-trival constructor. Initialise the data members and create the subcribed local folder list
+*/
+void CImapSyncManager::ConstructL()
+	{
+
+	// Get the flags from iImapSettings
+	iSynchroniseStrategy = iImapSettings.Synchronise();
+	iSubscribeStrategy = iImapSettings.Subscribe();
+	iServiceId = iImapSettings.ServiceId();
+	// Find the inbox
+	GetInboxL();
+	// Create the list for the rest of the folders
+	iSubscribeList=new (ELeave) RArray<TUint>(4);
+	iUnsubscribeList=new (ELeave) RArray<TUint>(4);
+	CreateLocalFolderListL();
+	// We're an active object...
+	CActiveScheduler::Add(this);
+	}
+
+	
+/** 
+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 CImapSyncManager::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 CImapSyncManager::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 CImapSyncManager::ChangeEntryBulkL(const TMsvEntry& aEntry)
+	{
+	User::LeaveIfError(iServerEntry.ChangeEntryBulk(aEntry));
+	}
+
+/**
+Return a list of all child entries of the currently selected entry node.
+
+@param  aSelection
+The ids for the found child entries will be put into this parameter
+*/
+void CImapSyncManager::GetChildrenL(CMsvEntrySelection& aSelection)
+	{
+	User::LeaveIfError(iServerEntry.GetChildren(aSelection));
+	}
+
+/** 
+Returns a pointer to the CImapFolder object associated with the passed entry ID.
+CImapSyncManager maintains an array of CImapFolder objects that are subscribed
+according to sync and subscribe strategy settings - if the folder exists in this
+array then the pointer to this instance is returned. Otherwise a CImapFolder
+instance is created for the specified folder and appended to the list.
+
+As the folder list is rebuilt on folder tree synscronisation, code using this
+API cannot expect a returned pointer to remain valid following an account or
+folder tree synchronisation operation.
+
+This method preserves the context of the shared CMsvServerEntry
+
+@param aMsvId The TMsvId of the folder as stored in the message server
+
+@param aAddToSubscribedList holds bool value,  ETure adds to subscribed list, EFalse does not add.
+
+@return NULL if the folder does not exist, pointer to the CImapFolder object otherwise.
+*/
+EXPORT_C CImapFolder* CImapSyncManager::GetFolderL(TMsvId aMsvId, TBool aAddToSubscribedList)
+	{
+	TMsvId preservedId = iServerEntry.Entry().Id();
+	
+	// Retrieve the folder from the maintained list if it is present.
+	// Will be present if it is subscribed according to settings.
+	CImapFolder* folder = GetFolderFromList(aMsvId);
+	
+	if (folder==NULL)
+		{
+		// Requested folder is not in the list of subscribed mailboxes.
+		// It may have been subscribed locally since the last folder sync 
+		// operation, or the client application may be attempting to access
+		// a non-subscribed folder.
+		// Create an instance for the folder and add it to the folder list.
+		SetEntryL(aMsvId);
+		TMsvEmailEntry entry = iServerEntry.Entry();
+		folder = CImapFolder::NewLC(*this, iServerEntry, entry, iImapSettings, KNullDesC());
+		if(aAddToSubscribedList)
+			{
+			iFolderList.AppendL(folder);
+			}
+		CleanupStack::Pop(folder);
+
+		// recover original serverentry context
+		SetEntryL(preservedId);
+		}
+	return folder;
+	}
+
+/**
+Returns a pointer to the CImapFolder object associated with the passed entry ID,
+if it appears in the array of CImapFolders.
+
+@param aMsvId The TMsvId of the folder as stored in the message server
+@return NULL if the folder is not in the list, pointer to the CImapFolder object otherwise.
+*/
+CImapFolder* CImapSyncManager::GetFolderFromList(TMsvId aMsvId)
+	{
+	// Check the inbox first
+	if(iInbox)
+		{
+		if(iInbox->MailboxId() == aMsvId)
+			{
+			return iInbox;
+			}
+		}
+		
+	TInt count = iFolderList.Count();
+	
+	for(TInt i = 0; i < count; i++)
+		{
+		if(iFolderList[i]->MailboxId() == aMsvId)
+			{
+			return iFolderList[i];
+			}
+		}
+
+	// the folder does not exist
+	return NULL;
+	}
+
+/** 
+This function populates the CImapfolder object passed in by the caller using the TMsvId given to get the relevent folder from
+the message server.
+
+@param aMsvId.
+The TMsvId of the folder as stored in the message server to be use to find the imap folder 
+@return Returns NULL if the folder is not subscribed or does not exist, pointer to the CImapFolder object otherwise.
+*/
+EXPORT_C CImapFolder* CImapSyncManager::GetTempFolderL(TMsvId aMsvId)
+	{
+	CImapFolder* tempfolder = NULL;
+	SetEntryL(aMsvId);
+	TMsvEmailEntry entry = iServerEntry.Entry();
+	tempfolder = CImapFolder::NewLC(*this, iServerEntry, entry, iImapSettings, KNullDesC());
+	CleanupStack::Pop(tempfolder);
+		
+	return tempfolder;
+	}
+
+/** 
+This function populates the CImapfolder object that represent the current service Inbox
+
+@return Returns the pointer to the CImapFolder representing the Inbox.
+*/
+EXPORT_C CImapFolder* CImapSyncManager::Inbox()
+	{
+	return iInbox;
+	}
+	
+RArray<TUint>* CImapSyncManager::GetUnSubscribedFolderToDoList()
+	{
+	return iUnsubscribeList;
+	}
+	
+RArray<TUint>* CImapSyncManager::GetSubscribedFolderToDoList()
+	{
+	return iSubscribeList;
+	}
+
+
+/** 
+Search through the messaging server to find the entry that represented the inbox and if not already
+in the list of CImapFolder objects, create one.
+*/
+void CImapSyncManager::GetInboxL()
+	{
+
+	// Remove the old inbox
+	delete iInbox;
+	iInbox = NULL;
+		
+	// First of all, synchronise the inbox
+	CMsvEntrySelection *findinbox=new (ELeave) CMsvEntrySelection;
+	CleanupStack::PushL(findinbox);
+	SetEntryL(iServiceId);
+	GetChildrenL(*findinbox);
+	
+	// Find inbox	
+	TMsvId inboxid=0;
+	for(TInt a=0;a<findinbox->Count();a++)
+		{
+		SetEntryL((*findinbox)[a]);
+		if(iServerEntry.Entry().iDetails.CompareF(KIMAP_INBOX)==0)
+			{
+			inboxid=(*findinbox)[a];
+			TMsvEmailEntry e = iServerEntry.Entry();
+			if((iInbox = GetFolderFromList(inboxid)) == NULL)
+				{
+				CImapFolder* tempfolder = CImapFolder::NewLC(*this, iServerEntry, e, iImapSettings, KIMAP_INBOX());
+				CleanupStack::Pop(tempfolder);
+				iInbox = tempfolder;
+				}
+
+			// Mailbox flag not set? It always should be. This will 'repair' it.
+			if(!e.Mailbox())
+				{
+				// Set it
+				e.SetMailbox(ETrue);
+				ChangeEntryL(e);
+				}
+			
+			// Found the inbox, so no need to search any further
+			break; // from for loop
+			}
+		}
+
+	// Clean up
+	CleanupStack::PopAndDestroy(findinbox);
+	findinbox = NULL;
+
+	// Not found/no entries?
+	if(inboxid == 0)
+		{
+		// Create an inbox entry below the service. This is a local-only
+		// creation as the server *WILL* have an inbox.
+		SetEntryL(iServiceId);
+		TMsvEmailEntry entry;
+
+		entry.iType = KUidMsvFolderEntry;
+		entry.iMtm = KUidMsgTypeIMAP4;
+		entry.iServiceId = iServiceId;
+		entry.SetMtmData1(0);
+		entry.SetMtmData2(0);
+		entry.SetMtmData3(0);
+		entry.iSize = 0;
+		entry.SetUID(0);
+		entry.SetValidUID(EFalse);
+		entry.SetMailbox(ETrue);
+		entry.SetLocalSubscription(ETrue);
+		entry.SetComplete(ETrue);
+		entry.iDetails.Set(KImapInboxDisplayName);
+		User::LeaveIfError(iServerEntry.CreateEntry(entry));
+
+		// Set inbox
+		// not there so add it
+		CImapFolder* tempfolder = CImapFolder::NewLC(*this, iServerEntry, entry, iImapSettings, KIMAP_INBOX());
+		CleanupStack::Pop(tempfolder);
+		iInbox = tempfolder;
+		}
+	}
+
+/**
+Synchronise outstanding delete operations on all subscribe folders on the IMAP service
+
+@param aStatus
+The TRequestStatus to complete
+@param aSession
+The session to be use for the sync operation
+*/
+EXPORT_C void CImapSyncManager::SynchroniseDeletesL(TRequestStatus& /*aStatus*/, CImapSession& /*aSession*/)
+	{
+	}
+
+/**
+Function to synchronise the inbox only.
+
+@param aStatus
+The TRequestStatus to complete
+@param aSession
+The session to be use for the sync operation
+*/
+EXPORT_C void CImapSyncManager::SynchroniseInboxL(TRequestStatus& aStatus, CImapSession& aSession)
+	{
+	//initialise progress 
+	iFoldersToDo=0;
+	iFoldersDone=0;
+	iFoldersNotFound=0;
+	iErrorCode=KErrNone;
+	iSyncDoSingleStep = ETrue;
+	
+	iSession = &aSession;
+	
+	// Note the invisibility
+	iNewFoldersAreInvisible = iImapSettings.UpdatingSeenFlags();
+	iPerformDeletes = iImapSettings.DeleteEmailsWhenDisconnecting();
+
+	// Get the synchronise settings
+	iSynchroniseStrategy = iImapSettings.Synchronise();
+	iSubscribeStrategy = iImapSettings.Subscribe();
+
+	GetInboxL();
+
+	// Reset stats: 1 folder remaining (inbox)
+	iFoldersToDo = 1;
+	iSyncProgressState = TImap4SyncProgress::ESyncInbox;
+	
+	// Synchronise with the inbox
+	iInbox->SelectL(iStatus, aSession, EFalse);
+	iSyncState = EInboxSelect;
+	iNextSyncAction = EInboxSync;
+
+	Queue(aStatus);
+	SetActive();
+	}
+	
+/**
+Synchronise the subscription status for the folders on the remote server only.
+
+@param aStatus
+The TRequestStatus to complete
+@param aSession
+The session to be use for the sync operation
+*/
+EXPORT_C void CImapSyncManager::SynchroniseFolderSubscriptionsL(TRequestStatus& aStatus, CImapSession& aSession)
+	{
+	// Only do this step
+	iSyncDoSingleStep = ETrue;
+
+	// Save the session
+	iSession = &aSession;
+
+	// Run the sync folder subscriptions status step
+	// set iSyncState when folder subscription is kicked off in DoRunL()
+	iNextSyncAction = ECheckRemoteSubscription;
+
+	Queue(aStatus);
+	CompleteSelf();
+	SetActive();
+	}
+	
+/**
+At the first call the value of aFolderId should be set to 0. This parameter will be updated with
+each call. Therefore after each calll to this function the value of aFolderCounter should be check,
+if the value is -1 then the last folder has already been processed.
+The Inbox is not part of this function call.
+
+@param aFolderCounter
+Folder counter to keep track of the current folder to be process. 
+*/
+EXPORT_C void CImapSyncManager::NextSubscribedFoldersL(TMsvId& aFolderId)
+	{
+	// Only do this step
+	iSyncDoSingleStep = ETrue;
+
+	if(aFolderId > 0)
+		{
+		// Get the next folder TMsvId and sets the variable
+		++iSyncFolderCounter;
+		if((iSyncFolderCounter) < iFolderList.Count())
+			{
+			CImapFolder *folder = iFolderList[iSyncFolderCounter];
+			aFolderId = folder->MailboxId();
+			}
+		else
+			{			
+			aFolderId = -1;
+			}
+		}
+	else if(aFolderId == 0)
+		{
+		iSyncFolderCounter = 0;
+
+		if(iFolderList.Count() > 0)
+			{
+			CImapFolder *folder = iFolderList[0];
+			aFolderId = folder->MailboxId();
+			}
+		else
+			{
+			aFolderId = -1;
+			}
+		}
+	else
+		{
+		aFolderId = -1;
+		__ASSERT_DEBUG(EFalse,TImapServerPanic::ImapPanic(TImapServerPanic::EImapSyncManagerInvalidFolderID));
+		}
+	}
+
+/**
+Perform the next synchronise step for all subscribed folders on the IMAP service.
+This function should only be call after one to NextSubscribedFoldersL to setup the folder to be synchronise.
+The Inbox will not be synchronise with this function call.
+
+@param aStatus
+The TRequestStatus to complete
+@param aSession
+The session to be use for the sync operation
+@param aFolderId
+Folder id to keep track of the current folder to be process. 
+*/
+EXPORT_C void CImapSyncManager::SynchroniseSubscribedFoldersL(TRequestStatus& aStatus, CImapSession& aSession, TMsvId& aFolderId)
+	{
+	// Only do this step
+	iSyncDoSingleStep = ETrue;
+
+	// Save the session
+	iSession = &aSession;
+
+	// Run the sync folder subscriptions status step
+	if(aFolderId > 0)
+		{
+		iNextSyncAction = EFolderSelect;
+		Queue(aStatus);
+		CompleteSelf();
+		SetActive();
+		}
+	}
+
+/**
+Synchronises the local view of the directory structure on the remote IMAP server
+
+@param aStatus
+The TRequestStatus to complete
+@param aSession
+The session to be use for the sync operation
+*/
+EXPORT_C void CImapSyncManager::SynchroniseFolderTreeL(TRequestStatus& aStatus, CImapSession& aSession)
+	{
+	// Only do this step
+	iSyncDoSingleStep = ETrue;
+
+	// Save the session
+	iSession = &aSession;
+
+	// Note where this list came from
+	iServiceId = iImapSettings.ServiceId();
+
+	// Create the synchronise tree object and starts the sync
+	if(iFolderTreeSync)
+		{
+		delete iFolderTreeSync;
+		iFolderTreeSync = NULL;
+		}
+
+	iSyncState = ESynchroniseTree;
+	iNextSyncAction = EEndSynchroniseTree;
+	//update the progress object
+	iSyncProgressState= TImap4SyncProgress::ESyncFolderTree;
+
+	iFolderTreeSync = CImapOpSyncFolderTree::NewL(iServerEntry, *iSession, *this, iImapSettings);
+	iFolderTreeSync->SynchroniseTreeL(iStatus);
+
+	Queue(aStatus);
+	SetActive();
+	}
+
+/**
+Callback function for the operation class CImapOpSyncSubs.
+Cycle through the list of local subscribed folders and creates one from the CImapListFolderInfo if
+it does not exist in the list.
+
+@param aFolderInfo
+The CImapListFolderInfo to be processed
+*/
+#ifdef __IMAP_LOGGING
+void CImapSyncManager::AddSubscribedFolderFromInfoL(CImapListFolderInfo* aFolderInfo, TInt aLogId)
+#else //__IMAP_LOGGING
+void CImapSyncManager::AddSubscribedFolderFromInfoL(CImapListFolderInfo* aFolderInfo, TInt /*aLogId*/)
+#endif //__IMAP_LOGGING
+	{
+#ifdef __IMAP_LOGGING
+	HBufC8* tempBuf = HBufC8::NewL(aFolderInfo->FolderName().Length());
+	TPtr8 tempBufPtr = tempBuf->Des();
+	CnvUtfConverter::ConvertFromUnicodeToUtf7(tempBufPtr, aFolderInfo->FolderName(), EFalse);
+	__LOG_FORMAT((aLogId, "AddSubscribedFolderFromInfoL - %S", &tempBufPtr));
+	delete tempBuf;
+#endif
+
+	// Don't add the INBOX
+	if(aFolderInfo->FolderName().CompareF(KIMAP_INBOX) == 0)
+		{
+		return;
+		}
+
+	// Search the folder list and don't add it if it's already there
+	TInt foldercount = iFolderList.Count();
+	for (int i = 0; i < foldercount; i++)
+		{
+		if(iFolderList[i]->FullFolderPathL().Compare(aFolderInfo->FolderName()) == 0)
+			{
+			// Found the folder object just return
+			return;
+			}
+		}
+
+	TMsvId folderid = FindAndSetFolderL(aFolderInfo->FolderName(), aFolderInfo->iHierarchySeperator);
+	
+	if(folderid != -1)
+		{
+		// Set subscribed flag
+		TMsvEmailEntry entry = iServerEntry.Entry();
+		if(!entry.Subscribed())
+			{
+			// It needs changing, do it
+			entry.SetVisible(ETrue);
+			if (iSubscribeStrategy == EUpdateLocal || iSubscribeStrategy == EUpdateBoth)
+				{
+				// set local subscribe flag if updating local flags
+				entry.SetLocalSubscription(ETrue);
+				}
+			entry.SetSubscribed(ETrue);
+			ChangeEntryL(entry);
+			}
+
+		// Create and add the CImapfolder object
+		CImapFolder* tempfolder = CImapFolder::NewLC(*this, iServerEntry, entry, iImapSettings, KNullDesC());
+		iFolderList.AppendL(tempfolder);
+		CleanupStack::Pop(tempfolder);
+		__LOG_TEXT(aLogId, "Folder Added");
+		}
+	}
+
+/**
+Create a CImapFolder list of local subscribed folder from scratch
+*/
+void CImapSyncManager::CreateLocalFolderListL()
+	{
+	// Clear list of folders to sync, and subscribe/unsubscribe lists
+	iFolderList.ResetAndDestroy();
+
+	AddLocalFoldersL(iImapSettings.ServiceId());
+	
+	// Complete any bulk entry changes that occured during AddLocalFoldersL()
+	iServerEntry.CompleteBulk();
+	}
+
+/**
+For a given folder id cycle through the current list of folders and create a new CImapFolder item 
+if it's not already in the list. Do not add the Inbox or the service.
+
+@param aFolder
+The TMsvId of the folder to be added.
+*/
+void CImapSyncManager::AddIfNotThereL(TMsvId aFolder)
+	{
+	// first see if we already have this folder and return if we do
+	for (int i=0; i < iFolderList.Count(); i++)
+		{
+		if( iFolderList[i]->MailboxId() == aFolder)
+			{
+			return;
+			}
+		}
+
+	// don't add the inbox or service
+	if(aFolder == iInbox->MailboxId() || aFolder == iServiceId)
+		{
+		return;
+		}
+	
+	// visit folder
+	SetEntryL(aFolder);
+	TMsvEmailEntry e=iServerEntry.Entry();
+	// not there so add it
+	CImapFolder* tempfolder = CImapFolder::NewLC(*this, iServerEntry, e, iImapSettings, KNullDesC());
+	iFolderList.AppendL(tempfolder);
+	CleanupStack::Pop(tempfolder);
+	}
+
+/**
+Add local (subscribed) folders to iFolderList - this is the list of
+folders that are to be synchronised according to flags and settings.
+Recursive.
+
+Also updates subscription flags on the TMsvEntry for the folder
+and adds the folder to iSubscribeList or iUnsubscribeList if remote
+update of subscription flag is required. These arrays are used
+during subscription synchronisation later in the sync procedure.
+
+
+@param aFolder
+TMsvId of the folder in the local message store.
+*/
+void CImapSyncManager::AddLocalFoldersL(const TMsvId aFolder)
+	{
+	// Select the entry
+	SetEntryL(aFolder);
+	TMsvEmailEntry entry = iServerEntry.Entry();
+
+	// Is it actually a folder or service? If not, ignore it. 
+	if(entry.iType != KUidMsvServiceEntry &&
+		entry.iType != KUidMsvFolderEntry)
+		{
+		return;
+		}
+
+	// What we do now depends on the strategy
+
+	// addthisone indicates this folder should be added to the list of folders
+	// that are to be synchronised according to subscription flags and settings.
+	TBool addthisone = EFalse;
+	
+	switch(iSynchroniseStrategy)
+		{
+	case EUseLocal:
+		{
+		// Is it locally subscribed?
+		if(entry.LocalSubscription())
+			{
+			addthisone = ETrue;
+			}
+		}
+		break;
+
+	case EUseRemote:
+		{
+		// Is it remotely subscribed?
+		if(entry.Subscribed())
+			{
+			addthisone = ETrue;
+			}
+		}
+		break;
+
+	case EUseCombination:
+		{
+		// Either will do
+		if(entry.LocalSubscription() || entry.Subscribed())
+			{
+			addthisone = ETrue;
+			}
+		}
+		break;
+	default:
+		{
+		__ASSERT_DEBUG(EFalse,TImapServerPanic::ImapPanic(TImapServerPanic::EAddLocalFolderInvalidSynchStrategy));
+		break;
+		}
+		}
+
+	
+	// Any childrenlist?
+	CMsvEntrySelection *childrenlist = new (ELeave) CMsvEntrySelection;
+	CleanupStack::PushL(childrenlist);
+	GetChildrenL(*childrenlist);
+	TInt noofchildren = childrenlist->Count();
+
+	if(aFolder != iInbox->MailboxId() && aFolder != iServiceId)
+		{
+		if(addthisone)
+			{
+			// Do updating
+			switch(iSubscribeStrategy)
+				{
+			case EUpdateNeither:
+				break;
+
+			case EUpdateLocal:
+				{
+				if(!entry.LocalSubscription())
+					{
+					// Update local subscription flag
+					entry.SetLocalSubscription(ETrue);
+					SetEntryL(aFolder);
+					ChangeEntryBulkL(entry); // bulk op completed by the caller of this method
+					}
+				}
+				break;
+			case EUpdateRemote:
+				{
+				if(!entry.Subscribed())
+					{
+					iSubscribeList->InsertInOrder(entry.Id());
+					}
+				}
+				break;
+			case EUpdateBoth:
+				{
+				if(entry.LocalSubscription() || entry.Subscribed())
+					{
+					if (!entry.LocalSubscription())
+						{
+						// Update local subscription flag
+						entry.SetLocalSubscription(ETrue);
+						SetEntryL(aFolder);
+						ChangeEntryBulkL(entry); // bulk op completed by the caller of this method
+						}
+					if (!entry.Subscribed())
+						{
+						// set the remote subscribed flag...
+						iSubscribeList->InsertInOrder(entry.Id());
+						}
+					}
+				}
+				break;
+			default:
+				{
+				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EAddLocalFolderInvalidSubscribeStrategy));
+				break;	
+				}
+				}
+			}
+		else // if(!addthisone)
+			{
+			// Do updating
+			switch(iSubscribeStrategy)
+				{
+			case EUpdateNeither:
+				break;
+
+			case EUpdateLocal:
+				{
+				if(entry.LocalSubscription())
+					{
+					// Update local subscription flag
+					entry.SetLocalSubscription(EFalse);
+					SetEntryL(aFolder);
+					ChangeEntryBulkL(entry); // bulk op completed by the caller of this method
+					}
+				}
+				break;
+			case EUpdateRemote:
+				{
+				if(entry.Subscribed())
+					{
+					iUnsubscribeList->InsertInOrder(entry.Id());
+					}
+				else if (entry.LocalSubscription())
+					{
+					iSubscribeList->InsertInOrder(entry.Id());
+					addthisone = ETrue;
+					}
+				}
+				break;
+			case EUpdateBoth:
+				{
+				if(entry.LocalSubscription() || entry.Subscribed())
+					{
+					if (!entry.LocalSubscription())
+						{
+						// Update local subscription flag
+						entry.SetLocalSubscription(ETrue);
+						SetEntryL(aFolder);
+						ChangeEntryBulkL(entry); // bulk op completed by the caller of this method
+						}
+					if (!entry.Subscribed())
+						{
+						iSubscribeList->InsertInOrder(entry.Id());
+						addthisone = ETrue;
+						}
+					}
+				}
+				break;	
+				} // end of switch 
+			} // end of if (addthisone)
+
+		// add subscribed afterwards
+		if(addthisone)
+			{
+			AddIfNotThereL(aFolder);
+			}
+		else
+			{
+			// This folder is not subscribed, but has childrenlist. 
+			// If any childrenlist are messages, then delete.
+			if(noofchildren)
+				{
+				// This folder is not subscribed to, so check if it has any messages.
+				// Do each in turn
+				TInt child = childrenlist->Count();
+				while (child--)
+					{
+					SetEntryL((*childrenlist)[child]);
+					TMsvEmailEntry deletingentry = iServerEntry.Entry();
+
+					// Is it a message?
+					if(deletingentry.iType == KUidMsvMessageEntry)
+						{
+						SetEntryL(deletingentry.Id());
+						SetEntryL(iServerEntry.Entry().Parent());
+						iServerEntry.DeleteEntry(deletingentry.Id());
+						}
+					}
+
+				// If we've some childrenlist then get the childrenlist list again
+				SetEntryL(aFolder);
+				GetChildrenL(*childrenlist);
+				noofchildren=childrenlist->Count();
+				} // end of if(noofchildren) 
+			}
+		} // end of if(aFolder != iInbox->MailboxId() && aFolder != iServiceId)
+	
+
+	// Any childrenlist?
+	if(noofchildren)
+		{
+		// Do each in turn
+		for(TInt child=0;child<childrenlist->Count();child++)
+			{
+			AddLocalFoldersL((*childrenlist)[child]);
+			}
+		
+		// Complete any bulk entry changes that occured during AddLocalFoldersL()
+		iServerEntry.CompleteBulk();
+		}
+
+	CleanupStack::PopAndDestroy(childrenlist);
+	}
+
+
+/**
+Deleting the child messages of the given folder from the message server.
+
+@param aDeleteFolderId
+The TMsvId of the foler whose content is to be deleted.
+*/
+EXPORT_C void CImapSyncManager::DeleteFolderContentsL(TMsvId aDeleteFolderId)
+	{
+	// Select the entry
+	SetEntryL(aDeleteFolderId);
+	TMsvEmailEntry entry = iServerEntry.Entry();
+
+	// Is it actually a folder or service? If not, ignore it. 
+	if(entry.iType != KUidMsvServiceEntry &&
+		entry.iType != KUidMsvFolderEntry)
+		{
+		return;
+		}
+
+	// Any childrenlist?
+	CMsvEntrySelection *childrenlist = new (ELeave) CMsvEntrySelection;
+	CleanupStack::PushL(childrenlist);
+	GetChildrenL(*childrenlist);
+	TInt noofchildren = childrenlist->Count();
+
+	// Any childrenlist?
+	if(noofchildren)
+		{
+		// Do each in turn
+		for(TInt child = 0; child < childrenlist->Count(); ++child)
+			{
+			TMsvEntry* entryPtr;
+			TMsvId id = (*childrenlist)[child];
+			User::LeaveIfError(iServerEntry.GetEntryFromId(id, entryPtr));
+
+			// Is it a message? And is it real (not shadow)
+			if(entryPtr->iType == KUidMsvMessageEntry &&
+				entryPtr->iRelatedId == KMsvNullIndexEntryId )
+				{
+				// yes it is... remove it
+				TInt err (iServerEntry.DeleteEntry(id));
+				if(err == KErrInUse)
+					{
+					// Dont leave if err = KErrInUse
+					}
+				else
+					{
+					User::LeaveIfError(err);
+					}
+				}
+			}
+		}
+
+	CleanupStack::PopAndDestroy(childrenlist);
+	}
+
+/**
+Remove the given folder from the folder index and delete the contents.
+
+@param aDeleteFolderId
+The TMsvId of the foler to be deleted.
+*/
+EXPORT_C void CImapSyncManager::RemoveFolderL(TMsvId aMsvId)
+	{
+	// Search the folder list and remove the folder
+	TInt foldercount = iFolderList.Count();
+	for (int i = 0; i < foldercount; i++)
+		{
+		if( iFolderList[i]->MailboxId() == aMsvId)
+			{
+			// Found the folder object remove then return
+			delete iFolderList[i];
+			iFolderList.Remove(i);
+			break;
+			}
+		}
+
+	DeleteFolderContentsL(aMsvId);
+
+	SetEntryL(aMsvId);
+	TMsvEmailEntry entry = iServerEntry.Entry();
+	SetEntryL(entry.Parent());
+	iServerEntry.DeleteEntry(aMsvId);
+	}
+	
+/**
+Called to notify the sync manager of a change in a folder's name.
+The TMsvEmailEntry for the folder is updated with the new name.
+The CImapFolder object representing the folder and that of any children
+folders affected by the namechange is also updated to show the new path.
+This must be called after a remote folder has been renamed.
+
+@param aFolderId id of the folder that has been renamed
+@param aNewName  the new folder name
+*/
+EXPORT_C void CImapSyncManager::RenameLocalL(TMsvId aFolderId, const TDesC& aNewName)
+	{
+
+	// First rename the folder on the local message server
+	SetEntryL(aFolderId);
+		
+	TMsvEmailEntry entry = iServerEntry.Entry();
+	entry.iDetails.Set(aNewName);
+	ChangeEntryL(entry);
+	
+	// Search the folder list and rename the folder if we have it subscribed
+	// then search the rest of the folder list and resets the full path for any subfolders.
+	TInt foldercount = iFolderList.Count();
+	CImapFolder* folder = NULL;
+	
+	for (int i = 0; i < foldercount; i++)
+		{
+		if( iFolderList[i]->MailboxId() == aFolderId)
+			{
+			folder = iFolderList[i];
+			// Found the folder object
+			break;
+			}
+		}
+	
+	if(folder)
+		{
+		// Save a copy of the old folder name
+		RBuf folderparentnamebuffer;
+		folderparentnamebuffer.CleanupClosePushL();
+		folderparentnamebuffer.CreateL(folder->FullFolderPathL());
+
+		// reset the path for the rename folder
+		// - this will be rebuilt when next requested
+		folder->SetFullFolderPathL(KNullDesC());
+		
+		TPtrC folderparentpath;
+		// Try and find the parent folder in the folder list
+		for (int i = 0; i < foldercount; i++)
+			{
+			folderparentpath.Set((iFolderList[i]->FullFolderPathL().Left(folderparentnamebuffer.Length())));
+			if( folderparentpath.Compare(folderparentnamebuffer) == 0)
+				{
+				// Found the parent name, reset the path
+				iFolderList[i]->SetFullFolderPathL(KNullDesC());
+				}
+			}
+			
+		CleanupStack::PopAndDestroy(&folderparentnamebuffer);
+		}
+	}
+
+
+/**
+Find the folder in the message server using the given path the sets the server context.
+
+@param aFullPath
+The full pathname of the folder relative to the service.
+@param aHierarchySeperator
+The character that is use as the path separator for the full pathname.
+@return The TMsvId of the folder if it was found in the message server.
+*/
+TMsvId CImapSyncManager::FindAndSetFolderL(const TPtrC& aFullPath, TChar& aHierarchySeperator)
+	{
+	TPtrC path(aFullPath);
+	TMsvId foundfolderid = -1;
+	
+	if (iImapSettings.FolderPath().Length() != 0)
+		{
+		//FolderPath will be 8 bit Descriptor, so we need to convert into 16 bit
+		HBufC* tempPath = HBufC::NewL(iImapSettings.FolderPath().Length());
+		tempPath->Des().Copy(iImapSettings.FolderPath());
+		
+		if (path.Match(tempPath->Des()) == 0)
+			{
+			TInt separator = path.Locate(aHierarchySeperator);
+			if (separator == iImapSettings.FolderPath().Length())
+				{
+				++separator;
+				if (separator < path.Length())
+					{
+					path.Set(path.Mid(separator));
+					}
+				else
+					{
+					// Path contains only the settings FolderPath and separator. This is an error.
+					delete tempPath;
+					return KErrNotFound;
+					}
+				}
+			}
+		delete tempPath;
+		}
+ 			
+	// Go down through path
+	CMsvEntrySelection*	selection = new (ELeave) CMsvEntrySelection();
+	CleanupStack::PushL(selection);
+	
+	TMsvId currentpos = iServiceId;
+			
+	while(currentpos)
+		{
+		// Truncate this bit of path: look for a hierarchy separator
+		TInt separator = path.Locate(aHierarchySeperator);
+		TPtrC element(path);
+
+		// Anything?
+		if(separator != KErrNotFound)
+			{
+			// Truncate this element there
+			element.Set(element.Left(separator));
+			}
+
+		// Try to find this element at the search level
+		SetEntryL(currentpos);
+		GetChildrenL(*selection);
+
+		// Nothing? Give up.
+		if(!selection->Count())
+			{
+			break;				// out of while
+			}
+			
+		// Check all the children
+		TInt a;
+
+		for(a = 0; a < selection->Count(); ++a)
+			{
+			// This one?
+			SetEntryL((*selection)[a]);
+
+			// Check if the path element matches the current entry details field.
+			// We need to do a specific check if the entry is the inbox, because
+			// inbox is case insensitive.
+			if ((iServerEntry.Entry().iType == KUidMsvFolderEntry && iServerEntry.Entry().iDetails.Compare(element) == 0 )||
+			    (element.CompareF(KIMAP_INBOX) == 0 && EntryIsInbox(iServerEntry.Entry())))
+				{
+				// Found it! Are we at the end, ie no more elements?
+				if(separator == KErrNotFound)
+					{
+					// Get the entry TMsvId
+					TMsvEmailEntry entry = iServerEntry.Entry();
+					foundfolderid = entry.Id();
+					
+					// All done: this will exit the loop
+					currentpos = 0;
+					break;
+					}
+				else
+					{
+					// Update path
+					currentpos = (*selection)[a];
+					path.Set(path.Mid(separator+1, path.Length()-separator-1));
+
+					// Exit loop
+					break;
+					}
+				}
+			}
+
+		if(a == selection->Count())
+			{
+			// Didn't find it. Humm
+			// Didn't find entry : tree out of date?
+			break;				// out of while
+			}
+		}
+	CleanupStack::PopAndDestroy(selection);
+	selection = NULL;
+	
+	return foundfolderid;
+	}
+
+/**
+Returns updated progress information on outstanding synchronisation operations.
+
+@param aProgress
+The reference to the progress object to be fill in with the local progress information.
+*/
+EXPORT_C void CImapSyncManager::Progress(TImap4SyncProgress& aProgress)
+	{
+	//copy values from member progress ob into aProgress
+	//this includes the progress information set by CImapFolder
+	
+	if(iInbox)
+		{
+		iInbox->Progress(aProgress);
+		}
+	aProgress.iFoldersToDo=iFoldersToDo;
+	aProgress.iFoldersDone=iFoldersDone;
+	aProgress.iFoldersNotFound=iFoldersNotFound;
+	aProgress.iState=iSyncProgressState;
+	aProgress.iErrorCode=iErrorCode;	
+	}
+
+/**
+Called when async child completes with >=KErrNone
+*/
+void CImapSyncManager::DoRunL()
+	{
+	//update the progress object
+	iErrorCode=iStatus.Int();
+	
+	// Handle any server errors
+	if(iStatus.Int()!=KErrNone)
+		{
+		if(TInt err=ProcessSessionError() != KErrNone)
+			{
+			Complete(err);
+			return;
+			}
+		}
+		
+	switch(iNextSyncAction)
+		{
+	case EInboxSync:
+		{
+		// Start the sync of the current folder (ie, the inbox)
+		iNextSyncAction = EEndSingleSyncStep;
+		iSyncState = EInboxSync;
+		iSyncProgressState=TImap4SyncProgress::ESyncInbox;
+        iInbox->SynchroniseL(iStatus, *iSession, EFalse, 0);
+		SetActive();
+		}
+		break;
+
+	case ECheckRemoteSubscription:
+		{
+		// Create the sync subscriptions object to update the local subscriptions
+		if(iSyncDoSingleStep)
+			{
+			iNextSyncAction = EEndSingleSyncStep;
+			}
+		else
+			{
+			iNextSyncAction = ESynchronise;
+			}
+		
+		// Update folder tree
+		if(iSyncSubs)
+			{
+			delete iSyncSubs;
+			iSyncSubs = NULL;
+			}
+		
+		iSyncState = ECheckRemoteSubscription;
+		iSyncSubs = CImapOpSyncSubs::NewL(iServerEntry, *iSession, *this, iImapSettings);
+		//update the progress object		
+		iSyncProgressState=TImap4SyncProgress::EUpdateRemoteSubscription;
+		iSyncSubs->SynchroniseSubscriptionsL(iStatus);
+		SetActive();
+		}
+		break;
+	case EFolderSelect:
+		{	
+		//update the progess object
+		++iFoldersDone;
+		iSyncProgressState=TImap4SyncProgress::ESyncOther;
+		
+		// This case is for the picking the next folder for the full sync.
+		if(iSyncFolderCounter >= iFolderList.Count())
+			{
+			// Ran out of folders. Finishing sync
+			Complete(iStatus.Int());
+			}
+		else
+			{
+			CImapFolder *folder = iFolderList[iSyncFolderCounter];
+			iNextSyncAction = EFolderSynchronise;
+			iSyncState = EFolderSelect;
+			folder->SelectL(iStatus, *iSession);
+			SetActive();
+			}
+		}
+		break;
+	case EFolderSynchronise:
+		{
+		// This case is for synching the selected folder during a full sync.
+		// Back to select next folder
+		CImapFolder *folder = iFolderList[iSyncFolderCounter];
+
+		if(iSyncDoSingleStep)
+			{
+			iNextSyncAction = EEndSingleSyncStep;
+			}
+		else
+			{
+			iNextSyncAction = EFolderSelect;
+			++iSyncFolderCounter;
+			}
+		
+		iSyncState = EFolderSynchronise;
+		iSyncProgressState=TImap4SyncProgress::ESyncOther;
+		folder->SynchroniseL(iStatus, *iSession, EFalse, 0);
+		SetActive();
+		}
+		break;
+	case ESynchronise:
+		{
+		// This case is for the full synching start with selecting the inbox.
+		// Starts the full sync process by reseting the folder counter
+		iSyncFolderCounter = 0;
+
+		iSyncState = ESynchronise;
+		iNextSyncAction = EFolderSelect;
+		CompleteSelf();
+		SetActive();
+		}
+		break;
+
+	case EEndSynchroniseTree:
+		{
+		// We have finished synchronising the folder tree, so now build the
+		// list of locally subscribed folders
+		CreateLocalFolderListL();
+		// Fall through to next state
+		}
+
+	case EEndInboxSync:
+		// Finishing the Synching of the inbox
+	case EEndSingleSyncStep:
+		{
+		iSyncProgressState = TImap4SyncProgress::EIdle;
+		Complete(iStatus.Int());
+		}
+		break;
+	
+	default:
+		break;
+		}
+	}
+
+/**
+Called when completing a client request.
+
+@param aErr
+The completed error code.
+*/
+void CImapSyncManager::DoComplete(TInt& aErr)
+	{
+	// clean up the internal states
+	iSyncState = ENotSyncing;
+	iNextSyncAction = ENotSyncing;
+	iErrorCode = aErr;
+	}
+
+/**
+Handles any positive completion codes
+*/
+TInt CImapSyncManager::ProcessSessionError()
+	{
+	TInt errCode = iStatus.Int();
+	if( errCode==KErrImapNo || errCode==KErrImapBad)
+		{
+		ProcessNegativeServerResponse(errCode);
+		}
+	return errCode;
+	}
+
+/** 
+Specific handling for NO and BAD server responses.
+The error code is updated to KErrNone if it has been successfully 
+fielded by the sync manager.
+
+@param aErrCode
+Reference to the error code. 
+*/
+void CImapSyncManager::ProcessNegativeServerResponse(TInt& aErrCode)
+	{
+	// iSyncState describes current outstanding operation
+	switch (iSyncState)
+		{
+	case EInboxSelect:
+		{
+		++iFoldersNotFound;
+		break;
+		}
+	case EFolderSelect:
+		{
+		// SELECT folder has failed.. 
+		++iFoldersNotFound;
+		if(!iSyncDoSingleStep)
+			{
+			// Doing all folders... 
+			// ignore error and proceed to the next
+			iNextSyncAction = EFolderSelect;
+			aErrCode = KErrNone;
+			}
+		break;
+		}
+	case EInboxSync:
+	case ECheckRemoteSubscription:
+	case EFolderSynchronise:
+		{
+		// NO/BAD responses should have been handled in the
+		// folder or operation classes.
+		break;
+		}
+	case ESynchronise:	// self completing state
+	case EEndInboxSync:
+	case EEndSynchroniseTree:
+	case EEndSingleSyncStep:
+	default:
+		{
+		// unexpected states.
+		break;
+		}
+		} // end of switch (iSyncState)
+	}
+
+
+/**
+"Silent" cancel for migration - 
+Resets the error code to KErrNone following the cancel
+*/
+EXPORT_C void CImapSyncManager::CancelForMigrate()
+	{
+	Cancel();
+	iErrorCode=KErrNone;
+	}
+
+/**
+Cancels any outstanding asynchronous service requests.
+*/
+void CImapSyncManager::DoCancel()
+	{
+	// iSyncState describes current outstanding operation
+	switch (iSyncState)
+		{
+	case EInboxSelect:
+	case EFolderSelect:
+		{
+		// Note that although select operations are performed on a folder they
+		// actually pass our iStatus to the session, so that is why we cancel
+		// the session for them.
+		iSession->Cancel();
+		break;
+		}
+	case EInboxSync:
+		{
+		iInbox->Cancel();
+		break;
+		}
+	case ESynchroniseTree:
+		{
+		iFolderTreeSync->Cancel();
+		break;
+		}
+	
+	case ECheckRemoteSubscription:
+		{
+		iSyncSubs->Cancel();
+		break;
+		}
+	case EFolderSynchronise:
+		{
+		(iFolderList[iSyncFolderCounter])->Cancel();
+		break;
+		}
+
+	case ESynchronise:	// self completing state
+	case EEndInboxSync:
+	case EEndSynchroniseTree:
+	case EEndSingleSyncStep:
+	case ENotSyncing:
+		{
+		break;
+		}
+
+	default:
+		{
+		__ASSERT_DEBUG(EFalse,
+		               TImapServerPanic::ImapPanic(TImapServerPanic::ESyncManagerCancelUnexpectedState));
+		break;
+		}
+		} // end of switch
+
+	CMsgActive::DoCancel();
+	}
+
+void CImapSyncManager::CompleteSelf()
+	{
+	TRequestStatus* status = &iStatus;
+	iStatus = KRequestPending;
+	User::RequestComplete(status, KErrNone);
+	}
+
+TBool CImapSyncManager::InboxClearNewFlags()
+	{
+	return iInboxClearNewFlags;
+	}
+
+TBool CImapSyncManager::NonInboxClearNewFlags()
+	{
+	return iNonInboxClearNewFlags;
+	}
+
+EXPORT_C void CImapSyncManager::ResetInboxClearNewFlags()
+	{
+	iInboxClearNewFlags = EFalse;
+	}
+
+EXPORT_C void CImapSyncManager::ResetNonInboxClearNewFlags()
+	{
+	iNonInboxClearNewFlags = EFalse;
+	}
+
+/**
+Checks if the entry passed in is the inbox.
+
+@param aEntry Entry to check
+@return ETrue if entry is inbox, EFalse otherwise
+*/
+TBool CImapSyncManager::EntryIsInbox(const TMsvEntry& aEntry)
+	{
+	if (aEntry.Parent() == iImapSettings.ServiceId() &&
+	    aEntry.iDetails.CompareF(KIMAP_INBOX) == 0)
+		{
+		return ETrue;
+		}
+
+	return EFalse;
+	}
+
+/**
+Returns pointer to the nth CImapFolder object in the subscribed folder array.
+Also returns aNumSubscribedFolders updated with the total number of subscribed folders.
+
+@param aFolderId index in the array for requested folder, the nth subscribed folder (0 offset)
+@param aNumSubscribedFolders updated with total number of subscribed folders.
+@return  NULL if aFolderId exceeds the number of subscribed folders, 
+           pointer to subscribed CImapFolder object otherwise
+*/
+EXPORT_C CImapFolder* CImapSyncManager::GetSubscribedFolder(TInt32 aFolderId, TInt32& aNumSubscribedFolders)
+	{
+	// return updated number of folders for progress reporting
+	aNumSubscribedFolders = iFolderList.Count();
+	
+	if (aFolderId >= aNumSubscribedFolders)
+		{
+		return NULL;
+		}
+	else
+		{
+		return iFolderList[aFolderId];
+		}
+	}
+
+
+