// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//
#include "cimapcompoundcopytolocal.h"
#include "cimapopfetchbody.h"
#include "cimapsessionconsts.h"
#include "cimapsession.h"
#include "cimapsyncmanager.h"
#include "cimapfolder.h"
#include "cimaplogger.h"
#include "imappaniccodes.h"
#include "cimapfolderinfo.h"
#include <imapset.h>
#include "mobilitytestmtmapi.h"
_LIT8(KMessageDataItem, "+FLAGS");
_LIT8(KDeleteValue, "\\Deleted");
CImapCompoundCopyToLocal::CImapCompoundCopyToLocal(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, TBool aIsMove, const TMsvId aDestination)
: CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings),
iMailStore(aImapMailStore), iIsMove(aIsMove), iDestinationFolderId(aDestination)
{
iPopulateCommand = EFalse;
UpdatePartialMailInfoToDefaults(aDestination);
}
CImapCompoundCopyToLocal::CImapCompoundCopyToLocal(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, TBool aIsMove, const TMsvId aDestination, const TImImap4GetPartialMailInfo& aGetPartialMailInfo)
: CImapCompoundBase(aSyncManager, aServerEntry, aImapSettings),
iMailStore(aImapMailStore), iIsMove(aIsMove), iDestinationFolderId(aDestination), iGetPartialMailInfo(aGetPartialMailInfo)
{
iPopulateCommand = ETrue;
}
CImapCompoundCopyToLocal::~CImapCompoundCopyToLocal()
{
iOutMessageFlagInfo.Close();
delete iSourceSel;
delete iBodyFetcher;
delete iMoveEntry;
}
CImapCompoundCopyToLocal* CImapCompoundCopyToLocal::NewL(CImapSyncManager& aSyncManager,
CMsvServerEntry& aServerEntry,
CImapSettings& aImapSettings,
CImapMailStore& aImapMailStore,
TBool aIsMove,
const CMsvEntrySelection& aSourceSel,
const TMsvId aDestination)
{
CImapCompoundCopyToLocal* self = new (ELeave) CImapCompoundCopyToLocal(aSyncManager, aServerEntry, aImapSettings, aImapMailStore, aIsMove, aDestination);
CleanupStack::PushL(self);
self->ConstructL(aSourceSel);
CleanupStack::Pop(self);
return self;
}
CImapCompoundCopyToLocal* CImapCompoundCopyToLocal::NewL(CImapSyncManager& aSyncManager, CMsvServerEntry& aServerEntry, CImapSettings& aImapSettings, CImapMailStore& aImapMailStore, TBool aIsMove, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination, const TImImap4GetPartialMailInfo& aGetPartialMailInfo)
{
CImapCompoundCopyToLocal* self = new (ELeave) CImapCompoundCopyToLocal(aSyncManager, aServerEntry, aImapSettings, aImapMailStore, aIsMove, aDestination, aGetPartialMailInfo);
CleanupStack::PushL(self);
self->ConstructL(aSourceSel);
CleanupStack::Pop(self);
return self;
}
/**
Secondary construction
*/
void CImapCompoundCopyToLocal::ConstructL(const CMsvEntrySelection& aSourceSel)
{
// Local copy of the selection of messages to copy
iSourceSel=new (ELeave) CMsvEntrySelection;
// Check the source selection for acceptable message types/parts
// Messages True
// Handle Parts True
// Handle Folders False
// Check source True
// Makes a local copy of the source selection in iSourceSel
User::LeaveIfError(CheckSelectionL(aSourceSel, iSourceSel, ETrue, ETrue, EFalse, ETrue));
// Create an Imap Body Fetcher object
iBodyFetcher = CImapOpFetchBody::NewL(iSession, iSyncManager, iServerEntry, iImapSettings, iMailStore);
// initialise progress stats
iMessageSelection = iSelectionStillToCopy = iSourceSel->Count();
iTotalSize = CalculateDownloadSizeL(*iSourceSel);
// Add to the active scheduler
CActiveScheduler::Add(this);
}
void CImapCompoundCopyToLocal::StartOperation(TRequestStatus& aStatus, CImapSession& aSession)
{
iSession = &aSession;
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::StartOperation()");
iNextStep = ESetSourceMailbox;
Queue(aStatus);
CompleteSelf();
}
/**
Handles the compound operation state machine
Sequence of steps:
For each message:
Select source mailbox
Fetch the message to the local mirror
IF copy/move to local service
Copy message to local service
IF move to local service
STORE /deleted flag on remote message
issue EXPUNGE command
delete local copy of the message
@return ETrue if compound operation is completed,
EFalse otherwise.
*/
TBool CImapCompoundCopyToLocal::DoRunLoopL()
{
SetCurrentStep();
switch (iCurrentStep)
{
case ESetSourceMailbox: // synchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(ESetSourceMailbox)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal1); // SELECT source folder
if (iSelectionStillToCopy > 0)
{
if (iStopForMigrate)
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::Stopped for migrate");
iCurrentStep = ESuspendedForMigrate;
iNextStep = ESetSourceMailbox;
Complete(KErrNone);
return ETrue;
}
// decrement iSelectionStillToCopy - it becomes the index in the list
// of the current message to operate on.
--iSelectionStillToCopy;
iCurrentMsgId = (*iSourceSel)[iSelectionStillToCopy];
if (SetSourceFolderL(iCurrentMsgId))
{
// no change in state if folder not acceptable,
// try again with the next message in the selection.
if (iSourceFolderId != NULL && iSourceFolder != NULL)
{
// When iIsMove is EFalse, we still need to have a writable mailbox
// so that the server can update the \Seen message flag duriung FETCH BODY
iNextStep=ESelectSourceMailboxRW;
}
}
else
{
iNextStep=EFetchMessage;
}
}
else
{
// All messages copied..
iNextStep=EFinished;
}
// immediately proceed to the next step
return EFalse;
}
case ESelectSourceMailboxRW: // asynchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(ESelectSourceMailboxRW)");
iSourceFolder->SelectL(iStatus, *iSession);
iNextStep=EFetchMessage;
SetActive();
break;
}
case ESelectSourceMailboxRO: // asynchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(ESelectSourceMailboxRO)");
iSourceFolder->ExamineL(iStatus, *iSession);
iNextStep=EFetchMessage;
SetActive();
break;
}
case EFetchMessage: // asynchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(EFetchMessage)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal2); // FETCHing the message
SetEntryL(iCurrentMsgId);
TMsvEmailEntry entry = static_cast<TMsvEmailEntry> (iServerEntry.Entry());
TBool doFetch(ETrue);
// Don't fetch the message if it is marked for delete
if (entry.DisconnectedOperation() == EDisconnectedDeleteOperation)
{
doFetch = EFalse;
iNextStep = ESetSourceMailbox;
return EFalse;
}
else
{
// Don't attempt to fetch the message if it has either been fully or
// partially downloaded, unless this is a populate command.
if (entry.Complete() && entry.PartialDownloaded() && !iPopulateCommand)
{
doFetch = EFalse;
}
}
if (doFetch)
{
// Fetch the message...
iBodyFetcher->FetchBodyL(iStatus, iCurrentMsgId, iGetPartialMailInfo);
SetActive();
}
// Set next state
if (iDestinationFolderId == KMsvNullIndexEntryId)
{
// Populating/Copying to local mirror. When fetched, proceed to next
// message in the selection
iNextStep=ESetSourceMailbox;
}
else
{
iNextStep=(iIsMove)?EInboxDuplicateMove:EInboxDuplicateCopy;
}
break;
}
case EInboxDuplicateCopy: // asynchronous
case EInboxDuplicateMove: // asynchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(EInboxDuplicate)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal3); // local async copy
SetEntryL(iCurrentMsgId);
iNextStep=ELocalCopyComplete;
// CopyMessage() kicks off an asynchronous copy operation if it succeeds
TInt ret = CopyMessage(iCurrentMsgId, iDestinationFolderId, iIsMove);
if (ret != KErrNone) // Asynchronous copy operation failed to start
{
// Store the error in the message entry
TRAPD(err, MessageErrorL(iCurrentMsgId, ret));
if (err != KErrNone)
{
iProgressErrorCode = err;
}
// Move straight on to next step
iNextStep = ESetSourceMailbox;
return EFalse;
}
break;
}
case ELocalCopyComplete: // synchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(ELocalCopyComplete)");
// The copy to local folder has completed.
CopyCompleteL();
// Delete the source message from the IMAP Service if it is a move operation,
// otherwise proceed to next message in the selection.
iNextStep=(iIsMove)?EDeleteMessage:ESetSourceMailbox;
// straight on to next step...
return EFalse;
}
case EDeleteMessage: // asynchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(EDeleteMessage)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal4); // STORE /deleted flag (move only)
// Deleting a message is a two-stage operation:
// 1. STORE the /deleted flag on the remote server.
// 2.a) EXPUNGE the messages
// or
// 2.b) CLOSE the folder and then SELECT the folder
// 2a) or 2b) used is dependent on the KImap4EmailExpungeFlag in CImImap4Settings.
// we haven't changed the TMsvId of moved messages,
// therefore can just use the original TmsvId to identify the UID.
MarkMessageForDeleteL(iCurrentMsgId);
if (iImapSettings.UseExpunge())
{
iNextStep=EExpunge;
}
else
{
iNextStep=ECloseFolder;
}
SetActive();
break;
}
case EExpunge: // asynchronous
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(EExpunge)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal5); // EXPUNGE
// Issue expunge to delete the message now.
iSession->ExpungeL(iStatus);
// This is the end of a move operation - move to EFetchMessage state
// to check for more messages to move.
iNextStep=ESetSourceMailbox;
SetActive();
break;
}
case ECloseFolder:
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(ECloseFolder)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal6); // CLOSE FOLDER
//Permanently removes all messages that have the deleted flag set
//from the currently selected mailbox
iSession->CloseL(iStatus);
iNextStep=ESelectFolderAfterClose;
SetActive();
break;
}
case ESelectFolderAfterClose:
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(ESelectFolderAfterClose)");
MOBILITY_TEST_MTM_STATE(iImapSettings.ServiceId(), KMobilityTestMtmStateImapCopyToLocal7); // SELECT FOLDER
//Selecting a mailbox so that messages in the mailbox can be accessed.
iSourceFolder->SelectL(iStatus, *iSession);
iNextStep=ESetSourceMailbox;
SetActive();
break;
}
case EFinished:
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::DoRunLoopL(EFinished OK)");
iProgressState = TImap4GenericProgress::EIdle;
Complete(KErrNone);
return ETrue;
}
default:
{
__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundUnexpectedState));
// unexpected state - complete the request
iProgressState = TImap4GenericProgress::EIdle;
return ETrue;
}
} // end of switch (iCurrentStep)
return EFalse;
}
/**
Special form of cancel, which enables message currently being fetched to be resumed.
*/
void CImapCompoundCopyToLocal::CancelEnableResume()
{
iResume = ETrue;
Cancel();
iResume = EFalse;
}
/**
May be called in case of a genuine cancel or a cancel for migrate.
Following a genuine cancel, the compound operation will be deleted.
Following a cancel for migrate, the compound operation will be resumed,
so the iNextState is updated here to ensure the operation is
correctly restarted.
In either case, CMsgActive::DoCancel() is called to complete the
user request with KErrCancel.
Note that if the default CMsgActive::DoComplete() is overridden,
then that must also be modified to handle either case described above.
*/
void CImapCompoundCopyToLocal::DoCancel()
{
__LOG_FORMAT((iSession->LogId(), "CImapCompoundCopyToLocal::DoCancel(iCurrentStep=%d)", iCurrentStep));
switch (iCurrentStep)
{
case ESelectSourceMailboxRW:
{
iSession->Cancel();
iNextStep=ESelectSourceMailboxRW; // (already set up - just need to resume here)
break;
}
case ESelectSourceMailboxRO:
{
iSession->Cancel();
iNextStep=ESelectSourceMailboxRO; // (already set up - just need to resume here)
break;
}
case EFetchMessage:
{
if (iResume)
{
iBodyFetcher->CancelEnableResume();
}
else
{
iBodyFetcher->Cancel();
}
iNextStep=EFetchMessage; // need to re-SELECT folder before resuming fetch
break;
}
case EInboxDuplicateCopy:
case EInboxDuplicateMove:
{
// outstanding request is on CMsvServerEntry
iMoveEntry->Cancel();
// cancel the copy, restart on re-connect
iNextStep=iCurrentStep;
break;
}
case EDeleteMessage:
{
iSession->Cancel();
iNextStep=EDeleteMessage; // need to re-SELECT folder before deleting
break;
}
case EExpunge:
{
iSession->Cancel();
iNextStep=EExpunge; // need to re-SELECT folder before deleting
break;
}
case ECloseFolder:
{
iSession->Cancel();
iNextStep=ECloseFolder;
break;
}
case ESelectFolderAfterClose:
{
iSession->Cancel();
iNextStep=ESelectFolderAfterClose;
break;
}
case EDeleteLocalMessage:
case ESetSourceMailbox:
case ELocalCopyComplete:
case EFinished:
{
// self-completed or no outstanding request.
break;
}
case ESuspendedForMigrate:
default:
{
__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundCancelUnexpectedState));
// attempt to resume from the next message in the array.
iNextStep=ESetSourceMailbox;
break;
}
} // end of switch (iCurrentStep)
if (!iCancelForMigrate)
{
// genuine cancel - update progress
iProgressErrorCode = KErrCancel;
}
CMsgActive::DoCancel();
}
void CImapCompoundCopyToLocal::Progress(TImap4CompoundProgress& aCompoundProgress)
{
if (iPopulateCommand)
{
aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::EPopulate;
}
else
{
if (iIsMove)
{
aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::EMoveToLocal;
}
else
{
aCompoundProgress.iGenericProgress.iOperation = TImap4GenericProgress::ECopyToLocal;
}
}
// Progress through the received selection
aCompoundProgress.iGenericProgress.iTotalSize = iTotalSize;
aCompoundProgress.iGenericProgress.iMsgsToDo = iMessageSelection;
aCompoundProgress.iGenericProgress.iMsgsDone = iMessageSelection - iSelectionStillToCopy;
// current message progress
iBodyFetcher->Progress(aCompoundProgress.iGenericProgress);
// Put error into progress buffer
if( aCompoundProgress.iGenericProgress.iErrorCode == KErrNone )
{
aCompoundProgress.iGenericProgress.iErrorCode = iProgressErrorCode;
}
}
/**
Find the parent folder
@return ETrue if the source folder has changed since the last message operated on
always true on the first call after creation.
@post iSourceFolderId - The TMsvId of the source folder for the message. May be NULL
@post iSourceFolder - CImapFolder pointer for the parent folder. May be NULL.
*/
TBool CImapCompoundCopyToLocal::SetSourceFolderL(const TMsvId aMessage)
{
TMsvId folderId = KMsvNullIndexEntryId;
TMsvId parentFolder = FindFolderL(aMessage);
CImapFolderInfo* selectedFolder = iSession->SelectedFolderInfo();
if(selectedFolder != NULL)
{
folderId = selectedFolder->MsvId() ;
}
if (parentFolder==iSourceFolderId)
{
// Same folder as last message copied.
return EFalse;
}
// otherwise, update to the new folder.
iSourceFolderId = parentFolder;
if (iSourceFolderId!=NULL)
{
iSourceFolder = iSyncManager.GetFolderL(iSourceFolderId);
}
//Check the same INBOX folder is selected before
if (parentFolder== folderId)
{
return EFalse;
}
return ETrue;
}
/**
Updates iGetPartialMailInfo to default values - (fetch whole message and attachments
without limits). This is used for copy/move to local operations (populate operations
uses a user-specified partial mail info object.
@param aDestination - destination folder.
@internalTechnology
*/
void CImapCompoundCopyToLocal::UpdatePartialMailInfoToDefaults(TMsvId aDestination)
{
iGetPartialMailInfo.iTotalSizeLimit= KMaxTInt;
iGetPartialMailInfo.iBodyTextSizeLimit = KMaxTInt;
iGetPartialMailInfo.iAttachmentSizeLimit = KMaxTInt;
iGetPartialMailInfo.iGetMailBodyParts = EGetImap4EmailBodyTextAndAttachments;
iGetPartialMailInfo.iPartialMailOptions=ENoSizeLimits;
iGetPartialMailInfo.iDestinationFolder=aDestination;
}
/**
Copy or move a message to the specified local service folder.
@param aSource The message to copy or move
@param aDestinationFolder The id of the destination folder
@param aRemoveOriginal ETrue if this is a move, EFalse for a copy.
*/
TInt CImapCompoundCopyToLocal::CopyMessage(const TMsvId aSource, const TMsvId aDestinationFolder, const TBool aRemoveOriginal)
{
TRAPD(err,CopyMessageL(aSource, aDestinationFolder, aRemoveOriginal));
if (err!=KErrNone)
{
// park moveentry if it fails to get going
if (iMoveEntry)
{
iMoveEntry->SetEntry(NULL);
}
__LOG_FORMAT((iSession->LogId(), " CopyMessage() failed, err=", err));
}
return err;
}
void CImapCompoundCopyToLocal::CopyMessageL(const TMsvId aSource, const TMsvId aDestinationFolder, const TBool aRemoveOriginal)
{
__LOG_FORMAT((iSession->LogId(), "CImapCompoundCopyToLocal::CopyMessageL(%x (in %x) to %x)", aSource, iSourceFolderId, aDestinationFolder));
// Get a moveentry if we don't already have one
if (!iMoveEntry)
{
// Get a MoveEntry: we need to ask for one as a child of this entry, so
// move it to the root and ask for a child in the local service, which should
// always be there.
SetEntryL(KMsvRootIndexEntryId);
// Get child
iMoveEntry=iServerEntry.NewEntryL(KMsvLocalServiceIndexEntryId);
}
// Do the move, using the iMoveEntry CMsvServerEntry object
SetEntryL(aSource);
User::LeaveIfError(iMoveEntry->SetEntry(iServerEntry.Entry().Parent()));
// Set context to null because the move / copy tries to lock each entry,
// and it will fail if we have it locked already
SetEntryL(KMsvNullIndexEntryId);
aRemoveOriginal?
iMoveEntry->MoveEntryL(aSource,aDestinationFolder,iStatus):
iMoveEntry->CopyEntryL(aSource,aDestinationFolder,iStatus);
if (!IsActive()) SetActive();
}
/**
Called when the copy operation is complete.
Clears the new flag on the message entry just copied/moved.
*/
void CImapCompoundCopyToLocal::CopyCompleteL()
{
// Park the move entry again
User::LeaveIfError(iMoveEntry->SetEntry(NULL));
SetEntryL(iCurrentMsgId);
TMsvEntry entry=iServerEntry.Entry();
entry.SetNew(EFalse);
iServerEntry.ChangeEntry(entry);
}
/**
Marks message specified by aTarget for delete locally,
and issues STORE command to mark it for delete remotely.
Issues an asynchronous request to the CImapSession. SetActive()
must be called after calling this function.
@param aTarget The message to be marked for delete
*/
void CImapCompoundCopyToLocal::MarkMessageForDeleteL(const TMsvId& aTarget)
{
// Move to the entry in question
SetEntryL(aTarget);
// Set deleted flag on this entry
TMsvEmailEntry entry=iServerEntry.Entry();
entry.SetDeletedIMAP4Flag(ETrue);
User::LeaveIfError(iServerEntry.ChangeEntry(entry));
RArray<TUint> uidArray;
CleanupClosePushL(uidArray);
uidArray.AppendL(entry.UID());
HBufC8* uids = CImapSession::CreateSequenceSetLC(uidArray);
iSession->StoreL(iStatus, *uids, KMessageDataItem, KDeleteValue, ETrue, iOutMessageFlagInfo);
CleanupStack::PopAndDestroy(2, &uidArray); // uids, uidArray
}
/**
Handles NO/BAD responses according to current step.
Negative server responses are not fatal - the error is saved in
the message currently being operated on and the state machine pushed
on to process the next message in the requested selection.
@return KErrNone if the error has been handled
Completion error code otherwise.
*/
TInt CImapCompoundCopyToLocal::ProcessNegativeServerResponse()
{
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::ProcessNegativeServerResponse");
TInt err = iStatus.Int();
switch (iCurrentStep)
{
case ESelectSourceMailboxRW:
case ESelectSourceMailboxRO:
case ESelectFolderAfterClose:
{
if (err == KErrImapNo)
{
err = KErrNotFound;
}
} // fall through
case EDeleteMessage:
case EExpunge:
case ECloseFolder:
case EFetchMessage:
{
// save the error with the associated message
TRAP_IGNORE(MessageErrorL(iCurrentMsgId, err));
// Skip to the next message or finish
iNextStep = (iSelectionStillToCopy>0)?ESetSourceMailbox:EFinished;
break;
}
case EInboxDuplicateCopy:
case EInboxDuplicateMove:
case EDeleteLocalMessage:
case ESetSourceMailbox:
case ELocalCopyComplete:
case EFinished:
case ESuspendedForMigrate:
default:
{
// positive error code not expected,
// self-completed states or no outstanding request.
TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundUnexpectedState);
break;
}
} // end of switch (iCurrentStep)
iProgressErrorCode = err;
return KErrNone;
}
/**
Called to resume the compound operation following a bearer migration.
*/
void CImapCompoundCopyToLocal::ResumeOperationL(TRequestStatus& aStatus, CImapSession& aSession)
{
iSession = &aSession;
__LOG_TEXT(iSession->LogId(), "CImapCompoundCopyToLocal::Resuming");
__ASSERT_DEBUG(iCurrentStep==ESuspendedForMigrate, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundUnexpectedState));
iStopForMigrate = EFalse;
// Switch on next step - some "next steps" require a SELEECT first...
switch (iNextStep)
{
case ESetSourceMailbox: // clean start on the next message in the array
case ESelectSourceMailboxRW: // current message already selected... continue...
case ESelectSourceMailboxRO:
case ESelectFolderAfterClose:
{
// just return to the main state machine
CompleteSelf();
break;
}
case EFetchMessage:
case EDeleteMessage:
case EExpunge:
case ECloseFolder:
case EInboxDuplicateCopy:
case EInboxDuplicateMove: // need to be selected to delete the message if this is a move
{
// select the source folder before returning to main state machine
iSourceFolder->SelectL(iStatus, *iSession);
iCurrentStep = ESelectSourceMailboxRW;
SetActive();
break;
}
case ELocalCopyComplete:
case EDeleteLocalMessage:
case EFinished:
// not expected
default:
{
__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::ECopyToLocalCompoundCancelUnexpectedState));
// abandon the compound operation
iNextStep=EFinished;
CompleteSelf();
break;
}
} // end switch (iNextStep)
Queue(aStatus);
}
/**
Removes matching messages from the array of messages to be fetched.
This is called when a populate or copy to local operation is requested while
a background sync operation is in progress. It is used to remove
messages from the array of messages to be auto-fetched that are going to
be fetched due to the populate request.
Note that this does not impact messages that have already been auto-fetched, or
messages that are in the process of being fetched as this function is called.
@param aSelection - the selection of messages to be removed from the list
*/
void CImapCompoundCopyToLocal::RemoveFromSelection(CMsvEntrySelection& aDeleteSel)
{
// Check each entry in the delete selection...
TInt source;
for (TInt del=0;del<aDeleteSel.Count();++del)
{
source = iSourceSel->Find(aDeleteSel[del]);
if (source!=KErrNotFound)
{
if (source < iSelectionStillToCopy)
{
// message has not yet been auto-fetched, remove it from the list.
// note that iSelection starts at iSourceSel.Count() and counts down...
iSourceSel->Delete(source);
// update the fetch index.
--iSelectionStillToCopy;
}
// otherwise message has already been auto-fetched. No action necessary.
}
}
}