email/imap4mtm/imapprotocolcontroller/src/cimapprotocolcontroller.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 72 6f657153cbc5
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <imapset.h>
       
    17 #include <mentact.h>
       
    18 #include <miut_err.h>
       
    19 
       
    20 #include "cimapprotocolcontroller.h"
       
    21 #include "cimapsettings.h"
       
    22 #include "cimapsessionmanager.h"
       
    23 #include "cimapsession.h"
       
    24 #include "cimapsessionconsts.h"
       
    25 #include "cimapmailstore.h" 
       
    26 #include "cimapofflinecontrol.h"
       
    27 #include "cimapsyncmanager.h"
       
    28 #include "cimapfolder.h"
       
    29 
       
    30 #include "cimapcompoundcopyfromlocal.h"
       
    31 #include "cimapcompoundcopytolocal.h"
       
    32 #include "cimapcompoundcopywithinservice.h"
       
    33 #include "cimapcompoundcreate.h"
       
    34 #include "cimapcompounddelete.h"
       
    35 #include "cimapcompounddeletefolder.h"
       
    36 #include "cimapcompounddisconnect.h"
       
    37 #include "cimapcompoundrename.h"
       
    38 #include "cimapcompoundselect.h"
       
    39 #include "cimapcompoundsyncfolder.h"
       
    40 #include "cimapcompoundsynctree.h"
       
    41 #include "cimapcompoundsyncservice.h"
       
    42 
       
    43 #include "cimapopbackgroundsync.h"
       
    44 #include "cimapidlecontroller.h"
       
    45 #include "cimapupdateflagoperation.h"
       
    46 
       
    47 #include "cimaplogger.h"
       
    48 
       
    49 #include "mobilitytestmtmapi.h"
       
    50 
       
    51 // at the moment we do not need more than 2 sessions
       
    52 const TInt KImapSessionArrayGranularity = 2;
       
    53 
       
    54 const TUid KUidImapServerMtm = {0x10003C4E};
       
    55 
       
    56 CImapProtocolController::CImapProtocolController(CMsvServerEntry& aEntry,CImapOfflineControl& aImapOfflineControl):
       
    57 	CMsgActive(EPriorityStandard),
       
    58 	iEntry(aEntry),
       
    59 	iImapSessionArray(KImapSessionArrayGranularity),
       
    60 	iImapOfflineControl(aImapOfflineControl)
       
    61 	{
       
    62 	}
       
    63 	
       
    64 CImapProtocolController::~CImapProtocolController()
       
    65 	{
       
    66 	Cancel();
       
    67 
       
    68 	// The mail store needs to be deleted before DisconnectAll() as its destructor
       
    69 	// uses the session that DisconnectAll() destroys.
       
    70 	delete iImapMailStore;	
       
    71 
       
    72 	//serviceid indicates that we are online
       
    73 	if(iServiceId!=0)
       
    74 		{
       
    75 		DisconnectAll();
       
    76 		}
       
    77 
       
    78 	delete iBackgroundSyncOp;
       
    79 	delete iImapCompound;
       
    80 	delete iMigrateCompound;
       
    81 	delete iImapSyncManager;
       
    82 	delete iImapIdleController;
       
    83 	delete iImapSettings;
       
    84 	
       
    85 	delete iMobilityManager;
       
    86 
       
    87 	// Need to destroy the sessions before the session manager is deleted.
       
    88 	// This is because session manager will cleanup transport handler code,
       
    89 	// and it is important to ensure that the sockets are not being used
       
    90 	// by the session when that happens.
       
    91 	iImapSessionArray.ResetAndDestroy();
       
    92 	delete iImapSessionManager;
       
    93 	}
       
    94 
       
    95 EXPORT_C CImapProtocolController* CImapProtocolController::NewL(CMsvServerEntry& aEntry,CImapOfflineControl& aImapOfflineControl)
       
    96 	{
       
    97 	CImapProtocolController* self = new (ELeave) CImapProtocolController(aEntry,aImapOfflineControl);
       
    98 	CleanupStack::PushL(self);
       
    99 	self->ConstructL();
       
   100 	CleanupStack::Pop(self);
       
   101 	return self;
       
   102 	}
       
   103 
       
   104 /**
       
   105 Part of two phase construction
       
   106 Note that syncmanager is not constructed until a connection is made.
       
   107 */
       
   108 void CImapProtocolController::ConstructL()
       
   109 	{
       
   110 	iImapSettings       = CImapSettings::NewL(iEntry);
       
   111 	iImapMailStore 		= CImapMailStore::NewL(iEntry);
       
   112 	iImapSessionManager = CImapSessionManager::NewL(*iImapSettings, *iImapMailStore);
       
   113 
       
   114 	iFlushPrimary = EFalse;
       
   115 	// We're an active object...
       
   116 	CActiveScheduler::Add(this);
       
   117 	}
       
   118 
       
   119 /**
       
   120 Query connection status - return true if at least one IMAP Session exists and is 
       
   121 connected. Also return true if migrating.
       
   122 This is not a compound operation.
       
   123 
       
   124 @return 
       
   125 */
       
   126 EXPORT_C TBool CImapProtocolController::Connected() const
       
   127 	{
       
   128 	if (iImapSessionArray.Count() > 0 || iMigrateState != ENotMigrating)
       
   129 		{
       
   130 		// Sessions are deleted if a disconnect is observed,
       
   131 		// therefore the existance of any sessions indicates 
       
   132 		// that the Protocol Controller is connected.
       
   133 		return ETrue;
       
   134 		}
       
   135 	return EFalse;
       
   136 	}
       
   137 
       
   138 /**
       
   139 If a connected session already exists, this API shall complete immediately with 
       
   140 KErrServerBusy. Otherwise, this API uses the IMAP Session Manager to create and connect 
       
   141 an IMAP Session object that can be used for subsequent commands.
       
   142 On successful connection, the passed request status is completed. This API can not 
       
   143 be used to instantiate further IMAP Session objects.
       
   144 
       
   145 Sequence For Connect
       
   146 	CreateSession
       
   147 	SelectInboxRW
       
   148 	Finished
       
   149 	
       
   150 @param aStatus
       
   151 @param aSelection
       
   152 @leave KErrServerBusy if a connected session already exists
       
   153 */
       
   154 EXPORT_C void CImapProtocolController::ConnectL( TRequestStatus& aStatus,
       
   155 												 CMsvEntrySelection& aSelection )
       
   156 	{
       
   157 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::ConnectL()");
       
   158 	
       
   159 	ResetProgress();
       
   160 	
       
   161 	if (Connected())
       
   162 		{
       
   163 		// Do not call Complete() - this would result in the Protocol
       
   164 		// Controller disconnecting all sessions.
       
   165 		TRequestStatus* pStatus = &aStatus;
       
   166 		User::RequestComplete(pStatus, KErrServerBusy);
       
   167 		}
       
   168 	else
       
   169 		{
       
   170 		// Load the Service Settings
       
   171 		iServiceId = aSelection[0];
       
   172 		iImapSettings->LoadSettingsL(iServiceId);
       
   173 
       
   174 		// We're going online - create a session manager if none exists
       
   175 		if (iImapSessionManager==NULL)
       
   176 			{
       
   177 			// session manage may have been deleted due to a mobility error
       
   178 			iImapSessionManager = CImapSessionManager::NewL(*iImapSettings, *iImapMailStore);
       
   179 			}
       
   180 	
       
   181 		// create a sync manager
       
   182 		delete iImapSyncManager;
       
   183 		iImapSyncManager = NULL;
       
   184 		iImapSyncManager = CImapSyncManager::NewL( iEntry, *iImapSettings);
       
   185 		
       
   186 		// create the mobility manager if mobility supported
       
   187 		delete iMobilityManager;
       
   188 		iMobilityManager = NULL;
       
   189 
       
   190 		if (iImapSettings->BearerMobility())
       
   191 			{
       
   192 			iMobilityManager = CImMobilityManager::NewL(KUidImapServerMtm, iServiceId, *this);
       
   193 			}
       
   194 	
       
   195 		// Create the primary session pointer
       
   196 		CImapSession* imapSession = NULL;
       
   197 		iImapSessionArray.AppendL(imapSession);
       
   198 
       
   199 		// Request the session manager to connect the session
       
   200 		iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[0]);
       
   201 
       
   202 		iForegroundSession = 0;
       
   203 		iRequestedOp = EConnect;
       
   204 		iCurrentOp = iRequestedOp;
       
   205 
       
   206 		Queue(aStatus);
       
   207 		SetActive();
       
   208 		}
       
   209 	}
       
   210 
       
   211 /**
       
   212 This method allows the client to connect to an IMAP account and initialise a 
       
   213 background synchronisation of the account once connection has completed. If a 
       
   214 connected IMAP Session already exists, the API shall complete immdediately with 
       
   215 KErrServerBusy. 
       
   216 On successful connection, a background synchronisation is started and the passed 
       
   217 request status is completed. The background synchronisation is processed by a 
       
   218 CImapBackgroundSyncOp object, which will notify the Protocol Controller that 
       
   219 the process has completed via a callback function void 
       
   220 BackgroundSyncCompleted( TInt aError )
       
   221 
       
   222 Sequence For ConnectAndSynchronise
       
   223 	CreateSession
       
   224 	StartBackgroundSyncOp
       
   225 	Finished
       
   226 
       
   227 @param aStatus
       
   228 @param aSelection
       
   229 @leave KErrServerBusy if a connected session already exists
       
   230 */
       
   231 EXPORT_C void CImapProtocolController::ConnectAndSynchroniseL( TRequestStatus& aStatus, 
       
   232 															   CMsvEntrySelection& aSelection )
       
   233 	{
       
   234 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::ConnectAndSynchroniseL()");
       
   235 
       
   236 	// Issue the connect request (this will cause ResetProgress() to be called)
       
   237 	ConnectL(aStatus, aSelection);
       
   238 
       
   239 	// Create the Background Sync Operation object
       
   240 	if (IsActive())
       
   241 		{
       
   242 		__ASSERT_DEBUG(iBackgroundSyncOp==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EConnectAndSyncBgSyncOpIsNotNull));
       
   243 		iBackgroundSyncOp = CImapOpBackgroundSync::NewL(*this, iEntry, *iImapSyncManager, *iImapSettings, *iImapMailStore, iImapOfflineControl);
       
   244 		}
       
   245 	}
       
   246 
       
   247 /**
       
   248 Logs out and disconnects all connected sessions with the remote server.
       
   249 
       
   250 Disconnect request is handled and acted upon during migration, unlike other 
       
   251 client-requested operations which are rejected (with KErrServerBusy).
       
   252 
       
   253 The Bearer Mobility Manager is deleted prior to acting on this request,
       
   254 effectively de-registering the server MTM from the mobility framework
       
   255 
       
   256 @param aStatus
       
   257 */
       
   258 EXPORT_C void CImapProtocolController::DisconnectL(TRequestStatus& aStatus)
       
   259 	{
       
   260 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectL()");
       
   261 
       
   262 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDisconnectCompoundIsNotNull));
       
   263 	
       
   264 	// de-register for mobility notifications
       
   265 	delete iMobilityManager;
       
   266 	iMobilityManager = NULL;
       
   267 	
       
   268 	// Disconnect allowed to happen even if we are migrating...
       
   269 	switch (iMigrateState)
       
   270 		{
       
   271 		case ENotMigrating:
       
   272 		case EHandlingConnectError:
       
   273 			{
       
   274 			// normal behaviour...
       
   275 			DoDisconnectL(aStatus);
       
   276 			break;
       
   277 			}
       
   278 		case EConnectingAfterMigrate: // Cancel connecting of new session
       
   279 		case EStartingReconnect:	  // already disconnected. Cancel dummy request
       
   280 		case EWaitingForNewCarrier:   // already disconnected. Cancel dummy request
       
   281 		case EWaitingInitialCarrierRejected: // already disconnected. Cancel dummy request
       
   282 			{
       
   283 			Cancel();
       
   284 			// mark offline and complete
       
   285 			DisconnectAll();
       
   286 			Queue(aStatus);
       
   287 			Complete(KErrNone);
       
   288 			break;
       
   289 			}
       
   290 		case EDisconnectingForMigrate:
       
   291 			{
       
   292 			// already doing a graceful disconnect, switch to main state machine.
       
   293 			iMigrateState = ENotMigrating;
       
   294 			iRequestedOp  = EDisconnect;
       
   295 			iCurrentOp    = EDisconnect;
       
   296 			// however, using the iMigrateCompound pointer...
       
   297 			iImapCompound = iMigrateCompound;
       
   298 			iMigrateCompound = NULL;
       
   299 			Queue(aStatus);
       
   300 			break;
       
   301 			}
       
   302 		case EWaitingForOpToComplete:
       
   303 		case EWaitingForOpToStop:
       
   304 		default:
       
   305 			{
       
   306 			__ASSERT_DEBUG(iBackgroundSyncOp==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDisconnectUnexpectedMigrateState));
       
   307 			break;
       
   308 			}
       
   309 		}
       
   310 	}
       
   311 
       
   312 void CImapProtocolController::DoDisconnectL(TRequestStatus& aStatus)
       
   313 	{
       
   314 	// Unlike the other async methods, DisconnectL() will wait for any flush operation to finish
       
   315 	// and then initiate the disconnect.
       
   316 	// Consequently there is no need to call CompleteIfBackgroundOpInProgress()	
       
   317 	ResetProgress();
       
   318 	
       
   319 	iImapCompound = CImapCompoundDisconnect::NewL( *iImapSyncManager, 
       
   320 												   iEntry, 
       
   321 												   *iImapSettings,
       
   322 												   *iImapSessionManager,
       
   323 												   *iImapMailStore,
       
   324 												   iImapSessionArray,
       
   325 												   iImapOfflineControl,
       
   326 												   ETrue );
       
   327 	iRequestedOp = EDisconnect;
       
   328 	
       
   329 	if (iCurrentOp != ECancelRecoverPrimary)
       
   330 		{
       
   331 		// Cancel any outstanding background sync												   
       
   332 		if (iBackgroundSyncOp!=NULL)
       
   333 			{
       
   334 			iBackgroundSyncOp->Cancel();
       
   335 			delete iBackgroundSyncOp;
       
   336 			iBackgroundSyncOp=NULL;
       
   337 
       
   338 			// Flush the session, now that it has been cancelled
       
   339 			iCurrentOp = ECancelRecoverPrimary;
       
   340 			CImapSession* session = iImapSessionArray[0];
       
   341 			session->FlushCancelledCommand(iStatus);
       
   342 			SetActive();
       
   343 			}
       
   344 		else
       
   345 			{
       
   346 			StartPrimaryOperation();	
       
   347 			SetActive();	
       
   348 			}
       
   349 		}
       
   350 	
       
   351 	// NOTE: In the case of iCurrentOp == ECancelRecoverPrimary, DoRunL() will start the async 
       
   352 	// iImapCompound operation after the flush has completed.
       
   353 	// The iImapCompound will expect aStatus to have been queued so that it can be Completed later.
       
   354 	
       
   355 	Queue(aStatus);
       
   356 	}
       
   357 
       
   358 /**
       
   359 Checks the status of the CImapSessions
       
   360 
       
   361 @return ETrue if a backgroundsync is in progress and the second session is busy,
       
   362 		EFalse otherwise.
       
   363 */
       
   364 EXPORT_C TBool CImapProtocolController::Busy() const
       
   365 	{
       
   366 	// second session is busy if a compound operation exists.
       
   367 	if (BackgroundSyncInProgress() && iImapCompound!=NULL)
       
   368 		{
       
   369 		return ETrue;
       
   370 		}
       
   371 	return EFalse;	
       
   372 					
       
   373 	}
       
   374 
       
   375 /**
       
   376 Gets the access point ID in use for the connection to the server
       
   377 
       
   378 @param aIap On return stores the access point ID value
       
   379 
       
   380 @return KErrNone if successful, or a system wide error code
       
   381 */
       
   382 EXPORT_C TInt CImapProtocolController::GetAccessPointIdForConnection(TUint32& aAccessPointId) const
       
   383 	{
       
   384 	if (iImapSessionManager)
       
   385 		{
       
   386 		return iImapSessionManager->GetAccessPointIdForConnection(aAccessPointId);
       
   387 		}
       
   388 
       
   389 	return KErrNotFound;
       
   390 	}
       
   391 
       
   392 /**
       
   393 Returns whether a Background synchronisation is in progress
       
   394 
       
   395 @return ETrue if a Background synchronisation is in progress, EFalse otherwise
       
   396 */
       
   397 EXPORT_C TBool CImapProtocolController::BackgroundSyncInProgress() const
       
   398 	{
       
   399 	return (iBackgroundSyncOp != NULL);
       
   400 	}
       
   401 
       
   402 /**
       
   403 Cancels an outstanding background synchronise operation. Calls 
       
   404 CImapOpBackgroundSync::Cancel() to propagate the cancel and kicks off
       
   405 an asynchronous cleanup operation.
       
   406 The cancel request is completed immediately with KErrNone if no background
       
   407 sync was in operation, otherwise it is completed with KErrCancel when
       
   408 the cleanup process is complete.
       
   409 */	
       
   410 EXPORT_C void CImapProtocolController::CancelBackgroundSync(TRequestStatus& aStatus)
       
   411 	{
       
   412 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CancelBackgroundSync()");
       
   413 	
       
   414 	ResetProgress();
       
   415 	
       
   416 	Queue(aStatus);
       
   417 	if (BackgroundSyncInProgress())
       
   418 		{
       
   419 		if (iMigrateState != ENotMigrating && iBackgroundSyncOp->IsSuspendedForMigrate())
       
   420 			{
       
   421 			delete iBackgroundSyncOp;
       
   422 			iBackgroundSyncOp = NULL;
       
   423 			Complete(KErrCancel);
       
   424 			}
       
   425 		else
       
   426 			{
       
   427 			iBackgroundSyncOp->CancelAndCleanup();
       
   428 			iWaitForBackgroundSync = ETrue;
       
   429 			}
       
   430 		}
       
   431 	else
       
   432 		{
       
   433 		Complete(KErrNone);
       
   434 		}
       
   435 	}
       
   436 
       
   437 /**
       
   438 Wait for background sync operation to complete. This effectively makes a background 
       
   439 synchronise a foreground operation blocking subsequent Server MTM requests until the 
       
   440 synchonise is completed.
       
   441 
       
   442 @param aStatus
       
   443 */
       
   444 EXPORT_C void CImapProtocolController::WaitForBackground(TRequestStatus& aStatus)
       
   445 	{
       
   446 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::WaitForBackground()");
       
   447 	
       
   448 	ResetProgress();
       
   449 	
       
   450 	Queue(aStatus);
       
   451 	// Wait for background operation to complete: is one running?
       
   452 	if (!BackgroundSyncInProgress())
       
   453 		{
       
   454 		// No, complete immediately
       
   455 		Complete(KErrNone);
       
   456 		}
       
   457 	else
       
   458 		{
       
   459 		// Otherwise, wait for completion
       
   460 		iWaitForBackgroundSync = ETrue;
       
   461 		}
       
   462 	}
       
   463 
       
   464 
       
   465 /**
       
   466 Completes the passed request status if a background operation is in progress,
       
   467 or if the primary session is being recovered following a cancel operation.
       
   468 This should be called prior to starting a compound operation that requires the
       
   469 primary session to be performed.
       
   470 
       
   471 This method must be called before assigning iRequestedOp, 
       
   472 for any operation that requires the primary session.
       
   473 
       
   474 @return ETrue if the user request has been completed
       
   475 		EFalse otherwise.
       
   476 */
       
   477 TBool CImapProtocolController::CompleteIfBackgroundOpInProgress(TRequestStatus& aStatus)
       
   478 	{
       
   479 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CompleteIfBackgroundOpInProgress()");
       
   480 	if (BackgroundSyncInProgress() || iCurrentOp==ECancelRecoverPrimary || iMigrateState!=ENotMigrating)
       
   481 		{
       
   482 		// Complete the user request
       
   483 		// Do not call Complete() - this would result in the Protocol
       
   484 		// Controller disconnecting all sessions.
       
   485 		TRequestStatus* status = &aStatus;
       
   486 		User::RequestComplete(status, KErrServerBusy);
       
   487 		return ETrue;
       
   488 		}
       
   489 	return EFalse;
       
   490 	}
       
   491 	
       
   492 /**
       
   493 Synchronise Folder Tree - calls CImapSyncManager::SynchroniseTreeL()
       
   494 Sequence For SynchroniseTree
       
   495 	StopIdle
       
   496 	SynchroniseTree // CImapSyncManager Operation
       
   497 
       
   498 @param aStatus
       
   499 @leave
       
   500 */	
       
   501 EXPORT_C void CImapProtocolController::SynchroniseTreeL(TRequestStatus& aStatus)
       
   502 	{
       
   503 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::SynchroniseTreeL()");
       
   504 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESynchroniseTreeCompoundIsNotNull));
       
   505 
       
   506 	ResetProgress();
       
   507 
       
   508 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
   509 		{
       
   510 		iImapCompound = CImapCompoundSyncTree::NewL( *iImapSyncManager, 
       
   511 													 iEntry, 
       
   512 													 *iImapSettings );
       
   513 		
       
   514 		iRequestedOp = ESync;
       
   515 		StartPrimaryOperation();	
       
   516 		Queue(aStatus);
       
   517 		SetActive();
       
   518 		}
       
   519 	}
       
   520 
       
   521 
       
   522 /**
       
   523 Perform a full account synchronisation - calls CImapSyncManager::SynchroniseL()
       
   524 Sequence For SynchroniseAll
       
   525 	StopIdle
       
   526 	SynchroniseL  // CImapSyncManager Operation
       
   527 
       
   528 @param aStatus
       
   529 @leave
       
   530 */	
       
   531 EXPORT_C void CImapProtocolController::SynchroniseAllL( TRequestStatus& aStatus )
       
   532 	{
       
   533 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::SynchroniseAllL()");
       
   534 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESynchroniseAllCompoundIsNotNull));
       
   535 
       
   536 	ResetProgress();
       
   537 
       
   538 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
   539 		{
       
   540 		iImapCompound = CImapCompoundSyncService::NewL( *iImapSyncManager, 
       
   541 												    	iEntry, 
       
   542 												    	*iImapSettings,
       
   543 												    	*iImapMailStore,
       
   544 												    	iImapOfflineControl,
       
   545 												    	EFalse);
       
   546 	
       
   547 		iRequestedOp = ESync;
       
   548 		StartPrimaryOperation();	
       
   549 		Queue(aStatus);
       
   550 		SetActive();
       
   551 		}
       
   552 	}
       
   553 
       
   554 /**
       
   555 Callback function to notify Protocol Controller that a background sync 
       
   556 operation has completed.
       
   557 Deletes the CImapOpBackgroundComplete object that has just completed.
       
   558 If WaitForBackground has been previously called, completes the user request.
       
   559 
       
   560 @param aError
       
   561 */	
       
   562 EXPORT_C void CImapProtocolController::BackgroundSyncComplete(TInt aError)
       
   563 	{
       
   564 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::BackgroundSyncComplete()");
       
   565 	__ASSERT_DEBUG(iBackgroundSyncOp!=NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ENoBackgroundSyncInProgress));
       
   566 
       
   567 	// get final sync progress... 
       
   568 	// unless a foreground operation is being performed
       
   569 	if (iImapCompound == NULL)
       
   570 		{
       
   571 		iBackgroundSyncOp->Progress(iProgress);
       
   572 		}
       
   573 		
       
   574 	if (iMigrateState != ENotMigrating)
       
   575 		{
       
   576 		// If the protocol controller is not active, then there is no
       
   577 		// operation currently in progress. Therefore we are now ready to
       
   578 		// migrate. Complete the request here, and then Disconnect current sockets in DoMigrateRunL(). 
       
   579 		// We cannot just test existance of a compound operation object, as there may be a "paused" operation.
       
   580 		if (!IsActive())
       
   581 			{
       
   582 			// Complete the request so that, we migrate from DoMigrateRunL()
       
   583 			SetActive();
       
   584 			TRequestStatus* pStatus = &iStatus;
       
   585 			User::RequestComplete(pStatus, KErrNone);
       
   586 			}
       
   587 		
       
   588 		// the background sync may have been completed early to allow
       
   589 		// a migration to occur. If that is the case, then we do not want
       
   590 		// to delete the background sync operation object - it will need
       
   591 		// to be restarted once the migrate has occurred. Otherwise, just
       
   592 		// process the completion of the background sync normally.
       
   593 		if (iBackgroundSyncOp->IsSuspendedForMigrate())
       
   594 			{
       
   595 			return;
       
   596 			}
       
   597 		}
       
   598 
       
   599 	// Deleting the background sync op.
       
   600 	// CImapOpBackgroundComplete must finish immediately after calling this API
       
   601 	delete iBackgroundSyncOp;
       
   602 	iBackgroundSyncOp = NULL;
       
   603 	
       
   604 	if (aError>0)
       
   605 		{
       
   606 		// translate positive error codes, weed out non-fatal errors
       
   607 		ThranslateSessionError(aError);
       
   608 		}
       
   609 
       
   610 	TBool foregroundOpCancelled = EFalse;
       
   611 	if (aError==KErrNone || aError==KErrCancel)
       
   612 		{
       
   613 		if (iImapCompound==NULL && iMigrateState == ENotMigrating)
       
   614 			{
       
   615 			// only start IDLE if foreground operation not in progress
       
   616 			StartIdle();
       
   617 			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStateImapIdle);
       
   618 			}
       
   619 		}
       
   620 	else
       
   621 		{
       
   622 		// Cancel any foreground operation - the primary session has
       
   623 		// failed, so all sessions are to be torn down.
       
   624 		if (iImapCompound != NULL)
       
   625 			{
       
   626 			iImapCompound->Cancel();
       
   627 			foregroundOpCancelled = ETrue;
       
   628 			delete iImapCompound;
       
   629 			iImapCompound=NULL;
       
   630 			}
       
   631 
       
   632 		// DisconnectAll will be process by DoComplete if a client request is outstanding.
       
   633 		if (!iWaitForBackgroundSync && !foregroundOpCancelled)
       
   634 			{
       
   635 			// Drop all session connections and mark the service offline.
       
   636 			DisconnectAll();
       
   637 			}
       
   638 		}
       
   639 
       
   640 	// Store the error in the progress object
       
   641 	iProgress.iGenericProgress.iErrorCode=aError;
       
   642 	iProgress.iGenericProgress.iState=TImap4GenericProgress::EIdle;
       
   643 		
       
   644 	// Complete the client request if it was waiting for notification of 
       
   645 	// bg sync complete, or if we have cancelled an foreground operation
       
   646 	if (iWaitForBackgroundSync || foregroundOpCancelled)
       
   647 		{
       
   648 		iCancelInProgress = ETrue;
       
   649 		Complete(aError);
       
   650 		iCancelInProgress = EFalse;
       
   651 		}
       
   652 
       
   653 	iWaitForBackgroundSync = EFalse;
       
   654 	}
       
   655 
       
   656 /**
       
   657 CopyToLocalL() is used to fetch a selection of messages from the remote 
       
   658 server as a single operation, without return to idle state between handling each
       
   659 message. The email is fetched to the local mirror of the containing folder. Optionally 
       
   660 this function can also copy the message to a local folder, specified in aDestination. 
       
   661 A fetch to mirror only is performed by calling with aDestination set to 
       
   662 KMsvNullIndexEntryId
       
   663 
       
   664 Sequence For CopyToLocal
       
   665 	StopIdle
       
   666 	SelectSourceMailboxRO
       
   667 	FetchMessage(s)
       
   668 	InboxDuplicateCopy
       
   669 
       
   670 @param aStatus
       
   671 @param aSourceSel
       
   672 @param aDestination
       
   673 */
       
   674 EXPORT_C void CImapProtocolController::CopyToLocalL(TRequestStatus& aStatus, 
       
   675 													const CMsvEntrySelection& aSourceSel, 
       
   676 													const TMsvId aDestination)
       
   677 	{
       
   678 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CopyToLocalL()");
       
   679 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundIsNotNull));
       
   680 
       
   681 	ResetProgress();
       
   682 
       
   683 	// Instead of calling CompleteIfBackgroundOpInProgress(), just check whether a flush is occurring 
       
   684 	// on the primary session (always index 0).
       
   685 	// If a background op is in progress, then the copy will be performed on a secondary session.
       
   686 	if (iCurrentOp == ECancelRecoverPrimary || iMigrateState != ENotMigrating)
       
   687 		{
       
   688 		// Do not call Complete() - this would result in the Protocol
       
   689 		// Controller disconnecting all sessions.
       
   690 		TRequestStatus* pStatus = &aStatus;
       
   691 		User::RequestComplete(pStatus, KErrServerBusy);
       
   692 
       
   693 		return;
       
   694 		}
       
   695 	
       
   696 	// must be set before calling SelectSession
       
   697 	iRequestedOp = ECopyToLocal;
       
   698 
       
   699 	// request the session to use.
       
   700 	TBool startNow = SelectSessionL(iForegroundSession);
       
   701 
       
   702 	if (iBackgroundSyncOp && iImapSettings->UseSyncDownloadRules())
       
   703 		{
       
   704 		// we need a non-const copy of the message selection to operate on.
       
   705 		CMsvEntrySelection* selection = aSourceSel.CopyLC();
       
   706 		
       
   707 		// show the list to the background sync controller
       
   708 		iBackgroundSyncOp->RemoveFromSelectionL(*selection);
       
   709 		// Create the copy to local operation object using the (possibly) updated selection
       
   710 		iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, 
       
   711 		                    			               iEntry, 
       
   712 		                                			   *iImapSettings,
       
   713 		                                			   *iImapMailStore,
       
   714 		                                               EFalse,
       
   715 		                                               *selection,
       
   716 		                                               aDestination);
       
   717 		CleanupStack::PopAndDestroy(selection);
       
   718 		}
       
   719 	else
       
   720 		{
       
   721 		// Create the compound operation object
       
   722 		iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, 
       
   723 		                    			               iEntry, 
       
   724 		                                			   *iImapSettings,
       
   725 		                                			   *iImapMailStore,
       
   726 		                                               EFalse,
       
   727 		                                               aSourceSel,
       
   728 		                                               aDestination);
       
   729 		}
       
   730 
       
   731 	if (startNow)
       
   732 		{
       
   733 		// A session is ready - start the command
       
   734 		// otherwise a request to connect a secondary session has been issued
       
   735 		if (iForegroundSession==0)
       
   736 			{
       
   737 			// Primary session
       
   738 			StartPrimaryOperation();
       
   739 			}
       
   740 		else
       
   741 			{
       
   742 			// Secondary session
       
   743 			iCurrentOp = iRequestedOp;
       
   744 			iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]);
       
   745 			}
       
   746 		}	
       
   747 	
       
   748 	Queue(aStatus);
       
   749 	SetActive();
       
   750 	}
       
   751 
       
   752 
       
   753 /**
       
   754 PopulateL() performs the same action as CopyToLocalL(), however uses the passed 
       
   755 TImImap4GetPartialMailInfo object instead of using the default parameters. This 
       
   756 allows the client application to specify the parts of the message that are to be 
       
   757 fetched, and to impose limits to on the amount of data that can be transferred.
       
   758 
       
   759 Sequence For Populate
       
   760 	StopIdle
       
   761 	SelectSourceMailboxRO
       
   762 	FetchMessage(s)
       
   763 	InboxDuplicateCopy
       
   764 
       
   765 @param aStatus
       
   766 @param aSourceSel
       
   767 @param aGetPartialMailInfo
       
   768 */
       
   769 EXPORT_C void CImapProtocolController::PopulateL(TRequestStatus& aStatus, 
       
   770                                                  const CMsvEntrySelection& aSourceSel, 
       
   771                                                  TImImap4GetPartialMailInfo aGetPartialMailInfo)
       
   772 	{
       
   773 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::PopulateL() - START - iCurrentOp: %d, iRequestedOp: %d", iCurrentOp, iRequestedOp ));
       
   774 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EPopulateCompoundIsNotNull));
       
   775 
       
   776 	// Instead of calling CompleteIfBackgroundOpInProgress(), just check whether a flush is occurring 
       
   777 	// on the primary session (always index 0).
       
   778 	// If a background op is in prgoress, then the copy will be performed on a secondary session.
       
   779 	ResetProgress();
       
   780 
       
   781 	// If a flush is occurring on the primary session (always index 0) then we are busy
       
   782 	if (iCurrentOp == ECancelRecoverPrimary || iMigrateState != ENotMigrating)
       
   783 		{
       
   784 		// Do not call Complete() - this would result in the Protocol
       
   785 		// Controller disconnecting all sessions.
       
   786 		TRequestStatus* pStatus = &aStatus;
       
   787 		User::RequestComplete(pStatus, KErrServerBusy);
       
   788 	    __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - END - KErrServerBusy...");
       
   789 		return;
       
   790 		}
       
   791 
       
   792 	// must be set before calling SelectSessionL()
       
   793 	iRequestedOp = EPopulate;		
       
   794 
       
   795 	// request the session to use.
       
   796 	TBool startNow = SelectSessionL(iForegroundSession);
       
   797 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::PopulateL() - iCurrentOp: %d, iRequestedOp: %d, startNow: %d", iCurrentOp, iRequestedOp, startNow ));
       
   798 	
       
   799 	if (iBackgroundSyncOp && iImapSettings->UseSyncDownloadRules())
       
   800 		{
       
   801 		// we need a non-const copy of the message selection to operate on.
       
   802 		CMsvEntrySelection* selection = aSourceSel.CopyLC();
       
   803 		
       
   804 		// show the list to the background sync controller
       
   805 		iBackgroundSyncOp->RemoveFromSelectionL(*selection);
       
   806 		// Create the copy to local operation object using the (possibly) updated selection
       
   807 		iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, 
       
   808 			                			               iEntry, 
       
   809 		    	                        			   *iImapSettings,
       
   810 		        	                    			   *iImapMailStore, 
       
   811 		            	                               EFalse,
       
   812 		                	                           *selection,
       
   813 		                    	                       KMsvNullIndexEntryId,
       
   814 		                        	                   aGetPartialMailInfo);
       
   815 		CleanupStack::PopAndDestroy(selection);
       
   816 		}
       
   817 	else
       
   818 		{
       
   819 		// Create the compound operation object
       
   820 		iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, 
       
   821 	    	                			               iEntry, 
       
   822 	        	                        			   *iImapSettings,
       
   823 	            	                    			   *iImapMailStore, 
       
   824 	                	                               EFalse,
       
   825 	                    	                           aSourceSel,
       
   826 	                        	                       KMsvNullIndexEntryId,
       
   827 	                            	                   aGetPartialMailInfo);
       
   828 		}
       
   829 
       
   830 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - done creation of CompoundCopyToLocal...");
       
   831 	if (startNow)
       
   832 		{
       
   833 		// A session is ready - start the command
       
   834 		// otherwise a request to connect a secondary session has been issued
       
   835 		if (iForegroundSession==0)
       
   836 			{
       
   837 			// Primary session
       
   838 	        __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - starting primary op...");
       
   839 			StartPrimaryOperation();
       
   840 			}
       
   841 		else
       
   842 			{
       
   843 			// Secondary session
       
   844 	        __LOG_TEXT(KDefaultLog, "CImapProtocolController::PopulateL() - starting compound op...");
       
   845 			iCurrentOp = iRequestedOp;
       
   846 			iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]);
       
   847 			}
       
   848 		}	
       
   849 	
       
   850 	Queue(aStatus);
       
   851 	SetActive();
       
   852 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::PopulateL() - END - iCurrentOp: %d, iRequestedOp: %d, startNow: %d", iCurrentOp, iRequestedOp, startNow ));
       
   853 	}
       
   854 
       
   855 /**
       
   856 MoveToCopyL() shall enable a selection of messages to be moved as a single operation, 
       
   857 without return to idle state between handling each message. If a message has not been 
       
   858 previously fetched (ie is not complete on the local mirror of the IMAP folder) the 
       
   859 message is fetched to the local mirror and a copy is then made in the local service 
       
   860 folder. The message is then deleted from the IMAP folder on the remote server and the 
       
   861 local mirror.
       
   862 
       
   863 Sequence For MoveToLocal
       
   864 	StopIdle
       
   865 	SelectSourceMailbox 
       
   866 	FetchMessage
       
   867 	InboxDuplicateCopy
       
   868 	DeleteMessage
       
   869 
       
   870 @param aStatus
       
   871 @param aSourceSel
       
   872 @param aDestination
       
   873 */	
       
   874 EXPORT_C void CImapProtocolController::MoveToLocalL(TRequestStatus& aStatus, 
       
   875 													const CMsvEntrySelection& aSourceSel, 
       
   876 													const TMsvId aDestination)
       
   877 	{
       
   878 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::MoveToLocalL()");
       
   879 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EMoveToLocalCompoundIsNotNull));
       
   880 
       
   881 	ResetProgress();
       
   882 
       
   883 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
   884 		{
       
   885 		// We can't do a 'movetolocal' with the destination being the same as the
       
   886 		// source, as then the mirror will be out of sync. We must be moving to somewhere
       
   887 		// outside this service. Check this.
       
   888 		if (!IdIsLocalL(aDestination))
       
   889 			{
       
   890 			// Complete the user request
       
   891 			// Do not call Complete() - this would result in the Protocol
       
   892 			// Controller disconnecting all sessions.
       
   893 			TRequestStatus* status = &aStatus;
       
   894 			User::RequestComplete(status, KErrNotSupported);
       
   895 			}
       
   896 		else
       
   897 			{
       
   898 			iImapCompound = CImapCompoundCopyToLocal::NewL(*iImapSyncManager, 
       
   899 														   iEntry, 
       
   900 														   *iImapSettings,
       
   901 														   *iImapMailStore,
       
   902 														   ETrue,
       
   903 		                                               	   aSourceSel,
       
   904 		                                               	   aDestination);
       
   905 			
       
   906 			iRequestedOp = EMoveToLocal;
       
   907 			StartPrimaryOperation();
       
   908 			Queue(aStatus);
       
   909 			SetActive();
       
   910 			}
       
   911 		}
       
   912 	}
       
   913 
       
   914 /**
       
   915 Copy within service is the operation of moving a message or selection of messages from 
       
   916 one mailbox  to another on the remote IMAP server. This is done by issuing a COPY IMAP 
       
   917 command to the remote server, followed by a sync operation on the destination folder.
       
   918 
       
   919 Sequence For CopyWithinService
       
   920 	StopIdle
       
   921 	SelectSourceMailboxRO
       
   922 	CopyMessage
       
   923 	SelectDestinationMailboxRO
       
   924 	NewSyncFolder
       
   925 
       
   926 @param aStatus
       
   927 @param aSourceSel
       
   928 @param aDestination
       
   929 */
       
   930 EXPORT_C void CImapProtocolController::CopyWithinServiceL( TRequestStatus& aStatus, 
       
   931 							 					  		   const CMsvEntrySelection& aSourceSel, 
       
   932 							 					  		   const TMsvId aDestination )
       
   933 	{
       
   934 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CopyWithinServiceL()");
       
   935 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundIsNotNull));
       
   936 	
       
   937 	ResetProgress();
       
   938 
       
   939 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
   940 		{	
       
   941 		iImapCompound = CImapCompoundCopyWithinService::NewL( *iImapSyncManager, 
       
   942 															  iEntry, 
       
   943 															  *iImapSettings,
       
   944 															  EFalse,
       
   945 															  aSourceSel,
       
   946 															  aDestination);
       
   947 		
       
   948 		iRequestedOp = ECopyWithinService;
       
   949 		StartPrimaryOperation();
       
   950 		Queue(aStatus);
       
   951 		SetActive();
       
   952 		}
       
   953 	}
       
   954 
       
   955 /**
       
   956 Move within service is the same as Copy Within Service, however the message is deleted 
       
   957 from the original location following the copy operation.
       
   958 
       
   959 Sequence For MoveWithinService
       
   960 	StopIdle
       
   961 	SelectSourceMailboxRW
       
   962 	CopyMessage
       
   963 	DeleteMessage
       
   964 	SelectDestinationMailboxRO
       
   965 	NewSyncFolder
       
   966 	
       
   967 @param aStatus
       
   968 @param aSourceSel
       
   969 @param aDestination
       
   970 */
       
   971 EXPORT_C void CImapProtocolController::MoveWithinServiceL( TRequestStatus& aStatus, 
       
   972 							 					  		   const CMsvEntrySelection& aSourceSel, 
       
   973 							 					  		   const TMsvId aDestination )
       
   974 	{
       
   975 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::MoveWithinServiceL()");
       
   976 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EMoveWithinServiceCompoundIsNotNull));
       
   977 	
       
   978 	ResetProgress();
       
   979 	
       
   980 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
   981 		{	
       
   982 		iImapCompound = CImapCompoundCopyWithinService::NewL( *iImapSyncManager, 
       
   983 															  iEntry, 
       
   984 															  *iImapSettings,
       
   985 															  ETrue,
       
   986 															  aSourceSel,
       
   987 															  aDestination );
       
   988 
       
   989 		iRequestedOp = EMoveWithinService;
       
   990 		StartPrimaryOperation();
       
   991 		Queue(aStatus);
       
   992 		SetActive();
       
   993 		}
       
   994 	}
       
   995 
       
   996 /**
       
   997 Copy from local is the action of copying an email from a local service folder (for 
       
   998 example the local inbox) to a folder on the remote IMAP service. This is done using 
       
   999 the IMAP APPEND command.
       
  1000 
       
  1001 Sequence For CopyFromLocal
       
  1002 	AppendMessage
       
  1003 	SelectDestinationMailboxRO
       
  1004 	NewSyncFolder
       
  1005 
       
  1006 @param aStatus
       
  1007 @param aSourceSel
       
  1008 @param aDestination
       
  1009 */	
       
  1010 EXPORT_C void CImapProtocolController::CopyFromLocalL( TRequestStatus& aStatus, 
       
  1011 						 					  		   const CMsvEntrySelection& aSourceSel, 
       
  1012 						 					  		   const TMsvId aDestination )
       
  1013 	{
       
  1014 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CopyFromLocalL()");
       
  1015 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundIsNotNull));
       
  1016 	
       
  1017 	ResetProgress();
       
  1018 	
       
  1019 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1020 		{	
       
  1021 		iImapCompound = CImapCompoundCopyFromLocal::NewL( *iImapSyncManager, 
       
  1022 														  iEntry, 
       
  1023 														  *iImapSettings,
       
  1024 														  EFalse,
       
  1025 														  aSourceSel,
       
  1026 														  aDestination );
       
  1027 		
       
  1028 		iRequestedOp = ECopyFromLocal;
       
  1029 		StartPrimaryOperation();
       
  1030 		Queue(aStatus);
       
  1031 		SetActive();
       
  1032 		}
       
  1033 	}
       
  1034 
       
  1035 /**
       
  1036 Move from local is the action of moving an email from a local service folder (for 
       
  1037 example the local inbox) to a folder on the remote IMAP service. It is performed 
       
  1038 by following the same steps as for a Copy From Local operation, using the IMAP APPEND 
       
  1039 command, however the local copy of the message is deleted after the APPEND has 
       
  1040 successfully completed.
       
  1041 
       
  1042 Sequence For MoveFromLocal
       
  1043 	StopIdle
       
  1044 	AppendMessage
       
  1045 	DeleteLocalMessage
       
  1046 	SelectDestinationMailboxRO
       
  1047 	NewSyncFolder
       
  1048 
       
  1049 @param aStatus
       
  1050 @param aSourceSel
       
  1051 @param aDestination
       
  1052 */
       
  1053 EXPORT_C void CImapProtocolController::MoveFromLocalL( TRequestStatus& aStatus, 
       
  1054 						 					  		   const CMsvEntrySelection& aSourceSel, 
       
  1055 						 					  		   const TMsvId aDestination )
       
  1056 	{
       
  1057 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::MoveFromLocalL()");
       
  1058 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyFromLocalCompoundIsNotNull));
       
  1059 	
       
  1060 	ResetProgress();
       
  1061 	
       
  1062 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1063 		{
       
  1064 		iImapCompound = CImapCompoundCopyFromLocal::NewL( *iImapSyncManager, 
       
  1065 														  iEntry, 
       
  1066 														  *iImapSettings,
       
  1067 														  ETrue,
       
  1068 														  aSourceSel,
       
  1069 														  aDestination );
       
  1070 	
       
  1071 		iRequestedOp = EMoveFromLocal;
       
  1072 		StartPrimaryOperation();
       
  1073 		Queue(aStatus);
       
  1074 		SetActive();
       
  1075 		}
       
  1076 	}
       
  1077 
       
  1078 /**
       
  1079 Deletes the specified messages from the remote server.
       
  1080 
       
  1081 Sequence For Delete
       
  1082 	StopIdle
       
  1083 	SelectSourceMailboxRW
       
  1084 	Store /delete flags for each message
       
  1085 	Expunge remote messages
       
  1086 	Delete local messages
       
  1087 
       
  1088 @param aStatus
       
  1089 @param aSourceSel
       
  1090 */
       
  1091 EXPORT_C void CImapProtocolController::DeleteL(TRequestStatus& aStatus, 
       
  1092 									   		   const CMsvEntrySelection& aSourceSel)
       
  1093 	{
       
  1094 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DeleteL()");
       
  1095 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDeleteCompoundIsNotNull));
       
  1096 	
       
  1097 	ResetProgress();
       
  1098 	
       
  1099 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1100 		{
       
  1101 		// Create the compound object for message delete
       
  1102 		iImapCompound = CImapCompoundDelete::NewL(*iImapSyncManager,
       
  1103 												  iEntry,
       
  1104 												  *iImapSettings,
       
  1105 												  aSourceSel);
       
  1106 
       
  1107 		iRequestedOp = EDelete;
       
  1108 		StartPrimaryOperation();
       
  1109 		Queue(aStatus);
       
  1110 		SetActive();
       
  1111 		}
       
  1112 	}
       
  1113 
       
  1114 /**
       
  1115 Deletes the specified folder(s) on the remote IMAP Server.
       
  1116 
       
  1117 Sequence For DeleteFolder
       
  1118 	StopIdle
       
  1119 	SelectSourceMailboxRW
       
  1120 	DeleteAllMessages
       
  1121 	CloseFolder
       
  1122 	DeleteLocalFolder
       
  1123 
       
  1124 @param aStatus
       
  1125 @param aSelection
       
  1126 */
       
  1127 EXPORT_C void CImapProtocolController::DeleteFolderL( TRequestStatus& aStatus, 
       
  1128 											 		  const CMsvEntrySelection& aSelection )
       
  1129 	{
       
  1130 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DeleteFolderL()");
       
  1131 	__ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EDeleteFolderCompoundIsNotNull));
       
  1132 
       
  1133 	ResetProgress();
       
  1134 	
       
  1135 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1136 		{
       
  1137 		iImapCompound = CImapCompoundDeleteFolder::NewL( *iImapSyncManager,
       
  1138 													     iEntry,
       
  1139 													     *iImapSettings,
       
  1140 													     aSelection );
       
  1141 													     
       
  1142 		iRequestedOp = EDelete;
       
  1143 		StartPrimaryOperation();
       
  1144 		Queue(aStatus);
       
  1145 		SetActive();
       
  1146 		}	
       
  1147 	}
       
  1148 
       
  1149 /**
       
  1150 NewOnlySyncL() is used to synchronise recent messages in the specified folder, 
       
  1151 i.e. any messages that have arrived in the remote IMAP mailbox since the last 
       
  1152 synchronisation. This is done by requesting (FETCHing) the header details for 
       
  1153 messages with UID's that are greater than the highest UID of the messages present 
       
  1154 in the local mirror of the folder. The message's header summary information, 
       
  1155 flags etc are stored as new entries in the Message Server entry array under the 
       
  1156 folder entry, and the header information is streamed to the Mailstore using the 
       
  1157 Mailstore API. 
       
  1158 
       
  1159 Sequence For NewSyncFolder
       
  1160 	StopIdle
       
  1161 	SelectSourceMailboxRW
       
  1162 	NewSyncFolder
       
  1163 
       
  1164 @param aStatus
       
  1165 */
       
  1166 EXPORT_C void CImapProtocolController::NewOnlySyncFolderL( TRequestStatus& aStatus )
       
  1167 	{
       
  1168 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::NewOnlySyncFolderL()");
       
  1169 	__ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ENewOnlySyncFolderCompoundIsNotNull));
       
  1170 
       
  1171 	ResetProgress();
       
  1172 	
       
  1173 	if (iMigrateState!=ENotMigrating)
       
  1174 		{
       
  1175 		// Complete the user request if migrating.
       
  1176 		// Do not call Complete() - this would result in the Protocol
       
  1177 		// Controller disconnecting all sessions.
       
  1178 		TRequestStatus* status = &aStatus;
       
  1179 		User::RequestComplete(status, KErrServerBusy);
       
  1180 		return;
       
  1181 		}
       
  1182 	
       
  1183 	// If we support idle, and the server we are talking to supports idle,
       
  1184 	// then we don't need to do the new only sync as IMAP idle will take
       
  1185 	// care of it for us.
       
  1186 	// Just complete the user request with KErrNone.
       
  1187 	if (iImapSettings->ImapIdle() && iImapSessionArray[0]->ImapIdleSupported())
       
  1188 		{
       
  1189 		__LOG_TEXT(KDefaultLog, "CImapProtocolController::NewOnlySyncFolderL() - Immediate complete as idle is in use");
       
  1190 		Queue(aStatus);
       
  1191 		Complete(KErrNone);
       
  1192 		return;
       
  1193 		}
       
  1194 	
       
  1195 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1196 		{	
       
  1197 		CImapFolder* folder = iImapSyncManager->Inbox();
       
  1198 		TMsvId inboxId = folder->MailboxId();
       
  1199 		
       
  1200 		iImapCompound = CImapCompoundSyncFolder::NewL( *iImapSyncManager,
       
  1201 													   iEntry,
       
  1202 													   *iImapSettings, 
       
  1203 													   *iImapMailStore, 
       
  1204 													   ETrue,
       
  1205 													   inboxId);
       
  1206 
       
  1207 		iRequestedOp = ESync;
       
  1208 		StartPrimaryOperation();
       
  1209 		Queue(aStatus);
       
  1210 		SetActive();
       
  1211 		}
       
  1212 	}
       
  1213 
       
  1214 /**
       
  1215 The full synchronisation of a folder involves the synchronisation of messages newly 
       
  1216 received at the IMAP server, as described for NewOnlySyncL, above, and the 
       
  1217 synchronisation of "old messages", ie messages that have previously been synchronised 
       
  1218 to the local mirror of the folder.
       
  1219 When synchronising old messages, messages that have been marked for delete locally 
       
  1220 are marked such on the remote folder (the actual delete occurs either at the end of 
       
  1221 the synchronisation process, or is deferred until the connection is cancelled), 
       
  1222 messages that have been removed from the remote server (by another client) are 
       
  1223 deleted locally and any outstanding offline operations are performed, for example 
       
  1224 move operations may be outstanding, etc.
       
  1225 
       
  1226 Sequence For FullSyncFolder
       
  1227 	StopIdle
       
  1228 	SelectSourceMailboxRW
       
  1229 	SyncFolder
       
  1230 
       
  1231 @param aStatus
       
  1232 @param aFolder
       
  1233 */
       
  1234 EXPORT_C void CImapProtocolController::FullSyncFolderL( TRequestStatus& aStatus, 
       
  1235 											   			const TMsvId aFolder )
       
  1236 	{
       
  1237 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::FullSyncFolderL()");
       
  1238 	__ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EFullSyncFolderCompoundIsNotNull));
       
  1239 	
       
  1240 	ResetProgress();
       
  1241 
       
  1242 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1243 		{
       
  1244 		iImapCompound = CImapCompoundSyncFolder::NewL( *iImapSyncManager,
       
  1245 													   iEntry,
       
  1246 													   *iImapSettings,
       
  1247 													   *iImapMailStore,
       
  1248 													   EFalse,
       
  1249 													   aFolder );
       
  1250 
       
  1251 		iRequestedOp = ESync;
       
  1252 		StartPrimaryOperation();
       
  1253 		Queue(aStatus);
       
  1254 		SetActive();
       
  1255 		}
       
  1256 	}
       
  1257 
       
  1258 /**
       
  1259 SELECT is made available to the client application directly via an IMAP MTM command 
       
  1260 which is handled by this function. It allows the client to specifically SELECT a 
       
  1261 mailbox and then, using the Synchronise MTM command, to specifically request the 
       
  1262 selected mailbox is synchronised.
       
  1263 
       
  1264 Sequence For Select
       
  1265 	StopIdle
       
  1266 	SelectSourceMailboxRW
       
  1267 
       
  1268 @param aStatus
       
  1269 @param aFolder
       
  1270 */	
       
  1271 EXPORT_C void CImapProtocolController::SelectL(TRequestStatus& aStatus, const TMsvId aFolder)
       
  1272 	{
       
  1273 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::SelectL()");
       
  1274 	__ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ESelectCompoundIsNotNull));
       
  1275 	
       
  1276 	ResetProgress();
       
  1277 	
       
  1278 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1279 		{
       
  1280 		iImapCompound = CImapCompoundSelect::NewL( *iImapSyncManager, 
       
  1281 												   iEntry, 
       
  1282 												   *iImapSettings,
       
  1283 												   aFolder );
       
  1284 
       
  1285 		iRequestedOp = ESelect;
       
  1286 		StartPrimaryOperation();
       
  1287 		Queue(aStatus);
       
  1288 		SetActive();
       
  1289 		}
       
  1290 	}
       
  1291 
       
  1292 /**
       
  1293 Performs a full sync on the currently selected mailbox.
       
  1294 
       
  1295 Sequence For FullSyncSelectedFolder
       
  1296 	StopIdle
       
  1297 	SyncFolder
       
  1298 
       
  1299 @param aStatus
       
  1300 */	
       
  1301 EXPORT_C void CImapProtocolController::FullSyncSelectedFolderL( TRequestStatus& aStatus )
       
  1302 	{
       
  1303 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::FullSyncSelectedFolderL()");
       
  1304 	__ASSERT_DEBUG( iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EFullSyncSelectedFolderCompoundIsNotNull));
       
  1305 	
       
  1306 	ResetProgress();
       
  1307 	
       
  1308 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1309 		{
       
  1310 		iImapCompound = CImapCompoundSyncFolder::NewL( *iImapSyncManager,
       
  1311 													   iEntry,
       
  1312 													   *iImapSettings,
       
  1313 													   *iImapMailStore, 
       
  1314 													   EFalse );
       
  1315 		
       
  1316 		iRequestedOp = ESync;
       
  1317 		StartPrimaryOperation();
       
  1318 		Queue(aStatus);
       
  1319 		SetActive();
       
  1320 		}
       
  1321 	}
       
  1322 	
       
  1323 /**
       
  1324 Creates a new folder on the remote IMAP service with the given name.
       
  1325 
       
  1326 Sequence For Create
       
  1327 	StopIdle
       
  1328 	Create
       
  1329 
       
  1330 @param aStatus
       
  1331 @param aParent
       
  1332 @param aLeafName
       
  1333 @param aFolder
       
  1334 */
       
  1335 EXPORT_C void CImapProtocolController::CreateL( TRequestStatus& aStatus, 
       
  1336 				  					   			const TMsvId aParent, 
       
  1337 				  					   			const TDesC& aLeafName, 
       
  1338 				  					   			const TBool aFolder )
       
  1339 	{
       
  1340 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CreateL()");
       
  1341 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundIsNotNull));
       
  1342 	
       
  1343 	ResetProgress();
       
  1344 	
       
  1345 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1346 		{
       
  1347 		iImapCompound = CImapCompoundCreate::NewL( *iImapSyncManager,
       
  1348 												   iEntry,
       
  1349 												   *iImapSettings,
       
  1350 												   aParent, 
       
  1351 												   aLeafName, 
       
  1352 												   aFolder );
       
  1353 
       
  1354 		iRequestedOp = ECreate;
       
  1355 		StartPrimaryOperation();
       
  1356 		Queue(aStatus);
       
  1357 		SetActive();
       
  1358 		}
       
  1359 	}
       
  1360 
       
  1361 /**
       
  1362 Renames the specified folder. Note that although this does cause a write to the 
       
  1363 remote folder, it does not change the contents of the folder and hence does not 
       
  1364 force a re-synchronisation of the folder.
       
  1365 
       
  1366 Sequence For Rename
       
  1367 	StopIdle
       
  1368 	RenameRemote
       
  1369 	RenameLocal
       
  1370 
       
  1371 @param aStatus
       
  1372 @param aTarget
       
  1373 @param aNewName
       
  1374 */	
       
  1375 EXPORT_C void CImapProtocolController::RenameL( TRequestStatus& aStatus, 
       
  1376 				  					   			const TMsvId aTarget, 
       
  1377 				  					   			const TDesC& aNewName )
       
  1378 	{
       
  1379 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::RenameL()");
       
  1380 	__ASSERT_DEBUG(iImapCompound == NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ERenameCompoundIsNotNull));
       
  1381 	
       
  1382 	ResetProgress();
       
  1383 	
       
  1384 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  1385 		{
       
  1386 		iImapCompound = CImapCompoundRename::NewL( *iImapSyncManager, 
       
  1387 												   iEntry, 
       
  1388 												   *iImapSettings,
       
  1389 												   aTarget,
       
  1390 												   aNewName );
       
  1391 												   
       
  1392 		iRequestedOp = ERename;
       
  1393 		StartPrimaryOperation();
       
  1394 		Queue(aStatus);
       
  1395 		SetActive();
       
  1396 		}
       
  1397 	}
       
  1398 
       
  1399 
       
  1400 EXPORT_C void CImapProtocolController::DoRunL()
       
  1401 	{
       
  1402 	// Handle all migration operations in a separate state machnine.
       
  1403 	if (iMigrateState != ENotMigrating)
       
  1404 		{
       
  1405 		DoMigrateRunL();
       
  1406 		return;
       
  1407 		}
       
  1408 
       
  1409 	// ProcessError completes and returns ETrue if an error occured
       
  1410 	if (ProcessError(iStatus.Int()))
       
  1411 		{
       
  1412 		return;
       
  1413 		}
       
  1414 
       
  1415 	switch (iCurrentOp)
       
  1416 		{
       
  1417 	case EConnect:
       
  1418 		{
       
  1419 		// Collect the final connect progress information		
       
  1420 		iImapSessionManager->Progress(iProgress.iGenericProgress);
       
  1421 
       
  1422 		// Set last socket activity timeout to iMtmData1. This is used by Imcm.
       
  1423 		User::LeaveIfError( iEntry.SetEntry( iServiceId ) );
       
  1424 		TMsvEntry entry=iEntry.Entry();
       
  1425 		entry.SetMtmData1(iImapSessionManager->LastSocketActivityTimeout());
       
  1426 		User::LeaveIfError( iEntry.ChangeEntry( entry ) );
       
  1427 
       
  1428 		TRAP_IGNORE(MarkOnOrOfflineL(ETrue));
       
  1429 				
       
  1430 		// Create an IMAP IDLE controller
       
  1431 		delete iImapIdleController;
       
  1432 		iImapIdleController=NULL;
       
  1433 		iImapIdleController = CImapIdleController::NewL(*this, iImapSessionArray[0], *iImapSyncManager, iEntry, *iImapSettings, *iImapMailStore);
       
  1434 		
       
  1435 		// Register the connection with the mobility manager, 
       
  1436 		// if we are a mobile service
       
  1437 		if (iMobilityManager)
       
  1438 			{
       
  1439 			iMobilityManager->SetConnection(iImapSessionManager->GetConnectionL());
       
  1440 			}
       
  1441 
       
  1442 		// kick off a background sync if it was requested.
       
  1443 		if (iBackgroundSyncOp != NULL)
       
  1444 			{
       
  1445 			iBackgroundSyncOp->StartSync(*iImapSessionArray[0]);
       
  1446 			iCurrentOp = EIdle;
       
  1447 			}
       
  1448 		else
       
  1449 			{
       
  1450 			StartIdle();
       
  1451 			}
       
  1452 
       
  1453 		// complete the connect request
       
  1454 		Complete(iStatus.Int());
       
  1455 		break;
       
  1456 		}
       
  1457 
       
  1458 	case EConnectSecondary:
       
  1459 		{
       
  1460 		// perform the user-requested operation using the
       
  1461 		// newly created imap session
       
  1462 		iCurrentOp = iRequestedOp;
       
  1463 		if(iImapCompound->Suspended())
       
  1464 			{
       
  1465 			// if the operation was previously suspended for migration, resume it...
       
  1466 			iImapCompound->ResumeOperationL(iStatus, *iImapSessionArray[iForegroundSession]);
       
  1467 			}
       
  1468 		else
       
  1469 			{
       
  1470 			// otherwise, just start the operation.
       
  1471 			iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]);
       
  1472 			}
       
  1473 		SetActive();
       
  1474 		break;
       
  1475 		}
       
  1476 	
       
  1477 	case EStopIdle:
       
  1478 		{
       
  1479 		// Idle has been cancelled, the primary session is available
       
  1480 		// Kick off the requested operation
       
  1481 		iCurrentOp = iRequestedOp;
       
  1482 		iImapCompound->StartOperation(iStatus, *iImapSessionArray[0]);
       
  1483 		SetActive();
       
  1484 		break;
       
  1485 		}
       
  1486 
       
  1487 	case EDisconnect:
       
  1488 		{
       
  1489 		TRAP_IGNORE( MarkOnOrOfflineL( EFalse ) );
       
  1490 
       
  1491 		iImapSessionArray.ResetAndDestroy();
       
  1492 
       
  1493 		// update last operation progress state
       
  1494 		iImapCompound->Progress(iProgress);
       
  1495 
       
  1496 		delete iImapCompound;
       
  1497 		iImapCompound = NULL;
       
  1498 		iServiceId=0;
       
  1499 		
       
  1500 		Complete(iStatus.Int());
       
  1501 		break;
       
  1502 		}
       
  1503 	
       
  1504 	case ECancelRecoverPrimary:
       
  1505 		{
       
  1506 		// Primary session is successfully recovered
       
  1507 		// Start the next requested operation
       
  1508 		
       
  1509 		if (iRequestedOp == EIdle)
       
  1510 			{
       
  1511 			// We should only go into Idle if no async operations have been requested.
       
  1512 			// Consequently, CMsgActive::iReport should be NULL.
       
  1513 			// We can't ASSERT this here as it is a private member of CMsgActive, but it is worth checking while debugging.
       
  1514 			StartIdle();
       
  1515 			}
       
  1516 		else if (iRequestedOp == EDisconnect)
       
  1517 			{
       
  1518 			// We should only start a primary operation if an async operation has been requested, and an aStatus Queue()ed.
       
  1519 			// Consequently, CMsgActive::iReport should NOT be NULL.
       
  1520 			// We can't ASSERT this here as it is a private member of CMsgActive, but it is worth checking while debugging.
       
  1521 			StartPrimaryOperation();
       
  1522 			SetActive();
       
  1523 			}
       
  1524 		else
       
  1525 			{
       
  1526 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerUnexpectedRequestedOp));
       
  1527 			}
       
  1528 		
       
  1529 		break;
       
  1530 		}
       
  1531 
       
  1532 	case ESync:
       
  1533 	case ESelect:
       
  1534 	case ECopyToLocal:
       
  1535 	case ECopyWithinService:
       
  1536 	case ECopyFromLocal:
       
  1537 	case EMoveToLocal:
       
  1538 	case EMoveWithinService:
       
  1539 	case EMoveFromLocal:
       
  1540 	case EPopulate:
       
  1541 	case EDelete:
       
  1542 	case EDeleteFolder:
       
  1543 	case ECreate:
       
  1544 	case ERename:
       
  1545 	case EUpdateFlag:
       
  1546 		{
       
  1547 		// update last operation progress state
       
  1548 		iImapCompound->Progress(iProgress);
       
  1549 
       
  1550 		delete iImapCompound;
       
  1551 		iImapCompound = NULL;
       
  1552 		
       
  1553 		if ((iRequestedOp==ESelect) && (iProgress.iGenericProgress.iErrorCode==KErrNone))
       
  1554 			{
       
  1555 			// Do not start IDLE following a select request
       
  1556 			Complete(iStatus.Int());
       
  1557 			}
       
  1558 		else
       
  1559 			{
       
  1560 			// Start idle and complete the server mtm request.
       
  1561 			StartIdle();
       
  1562 			Complete(iStatus.Int());
       
  1563 			}
       
  1564 		break;
       
  1565 		}
       
  1566 
       
  1567 	case EIdle:	// shouldn't happen
       
  1568 	default:
       
  1569 		{
       
  1570 		Complete(iStatus.Int());
       
  1571 		break;
       
  1572 		}
       
  1573 		
       
  1574 		} // end of switch (iCurrentOp)
       
  1575 	}
       
  1576 
       
  1577 /**
       
  1578 This variation on DoRunL() presents a super-state machine, that replaces 
       
  1579 the default state machine during a migration process.
       
  1580 */
       
  1581 void CImapProtocolController::DoMigrateRunL()
       
  1582 	{
       
  1583 	// waiting for existing operation to stop to allow migration to occur.
       
  1584 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::DoMigrateRunL(iMigrateState = %d) CurrentOp = %d", iMigrateState, iCurrentOp));
       
  1585 	switch (iMigrateState)
       
  1586 		{
       
  1587  		case EWaitingForOpToStop: 
       
  1588 		case EWaitingForOpToComplete:
       
  1589 			{
       
  1590 			// operation has completed (is either finished, or has "paused"
       
  1591 			// to allow migration to complete. Do any tidying up necessary.
       
  1592 			ProcessOpCompleteForMigrate();
       
  1593 			
       
  1594 			// is there also a background sync op in progress? if not (or if the
       
  1595 			// background sync op is suspended, we are now ready to migrate, 
       
  1596 			// otherwise wait for the background op to complete.
       
  1597 			 // 
       
  1598 			if (!iBackgroundSyncOp || iBackgroundSyncOp->IsSuspendedForMigrate())
       
  1599 				{
       
  1600 				// Asynch disconnect current sockets.
       
  1601 				DisconnectForMigrateL();
       
  1602 				}
       
  1603 			break;
       
  1604 			}
       
  1605 		case EDisconnectingForMigrate:
       
  1606 			{
       
  1607 			// The disconnect operation has completed. Delete IMAP Sessions.
       
  1608 			iImapSessionArray.ResetAndDestroy();
       
  1609 
       
  1610 			// delete the migration compound object
       
  1611 			delete iMigrateCompound;
       
  1612 			iMigrateCompound = NULL;
       
  1613 			
       
  1614 			// Notify the mobility framework that we are ready to migrate.
       
  1615 			iMigrateState = EWaitingForNewCarrier;
       
  1616 			iMobilityManager->MigrateToNewCarrier();
       
  1617 			
       
  1618 			// do not set waiting if NewCarrierActive has been called synchronously.
       
  1619 			if (iMigrateState == EWaitingForNewCarrier)
       
  1620 				{
       
  1621 				// Now in a waiting state, set self active
       
  1622 				iStatus = KRequestPending;
       
  1623 				SetActive();
       
  1624 				}
       
  1625 			break;
       
  1626 			}
       
  1627 		case EHandlingConnectError:
       
  1628 			{
       
  1629 			// register with the mobility framework
       
  1630 			iMobilityManager->SetConnection(iImapSessionManager->GetConnectionL());
       
  1631 						
       
  1632 			// empty the session array
       
  1633 			TInt numSessions = iImapSessionArray.Count();
       
  1634 			for (TInt i=0; i<numSessions; ++i)
       
  1635 				{
       
  1636 				if (iImapSessionArray[i])
       
  1637 					{
       
  1638 					iImapSessionManager->Disconnect(*(iImapSessionArray[i]));
       
  1639 					}
       
  1640 				}
       
  1641 			iImapSessionArray.ResetAndDestroy();
       
  1642 
       
  1643 			// reject the initial carrier
       
  1644 			iMigrateState = EWaitingInitialCarrierRejected;
       
  1645 			iMobilityManager->NewCarrierRejected();
       
  1646 			
       
  1647 			if (iMigrateState == EWaitingInitialCarrierRejected)
       
  1648 				{
       
  1649 				iStatus = KRequestPending;
       
  1650 				SetActive();
       
  1651 				}
       
  1652 			break;
       
  1653 			}
       
  1654 		case EStartingReconnect:
       
  1655 			{
       
  1656 			NewPrimarySessionL();
       
  1657 			break;
       
  1658 			}
       
  1659 		case EConnectingAfterMigrate:
       
  1660 			{
       
  1661 			if (iStatus.Int()!=KErrNone)
       
  1662 				{
       
  1663 				// An error has occurred while attempting to re-connect
       
  1664 				// - reject this new carrier, wait to see if a new one turns up.
       
  1665 				iMigrateState = EWaitingForNewCarrier;
       
  1666 				iMobilityManager->NewCarrierRejected();
       
  1667 
       
  1668 				// Now in a waiting state, set self active
       
  1669 				if (iMigrateState == EWaitingForNewCarrier)
       
  1670 					{
       
  1671 					iStatus = KRequestPending;
       
  1672 					SetActive();
       
  1673 					}
       
  1674 				}
       
  1675 			else
       
  1676 				{
       
  1677 				iMobilityManager->NewCarrierAccepted();
       
  1678 				RestartAfterMigrateL();
       
  1679 				}
       
  1680 			break;
       
  1681 			}
       
  1682 		case ENotMigrating:
       
  1683 		case EWaitingForNewCarrier:
       
  1684 		case EWaitingInitialCarrierRejected:
       
  1685 			// DoRunMigrateL() Should never be called in this state.
       
  1686 		default:
       
  1687 			{
       
  1688 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerUnexpectedMigrateState));
       
  1689 			break;
       
  1690 			}
       
  1691 		}
       
  1692 	}
       
  1693 
       
  1694 
       
  1695 /** 
       
  1696 Called when completing an outstanding client request.
       
  1697 Handles negative (system-wide) error codes returned
       
  1698 on completion of asynchronous service requests.
       
  1699 */
       
  1700 void CImapProtocolController::DoComplete(TInt& aErr)
       
  1701 	{
       
  1702 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::DoComplete() - START - aErr = %d, CurrentOp = %d, iCancelInProgress: %d", aErr, iCurrentOp, iCancelInProgress));
       
  1703 
       
  1704 	// Requested operation is completed.
       
  1705 	iRequestedOp = EIdle;
       
  1706 
       
  1707 	// return if everything is OK
       
  1708 	if (aErr==KErrNone)
       
  1709 		{
       
  1710 	    __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - END - KErrNone" );
       
  1711 		return;
       
  1712 		}
       
  1713 		
       
  1714 	// First retrieve the progress information
       
  1715 	this->Progress();
       
  1716 	
       
  1717 	// log that a cancel has occurred and return
       
  1718 	if (aErr==KErrCancel)
       
  1719 		{
       
  1720 	    __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - dealing with cancel case..." );
       
  1721 		iProgress.iGenericProgress.iErrorCode=aErr;
       
  1722 		if(!iCancelInProgress)
       
  1723 			{
       
  1724 	        __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - no cancel in progress, so disconnecting all..." );
       
  1725 			DisconnectAll();
       
  1726 			}
       
  1727 			
       
  1728 	    __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - END - KErrCancel" );
       
  1729 		return;
       
  1730 		}
       
  1731 
       
  1732 	// Non-fatal errors should have been handled prior to this.
       
  1733 	__LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - fatal error - disconnect all..." );
       
  1734 	// iServiceId = 0, indicates we are already disconnected.
       
  1735 	if(iServiceId!=0)
       
  1736 		{
       
  1737 		DisconnectAll();
       
  1738 		}
       
  1739 	
       
  1740 	// Save error code in progress and flag the disconnect
       
  1741 	iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected;
       
  1742 	iProgress.iGenericProgress.iErrorCode=aErr;
       
  1743 
       
  1744     __LOG_TEXT( KDefaultLog, "CImapProtocolController::DoComplete() - END - fatal error" );
       
  1745 	}
       
  1746 	
       
  1747 
       
  1748 /**
       
  1749 Cancels any outstanding client requested asynchronous operations and recovers
       
  1750 the primary session if required.
       
  1751 
       
  1752 This function is exclusively for the use of the CImapServerMtm, and only calls
       
  1753 Cancel() if the PC is currently active performing the requested operation. 
       
  1754 If the PC is active for other reasons (for example, waiting for a bearer
       
  1755 migration to complete), the appropriate action is taken.
       
  1756 */
       
  1757 EXPORT_C void CImapProtocolController::CancelAndCleanup()
       
  1758 	{
       
  1759 	__LOG_FORMAT( (KDefaultLog, "CImapProtocolController::CancelAndCleanup() - START - iCurrentOp: %d, iRequestedOp: %d, iFlushPrimary: %d", iCurrentOp, iRequestedOp, iFlushPrimary ) );
       
  1760 	if ( iMigrateState == ENotMigrating ||
       
  1761 	     iMigrateState == EWaitingForOpToComplete ||
       
  1762 	     iMigrateState == EWaitingForOpToStop )
       
  1763 		{
       
  1764 		// In these states the protocol controller is currently doing something
       
  1765 		// at the clients request.
       
  1766 		// iCancelInProgress
       
  1767 		iCancelInProgress = ETrue;
       
  1768 		Cancel();
       
  1769 
       
  1770 	    __LOG_TEXT(KDefaultLog, "CImapProtocolController::CancelAndCleanup() - done DoCancel");
       
  1771 
       
  1772 		// DoCancel() will set iFlushPrimary to ETrue for operations that require 
       
  1773 		// a flush after being cancelled. This will cause DoRunL() to be called when the
       
  1774 		// session has been flushed. In the case of bearer migration, the next step will
       
  1775 		// be started in DoRunL.
       
  1776 		if (iFlushPrimary) 
       
  1777 			{
       
  1778 			iRequestedOp = EIdle; // We want to return to idle when the flush has completed.
       
  1779 			iCurrentOp = ECancelRecoverPrimary;
       
  1780 			CImapSession* session = iImapSessionArray[0];
       
  1781 			session->FlushCancelledCommand(iStatus);
       
  1782 			SetActive();
       
  1783 			iFlushPrimary = EFalse;
       
  1784 			}
       
  1785 		// clear the cancelling flag
       
  1786 		iCancelInProgress = EFalse;
       
  1787 		}
       
  1788 	else			
       
  1789 		{
       
  1790 		// in other migration states, we don't want to cancel because we 
       
  1791 		// are active for migration purposes. However, we do need to clean
       
  1792 		// compound operation objects and complete the user.
       
  1793 		iRequestedOp = iCurrentOp = EIdle;
       
  1794 		
       
  1795 		// Update the progress object
       
  1796 		iProgress.iGenericProgress.iState = TImap4GenericProgress::EIdle;
       
  1797 		iProgress.iGenericProgress.iErrorCode = KErrCancel;
       
  1798 
       
  1799 		delete iImapCompound;
       
  1800 		iImapCompound = NULL;
       
  1801 		CMsgActive::DoCancel(); // completes the user request.
       
  1802 		}
       
  1803     __LOG_TEXT(KDefaultLog, "CImapProtocolController::CancelAndCleanup() - END");
       
  1804 	}
       
  1805 
       
  1806 
       
  1807 /**
       
  1808 DoCancel - called by CMsgActive::Cancel() to cancel asychronous services:
       
  1809 
       
  1810 Cancel() must not be called on this class to cancel a requested async
       
  1811 service - CancelAndCleanup() should be used instead. CancelAndCleanup()
       
  1812 provides support for cancelling requested operations while this class
       
  1813 has become active for migration purposes.
       
  1814 
       
  1815 However, Cancel() must always be called eventually as the iStatus needs 
       
  1816 to be cleared. Hence this function must support all cancel operations.
       
  1817 
       
  1818 This class is allows for Cancel() to be called internally to cancel
       
  1819 async operations that have been launched internally for migration 
       
  1820 purposes, without completing the CImapServerMtm.
       
  1821 */
       
  1822 void CImapProtocolController::DoCancel()
       
  1823 	{
       
  1824 	__LOG_FORMAT( (KDefaultLog, "CImapProtocolController::DoCancel() - START - iCurrentOp: %d, iRequestedOp: %d, iFlushPrimary: %d", iCurrentOp, iRequestedOp, iFlushPrimary ) );
       
  1825 
       
  1826 	if (iMigrateState==ENotMigrating)
       
  1827 		{
       
  1828 		DoCancelClientOp();
       
  1829 		}
       
  1830 	else
       
  1831 		{
       
  1832 		switch (iMigrateState)
       
  1833 			{
       
  1834 			case ESuspendingForMigrate:
       
  1835 				{
       
  1836 				// Special handling for cancelling current operation to allow
       
  1837 				// migration to occur.
       
  1838 				DoCancelForMigrate();
       
  1839 				break;
       
  1840 				}
       
  1841 			case EWaitingForOpToComplete:
       
  1842 			case EWaitingForOpToStop:
       
  1843 				{
       
  1844 				// we have an outstanding request on the compound operation
       
  1845 				// call the default DoCancelClientOp(). This will also
       
  1846 				// complete the client's iStatus with KErrCancel
       
  1847 				DoCancelClientOp();
       
  1848 				break;
       
  1849 				}
       
  1850 			case EDisconnectingForMigrate:
       
  1851 				{
       
  1852 				// outstanding op is on the iMigrateCompound
       
  1853 				iMigrateCompound->Cancel();
       
  1854 				delete iMigrateCompound;
       
  1855 				iMigrateCompound = NULL;
       
  1856 				break;
       
  1857 				}
       
  1858 			case EConnectingAfterMigrate:
       
  1859 				{
       
  1860 				// This state represents re-connection of the primary session,
       
  1861 				// it is safe to simply clear the imap session array.
       
  1862 				iImapSessionManager->Cancel();
       
  1863 				iImapSessionArray.ResetAndDestroy();
       
  1864 				break;
       
  1865 				}
       
  1866 			case EWaitingForNewCarrier:
       
  1867 			case EWaitingInitialCarrierRejected:
       
  1868 				{
       
  1869 				// in these states, we are in a self-induced active state
       
  1870 				// Cancel it:
       
  1871 				TRequestStatus* status = &iStatus;
       
  1872 				User::RequestComplete(status, KErrCancel);
       
  1873 				break;
       
  1874 				}
       
  1875 
       
  1876 			case EStartingReconnect: // nothing to cancel
       
  1877 			case EHandlingConnectError: // nothing to cancel
       
  1878 			case ENotMigrating:		 // somethings gone wrong
       
  1879 			default:
       
  1880 				{
       
  1881 				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerCancelBadMigrateState));
       
  1882 				}
       
  1883 			} // switch (iMigrateState)
       
  1884 		}
       
  1885 
       
  1886 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancel() - END");
       
  1887 	}
       
  1888 
       
  1889 void CImapProtocolController::DoCancelClientOp()
       
  1890 	{
       
  1891 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - START");
       
  1892 
       
  1893 	// Update the requested and current operations
       
  1894 	// the implication is that a return to EIdle is required
       
  1895 	// current op may be updated later if an async op is issued.
       
  1896 	TImapProtocolOp cancelledOp = iCurrentOp;
       
  1897 	iRequestedOp = iCurrentOp = EIdle;
       
  1898 
       
  1899 	switch (cancelledOp)
       
  1900 		{
       
  1901 		case EConnect:
       
  1902 			{
       
  1903 			__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - EConnect");
       
  1904 			iImapSessionManager->Cancel();
       
  1905 			
       
  1906 			// As this state represents connection of the primary session,
       
  1907 			// it is safe to simply clear the imap session array.
       
  1908 			iImapSessionArray.ResetAndDestroy();
       
  1909 
       
  1910 			// delete the background sync operation if it exists.
       
  1911 			if (iBackgroundSyncOp != NULL)
       
  1912 				{
       
  1913 				iBackgroundSyncOp->Cancel();
       
  1914 				delete iBackgroundSyncOp;
       
  1915 				iBackgroundSyncOp=NULL;
       
  1916 				}
       
  1917 
       
  1918 			// delete the sync manager		
       
  1919 			delete iImapSyncManager;
       
  1920 			iImapSyncManager = NULL;
       
  1921 
       
  1922 			break;
       
  1923 			}
       
  1924 		
       
  1925 		case EConnectSecondary:
       
  1926 			{
       
  1927 	        __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - EConnectSecondary");
       
  1928 			// Cancel the connect request
       
  1929 			iImapSessionManager->Cancel();
       
  1930 			iForegroundSession=0;
       
  1931 			
       
  1932 			// Remove the session pointer from the array
       
  1933 			// The session has already been deleted - see note above.
       
  1934 			TInt numSessions = iImapSessionArray.Count();
       
  1935 			iImapSessionArray.Remove(numSessions-1);
       
  1936 			
       
  1937 			if (iImapCompound!=NULL)
       
  1938 				{
       
  1939 				// The requested op hasn't actually started yet
       
  1940 				// so don't cancel on the compound operation..
       
  1941 				// update last operation progress state
       
  1942 				iImapCompound->Progress(iProgress);
       
  1943 				
       
  1944 				delete iImapCompound;
       
  1945 				iImapCompound = NULL;
       
  1946 				}
       
  1947 			
       
  1948 			// The progress will not report cancel at this stage - force it here.
       
  1949 			iProgress.iGenericProgress.iState = TImap4GenericProgress::EIdle;
       
  1950 			iProgress.iGenericProgress.iErrorCode = KErrCancel;
       
  1951 
       
  1952 			break;
       
  1953 			}
       
  1954 
       
  1955 		case EDisconnect:
       
  1956 			{
       
  1957 	        __LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - EDisconnect");
       
  1958 			// Cancel the disconnect compound operation
       
  1959 			iImapCompound->Cancel();
       
  1960 
       
  1961 			delete iImapCompound;
       
  1962 			iImapCompound = NULL;
       
  1963 			
       
  1964 			// A cancelled disconnect will leave the sessions disconnected
       
  1965 			// but not deleted. Reset and destroy the session array.
       
  1966 			iImapSessionArray.ResetAndDestroy();
       
  1967 			
       
  1968 			break;
       
  1969 			}
       
  1970 		
       
  1971 		case EIdle:
       
  1972 			{
       
  1973 			// This is unexpected - in this state there should be no
       
  1974 			// outstanding asynconous requests on the Protocol Controller.
       
  1975 			// Protocol Controller has no outstanding requests in this state
       
  1976 			// however a sync may be running in the background. This is
       
  1977 			// cancelled when the background sync object's destructor is called.
       
  1978 			// So.. Nothing to do.
       
  1979 			break;
       
  1980 			}
       
  1981 		
       
  1982 		case EStopIdle:
       
  1983 			{
       
  1984 			if (iImapCompound!=NULL)
       
  1985 				{
       
  1986 				// The requested op hasn't actually started yet
       
  1987 				// so don't cancel on the compound operation..
       
  1988 				// update last operation progress state
       
  1989 				iImapCompound->Progress(iProgress);
       
  1990 				
       
  1991 				delete iImapCompound;
       
  1992 				iImapCompound = NULL;
       
  1993 				}
       
  1994 			
       
  1995 			// The progress will not report cancel at this stage - force it here.
       
  1996 			iProgress.iGenericProgress.iState = TImap4GenericProgress::EIdle;
       
  1997 			iProgress.iGenericProgress.iErrorCode = KErrCancel;
       
  1998 			
       
  1999 			// Cancel the idle controller.
       
  2000 			iImapIdleController->Cancel();
       
  2001 			
       
  2002 			// Cancelling the idle controller is likely to leave the IMAP Session
       
  2003 			// with data left on the input stream to be dealt with. We need to 
       
  2004 			// flush the session if we wish to re-use it.
       
  2005 			iFlushPrimary = ETrue;
       
  2006 
       
  2007 			break;
       
  2008 			}
       
  2009 
       
  2010 		case ESync:
       
  2011 		case ESelect:
       
  2012 		case ECopyToLocal:
       
  2013 		case ECopyWithinService:
       
  2014 		case ECopyFromLocal:
       
  2015 		case EMoveToLocal:
       
  2016 		case EMoveWithinService:
       
  2017 		case EMoveFromLocal:
       
  2018 		case EPopulate:
       
  2019 		case EDelete:
       
  2020 		case EDeleteFolder:
       
  2021 		case ECreate:
       
  2022 		case ERename:
       
  2023 	case EUpdateFlag:
       
  2024 			{
       
  2025 			__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - ESync/ESelect/ECopyToLocal/ECopyWithinService/ECopyFromLocal/EMoveToLocal/EMoveWithinService/EMoveFromLocal/EPopulate/EDelete/EDeleteFolder/ECreate/ERename/");
       
  2026 			// This is the normal case, a requested operation is
       
  2027 			// being performed by a compound operation object.
       
  2028 			// First of all, check one exists.
       
  2029 			if (iImapCompound!=NULL)
       
  2030 				{
       
  2031 				// Cancel the compound operation
       
  2032 				__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - cancelling iImapCompound...");
       
  2033 				iImapCompound->Cancel();
       
  2034 
       
  2035 				// update last operation progress state
       
  2036 				__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - getting progres...");
       
  2037 				iImapCompound->Progress(iProgress);
       
  2038 
       
  2039 				// Delete the compound object
       
  2040 				__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - deleting compound...");
       
  2041 				delete iImapCompound;
       
  2042 				iImapCompound = NULL;
       
  2043 				
       
  2044 				// Cancelling the compound operation is likely to leave 
       
  2045 				// the IMAP Session in an incomplete state. We need to 
       
  2046 				// flush the session if we wish to re-use it.
       
  2047 				if (iForegroundSession==0)
       
  2048 					{
       
  2049 					__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - flush primary = ETrue...");
       
  2050 					iFlushPrimary = ETrue;
       
  2051 					}
       
  2052 				else
       
  2053 					{
       
  2054 					__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - drop session...");
       
  2055 					DropSession(iForegroundSession);
       
  2056 					iForegroundSession=0;
       
  2057 					}
       
  2058 
       
  2059 				__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - main iImapCompound handling complete...");
       
  2060 				}
       
  2061 			break;
       
  2062 			}
       
  2063 	
       
  2064 		case ECancelRecoverPrimary:
       
  2065 			{
       
  2066 			// The recover must be taking too long.
       
  2067 			// cancel the recover request..
       
  2068 			(iImapSessionArray[0])->Cancel();
       
  2069 			// Delete all sessions, go offline etc.
       
  2070 			DisconnectAll();
       
  2071 			break;
       
  2072 			}
       
  2073 		default:
       
  2074 			{
       
  2075 			// nothing to do..
       
  2076 			break;
       
  2077 			}
       
  2078 		} // end of switch (cancelledOp)
       
  2079 
       
  2080 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - about to call CMsgActive::DoCancel()...");
       
  2081 	CMsgActive::DoCancel();
       
  2082 
       
  2083 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelClientOp() - END");
       
  2084 	}
       
  2085 
       
  2086 
       
  2087 /**
       
  2088 Performs a fast disconnect on all sessions
       
  2089 
       
  2090 Ensures that the compound, background sync and sync manager objects are
       
  2091 deleted following the disconnect.
       
  2092 @param aMarkOffline - indicates if the service is to be marked offline.
       
  2093 */
       
  2094 void CImapProtocolController::DisconnectAll()
       
  2095 	{
       
  2096     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - START");
       
  2097 
       
  2098 	// Delete the background sync op
       
  2099     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - deleting iBackgroundSyncOp");
       
  2100 	delete iBackgroundSyncOp;
       
  2101 	iBackgroundSyncOp=NULL;
       
  2102 
       
  2103 	// Delete the imap compound operation
       
  2104     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - deleting iImapCompound");
       
  2105 	delete iImapCompound;
       
  2106 	iImapCompound=NULL;
       
  2107 	
       
  2108 	// Delete the migrate compound operation
       
  2109 	delete iMigrateCompound;
       
  2110 	iMigrateCompound = NULL;
       
  2111 
       
  2112 	// delete the sync manager
       
  2113     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - deleting iImapSyncManager");
       
  2114 	delete iImapSyncManager;
       
  2115 	iImapSyncManager = NULL;
       
  2116 	
       
  2117 	// delete the mobility manager (de-register for mobility notifications)
       
  2118 	delete iMobilityManager;
       
  2119 	iMobilityManager = NULL;
       
  2120 
       
  2121 	// delete the imap idle controller
       
  2122 	delete iImapIdleController;
       
  2123 	iImapIdleController = NULL;
       
  2124 
       
  2125 	// Drop connection on each of the imap sessions
       
  2126 	TInt numSessions = iImapSessionArray.Count();
       
  2127 	for (TInt i=0; i<numSessions; ++i)
       
  2128 		{
       
  2129 		if (iImapSessionArray[i])
       
  2130 			{
       
  2131 	        __LOG_FORMAT( (KDefaultLog, "CImapProtocolController::DisconnectAll() - disconnecting session: %d/%d", i, numSessions ) );
       
  2132 			iImapSessionManager->Disconnect(*(iImapSessionArray[i]));
       
  2133 			}
       
  2134 		}
       
  2135 		
       
  2136 	// The current network connection will be closed
       
  2137  	iImapSessionManager->CloseNetworkConnection();
       
  2138 
       
  2139 
       
  2140 	// empty the session array
       
  2141     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - resetting and destroying sessions...");
       
  2142 	iImapSessionArray.ResetAndDestroy();
       
  2143 	
       
  2144 	// force the state to IDLE
       
  2145 	iRequestedOp = EIdle;
       
  2146 	iCurrentOp = EIdle;
       
  2147 	
       
  2148 	// Clear serviceid and mark the service as offline
       
  2149     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - about to MarkOnOrOffline...");
       
  2150 	TRAP_IGNORE(MarkOnOrOfflineL(EFalse));
       
  2151 	iServiceId=0;
       
  2152 
       
  2153     __LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectAll() - END");
       
  2154 	}
       
  2155 
       
  2156 /**
       
  2157 Performs an immediate disconnect of specifed session and removes it from
       
  2158 the session array.
       
  2159 
       
  2160 @param sessionId - the index in the session array of the session to drop.
       
  2161 */
       
  2162 void CImapProtocolController::DropSession(TInt sessionId)
       
  2163 	{
       
  2164 	if (sessionId < iImapSessionArray.Count())
       
  2165 		{
       
  2166 		CImapSession* tempSession = iImapSessionArray[sessionId];
       
  2167 		if (tempSession)
       
  2168 			{
       
  2169 			iImapSessionManager->Disconnect(*tempSession);
       
  2170 			delete tempSession;
       
  2171 			}
       
  2172 		iImapSessionArray.Remove(sessionId);
       
  2173 		}
       
  2174 	}
       
  2175 
       
  2176 /**
       
  2177 Private method to select session from the session array for use for operations
       
  2178 that are supported while background operations are in progress.
       
  2179 Issues a request to connect a secondary session if the primary session is busy
       
  2180 and a secondary session is not already available. In this case the requested op
       
  2181 is updated to show a secondary connect request, and the original requested op
       
  2182 is saved.
       
  2183 
       
  2184 @param  aIndexToUse updated to indicate the index of the session to be used
       
  2185 @return ETrue if the session is connected and ready to use immediately.
       
  2186 		EFalse if a request to connect a secondary session has been issued.
       
  2187 */
       
  2188 TBool CImapProtocolController::SelectSessionL(TInt& aIndexToUse)
       
  2189 	{
       
  2190 	__ASSERT_DEBUG(iCurrentOp != ECancelRecoverPrimary, TImapServerPanic::ImapPanic(TImapServerPanic::EProtocolControllerUnexpectedCurrentOp));
       
  2191 	
       
  2192 	aIndexToUse = 0; // default to primary session.
       
  2193 	TBool sessionReady = ETrue;
       
  2194 	if (iBackgroundSyncOp != NULL)
       
  2195 		{
       
  2196 		TInt sessionCount = iImapSessionArray.Count();
       
  2197 		if (sessionCount>=2)
       
  2198 			{
       
  2199 			// already a secondary session available - use this
       
  2200 			aIndexToUse = sessionCount-1;
       
  2201 			}
       
  2202 		else
       
  2203 			{
       
  2204 			// Create a new session and get it connected.
       
  2205 			iCurrentOp = EConnectSecondary;
       
  2206 			
       
  2207 			CImapSession* imapSession = NULL;
       
  2208 			iImapSessionArray.AppendL(imapSession);
       
  2209 			iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[sessionCount]);
       
  2210 			aIndexToUse = sessionCount;
       
  2211 			sessionReady = EFalse;
       
  2212 			}
       
  2213 		}
       
  2214 	return sessionReady;
       
  2215 	}
       
  2216 
       
  2217 /**
       
  2218 Called to kick off a foreground operation, ie a user requested
       
  2219 operation that is being performed on the primary IMAP session.
       
  2220 
       
  2221 If the session is in IMAP IDLE, a request is issued to stop this
       
  2222 and the requested operation is started when the stop-idle operation
       
  2223 has completed. Otherwise the operation is started immediately.
       
  2224 */
       
  2225 void CImapProtocolController::StartPrimaryOperation()
       
  2226 	{
       
  2227 	// Make sure the foreground session id is correct
       
  2228 	iForegroundSession = 0;
       
  2229 	// imap idle controller is active in any state after
       
  2230 	// idle has been requested.
       
  2231 	if (iImapIdleController->IsActive())
       
  2232 		{
       
  2233 		iCurrentOp = EStopIdle;
       
  2234 		iImapIdleController->StopIdle(iStatus);
       
  2235 		}
       
  2236 	else
       
  2237 		{
       
  2238 		iCurrentOp = iRequestedOp;
       
  2239 		iImapCompound->StartOperation(iStatus, *iImapSessionArray[iForegroundSession]);
       
  2240 		}
       
  2241 	}
       
  2242 
       
  2243 /**
       
  2244 Starts the background IDLE process.
       
  2245 If IDLE is not supported by the server, or if IDLE is disabled via the
       
  2246 account settings, a "dummy read" is issued, to manage any unsolicited
       
  2247 server messages.
       
  2248 
       
  2249 This is called when user-requested compound operations have completed
       
  2250 to return the primary session to IDLE state. Note that some operations
       
  2251 require that IDLE is not re-issued, eg "select". It is also called
       
  2252 when a background sync operation has completed, if there is no foreground
       
  2253 operation currently in progress
       
  2254 
       
  2255 Idle is only issued on the primary session.
       
  2256 
       
  2257 Idle is not started if there is a background operation in progress 
       
  2258 */
       
  2259 void CImapProtocolController::StartIdle()
       
  2260 	{
       
  2261 	iCurrentOp = EIdle;
       
  2262 	if (iBackgroundSyncOp==NULL)
       
  2263 		{
       
  2264 		iImapIdleController->StartIdle();
       
  2265 		}
       
  2266 	}
       
  2267 
       
  2268 /**
       
  2269 Called by the CImapIdleController in the case of an error being observed
       
  2270 while in IDLE state.
       
  2271 
       
  2272 @param aError - the observed error
       
  2273 */
       
  2274 void CImapProtocolController::OnIdleError(TInt aError)
       
  2275 	{
       
  2276 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::OnIdleError(aError = %d)", aError));
       
  2277 	if (aError>0)
       
  2278 		{
       
  2279 		aError = KErrImapServerFail;
       
  2280 		}
       
  2281 	iProgress.iGenericProgress.iErrorCode = aError;
       
  2282 	iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected;
       
  2283 	DisconnectAll();
       
  2284 	// Nothing to complete.
       
  2285 	}
       
  2286 
       
  2287 /**
       
  2288 Returns the progress information for the outstanding command.
       
  2289 
       
  2290 @return progress information
       
  2291 */
       
  2292 EXPORT_C TImap4CompoundProgress CImapProtocolController::Progress()
       
  2293 	{
       
  2294 	// Progress of foreground operation is returned	over that of a
       
  2295 	// background sync operation.
       
  2296 	// Do not refresh the progress while migrating.
       
  2297 	if (iCurrentOp!=EIdle && iMigrateState == ENotMigrating)
       
  2298 		{
       
  2299 		// do not update if IDLEing - return the stored progress object
       
  2300 		// this should have been populated correctly on completion of
       
  2301 		// requested operation, whether successful or otherwise.
       
  2302 		switch (iCurrentOp)
       
  2303 			{
       
  2304 		case EConnect:
       
  2305 			{
       
  2306 			iImapSessionManager->Progress(iProgress.iGenericProgress);
       
  2307 			break;
       
  2308 			}
       
  2309 		case EStopIdle:
       
  2310 		case ESync:
       
  2311 		case ESelect:
       
  2312 		case ECopyToLocal:
       
  2313 		case ECopyWithinService:
       
  2314 		case ECopyFromLocal:
       
  2315 		case EMoveToLocal:
       
  2316 		case EMoveWithinService:
       
  2317 		case EMoveFromLocal:
       
  2318 		case EPopulate:
       
  2319 		case EDelete:
       
  2320 		case EDeleteFolder:
       
  2321 		case ECreate:
       
  2322 		case ERename:
       
  2323 		case EDisconnect:
       
  2324 		case EUpdateFlag: 
       
  2325 			{
       
  2326 			// Obtain progress from compound object if it exists
       
  2327 			// Otherwise the last progress obtained on completion
       
  2328 			// of the compound object is returned.
       
  2329 			if (iImapCompound!=NULL)
       
  2330 				{
       
  2331 				iImapCompound->Progress(iProgress);
       
  2332 				}
       
  2333 			break;
       
  2334 			}
       
  2335 		case EIdle:
       
  2336 		default:
       
  2337 			break;
       
  2338 			}
       
  2339 		}
       
  2340 		else if (iBackgroundSyncOp!=NULL)
       
  2341 		{
       
  2342 		// update sync progress if background sync is being performed.
       
  2343 		iBackgroundSyncOp->Progress(iProgress);
       
  2344 		}
       
  2345 
       
  2346 	return iProgress;
       
  2347 	}
       
  2348 
       
  2349 /**
       
  2350 changes local subscription flag on a folder immediately.
       
  2351 If unsubscribing, the folder is marked as invisible, and the invisible
       
  2352 flag is propagated to any parent folders that are not themselves subscribed
       
  2353 or contain subscribed folders.
       
  2354 
       
  2355 @param aFolder
       
  2356 @param aSubscribed
       
  2357 @return Error code
       
  2358 */
       
  2359 EXPORT_C TInt CImapProtocolController::SetLocalSubscription(const TMsvId aFolder, 
       
  2360 															TBool aSubscribed)
       
  2361 	{
       
  2362 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::SetLocalSubscription()");
       
  2363 
       
  2364 	TInt err;
       
  2365 
       
  2366 	// Move to the entry
       
  2367 	if ((err=iEntry.SetEntry(aFolder))!=KErrNone)
       
  2368 		return(err);
       
  2369 
       
  2370 	// Check it's a folder
       
  2371 	if (iEntry.Entry().iType!=KUidMsvFolderEntry)
       
  2372 		return(KErrNotSupported);
       
  2373 
       
  2374 	// update subscription flag
       
  2375 	TMsvEmailEntry entry=iEntry.Entry();
       
  2376 	entry.SetLocalSubscription(aSubscribed);
       
  2377 	entry.SetVisible(aSubscribed);
       
  2378 	
       
  2379 	err = iEntry.ChangeEntry(entry);
       
  2380 		
       
  2381 	// Return if error or if setting subscribed
       
  2382 	if (err!=KErrNone || !aSubscribed)
       
  2383 		{
       
  2384 		TRAP(err, PropagateUnsubscribeL(aFolder));
       
  2385 		return err;
       
  2386 		}
       
  2387 	else
       
  2388 		{
       
  2389 		return KErrNone;
       
  2390 		}
       
  2391 	}
       
  2392 
       
  2393 /**
       
  2394 Marks aFolder as invisible and propagates the invisible flag to parent folder.
       
  2395 
       
  2396 @param aFolder the unsubscribed folder.
       
  2397 */
       
  2398 void CImapProtocolController::PropagateUnsubscribeL(const TMsvId aFolder)
       
  2399 	{
       
  2400 	// Settings may not yet be loaded.
       
  2401 	if (iImapSettings->SettingsLoaded()==EFalse)
       
  2402 		{
       
  2403 		iImapSettings->LoadSettingsL(aFolder);
       
  2404 		}
       
  2405 
       
  2406 	// if synchronisation setting is not remote only then
       
  2407 	// update the invisibility flags
       
  2408 	if (iImapSettings->Synchronise() != EUseRemote)
       
  2409 		{
       
  2410 		PropagateInvisibleFlagL(aFolder);
       
  2411 		ChangeVisibilityL(aFolder,ETrue,EFalse,KUidMsvMessageEntry);
       
  2412 		}
       
  2413 	}
       
  2414 
       
  2415 
       
  2416 // Mark service as on or offline
       
  2417 void CImapProtocolController::MarkOnOrOfflineL( const TBool aOnline )
       
  2418 	{
       
  2419 	// Mark service entry as on/offline	
       
  2420 	User::LeaveIfError( iEntry.SetEntry( iServiceId ) );
       
  2421 
       
  2422 	TMsvEntry entry=iEntry.Entry();
       
  2423 	entry.SetConnected( aOnline );
       
  2424 	User::LeaveIfError( iEntry.ChangeEntry( entry ) );
       
  2425 
       
  2426 	// Release the service entry
       
  2427 	User::LeaveIfError( iEntry.SetEntry( KMsvNullIndexEntryId ) );
       
  2428 
       
  2429 	// Going offline?
       
  2430 	if ( !aOnline && iImapSettings->DisconnectedUserMode() )
       
  2431 		{
       
  2432 		// We're an expert user going offline: don't touch anything
       
  2433 		return;
       
  2434 		}
       
  2435 
       
  2436 	// Mark all immediate children of the service as invisible
       
  2437 	if ( !aOnline )
       
  2438 		ChangeVisibilityL( iServiceId, !aOnline );
       
  2439 	}
       
  2440 	
       
  2441 void CImapProtocolController::ChangeVisibilityL(TMsvId aParent, TBool aInvisible)
       
  2442 	{
       
  2443 	ChangeVisibilityL(aParent, aInvisible, ETrue, KUidMsvFolderEntry);
       
  2444 	}
       
  2445 
       
  2446 
       
  2447 void CImapProtocolController::ChangeVisibilityL(TMsvId aParent, TBool aInvisible, TBool aRecurse, TUid aType)
       
  2448 	{
       
  2449 	// Get children at this level
       
  2450 	CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
       
  2451 	CleanupStack::PushL( selection );
       
  2452 
       
  2453 	CMsvEntrySelection* folders = new (ELeave) CMsvEntrySelection;
       
  2454 	CleanupStack::PushL( folders );
       
  2455 
       
  2456 	User::LeaveIfError( iEntry.SetEntry( aParent ) );
       
  2457 	User::LeaveIfError( iEntry.GetChildren( *selection ) );
       
  2458 
       
  2459 	if ( selection->Count() )
       
  2460 		{
       
  2461 		for( TInt child=0; child < selection->Count(); child++ )
       
  2462 			{
       
  2463 			// Move to this child
       
  2464 			User::LeaveIfError( iEntry.SetEntry( (*selection)[child] ) );
       
  2465 			
       
  2466 			TMsvEntry message=iEntry.Entry();
       
  2467 			
       
  2468 			// Is this the type we want to change?
       
  2469 			if (message.iType==aType)
       
  2470 				{
       
  2471 				// Add to selection to do bulk change on, if necessary
       
  2472 				if ((message.Visible() && aInvisible) ||
       
  2473 					(!message.Visible() && !aInvisible))
       
  2474 					{
       
  2475 					folders->AppendL(message.Id());
       
  2476 					}
       
  2477 				}
       
  2478 			
       
  2479 			// Recurse downwards
       
  2480 			if (aRecurse && message.iType==KUidMsvFolderEntry)
       
  2481 				ChangeVisibilityL(message.Id(),aInvisible,aRecurse,aType);
       
  2482 			}
       
  2483 
       
  2484 		// Change its visibility off all children if necessary
       
  2485 		if (folders->Count())
       
  2486 			{
       
  2487 			// Do the change to the invisible flag (actual constant for the
       
  2488 			// flag we want is private:()
       
  2489 			
       
  2490 			User::LeaveIfError( iEntry.SetEntry( aParent ) );
       
  2491 			User::LeaveIfError( iEntry.ChangeAttributes(*folders,
       
  2492 								aInvisible?0:KMsvVisibilityAttribute,
       
  2493 								aInvisible?KMsvVisibilityAttribute:0));
       
  2494 			}
       
  2495 		}
       
  2496 
       
  2497 	// Release the service entry
       
  2498 	User::LeaveIfError( iEntry.SetEntry( KMsvNullIndexEntryId ) );
       
  2499 
       
  2500 	// Get rid of selection
       
  2501 	CleanupStack::PopAndDestroy(2);
       
  2502 	}
       
  2503 
       
  2504 /**
       
  2505 Propagates invisible flag for unsubscribed folders.
       
  2506 aId has been unsubscribed. If it has no visible child folders then
       
  2507 it is made invisible and its parent checked with the same test
       
  2508 
       
  2509 @param aId the folder that has been unsubscribed
       
  2510 */
       
  2511 void CImapProtocolController::PropagateInvisibleFlagL(TMsvId aId)
       
  2512 	{
       
  2513 	__LOG_FORMAT((KDefaultLog, "PropagateInvisibleFlagL: 0x%x", aId));
       
  2514 
       
  2515 	// finish if we've reached the top
       
  2516 	if (aId == KMsvRootIndexEntryId)
       
  2517 		{
       
  2518 		return;
       
  2519 		}
       
  2520 	
       
  2521 	User::LeaveIfError(iEntry.SetEntry(aId));
       
  2522 
       
  2523 	// finish if we've reached a service
       
  2524 	if (iEntry.Entry().iType == KUidMsvServiceEntry)
       
  2525 		{
       
  2526 		return;
       
  2527 		}
       
  2528 
       
  2529 	// return if we've found a subscribed folder since we can't make
       
  2530 	// it invisible
       
  2531 	if (((TMsvEmailEntry)iEntry.Entry()).LocalSubscription())
       
  2532 		{
       
  2533 		return;
       
  2534 		}
       
  2535 	
       
  2536 	// check the children of this unsubscribed folder
       
  2537 	CMsvEntrySelection* selection=new (ELeave) CMsvEntrySelection;
       
  2538 	CleanupStack::PushL(selection);
       
  2539 
       
  2540 	User::LeaveIfError(iEntry.GetChildren(*selection));
       
  2541 
       
  2542 	TBool visible=EFalse;
       
  2543 	TInt count = selection->Count();
       
  2544 	for (TInt i=0; i < count; ++i)
       
  2545 		{
       
  2546 		User::LeaveIfError(iEntry.SetEntry((*selection)[i]));
       
  2547 
       
  2548 		// look for a visible folder
       
  2549 		TMsvEmailEntry entry = (TMsvEmailEntry)iEntry.Entry();
       
  2550 		if (entry.iType == KUidMsvFolderEntry && entry.Visible())
       
  2551 			{
       
  2552 			visible=ETrue;
       
  2553 			break;
       
  2554 			}
       
  2555 		}
       
  2556 	
       
  2557 	CleanupStack::PopAndDestroy(selection);
       
  2558 
       
  2559 	// if no child folders were visible then make this folder
       
  2560 	// invisible and continue up
       
  2561 	if (!visible)
       
  2562 		{
       
  2563 		User::LeaveIfError(iEntry.SetEntry(aId));
       
  2564 		
       
  2565 		// make this invisible
       
  2566 		TMsvEntry entry = iEntry.Entry();
       
  2567 		entry.SetVisible(EFalse);
       
  2568 		User::LeaveIfError(iEntry.ChangeEntry(entry));
       
  2569 
       
  2570 		// go up
       
  2571 		PropagateInvisibleFlagL(entry.Parent());
       
  2572 		}
       
  2573 	}
       
  2574 
       
  2575 
       
  2576 /**
       
  2577 Is this id in the local service?
       
  2578 @param  aId   the id of the entry to check
       
  2579 @return true, if the message id belongs to the local service.
       
  2580 */
       
  2581 TBool CImapProtocolController::IdIsLocalL(TMsvId aId)
       
  2582 	{
       
  2583 	return ServiceOfL(aId) == KMsvLocalServiceIndexEntryIdValue;
       
  2584 	}
       
  2585 
       
  2586 /**
       
  2587 Returns the id of the service containing this id
       
  2588 @param  aId   the id of the entry to check
       
  2589 @return       the id of the containing service
       
  2590 */
       
  2591 TMsvId CImapProtocolController::ServiceOfL(TMsvId aId)
       
  2592 	{
       
  2593 	TMsvId current=aId;
       
  2594 	while(current!=KMsvRootIndexEntryIdValue)
       
  2595 		{
       
  2596 		// Visit this entry
       
  2597 		User::LeaveIfError(iEntry.SetEntry(current));
       
  2598 
       
  2599 		TMsvEmailEntry entry = iEntry.Entry();
       
  2600 		
       
  2601 		// if service then searched far enough
       
  2602 		if (entry.iType==KUidMsvServiceEntry)
       
  2603 			break;
       
  2604 
       
  2605 		// Go upwards
       
  2606 		current=entry.Parent();
       
  2607 		}
       
  2608 
       
  2609 	return current;
       
  2610  	}
       
  2611  	
       
  2612 /**
       
  2613 Processes positive error codes returned by asynchronous service requests.
       
  2614 Specifically, these will be error codes returned by the CImapSession,
       
  2615 indicating error conditions in communication with the remote server.
       
  2616 
       
  2617 See cimapsessionconsts.h for full definition of error codes, summarised here:
       
  2618 
       
  2619 KErrImapNo 		 	 IMAP server returned a tagged NO response
       
  2620 KErrImapBad 	 	 IMAP server returned a tagged BAD response
       
  2621 KErrImapClosed		 indicates one of the streams has closed
       
  2622 KErrImapFlushTimeout an attempt to flush a cancelled command has timed out
       
  2623 KErrImapCorrupt		 corrupt data was enountered during parsing of IMAP server data
       
  2624 
       
  2625 @param  aError - the positive error code received on completion 
       
  2626                  of an asynchronous service
       
  2627 
       
  2628 @return ETrue  - if this function has called Complete() due to a fatal error.
       
  2629 		EFalse - otherwise
       
  2630 */
       
  2631 TBool CImapProtocolController::ProcessError(TInt aError)
       
  2632 	{
       
  2633 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::ProcessError(iCurrentOp = %d, aError = %d)", iCurrentOp, aError));
       
  2634 	
       
  2635 	// Bearer mobility support for initially connect failure 
       
  2636 	if (iMobilityManager && aError == KErrImapConnectError && iImapSessionManager->HasConnection())
       
  2637 		{
       
  2638 		// Change migration state, so the connect error can be dealt with, 
       
  2639 		// using the migration state machine.
       
  2640 		iMigrateState = EHandlingConnectError;
       
  2641 
       
  2642 		SetActive();
       
  2643 		TRequestStatus* status = &iStatus;
       
  2644 		User::RequestComplete(status, KErrNone);
       
  2645 
       
  2646 		return ETrue;
       
  2647 		}
       
  2648 	
       
  2649 
       
  2650 	// weed out non-fatal server errors
       
  2651 	ThranslateSessionError(aError);
       
  2652 	if (aError == KErrNone)
       
  2653 		{
       
  2654 		return EFalse;
       
  2655 		}
       
  2656 	
       
  2657 	if (iForegroundSession>0)
       
  2658 		{
       
  2659 		// error has occurred on a secondary session.
       
  2660 		// This is not fatal to the whole protocol controller's
       
  2661 		// existance, but it is fatal to the requested operation
       
  2662 		
       
  2663 		// get final progress state...
       
  2664 		if (iCurrentOp==EConnectSecondary)
       
  2665 			{
       
  2666 			iImapSessionManager->Progress(iProgress.iGenericProgress);
       
  2667 			}
       
  2668 		else
       
  2669 			{
       
  2670 			iImapCompound->Progress(iProgress);
       
  2671 			}
       
  2672 		
       
  2673 		//... and update reported error code
       
  2674 		iProgress.iGenericProgress.iErrorCode=aError;
       
  2675 		
       
  2676 		// delete the compound operation object
       
  2677 		delete iImapCompound;
       
  2678 		iImapCompound = NULL;
       
  2679 		
       
  2680 		// drop the secondary session
       
  2681 		DropSession(iForegroundSession);
       
  2682 		
       
  2683 		// complete the user request with KErrNone..
       
  2684 		Complete(KErrNone);
       
  2685 		}
       
  2686 	else
       
  2687 		{
       
  2688 		// DoComplete normally handles the session tidyup, but
       
  2689 		// is not called if the error has occurred during a background
       
  2690 		// operation, for example ECancelRecoverPrimary
       
  2691 		if (iCurrentOp==ECancelRecoverPrimary)
       
  2692 			{
       
  2693 			// Non-fatal errors should have been handled prior to this.
       
  2694 			DisconnectAll();
       
  2695 	
       
  2696 			// Save error code in progress and flag the disconnect
       
  2697 			// this is defensive as the client should not be watching progress
       
  2698 			iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected;
       
  2699 			iProgress.iGenericProgress.iErrorCode=aError;
       
  2700 			}
       
  2701 		Complete(aError);
       
  2702 		}
       
  2703 	return ETrue;
       
  2704 	}
       
  2705 
       
  2706 /**
       
  2707 Translates session error codes for reporting to the Server MTM.
       
  2708 KErrImapNo and KErrImapBad are non-fatal to the session, and 
       
  2709 should have been fielded by the compound operation, sync manager
       
  2710 or session manager (during session connect), however they are
       
  2711 translated to KErrNone here.
       
  2712 
       
  2713 All other session errors are fatal to the connection. If an
       
  2714 error occurs on the primary session, all connected sessions 
       
  2715 should be disconnected and the client completed.
       
  2716 */
       
  2717 void CImapProtocolController::ThranslateSessionError(TInt& errCode)
       
  2718 	{
       
  2719 	if ( errCode == KErrNone 
       
  2720 	  || errCode == KErrImapNo 
       
  2721 	  || errCode == KErrImapBad )
       
  2722 		{
       
  2723 		// No and bad should have been handled by the compound 
       
  2724 		// operation and are non-fatal to the connection.
       
  2725 		errCode = KErrNone;
       
  2726 		}
       
  2727 	else
       
  2728 		{
       
  2729 		errCode = KErrImapServerFail;
       
  2730 		}
       
  2731 	}
       
  2732 
       
  2733 /**
       
  2734 Resets the progress object
       
  2735 */
       
  2736 void CImapProtocolController::ResetProgress()
       
  2737 	{
       
  2738 	//initialise the TImap4SyncProgress part
       
  2739 	iProgress.iSyncProgress.iFoldersToDo = 0;
       
  2740 	iProgress.iSyncProgress.iFoldersDone = 0;
       
  2741 	iProgress.iSyncProgress.iMsgsToDo = 0;
       
  2742 	iProgress.iSyncProgress.iMsgsDone = 0;
       
  2743 	iProgress.iSyncProgress.iHeadersFetched = 0;
       
  2744 	iProgress.iSyncProgress.iOrphanedFolders = 0;
       
  2745 	iProgress.iSyncProgress.iNewFolders = 0;
       
  2746 	iProgress.iSyncProgress.iOrphanedMessages = 0;
       
  2747 	iProgress.iSyncProgress.iRemoteMessagesDeleteTagged = 0;
       
  2748 	iProgress.iSyncProgress.iMessagesFetchedOK = 0;
       
  2749 	iProgress.iSyncProgress.iMessagePartsFetchedOK = 0;
       
  2750 	iProgress.iSyncProgress.iMessagePartsNotFound = 0;
       
  2751 	iProgress.iSyncProgress.iFoldersNotFound = 0;
       
  2752 	iProgress.iSyncProgress.iErrorCode = KErrNone;	
       
  2753 	iProgress.iSyncProgress.iType = EImap4SyncProgressType;
       
  2754 	
       
  2755 	//initialise the TImap4GenericProgress part
       
  2756 	iProgress.iGenericProgress.iMsgsToDo = 0;
       
  2757 	iProgress.iGenericProgress.iMsgsDone = 0;
       
  2758 	iProgress.iGenericProgress.iPartsToDo = 0;
       
  2759 	iProgress.iGenericProgress.iPartsDone = 0;
       
  2760 	iProgress.iGenericProgress.iBytesToDo = 0;
       
  2761 	iProgress.iGenericProgress.iBytesDone = 0;
       
  2762 	iProgress.iGenericProgress.iReturnedMsvId = 0;
       
  2763 	iProgress.iGenericProgress.iTotalSize = 0;
       
  2764 	iProgress.iGenericProgress.iErrorCode = KErrNone;
       
  2765 	iProgress.iGenericProgress.iType = EImap4GenericProgressType;
       
  2766 
       
  2767 	}
       
  2768 
       
  2769 /**
       
  2770 Notice that a preferred carrier has become available, and migration to that bearer has been accepted.
       
  2771 The protocol controller shall either pause or allow any current operation to complete
       
  2772 according to the action specified in parameter aAction. Once the current operation 
       
  2773 is paused or complete, the protocol controller shall close any existing sockets
       
  2774 and finally notify the mobility framework that it is ready to migrate to the new
       
  2775 carrier.
       
  2776 
       
  2777 @param aAction      - indicates the action that should be taken re: current operations
       
  2778 @param aIsSeamless  - indicates if the 
       
  2779 */
       
  2780 void CImapProtocolController::PrepareForNewCarrier(TImMobilityAction aAction, TBool /*aIsSeamless*/)
       
  2781 	{
       
  2782 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::PrepareForNewCarrier(iMigrateState=%d, aAction = %d)", iMigrateState, aAction));
       
  2783 	// Handle being called in an already-migrating state before handling usual case
       
  2784 	if (iMigrateState!=ENotMigrating)
       
  2785 		{
       
  2786 		switch (iMigrateState)
       
  2787 			{
       
  2788 			case EDisconnectingForMigrate:
       
  2789 			case EWaitingForOpToStop:
       
  2790 				{
       
  2791 				// Do not allow change from EWaitingForOpToStop to EWaitingForOpToComplete
       
  2792 				// but do allow an operation to be stopped suddenly if necessary.
       
  2793 				if (aAction==KAcceptImmediately)
       
  2794 					{
       
  2795 					CarrierLost();
       
  2796 					iMigrateState = EWaitingForNewCarrier;
       
  2797 					iMobilityManager->MigrateToNewCarrier();
       
  2798 		
       
  2799 					// do not set waiting if NewCarrierActive has been called synchronously.
       
  2800 					if (iMigrateState == EWaitingForNewCarrier)
       
  2801 						{
       
  2802 						// Now in a waiting state, set self active
       
  2803 						iStatus = KRequestPending;
       
  2804 						SetActive();
       
  2805 						}
       
  2806 					}
       
  2807 				// else already preparing for new carrier, nothing to do.
       
  2808 				return;
       
  2809 				}
       
  2810 
       
  2811 			case EWaitingForOpToComplete:	// async wait on compound op/bground op/idle controller
       
  2812 				{
       
  2813 				// Allow change from EWaitingForOpToComplete to EWaitingForOpToStop
       
  2814 				// also allow an operation to be stopped suddenly if necessary.
       
  2815 				if (aAction==KAcceptImmediately)
       
  2816 					{
       
  2817 					CarrierLost();
       
  2818 					iMigrateState = EWaitingForNewCarrier;
       
  2819 					iMobilityManager->MigrateToNewCarrier();
       
  2820 		
       
  2821 					// do not set waiting if NewCarrierActive has been called synchronously.
       
  2822 					if (iMigrateState == EWaitingForNewCarrier)
       
  2823 						{
       
  2824 						// Now in a waiting state, set self active
       
  2825 						iStatus = KRequestPending;
       
  2826 						SetActive();
       
  2827 						}
       
  2828 					}
       
  2829 				else if (aAction==KAcceptStopCurrent)
       
  2830 					{
       
  2831 					// change from EWaitingForOpToComplete to EWaitingForOpToStop
       
  2832 					StopCurrentForMigrate();
       
  2833 					}
       
  2834 				// else already preparing for new carrier, nothing to do.
       
  2835 				return;
       
  2836 				}
       
  2837 			case EHandlingConnectError:
       
  2838 				{
       
  2839 				// We have a Connect Error, from previous connect attempt
       
  2840 				// We are ready to (migrate) reconnect
       
  2841 				iMigrateState = EWaitingForNewCarrier;
       
  2842 				iMobilityManager->MigrateToNewCarrier();
       
  2843 				
       
  2844 				// do not set waiting if NewCarrierActive has been called synchronously.
       
  2845 				if (iMigrateState == EWaitingForNewCarrier)
       
  2846 					{
       
  2847 					// Now in a waiting state, set self active
       
  2848 					iStatus = KRequestPending;
       
  2849 					SetActive();
       
  2850 					}
       
  2851 				break;
       
  2852 				}
       
  2853 			case EConnectingAfterMigrate:	// async wait on session manager
       
  2854 				{
       
  2855 				// cancelling in this state tidies up the session array, so
       
  2856 				// nothing extra to do here - now ready for migration.
       
  2857 				Cancel();
       
  2858 				iMigrateState = EWaitingForNewCarrier;
       
  2859 				iMobilityManager->MigrateToNewCarrier();
       
  2860 	
       
  2861 				// do not set waiting if NewCarrierActive has been called synchronously.
       
  2862 				if (iMigrateState == EWaitingForNewCarrier)
       
  2863 					{
       
  2864 					// Now in a waiting state, set self active
       
  2865 					iStatus = KRequestPending;
       
  2866 					SetActive();
       
  2867 					}
       
  2868 				return;				
       
  2869 				}
       
  2870 
       
  2871 			case EWaitingInitialCarrierRejected:	// async wait state on mobility engine
       
  2872 			case EWaitingForNewCarrier:		// async wait state on mobility engine
       
  2873 			case EStartingReconnect:		// intermediate state
       
  2874 				{
       
  2875 				// already ready and waiting for a new carrier - Cancel dummy request
       
  2876 				// and tell the Mobility framework we are ready
       
  2877 				Cancel();
       
  2878 				iMigrateState = EWaitingForNewCarrier;
       
  2879 				iMobilityManager->MigrateToNewCarrier();
       
  2880 	
       
  2881 				// do not set waiting if NewCarrierActive has been called synchronously.
       
  2882 				if (iMigrateState == EWaitingForNewCarrier)
       
  2883 					{
       
  2884 					// Now in a waiting state, set self active
       
  2885 					iStatus = KRequestPending;
       
  2886 					SetActive();
       
  2887 					}
       
  2888 				return;
       
  2889 				}
       
  2890 			case ESuspendingForMigrate:     // intermediate state
       
  2891 			case ENotMigrating:				// already checked this isn't true
       
  2892 			default:
       
  2893 				{
       
  2894 				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProConPreForNewCarBadMigrateState));
       
  2895 				}
       
  2896 			}
       
  2897 		}
       
  2898 
       
  2899 	// Do the requested action...
       
  2900 	switch (aAction)
       
  2901 		{
       
  2902 		case KAcceptCompleteCurrent:
       
  2903 			{
       
  2904 			// Any current operation shall be allowed to complete prior
       
  2905 			// to indicating that the server MTM is ready to migrate to
       
  2906 			// the new bearer.
       
  2907 			CompleteCurrentForMigrate();
       
  2908 			break;
       
  2909 			}
       
  2910 		case KAcceptStopCurrent:
       
  2911 			{
       
  2912 			// Any current operation shall be allowed to continue until
       
  2913 			// such a point that it may be resumed without re-sending or
       
  2914 			// re-receiveing a significant amount to data prior to 
       
  2915 			// indicating that the server MTM is ready to migrate to the 
       
  2916 			// new bearer.
       
  2917 			StopCurrentForMigrate();
       
  2918 			break;
       
  2919 			}
       
  2920 		case KAcceptImmediately:
       
  2921 		default:
       
  2922 			{
       
  2923 			// accept immediately is an instruction to immediately suspend any
       
  2924 			// current operation (cancel any outstanding server communication)
       
  2925 			// and close any open sockets. This is the same behaviour as required
       
  2926 			// for a downgrade situation.
       
  2927 			CarrierLost();
       
  2928 			iMigrateState = EWaitingForNewCarrier;
       
  2929 			iMobilityManager->MigrateToNewCarrier();
       
  2930 
       
  2931 			// do not set waiting if NewCarrierActive has been called synchronously.
       
  2932 			if (iMigrateState == EWaitingForNewCarrier)
       
  2933 				{
       
  2934 				// Now in a waiting state, set self active
       
  2935 				iStatus = KRequestPending;
       
  2936 				SetActive();
       
  2937 				}
       
  2938 			break;
       
  2939 			}
       
  2940 		} // end switch (aAction)
       
  2941 	}
       
  2942 
       
  2943 /**
       
  2944 Configures the protocol controller (PC) to allow any current operation in progress
       
  2945 to complete prior to indicating to the mobility framework that it is ready to
       
  2946 migrate to the new carrier.
       
  2947 
       
  2948 Note the protocol controller may be in any of the following states
       
  2949  - IDLE (only one session exists)
       
  2950  - background sync in progress only (only one session exists)
       
  2951  - foreground op in progress only (only one session exists)
       
  2952  - background sync and foreground operation in progress (2 sessions exist)
       
  2953  - background sync in progress and connecting second session for foreground op
       
  2954 
       
  2955 */ 	
       
  2956 void CImapProtocolController::CompleteCurrentForMigrate()	
       
  2957 	{
       
  2958 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::CompleteCurrentForMigrate()");
       
  2959 	// set the migrating flag
       
  2960 	iMigrateState = EWaitingForOpToComplete;
       
  2961 	
       
  2962 	if (BackgroundSyncInProgress())
       
  2963 		{
       
  2964 		// 2-phase background sync is always delayed till after migration
       
  2965 		iBackgroundSyncOp->StopForMigrate();
       
  2966 		}
       
  2967 
       
  2968 	// If no operation in progress, stop the IDLE
       
  2969 	if (iCurrentOp == EIdle && iImapIdleController->IsActive())
       
  2970 		{
       
  2971 		iCurrentOp = EStopIdle;
       
  2972 		iImapIdleController->StopIdle(iStatus);
       
  2973 		SetActive();
       
  2974 		return;
       
  2975 		}
       
  2976 
       
  2977 	// cancel a secondary session connect
       
  2978 	if (iCurrentOp == EConnectSecondary)
       
  2979 		{
       
  2980 		CancelForMigrate();
       
  2981 		iMigrateState = EWaitingForOpToComplete;
       
  2982 		
       
  2983 		// defensive: it is possible that the background sync has completed
       
  2984 		// while the secondary connect is still in progress. In this case
       
  2985 		// neither DoRunL() nor BackgroundSyncComplete() will not be called.
       
  2986 		if (!BackgroundSyncInProgress())
       
  2987 			{
       
  2988 			// fake a stop-idle op
       
  2989 			iCurrentOp = EStopIdle;
       
  2990 			SetActive();
       
  2991 			TRequestStatus* status = &iStatus;
       
  2992 			User::RequestComplete(status, KErrNone);
       
  2993 			}
       
  2994 		}
       
  2995 	}
       
  2996 
       
  2997 /**
       
  2998 CancelForMigrate() - cancels any outstanding service without deleting the
       
  2999 compound operation or completing the user request.
       
  3000 
       
  3001 This does not cancel a background sync.
       
  3002 
       
  3003 iMigrateState must be set to a new state immediately after calling this.
       
  3004 */
       
  3005 void CImapProtocolController::CancelForMigrate()
       
  3006 	{
       
  3007 	iMigrateState = ESuspendingForMigrate;
       
  3008 	Cancel();
       
  3009 	}
       
  3010 
       
  3011 /**
       
  3012 */
       
  3013 void CImapProtocolController::DoCancelForMigrate()
       
  3014 	{
       
  3015 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DoCancelForMigrate()");
       
  3016 	switch (iCurrentOp)
       
  3017 		{
       
  3018 		case EConnectSecondary:
       
  3019 			{
       
  3020 			// Cancel the connect request
       
  3021 			iImapSessionManager->Cancel();
       
  3022 			// Remove the session pointer from the array
       
  3023 			// The session has already been deleted - see note above.
       
  3024 			TInt numSessions = iImapSessionArray.Count();
       
  3025 			iImapSessionArray.Remove(numSessions-1);
       
  3026 			break;
       
  3027 			}
       
  3028 
       
  3029 		case EIdle:
       
  3030 		case EStopIdle:
       
  3031 			{
       
  3032 			// Cancel the IDLE controller.
       
  3033 			iImapIdleController->Cancel();
       
  3034 			break;
       
  3035 			}
       
  3036 
       
  3037 		case ESync:
       
  3038 		case ESelect:
       
  3039 		case ECopyToLocal:
       
  3040 		case ECopyWithinService:
       
  3041 		case ECopyFromLocal:
       
  3042 		case EMoveToLocal:
       
  3043 		case EMoveWithinService:
       
  3044 		case EMoveFromLocal:
       
  3045 		case EPopulate:
       
  3046 		case EDelete:
       
  3047 		case EDeleteFolder:
       
  3048 		case ECreate:
       
  3049 		case ERename:
       
  3050 			{
       
  3051 			// Cancel the compound operation
       
  3052 			iImapCompound->CancelForMigrate();
       
  3053 			break;
       
  3054 			}
       
  3055 
       
  3056 		case ECancelRecoverPrimary:
       
  3057 			{
       
  3058 			// Cancel the session recovery.
       
  3059 			(iImapSessionArray[0])->Cancel();
       
  3060 			}
       
  3061 
       
  3062 		case EConnect:
       
  3063 //		case EConnectAndSync:
       
  3064 		case EDisconnect:
       
  3065 		default:
       
  3066 			{
       
  3067 			// nothing to do..
       
  3068 			break;
       
  3069 			}
       
  3070 			
       
  3071 		} // end of switch (iCurrentOp)
       
  3072 
       
  3073 	// Do NOT call CMsgActive::DoCancel()
       
  3074 	// - the client requested operation is not being cancelled
       
  3075 	}
       
  3076 
       
  3077 
       
  3078 /**
       
  3079 Configures the protocol controller (PC) to stop any current operation in 
       
  3080 progress at the next convenient point - the meaning of this depends on the 
       
  3081 specific compound operations. For example, for simple operations such as 
       
  3082 creating a folder, this will be when the operation has completed but for
       
  3083 operations for which multiple messages are processed in sequence (eg 
       
  3084 fetching several messages), it shall be once the current message has been
       
  3085 processed (eg fetched). At this point the operation shall complete the
       
  3086 protocol controller's iStatus
       
  3087 
       
  3088 Note the protocol controller may be in any of the following states
       
  3089  - IDLE (only one session exists)
       
  3090  - background sync in progress only (only one session exists)
       
  3091  - foreground op in progress only (only one session exists)
       
  3092  - background sync and foreground operation in progress (2 sessions exist)
       
  3093  - background sync in progress and connecting second session for foreground op
       
  3094 
       
  3095 */ 
       
  3096 void CImapProtocolController::StopCurrentForMigrate()	
       
  3097 	{
       
  3098 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::StopCurrentForMigrate()");
       
  3099 	// set the migrating flag
       
  3100 	iMigrateState = EWaitingForOpToStop;
       
  3101 	
       
  3102 	if (BackgroundSyncInProgress())
       
  3103 		{
       
  3104 		iBackgroundSyncOp->StopForMigrate();
       
  3105 		}
       
  3106 	
       
  3107 	if (iCurrentOp == EIdle && iImapIdleController->IsActive())
       
  3108 		{
       
  3109 		// If no operation in progress, stop the IDLE
       
  3110 		iCurrentOp = EStopIdle;
       
  3111 		iImapIdleController->StopIdle(iStatus);
       
  3112 		SetActive();
       
  3113 		return;
       
  3114 		}
       
  3115 	else if (iCurrentOp == EConnectSecondary)
       
  3116 		{
       
  3117 		// cancel a secondary session connect
       
  3118 		Cancel();
       
  3119 		
       
  3120 		// defensive: it is possible that the background sync has completed
       
  3121 		// while the secondary connect is still in progress. In this case
       
  3122 		// neither DoRunL() nor BackgroundSyncComplete() will not be called.
       
  3123 		if (!BackgroundSyncInProgress())
       
  3124 			{
       
  3125 			// fake a stop-idle op
       
  3126 			iCurrentOp = EStopIdle;
       
  3127 			SetActive();
       
  3128 			TRequestStatus* status = &iStatus;
       
  3129 			User::RequestComplete(status, KErrNone);
       
  3130 			}
       
  3131 		}
       
  3132 	else if (iCurrentOp != ECancelRecoverPrimary)
       
  3133 		{
       
  3134 		// nothing to do for ECancelRecoverPrimary - just wait for the
       
  3135 		// session to flush.
       
  3136 		// all other operations are told to stop:
       
  3137 		iImapCompound->StopForMigrate();		
       
  3138 		}
       
  3139 	}		
       
  3140 
       
  3141 /**
       
  3142 This API is called by the Bearer Mobility Manager. It is typically called in the 
       
  3143 case that a downgrade is occuring, and the original sockets are no longer valid
       
  3144 for use. It may also be called if an immediate migration to an preferred bearer is
       
  3145 required, without graceful closing of the original sockets.
       
  3146 
       
  3147 Any operations are cancelled immediately using the CancelForMigrate() API. This
       
  3148 cancels the operations in such a way that they may be restarted following migration
       
  3149 to a new carrier.
       
  3150 */
       
  3151 void CImapProtocolController::CarrierLost()
       
  3152 	{
       
  3153 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::CarrierLost(iMigrateState=%d)", iMigrateState));
       
  3154 
       
  3155 	// Handle being called in an already-migrating state before handling usual case
       
  3156 	if (iMigrateState!=ENotMigrating)
       
  3157 		{
       
  3158 		switch (iMigrateState)
       
  3159 			{
       
  3160 			case EWaitingForOpToStop:
       
  3161 			case EWaitingForOpToComplete:
       
  3162 				{
       
  3163 				// break to default behaviour
       
  3164 				break;
       
  3165 				}
       
  3166 			
       
  3167 			case EStartingReconnect:		// intermediate state
       
  3168 			case EDisconnectingForMigrate:
       
  3169 			case EConnectingAfterMigrate:
       
  3170 				{
       
  3171 				// cancel the disconnect/connect, then break to default behaviour
       
  3172 				// (calling CancelForMigrate() shouldn't do anything as any compound
       
  3173 				// operations will not themselves be active)
       
  3174 				Cancel();
       
  3175 				break;
       
  3176 				}
       
  3177 				
       
  3178 			case EHandlingConnectError:
       
  3179 				{
       
  3180 				// empty the session array
       
  3181 				TInt numSessions = iImapSessionArray.Count();
       
  3182 				for (TInt i=0; i<numSessions; ++i)
       
  3183 					{
       
  3184 					if (iImapSessionArray[i])
       
  3185 						{
       
  3186 						iImapSessionManager->Disconnect(*(iImapSessionArray[i]));
       
  3187 						}
       
  3188 					}
       
  3189 				iImapSessionArray.ResetAndDestroy();
       
  3190 
       
  3191 				// Set the migration state:
       
  3192 				iMigrateState = EWaitingForNewCarrier;
       
  3193 				
       
  3194 				// Now in an waiting state, set self active
       
  3195 				iStatus = KRequestPending;
       
  3196 				SetActive();
       
  3197 				return;
       
  3198 				}
       
  3199 					
       
  3200 			case EWaitingInitialCarrierRejected:
       
  3201 			case EWaitingForNewCarrier:
       
  3202 				{
       
  3203 				// already ready and waiting for a new carrier - nothing to do.
       
  3204 				return;
       
  3205 				}
       
  3206 			
       
  3207 			case ESuspendingForMigrate:     // intermediate state
       
  3208 			case ENotMigrating:				// normal state
       
  3209 			default:
       
  3210 				{
       
  3211 				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProConKillCurrentBadMigrateState));
       
  3212 				break;
       
  3213 				}
       
  3214 			}
       
  3215 		}
       
  3216 
       
  3217 
       
  3218 	// stop any background operation
       
  3219 	if (iBackgroundSyncOp)
       
  3220 		{
       
  3221 		iBackgroundSyncOp->CancelForMigrate();
       
  3222 		}
       
  3223 
       
  3224 	// Cancel foreground operations
       
  3225 	CancelForMigrate();
       
  3226 		
       
  3227 	// delete the imap idle controller - this will be re-created on reconnect.
       
  3228 	delete iImapIdleController;
       
  3229 	iImapIdleController=NULL;
       
  3230 		
       
  3231 	// Drop connection on each of the imap sessions
       
  3232 	TInt numSessions = iImapSessionArray.Count();
       
  3233 	for (TInt i=0; i<numSessions; ++i)
       
  3234 		{
       
  3235 		if (iImapSessionArray[i])
       
  3236 			{
       
  3237 			iImapSessionManager->Disconnect(*(iImapSessionArray[i]));
       
  3238 			}
       
  3239 		}
       
  3240 
       
  3241 	// empty the session array
       
  3242 	iImapSessionArray.ResetAndDestroy();
       
  3243 	
       
  3244 	// Set the migration state:
       
  3245 	iMigrateState = EWaitingForNewCarrier;
       
  3246 	
       
  3247 	// Now in an waiting state, set self active
       
  3248 	iStatus = KRequestPending;
       
  3249 	SetActive();
       
  3250 	}
       
  3251 	
       
  3252 /**
       
  3253 Called to indicate the migration has completed and the RConnection is ready to
       
  3254 provide new sockets via the new bearer.
       
  3255 
       
  3256 Initiates the creation of a new IMAP session, following which any suspended
       
  3257 operation shall be restarted.
       
  3258 */
       
  3259 void CImapProtocolController::NewCarrierActive(TAccessPointInfo /*aNewAp*/, TBool /*aIsSeamless*/)
       
  3260 	{
       
  3261 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::NewCarrierActive()");
       
  3262 	__ASSERT_DEBUG((iMigrateState == EWaitingForNewCarrier || iMigrateState == EWaitingInitialCarrierRejected),
       
  3263 	               TImapServerPanic::ImapPanic(TImapServerPanic::ENewCarrierActiveUnexpectedMigrateState));
       
  3264 
       
  3265 	// Cancel the dummy active state
       
  3266 	Cancel();
       
  3267 
       
  3268 	// set the new migration state
       
  3269 	iMigrateState = EStartingReconnect;
       
  3270 
       
  3271 	// complete self - this requires some memory allocation, do it within the RunL.
       
  3272 	TRequestStatus* status = &iStatus;
       
  3273 	User::RequestComplete(status, KErrNone);
       
  3274 	SetActive();	
       
  3275 	}
       
  3276 
       
  3277 	
       
  3278 void CImapProtocolController::NewPrimarySessionL()
       
  3279 	{
       
  3280 	// Create the primary session pointer
       
  3281 	CImapSession* imapSession = NULL;
       
  3282 	iImapSessionArray.AppendL(imapSession);
       
  3283 
       
  3284 	// Request the session manager to connect the session
       
  3285 	iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[0]);
       
  3286 	iMigrateState = EConnectingAfterMigrate;
       
  3287 
       
  3288 	SetActive();
       
  3289 	}
       
  3290 	
       
  3291 /**
       
  3292 Indicates that the RConnection is no longer valid.
       
  3293 Therefore disconnect and mark the service as offline.
       
  3294 */
       
  3295 #ifdef __IMAP_LOGGING
       
  3296 void CImapProtocolController::MobilityError(TUint aError)
       
  3297 #else //__IMAP_LOGGING
       
  3298 void CImapProtocolController::MobilityError(TUint /*aError*/)
       
  3299 #endif //__IMAP_LOGGING
       
  3300 	{
       
  3301 	__LOG_FORMAT((KDefaultLog, "CImapProtocolController::MobilityError(iMigrateState=%d, aError=%d)", iMigrateState, aError));
       
  3302 	
       
  3303 	// Cancel any async request
       
  3304 	Cancel();
       
  3305 	
       
  3306 	if (iRequestedOp != EIdle)
       
  3307 		{
       
  3308 		// Complete the user request - calls DisconnectAll()
       
  3309 		Complete(KErrDisconnected);
       
  3310 		}
       
  3311 	else
       
  3312 		{
       
  3313 		// Disconnect all sessions and mark the service as offline
       
  3314 		DisconnectAll();
       
  3315 		}
       
  3316 	
       
  3317 	// the RConnection is no longer valid - delete the session manager
       
  3318 	// (will be recreated on ConnectL())
       
  3319 	delete iImapSessionManager;
       
  3320 	iImapSessionManager = NULL;
       
  3321 	
       
  3322 	// no longer migrating...
       
  3323 	iMigrateState = ENotMigrating;
       
  3324 
       
  3325 	// Save error code in progress and flag the disconnect
       
  3326 	// this is defensive as the client should not be watching progress
       
  3327 	iProgress.iGenericProgress.iState=TImap4GenericProgress::EDisconnected;
       
  3328 	iProgress.iGenericProgress.iErrorCode=KErrDisconnected;
       
  3329 	}
       
  3330 
       
  3331 void CImapProtocolController::ProcessOpCompleteForMigrate()
       
  3332 	{
       
  3333 	// Any tidying up to do for the current user-requested operation
       
  3334 	switch (iCurrentOp)
       
  3335 		{
       
  3336 		case ECancelRecoverPrimary:
       
  3337 		case EIdle:
       
  3338 		case EStopIdle:
       
  3339 			{
       
  3340 			// engine was IDLE or recovering from a cancel when the 
       
  3341 			// migrate notice arrived... nothing to do before disconnecting.
       
  3342 			break;
       
  3343 			}
       
  3344 
       
  3345 		case ESync:
       
  3346 		case ESelect:
       
  3347 		case ECopyToLocal:
       
  3348 		case ECopyWithinService:
       
  3349 		case ECopyFromLocal:
       
  3350 		case EMoveToLocal:
       
  3351 		case EMoveWithinService:
       
  3352 		case EMoveFromLocal:
       
  3353 		case EPopulate:
       
  3354 		case EDelete:
       
  3355 		case EDeleteFolder:
       
  3356 		case ECreate:
       
  3357 		case ERename:
       
  3358 			{
       
  3359 			// update last operation progress state
       
  3360 			iImapCompound->Progress(iProgress);
       
  3361 			
       
  3362 			// if the user requested operation has finished, 
       
  3363 			// tidyup and inform the client 
       
  3364 			if (iProgress.iGenericProgress.iState == TImap4GenericProgress::EIdle)
       
  3365 				{
       
  3366 				delete iImapCompound;
       
  3367 				iImapCompound = NULL;
       
  3368 		
       
  3369 				// Complete the server mtm request.
       
  3370 				Complete(iStatus.Int());
       
  3371 				}
       
  3372 			break;
       
  3373 			}
       
  3374 
       
  3375 		case EConnect:
       
  3376 		case EDisconnect:
       
  3377 		case EConnectSecondary:
       
  3378 		default:
       
  3379 			{
       
  3380 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EProcessOpCompleteForMigrateUnexpectedState));
       
  3381 			}
       
  3382 		} // end of switch (iCurrentOp)
       
  3383 	}
       
  3384 
       
  3385 /**
       
  3386 Logs out and disconnects all connected sessions with the remote server.
       
  3387 */
       
  3388 void CImapProtocolController::DisconnectForMigrateL()
       
  3389 	{
       
  3390 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::DisconnectForMigrateL()");
       
  3391 	__ASSERT_DEBUG(iMigrateCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::EMigrateCompoundIsNotNull));
       
  3392 	
       
  3393 	// Background operations will have been taken care of already - just disconnect.
       
  3394 	// Do not perform the late-delete offline operations.
       
  3395 	delete iMigrateCompound;
       
  3396 	iMigrateCompound = NULL;
       
  3397 	
       
  3398 	iMigrateCompound = CImapCompoundDisconnect::NewL( *iImapSyncManager, 
       
  3399 												      iEntry, 
       
  3400 												      *iImapSettings,
       
  3401 												      *iImapSessionManager,
       
  3402 												      *iImapMailStore,
       
  3403 												      iImapSessionArray,
       
  3404 												      iImapOfflineControl,
       
  3405 												      EFalse );
       
  3406 
       
  3407 	iMigrateState = EDisconnectingForMigrate;
       
  3408 	iMigrateCompound->StartOperation(iStatus, *iImapSessionArray[0]);
       
  3409 	SetActive();	
       
  3410 	}
       
  3411 
       
  3412 
       
  3413 /**
       
  3414 Resumes operations that were stopped to allow migration to occur,
       
  3415 or operations that were requested while migration was in progress.
       
  3416 */
       
  3417 void CImapProtocolController::RestartAfterMigrateL()
       
  3418 	{
       
  3419 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::RestartAfterMigrateL()");
       
  3420 	
       
  3421 	// The migration has completed. Restart anything that was going on
       
  3422 	// before the migration started, or has been requested in the meantime.
       
  3423 	iMigrateState = ENotMigrating;
       
  3424 	
       
  3425 	// was the initial carrier rejected during the connect operation?
       
  3426 	// if so, mark as online and get the final connection progress info.
       
  3427 	if (iCurrentOp == EConnect)
       
  3428 		{
       
  3429 		TRAP_IGNORE(MarkOnOrOfflineL(ETrue));
       
  3430 
       
  3431 		// Collect the final connect progress information		
       
  3432 		iImapSessionManager->Progress(iProgress.iGenericProgress);
       
  3433 
       
  3434 		// Set last socket activity timeout to iMtmData1. This is used by Imcm.
       
  3435 		User::LeaveIfError( iEntry.SetEntry( iServiceId ) );
       
  3436 		TMsvEntry entry=iEntry.Entry();
       
  3437 		entry.SetMtmData1(iImapSessionManager->LastSocketActivityTimeout());
       
  3438 		User::LeaveIfError( iEntry.ChangeEntry( entry ) );
       
  3439 				
       
  3440 		// complete the connect request
       
  3441 		Complete(iStatus.Int());		
       
  3442 		}
       
  3443 	
       
  3444 	// Create a new IDLE controller - the old one was deleted.
       
  3445 	delete iImapIdleController;
       
  3446 	iImapIdleController=NULL;
       
  3447 	iImapIdleController = CImapIdleController::NewL(*this, iImapSessionArray[0], *iImapSyncManager, iEntry, *iImapSettings, *iImapMailStore);
       
  3448 
       
  3449 	//	was there a background sync in progress prior to migration?
       
  3450 	if (iBackgroundSyncOp)
       
  3451 		{
       
  3452 		// restart any background operation, using the new primary session.
       
  3453 		iBackgroundSyncOp->ResumeOperationL(*iImapSessionArray[0]);
       
  3454 		
       
  3455 		// was there a forground operation paused as well?
       
  3456 		if (iImapCompound)
       
  3457 			{
       
  3458 			// Create a second connected session.
       
  3459 			iCurrentOp = EConnectSecondary;
       
  3460 			// iRequestedOp should not have been changed...
       
  3461 			CImapSession* imapSession = NULL;
       
  3462 			iImapSessionArray.AppendL(imapSession);
       
  3463 			TInt sessionCount = iImapSessionArray.Count();
       
  3464 			iImapSessionManager->GetSessionL(iStatus, iImapSessionArray[sessionCount-1]);
       
  3465 			SetActive();
       
  3466 			}
       
  3467 		else
       
  3468 			{
       
  3469 			iCurrentOp = EIdle;
       
  3470 			}
       
  3471 		return;
       
  3472 		}
       
  3473 
       
  3474 	if (iImapCompound)
       
  3475 		{
       
  3476 		// Idle has not been restarted after the migration, so the requested 
       
  3477 		// operation can be re-started without calling StopIdle()
       
  3478 		// resume the suspended operation
       
  3479 		iCurrentOp = iRequestedOp;
       
  3480 		iImapCompound->ResumeOperationL(iStatus, *iImapSessionArray[0]);
       
  3481 		SetActive();		
       
  3482 		}
       
  3483 	else
       
  3484 		{
       
  3485 		// otherwise just start Idle
       
  3486 		iCurrentOp = EIdle;
       
  3487 		iRequestedOp = EIdle;
       
  3488 		StartIdle();
       
  3489 		}
       
  3490 	}
       
  3491 
       
  3492 /**
       
  3493 Returns a packaged copy of the current progress for passing to the
       
  3494 mobility policy plugin when a preferred carrier available notice
       
  3495 is received.
       
  3496 */
       
  3497 const TDesC8& CImapProtocolController::MobilityProgress()
       
  3498 	{
       
  3499 	Progress();
       
  3500 	iProgressBuffer = TImap4ProgressBuf(iProgress);
       
  3501 	return iProgressBuffer;
       
  3502 	}
       
  3503 /**
       
  3504 Updates  the specified messages read/unread status from the remote server.
       
  3505 @param aStatus
       
  3506 */	
       
  3507 EXPORT_C void CImapProtocolController::UpdateFlagL( TRequestStatus& aStatus)
       
  3508  
       
  3509 	{
       
  3510 	__LOG_TEXT(KDefaultLog, "CImapProtocolController::UpdateFlagL()");
       
  3511 	__ASSERT_DEBUG(iImapCompound==NULL, TImapServerPanic::ImapPanic(TImapServerPanic::ECreateCompoundIsNotNull));
       
  3512 	ResetProgress();
       
  3513 	if (!CompleteIfBackgroundOpInProgress(aStatus))	
       
  3514 		{
       
  3515 		iImapCompound = CImapUpdateFlagOperation::NewL(*iImapSyncManager,
       
  3516 												   iEntry,
       
  3517 												   *iImapSettings
       
  3518 												   );
       
  3519 		iRequestedOp = EUpdateFlag;
       
  3520 		StartPrimaryOperation();
       
  3521 		Queue(aStatus);
       
  3522 		SetActive();
       
  3523 		}
       
  3524 	}
       
  3525 	
       
  3526