email/pop3andsmtpmtm/popservermtm/src/POPSTOPPOP.CPP
changeset 0 72b543305e3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/pop3andsmtpmtm/popservermtm/src/POPSTOPPOP.CPP	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,429 @@
+// 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 <e32std.h>
+
+#include "POPSMBX.H"
+#include "POPS.H"
+#include "POPSOP.H" //CImPop3Operations
+
+// includes for IMCV stuff
+#include <imcvrecv.h>
+#include <logwrap.h>
+#include <logwraplimits.h>
+
+#include <bautils.h>
+#include <msvutils.h>
+#include <imcvutil.h>
+
+#include <imcm.rsg>
+
+#include "PopsTopPop.h"
+#include "POPS.H"
+#include "POPSOP.H" //CImPop3Operations
+#include "POPSMBX.H"
+
+#include "POPS.PAN" // imrc's own panic codes
+
+#include "mobilitytestmtmapi.h"
+
+// IMRC Panic function
+GLREF_C void Panic(TPopsPanic aPanic);
+
+CImPop3TopPopulate* CImPop3TopPopulate::NewL(const CMsvEntrySelection& aRemoteEntry, CMsvServerEntry& aLocalEntry, TInt aLimit, CImPop3Session* aPop3Session, RFs& anFs, CImLogMessage* aLogMessage, TBool aDisconnectedMode, RArray<TUint>& aRemoteSizes)
+	{
+	CImPop3TopPopulate* self = new (ELeave) CImPop3TopPopulate( aLocalEntry, aLimit, aPop3Session, anFs, aLogMessage, aDisconnectedMode, aRemoteSizes);
+
+	CleanupStack::PushL(self);
+	self->ConstructL(aRemoteEntry);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CImPop3TopPopulate::~CImPop3TopPopulate()
+	{
+	iRemoteSizes.Close();
+	delete iTop;
+	delete iSource;
+	delete iRecvConverter;
+	}
+
+void CImPop3TopPopulate::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 += iRemoteSizes[i];
+			}
+		}
+	
+
+	if(iProgress.iTotalMsgs>0)
+		{
+		delete iTop;
+		iTop=NULL;
+		iTop=CImPop3Top::NewL(iPopSession,iRecvConverter,EFalse);
+		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 CImPop3TopPopulate::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));
+	
+	delete iTop;
+	iTop=NULL;
+	iTop=CImPop3Top::NewL(iPopSession,iRecvConverter,EFalse);
+	
+	// Set the MIME parser to point at the first message to be processed.
+	iRecvConverter->SetMsvId((*iSource)[iMsgCtr]);
+		
+	DoRetrieveL();
+	Queue(aStatus);
+	}	
+
+TPop3Progress CImPop3TopPopulate::Progress()
+	{
+	if(iPopTopPopState==EPopTopPopRetrieving)
+		{
+		// Get the Copy/Move Progress
+		iProgress.iBytesDone=iTop->Progress();
+		}
+	else if (iPopTopPopState == EPopTopPopLogging)
+		{
+		// We are doing Logging so the move/copy is complete
+		iProgress.iBytesDone = iProgress.iTotalBytes;
+		}
+	else
+		{
+		iProgress.iBytesDone=0;
+		iProgress.iTotalBytes=0;
+		}
+	return iProgress;
+	}
+
+CImPop3TopPopulate::CImPop3TopPopulate(CMsvServerEntry& aLocalEntry, TInt aLimit, CImPop3Session* aPop3Session, RFs& anFs, CImLogMessage* aLogMessage, TBool aDisconnectedMode, RArray<TUint>& aRemoteSizes)
+	: CMsgActive( KMsgPop3RefreshMailboxPriority ), iDestination(aLocalEntry), iPopSession(aPop3Session),iFs(anFs), iLogMessage(aLogMessage), iDisconnectedMode(aDisconnectedMode), iTopLimit(aLimit), iRemoteSizes(aRemoteSizes)
+	{
+	}
+
+void CImPop3TopPopulate::ConstructL( const CMsvEntrySelection& aRemoteSelection)
+	{
+	// 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));
+	iPopTopPopState=EPopTopPopRetrieving;
+	iProcessComplete=EFalse;
+
+	// set recv conv. 
+	if (iSource->Count())
+		{
+		// Set the MIME parser to point at the first message to be populated.
+		iRecvConverter->SetMsvId((*iSource)[0]);
+		}	
+	CActiveScheduler::Add(this);	  // Add CImPop3CopyMove to scheduler's queue
+	}
+
+void CImPop3TopPopulate::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();
+	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()))
+		{
+		iAlreadyComplete = ETrue;
+		SetActive();
+		User::RequestComplete(pS, KErrNone);
+		}
+	else
+		{
+		iProgress.iTotalBytes = iRemoteSizes[iMsgCtr];
+		// reset entry to destination context if the current entry is not meant to be populated
+		User::LeaveIfError(iDestination.SetEntry(iDestId));
+		iRetrieveMessage = ETrue;
+
+		//If the message is not found complete the request.
+		if (!iTop->SetMessageAndLines(msgId,iTopLimit)) 
+			{
+			iAlreadyComplete = ETrue;
+			SetActive();
+			User::RequestComplete(pS, KErrNone);
+			}
+		else
+			{
+			iCurrentMsgSize = iRemoteSizes[iMsgCtr];
+			iTop->StartL(iStatus);
+			SetActive();
+			MOBILITY_TEST_MTM_STATE(iServiceId, KMobilityTestMtmStatePopRetrieving);
+			}
+		}
+	}
+
+void CImPop3TopPopulate::RetrievalCompleteL()
+	{
+	iProcessComplete=ETrue;
+	}
+
+void CImPop3TopPopulate::DoRunL()
+	{
+	// 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::LeaveIfError(iSavedError);
+
+	// 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)
+			{
+			if ((!iAlreadyComplete) && (!iMessageMarkedForDelete))
+				{
+				TRAPD(err,iRecvConverter->MessageCompleteL());
+
+	 			if(err != KErrNone)
+					{
+					// something is wrong with the message delete and report back
+					err = iDestination.SetEntry(iDestId);
+					if (err == KErrNone)
+						{
+						err = iDestination.DeleteEntry(iTop->EntryId());
+						}
+					}
+				}
+			}
+
+		// The message is logged as 'failed' if iSavedError is not KErrNone.
+		LogFetchedMessageL();
+		}
+	}
+
+void CImPop3TopPopulate::DoComplete(TInt& /*aCompleteStatus*/)
+	{
+	}
+
+void CImPop3TopPopulate::DoCancel()
+	{
+	iPopSession->SetOpNotPending();
+
+	if(iPopTopPopState==EPopTopPopRetrieving)
+		{
+		iTop->Cancel();
+		}
+
+	CMsgActive::DoCancel();
+	}
+
+void CImPop3TopPopulate::RunLProcessingL()
+	{
+	switch (iPopTopPopState)
+		{
+		case EPopTopPopRetrieving:
+			{
+		    TInt amountLeft = 0;
+			if(iRetrieveMessage)
+				{
+				TBool partial=ETrue;
+				if (iTop->Progress()>=TUint(iCurrentMsgSize))
+					{
+					partial=EFalse;
+					}
+				
+				if ((!iAlreadyComplete) && (!iMessageMarkedForDelete))
+					{
+					iRecvConverter->MessageCompleteL(partial);
+					}
+				amountLeft=(iCurrentMsgSize)-iTop->Progress()+iRecvConverter->DeletedAttachmentSize();
+				if (amountLeft<0)
+					{
+					amountLeft=0;
+					}
+
+				TMsvId msgId=(*iSource)[iMsgCtr];
+				if(iDestination.SetEntry(msgId)==KErrNone)
+					{
+					TMsvEmailEntry header=iDestination.Entry();
+					TBool changed=EFalse;
+					if((header.Unread()))
+						{
+						header.SetNew(EFalse);
+						changed=ETrue;
+						}
+
+					if(partial!=EFalse)
+						{
+						// We have used TOP so the entry will be partial, unless we have got the whole thing.
+						header.SetPartialDownloaded(partial);
+						changed=ETrue;
+						}
+
+					if(changed != EFalse)
+						{
+						User::LeaveIfError(iDestination.ChangeEntry(header));
+						}						
+					if(iDestination.SetEntry(iDestId)!=KErrNone)						
+					{
+					User::Leave(KPop3ProblemWithRemotePopServer);
+					}
+					}
+
+				}
+
+			iRecvConverter->WritePartialFooterL(amountLeft);
+
+			iDestination.SetEntry(iDestId);	// make sure not trying to delete current context
+			LogFetchedMessageL();
+			}
+			break;
+		case EPopTopPopLogging:
+			// If the message has been logged then move on and download the next one.
+			{
+			--iProgress.iMsgsToProcess;
+			if(++iMsgCtr<iSource->Count())
+				{
+				// If we are migrating halt the operation here
+				if (iMigratingToNewBearer)
+					{			
+					// If we don't SetActive, the RunL will complete the request
+					return;
+					}
+				else
+					{
+ 					iRecvConverter->ResetL();
+					iRecvConverter->SetMsvId((*iSource)[iMsgCtr]);
+					DoRetrieveL(); //add it to the collection;
+					iPopTopPopState = EPopTopPopRetrieving;
+					}
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+//
+// Helper function to set up the iLogEntry object which is invoked after the copy/move.
+//
+void CImPop3TopPopulate::LogFetchedMessageL()
+	{
+	iPopTopPopState = EPopTopPopLogging;
+	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 CImPop3TopPopulate::Pause()
+	{
+	// Set the Migration flag
+	iMigratingToNewBearer = ETrue;
+	}
+
+// ****************************************************************************************** 
+// This is called by the POP Server MTM when it starts Migrating Bearer
+// 
+// ******************************************************************************************	
+void CImPop3TopPopulate::CancelAllowResume()
+	{
+	iMigratingToNewBearer = ETrue;
+	
+	// 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.
+	Cancel();		
+	}