email/pop3andsmtpmtm/popservermtm/src/POPSCPMV.CPP
changeset 0 72b543305e3a
--- /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 <e32std.h>
+
+#include "POPSMBX.H"
+#include "POPS.H"
+#include "POPSOP.H" //CImPop3Operations
+#include "POPSMTM.H"
+
+// includes for IMCV stuff
+#include <txtetext.h>
+#include <txtrich.h>
+#include <miuthdr.h>
+#include <imcvrecv.h>
+// Oyster includes
+#include <msventry.h>	// CMsvServerEntry
+
+#include <logwrap.h>
+#include <logwraplimits.h>
+
+#include <s32mem.h>
+#include <s32file.h>
+#include <msvapi.h>
+#include <imcvutil.h>
+
+#include "PopsDele.h"
+#include "PopsCpMv.h"
+#include "POPS.H"
+#include "POPSOP.H" //CImPop3Operations
+#include "popstran.h"
+#include <msvstore.h>
+#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(++iMsgCtr<iSource->Count())
+				{
+				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<KLogMaxSharedStringLength> 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<KLogMaxSharedStringLength> 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();
+	}