email/imap4mtm/imapprotocolcontroller/src/cimapopbackgroundsync.cpp
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/imap4mtm/imapprotocolcontroller/src/cimapopbackgroundsync.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,351 @@
+// 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 <e32base.h>
+#include <mentact.h>
+
+#include "cimapopbackgroundsync.h"
+#include "cimapfolder.h"
+#include "cimapprotocolcontroller.h"
+#include "cimapmailstore.h" 
+#include "cimapsyncmanager.h"
+#include "cimapcompoundsyncservice.h"
+#include "cimapsessionconsts.h"
+#include "cimaplogger.h"
+
+CImapOpBackgroundSync::CImapOpBackgroundSync( MImapOpBackgroundSyncObserver& aBackgroundSyncObserver,
+											  CMsvServerEntry& aServerEntry, 
+										      CImapSyncManager& aSyncMan,
+											  CImapSettings& aImapSettings,
+											  CImapMailStore& aImapMailStore,
+											  CImapOfflineControl& aImapOfflineControl ) :
+	CActive(EPriorityStandard),
+	iBackgroundSyncObserver(aBackgroundSyncObserver),
+	iEntry(aServerEntry),
+	iSyncMan(aSyncMan),
+	iImapSettings(aImapSettings),
+	iImapMailStore(aImapMailStore),
+	iImapOfflineControl(aImapOfflineControl),
+	iMigrateState(ENotMigrating)
+	{
+	
+	}
+						   
+CImapOpBackgroundSync::~CImapOpBackgroundSync()
+	{
+	Cancel();
+	delete iCompoundSync;
+	iCompoundSync = NULL;
+	}
+
+/**
+Returns a CImapOpBackgroundSync. The background synchronise operation is started 
+by calling StartSync().
+
+@param aBackgroundSyncObserver Owning observer that is notified when the operation is completed.
+@param aSyncMan IMAP Sync Manager used to perform the full synchronise
+@return the newly created CImapOpBackgroundSync object. The caller is responsible for deleting
+the object. Usually this is done after the caller is notified by the CImapOpBackgroundSync
+object through the MImapOpBackgroundSyncObserver API.
+*/
+CImapOpBackgroundSync* CImapOpBackgroundSync::NewL( MImapOpBackgroundSyncObserver& aBackgroundSyncObserver,
+													CMsvServerEntry& aServerEntry,
+													CImapSyncManager& aSyncMan,
+													CImapSettings& aImapSettings,
+													CImapMailStore& aImapMailStore,
+													CImapOfflineControl& aImapOfflineControl  )
+	{
+	CImapOpBackgroundSync* self = new (ELeave) CImapOpBackgroundSync( aBackgroundSyncObserver,
+																	  aServerEntry,
+																	  aSyncMan,
+																	  aImapSettings,
+																	  aImapMailStore,
+																	  aImapOfflineControl );
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+void CImapOpBackgroundSync::ConstructL()
+	{
+	iCompoundSync = CImapCompoundSyncService::NewL( iSyncMan, 
+											    	iEntry, 
+											    	iImapSettings,
+											    	iImapMailStore,
+											    	iImapOfflineControl,
+											    	EFalse);
+	CActiveScheduler::Add(this);
+	}
+
+/**
+Starts the asynchronous background synchronisation. When the operation is completed, the
+observer iBackgroundSyncObserver is notified.
+*/	
+void CImapOpBackgroundSync::StartSync(CImapSession& aSession)
+	{
+	iSession = &aSession;
+	iState = EStartingSync;
+
+	__LOG_TEXT(iSession->LogId(), "CImapOpBackgroundSync::StartSync()");
+	
+	// Complete self
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+void CImapOpBackgroundSync::RunL()
+	{
+	__ASSERT_DEBUG(iSession!=NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EBackgroundSyncSessionIsNull));
+	
+	if (iMigrateState==EStoppingForMigrate)
+		{
+		// has the sync finished? if so, process normally as we do not need to resume.
+		// Otherwise mark the background sync as suspended
+		TImap4CompoundProgress compoundProgress;
+		iCompoundSync->Progress(compoundProgress);
+		if (compoundProgress.iGenericProgress.iState != TImap4GenericProgress::EIdle)
+			{
+			// the sync op has completed prematurely to allow the migration to occur
+			iMigrateState=ESuspendedForMigrate;
+			iBackgroundSyncObserver.BackgroundSyncComplete(iStatus.Int());
+			iSession = NULL;
+			return;
+			}
+		}
+
+	// Normal behaviour follows:
+	switch (iState)
+		{
+		case EStartingSync:
+			{
+			iCompoundSync->StartOperation(iStatus, *iSession);
+			iState = ESynchronising;
+			SetActive();
+			break;
+			}
+		case ESynchronising:
+			{
+			// call backgroundsynccomplete
+			iState = EFinished;
+			iBackgroundSyncObserver.BackgroundSyncComplete(iStatus.Int());
+			break;
+			}
+		case ECancelRecoveringSession:
+			{
+			// Call syncmanager api to clean up after cancel
+			iState = ECancelRefreshingSyncManager;
+			// break; fall through
+			}
+		case ECancelRefreshingSyncManager:
+			{
+			iState = EFinished;
+			if(iStatus.Int() != KErrNone)
+				{
+				// An error has occured during the flushing of the session.
+				// Pass the error code to the observer for processing.
+				iBackgroundSyncObserver.BackgroundSyncComplete(iStatus.Int());	
+				}
+			else
+				{
+				iBackgroundSyncObserver.BackgroundSyncComplete(KErrCancel);	
+				}
+			break;
+			}
+		default:
+			{
+			__ASSERT_DEBUG(iSession!=NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EBackgroundSyncUnexpectedState));
+			break;
+			}
+		} // end of switch (iState)
+	}
+	
+TInt CImapOpBackgroundSync::RunError(TInt aError)
+	{
+	// Complete with error
+	iBackgroundSyncObserver.BackgroundSyncComplete(aError);
+	return KErrNone;
+	}
+
+void CImapOpBackgroundSync::DoCancel()
+	{
+	switch(iState)
+		{
+		case ESynchronising:
+			{
+			// Do not change state - cleanup needs it.
+			// Do not delete as the status needs to be checked later.
+			if (iMigrateState==ECancellingForMigrate)
+				{
+				iCompoundSync->CancelForMigrate();
+				}
+			else
+				{
+				iCompoundSync->Cancel();
+				}
+			break;
+			}
+
+		case ECancelRecoveringSession:
+			{
+			iSession->Cancel();
+			break;
+			}
+
+		case EStartingSync:
+		case ECancelRefreshingSyncManager:
+			{
+			// self-completed or no outstanding request.
+			break;
+			}
+
+		default:
+			{
+			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBackgroundSyncCancelUnexpectedState));
+			break;
+			}
+		}
+	}
+
+/**
+Calls Cancel() to cancel any outstanding asynchronous service requests,
+then cleans up the sync manager and issues the appropriate command to 
+flushes the imap session if necessary.
+*/
+void CImapOpBackgroundSync::CancelAndCleanup()
+	{
+	__LOG_TEXT(iSession->LogId(), "CImapOpBackgroundSync::CancelAndCleanup()");
+	if (iMigrateState==ESuspendedForMigrate)
+		{
+		// already suspended.
+		iState = EFinished;
+		iBackgroundSyncObserver.BackgroundSyncComplete(KErrCancel);
+		}
+	else
+		{
+		Cancel();
+		if (iState==ESynchronising)
+			{
+			iSession->FlushCancelledCommand(iStatus);
+			iState=ECancelRecoveringSession;
+			SetActive();
+			}
+		else
+			{
+			iState = EFinished;
+			iBackgroundSyncObserver.BackgroundSyncComplete(KErrCancel);
+			}
+		}
+	}
+
+
+void CImapOpBackgroundSync::Progress(TImap4CompoundProgress& aCompoundProgress)
+	{
+	iCompoundSync->Progress(aCompoundProgress);	
+	}
+
+/**
+Returns ETrue if the background sync operation has been suspended to allow
+a bearer migration to occur.
+*/
+TBool CImapOpBackgroundSync::IsSuspendedForMigrate()
+	{
+	return (iMigrateState==ESuspendedForMigrate?ETrue:EFalse);
+	}
+
+/**
+Immediately cancels outstanding operation, and recovers the compound operation
+object to a state in which the operation may be restarted following migration
+to a new carrier.
+The operation will be restarted by a call to StartOperation()
+*/
+void CImapOpBackgroundSync::CancelForMigrate()
+	{
+	iMigrateState=ECancellingForMigrate;
+	Cancel();
+	iMigrateState=ESuspendedForMigrate;
+	iSession=NULL;
+	}
+
+/**
+Indicates that the compound operation should complete as soon as it is possible
+for the operation to be re-started without requiring large amounts of communication
+that has already been performed to be repeated to complete the operation.
+The operation will be restarted by a call to StartOperation()
+*/
+void CImapOpBackgroundSync::StopForMigrate()
+	{
+	iMigrateState=EStoppingForMigrate;
+	iCompoundSync->StopForMigrate();
+	}
+
+/**
+Resumes the background sync operation (following bearer migration).
+@param aSession the connected IMAP session 
+*/
+void CImapOpBackgroundSync::ResumeOperationL(CImapSession& aSession)
+	{
+	iSession = &aSession;
+	__ASSERT_DEBUG(iMigrateState==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::EBackgroundSyncUnexpectedState));
+	iMigrateState=ENotMigrating;
+	
+	switch (iState)
+		{
+		case ENotInUse:
+		case EStartingSync:
+			{
+			// the sync operation has not yet been started.
+			iCompoundSync->StartOperation(iStatus, *iSession);
+			iState = ESynchronising;
+			SetActive();
+			break;
+			}
+		case ESynchronising:
+			{
+			iCompoundSync->ResumeOperationL(iStatus, *iSession);
+			SetActive();
+			break;
+			}	
+		case ECancelRecoveringSession:
+		case ECancelRefreshingSyncManager:
+		case EFinished:
+		default:
+			{
+			// just auto-complete to force the background sync op to complete.
+			iState = ESynchronising;
+			TRequestStatus* status = &iStatus;
+			User::RequestComplete(status, KErrNone);
+			SetActive();
+			}
+		}
+	}
+
+/**
+Allows the protocol to specify an array of messages that should not be fetched
+using the download rules during background sync. This is called in the case that
+a copy to local or populate operation is requested while the background sync op
+is still in progress.
+
+@param aSelection - the selection of messages that should not be autofetched
+*/
+void CImapOpBackgroundSync::RemoveFromSelectionL(CMsvEntrySelection& aDeleteSel)
+	{
+	if (iCompoundSync)
+		{
+		iCompoundSync->RemoveFromSelectionL(aDeleteSel);
+		}
+	}
+