email/pop3andsmtpmtm/imapservermtm/src/IMAPCOMP.CPP
changeset 25 84d9eb65b26f
equal deleted inserted replaced
23:238255e8b033 25:84d9eb65b26f
       
     1 // Copyright (c) 1998-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 // IMAP4 compound operations
       
    15 // This class wraps up operations which require more than one IMAP command
       
    16 // (the imapsess.cpp class deals with single IMAP commands generally),
       
    17 // allowing increased neatness in the higher classes.
       
    18 // 
       
    19 //
       
    20 
       
    21 #include <e32base.h>
       
    22 #include <e32cons.h>
       
    23 #include <mentact.h>
       
    24 #include "impspan.h"
       
    25 #include "imapsess.h"
       
    26 #include <imapset.h>
       
    27 #include "imapcomp.h"
       
    28 
       
    29 #ifdef _DEBUG
       
    30 #define LOG_COMMANDS(a) a
       
    31 #define DBG(a) a
       
    32 #define PRINTING
       
    33 #else
       
    34 #define LOG_COMMANDS(a)
       
    35 #define DBG(a)
       
    36 #undef PRINTING
       
    37 #endif
       
    38 
       
    39 // Priority of MsgActive object
       
    40 const TInt ECompoundPriority=1;
       
    41 
       
    42 
       
    43 // Operations that can be chained
       
    44 enum
       
    45 	{
       
    46 	EFinished=0,
       
    47 	ESelectSourceMailboxRW,
       
    48 	ESelectSourceMailboxRO,
       
    49 	ESelectDestinationMailboxRW,
       
    50 	ESelectDestinationMailboxRO,
       
    51 	EFetchMessage,
       
    52 	ECopyMessage,
       
    53 	EAppendMessage,
       
    54 	EDeleteMessage,
       
    55 	EDeleteLocalMessage,
       
    56 	EDeleteAllMessages,
       
    57 	ENewSyncFolder,
       
    58 	ESyncFolder,
       
    59 	EInboxDuplicateMove,
       
    60 	EInboxDuplicateCopy,
       
    61 	ECloseFolderWithoutExpunge,
       
    62 	EDeleteFolder,
       
    63 	EStartIdle,
       
    64 	EStopIdle,
       
    65 	ECreate,
       
    66 	ERename,
       
    67 	ESelectInbox
       
    68 	};
       
    69 
       
    70 //DS - Split EInboxDuplicate into EInboxDuplicateCopy and EInboxDuplicateMove to allow
       
    71 //use of either CMsvServerEntry::CopyL or MoveL depending on what operation the user
       
    72 //is attempting.
       
    73 
       
    74 CImImap4Compound::CImImap4Compound():CMsgActive(ECompoundPriority)
       
    75 	{
       
    76 	__DECLARE_NAME(_S("CImImap4Compound"));
       
    77 	}
       
    78 
       
    79 CImImap4Compound::~CImImap4Compound()
       
    80 	{
       
    81 	// We don't delete iSession as we don't own it, we were just passed it to use.
       
    82 	delete iSourceSel;
       
    83 	}
       
    84 
       
    85 CImImap4Compound* CImImap4Compound::NewL(CImImap4Session* aSession)
       
    86 	{
       
    87 	CImImap4Compound* self=new (ELeave) CImImap4Compound();
       
    88 	CleanupStack::PushL(self);
       
    89 
       
    90 	// Non-trivial constructor
       
    91 	self->ConstructL(aSession);
       
    92 	CleanupStack::Pop();
       
    93 	return self;
       
    94 	}
       
    95 
       
    96 // The non-trivial constructor
       
    97 void CImImap4Compound::ConstructL(CImImap4Session* aSession)
       
    98 	{
       
    99 	// Save session & entry
       
   100 	iSession=aSession;
       
   101 	
       
   102 	iPopulateCommand=EFalse;
       
   103 	iIdleBeforeFirstPopulate = EFalse;
       
   104 	// We're an active object...
       
   105 	CActiveScheduler::Add(this);
       
   106 
       
   107 	// Initialise static sequences. There must be a better way
       
   108 	// than this without causing complaints :-(
       
   109 	SeqCopyToLocal[0]=EStopIdle;
       
   110 	SeqCopyToLocal[1]=ESelectSourceMailboxRO;
       
   111 	SeqCopyToLocal[2]=EFetchMessage;
       
   112 	SeqCopyToLocal[3]=EInboxDuplicateCopy;
       
   113 	SeqCopyToLocal[4]=ESelectInbox;
       
   114 	SeqCopyToLocal[5]=EStartIdle;
       
   115 	SeqCopyToLocal[6]=EFinished;
       
   116 
       
   117 	SeqMoveToLocal[0]=EStopIdle;
       
   118 	SeqMoveToLocal[1]=ESelectSourceMailboxRW;
       
   119 	SeqMoveToLocal[2]=EFetchMessage;
       
   120 	SeqMoveToLocal[3]=EInboxDuplicateMove;
       
   121 	SeqMoveToLocal[4]=EDeleteMessage;
       
   122 	SeqMoveToLocal[5]=ESelectInbox;
       
   123 	SeqMoveToLocal[6]=EStartIdle;
       
   124 	SeqMoveToLocal[7]=EFinished;
       
   125 
       
   126 	SeqCopyWithinService[0]=EStopIdle;
       
   127 	SeqCopyWithinService[1]=ESelectSourceMailboxRO;
       
   128 	SeqCopyWithinService[2]=ECopyMessage;
       
   129 	SeqCopyWithinService[3]=ESelectDestinationMailboxRO;
       
   130 	SeqCopyWithinService[4]=ENewSyncFolder;
       
   131 	SeqCopyWithinService[5]=ESelectInbox;
       
   132 	SeqCopyWithinService[6]=EStartIdle;
       
   133 	SeqCopyWithinService[7]=EFinished;
       
   134 
       
   135 	SeqMoveWithinService[0]=EStopIdle;
       
   136 	SeqMoveWithinService[1]=ESelectSourceMailboxRW;
       
   137 	SeqMoveWithinService[2]=ECopyMessage;
       
   138 	SeqMoveWithinService[3]=EDeleteMessage;
       
   139 	SeqMoveWithinService[4]=ESelectDestinationMailboxRO;
       
   140 	SeqMoveWithinService[5]=ENewSyncFolder;
       
   141 	SeqMoveWithinService[6]=ESelectInbox;
       
   142 	SeqMoveWithinService[7]=EStartIdle;
       
   143 	SeqMoveWithinService[8]=EFinished;
       
   144 
       
   145 	SeqCopyFromLocal[0]=EAppendMessage;
       
   146 	SeqCopyFromLocal[1]=ESelectDestinationMailboxRO;
       
   147 	SeqCopyFromLocal[2]=ENewSyncFolder;
       
   148 	SeqCopyFromLocal[3]=EFinished;
       
   149 
       
   150 	SeqMoveFromLocal[0]=EStopIdle;
       
   151 	SeqMoveFromLocal[1]=EAppendMessage;
       
   152 	SeqMoveFromLocal[2]=EDeleteLocalMessage;
       
   153 	SeqMoveFromLocal[3]=ESelectDestinationMailboxRO;
       
   154 	SeqMoveFromLocal[4]=ENewSyncFolder;
       
   155 	SeqMoveFromLocal[5]=ESelectInbox;
       
   156 	SeqMoveFromLocal[6]=EStartIdle;
       
   157 	SeqMoveFromLocal[7]=EFinished;
       
   158 
       
   159 	SeqDelete[0]=EStopIdle;
       
   160 	SeqDelete[1]=ESelectSourceMailboxRW;
       
   161 	SeqDelete[2]=EDeleteMessage; // Explicit expunge
       
   162 	SeqDelete[3]=ESelectInbox;
       
   163 	SeqDelete[4]=EStartIdle;
       
   164 	SeqDelete[5]=EFinished;
       
   165 
       
   166 	SeqDeleteFolder[0]=EStopIdle;
       
   167 	SeqDeleteFolder[1]=ESelectSourceMailboxRW;
       
   168 	SeqDeleteFolder[2]=EDeleteAllMessages;
       
   169 	SeqDeleteFolder[3]=ECloseFolderWithoutExpunge;
       
   170 	SeqDeleteFolder[4]=EDeleteFolder;
       
   171 	SeqDeleteFolder[5]=ESelectInbox;
       
   172 	SeqDeleteFolder[6]=EStartIdle;
       
   173 	SeqDeleteFolder[7]=EFinished;
       
   174 
       
   175 	SeqNewSync[0]=EStopIdle;
       
   176 	SeqNewSync[1]=ESelectSourceMailboxRW;
       
   177 	SeqNewSync[2]=ENewSyncFolder;
       
   178 	SeqNewSync[3]=ESelectInbox;
       
   179 	SeqNewSync[4]=EStartIdle;
       
   180 	SeqNewSync[5]=EFinished;
       
   181 
       
   182 	SeqFullSync[0]=EStopIdle;
       
   183 	SeqFullSync[1]=ESelectSourceMailboxRW;
       
   184 	SeqFullSync[2]=ESyncFolder;
       
   185 	SeqFullSync[3]=ESelectInbox;
       
   186 	SeqFullSync[4]=EStartIdle;
       
   187 	SeqFullSync[5]=EFinished;
       
   188 
       
   189 	SeqSelect[0]=EStopIdle;
       
   190 	SeqSelect[1]=ESelectSourceMailboxRW;
       
   191 	SeqSelect[2]=EFinished;
       
   192 
       
   193 	SeqSynchronise[0]=EStopIdle;
       
   194 	SeqSynchronise[1]=ESyncFolder;
       
   195 	SeqSynchronise[2]=ESelectInbox;
       
   196 	SeqSynchronise[3]=EStartIdle;
       
   197 	SeqSynchronise[4]=EFinished;
       
   198 
       
   199 	SeqCreate[0]=EStopIdle;
       
   200 	SeqCreate[1]=ECreate;
       
   201 	SeqCreate[2]=ESelectInbox;
       
   202 	SeqCreate[3]=EStartIdle;
       
   203 	SeqCreate[4]=EFinished;
       
   204 
       
   205 	SeqRename[0]=EStopIdle;
       
   206 	SeqRename[1]=ERename;
       
   207 	SeqRename[2]=ESelectInbox;
       
   208 	SeqRename[3]=EStartIdle;
       
   209 	SeqRename[4]=EFinished;
       
   210 
       
   211 	// operations when done as part of a synchronisation process
       
   212 	SeqSyncCopyToLocal[0]=EFetchMessage;
       
   213 	SeqSyncCopyToLocal[1]=EInboxDuplicateCopy;
       
   214 	SeqSyncCopyToLocal[2]=EFinished;
       
   215 	}
       
   216 
       
   217 // Set a new session
       
   218 void CImImap4Compound::SetSession(CImImap4Session* aSession)
       
   219 	{
       
   220 	iSession=aSession;
       
   221 	}
       
   222 
       
   223 // Set entry for access to server's database
       
   224 void CImImap4Compound::SetEntry(CMsvServerEntry* aEntry)
       
   225 	{
       
   226 	iEntry=aEntry;
       
   227 	}
       
   228 
       
   229 // Do setentry, leave if there is an error
       
   230 void CImImap4Compound::SetEntryL(const TMsvId aId)
       
   231 	{
       
   232 #ifdef PRINTING
       
   233 	TInt error=iEntry->SetEntry(aId);
       
   234 	if (error)
       
   235 		iSession->LogText(_L8("SetEntryL(%x) returned %d"),aId,error);
       
   236 	User::LeaveIfError(error);
       
   237 #else
       
   238 	User::LeaveIfError(iEntry->SetEntry(aId));
       
   239 #endif
       
   240 	}
       
   241 
       
   242 
       
   243 // Called when async child completes
       
   244 void CImImap4Compound::DoRunL()
       
   245 	{
       
   246 	DBG((iSession->LogText(_L8("COMPOUND dorunl, step %d, status=%d"),iStep,iStatus.Int())));
       
   247 
       
   248 	// Are we still connected? Worth checking...
       
   249 	if (!iSession->Connected())
       
   250 		{
       
   251 		Complete(KErrDisconnected);
       
   252 		return;
       
   253 		}
       
   254 
       
   255 	// Any error from last operation?
       
   256 	if (iStep>0 && iStatus.Int()!=KErrNone)
       
   257 		{
       
   258 		switch(iSequence[iStep-1])
       
   259 			{
       
   260 		// If we get KErrIMAPNO from a selection state, we need to report this as KErrNotFound
       
   261 		case ESelectSourceMailboxRW:
       
   262 		case ESelectSourceMailboxRO:
       
   263 		case ESelectDestinationMailboxRW:
       
   264 		case ESelectDestinationMailboxRO:
       
   265 		case ESelectInbox:
       
   266 			if (iStatus.Int()==KErrIMAPNO)
       
   267 				{
       
   268 				Complete(KErrNotFound);
       
   269 				break;
       
   270 				}
       
   271 
       
   272 			// Fall through
       
   273 
       
   274 		default:
       
   275 			// Complete with this error
       
   276 			Complete(iStatus.Int());
       
   277 			break;
       
   278 			}
       
   279 
       
   280 		// Reset step (shouldn't really be necessary, but it looks neat!)
       
   281 		iStep=0;
       
   282 		return;
       
   283 		}
       
   284 
       
   285 	while (!IsActive() && !DoRunLoopL())
       
   286 		{
       
   287 		// do nothing in the body of this
       
   288 		}
       
   289 	}
       
   290 
       
   291 // Called when async child completes
       
   292 TBool CImImap4Compound::DoRunLoopL()
       
   293 	{
       
   294         DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): step to execute: %d"), iSequence[iStep])));
       
   295 
       
   296 	switch(iSequence[iStep++])
       
   297 		{
       
   298 	case EFinished:
       
   299 		// All done
       
   300 		DBG((iSession->LogText(_L8("COMPOUND finished"))));
       
   301 
       
   302 		Complete(KErrNone);
       
   303 		iStep=0;
       
   304 		return ETrue;
       
   305 
       
   306 	case ESelectSourceMailboxRW:
       
   307 		iSession->Select(iStatus,iSourceFolder,ETrue);
       
   308 		break;
       
   309 
       
   310 	case ESelectSourceMailboxRO:
       
   311 		iSession->Select(iStatus,iSourceFolder,EFalse);
       
   312 		break;
       
   313 
       
   314 	case ESelectDestinationMailboxRW:
       
   315 		iSession->Select(iStatus,iDestinationFolder,ETrue);
       
   316 		break;
       
   317 
       
   318 	case ESelectDestinationMailboxRO:
       
   319 		iSession->Select(iStatus,iDestinationFolder,EFalse);
       
   320 		break;
       
   321 
       
   322 	case ESelectInbox:
       
   323 		{
       
   324 		// Selecting inbox before starting IDLE command
       
   325 		if (iSession->ImapIdleSupported()==EFalse || iIdleBeforeCommand==EFalse || iIdleBeforeFirstPopulate == EFalse || iMsgCount > 0)
       
   326 			{
       
   327 			return EFalse;
       
   328 			}
       
   329 
       
   330 		TMsvId inbox = iSession->GetInbox();
       
   331                 DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): selecting inbox"))));
       
   332 		iSession->Select(iStatus,inbox,ETrue);
       
   333 		break;
       
   334 		}
       
   335 
       
   336 	case ECreate:
       
   337 		iSession->Create(iStatus,iSource,iLeafName,iFolder);
       
   338 		break;
       
   339 
       
   340 	case ERename:
       
   341 		iSession->Rename(iStatus,iSource,iLeafName);
       
   342 		break;
       
   343 
       
   344 	case EFetchMessage:
       
   345 		{
       
   346 		// Don't fetch the message if it is marked for delete
       
   347 		SetEntryL(iSource);
       
   348 
       
   349 		TMsvEmailEntry entry = static_cast<TMsvEmailEntry> (iEntry->Entry()); 
       
   350 		
       
   351 		if (((TMsvEmailEntry)iEntry->Entry()).DisconnectedOperation() == EDisconnectedDeleteOperation)
       
   352 			return EFalse;
       
   353 
       
   354 		// Don't attempt to fetch the message if it has either been fully or partially downloaded, unless this is a populate command.
       
   355         if ( entry.Complete() && entry.PartialDownloaded() && !iPopulateCommand )
       
   356    			return EFalse;
       
   357 
       
   358 		// We fetch to the mirror in all cases
       
   359                 DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): fetching message"))));
       
   360 		iSession->FetchBody(iStatus,iSource,iGetPartialMailInfo);
       
   361 		
       
   362 		break;
       
   363 		}
       
   364 
       
   365 	case ECopyMessage:
       
   366 		if (iSequence==SeqCopyWithinService || iSequence==SeqMoveWithinService)
       
   367 			{
       
   368 			if (iSelectionStillToCopy-->0) 
       
   369 				{
       
   370 				 // Copy all messages before moving onto next step.
       
   371 				iSession->Copy(iStatus,(*iSourceSel)[iSelectionStillToCopy],iDestinationFolder,ETrue);
       
   372 				if (iSelectionStillToCopy>0)
       
   373 					iStep--; // still copying.
       
   374 				}
       
   375 			}
       
   376 		else
       
   377 			iSession->Copy(iStatus,iSource,iDestinationFolder,ETrue);
       
   378 		break;
       
   379 
       
   380 	case EAppendMessage:
       
   381 		iSession->Append(iStatus,iSource,iDestinationFolder);
       
   382 		break;
       
   383 
       
   384 	case EDeleteMessage:
       
   385 		// Deletes a message remotely
       
   386 		if (iSequence==SeqMoveWithinService && iSession->CommandFailure()==KErrIMAPNO)
       
   387 			{
       
   388 			DBG((iSession->LogText(_L8("Copy failed, Cancelling Delete"))));
       
   389 			// Copy failed, so do not continue with delete.
       
   390 			return EFalse;
       
   391 			}
       
   392 		
       
   393 		if (iSelectionStillToDelete>1)
       
   394 			iSession->Delete(iStatus,*iSourceSel);
       
   395 		else
       
   396 			iSession->Delete(iStatus,iSource);
       
   397 		iSelectionStillToDelete=0;
       
   398 		break;
       
   399 
       
   400 	case EDeleteLocalMessage:
       
   401 		// Deletes a message locally: only for messages not within the service
       
   402 		iSession->DeleteMessageL(iSource);
       
   403 
       
   404 		// As this is an instant operation, loop
       
   405 		return EFalse;
       
   406 
       
   407 	case EDeleteAllMessages:
       
   408 		// Deletes all messages/folder (must have no subfolders)
       
   409 		iSession->DeleteAllMessagesL(iStatus);
       
   410 		break;
       
   411 
       
   412 	case EDeleteFolder:
       
   413 		// Delete the folder
       
   414 		iSession->Delete(iStatus,iSourceFolder);
       
   415 		break;
       
   416 
       
   417 	case ENewSyncFolder:
       
   418 		// New only sync.
       
   419 
       
   420 		// if the current folder hasn't actually changed then don't
       
   421 		// bother with the Sync
       
   422 		if (!iSession->FolderChanged())
       
   423 			return EFalse;
       
   424 		
       
   425 		// This used to do just that, new only messages, but it causes a lot of problems 
       
   426 		// with sync limits, as for that to work deletes need to be taken into account also.
       
   427 		// This will fix that.
       
   428                 DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): ESyncNewFolder: synchronising"))));
       
   429 		iSession->Synchronise(iStatus,EFalse);
       
   430 		break;
       
   431 
       
   432 	case ESyncFolder:
       
   433 		// Full sync
       
   434                 DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): ESyncFolder: synchronising"))));
       
   435 		iSession->Synchronise(iStatus,EFalse);
       
   436 		break;
       
   437 
       
   438 	case ECloseFolderWithoutExpunge:
       
   439 		// Close current folder
       
   440 		iSession->Close(iStatus,EFalse);
       
   441 		break;
       
   442 
       
   443 	case EInboxDuplicateCopy:
       
   444 	case EInboxDuplicateMove:
       
   445 		{
       
   446 		// SJM: if we asked to fetch to the mirror then we can skip
       
   447 		// this stage
       
   448 		if (iDestinationFolder == KMsvNullIndexEntryId)
       
   449 			{
       
   450 			return EFalse;
       
   451 			}
       
   452 		
       
   453 		// Move the message to the destination (the local inbox) then duplicate it
       
   454 		// back to the original folder for the mirror.
       
   455 		iEntry->SetEntry(iSource);
       
   456 		TMsvId sourcefolder=iEntry->Entry().Parent();
       
   457 
       
   458 		// Do the move & copy back structure: we update iSource here as the message
       
   459 		// in the mirror is actually a recreated one with a new TMsvId. We may want
       
   460 		// to delete this (if we're doing a MoveToLocal, for example) and so we need
       
   461 		// the correct TMsvId
       
   462 		
       
   463 #if 1
       
   464 		// always copy so that on a move the delete happens on the original correctly
       
   465 		iSession->CopyMessage(iStatus,sourcefolder,iSource,iDestinationFolder,
       
   466 							  &iSource,EFalse);
       
   467 #else
       
   468 		//DS - Added the iSequence[iStep]==EInboxDuplicateMove to represent whether or not
       
   469 		//to remove the original (i.e. copy or move).
       
   470 		iSession->CopyMessage(iStatus,sourcefolder,iSource,iDestinationFolder,
       
   471 							  &iSource,iSequence[iStep-1]==EInboxDuplicateMove);
       
   472 #endif
       
   473 		break;
       
   474 		}
       
   475 
       
   476 	case EStartIdle:
       
   477 		 // if there are more messages(iMsgCount) to populate don't go to IDLE state.
       
   478 		if (iSession->ImapIdleSupported()==EFalse || iIdleBeforeCommand==EFalse || iIdleBeforeFirstPopulate == EFalse || iMsgCount > 0)
       
   479 			{
       
   480 			return EFalse;
       
   481 			}
       
   482                 DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStartIdle: calling StartIdle()"))));
       
   483         iIdleBeforeFirstPopulate = EFalse;
       
   484 		iSession->StartIdle(iStatus);
       
   485 		break;
       
   486 
       
   487 	case EStopIdle:
       
   488 		if (iSession->ImapIdleSupported()==EFalse || iSession->IsIdling()==EFalse)
       
   489 			{
       
   490                         DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStopIdle: not idling or waitng for idle"))));
       
   491 			iIdleBeforeCommand = EFalse;
       
   492 		
       
   493 			// If last message being fetched , then should start IDLE after that.
       
   494 			if (iMsgCount == 1 )
       
   495 				{
       
   496 				iIdleBeforeCommand = ETrue;	
       
   497 				}
       
   498 
       
   499 			return EFalse;
       
   500 			}
       
   501 		
       
   502  		iIdleBeforeFirstPopulate = ETrue;//Are we "IDLE" before first populate..
       
   503 		iIdleBeforeCommand = ETrue;
       
   504                 DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStopIdle: Calling StopIdle()"))));
       
   505 		iSession->StopIdle(iStatus);
       
   506 		break;
       
   507 
       
   508 	default:
       
   509 		gPanic(EUnknownState);
       
   510 		return ETrue;
       
   511 		}
       
   512 
       
   513 	// Next step in sequence...
       
   514         DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): Setting active"))));
       
   515 	SetActive();
       
   516 	return EFalse;
       
   517 	}
       
   518 
       
   519 // Called when parent wants to cancel us
       
   520 void CImImap4Compound::DoCancel()
       
   521 	{
       
   522 	DBG((iSession->LogText(_L8("CImImap4Compound::DoCancel()"))));
       
   523 
       
   524 	// Cancel any session object we're using
       
   525 	switch( iSequence[iStep-1] )
       
   526 		{
       
   527 	case EStopIdle:
       
   528 	case ESelectSourceMailboxRO:
       
   529 	case EFetchMessage:
       
   530 	case EInboxDuplicateCopy:
       
   531 	case ESelectInbox:
       
   532 	case EStartIdle:
       
   533 		{
       
   534 		TRAP_IGNORE(iSession->CancelAndIdleL(iIdleBeforeFirstPopulate));
       
   535 		} break;
       
   536 		
       
   537 	default:
       
   538 		iSession->Cancel();
       
   539 		}
       
   540 
       
   541 	iIdleBeforeFirstPopulate = EFalse;
       
   542 	iMsgCount = 0;
       
   543 	// ...and parent
       
   544 	CMsgActive::DoCancel();
       
   545 	}
       
   546 
       
   547 // Store an offline operation in the correct place
       
   548 TMsvId CImImap4Compound::FindFolderL(const TMsvId aMessage)
       
   549 	{
       
   550 	DBG((iSession->LogText(_L8("FindFolderL(%x)"),aMessage)));
       
   551 
       
   552 	// Find folder that encloses this message (has Mailbox flag set), or service,
       
   553 	// whichever we find first
       
   554 	SetEntryL(aMessage);
       
   555 	TMsvEmailEntry entry;
       
   556 	do
       
   557 		{
       
   558 		// Visit this entry
       
   559 		SetEntryL(iEntry->Entry().Parent());
       
   560 		entry=iEntry->Entry();
       
   561 
       
   562 		DBG((iSession->LogText(_L8("  At %x, type=%x, mailbox=%d"),entry.Id(),entry.iType,entry.Mailbox())));
       
   563 
       
   564 		// A folder & a mailbox, or a service?
       
   565 		if (entry.iType==KUidMsvFolderEntry &&
       
   566 			entry.Mailbox())
       
   567 			{
       
   568 			// This'll do!
       
   569 			return(entry.Id());
       
   570 			}
       
   571 		}
       
   572 	while(iEntry->Entry().iType!=KUidMsvServiceEntry && entry.Id()!=KMsvRootIndexEntryId);
       
   573 
       
   574 	DBG((iSession->LogText(_L8("  Failed"))));
       
   575 
       
   576 	return(NULL);
       
   577 	}
       
   578 
       
   579 void CImImap4Compound::GenericCopyL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination, TInt* aSequence)
       
   580 	{
       
   581         DBG((iSession->LogText(_L8("CImImap4Compound::GenericCopyL()"))));
       
   582  	Queue(aStatus);
       
   583 
       
   584 	// Save parameters
       
   585 	iSource=aSource;
       
   586 	iDestinationFolder=aDestination;
       
   587 	iSourceFolder=FindFolderL(iSource);
       
   588 	iMessageSelection=iSelectionStillToCopy=iSelectionStillToDelete=-1;
       
   589 
       
   590 	// Find the offending source folder
       
   591 	if (iSourceFolder == NULL &&
       
   592 		aSequence != SeqMoveFromLocal && aSequence != SeqCopyFromLocal)
       
   593 		{
       
   594 		Complete(KErrNotFound);
       
   595 		return;
       
   596 		}
       
   597 
       
   598 	// Select it
       
   599 	iStep=0;
       
   600 	iSequence=aSequence;
       
   601 	DoRunL();
       
   602 	}
       
   603 
       
   604 void CImImap4Compound::GenericCopyL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination, TInt* aSequence)
       
   605 	{
       
   606 	DBG((iSession->LogText(_L8("CImImap4Compound::GenericCopyL()"))));
       
   607  	Queue(aStatus);
       
   608 
       
   609 	// Save parameters
       
   610 	iSource=aSourceSel[0];
       
   611 	delete iSourceSel;
       
   612 	iSourceSel = NULL;
       
   613 	iSourceSel=aSourceSel.CopyL();
       
   614 	iDestinationFolder=aDestination;
       
   615 	iMessageSelection=iSelectionStillToCopy=iSelectionStillToDelete=aSourceSel.Count();
       
   616 
       
   617 	// Check that selection elements are contiguous. Just call Copy on contiguous selections.
       
   618 	
       
   619 	iSourceFolder=FindFolderL((*iSourceSel)[iSelectionStillToCopy-1]);
       
   620 
       
   621 	// Find the offending source folder
       
   622 	if (iSourceFolder == NULL &&
       
   623 		aSequence != SeqMoveFromLocal && aSequence != SeqCopyFromLocal)
       
   624 		{
       
   625 		Complete(KErrNotFound);
       
   626 		return;
       
   627 		}
       
   628 
       
   629 	// Select it
       
   630 	iStep=0;
       
   631 	iSequence=aSequence;
       
   632 	DoRunL();
       
   633 	}
       
   634 
       
   635 // CopyToLocal
       
   636 void CImImap4Compound::CopyToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   637 	{
       
   638 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyToLocal(%x to %x)"),aSource,aDestination)));
       
   639 
       
   640 	iPopulateCommand=EFalse;
       
   641 	
       
   642 	UpdatePartialMailInfoToDefaults(aDestination);
       
   643 
       
   644 	// Kick off the copy	
       
   645 	GenericCopyL(aStatus,aSource,aDestination,SeqCopyToLocal);		
       
   646 	}
       
   647 
       
   648 void CImImap4Compound::PopulateL(TRequestStatus& aStatus, const TMsvId aSource, TImImap4GetPartialMailInfo aGetPartialMailInfo)
       
   649 	{
       
   650 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Populate(%x,%d)"),aSource,aGetPartialMailInfo.iGetMailBodyParts)));
       
   651 	
       
   652 	iPopulateCommand = ETrue;
       
   653 	// Set options and kick off the copy to ourselves
       
   654 	iGetPartialMailInfo = aGetPartialMailInfo;
       
   655 	GenericCopyL(aStatus,aSource,KMsvNullIndexEntryId,SeqCopyToLocal);
       
   656 	
       
   657 	if(iMsgCount > 0)
       
   658 		{
       
   659 		iMsgCount--;	
       
   660 		}
       
   661 	
       
   662 	}
       
   663 
       
   664 // MoveToLocal
       
   665 void CImImap4Compound::MoveToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   666 	{
       
   667 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveToLocal(%x to %x)"),aSource,aDestination)));
       
   668 
       
   669 
       
   670 	//Partial populate option is implemented only for the populate command. moving a partially
       
   671 	//populated message will delete the unpopulated message from the remote server. UI takes care 
       
   672 	// of notifying this and ask for confirmation whether user still wants to move the message.
       
   673 
       
   674 	iPopulateCommand=EFalse;
       
   675 	
       
   676 	UpdatePartialMailInfoToDefaults(aDestination);
       
   677 
       
   678 	// We can't do a MoveToLocal if the destination is in the service: this possibility
       
   679 	// if filtered out by the things calling us, so we don't have to worry about it here.
       
   680 	// We know the destination is therefore a local folder.
       
   681 	GenericCopyL(aStatus,aSource,aDestination,SeqMoveToLocal);
       
   682 	}
       
   683 
       
   684 // CopyWithinService
       
   685 void CImImap4Compound::CopyWithinServiceL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   686 	{
       
   687 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyWithinService(%x to %x)"),aSource,aDestination)));
       
   688 
       
   689 	GenericCopyL(aStatus,aSource,aDestination,SeqCopyWithinService);
       
   690 	}
       
   691 
       
   692 void CImImap4Compound::CopyWithinServiceL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination)
       
   693 	{
       
   694 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyWithinService(to %x)"),aDestination)));
       
   695 
       
   696 	GenericCopyL(aStatus,aSourceSel,aDestination,SeqCopyWithinService);
       
   697 	}
       
   698 
       
   699 // MoveWithinService
       
   700 void CImImap4Compound::MoveWithinServiceL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   701 	{
       
   702 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveWithinService(%x to %x)"),aSource,aDestination)));
       
   703 
       
   704 	GenericCopyL(aStatus,aSource,aDestination,SeqMoveWithinService);
       
   705 	}
       
   706 
       
   707 void CImImap4Compound::MoveWithinServiceL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination)
       
   708 	{
       
   709 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveWithinService(to %x)"),aDestination)));
       
   710 
       
   711 	GenericCopyL(aStatus,aSourceSel,aDestination,SeqMoveWithinService);
       
   712 	}
       
   713 
       
   714 // CopyFromLocal
       
   715 void CImImap4Compound::CopyFromLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   716 	{
       
   717 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyFromLocal(%x to %x)"),aSource,aDestination)));
       
   718 
       
   719 	GenericCopyL(aStatus,aSource,aDestination,SeqCopyFromLocal);
       
   720 	}
       
   721 
       
   722 // MoveFromLocal
       
   723 void CImImap4Compound::MoveFromLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   724 	{
       
   725 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveFromLocal(%x to %x)"),aSource,aDestination)));
       
   726 
       
   727 	GenericCopyL(aStatus,aSource,aDestination,SeqMoveFromLocal);
       
   728 	}
       
   729 
       
   730 // SyncCopyToLocal
       
   731 void CImImap4Compound::SyncCopyToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
       
   732 	{
       
   733 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND SyncCopyToLocal(%x to %x)"),aSource,aDestination)));
       
   734 
       
   735 	iPopulateCommand=EFalse;
       
   736 	
       
   737 	UpdatePartialMailInfoToDefaults(aDestination);
       
   738 
       
   739 	// Kick off the copy	
       
   740 	GenericCopyL(aStatus,aSource,aDestination,SeqSyncCopyToLocal);		
       
   741 	}
       
   742 
       
   743 // Delete
       
   744 void CImImap4Compound::DeleteL(TRequestStatus& aStatus, const TMsvId aSource)
       
   745 	{
       
   746 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Delete(%x)"),aSource)));
       
   747 
       
   748 	Queue(aStatus);
       
   749 
       
   750 	// Save parameters
       
   751 	iSource=aSource;
       
   752 	iMessageSelection=iSelectionStillToDelete=1;
       
   753 
       
   754 	// Find the offending source folder
       
   755 	if ((iSourceFolder=FindFolderL(iSource))==NULL)
       
   756 		{
       
   757 		Complete(KErrNotFound);
       
   758 		return;
       
   759 		}
       
   760 
       
   761 	// Select it
       
   762 	iStep=0;
       
   763 	iSequence=SeqDelete;
       
   764 	DoRunL();
       
   765 	}
       
   766 
       
   767 // Delete
       
   768 void CImImap4Compound::DeleteL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel)
       
   769 	{
       
   770 	LOG_COMMANDS( (iSession->LogText(_L8("COMPOUND Delete selection"))));
       
   771 
       
   772 	Queue(aStatus);
       
   773 
       
   774 	// Save parameters
       
   775 	iSource=aSourceSel[0];
       
   776 	delete iSourceSel;
       
   777 	iSourceSel = NULL;
       
   778 	iSourceSel=aSourceSel.CopyL();
       
   779 	iMessageSelection=iSelectionStillToDelete=aSourceSel.Count();
       
   780 
       
   781 	// Find the offending source folder
       
   782 	if ((iSourceFolder=FindFolderL(iSource))==NULL)
       
   783 		{
       
   784 		Complete(KErrNotFound);
       
   785 		return;
       
   786 		}
       
   787 
       
   788 	// Select it
       
   789 	iStep=0;
       
   790 	iSequence=SeqDelete;
       
   791 	DoRunL();
       
   792 	}
       
   793 
       
   794 // Delete all in folder, then folder itself
       
   795 void CImImap4Compound::DeleteFolderL(TRequestStatus& aStatus, const TMsvId aSource)
       
   796 	{
       
   797 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND DeleteFolder(%x)"),aSource)));
       
   798 
       
   799 	Queue(aStatus);
       
   800 
       
   801 	// Save parameters
       
   802 	iSourceFolder=aSource;
       
   803 	iSequence=SeqDeleteFolder;
       
   804 
       
   805 	// The folder might be a mailbox (in which case it needs selecting, messages
       
   806 	// deleting, closing, then deletion of the folder) or it might be a \Noselect
       
   807 	// folder, which we just delete.
       
   808 	User::LeaveIfError(iEntry->SetEntry(aSource));
       
   809 	TMsvEmailEntry folder=iEntry->Entry();
       
   810 	if (!folder.Mailbox())
       
   811 		{
       
   812 		DBG((iSession->LogText(_L8("Folder is marked \\NoSelect: just delete it"))));
       
   813 
       
   814 		// Skip the first few steps
       
   815 		iStep=2;
       
   816 		}
       
   817 	else
       
   818 		{
       
   819 		DBG((iSession->LogText(_L8("Folder is a mailbox: deleting messages and folder"))));
       
   820 
       
   821 		// Start from folder selection
       
   822 		iStep=0;
       
   823 		}
       
   824 
       
   825 	DoRunL();
       
   826 	}
       
   827 
       
   828 void CImImap4Compound::CreateL(TRequestStatus& aStatus, const TMsvId aParent, const TDesC& aLeafName, const TBool aFolder)
       
   829 	{
       
   830 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Create(%x)"),aParent)));
       
   831 
       
   832 	Queue(aStatus);
       
   833 
       
   834 	iStep=0;
       
   835 	iSequence=SeqCreate;
       
   836 	iSource=aParent;
       
   837 	iLeafName=aLeafName;
       
   838 	iFolder=aFolder;
       
   839 	DoRunL();	
       
   840 	}
       
   841 
       
   842 void CImImap4Compound::RenameL(TRequestStatus& aStatus, const TMsvId aTarget, const TDesC& aNewName)
       
   843 	{
       
   844 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Rename(%x)"),aTarget)));
       
   845 
       
   846 	Queue(aStatus);
       
   847 
       
   848 	iStep=0;
       
   849 	iSequence=SeqRename;
       
   850 	iSource=aTarget;
       
   851 	iLeafName=aNewName;
       
   852 	DoRunL();	
       
   853 	}
       
   854 
       
   855 void CImImap4Compound::SynchroniseL(TRequestStatus& aStatus)
       
   856 	{
       
   857 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Synchronise"))));
       
   858 
       
   859 	Queue(aStatus);
       
   860 
       
   861 	iStep=0;
       
   862 	iSequence=SeqSynchronise;
       
   863 	DoRunL();	
       
   864 	}
       
   865 
       
   866 void CImImap4Compound::SelectL(TRequestStatus& aStatus, const TMsvId aFolder)
       
   867 	{
       
   868 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Select(%x)"),aFolder)));
       
   869 
       
   870 	Queue(aStatus);
       
   871 
       
   872 	iStep=0;
       
   873 	iSequence=SeqSelect;
       
   874 	iSourceFolder=aFolder;
       
   875 	DoRunL();
       
   876 	}
       
   877 
       
   878 void CImImap4Compound::NewOnlySyncL(TRequestStatus& aStatus, const TMsvId aFolder)
       
   879 	{
       
   880 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND NewOnlySync(%x)"),aFolder)));
       
   881 
       
   882 	Queue(aStatus);
       
   883 
       
   884 	if (iSession->ImapIdleSupported())
       
   885 		{
       
   886 		// Igmore sync as Imap Idle is supported
       
   887 		Complete(KErrNone);
       
   888 		return;
       
   889 		}
       
   890 
       
   891 	// Check folder is a mailbox
       
   892 	User::LeaveIfError(iEntry->SetEntry(aFolder));
       
   893 	TMsvEmailEntry mbcheck=iEntry->Entry();
       
   894 	if (!mbcheck.Mailbox())
       
   895 		{
       
   896 		// Not a mailbox, so we can't sync it
       
   897 		Complete(KErrNotSupported);
       
   898 		return;
       
   899 		}
       
   900 
       
   901 	// Select it
       
   902 	iStep=0;
       
   903 	iSequence=SeqNewSync;
       
   904 	iSourceFolder=aFolder;
       
   905 	DoRunL();
       
   906 	}
       
   907 
       
   908 void CImImap4Compound::FullSyncL(TRequestStatus& aStatus, const TMsvId aFolder)
       
   909 	{
       
   910 	LOG_COMMANDS((iSession->LogText(_L8("COMPOUND FullSync(%x)"),aFolder)));
       
   911 
       
   912 	Queue(aStatus);
       
   913 
       
   914 	// Check folder is a mailbox
       
   915 	User::LeaveIfError(iEntry->SetEntry(aFolder));
       
   916 	TMsvEmailEntry mbcheck=iEntry->Entry();
       
   917 	if (!mbcheck.Mailbox())
       
   918 		{
       
   919 		do
       
   920 			{
       
   921 			// Ensure visibility
       
   922 			if (!mbcheck.Visible())
       
   923 				{
       
   924 				mbcheck.SetVisible(ETrue);
       
   925 				User::LeaveIfError(iEntry->ChangeEntryBulk(mbcheck));
       
   926 				}
       
   927 
       
   928 			// Move up one
       
   929 			User::LeaveIfError(iEntry->SetEntry(mbcheck.Parent()));
       
   930 			mbcheck=iEntry->Entry();
       
   931 			}
       
   932 		while(mbcheck.iType!=KUidMsvServiceEntry && mbcheck.Id()!=KMsvRootIndexEntryId);
       
   933 
       
   934 		// Not a mailbox, so we can't sync it
       
   935 		Complete(KErrNone);
       
   936 		return;
       
   937 		}
       
   938 
       
   939 	// Select it
       
   940 	iStep=0;
       
   941 	iSequence=SeqFullSync;
       
   942 	iSourceFolder=aFolder;
       
   943 	DoRunL();
       
   944 	}
       
   945 
       
   946 // Report progress
       
   947 TImap4GenericProgress CImImap4Compound::Progress()
       
   948 	{
       
   949 	// First, ask session (updates byte counts & stuff)
       
   950 	TImap4GenericProgress progress=iSession->Progress();
       
   951 	if (iSequence==SeqDelete || iSequence==SeqCopyWithinService)
       
   952 		{
       
   953 		progress.iMsgsToDo=iMessageSelection;
       
   954 		progress.iMsgsDone=iMessageSelection-iSelectionStillToCopy;
       
   955 		}
       
   956 	else if (iSequence==SeqMoveWithinService)
       
   957 		{
       
   958 		// DEL done in one go in imapsess, 
       
   959 		// just have progress for the COPY part of the MOVE command.
       
   960 		progress.iMsgsToDo=iMessageSelection;
       
   961 		progress.iMsgsDone=iMessageSelection-iSelectionStillToCopy;
       
   962 		}
       
   963 
       
   964 	// don't believe there's any point in modifying the operation
       
   965 	// since it'll be set correctly in the Mtm handler.
       
   966 #if 0
       
   967 	// Now, overlay our current operation (move or copy, at least)
       
   968 	if (iSequence==SeqCopyToLocal || iSequence==SeqCopyWithinService ||
       
   969 		iSequence==SeqCopyFromLocal)
       
   970 		progress.iOperation=TImap4Progress::ECopying;
       
   971 	else if (iSequence==SeqMoveToLocal || iSequence==SeqMoveWithinService ||
       
   972 			 iSequence==SeqMoveFromLocal)
       
   973 		progress.iOperation=TImap4Progress::EMoving;
       
   974 #endif
       
   975 
       
   976 	// Return the modified progress
       
   977 	return(progress);
       
   978 	}
       
   979 
       
   980 void CImImap4Compound::UpdatePartialMailInfoToDefaults(TMsvId aDestination)
       
   981 	{	
       
   982 	iGetPartialMailInfo.iTotalSizeLimit= KMaxTInt;
       
   983 	iGetPartialMailInfo.iBodyTextSizeLimit = KMaxTInt;
       
   984 	iGetPartialMailInfo.iAttachmentSizeLimit = KMaxTInt;
       
   985 	iGetPartialMailInfo.iGetMailBodyParts = EGetImap4EmailBodyTextAndAttachments;		 
       
   986 	iGetPartialMailInfo.iPartialMailOptions=ENoSizeLimits;
       
   987 	iGetPartialMailInfo.iDestinationFolder=aDestination;
       
   988 	}
       
   989 
       
   990 void CImImap4Compound::SetMessageCount(const TInt aCount)
       
   991 	{
       
   992 	iMsgCount = aCount;
       
   993 	}