--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/imapservermtm/src/IMAPCOMP.CPP Mon May 03 12:29:07 2010 +0300
@@ -0,0 +1,993 @@
+// Copyright (c) 1998-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:
+// IMAP4 compound operations
+// This class wraps up operations which require more than one IMAP command
+// (the imapsess.cpp class deals with single IMAP commands generally),
+// allowing increased neatness in the higher classes.
+//
+//
+
+#include <e32base.h>
+#include <e32cons.h>
+#include <mentact.h>
+#include "impspan.h"
+#include "imapsess.h"
+#include <imapset.h>
+#include "imapcomp.h"
+
+#ifdef _DEBUG
+#define LOG_COMMANDS(a) a
+#define DBG(a) a
+#define PRINTING
+#else
+#define LOG_COMMANDS(a)
+#define DBG(a)
+#undef PRINTING
+#endif
+
+// Priority of MsgActive object
+const TInt ECompoundPriority=1;
+
+
+// Operations that can be chained
+enum
+ {
+ EFinished=0,
+ ESelectSourceMailboxRW,
+ ESelectSourceMailboxRO,
+ ESelectDestinationMailboxRW,
+ ESelectDestinationMailboxRO,
+ EFetchMessage,
+ ECopyMessage,
+ EAppendMessage,
+ EDeleteMessage,
+ EDeleteLocalMessage,
+ EDeleteAllMessages,
+ ENewSyncFolder,
+ ESyncFolder,
+ EInboxDuplicateMove,
+ EInboxDuplicateCopy,
+ ECloseFolderWithoutExpunge,
+ EDeleteFolder,
+ EStartIdle,
+ EStopIdle,
+ ECreate,
+ ERename,
+ ESelectInbox
+ };
+
+//DS - Split EInboxDuplicate into EInboxDuplicateCopy and EInboxDuplicateMove to allow
+//use of either CMsvServerEntry::CopyL or MoveL depending on what operation the user
+//is attempting.
+
+CImImap4Compound::CImImap4Compound():CMsgActive(ECompoundPriority)
+ {
+ __DECLARE_NAME(_S("CImImap4Compound"));
+ }
+
+CImImap4Compound::~CImImap4Compound()
+ {
+ // We don't delete iSession as we don't own it, we were just passed it to use.
+ delete iSourceSel;
+ }
+
+CImImap4Compound* CImImap4Compound::NewL(CImImap4Session* aSession)
+ {
+ CImImap4Compound* self=new (ELeave) CImImap4Compound();
+ CleanupStack::PushL(self);
+
+ // Non-trivial constructor
+ self->ConstructL(aSession);
+ CleanupStack::Pop();
+ return self;
+ }
+
+// The non-trivial constructor
+void CImImap4Compound::ConstructL(CImImap4Session* aSession)
+ {
+ // Save session & entry
+ iSession=aSession;
+
+ iPopulateCommand=EFalse;
+ iIdleBeforeFirstPopulate = EFalse;
+ // We're an active object...
+ CActiveScheduler::Add(this);
+
+ // Initialise static sequences. There must be a better way
+ // than this without causing complaints :-(
+ SeqCopyToLocal[0]=EStopIdle;
+ SeqCopyToLocal[1]=ESelectSourceMailboxRO;
+ SeqCopyToLocal[2]=EFetchMessage;
+ SeqCopyToLocal[3]=EInboxDuplicateCopy;
+ SeqCopyToLocal[4]=ESelectInbox;
+ SeqCopyToLocal[5]=EStartIdle;
+ SeqCopyToLocal[6]=EFinished;
+
+ SeqMoveToLocal[0]=EStopIdle;
+ SeqMoveToLocal[1]=ESelectSourceMailboxRW;
+ SeqMoveToLocal[2]=EFetchMessage;
+ SeqMoveToLocal[3]=EInboxDuplicateMove;
+ SeqMoveToLocal[4]=EDeleteMessage;
+ SeqMoveToLocal[5]=ESelectInbox;
+ SeqMoveToLocal[6]=EStartIdle;
+ SeqMoveToLocal[7]=EFinished;
+
+ SeqCopyWithinService[0]=EStopIdle;
+ SeqCopyWithinService[1]=ESelectSourceMailboxRO;
+ SeqCopyWithinService[2]=ECopyMessage;
+ SeqCopyWithinService[3]=ESelectDestinationMailboxRO;
+ SeqCopyWithinService[4]=ENewSyncFolder;
+ SeqCopyWithinService[5]=ESelectInbox;
+ SeqCopyWithinService[6]=EStartIdle;
+ SeqCopyWithinService[7]=EFinished;
+
+ SeqMoveWithinService[0]=EStopIdle;
+ SeqMoveWithinService[1]=ESelectSourceMailboxRW;
+ SeqMoveWithinService[2]=ECopyMessage;
+ SeqMoveWithinService[3]=EDeleteMessage;
+ SeqMoveWithinService[4]=ESelectDestinationMailboxRO;
+ SeqMoveWithinService[5]=ENewSyncFolder;
+ SeqMoveWithinService[6]=ESelectInbox;
+ SeqMoveWithinService[7]=EStartIdle;
+ SeqMoveWithinService[8]=EFinished;
+
+ SeqCopyFromLocal[0]=EAppendMessage;
+ SeqCopyFromLocal[1]=ESelectDestinationMailboxRO;
+ SeqCopyFromLocal[2]=ENewSyncFolder;
+ SeqCopyFromLocal[3]=EFinished;
+
+ SeqMoveFromLocal[0]=EStopIdle;
+ SeqMoveFromLocal[1]=EAppendMessage;
+ SeqMoveFromLocal[2]=EDeleteLocalMessage;
+ SeqMoveFromLocal[3]=ESelectDestinationMailboxRO;
+ SeqMoveFromLocal[4]=ENewSyncFolder;
+ SeqMoveFromLocal[5]=ESelectInbox;
+ SeqMoveFromLocal[6]=EStartIdle;
+ SeqMoveFromLocal[7]=EFinished;
+
+ SeqDelete[0]=EStopIdle;
+ SeqDelete[1]=ESelectSourceMailboxRW;
+ SeqDelete[2]=EDeleteMessage; // Explicit expunge
+ SeqDelete[3]=ESelectInbox;
+ SeqDelete[4]=EStartIdle;
+ SeqDelete[5]=EFinished;
+
+ SeqDeleteFolder[0]=EStopIdle;
+ SeqDeleteFolder[1]=ESelectSourceMailboxRW;
+ SeqDeleteFolder[2]=EDeleteAllMessages;
+ SeqDeleteFolder[3]=ECloseFolderWithoutExpunge;
+ SeqDeleteFolder[4]=EDeleteFolder;
+ SeqDeleteFolder[5]=ESelectInbox;
+ SeqDeleteFolder[6]=EStartIdle;
+ SeqDeleteFolder[7]=EFinished;
+
+ SeqNewSync[0]=EStopIdle;
+ SeqNewSync[1]=ESelectSourceMailboxRW;
+ SeqNewSync[2]=ENewSyncFolder;
+ SeqNewSync[3]=ESelectInbox;
+ SeqNewSync[4]=EStartIdle;
+ SeqNewSync[5]=EFinished;
+
+ SeqFullSync[0]=EStopIdle;
+ SeqFullSync[1]=ESelectSourceMailboxRW;
+ SeqFullSync[2]=ESyncFolder;
+ SeqFullSync[3]=ESelectInbox;
+ SeqFullSync[4]=EStartIdle;
+ SeqFullSync[5]=EFinished;
+
+ SeqSelect[0]=EStopIdle;
+ SeqSelect[1]=ESelectSourceMailboxRW;
+ SeqSelect[2]=EFinished;
+
+ SeqSynchronise[0]=EStopIdle;
+ SeqSynchronise[1]=ESyncFolder;
+ SeqSynchronise[2]=ESelectInbox;
+ SeqSynchronise[3]=EStartIdle;
+ SeqSynchronise[4]=EFinished;
+
+ SeqCreate[0]=EStopIdle;
+ SeqCreate[1]=ECreate;
+ SeqCreate[2]=ESelectInbox;
+ SeqCreate[3]=EStartIdle;
+ SeqCreate[4]=EFinished;
+
+ SeqRename[0]=EStopIdle;
+ SeqRename[1]=ERename;
+ SeqRename[2]=ESelectInbox;
+ SeqRename[3]=EStartIdle;
+ SeqRename[4]=EFinished;
+
+ // operations when done as part of a synchronisation process
+ SeqSyncCopyToLocal[0]=EFetchMessage;
+ SeqSyncCopyToLocal[1]=EInboxDuplicateCopy;
+ SeqSyncCopyToLocal[2]=EFinished;
+ }
+
+// Set a new session
+void CImImap4Compound::SetSession(CImImap4Session* aSession)
+ {
+ iSession=aSession;
+ }
+
+// Set entry for access to server's database
+void CImImap4Compound::SetEntry(CMsvServerEntry* aEntry)
+ {
+ iEntry=aEntry;
+ }
+
+// Do setentry, leave if there is an error
+void CImImap4Compound::SetEntryL(const TMsvId aId)
+ {
+#ifdef PRINTING
+ TInt error=iEntry->SetEntry(aId);
+ if (error)
+ iSession->LogText(_L8("SetEntryL(%x) returned %d"),aId,error);
+ User::LeaveIfError(error);
+#else
+ User::LeaveIfError(iEntry->SetEntry(aId));
+#endif
+ }
+
+
+// Called when async child completes
+void CImImap4Compound::DoRunL()
+ {
+ DBG((iSession->LogText(_L8("COMPOUND dorunl, step %d, status=%d"),iStep,iStatus.Int())));
+
+ // Are we still connected? Worth checking...
+ if (!iSession->Connected())
+ {
+ Complete(KErrDisconnected);
+ return;
+ }
+
+ // Any error from last operation?
+ if (iStep>0 && iStatus.Int()!=KErrNone)
+ {
+ switch(iSequence[iStep-1])
+ {
+ // If we get KErrIMAPNO from a selection state, we need to report this as KErrNotFound
+ case ESelectSourceMailboxRW:
+ case ESelectSourceMailboxRO:
+ case ESelectDestinationMailboxRW:
+ case ESelectDestinationMailboxRO:
+ case ESelectInbox:
+ if (iStatus.Int()==KErrIMAPNO)
+ {
+ Complete(KErrNotFound);
+ break;
+ }
+
+ // Fall through
+
+ default:
+ // Complete with this error
+ Complete(iStatus.Int());
+ break;
+ }
+
+ // Reset step (shouldn't really be necessary, but it looks neat!)
+ iStep=0;
+ return;
+ }
+
+ while (!IsActive() && !DoRunLoopL())
+ {
+ // do nothing in the body of this
+ }
+ }
+
+// Called when async child completes
+TBool CImImap4Compound::DoRunLoopL()
+ {
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): step to execute: %d"), iSequence[iStep])));
+
+ switch(iSequence[iStep++])
+ {
+ case EFinished:
+ // All done
+ DBG((iSession->LogText(_L8("COMPOUND finished"))));
+
+ Complete(KErrNone);
+ iStep=0;
+ return ETrue;
+
+ case ESelectSourceMailboxRW:
+ iSession->Select(iStatus,iSourceFolder,ETrue);
+ break;
+
+ case ESelectSourceMailboxRO:
+ iSession->Select(iStatus,iSourceFolder,EFalse);
+ break;
+
+ case ESelectDestinationMailboxRW:
+ iSession->Select(iStatus,iDestinationFolder,ETrue);
+ break;
+
+ case ESelectDestinationMailboxRO:
+ iSession->Select(iStatus,iDestinationFolder,EFalse);
+ break;
+
+ case ESelectInbox:
+ {
+ // Selecting inbox before starting IDLE command
+ if (iSession->ImapIdleSupported()==EFalse || iIdleBeforeCommand==EFalse || iIdleBeforeFirstPopulate == EFalse || iMsgCount > 0)
+ {
+ return EFalse;
+ }
+
+ TMsvId inbox = iSession->GetInbox();
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): selecting inbox"))));
+ iSession->Select(iStatus,inbox,ETrue);
+ break;
+ }
+
+ case ECreate:
+ iSession->Create(iStatus,iSource,iLeafName,iFolder);
+ break;
+
+ case ERename:
+ iSession->Rename(iStatus,iSource,iLeafName);
+ break;
+
+ case EFetchMessage:
+ {
+ // Don't fetch the message if it is marked for delete
+ SetEntryL(iSource);
+
+ TMsvEmailEntry entry = static_cast<TMsvEmailEntry> (iEntry->Entry());
+
+ if (((TMsvEmailEntry)iEntry->Entry()).DisconnectedOperation() == EDisconnectedDeleteOperation)
+ return EFalse;
+
+ // 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 )
+ return EFalse;
+
+ // We fetch to the mirror in all cases
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): fetching message"))));
+ iSession->FetchBody(iStatus,iSource,iGetPartialMailInfo);
+
+ break;
+ }
+
+ case ECopyMessage:
+ if (iSequence==SeqCopyWithinService || iSequence==SeqMoveWithinService)
+ {
+ if (iSelectionStillToCopy-->0)
+ {
+ // Copy all messages before moving onto next step.
+ iSession->Copy(iStatus,(*iSourceSel)[iSelectionStillToCopy],iDestinationFolder,ETrue);
+ if (iSelectionStillToCopy>0)
+ iStep--; // still copying.
+ }
+ }
+ else
+ iSession->Copy(iStatus,iSource,iDestinationFolder,ETrue);
+ break;
+
+ case EAppendMessage:
+ iSession->Append(iStatus,iSource,iDestinationFolder);
+ break;
+
+ case EDeleteMessage:
+ // Deletes a message remotely
+ if (iSequence==SeqMoveWithinService && iSession->CommandFailure()==KErrIMAPNO)
+ {
+ DBG((iSession->LogText(_L8("Copy failed, Cancelling Delete"))));
+ // Copy failed, so do not continue with delete.
+ return EFalse;
+ }
+
+ if (iSelectionStillToDelete>1)
+ iSession->Delete(iStatus,*iSourceSel);
+ else
+ iSession->Delete(iStatus,iSource);
+ iSelectionStillToDelete=0;
+ break;
+
+ case EDeleteLocalMessage:
+ // Deletes a message locally: only for messages not within the service
+ iSession->DeleteMessageL(iSource);
+
+ // As this is an instant operation, loop
+ return EFalse;
+
+ case EDeleteAllMessages:
+ // Deletes all messages/folder (must have no subfolders)
+ iSession->DeleteAllMessagesL(iStatus);
+ break;
+
+ case EDeleteFolder:
+ // Delete the folder
+ iSession->Delete(iStatus,iSourceFolder);
+ break;
+
+ case ENewSyncFolder:
+ // New only sync.
+
+ // if the current folder hasn't actually changed then don't
+ // bother with the Sync
+ if (!iSession->FolderChanged())
+ return EFalse;
+
+ // This used to do just that, new only messages, but it causes a lot of problems
+ // with sync limits, as for that to work deletes need to be taken into account also.
+ // This will fix that.
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): ESyncNewFolder: synchronising"))));
+ iSession->Synchronise(iStatus,EFalse);
+ break;
+
+ case ESyncFolder:
+ // Full sync
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): ESyncFolder: synchronising"))));
+ iSession->Synchronise(iStatus,EFalse);
+ break;
+
+ case ECloseFolderWithoutExpunge:
+ // Close current folder
+ iSession->Close(iStatus,EFalse);
+ break;
+
+ case EInboxDuplicateCopy:
+ case EInboxDuplicateMove:
+ {
+ // SJM: if we asked to fetch to the mirror then we can skip
+ // this stage
+ if (iDestinationFolder == KMsvNullIndexEntryId)
+ {
+ return EFalse;
+ }
+
+ // Move the message to the destination (the local inbox) then duplicate it
+ // back to the original folder for the mirror.
+ iEntry->SetEntry(iSource);
+ TMsvId sourcefolder=iEntry->Entry().Parent();
+
+ // Do the move & copy back structure: we update iSource here as the message
+ // in the mirror is actually a recreated one with a new TMsvId. We may want
+ // to delete this (if we're doing a MoveToLocal, for example) and so we need
+ // the correct TMsvId
+
+#if 1
+ // always copy so that on a move the delete happens on the original correctly
+ iSession->CopyMessage(iStatus,sourcefolder,iSource,iDestinationFolder,
+ &iSource,EFalse);
+#else
+ //DS - Added the iSequence[iStep]==EInboxDuplicateMove to represent whether or not
+ //to remove the original (i.e. copy or move).
+ iSession->CopyMessage(iStatus,sourcefolder,iSource,iDestinationFolder,
+ &iSource,iSequence[iStep-1]==EInboxDuplicateMove);
+#endif
+ break;
+ }
+
+ case EStartIdle:
+ // if there are more messages(iMsgCount) to populate don't go to IDLE state.
+ if (iSession->ImapIdleSupported()==EFalse || iIdleBeforeCommand==EFalse || iIdleBeforeFirstPopulate == EFalse || iMsgCount > 0)
+ {
+ return EFalse;
+ }
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStartIdle: calling StartIdle()"))));
+ iIdleBeforeFirstPopulate = EFalse;
+ iSession->StartIdle(iStatus);
+ break;
+
+ case EStopIdle:
+ if (iSession->ImapIdleSupported()==EFalse || iSession->IsIdling()==EFalse)
+ {
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStopIdle: not idling or waitng for idle"))));
+ iIdleBeforeCommand = EFalse;
+
+ // If last message being fetched , then should start IDLE after that.
+ if (iMsgCount == 1 )
+ {
+ iIdleBeforeCommand = ETrue;
+ }
+
+ return EFalse;
+ }
+
+ iIdleBeforeFirstPopulate = ETrue;//Are we "IDLE" before first populate..
+ iIdleBeforeCommand = ETrue;
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): EStopIdle: Calling StopIdle()"))));
+ iSession->StopIdle(iStatus);
+ break;
+
+ default:
+ gPanic(EUnknownState);
+ return ETrue;
+ }
+
+ // Next step in sequence...
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoRunLoopL(): Setting active"))));
+ SetActive();
+ return EFalse;
+ }
+
+// Called when parent wants to cancel us
+void CImImap4Compound::DoCancel()
+ {
+ DBG((iSession->LogText(_L8("CImImap4Compound::DoCancel()"))));
+
+ // Cancel any session object we're using
+ switch( iSequence[iStep-1] )
+ {
+ case EStopIdle:
+ case ESelectSourceMailboxRO:
+ case EFetchMessage:
+ case EInboxDuplicateCopy:
+ case ESelectInbox:
+ case EStartIdle:
+ {
+ TRAP_IGNORE(iSession->CancelAndIdleL(iIdleBeforeFirstPopulate));
+ } break;
+
+ default:
+ iSession->Cancel();
+ }
+
+ iIdleBeforeFirstPopulate = EFalse;
+ iMsgCount = 0;
+ // ...and parent
+ CMsgActive::DoCancel();
+ }
+
+// Store an offline operation in the correct place
+TMsvId CImImap4Compound::FindFolderL(const TMsvId aMessage)
+ {
+ DBG((iSession->LogText(_L8("FindFolderL(%x)"),aMessage)));
+
+ // Find folder that encloses this message (has Mailbox flag set), or service,
+ // whichever we find first
+ SetEntryL(aMessage);
+ TMsvEmailEntry entry;
+ do
+ {
+ // Visit this entry
+ SetEntryL(iEntry->Entry().Parent());
+ entry=iEntry->Entry();
+
+ DBG((iSession->LogText(_L8(" At %x, type=%x, mailbox=%d"),entry.Id(),entry.iType,entry.Mailbox())));
+
+ // A folder & a mailbox, or a service?
+ if (entry.iType==KUidMsvFolderEntry &&
+ entry.Mailbox())
+ {
+ // This'll do!
+ return(entry.Id());
+ }
+ }
+ while(iEntry->Entry().iType!=KUidMsvServiceEntry && entry.Id()!=KMsvRootIndexEntryId);
+
+ DBG((iSession->LogText(_L8(" Failed"))));
+
+ return(NULL);
+ }
+
+void CImImap4Compound::GenericCopyL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination, TInt* aSequence)
+ {
+ DBG((iSession->LogText(_L8("CImImap4Compound::GenericCopyL()"))));
+ Queue(aStatus);
+
+ // Save parameters
+ iSource=aSource;
+ iDestinationFolder=aDestination;
+ iSourceFolder=FindFolderL(iSource);
+ iMessageSelection=iSelectionStillToCopy=iSelectionStillToDelete=-1;
+
+ // Find the offending source folder
+ if (iSourceFolder == NULL &&
+ aSequence != SeqMoveFromLocal && aSequence != SeqCopyFromLocal)
+ {
+ Complete(KErrNotFound);
+ return;
+ }
+
+ // Select it
+ iStep=0;
+ iSequence=aSequence;
+ DoRunL();
+ }
+
+void CImImap4Compound::GenericCopyL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination, TInt* aSequence)
+ {
+ DBG((iSession->LogText(_L8("CImImap4Compound::GenericCopyL()"))));
+ Queue(aStatus);
+
+ // Save parameters
+ iSource=aSourceSel[0];
+ delete iSourceSel;
+ iSourceSel = NULL;
+ iSourceSel=aSourceSel.CopyL();
+ iDestinationFolder=aDestination;
+ iMessageSelection=iSelectionStillToCopy=iSelectionStillToDelete=aSourceSel.Count();
+
+ // Check that selection elements are contiguous. Just call Copy on contiguous selections.
+
+ iSourceFolder=FindFolderL((*iSourceSel)[iSelectionStillToCopy-1]);
+
+ // Find the offending source folder
+ if (iSourceFolder == NULL &&
+ aSequence != SeqMoveFromLocal && aSequence != SeqCopyFromLocal)
+ {
+ Complete(KErrNotFound);
+ return;
+ }
+
+ // Select it
+ iStep=0;
+ iSequence=aSequence;
+ DoRunL();
+ }
+
+// CopyToLocal
+void CImImap4Compound::CopyToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyToLocal(%x to %x)"),aSource,aDestination)));
+
+ iPopulateCommand=EFalse;
+
+ UpdatePartialMailInfoToDefaults(aDestination);
+
+ // Kick off the copy
+ GenericCopyL(aStatus,aSource,aDestination,SeqCopyToLocal);
+ }
+
+void CImImap4Compound::PopulateL(TRequestStatus& aStatus, const TMsvId aSource, TImImap4GetPartialMailInfo aGetPartialMailInfo)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Populate(%x,%d)"),aSource,aGetPartialMailInfo.iGetMailBodyParts)));
+
+ iPopulateCommand = ETrue;
+ // Set options and kick off the copy to ourselves
+ iGetPartialMailInfo = aGetPartialMailInfo;
+ GenericCopyL(aStatus,aSource,KMsvNullIndexEntryId,SeqCopyToLocal);
+
+ if(iMsgCount > 0)
+ {
+ iMsgCount--;
+ }
+
+ }
+
+// MoveToLocal
+void CImImap4Compound::MoveToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveToLocal(%x to %x)"),aSource,aDestination)));
+
+
+ //Partial populate option is implemented only for the populate command. moving a partially
+ //populated message will delete the unpopulated message from the remote server. UI takes care
+ // of notifying this and ask for confirmation whether user still wants to move the message.
+
+ iPopulateCommand=EFalse;
+
+ UpdatePartialMailInfoToDefaults(aDestination);
+
+ // We can't do a MoveToLocal if the destination is in the service: this possibility
+ // if filtered out by the things calling us, so we don't have to worry about it here.
+ // We know the destination is therefore a local folder.
+ GenericCopyL(aStatus,aSource,aDestination,SeqMoveToLocal);
+ }
+
+// CopyWithinService
+void CImImap4Compound::CopyWithinServiceL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyWithinService(%x to %x)"),aSource,aDestination)));
+
+ GenericCopyL(aStatus,aSource,aDestination,SeqCopyWithinService);
+ }
+
+void CImImap4Compound::CopyWithinServiceL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyWithinService(to %x)"),aDestination)));
+
+ GenericCopyL(aStatus,aSourceSel,aDestination,SeqCopyWithinService);
+ }
+
+// MoveWithinService
+void CImImap4Compound::MoveWithinServiceL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveWithinService(%x to %x)"),aSource,aDestination)));
+
+ GenericCopyL(aStatus,aSource,aDestination,SeqMoveWithinService);
+ }
+
+void CImImap4Compound::MoveWithinServiceL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveWithinService(to %x)"),aDestination)));
+
+ GenericCopyL(aStatus,aSourceSel,aDestination,SeqMoveWithinService);
+ }
+
+// CopyFromLocal
+void CImImap4Compound::CopyFromLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND CopyFromLocal(%x to %x)"),aSource,aDestination)));
+
+ GenericCopyL(aStatus,aSource,aDestination,SeqCopyFromLocal);
+ }
+
+// MoveFromLocal
+void CImImap4Compound::MoveFromLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND MoveFromLocal(%x to %x)"),aSource,aDestination)));
+
+ GenericCopyL(aStatus,aSource,aDestination,SeqMoveFromLocal);
+ }
+
+// SyncCopyToLocal
+void CImImap4Compound::SyncCopyToLocalL(TRequestStatus& aStatus, const TMsvId aSource, const TMsvId aDestination)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND SyncCopyToLocal(%x to %x)"),aSource,aDestination)));
+
+ iPopulateCommand=EFalse;
+
+ UpdatePartialMailInfoToDefaults(aDestination);
+
+ // Kick off the copy
+ GenericCopyL(aStatus,aSource,aDestination,SeqSyncCopyToLocal);
+ }
+
+// Delete
+void CImImap4Compound::DeleteL(TRequestStatus& aStatus, const TMsvId aSource)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Delete(%x)"),aSource)));
+
+ Queue(aStatus);
+
+ // Save parameters
+ iSource=aSource;
+ iMessageSelection=iSelectionStillToDelete=1;
+
+ // Find the offending source folder
+ if ((iSourceFolder=FindFolderL(iSource))==NULL)
+ {
+ Complete(KErrNotFound);
+ return;
+ }
+
+ // Select it
+ iStep=0;
+ iSequence=SeqDelete;
+ DoRunL();
+ }
+
+// Delete
+void CImImap4Compound::DeleteL(TRequestStatus& aStatus, const CMsvEntrySelection& aSourceSel)
+ {
+ LOG_COMMANDS( (iSession->LogText(_L8("COMPOUND Delete selection"))));
+
+ Queue(aStatus);
+
+ // Save parameters
+ iSource=aSourceSel[0];
+ delete iSourceSel;
+ iSourceSel = NULL;
+ iSourceSel=aSourceSel.CopyL();
+ iMessageSelection=iSelectionStillToDelete=aSourceSel.Count();
+
+ // Find the offending source folder
+ if ((iSourceFolder=FindFolderL(iSource))==NULL)
+ {
+ Complete(KErrNotFound);
+ return;
+ }
+
+ // Select it
+ iStep=0;
+ iSequence=SeqDelete;
+ DoRunL();
+ }
+
+// Delete all in folder, then folder itself
+void CImImap4Compound::DeleteFolderL(TRequestStatus& aStatus, const TMsvId aSource)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND DeleteFolder(%x)"),aSource)));
+
+ Queue(aStatus);
+
+ // Save parameters
+ iSourceFolder=aSource;
+ iSequence=SeqDeleteFolder;
+
+ // The folder might be a mailbox (in which case it needs selecting, messages
+ // deleting, closing, then deletion of the folder) or it might be a \Noselect
+ // folder, which we just delete.
+ User::LeaveIfError(iEntry->SetEntry(aSource));
+ TMsvEmailEntry folder=iEntry->Entry();
+ if (!folder.Mailbox())
+ {
+ DBG((iSession->LogText(_L8("Folder is marked \\NoSelect: just delete it"))));
+
+ // Skip the first few steps
+ iStep=2;
+ }
+ else
+ {
+ DBG((iSession->LogText(_L8("Folder is a mailbox: deleting messages and folder"))));
+
+ // Start from folder selection
+ iStep=0;
+ }
+
+ DoRunL();
+ }
+
+void CImImap4Compound::CreateL(TRequestStatus& aStatus, const TMsvId aParent, const TDesC& aLeafName, const TBool aFolder)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Create(%x)"),aParent)));
+
+ Queue(aStatus);
+
+ iStep=0;
+ iSequence=SeqCreate;
+ iSource=aParent;
+ iLeafName=aLeafName;
+ iFolder=aFolder;
+ DoRunL();
+ }
+
+void CImImap4Compound::RenameL(TRequestStatus& aStatus, const TMsvId aTarget, const TDesC& aNewName)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Rename(%x)"),aTarget)));
+
+ Queue(aStatus);
+
+ iStep=0;
+ iSequence=SeqRename;
+ iSource=aTarget;
+ iLeafName=aNewName;
+ DoRunL();
+ }
+
+void CImImap4Compound::SynchroniseL(TRequestStatus& aStatus)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Synchronise"))));
+
+ Queue(aStatus);
+
+ iStep=0;
+ iSequence=SeqSynchronise;
+ DoRunL();
+ }
+
+void CImImap4Compound::SelectL(TRequestStatus& aStatus, const TMsvId aFolder)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND Select(%x)"),aFolder)));
+
+ Queue(aStatus);
+
+ iStep=0;
+ iSequence=SeqSelect;
+ iSourceFolder=aFolder;
+ DoRunL();
+ }
+
+void CImImap4Compound::NewOnlySyncL(TRequestStatus& aStatus, const TMsvId aFolder)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND NewOnlySync(%x)"),aFolder)));
+
+ Queue(aStatus);
+
+ if (iSession->ImapIdleSupported())
+ {
+ // Igmore sync as Imap Idle is supported
+ Complete(KErrNone);
+ return;
+ }
+
+ // Check folder is a mailbox
+ User::LeaveIfError(iEntry->SetEntry(aFolder));
+ TMsvEmailEntry mbcheck=iEntry->Entry();
+ if (!mbcheck.Mailbox())
+ {
+ // Not a mailbox, so we can't sync it
+ Complete(KErrNotSupported);
+ return;
+ }
+
+ // Select it
+ iStep=0;
+ iSequence=SeqNewSync;
+ iSourceFolder=aFolder;
+ DoRunL();
+ }
+
+void CImImap4Compound::FullSyncL(TRequestStatus& aStatus, const TMsvId aFolder)
+ {
+ LOG_COMMANDS((iSession->LogText(_L8("COMPOUND FullSync(%x)"),aFolder)));
+
+ Queue(aStatus);
+
+ // Check folder is a mailbox
+ User::LeaveIfError(iEntry->SetEntry(aFolder));
+ TMsvEmailEntry mbcheck=iEntry->Entry();
+ if (!mbcheck.Mailbox())
+ {
+ do
+ {
+ // Ensure visibility
+ if (!mbcheck.Visible())
+ {
+ mbcheck.SetVisible(ETrue);
+ User::LeaveIfError(iEntry->ChangeEntryBulk(mbcheck));
+ }
+
+ // Move up one
+ User::LeaveIfError(iEntry->SetEntry(mbcheck.Parent()));
+ mbcheck=iEntry->Entry();
+ }
+ while(mbcheck.iType!=KUidMsvServiceEntry && mbcheck.Id()!=KMsvRootIndexEntryId);
+
+ // Not a mailbox, so we can't sync it
+ Complete(KErrNone);
+ return;
+ }
+
+ // Select it
+ iStep=0;
+ iSequence=SeqFullSync;
+ iSourceFolder=aFolder;
+ DoRunL();
+ }
+
+// Report progress
+TImap4GenericProgress CImImap4Compound::Progress()
+ {
+ // First, ask session (updates byte counts & stuff)
+ TImap4GenericProgress progress=iSession->Progress();
+ if (iSequence==SeqDelete || iSequence==SeqCopyWithinService)
+ {
+ progress.iMsgsToDo=iMessageSelection;
+ progress.iMsgsDone=iMessageSelection-iSelectionStillToCopy;
+ }
+ else if (iSequence==SeqMoveWithinService)
+ {
+ // DEL done in one go in imapsess,
+ // just have progress for the COPY part of the MOVE command.
+ progress.iMsgsToDo=iMessageSelection;
+ progress.iMsgsDone=iMessageSelection-iSelectionStillToCopy;
+ }
+
+ // don't believe there's any point in modifying the operation
+ // since it'll be set correctly in the Mtm handler.
+#if 0
+ // Now, overlay our current operation (move or copy, at least)
+ if (iSequence==SeqCopyToLocal || iSequence==SeqCopyWithinService ||
+ iSequence==SeqCopyFromLocal)
+ progress.iOperation=TImap4Progress::ECopying;
+ else if (iSequence==SeqMoveToLocal || iSequence==SeqMoveWithinService ||
+ iSequence==SeqMoveFromLocal)
+ progress.iOperation=TImap4Progress::EMoving;
+#endif
+
+ // Return the modified progress
+ return(progress);
+ }
+
+void CImImap4Compound::UpdatePartialMailInfoToDefaults(TMsvId aDestination)
+ {
+ iGetPartialMailInfo.iTotalSizeLimit= KMaxTInt;
+ iGetPartialMailInfo.iBodyTextSizeLimit = KMaxTInt;
+ iGetPartialMailInfo.iAttachmentSizeLimit = KMaxTInt;
+ iGetPartialMailInfo.iGetMailBodyParts = EGetImap4EmailBodyTextAndAttachments;
+ iGetPartialMailInfo.iPartialMailOptions=ENoSizeLimits;
+ iGetPartialMailInfo.iDestinationFolder=aDestination;
+ }
+
+void CImImap4Compound::SetMessageCount(const TInt aCount)
+ {
+ iMsgCount = aCount;
+ }