diff -r 6a20128ce557 -r ebfee66fde93 email/imap4mtm/imapprotocolcontroller/src/cimapcompoundsyncservice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/imap4mtm/imapprotocolcontroller/src/cimapcompoundsyncservice.cpp Fri Jun 04 10:25:39 2010 +0100 @@ -0,0 +1,1608 @@ +// 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: +// + +#include "cimapcompoundsyncservice.h" + +#include + +#include "cimapfolder.h" +#include "cimapsession.h" +#include "cimapmailstore.h" +#include "cimapofflinecontrol.h" +#include "cimapsyncmanager.h" +#include "cimapfolder.h" +#include "cimaplogger.h" + +#include "cimapcompoundcopyfromlocal.h" +#include "cimapcompoundcopytolocal.h" +#include "cimapcompoundcopywithinservice.h" +#include "cimapcompoundcreate.h" +#include "cimapcompounddelete.h" +#include "cimapcompounddeletefolder.h" +#include "cimapcompounddisconnect.h" +#include "cimapcompoundrename.h" +#include "cimapcompoundselect.h" +#include "cimapsessionconsts.h" +#include "imappaniccodes.h" +#include "cimapofflinecontrol.h" +#include "imappaniccodes.h" +#include "cimapsyncdownloadrules.h" + +#include "mobilitytestmtmapi.h" + +CImapCompoundSyncService::CImapCompoundSyncService(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapOfflineControl& aImapOfflineControl ,TBool aDoLateDeletes) + : CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings), iImapOfflineControl(aImapOfflineControl), iImapMailStore(aImapMailStore), iDoLateDeletes(aDoLateDeletes) + { + // Set default progress values here so that any progress request before + // the operation is started returns valid information. + if(aDoLateDeletes) + { + iProgressState = TImap4GenericProgress::EBusy; + iSyncProgressState=TImap4SyncProgress::EDeleting; + } + else + { + iProgressState = TImap4GenericProgress::ESyncing; + iSyncProgressState=TImap4SyncProgress::ESyncInbox; + } + } + +CImapCompoundSyncService::~CImapCompoundSyncService() + { + delete iOutstandingOps; + delete iOutstandingMoveTypeDeletes; + delete iOutstandingLocalDeletes; + delete iImapCompound; + delete iDoNotFetchSel; + } + +CImapCompoundSyncService* CImapCompoundSyncService::NewL(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, CImapOfflineControl& aImapOfflineControl ,TBool aDoLateDeletes) + { + CImapCompoundSyncService* self = new (ELeave) CImapCompoundSyncService(aSyncManager, aServerEntry, aImapSettings, aImapMailStore, aImapOfflineControl,aDoLateDeletes); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CImapCompoundSyncService::ConstructL() + { + iOutstandingMoveTypeDeletes = new (ELeave) CArrayFixFlat(4); + iOutstandingLocalDeletes = new (ELeave) CArrayFixFlat(4); + iPerformDeletes = !(iImapSettings.DeleteEmailsWhenDisconnecting()); + + CActiveScheduler::Add(this); + } + +void CImapCompoundSyncService::StartOperation(TRequestStatus& aStatus, CImapSession& aSession) + { + iSession = &aSession; + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::StartOperation()"); + if(iDoLateDeletes) + { + iNextStep = EInboxLateDeletes; + } + else + { + iNextStep = ESyncService; + } + Queue(aStatus); + CompleteSelf(); + } + +/** +Handles the compound operation state machine + +@return ETrue if compound operation is completed, + EFalse otherwise (will be called again, unless active) +*/ +TBool CImapCompoundSyncService::DoRunLoopL() + { + SetCurrentStep(); + switch (iCurrentStep) + { + case ESyncService: // synchronous + { + // Starts the full sync process by synching the inbox + iNextFolderSync = 0; + + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Starting the full Sync steps."); + CImapFolder* inbox = iSyncManager.Inbox(); + + if(inbox != NULL) + { + iNextStep = EInboxSync; + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Processing offline for the inbox."); + // Deal with operations in the array + if (RefreshOutstandingOpsL(inbox->MailboxId())) + { + iNextStep = EInboxCheckPendingOps; + } + } + else + { + iNextStep = ESyncTree; + } + + CompleteSelf(); + } + break; + case EInboxDoneOps: // synchronous + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Performing the current offline op for the inbox."); + + iNextStep = EInboxCheckPendingOps; + DonePendingOpL(); + CompleteSelf(); + } + break; + case EInboxCheckPendingOps: // synchronous + { + iSyncProgressState=TImap4SyncProgress::EProcessingPendingOps; + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Find the next offline op for the inbox."); + if (NextPendingOpL()) + { + iNextStep = EInboxSync; + DonePendingOpL(); + CompleteSelf(); + } + else + { + iNextStep = EInboxDoneOps; + + // As there is a next pending op, we should be active so that the + // operation can go ahead. However under some circumstances (such + // as a missing shadow ID), the operation will not happen so we need + // to ensure the state machine does not lock up. + if (!IsActive()) + { + CompleteSelf(); + } + } + } + break; + case EInboxEarlyDeletes: // async, SELECTing the inbox prior to EXPUNGE. + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Performing early deletes for the inbox."); + + iSyncProgressState=TImap4SyncProgress::EDeleting; + // get rid of the FromLocal message sources + CImapFolder* inbox = iSyncManager.Inbox(); + + if(inbox) + { + for (TInt i = 0; i < iOutstandingLocalDeletes->Count(); ++i) + { + TMsvId id = (*iOutstandingLocalDeletes)[i]; + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Removing message %d.", id)); + inbox->DeleteMessageL(id); + } + + iOutstandingLocalDeletes->Reset(); + + // then do the inbox deletes + if (ProcessPendingDeleteOpsL(inbox->MailboxId(), !iPerformDeletes)) + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEInboxEarlyDeletes); + iNextStep = EInboxEarlyExpunge; + inbox->SelectL(iStatus, *iSession); + SetActive(); + return EFalse; + } + } + else + { + iOutstandingLocalDeletes->Reset(); + } + + iNextStep = ESyncTree; + CompleteSelf(); + } + break; + case EInboxEarlyExpunge: // async - sync deletes performed by the folder object, STORE /deleted and EXPUNGE + { + iSyncProgressState=TImap4SyncProgress::EDeleting; + + iNextStep = ESyncTree; + + if (iStatus.Int() == KErrImapNo) + { + iFoldersNotFound++; + } + else + { + // expunge the folder + iFolder = iSyncManager.Inbox(); + + if(iFolder) + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEInboxEarlyExpunge); + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Expunge the folder %S.", &(iFolder->FullFolderPathL()))); + iFolder->SyncDeletesL(iStatus, *iSession); + SetActive(); + return EFalse; + } + } + + CompleteSelf(); + } + break; + case EInboxSync: // async + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Calling the Syncmanger step for synching the inbox."); + + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + iNextStep = EInboxSync; + Complete(KErrNone); + return ETrue; + } + + // Call the SyncManager inbox sync + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEInboxSync); + iSyncProgressState=TImap4SyncProgress::ESyncInbox; + iSyncManager.SynchroniseInboxL(iStatus, *iSession); + iNextStep = EInboxEarlyDeletes; + } + break; + case ESyncTree: // async + { + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + iNextStep = ESyncTree; + Complete(KErrNone); + return ETrue; + } + + iNextStep = ESyncSubscriptions; + + // skip folder tree sync if disabled. + if (iImapSettings.FolderSyncDisabled()) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Folder Tree Sync Disabled...."); + return EFalse; + } + + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Calling the Syncmanger step to sync the folder tree."); + + // Synching the remote folders tree to local + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncESyncTree); + iSyncProgressState=TImap4SyncProgress::ESyncFolderTree; + iSyncManager.SynchroniseFolderTreeL(iStatus, *iSession); + } + break; + case ESyncSubscriptions: // async + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Calling the Syncmanger step to sync the folders subscriptions."); + // Synching the remote folders tree to local + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncESyncSubscriptions); + iSyncProgressState=TImap4SyncProgress::ECheckRemoteSubscription; + iSyncManager.SynchroniseFolderSubscriptionsL(iStatus, *iSession); + iNextStep = ESelectSyncFolder; + } + break; + case EFolderDoneOps: // synchronous + { + if(iNextFolderSync > 0) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Calling DonePendingOp."); + iNextStep = EFolderCheckPendingOPs; + DonePendingOpL(); + } + else + { + // All folders are done. + iNextStep = ESyncInboxAutoFetch; + } + + CompleteSelf(); + } + break; + case EFolderCheckPendingOPs: // synchronous + { + iSyncProgressState=TImap4SyncProgress::EProcessingPendingOps; + + if(NextPendingOpL()) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : All offline ops are done, calling folder sync."); + iNextStep = ESyncFolder; + DonePendingOpL(); + CompleteSelf(); + } + else + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Got a pending offline op, now do it."); + iNextStep = EFolderDoneOps; + + // As there is a next pending op, we should be active so that the + // operation can go ahead. However under some circumstances (such + // as a missing shadow ID), the operation will not happen so we need + // to ensure the state machine does not lock up. + if (!IsActive()) + { + CompleteSelf(); + } + } + } + break; + case EFolderEarlyDeletes: // asynchronous + { + iSyncProgressState=TImap4SyncProgress::EDeleting; + + CImapFolder* currentFolder = iSyncManager.GetFolderL(iNextFolderSync); + + if (currentFolder) + { + for (TInt i = 0; i < iOutstandingLocalDeletes->Count(); ++i) + { + TMsvId id = (*iOutstandingLocalDeletes)[i]; + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Removing message %d.", id)); + currentFolder->DeleteMessageL(id); + } + + iOutstandingLocalDeletes->Reset(); + + // if we are doing deletes on connection then all deletes will + // be marked Delete + if (ProcessPendingDeleteOpsListL(!iPerformDeletes)) + { + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Selecting the folder %S for expunge.", &(currentFolder->FullFolderPathL()))); + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEFolderEarlyDeletes); + currentFolder->SelectL(iStatus, *iSession); + iNextStep = EFolderEarlyExpunge; + SetActive(); + return EFalse; + } + } + else + { + iOutstandingLocalDeletes->Reset(); + } + + iNextStep = ESelectSyncFolder; + CompleteSelf(); + } + break; + case EFolderEarlyExpunge: // asynchronous + { + iSyncProgressState=TImap4SyncProgress::EDeleting; + + iNextStep = ESelectSyncFolder; + + if (iStatus.Int() == KErrImapNo) + { + ++iFoldersNotFound; + } + else + { + iFolder = iSyncManager.GetFolderL(iNextFolderSync); + if(iFolder) + { + // expunge the folder + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Expunge the folder %S.", &(iFolder->FullFolderPathL()))); + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEFolderEarlyExpunge); + iFolder->SyncDeletesL(iStatus, *iSession); + SetActive(); + return EFalse; + } + } + + CompleteSelf(); + } + break; + case ESelectSyncFolder: // synchronous + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::ESelectSyncFolder()"); + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + iNextStep = ESelectSyncFolder; + Complete(KErrNone); + return ETrue; + } + + // Call for the first time will not be active + iSyncManager.NextSubscribedFoldersL(iNextFolderSync); + iSyncProgressState=TImap4SyncProgress::ESyncOther; + + if(iNextFolderSync > 0) + { + // Perform the pending offline operations first + iNextStep = ESyncFolder; + if(RefreshOutstandingOpsL(iNextFolderSync)) + { + iNextStep = EFolderCheckPendingOPs; + } + } + else + { + // All folders are done. + iNextStep = ESyncInboxAutoFetch; + } + CompleteSelf(); + } + break; + case ESyncFolder: // async + { + if(iNextFolderSync > 0) + { + // Now sync the folder + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncESyncFolder); + iSyncManager.SynchroniseSubscribedFoldersL(iStatus, *iSession, iNextFolderSync); + iNextStep = EFolderEarlyDeletes; + } + else + { + // All folders are done. + iNextStep = ESyncInboxAutoFetch; + CompleteSelf(); + } + } + break; + case EInboxLateDeletes: // async + { + iNextFolderSync = 0; + iSyncProgressState=TImap4SyncProgress::EDeleting; + CImapFolder* inbox = iSyncManager.Inbox(); + + if (inbox) + { + if (ProcessPendingDeleteOpsL( inbox->MailboxId(), EFalse )) + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapEInboxLateDeletes); + inbox->SelectL(iStatus, *iSession); + iNextStep = EInboxLateExpunge; + SetActive(); + return EFalse; + } + } + + iNextStep = EFolderLateDeletes; + CompleteSelf(); + } + break; + case EInboxLateExpunge: // async + { + iNextStep = EFolderLateDeletes; + + if (iStatus.Int() == KErrImapNo) + { + iFoldersNotFound++; + } + else + { + // expunge the folder + iFolder = iSyncManager.Inbox(); + + if(iFolder) + { + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncESyncFolder); + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Late Expunge the folder %S.", &(iFolder->FullFolderPathL()))); + iFolder->SyncDeletesL(iStatus, *iSession); + SetActive(); + return EFalse; + } + } + + CompleteSelf(); + } + break; + case EFolderLateDeletes: // async + { + iSyncProgressState=TImap4SyncProgress::EDeleting; + + // Call for the first time will not be active + iSyncManager.NextSubscribedFoldersL(iNextFolderSync); + + if(iNextFolderSync > 0) + { + if (ProcessPendingDeleteOpsListL( EFalse ) ) + { + iNextStep = EFolderLateExpunge; + } + else + { + CImapFolder* currentFolder = iSyncManager.GetFolderL(iNextFolderSync); + if(currentFolder) + { + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Selecting the folder %S for expunge.", &(currentFolder->FullFolderPathL()))); + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEFolderLateDeletes); + iNextStep = EFolderLateExpunge; + currentFolder->SelectL(iStatus, *iSession); + SetActive(); + return EFalse; + } + + // back to select next folder + iNextStep = EFolderLateDeletes; + } + } + else + { + // No more subscribed folder was found + iNextStep = EFinished; + } + + CompleteSelf(); + } + break; + case EFolderLateExpunge: // async + { + iNextStep = EFolderLateDeletes; + + if (iStatus.Int() == KErrImapNo) + { + iFoldersNotFound++; + } + else + { + iFolder = iSyncManager.GetFolderL(iNextFolderSync); + if(iFolder) + { + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::DoRunLoopL : Late Expunge the folder %S.", &(iFolder->FullFolderPathL()))); + // expunge the folder + MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmImapSyncEFolderLateExpunge); + iFolder->SyncDeletesL(iStatus, *iSession); + SetActive(); + return EFalse; + } + } + + CompleteSelf(); + } + break; + case ESyncInboxAutoFetch: + { + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + iNextStep = ESyncInboxAutoFetch; + Complete(KErrNone); + return ETrue; + } + + iSyncProgressState=TImap4SyncProgress::ESyncOther; + if (!iImapSettings.UseSyncDownloadRules()) + { + // not using sync rules, loop to EFinished. + iNextStep = EFinished; + return EFalse; + } + + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Starting Second Phase Synchronisation"); + + // set the next step to perform + iNextStep = ESyncFolderAutoFetchCheck; + + if (KErrNotFound == iImapSettings.GetSyncDownloadRuleL(CImapSyncDownloadRules::EInboxRulesType, iMailInfo)) + { + // No download rules for the inbox, check other folders + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::No download rules for inbox on this bearer"); + return EFalse; + } + + CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection; + CleanupStack::PushL(selection); + + TInt msgsToFetch = iSyncManager.Inbox()->GetFetchMessageChildrenL(*selection); + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::Fetching %d INBOX messages.", msgsToFetch)); + if (msgsToFetch>0) + { + delete iImapCompound; + iImapCompound = NULL; + // Create the compound operation object + iImapCompound = CImapCompoundCopyToLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + iImapMailStore, + EFalse, + *selection, + KMsvNullIndexEntryId, + iMailInfo); + iImapCompound->StartOperation(iStatus, *iSession); + if (iDoNotFetchSel) + { + ((CImapCompoundCopyToLocal*)iImapCompound)->RemoveFromSelection(*iDoNotFetchSel); + } + SetActive(); + } + CleanupStack::PopAndDestroy(selection); + return EFalse; // if not active, will re-enter this function and perform next step... + } + + case ESyncFolderAutoFetchCheck: + { + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + // fetching of inbox contents may have been stopped prematurely, + // on resume, go back to check if any inbox messages still to fetch. + iNextStep = ESyncInboxAutoFetch; + Complete(KErrNone); + return ETrue; + } + + // reset folder sync counter + iFolderSyncCount = 0; + // can only get here if download rules being used, so no need to check that. + // No point in continuing if no download rules defined for non-inbox folders: + if (KErrNotFound == iImapSettings.GetSyncDownloadRuleL(CImapSyncDownloadRules::EFolderRulesType, iMailInfo)) + { + // No download rules for non-inbox folders. + iNextStep = EFinished; + return EFalse; + } + // else continue to next step... + } + case ESyncFolderAutoFetch: + { + // suspend operation if stop for migrate has been requested + if (iStopForMigrate) + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Stopped for migrate"); + iCurrentStep = ESuspendedForMigrate; + iNextStep = ESyncFolderAutoFetchCheck; + // delete the compound fetch operation - we will create a new one on resume, + // using the download rules for the new bearer. + delete iImapCompound; + iImapCompound = NULL; + Complete(KErrNone); + return ETrue; + } + + TInt32 numSubscribedFolders; + CImapFolder* folder = iSyncManager.GetSubscribedFolder(iFolderSyncCount, numSubscribedFolders); + if (folder) + { + CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection; + CleanupStack::PushL(selection); + TInt msgsToFetch = folder->GetFetchMessageChildrenL(*selection); + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::Fetching %d messages in folder %d.", msgsToFetch, folder->MailboxId())); + if (msgsToFetch>0) + { + delete iImapCompound; + iImapCompound = NULL; + // Create the compound operation object + iImapCompound = CImapCompoundCopyToLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + iImapMailStore, + EFalse, + *selection, + KMsvNullIndexEntryId, + iMailInfo); + iImapCompound->StartOperation(iStatus, *iSession); + if (iDoNotFetchSel) + { + ((CImapCompoundCopyToLocal*)iImapCompound)->RemoveFromSelection(*iDoNotFetchSel); + } + SetActive(); + } + CleanupStack::PopAndDestroy(selection); + // when complete, check the next folder... + ++iFolderSyncCount; + iNextStep = ESyncFolderAutoFetch; + } + else + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Download Rules Auto Fetch Completed."); + iNextStep = EFinished; + } + return EFalse; // not finished yet... + } + + case EFinished: + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Completing OK"); + iSyncProgressState=TImap4SyncProgress::EIdle; + iProgressState = TImap4GenericProgress::EIdle; + Complete(KErrNone); + return ETrue; + } + default: + { + __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncServiceCompoundUnexpectedState)); + // unexpected state - complete the request + iSyncProgressState=TImap4SyncProgress::EIdle; + iProgressState = TImap4GenericProgress::EIdle; + return ETrue; + } + } // end of switch (iCurrentStep) + + if (!IsActive()) + { + SetActive(); + } + return EFalse; + } + +/** +May be called in case of a genuine cancel or a cancel for migrate. +Following a genuine cancel, the compound operation will be deleted. +Following a cancel for migrate, the compound operation will be resumed, +so the iNextState is updated here to ensure the operation is +correctly restarted. + +In either case, CMsgActive::DoCancel() is called to complete the +user request with KErrCancel. + +In most cases, it is possible to resume at the current step following a +cancel-for-migration (sometimes following a SELECT on the current folder). + +Note that if the default CMsgActive::DoComplete() is overridden, +then that must also be modified to handle either case described above. + +Note on cancelling folder select operations: the folder actually passes +the iStatus to the session, hence the cancel is on the session. +*/ +void CImapCompoundSyncService::DoCancel() + { + switch (iCurrentStep) + { + case ESelectSourceMailboxRW: + { + // only set by ResumeOperation. No update to iNextStep required + iSession->Cancel(); + break; + } + case EInboxEarlyDeletes: // re-select inbox before resuming + case EFolderEarlyDeletes: // re-select current folder before resuming + case EInboxLateDeletes: // wont be resumed, as part of disconnect + case EFolderLateDeletes: // wont be resumed, as part of disconnect + { + // outstanding request on session. + iSession->Cancel(); + break; + } + case EInboxEarlyExpunge: // re-select inbox before resuming + case EFolderEarlyExpunge: // re-select current folder before resuming + case EInboxLateExpunge: // should not be resumed, as part of disconnect + case EFolderLateExpunge: // should not resumed, as part of disconnect + { + // outstanding request on folder + if (iFolder) + { + iFolder->Cancel(); + } + iNextStep = iCurrentStep; + break; + } + case EInboxSync: + case ESyncSubscriptions: + case ESyncTree: + case ESyncFolder: + { + // outstanding request on syncmanager + if (iCancelForMigrate) + { + iSyncManager.CancelForMigrate(); + } + else + { + iSyncManager.Cancel(); + } + // resume from the tree synchronisation + iNextStep = iCurrentStep; + break; + } + case EFolderCheckPendingOPs: + case EInboxCheckPendingOps: + { + // outstanding request on compound object + if (iImapCompound) + { + if (iCancelForMigrate) + { + iImapCompound->CancelForMigrate(); + // do not update iNextStep ( == EInboxDoneOps || EFolderDoneOps ) + // This operation will be resumed... + } + else + { + iImapCompound->Cancel(); + } + } + break; + } + case ESyncInboxAutoFetch: + { + // outstanding request on compound object + if (iImapCompound) + { + // don't cancel-for-migrate - will re-create new object on restart + // as the download rules may well be different on the new carrier. + iImapCompound->Cancel(); + } + iNextStep = ESyncInboxAutoFetch; + break; + } + case ESyncFolderAutoFetchCheck: + case ESyncFolderAutoFetch: + { + // outstanding request on compound object + if (iImapCompound) + { + // don't cancel-for-migrate - will re-create new object on restart + // as the download rules may well be different on the new carrier. + iImapCompound->Cancel(); + } + // restart in the check state to update the download rules being used. + iNextStep = ESyncFolderAutoFetchCheck; + break; + } + case EInboxDoneOps: + case ESyncService: + case EFolderDoneOps: + case ESelectSyncFolder: + case EFinished: + case ESuspendedForMigrate: + default: + { + __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncServiceCompoundCancelUnexpectedState)); + iNextStep = EFinished; + break; + } + } // end of switch (iCurrentStep) + + if (!iCancelForMigrate) + { + // genuine cancel - update progress + iProgressErrorCode = KErrCancel; + } + CMsgActive::DoCancel(); + } + + +void CImapCompoundSyncService::Progress(TImap4CompoundProgress& aCompoundProgress) + { + aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::ESync; + aCompoundProgress.iGenericProgress.iState = iProgressState; + + iSyncManager.Progress(aCompoundProgress.iSyncProgress); + aCompoundProgress.iSyncProgress.iState = iSyncProgressState; + + // Put error into progress buffer + if( aCompoundProgress.iGenericProgress.iErrorCode == KErrNone ) + { + aCompoundProgress.iGenericProgress.iErrorCode = iProgressErrorCode; + } + } + +/** +Handles NO/BAD responses according to current step. +Negative server responses are not fatal - the error is saved in +the message currently being operated on and the state machine pushed +on to process the next message in the requested selection. + +@return KErrNone if the error has been handled + Completion error code otherwise. +*/ +TInt CImapCompoundSyncService::ProcessNegativeServerResponse() + { + TInt err = iStatus.Int(); + switch (iCurrentStep) + { + case ESyncTree: + case ESyncSubscriptions: + case EInboxDoneOps: + case EFolderDoneOps: + case EFolderCheckPendingOPs: + case EInboxCheckPendingOps: + case EInboxSync: + case EInboxEarlyDeletes: + case EFolderEarlyDeletes: + case EInboxEarlyExpunge: + case EFolderEarlyExpunge: + case EInboxLateDeletes: + case EFolderLateDeletes: + case EInboxLateExpunge: + case EFolderLateExpunge: + case ESyncFolder: + case ESyncService: + case ESyncInboxAutoFetch: + case ESyncFolderAutoFetchCheck: + case ESyncFolderAutoFetch: + { + // Just store the error code in the progress response. + break; + } + case ESuspendedForMigrate: + case EFinished: + default: + { + // positive error code not expected, + // self-completed states or no outstanding request. + TImapServerPanic::ImapPanic(TImapServerPanic::ESyncServiceCompoundUnexpectedState); + break; + } + } // end of switch (iCurrentStep) + iProgressErrorCode = err; + return KErrNone; + } + + +/** +Given an id of a folder or the service, restores the offline +operation array. Returns the number of operations in the array. +Any non-zero return value indicates an action that needs to be addressed. +*/ +TBool CImapCompoundSyncService::RefreshOutstandingOpsL(TMsvId aId) + { + if (iOutstandingOps) + { + delete iOutstandingOps; + iOutstandingOps = NULL; + } + + iOutstandingOps = iImapOfflineControl.OffLineOpArrayL(aId); + iOutstandingOpsFolder = aId; + + // reset the count + iMsgsToDo = iOutstandingOps->CountOperations(); + + iMsgsDone = 0; + + iMovedId = KMsvNullIndexEntryId; + iShadowId = KMsvNullIndexEntryId; + + return iMsgsToDo; + } + +/** + This routine sets up iShadowId which will be deleted when the +operation completes successfully + +*/ +void CImapCompoundSyncService::DoOpL(const CImOffLineOperation& aOp) + { + // clean the disconnected op flags and ensure its visible and get + // an entry copy + SetEntryL(aOp.MessageId()); + TMsvEmailEntry entry = iServerEntry.Entry(); + entry.SetVisible(ETrue); + entry.SetDisconnectedOperation(ENoDisconnectedOperations); + ChangeEntryL(entry); + + // check and see if there is a shadow and whether it has been + // removed or marked for deletion + TBool shadowOK = ETrue; + if ( aOp.OpType() != CImOffLineOperation::EOffLineOpMtmSpecific && + aOp.OpType() != CImOffLineOperation::EOffLineOpDelete ) + { + iShadowId = iImapOfflineControl.FindShadowIdL(aOp); + + shadowOK = iShadowId != KMsvNullIndexEntryId && + iServerEntry.SetEntry(iShadowId) == KErrNone && + ((TMsvEmailEntry)iServerEntry.Entry()).DisconnectedOperation() != EDisconnectedDeleteOperation; + } + + delete iImapCompound; + iImapCompound = NULL; + + CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection; + CleanupStack::PushL(selection); + + // Deal with operation + switch(aOp.OpType()) + { + case CImOffLineOperation::EOffLineOpCopyToLocal: + // do the copy, if not a message + if (entry.iType != KUidMsvMessageEntry || + // or the shadow exists + shadowOK ) + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EOffLineOpCopyToLocal : %d %d", aOp.MessageId(), aOp.TargetMessageId())); + + //Create Copy to Local Compound object + + selection->AppendL(aOp.MessageId()); + + iImapCompound = CImapCompoundCopyToLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + iImapMailStore, + EFalse, + *selection, + aOp.TargetMessageId()); + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + } + break; + + case CImOffLineOperation::EOffLineOpCopyFromLocal: + if (shadowOK) + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EOffLineOpCopyFromLocal : %d %d", aOp.MessageId(), aOp.TargetMessageId())); + + //Create Copy from Local Compound object + + selection->AppendL(aOp.MessageId()); + + iImapCompound = CImapCompoundCopyFromLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + EFalse, + *selection, + aOp.TargetMessageId()); + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + } + break; + + case CImOffLineOperation::EOffLineOpCopyWithinService: + if (shadowOK) + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EOffLineOpCopyWithinService : %d %d", aOp.MessageId(), aOp.TargetMessageId())); + + //Create Copy within service Compound object + + selection->AppendL(aOp.MessageId()); + + iImapCompound = CImapCompoundCopyWithinService::NewL(iSyncManager, + iServerEntry, + iImapSettings, + EFalse, + *selection, + aOp.TargetMessageId()); + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + } + break; + + case CImOffLineOperation::EOffLineOpMoveToLocal: + if (shadowOK) + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EOffLineOpMoveToLocal : %d %d", aOp.MessageId(), aOp.TargetMessageId())); + + selection->AppendL(aOp.MessageId()); + + iImapCompound = CImapCompoundCopyToLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + iImapMailStore, + EFalse, + *selection, + aOp.TargetMessageId()); + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + } + // even if the shadow has been removed we still want to delete + // the original + iMovedId = aOp.MessageId(); + break; + + case CImOffLineOperation::EOffLineOpMoveFromLocal: + if (shadowOK) + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EOffLineOpMoveFromLocal : %d %d", aOp.MessageId(), aOp.TargetMessageId())); + + //Create Copy from Local Compound object + + selection->AppendL(aOp.MessageId()); + + iImapCompound = CImapCompoundCopyFromLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + EFalse, + *selection, + aOp.TargetMessageId()); + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + } + // even if the shadow has been removed we still want to delete + // the original + iMovedId = aOp.MessageId(); + break; + + case CImOffLineOperation::EOffLineOpMoveWithinService: + if (shadowOK) + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EOffLineOpMoveWithinService : %d %d", aOp.MessageId(), aOp.TargetMessageId())); + + //Create Copy within service Compound object + + selection->AppendL(aOp.MessageId()); + + iImapCompound = CImapCompoundCopyWithinService::NewL(iSyncManager, + iServerEntry, + iImapSettings, + EFalse, + *selection, + aOp.TargetMessageId()); + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + } + // even if the shadow has been removed we still want to delete + // the original, unless the folder itself has been removed + if (iServerEntry.SetEntry(aOp.TargetMessageId()) == KErrNone) + { + iMovedId = aOp.MessageId(); + } + break; + + case CImOffLineOperation::EOffLineOpMtmSpecific: + switch (aOp.MtmFunctionId()) + { + case EFnOffLineOpPopulate: + { + __LOG_FORMAT((iSession->LogId(), "CImOffLineOperation::EFnOffLineOpPopulate : %d", aOp.MessageId())); + + //Create Copy to Local Compound object + + selection->AppendL(aOp.MessageId()); + + // aOp.MtmParameters() for EFnOffLineOpPopulate is a package that contains the partial mail info. + // + // 1) Create an unitialised dummy partial mail object. This will NOT receive the partial mail data, but is needed for the build. + TImImap4GetPartialMailInfo dummyPartialMailInfo; + // 2) Create a package object that WILL point at the package data. + // but for now we need to point it at our unitialised partial mail object, in order for it to compile. + TPckgC partialMailInfoPackage(dummyPartialMailInfo); + // 3) Immediately point our package object at the actual package data. + partialMailInfoPackage.Set(aOp.MtmParameters()); + + iImapCompound = CImapCompoundCopyToLocal::NewL(iSyncManager, + iServerEntry, + iImapSettings, + iImapMailStore, + EFalse, + *selection, + KMsvNullIndexEntryId, + partialMailInfoPackage()); // pass the actual package data as an object + + iImapCompound->StartOperation(iStatus, *iSession); + SetActive(); + break; + } + default: + break; + } + break; + + case CImOffLineOperation::EOffLineOpDelete: + default: + break; + } + + CleanupStack::PopAndDestroy(selection); + } + +/** +Tidies up after performing an offline operation. +In the case of move operations, this means storing an array of messages that are to +be deleted on the server later in the sync phase (early deletes) or as the service +is disconnected (late deletes). + +*/ +void CImapCompoundSyncService::DonePendingOpL() + { + // if we've done one then... + if (iMsgsDone != 0) + { + // if this was a move then append a delete + if (iMovedId != KMsvNullIndexEntryId) + { + SetEntryL(iMovedId); + if (iServerEntry.Entry().Parent() == iOutstandingOpsFolder) + { + __LOG_FORMAT((iSession->LogId(), "Append MoveDelete for %x", iMovedId)); + iOutstandingMoveTypeDeletes->AppendL(iMovedId); + } + else + { + // if this id was from a MoveFrom (ie its parent is not + // this folder) then put it in a different pending array + __LOG_FORMAT((iSession->LogId(), "Append LocalDelete for %x", iMovedId)); + iOutstandingLocalDeletes->AppendL(iMovedId); + } + } + + // delete the shadowid if there is one, ignore errors + if (iShadowId != KMsvNullIndexEntryId && + iServerEntry.SetEntry(iShadowId) == KErrNone && + iServerEntry.SetEntry(iServerEntry.Entry().Parent()) == KErrNone) + { + iServerEntry.DeleteEntry(iShadowId); + } + } + } + +/** +Checks current folder's pending offline operation list. If no more pending operations +exist, returns ETrue, otherwise calls DoOpL() and returns EFalse. + +DoOpL() creates a compound operation object to perform the requested operation, +and launches it, setting this class active. + +Note in some circumstances it is possible that the operation cannot be performed, for +example if the folder in question has subsequently become unsubscribed. If this occurs, +this function shall return EFalse (as though an operation had been started) however, +the class will not have been set active. + +@return ETrue if no more pending operations to be performed at this time. +*/ +TBool CImapCompoundSyncService::NextPendingOpL() + { + TBool finished = EFalse; + + iMovedId = KMsvNullIndexEntryId; + iShadowId = KMsvNullIndexEntryId; + + // Any operations in outstanding list? + if (iOutstandingOps->CountOperations()) + { + __LOG_FORMAT((iSession->LogId(), "Outstanding operations on this folder %d", iOutstandingOps->CountOperations())); + + // Fetch operation + CImOffLineOperation* thisop = new(ELeave)CImOffLineOperation(); + CleanupStack::PushL(thisop); + + thisop->CopyL(iOutstandingOps->Operation(0)); + + // when we get to one of the Delete operations then it is time + // to stop + if (thisop->OpType() == CImOffLineOperation::EOffLineOpDelete || + (thisop->OpType() == CImOffLineOperation::EOffLineOpMtmSpecific && + thisop->MtmFunctionId() == EFnOffLineOpMoveDelete)) + { + __LOG_TEXT(iSession->LogId(),"Reached delete op. Finished"); + ++iMsgsDone; + finished = ETrue; + } + else + { + // remove from list and save back + iOutstandingOps->Delete(0); + iImapOfflineControl.SetOffLineOpArrayL(iOutstandingOpsFolder, *iOutstandingOps); + + // and execute + DoOpL(*thisop); + ++iMsgsDone; + } + + CleanupStack::PopAndDestroy(thisop); + } + else + { + // No more operations to do, return to what we should be doing next + finished = ETrue; + } + + // when we are about to finish this folder then tidy up + if (finished) + { + // add the list of pending deletes to the front of the + // offline op array + for (TInt i = 0; i < iOutstandingMoveTypeDeletes->Count(); i++) + { + TMsvId id = (*iOutstandingMoveTypeDeletes)[i]; + CImOffLineOperation* thisop = new(ELeave)CImOffLineOperation(); + CleanupStack::PushL(thisop); + + // if we are doing deletes on connection then store this + // as a delete and we will do all deletes at the end of + // the sync. + + // if we are doing deletes on disconnection then store + // this as a special code - it will still get done at end + // of sync, but real deletes will be done on + // disconnection. + if (!iImapSettings.DeleteEmailsWhenDisconnecting()) // iPerformDeletes + { + thisop->SetDelete(id); + } + else + { + thisop->SetMtmSpecificCommandL(id, EFnOffLineOpMoveDelete, 0, KNullDesC8()); + } + + iOutstandingOps->InsertOperationL(*thisop, 0); + CleanupStack::PopAndDestroy(thisop); + } + + // if there were outstanding move type deletes then clear + // their array and save back the main outstanding ops list + if (iOutstandingMoveTypeDeletes->Count()) + { + iOutstandingMoveTypeDeletes->Reset(); + + iImapOfflineControl.SetOffLineOpArrayL(iOutstandingOpsFolder, *iOutstandingOps); + } + } + + return finished; + } + +TBool CImapCompoundSyncService::MatchDeleteOp(const CImOffLineOperation& aOp , TBool aMoveDeletesOnly ) + { + return (aOp.OpType() == CImOffLineOperation::EOffLineOpMtmSpecific && aOp.MtmFunctionId() == EFnOffLineOpMoveDelete) || + (!aMoveDeletesOnly && aOp.OpType() == CImOffLineOperation::EOffLineOpDelete); + } + +TBool CImapCompoundSyncService::ProcessPendingDeleteOpsL( TMsvId aFolder, TBool aMoveDeletesOnly ) + { + TBool hadDeletes = EFalse; + + __LOG_FORMAT((iSession->LogId(), "CImapCompoundSyncService::ProcessPendingDeleteOpsL: Folder %x aMoveDeletesOnly=%d", aFolder, aMoveDeletesOnly)); + + // get the current offline operations of this folder + if (RefreshOutstandingOpsL(aFolder)) + { + // Fetch operation + CImOffLineOperation* thisop = new(ELeave)CImOffLineOperation(); + CleanupStack::PushL(thisop); + + thisop->CopyL(iOutstandingOps->Operation(0)); + + // check delete type + if (MatchDeleteOp(*thisop, aMoveDeletesOnly)) + { + do + { + // if can't find the entry then just skip it so it is + // removed from array + if (iServerEntry.SetEntry(thisop->MessageId()) == KErrNone) + { + // set its server deleted flag + TMsvEmailEntry entry=iServerEntry.Entry(); + entry.SetDeletedIMAP4Flag(ETrue); + ChangeEntryL(entry); + } + + // remove from the array and write back immediately + iOutstandingOps->Delete(0); + iImapOfflineControl.SetOffLineOpArrayL(iOutstandingOpsFolder, *iOutstandingOps); + + // check for finish + if (iOutstandingOps->CountOperations() == 0) + break; + + // get next op + thisop->CopyL(iOutstandingOps->Operation(0)); + } + while (MatchDeleteOp(*thisop, aMoveDeletesOnly)); + + hadDeletes = ETrue; + } + + CleanupStack::PopAndDestroy(thisop); + } + + return hadDeletes; + } + +TBool CImapCompoundSyncService::ProcessPendingDeleteOpsListL( TBool aMoveDeletesOnly ) + { + if(iNextFolderSync > 0) + { + if (ProcessPendingDeleteOpsL( iNextFolderSync, aMoveDeletesOnly )) + { + return ETrue; + } + } + + return EFalse; + } + +/** +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 CImapCompoundSyncService::ChangeEntryL(const TMsvEntry& aEntry) + { + User::LeaveIfError(iServerEntry.ChangeEntry(aEntry)); + } + +/** +Called when operation has completed and we are about to complete the caller. + +@param aErr Error code that we will complete with. +*/ +void CImapCompoundSyncService::DoComplete(TInt& aErr) + { + CImapCompoundBase::DoComplete(aErr); + + if (!iCancelForMigrate) + { + // Reset the flags which show if the new flags should be cleared on the + // next sync. + iSyncManager.ResetInboxClearNewFlags(); + iSyncManager.ResetNonInboxClearNewFlags(); + } + } + + +/** +Resumes the operation following a migration. +*/ +void CImapCompoundSyncService::ResumeOperationL(TRequestStatus& aStatus, CImapSession& aSession) + { + iSession = &aSession; + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::Resuming"); + __ASSERT_DEBUG(iCurrentStep==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncServiceCompoundUnexpectedState)); + iStopForMigrate = EFalse; + + switch (iNextStep) + { + case EInboxEarlyExpunge: + case EInboxEarlyDeletes: + { + // re-select the inbox, and then re-enter state machine + iSyncManager.Inbox()->SelectL(iStatus, *iSession); + SetActive(); + iCurrentStep = ESelectSourceMailboxRW; + break; + } + case EFolderEarlyDeletes: + case EFolderEarlyExpunge: + { + // re-select the inbox, and then re-enter state machine + iSyncManager.GetFolderL(iNextFolderSync)->SelectL(iStatus, *iSession); + iCurrentStep = ESelectSourceMailboxRW; + break; + } + case EInboxLateDeletes: + case EFolderLateDeletes: + case EInboxLateExpunge: + case EFolderLateExpunge: + { + // resume not expected since these states are only entered during + // a disconnection operation. Migrations are not accepted during + // diconnection - a downgrade results in the operation being + // cancelled and any sessions deleted. + iNextStep=EFinished; + CompleteSelf(); + break; + } + case EInboxSync: // select is called by the sync manager in this state + case ESyncSubscriptions: // select not required + case ESyncTree: // select not required + case ESyncFolder: // select is called by the sync manager in this state + case ESelectSyncFolder: // self-completed state, however can suspend in this state + case ESyncInboxAutoFetch: // select not required prior to resuming 2nd phase + case ESyncFolderAutoFetchCheck:// select not required prior to resuming 2nd phase + { + // resume the state machine in this state. + CompleteSelf(); + break; + } + case EInboxDoneOps: + { + if (iImapCompound) + { + // restart the compound object performing the offline-requested operation. + iCurrentStep = EInboxCheckPendingOps; + iImapCompound->ResumeOperationL(iStatus, *iSession); + SetActive(); + } + else + { + // Resume with check for further pending inbox operations + iNextStep = EInboxCheckPendingOps; + CompleteSelf(); + } + break; + } + case EFolderDoneOps: + { + if (iImapCompound) + { + // resume the compound object performing the offline-requested operation. + iCurrentStep = EFolderCheckPendingOPs; + iImapCompound->ResumeOperationL(iStatus, *iSession); + SetActive(); + } + else + { + // Resume with check for further pending folder operations + iNextStep = EFolderCheckPendingOPs; + CompleteSelf(); + } + break; + } + case ESyncFolderAutoFetch: + case EFolderCheckPendingOPs: // not expected... + case EInboxCheckPendingOps: // not expected... + case ESyncService: // self-completed state + case EFinished: + default: + { + __ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ESyncServiceCompoundCancelUnexpectedState)); + // something unexpected has happened. Complete the operation. + iNextStep = EFinished; + break; + } + } // end of switch (iNextStep) + Queue(aStatus); + } + +/** +Provides the sync class with an array of messages that are not to be fetched according +to the download rules. This function is called by the background sync controller if a +fetch command is received by the server MTM is performing a background synchronise, and +allows the sync operation to prevent attempts to simultaneously fetch the same message +via multiple imap sessions. + +If message content fetch is already underway, then the array is passed to the +CImapCompoundCopyToLocal object for immediate checking. The array is then stored +within this class and each subsequent copy to local operation is checked for matching +message id's. + +Note that it is possible for a message ID to be remove from the passed entry selection +in the case that that message is currently being fetched at the time of calling this +function. + +@param aSelection - the selection of messages that should not be autofetched +*/ +void CImapCompoundSyncService::RemoveFromSelectionL(CMsvEntrySelection& aDeleteSel) + { + if (iCurrentStep == ESyncFolderAutoFetch || + iCurrentStep == ESyncInboxAutoFetch || + iCurrentStep == ESyncFolderAutoFetchCheck) + { + ((CImapCompoundCopyToLocal*)iImapCompound)->RemoveFromSelection(aDeleteSel); + } + + // keep a copy of this selection to prevent future fetch clashes. + delete iDoNotFetchSel; + iDoNotFetchSel = aDeleteSel.CopyL(); + } + +/** +Indicates that the compound operation should complete as soon as it is possible +for the operation to be re-started without requiring a significant amount of +repeated communication. +The operation will be restarted by a call to ResumeOperationL() +Overrides the base-class implementation. +*/ +void CImapCompoundSyncService::StopForMigrate() + { + __LOG_TEXT(iSession->LogId(), "CImapCompoundSyncService::StopForMigrate()"); + + if (iCurrentStep==ESyncFolderAutoFetch || iCurrentStep==ESyncInboxAutoFetch) + { + // if doing a download-rules based fetch, instruct it to stop. + if(iImapCompound) + { + iImapCompound->StopForMigrate(); + } + } + iStopForMigrate = ETrue; + } +