email/imap4mtm/imapprotocolcontroller/src/cimapcompoundcopywithinservice.cpp
changeset 0 72b543305e3a
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 // Copyright (c) 2006-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 "cimapcompoundcopywithinservice.h"
       
    17 #include "cimapsessionconsts.h"
       
    18 #include "cimapsyncmanager.h"
       
    19 #include "cimapfolder.h"
       
    20 #include "cimaplogger.h"
       
    21 #include "imappaniccodes.h"
       
    22 
       
    23 #include "mobilitytestmtmapi.h"
       
    24 
       
    25 _LIT8( KMessageDataItem, "+FLAGS" );
       
    26 _LIT8( KDeleteValue,	 "\\Deleted" );
       
    27 
       
    28 CImapCompoundCopyWithinService::CImapCompoundCopyWithinService( CImapSyncManager& aSyncManager, 
       
    29 																CMsvServerEntry& aServerEntry, 
       
    30 																CImapSettings& aImapSettings, 
       
    31 																TBool aIsMove, 
       
    32 															  	const TMsvId aDestination )
       
    33  : CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings),
       
    34  	iIsMove(aIsMove), iDestinationId(aDestination)
       
    35 	{
       
    36 	
       
    37 	}
       
    38 
       
    39 CImapCompoundCopyWithinService::~CImapCompoundCopyWithinService()
       
    40 	{
       
    41 	iOutMessageFlagInfo.Close();
       
    42 	iMessageUids.Reset();
       
    43 	delete iUidSeq;
       
    44 	delete iSourceSel;
       
    45 	}
       
    46 	
       
    47 CImapCompoundCopyWithinService* CImapCompoundCopyWithinService::NewL( CImapSyncManager& aSyncManager, 
       
    48 																	  CMsvServerEntry& aServerEntry, 
       
    49 																	  CImapSettings& aImapSettings,
       
    50 																	  TBool aIsMove, 
       
    51 															  		  const CMsvEntrySelection& aSourceSel,
       
    52 															  		  const TMsvId aDestination )
       
    53 	{
       
    54 	CImapCompoundCopyWithinService* self = new (ELeave) CImapCompoundCopyWithinService( aSyncManager, 
       
    55 																						aServerEntry, 
       
    56 																						aImapSettings,
       
    57 																						aIsMove, 
       
    58 																						aDestination );
       
    59 	CleanupStack::PushL(self);
       
    60 	self->ConstructL(aSourceSel);
       
    61 	CleanupStack::Pop(self);
       
    62 	return self;
       
    63 	
       
    64 	}
       
    65 	
       
    66 void CImapCompoundCopyWithinService::ConstructL(const CMsvEntrySelection& aSourceSel)
       
    67 	{
       
    68 	// Local copy of the selection of messages to copy
       
    69 	iSourceSel  = new (ELeave) CMsvEntrySelection();
       
    70 	
       
    71 	// Check the source selection for acceptable message types/parts
       
    72 	// Messages         True
       
    73 	// Handle Parts     True
       
    74 	// Handle Folders   False
       
    75 	// Check source     True
       
    76 	// Makes a local copy of the source selection in iSourceSel
       
    77 	TInt err = CheckSelectionL(aSourceSel, iSourceSel, ETrue, ETrue, EFalse, ETrue);
       
    78 	if (err==KErrNone)
       
    79 		{
       
    80 		// reset the stats
       
    81 		iMsgsCopied = 0;
       
    82 		iMsgsDone = 0;
       
    83 		iMsgsToDo = aSourceSel.Count();
       
    84 		iTotalSize = CalculateDownloadSizeL(*iSourceSel);
       
    85 		}
       
    86 
       
    87 	// Add to the active scheduler
       
    88 	CActiveScheduler::Add(this);
       
    89 	}
       
    90 
       
    91 void CImapCompoundCopyWithinService::StartOperation(TRequestStatus& aStatus, CImapSession& aSession)
       
    92 	{
       
    93 	iSession = &aSession;
       
    94 	__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyWithinService::StartOperation()");
       
    95 	iNextStep = ECheckDestinationMailbox;
       
    96 	Queue(aStatus);
       
    97 	CompleteSelf();
       
    98 	}
       
    99 
       
   100 /**
       
   101 Handles the compound operation state machine
       
   102 
       
   103 @return ETrue if compound operation is completed, 
       
   104 		EFalse otherwise.
       
   105 */	
       
   106 TBool CImapCompoundCopyWithinService::DoRunLoopL( )
       
   107 	{
       
   108 	SetCurrentStep();
       
   109 	switch (iCurrentStep)
       
   110 		{
       
   111 		case ECheckDestinationMailbox:		// synchronous
       
   112 			{
       
   113 			// Obtain pointer to CImapFolder object for the destination folder.
       
   114 			iDestinationFolder = iSyncManager.GetFolderL(iDestinationId);
       
   115 			if (iDestinationFolder==NULL)
       
   116 				{
       
   117 				// note the error code for the progress report and complete
       
   118 				iProgressErrorCode = KErrNotFound;
       
   119 				iNextStep = EFinished;
       
   120 				}
       
   121 			else
       
   122 				{
       
   123 				iNextStep = ESetSourceMailbox;
       
   124 				}
       
   125 			// go to the next step
       
   126 			return EFalse;
       
   127 			}
       
   128 		
       
   129 		case ESetSourceMailbox:				// synchronous
       
   130 			{
       
   131 			// State machine returns to this state after performing a copy/move
       
   132 			// on messages in the selection in a single mailbox. The progress is
       
   133 			// incremented here for messages that have been copied. If all messages
       
   134 			// have been moved/copied the state machine progresses to the
       
   135 			// synchronisation of the destination folder.
       
   136 			IncrementProgress(iMsgsCopied);
       
   137 			
       
   138 			// starting a new copy operation...
       
   139 			iMsgsCopied = 0;
       
   140 			
       
   141 			if (iSourceSel->Count() > 0)
       
   142 				{
       
   143 				if (iStopForMigrate)
       
   144 					{
       
   145 					__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyWithinService::Stopped for migrate");
       
   146 					iCurrentStep = ESuspendedForMigrate;
       
   147 					iNextStep = ESetSourceMailbox;
       
   148 					Complete(KErrNone);
       
   149 					return ETrue;
       
   150 					}
       
   151 					
       
   152 				iCurrentMsgId = (*iSourceSel)[0];
       
   153 				SetSourceFolderL(iCurrentMsgId);
       
   154 				if (iSourceFolderId != NULL && iSourceFolder != NULL)
       
   155 					{
       
   156 					iNextStep = (iIsMove) ? ESelectSourceMailboxRW : ESelectSourceMailboxRO;
       
   157 					}
       
   158 				else
       
   159 					{
       
   160 					// no change in state if folder not acceptable,
       
   161 					// try again with the next message in the selection.
       
   162 					iNextStep = ESetSourceMailbox;
       
   163 					IncrementProgress(1);
       
   164 					}
       
   165 				}
       
   166 			else
       
   167 				{
       
   168 				// All messages copied or moved... 
       
   169 				// Sync the destination folder
       
   170 				iNextStep = ESelectDestinationMailboxRO;
       
   171 				}
       
   172 			// go to the next step
       
   173 			return EFalse;
       
   174 			}
       
   175 			
       
   176 		case ESelectSourceMailboxRW:			// asynchronous
       
   177 			{
       
   178 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService1);	// SELECT source mailbox
       
   179 			iSourceFolder->SelectL(iStatus, *iSession);
       
   180 			iNextStep = ECopyMessage;
       
   181 			SetActive();
       
   182 			break;
       
   183 			}
       
   184 
       
   185 		case ESelectSourceMailboxRO:
       
   186 			{
       
   187 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService1);	// EXAMINE source mailbox
       
   188 			iSourceFolder->ExamineL(iStatus, *iSession);
       
   189 			iNextStep = ECopyMessage;
       
   190 			SetActive();
       
   191 			break;
       
   192 			}
       
   193 			
       
   194 		case ECopyMessage:						// asynchronous
       
   195 			{
       
   196 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService2);	// COPY message(s)
       
   197 			// issue the COPY command - copies all messages in the selection
       
   198 			// that have the same parent folder as the first in the selection.
       
   199 			CopyMessagesL();
       
   200 			if (iIsMove)
       
   201 				{
       
   202 				iProgressState = TImap4GenericProgress::EMoving;
       
   203 				iNextStep = EDeleteMessage;
       
   204 				}
       
   205 			else
       
   206 				{
       
   207 				// on completion, return to SetSourceMailbox to check for
       
   208 				// more messages to copy (from other source folders)
       
   209 				iProgressState = TImap4GenericProgress::ECopying;
       
   210 				iNextStep = ESetSourceMailbox;
       
   211 				}
       
   212 			SetActive();
       
   213 			break;
       
   214 			}
       
   215 			
       
   216 		case EDeleteMessage: // asynchronous
       
   217 			{
       
   218 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService3);	// STORE /deleted flag (move only)
       
   219 			// Deleting a message is a two-stage operation:
       
   220 			// 1. STORE the /deleted flag on the remote server.
       
   221 			// 2.a) EXPUNGE the messages 
       
   222 			//or
       
   223 			// 2.b) CLOSE the folder and then SELECT the folder
       
   224 			// 2a) or 2b) used is dependent on the KImap4EmailExpungeFlag in CImImap4Settings.
       
   225 			MarkMessageForDeletesL();
       
   226 
       
   227 			if (iImapSettings.UseExpunge())
       
   228 				{
       
   229 				iNextStep=EExpunge;
       
   230 				}
       
   231 			else
       
   232 				{
       
   233 				iNextStep=ECloseFolder;
       
   234 				}
       
   235 
       
   236 			SetActive();
       
   237 			break;
       
   238 			}
       
   239 
       
   240 		case EExpunge: // asynchronous
       
   241 			{
       
   242 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService4);	// EXPUNGE source folder (move only)
       
   243 			iSession->ExpungeL(iStatus);
       
   244 			iNextStep = EDeleteLocalMessage;
       
   245 			SetActive();
       
   246 			break;
       
   247 			}
       
   248 
       
   249 		case ECloseFolder:
       
   250 			{
       
   251 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService7);	// CLOSE FOLDER (move only)
       
   252 			//Permanently removes all messages that have the deleted flag set
       
   253 			//from the currently selected mailbox
       
   254 			iSession->CloseL(iStatus);
       
   255 			iNextStep=ESelectFolderAfterClose;
       
   256 			SetActive();
       
   257 			break;
       
   258 			}
       
   259 
       
   260 		case ESelectFolderAfterClose:
       
   261 			{
       
   262 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService8);	// SELECT FOLDER (move only)
       
   263 			//Selecting a mailbox so that messages in the mailbox can be accessed. 
       
   264 			iSourceFolder->SelectL(iStatus, *iSession);
       
   265 			iNextStep=EDeleteLocalMessage;
       
   266 			SetActive();
       
   267 			break;
       
   268 			}
       
   269 
       
   270 		case EDeleteLocalMessage: // synchonous
       
   271 			{
       
   272 			// Delete the messages locally
       
   273 			DeleteMovedMessagesL();
       
   274 			// immediately proceed to the next step
       
   275 			iNextStep = ESetSourceMailbox;			
       
   276 			return EFalse;
       
   277 			}
       
   278 			
       
   279 		case ESelectDestinationMailboxRO:
       
   280 			{
       
   281 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService5);	// SELECT destination folder
       
   282 			iDestinationFolder->ExamineL(iStatus, *iSession);
       
   283 			iNextStep = ENewSyncFolder;
       
   284 			SetActive();
       
   285 			break;
       
   286 			}
       
   287 			
       
   288 		case ENewSyncFolder:
       
   289 			{
       
   290 			MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyWithinService6);	// sync'ing destination folder
       
   291 			// if the current folder hasn't actually changed then don't
       
   292 			// bother with the Sync
       
   293 			iNextStep = EFinished;
       
   294 			if (iDestinationFolder->Changed(*iSession))
       
   295 				{
       
   296 				iSyncProgressState=TImap4SyncProgress::ESyncOther;
       
   297 				iDestinationFolder->SynchroniseL(iStatus, *iSession, ETrue, 0);
       
   298 				SetActive();
       
   299 				}
       
   300 			break;
       
   301 			}
       
   302 			
       
   303 		case EFinished:
       
   304 			{
       
   305 			__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyWithinService::Completing OK");
       
   306 			iProgressState = TImap4GenericProgress::EIdle;
       
   307 			iSyncProgressState = TImap4SyncProgress::EIdle;
       
   308 			
       
   309 			Complete(KErrNone);
       
   310 			return ETrue;
       
   311 			}
       
   312 			
       
   313 		default:
       
   314 			{
       
   315 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundUnexpectedState));
       
   316 			// unexpected state - complete the request
       
   317 			iProgressState = TImap4GenericProgress::EIdle;
       
   318 			return ETrue;
       
   319 			}
       
   320 		} // end switch (iCurrentStep)
       
   321 	return EFalse;
       
   322 	}
       
   323 
       
   324 /**
       
   325 May be called in case of a genuine cancel or a cancel for migrate.
       
   326 Following a genuine cancel, the compound operation will be deleted.
       
   327 Following a cancel for migrate, the compound operation will be resumed,
       
   328 so the iNextState is updated here to ensure the operation is
       
   329 correctly restarted.
       
   330 
       
   331 In either case, CMsgActive::DoCancel() is called to complete the
       
   332 user request with KErrCancel.
       
   333 
       
   334 Note that if the default CMsgActive::DoComplete() is overridden,
       
   335 then that must also be modified to handle either case described above.
       
   336 */
       
   337 void CImapCompoundCopyWithinService::DoCancel()
       
   338 	{
       
   339 	switch (iCurrentStep)
       
   340 		{
       
   341 		case ESelectSourceMailboxRW:
       
   342 			{
       
   343 			iSession->Cancel();	
       
   344 			iNextStep = ESelectSourceMailboxRW;	// just resume
       
   345 			break;
       
   346 			}
       
   347 		case ESelectSourceMailboxRO:
       
   348 			{
       
   349 			iSession->Cancel();
       
   350 			iNextStep = ESelectSourceMailboxRO; // just resume
       
   351 			break;
       
   352 			}
       
   353 		case ECopyMessage:
       
   354 			{
       
   355 			iSession->Cancel();
       
   356 			iMsgsCopied = 0;					// reset copied count
       
   357 			iNextStep = ECopyMessage;			// reSELECT source
       
   358 			break;
       
   359 			}
       
   360 		case EDeleteMessage:
       
   361 			{
       
   362 			iSession->Cancel();
       
   363 			iNextStep = EDeleteMessage;			// reSELECT source
       
   364 			break;
       
   365 			}	
       
   366 		case EExpunge:
       
   367 			{
       
   368 			iSession->Cancel();
       
   369 			iNextStep = EExpunge;				// reSELECT source
       
   370 			break;
       
   371 			}
       
   372 		case ECloseFolder:
       
   373 			{
       
   374 			iSession->Cancel();
       
   375 			iNextStep = ECloseFolder;
       
   376 			break;
       
   377 			}
       
   378 		case ESelectFolderAfterClose:
       
   379 			{
       
   380 			iSession->Cancel();
       
   381 			iNextStep = ESelectFolderAfterClose;
       
   382 			break;
       
   383 			}
       
   384 		case ESelectDestinationMailboxRO:		
       
   385 			{
       
   386 			iSession->Cancel();
       
   387 			iNextStep = ESelectDestinationMailboxRO; // just restart
       
   388 			break;
       
   389 			}
       
   390 		case ENewSyncFolder:					
       
   391 			{
       
   392 			iDestinationFolder->Cancel();
       
   393 			iNextStep = ESelectDestinationMailboxRO; // just restart
       
   394 			break;
       
   395 			}
       
   396 		case ECheckDestinationMailbox:
       
   397 		case ESetSourceMailbox:
       
   398 		case EDeleteLocalMessage:
       
   399 		case EFinished:
       
   400 			// self-completed or no outstanding request.
       
   401 		case ESuspendedForMigrate:
       
   402 		default:
       
   403 			{
       
   404 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundCancelUnexpectedState));
       
   405 			iNextStep = ESetSourceMailbox;
       
   406 			// starting a new copy operation...
       
   407 			iMsgsCopied = 0;
       
   408 			break;
       
   409 			}
       
   410 		} // end switch (iCurrentStep)
       
   411 
       
   412 	if (!iCancelForMigrate)
       
   413 		{
       
   414 		// genuine cancel - update progress
       
   415 		iProgressErrorCode = KErrCancel;
       
   416 		}
       
   417 	CMsgActive::DoCancel();
       
   418 	}
       
   419 
       
   420 void CImapCompoundCopyWithinService::Progress(TImap4CompoundProgress& aCompoundProgress)
       
   421 	{
       
   422 	if (iIsMove)
       
   423 		{
       
   424 		aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::EMoveWithinService;
       
   425 		}
       
   426 	else
       
   427 		{
       
   428 		aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::ECopyWithinService;
       
   429 		}
       
   430 	
       
   431 	// Progress through the received selection
       
   432 	aCompoundProgress.iGenericProgress.iTotalSize = iTotalSize;
       
   433 	aCompoundProgress.iGenericProgress.iMsgsToDo  = iMsgsToDo;
       
   434 	aCompoundProgress.iGenericProgress.iMsgsDone  = iMsgsDone;
       
   435 	
       
   436 	aCompoundProgress.iSyncProgress.iState=iSyncProgressState;
       
   437 	
       
   438 	//if currently syncing then get the latest progress
       
   439 	if(iSyncProgressState!=TImap4SyncProgress::EIdle)
       
   440 		{
       
   441 		iDestinationFolder->Progress(aCompoundProgress.iSyncProgress);
       
   442 		}
       
   443 	
       
   444 		
       
   445 	// Put error into progress buffer
       
   446 	if( aCompoundProgress.iGenericProgress.iErrorCode == KErrNone )
       
   447 		{
       
   448 		aCompoundProgress.iGenericProgress.iErrorCode = iProgressErrorCode;
       
   449 		}
       
   450 	}
       
   451 
       
   452 /**
       
   453 Builds an array of messages within the same source folder that can be copied
       
   454 with a single command to the remote server.
       
   455 */
       
   456 void CImapCompoundCopyWithinService::CopyMessagesL( )
       
   457 	{
       
   458 	iMessageUids.Reset();
       
   459 	// build an array of the UIDs to copy,
       
   460 	TInt  i = 0;
       
   461 	TInt  count = iSourceSel->Count();
       
   462 
       
   463 	TBool sameParent = ETrue;
       
   464 	while(i<count && sameParent)
       
   465 		{
       
   466 		SetEntryL((*iSourceSel)[i]);
       
   467 		TMsvEmailEntry entry = iServerEntry.Entry();
       
   468 		if (entry.Parent()==iSourceFolderId)
       
   469 			{
       
   470 			TUint id = entry.UID();
       
   471 			iMessageUids.AppendL(id);
       
   472 			++iMsgsCopied;
       
   473 			}
       
   474 		else
       
   475 			{
       
   476 			sameParent=EFalse;
       
   477 			}
       
   478 		++i;
       
   479 		}
       
   480 		
       
   481 	// store the UID sequence array - we will need to reuse it to
       
   482 	// STORE the delete flag if we are performing a move.
       
   483 	delete iUidSeq;
       
   484 	iUidSeq = CImapSession::CreateSequenceSetLC(iMessageUids);
       
   485 	CleanupStack::Pop(iUidSeq);
       
   486 
       
   487 	// issue the store command
       
   488 	iSession->CopyL(iStatus, *iUidSeq, iDestinationFolder->FullFolderPathL());
       
   489 	}
       
   490 
       
   491 /*
       
   492 Marks the messages that have been copied as deleted locally.
       
   493 
       
   494 Takes the uids in iMessageUids and marks messages for delete locally,
       
   495 and issues STORE command to mark it for delete remotely.
       
   496 */
       
   497 void CImapCompoundCopyWithinService::MarkMessageForDeletesL()
       
   498 	{
       
   499 	for (TInt i=0 ; i<iMsgsCopied ; ++i)
       
   500 		{
       
   501 		// Move to the entry in question
       
   502 		SetEntryL((*iSourceSel)[i]);
       
   503 		
       
   504 		// Set deleted flag on this entry
       
   505 		TMsvEmailEntry entry = iServerEntry.Entry();
       
   506 		entry.SetDeletedIMAP4Flag(ETrue);
       
   507 		User::LeaveIfError(iServerEntry.ChangeEntry(entry));
       
   508 		}
       
   509 
       
   510 	iSession->StoreL( iStatus, 
       
   511 					  *iUidSeq, 
       
   512 					  KMessageDataItem, 
       
   513 					  KDeleteValue, 
       
   514 					  ETrue, 
       
   515 					  iOutMessageFlagInfo );
       
   516 	}
       
   517 
       
   518 /**
       
   519 Deletes the local copy of messages that have been expunged on the remote server.
       
   520 */
       
   521 void CImapCompoundCopyWithinService::DeleteMovedMessagesL()
       
   522 	{
       
   523 	// move to parent
       
   524 	SetEntryL(iSourceFolderId);
       
   525 	
       
   526 	TInt messagesToDelete = iMsgsCopied - iMsgsDone ;
       
   527 	for (TInt i=0 ; i<messagesToDelete ; ++i)
       
   528 		{
       
   529 		TMsvId msgId = (*iSourceSel)[i];
       
   530 		TInt err (iServerEntry.DeleteEntry(msgId));
       
   531 		
       
   532 		// Do not leave when entry is in use 
       
   533 		if(err == KErrInUse)
       
   534 			{
       
   535 			// Dont leave if err = KErrInUse
       
   536 			}
       
   537 		else
       
   538 			{
       
   539 			User::LeaveIfError(err);
       
   540 			}
       
   541 		}
       
   542 	}
       
   543 
       
   544 
       
   545 /**
       
   546 Find the parent folder
       
   547 @return ETrue if the source folder has changed since the last message operated on
       
   548 always true on the first call after creation.
       
   549 @post iSourceFolderId - The TMsvId of the source folder for the message. May be NULL
       
   550 @post iSourceFolder - CImapFolder pointer for the parent folder. May be NULL.
       
   551 */
       
   552 TBool CImapCompoundCopyWithinService::SetSourceFolderL(const TMsvId aMessage)
       
   553 	{
       
   554 	TMsvId parentFolder = FindFolderL(aMessage);
       
   555 	if (parentFolder==iSourceFolderId)
       
   556 		{
       
   557 		// Same folder as last message copied.
       
   558 		return EFalse;
       
   559 		}
       
   560 	// otherwise, update to the new folder.	
       
   561 	iSourceFolderId = parentFolder;
       
   562 	if (iSourceFolderId!=NULL)
       
   563 		{
       
   564 		iSourceFolder = iSyncManager.GetFolderL(iSourceFolderId);
       
   565 		}
       
   566 	return ETrue;
       
   567 	}
       
   568 
       
   569 /**
       
   570 Handles NO/BAD responses according to current step.
       
   571 Negative server responses are not fatal - the error is saved in
       
   572 the message currently being operated on and the state machine pushed
       
   573 on to process the next message in the requested selection.
       
   574 
       
   575 @return KErrNone if the error has been handled
       
   576 		Completion error code otherwise.
       
   577 */
       
   578 TInt CImapCompoundCopyWithinService::ProcessNegativeServerResponse()
       
   579 	{
       
   580 	TInt err = iStatus.Int();
       
   581 	switch (iCurrentStep)
       
   582 		{
       
   583 		case ESelectSourceMailboxRW:
       
   584 		case ESelectSourceMailboxRO:
       
   585 		case ESelectDestinationMailboxRO:
       
   586 		case ESelectFolderAfterClose:
       
   587 			{
       
   588 			if (err == KErrImapNo)
       
   589 				{
       
   590 				err = KErrNotFound;
       
   591 				}
       
   592 			} // fall through
       
   593 		case ECopyMessage:
       
   594 		case EDeleteMessage:
       
   595 		case EExpunge:
       
   596 		case ECloseFolder:
       
   597 		case ENewSyncFolder:
       
   598 			{
       
   599 			// save the error with the associated message
       
   600 			TRAP_IGNORE(MessageErrorL(iCurrentMsgId, err));
       
   601 			// Skip to the next message, or finish
       
   602 			iNextStep = EFinished;
       
   603 			break;
       
   604 			}
       
   605 		case ESuspendedForMigrate:
       
   606 		case ESetSourceMailbox:
       
   607 		case EFinished:
       
   608 		default:
       
   609 			{
       
   610 			// positive error code not expected,
       
   611 			// self-completed states or no outstanding request.
       
   612 			TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundUnexpectedState);
       
   613 			break;
       
   614 			}
       
   615 		} // end switch (iCurrentStep)
       
   616 	iProgressErrorCode = err;
       
   617 	return KErrNone;
       
   618 	}
       
   619 
       
   620 
       
   621 /**
       
   622 Increments the progress count and removes the copied/moved messages
       
   623 from the source selection.
       
   624 
       
   625 @param aNum - number of message copied/moved/otherwise managed.
       
   626 */
       
   627 void CImapCompoundCopyWithinService::IncrementProgress(TInt aNum)
       
   628 	{
       
   629 	if (aNum>0)
       
   630 		{
       
   631 		iMsgsDone+=aNum;
       
   632 		iSourceSel->Delete(0,aNum);
       
   633 		}
       
   634 	}
       
   635 
       
   636 
       
   637 /**
       
   638 Called to resume the compound operation following a bearer migration.
       
   639 */
       
   640 void CImapCompoundCopyWithinService::ResumeOperationL(TRequestStatus& aStatus, CImapSession& aSession)
       
   641 	{
       
   642 	iSession = &aSession;
       
   643 	__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyWithinService::Resuming");
       
   644 	__ASSERT_DEBUG(iCurrentStep==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundUnexpectedState));
       
   645 	iStopForMigrate = EFalse;
       
   646 
       
   647 	switch (iNextStep)
       
   648 		{
       
   649 		case ESelectSourceMailboxRW:
       
   650 		case ESelectSourceMailboxRO:
       
   651 		case ESelectDestinationMailboxRO:		
       
   652 		case ENewSyncFolder:
       
   653 		case ESelectFolderAfterClose:
       
   654 			{
       
   655 			CompleteSelf();
       
   656 			break;
       
   657 			}
       
   658 		case ECopyMessage:
       
   659 		case EDeleteMessage:
       
   660 		case EExpunge:
       
   661 		case ECloseFolder:
       
   662 			{
       
   663 			iSourceFolder->SelectL(iStatus, *iSession);
       
   664 			iCurrentStep = ESelectSourceMailboxRW;
       
   665 			SetActive();
       
   666 			break;
       
   667 			}
       
   668 		case ECheckDestinationMailbox:
       
   669 		case ESetSourceMailbox:
       
   670 		case EDeleteLocalMessage:
       
   671 		case EFinished:
       
   672 			// self-completed or no outstanding request.
       
   673 		default:
       
   674 			{
       
   675 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyWithinServiceCompoundCancelUnexpectedState));
       
   676 			// abandon the compound operation
       
   677 			iNextStep=EFinished;
       
   678 			CompleteSelf();
       
   679 			break;
       
   680 			}
       
   681 		} // end switch (iNextStep)
       
   682 	Queue(aStatus);
       
   683 	}
       
   684