diff -r 000000000000 -r 72b543305e3a email/pop3andsmtpmtm/popservermtm/src/POPSCPMV.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/pop3andsmtpmtm/popservermtm/src/POPSCPMV.CPP Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,660 @@ +// 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: +// + +#define _MSVAPI_DONT_INCLUDE_FLOGGER_ + +#include + +#include "POPSMBX.H" +#include "POPS.H" +#include "POPSOP.H" //CImPop3Operations +#include "POPSMTM.H" + +// includes for IMCV stuff +#include +#include +#include +#include +// Oyster includes +#include // CMsvServerEntry + +#include +#include + +#include +#include +#include +#include + +#include "PopsDele.h" +#include "PopsCpMv.h" +#include "POPS.H" +#include "POPSOP.H" //CImPop3Operations +#include "popstran.h" +#include +#include "POPS.PAN" // imrc's own panic codes +#include "POPSMBX.H" + +#include "mobilitytestmtmapi.h" + + +// IMRC Panic function +GLREF_C void Panic(TPopsPanic aPanic); + +CImPop3CopyMove::CImPop3CopyMove(CMsvServerEntry& aLocalEntry, CImPop3Session* aPop3Session, TBool aCopy, RFs& anFs, TMsvId aDestinationId, CImLogMessage* aLogMessage, TBool aDisconnectedMode) + : CMsgActive( KMsgPop3RefreshMailboxPriority ), iDestination(aLocalEntry), iPopSession(aPop3Session),iCopy(aCopy),iFs(anFs), iDestId(aDestinationId), iPopulate(EFalse), iLogMessage(aLogMessage), iDisconnectedMode(aDisconnectedMode) + { + } + +CImPop3CopyMove::CImPop3CopyMove(CMsvServerEntry& aLocalEntry, CImPop3Session* aPop3Session, TBool aCopy, RFs& anFs, CImLogMessage* aLogMessage, TBool aDisconnectedMode) + : CMsgActive( KMsgPop3RefreshMailboxPriority ), iDestination(aLocalEntry), iPopSession(aPop3Session),iCopy(aCopy),iFs(anFs), iPopulate(ETrue), iLogMessage(aLogMessage), iDisconnectedMode(aDisconnectedMode) + { + } + +CImPop3CopyMove* CImPop3CopyMove::NewL(const CMsvEntrySelection& aRemoteEntry, CMsvServerEntry& aLocalEntry, CImPop3Session* aPop3Session, TBool aCopy, RFs& anFs, TMsvId aServiceId, CImLogMessage* aLogMessage, TBool aDisconnectedMode) + { + CImPop3CopyMove* self = new (ELeave) CImPop3CopyMove( aLocalEntry, aPop3Session, aCopy, anFs, aServiceId, aLogMessage, aDisconnectedMode); + + CleanupStack::PushL(self); + self->ConstructL(aRemoteEntry); + CleanupStack::Pop(); + return self; + } + +CImPop3CopyMove* CImPop3CopyMove::NewL(const CMsvEntrySelection& aRemoteEntry, CMsvServerEntry& aLocalEntry, CImPop3Session* aPop3Session, TBool aCopy, RFs& anFs, CImLogMessage* aLogMessage, TBool aDisconnectedMode) +// This verion of NewL creates a CImPop3CopyMove for populating entries from the remote mailbox + { + // Moving does not make sense when populating a message entry from the remote mailbox + __ASSERT_DEBUG(aCopy, Panic(EPopFailedDebugAssert)); + + CImPop3CopyMove* self = new (ELeave) CImPop3CopyMove( aLocalEntry, aPop3Session, aCopy, anFs, aLogMessage, aDisconnectedMode); + + CleanupStack::PushL(self); + self->ConstructL(aRemoteEntry); + CleanupStack::Pop(); + return self; + } + +void CImPop3CopyMove::ConstructL( const CMsvEntrySelection& aRemoteSelection ) + { + LeaveIfLowDiskL(aRemoteSelection); + iTransfer = CImPop3TransferMessage::NewL(iDestination); + + // make our copy of aRemoteEntry + iSource = aRemoteSelection.CopyL(); + iServiceId = iDestination.Entry().Id(); + + // assume Entry passed in is set to service id (IMCV needs to set new entries to this) + iRecvConverter = CImRecvConvert::NewL( iFs, &iDestination, KUidMsgTypePOP3, iServiceId); + iRecvConverter->SetCaf(*iPopSession->GetCafL(iFs)); + iPopCopyMoveState=EPopCpMvRetrieving; + iProcessComplete=EFalse; + iMigratingToNewBearer = EFalse; + // richtext body which we might or might not need + + // set recv conv. + if (iPopulate) + { + if (iSource->Count()) + { + // Set the MIME parser to point at the first message to be populated. + iRecvConverter->SetMsvId((*iSource)[0]); + } + } + else + { + iRecvConverter->SetMsvId(iDestId); + } + + CActiveScheduler::Add(this); // Add CImPop3CopyMove to scheduler's queue + } + + +CImPop3CopyMove::~CImPop3CopyMove() + { + Cancel(); + // delete everything here + delete iRetrieve; + delete iDelete; + delete iSource; + + delete iRecvConverter; + + delete iTransfer; + } + + +void CImPop3CopyMove::LeaveIfLowDiskL(const CMsvEntrySelection& aMsgSelection) + { + // Get the original destination + TMsvEntry destination = iDestination.Entry(); + + // Get the size of all the messages that need to be downloaded + TInt totalMsgsSize = 0; + for(TInt i = 0; i < aMsgSelection.Count(); i ++) + { + iDestination.SetEntry(aMsgSelection.At(i)); + if(!iDestination.Entry().Complete()) + { + totalMsgsSize += iDestination.Entry().iSize; + } + } + + // Set the destination back to the original + iDestination.SetEntry(destination.Id()); + + // Get the Free Disk Space + TVolumeInfo volumeInfo; + TInt currentDrive = MessageServer::CurrentDriveL(iFs); + User::LeaveIfError(iFs.Volume(volumeInfo, currentDrive)); + + // Leave if not enougth Disk Space + if (volumeInfo.iFree < (totalMsgsSize + KMinimumDiskSpaceForSync)) + { + User::Leave(KErrDiskFull); + } + } + +// +// Cancel any current operation +// +void CImPop3CopyMove::DoCancel() + { + iPopSession->SetOpNotPending(); + + if(iPopCopyMoveState==EPopCpMvRetrieving) + { + iRetrieve->Cancel(); + } + else if (iDelete != NULL) + { + if (iMigratingToNewBearer) + { + iDelete->CancelAllowResume(); + } + else + { + iDelete->Cancel(); + } + } + + if (iTransfer != NULL) + { + iTransfer->Cancel(); + } + + CMsgActive::DoCancel(); + } + +// +// +// +void CImPop3CopyMove::DoComplete(TInt& /*aCompleteStatus*/) + { + } +// +// Start me up +// +void CImPop3CopyMove::StartL(TRequestStatus& aStatus) + { + iMsgCtr=0; + iSavedError = KErrNone; + // set up progress obj. + iProgress.iTotalMsgs=iSource->Count(); + iProgress.iMsgsToProcess=iProgress.iTotalMsgs; + + // Do a quick tally on the size of messages which are to be copied / moved. + iProgress.iTotalSize = 0; + for(TInt i = 0; i < iProgress.iTotalMsgs; i ++) + { + iDestination.SetEntry(iSource->At(i)); + if(!iDestination.Entry().Complete()) + { + iProgress.iTotalSize += iDestination.Entry().iSize; + } + } + + delete iRetrieve; + iRetrieve=NULL; + iRetrieve=CImPop3Retr::NewL(iPopSession,iRecvConverter, iFs); + + if(iProgress.iTotalMsgs) + { + DoRetrieveL(); + Queue(aStatus); + } + else + { + aStatus = KRequestPending; + TRequestStatus* pS=&aStatus; + User::RequestComplete(pS,KErrNone); + } + } + + +// ****************************************************************************************** +// Resume function called by the POP Server MTM, once it has completed Migrating to new bearer +// +// ****************************************************************************************** +void CImPop3CopyMove::ResumeL(CImPop3Session* aPopSession, TRequestStatus& aStatus) + { + iMigratingToNewBearer = EFalse; + iPopSession = aPopSession; + + delete iRecvConverter; + iRecvConverter = NULL; + iRecvConverter = CImRecvConvert::NewL( iFs, &iDestination, KUidMsgTypePOP3, iServiceId); + iRecvConverter->SetCaf(*iPopSession->GetCafL(iFs)); + + if (iPopulate) + { + if (iSource->Count()) + { + // Set the MIME parser to point at the first message to be populated. + iRecvConverter->SetMsvId((*iSource)[iMsgCtr]); + } + } + else + { + // Set the folder + iRecvConverter->SetMsvId(iDestId); + } + + + switch (iPopCopyMoveState) + { + case EPopCpMvRetrieving: + case EPopCpMvLogging: + { + delete iRetrieve; + iRetrieve=NULL; + iRetrieve=CImPop3Retr::NewL(iPopSession,iRecvConverter, iFs); + + // Start retrieving again, from where we had left + DoRetrieveL(); + break; + } + case EPopCpMvDeleting: + { + // set iDestination to service entry so we can delete stuff + User::LeaveIfError(iDestination.SetEntry( iServiceId )); + + iDelete->ResumeL(iPopSession, iStatus); + SetActive(); + + break; + } + default: + { + __ASSERT_ALWAYS(EFalse, Panic(EPopUnexpectedMigrateState)); + break; + } + } + Queue(aStatus); + } + + +// +// Function called from DoRunL. +// +void CImPop3CopyMove::RunLProcessingL() +// This function is called and trapped by the DoRunL function. +// This allows a logging operation to be carried if it leaves. + { + TInt err = KErrNone; + + switch (iPopCopyMoveState) + { + case EPopCpMvRetrieving: + { + + if(iRetrieveMessage) + { + if ((!iAlreadyComplete) && (!iMessageMarkedForDelete)) + iRecvConverter->MessageCompleteL(); + + TMsvId msgId=(*iSource)[iMsgCtr]; + err = iDestination.SetEntry(msgId); + if(err==KErrNone) + { + TMsvEntry header=iDestination.Entry(); + if((header.Unread()) && (!iPopulate)) + { + header.SetNew(EFalse); + err = iDestination.ChangeEntry(header); + __ASSERT_DEBUG(err == KErrNone, Panic(EPopFailedDebugAssert)); + } + err = iDestination.SetEntry(iDestId); // make sure not trying to delete current context + if(err!=KErrNone) + { + User::Leave(KPop3ProblemWithRemotePopServer); + } + } + + // If the server replies with "-ERR" command, leave with "KErrNotFound". + if(!iRetrieve->PopCommandAccepted()) + { + User::Leave(KErrNotFound); + } + } + LogFetchedMessageL(); + } + break; + case EPopCpMvLogging: + { + // If the message has been logged then move on and download the next one. + iProgress.iMsgsToProcess--; + if(++iMsgCtrCount()) + { + if (iPopulate) + // The destination must be changed to the new message when populating + { + iRecvConverter->ResetL(); + iRecvConverter->SetMsvId((*iSource)[iMsgCtr]); + } + // If we are migrating halt the operation here + if (iMigratingToNewBearer) + { + // If we don't SetActive, the RunL will complete the request + iPopCopyMoveState = EPopCpMvRetrieving; + return; + } + DoRetrieveL(); //add it to the collection; + iPopCopyMoveState = EPopCpMvRetrieving; + } + else + { + // There are no more messages to download. + // If we're moving rather than copying then delete the source messages. + iPopCopyMoveState = EPopCpMvDeleting; + RetrievalCompleteL(); + } + } + break; + default: + break; + } + } + +// +// Result of last active call +// +void CImPop3CopyMove::DoRunL() + { + if (iDoingTransfer) + { + iDoingTransfer = EFalse; + TMsvEntry entry = iDestination.Entry(); + entry.SetComplete(EFalse); + iDestination.ChangeEntry(entry); + } + + if (iSavedError != KErrNone) + // If we have already have an error then we have just been logging the failure. + // The failure has been logged so we can leave now. + { + User::Leave(iSavedError); + } + else + // There was no error so handle the completion of either the logging or the retrieve operations. + { + TRAP(iSavedError, RunLProcessingL()); + + if (iSavedError != KErrNone) + // If an error has occured then we need to clean up the message and log the failure before bailing out. + { + if( iRetrieveMessage ) + { + TInt err = KErrNone; + if ((!iAlreadyComplete) && (!iMessageMarkedForDelete)) + { + TRAP(err,iRecvConverter->MessageCompleteL()); + } + + if(err != KErrNone || iSavedError) + { + // something is wrong with the message delete and report back + if (!iPopulate) + { + err = iDestination.SetEntry(iDestId); + if (err == KErrNone) + { + err = iDestination.DeleteEntry(iRetrieve->EntryId()); + } + } + else + // cleanup the message, leave the root entry only. + { + TMsvId entryId = iRetrieve->EntryId(); + if (entryId != KMsvNullIndexEntryId) + { + err = iDestination.SetEntry(iRetrieve->EntryId()); + if (err == KErrNone) + { + CMsvEntrySelection *childEntries = new (ELeave) CMsvEntrySelection(); + CleanupStack::PushL(childEntries); + // ignore any errors, there is nothing that can be done about them here. + User::LeaveIfError(iDestination.GetChildren(*childEntries)); + if (childEntries->Count() != 0) + { + iDestination.DeleteEntries(*childEntries); + } + CleanupStack::PopAndDestroy(); //childEntries + } + } + } + } + } + + // The message is logged as 'failed' if iSavedError is not KErrNone. + LogFetchedMessageL(); + } + } + } + +// +// Use Pop3Retr to Retrieve a message specified by it's Oyster message Id +// +void CImPop3CopyMove::DoRetrieveL() + { + iAlreadyComplete = EFalse; + iMessageMarkedForDelete = EFalse; + TRequestStatus* pS = &iStatus; + TMsvId msgId=(*iSource)[iMsgCtr]; + // iDestination will later be changed back to the destination entry, if required + TInt err = iDestination.SetEntry(msgId); + TMsvEmailEntry entry = iDestination.Entry(); + + TBool partial=entry.PartialDownloaded(); + if(err != KErrNone) + { + SetActive(); + User::RequestComplete(pS,err); + } + else if (entry.Operation() && (entry.DisconnectedOperation() == EDisconnectedDeleteOperation)) + { + iMessageMarkedForDelete = ETrue; + SetActive(); + User::RequestComplete(pS, KErrNone); + } + else if ((entry.Complete() && !partial) && (iPopulate)) + { + iAlreadyComplete = ETrue; + SetActive(); + User::RequestComplete(pS, KErrNone); + } + else + { + iProgress.iTotalBytes = entry.iSize; + if(entry.Complete() && !iPopulate) + { + iRetrieveMessage=EFalse; + // copy from source to target collection + DoTransferL(entry); + } + else + { + // reset entry to destination context if the current entry is not meant to be populated + if (!iPopulate) + { + err = iDestination.SetEntry(iDestId); + User::LeaveIfError(err); + } + + iRetrieveMessage = ETrue; + +//If the message is not found complete the request. + if (!iRetrieve->SetMessage(msgId)) + { + iAlreadyComplete = ETrue; + SetActive(); + User::RequestComplete(pS, KErrNone); + } + else + { + iRetrieve->StartL(iStatus); + SetActive(); + MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopRetrieving); + } + } + } + } + +// +// Report the refreshing news back to the UI +// +TPop3Progress CImPop3CopyMove::Progress() + { + if(iPopCopyMoveState==EPopCpMvRetrieving) + { + // Get the Copy/Move Progress + iProgress.iBytesDone=iRetrieve->Progress(); + } + else if (iPopCopyMoveState == EPopCpMvLogging) + { + // We are doing Logging so the move/copy is complete + iProgress.iBytesDone = iProgress.iTotalBytes; + } + else + { + iProgress.iBytesDone=0; + iProgress.iTotalBytes=0; + iProgress.iMsgsToProcess=0; + } + return iProgress; + } + +// +// Transfer message from remote to local collection (when there's no TOP) +// +void CImPop3CopyMove::DoTransferL(TMsvEntry& aMsvEntry) + { + CImPop3TransferMessage::TImPop3TransferMethod transferMethod; + + if (iDisconnectedMode) + { + transferMethod = CImPop3TransferMessage::EImPop3CopyTransfer; + } + else + { + transferMethod = CImPop3TransferMessage::EImPop3MoveTransfer; + } + + iStatus = KRequestPending; + iTransfer->StartL(aMsvEntry.Id(), iDestId, transferMethod, iStatus); + SetActive(); + } + +void CImPop3CopyMove::RetrievalCompleteL() + { + iProcessComplete=ETrue; + if(iCopy==EFalse) + { + // set iDestination to service entry so we can delete stuff + User::LeaveIfError(iDestination.SetEntry( iServiceId )); + + delete iDelete; + iDelete=NULL; + iDelete = CImPop3Delete::NewL(iDestination,*iSource,iPopSession, iServiceId); + iDelete->Start(iStatus); + SetActive(); // Don't need to requeue? + } + } + +// +// Helper function to set up the iLogEntry object which is invoked after the copy/move. +// +void CImPop3CopyMove::LogFetchedMessageL() + { + iPopCopyMoveState = EPopCpMvLogging; + if (iLogMessage) + { +// Get the header information for the message that is to be copied or moved. + User::LeaveIfError(iDestination.SetEntry((*iSource)[iMsgCtr])); + + // Get the 'Fetch' string from the logging string table. + TBuf fetchString; + iLogMessage->GetString(fetchString, R_LOG_DIR_FETCHED); + +// Set up the log event. + iLogMessage->LogEvent().SetEventType(KLogMailEventTypeUid); + + iLogMessage->LogEvent().SetDirection(fetchString); + iLogMessage->LogEvent().SetRemoteParty(iDestination.Entry().iDetails); + iLogMessage->LogEvent().SetSubject(iDestination.Entry().iDescription); + iLogMessage->LogEvent().SetLink(iDestId); + + if (iSavedError != KErrNone) + { + TBuf failedString; + iLogMessage->GetString(failedString, R_LOG_DEL_FAILED); + iLogMessage->LogEvent().SetStatus(failedString); + } + +// Run the iLogMessage operation. + iLogMessage->Start(iDestination.Entry().iError, iStatus); + SetActive(); + } + else + { + TRequestStatus* status = &iStatus; + SetActive(); + User::RequestComplete(status, KErrNone); + } + } + + +// ****************************************************************************************** +// This is called by the POP Server MTM when it starts Migrating Bearer +// +// ****************************************************************************************** +void CImPop3CopyMove::Pause() + { + // Set the Migration flag, so we can migrate when the current operation (msg) is complete. + iMigratingToNewBearer = ETrue; + } + +// ****************************************************************************************** +// This is called by the POP Server MTM when it starts Migrating Bearer +// +// ****************************************************************************************** +void CImPop3CopyMove::CancelAllowResume() + { + // Cancel the copying of the current message and decrement counters + // so we can restart from this message onwards when we have migrated. + // Use the normal cancel, as we really need to cancel here. + iMigratingToNewBearer = ETrue; + Cancel(); + }