email/email/smtp/src/Local_imcvrecv.cpp
branchSymbian2
changeset 1 8758140453c0
child 6 c108117318cb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/email/email/smtp/src/Local_imcvrecv.cpp	Thu Jan 21 12:53:44 2010 +0000
@@ -0,0 +1,4020 @@
+// 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 the License "Symbian Foundation License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+
+
+/**
+ @file
+*/
+
+
+// epoc include
+#include <e32base.h>
+#include <imutdll.h>
+#include <imcvtext.h>
+#include "Local_imcvrecv.h"
+#include <imcvcodc.h>	// TImConvert
+#include <imcvutil.h>
+
+#include <miuthdr.h>	// CImHeader
+#include <miutatch.h>	// TImAttachmentFile
+#include <txtrich.h>
+#include <imcm.rsg>		// resource definition for IMCM
+
+#include <pop3set.h>	// For including KUidMsgTypePOP3
+#include <barsread.h>	// TResourceReader
+
+#include <cmsvbodytext.h>
+
+#ifdef __WINS__
+#include <e32wins.h>    // for maxfilename lengths
+#include <msvapi.h>
+#endif
+
+#ifndef __WINS__
+#include <msvapi.h>
+#endif
+#include <cmsvattachment.h> 
+#include <mmsvattachmentmanager.h>
+#include <mmsvattachmentmanagersync.h>
+#ifndef _MSG_NO_LOGGING
+#define __IMUT_LOGGING
+
+
+// literals used
+_LIT(KLogFilePath, "c:\\logs\\mailtext\\in.txt");
+_LIT8(KNewLogHeader, "\r\n------ New Receive Session ------\r\n");
+_LIT8(KFound, "found: ");
+_LIT8(KPartLine, "unknown or part line");
+_LIT8(KEndOFHeader, "End of header");
+_LIT8(KSkippingData, "Skipping data");
+_LIT8(KCollectingData7, "Collecting 7/8-bit data");
+_LIT8(KCollectingDataQP, "Collecting QP data");
+_LIT8(KCollectingBase64, "Collecting BASE64 data");
+_LIT8(KCollectingUU, "Collecting UU data");
+_LIT8(KDecodingBase64, "Decoding BASE64 data");
+_LIT8(KDecodedBase64, "Decoded BASE64 data");
+_LIT8(KDecodingUU, "Decoding UU data");
+_LIT8(KDecodedUU, "Decoded UU data");
+_LIT8(KDecodingQP, "Decoding QP data");
+_LIT8(KDecodedQP, "Decoded QP data");
+_LIT8(KUUEDataCorrupt, "UU Data is corrupt");
+_LIT8(KFoundUUEStartBoundary, "UUE start boundary");
+_LIT8(KFoundUUEEndBoundary, "UUE end boundary");
+_LIT8(KClosingAttachFile, "Closing attachment file");
+_LIT8(KDeletingAttachFile, "Deleting attachment file");
+_LIT8(KDeletedAttachFile, "Deleted attachment file");
+_LIT8(KFailedToWriteToFile, "Failed to write to attachment file");
+_LIT8(KSectionHeader, "Section header");
+_LIT8(KFoundMIMEBoundary, "MIME boundary");
+_LIT8(KWritingToBody, "writing body");
+_LIT8(KWroteToBody, "wrote body");
+_LIT8(KWritingToFile, "writing attachment");
+_LIT8(KWroteToFile, "wrote attachment");
+_LIT8(KReset, "Resetting CLocalImRecvConvert");
+_LIT8(KReseted, "Resetting CLocalImRecvConvert");
+_LIT8(KDeleted, "Deleting CLocalImRecvConvert");
+_LIT8(KLineHasLineBreak, "Linebreak");
+_LIT8(KLastToken, "That was the last token");
+_LIT8(KBlankLine, "Blank line");
+_LIT8(KRemoveBoundary, "Remove boundary");
+_LIT8(KRemovedBoundary, "Removed boundary");
+_LIT8(KResetForNewEntry, "Reset for a New Entry");
+_LIT8(KResetedForNewEntry, "Reseted for a New Entry");
+_LIT8(KResetForNonMimeEntry, "Reset for a New Non-Mime Entry");
+_LIT8(KResetedForNonMimeEntry, "Reseted for a New Non-Mime Entry");
+_LIT8(KCreatingEntry, "Creating Entry");
+_LIT8(KCreatedEntry, "Created Entry");
+_LIT8(KUpdatingEntry, "Updating Entry");
+_LIT8(KUpdatedEntry, "Updated Entry");
+_LIT8(KMoveToParentEntry, "Moved to parent entry");
+_LIT8(KMovedToParentEntry, "End of Moved to parent entry");
+_LIT8(KStoringHeader, "Storing CImHeader");
+_LIT8(KStoredHeader, "Stored CImHeader");
+_LIT8(KStoringBody, "Storing CRichText");
+_LIT8(KStoring8BitBody, "Storing CMsvBodyText");
+_LIT8(KStoredBody, "Stored CRichText");
+_LIT8(KStored8BitBody, "Stored CMsvBodyText");
+_LIT8(KStoringMIMEHeader, "Storing CImMimeHeader");
+_LIT8(KStoredMIMEHeader, "Stored CImMimeHeader");
+_LIT8(KIgnoringStreams, "Discarding streams");
+_LIT8(KStartMessageComplete, "Start Message Complete");
+_LIT8(KMessageComplete, "Message Complete");
+_LIT8(KHeaderComplete, "Message Header complete");
+_LIT8(KReturnReceiptTo, "return-receipt-To is set");
+_LIT8(KStartStoringEntryStream, "Starting Storing Entry Stream");
+_LIT8(KStoringEntryStream, "Storing Entry Stream");
+_LIT8(KDoneStoringEntryStream, "Done Storing Entry Stream");
+#endif // _MSG_NO_LOGGING
+
+// uncomment the line below if logging is to be enabled
+
+#if defined(__IMUT_LOGGING)
+#define RECVLOG(text) (iImcvLog?iImcvLog->AppendComment(text):void(0));
+#define RECVLOG_OUT(text) (iImcvLog?iImcvLog->AppendOut(text):void(0));
+#define LOGGING(string1, string2) (Logging(string1, string2));
+#else
+#define RECVLOG(text) (void(0));
+#define RECVLOG_OUT(text) (void(0));
+#define LOGGING(string1, string2) (void(0));
+#endif
+
+#define UNUSED_VAR( var ) var = var  // fix for armv5 build warnings
+const TInt KBodyTextChunkSizeBytes = 512;
+
+_LIT(KIntegerKey,"%d");
+const TInt KSpaceToAddNumber=20;
+
+// added this to handle DRM files
+_LIT8(KTImcvDrm, "testagent.drm");
+
+
+/**
+IsIllegalChar()
+Checks if the character is illegal in EPOC32 file system
+
+@param aChar
+@return
+*/
+LOCAL_C TBool IsIllegalChar(const TUint aChar)
+	{
+	// EPOC32 filenames must not contain any of the following chars
+    return (aChar == '*' || aChar == '\\' || aChar == '<' || aChar == '>' ||
+			aChar == ':'  || aChar == '"' ||  aChar    == '/' || aChar == '|' ||
+			aChar < ' ' || aChar == '?');
+	}
+
+/**
+RemoveSurroundingCharacters()
+
+@param aLeft
+@param aRight
+@param aString
+*/
+LOCAL_C void RemoveSurroundingCharacters( const TUint8& aLeft, const TUint8& aRight, HBufC8& aString)
+	{
+	TPtr8 des = aString.Des();
+	TInt len  = des.Length();
+	
+	if( len > 2 && des[0] == aLeft && des[len - 1] == aRight )
+		{
+		TPtrC8 mid = des.Mid(1, len - 1);
+		des.Copy(mid);
+		des.SetLength(len - 2);
+		}
+	}
+
+
+//****************************************************************************************
+//              Class CLocalRfc822Token Functions
+//****************************************************************************************
+
+
+/**
+NewLC()
+Static factory constructor. Uses two phase 
+construction.
+
+@leave KErrNoMemory
+@return
+A pointer to the newly created CLocalRfc822Token object.
+*/
+CLocalRfc822Token* CLocalRfc822Token::NewLC()
+	{
+	CLocalRfc822Token* self = new (ELeave) CLocalRfc822Token;
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+
+/**
+ConstructL()
+
+*/
+void CLocalRfc822Token::ConstructL()
+	{
+	iOutputLine = HBufC8::NewL(KMaxIMailHeaderReadLineLength + 1);
+	Reset();
+	}
+
+
+/**
+CLocalRfc822Token()
+Constructor
+*/
+CLocalRfc822Token::CLocalRfc822Token()
+	{
+	__DECLARE_NAME(_S("CLocalRfc822Token"));
+	}
+
+
+/**
+~CLocalRfc822Token()
+Destructor
+*/
+CLocalRfc822Token::~CLocalRfc822Token()
+	{
+	delete iOutputLine;
+	iOutputLine=NULL;
+	}
+
+
+/**
+Reset()
+
+*/
+void CLocalRfc822Token::Reset()
+	{
+	iOutputLine->Des().FillZ();
+	iBufferedInput.SetLength(0);
+	iBufferedInput.FillZ();
+
+	iLastToken = EFalse;
+	iFirstLine = ETrue;
+	i822FieldsExist=EFalse;
+	}
+
+
+/**
+ParseNextLineL()
+
+@param aSourceLine
+*/
+void CLocalRfc822Token::ParseNextLineL(const TDesC8& aSourceLine)
+	{
+	TBool hitEof = EFalse;
+	TBool endOfField = EFalse;
+	// Always read one more packet than we need so we know we've read the entire field.
+
+	// Consequently, we need to check whether there is any buffered input from the
+	// previous rfc822 field:*******
+
+	if(iBufferedInput.Length())
+		{
+		// the buffered input is never more than a line of text...
+		*iOutputLine = iBufferedInput;
+		
+ 		iBufferedInput.FillZ();
+		iBufferedInput.SetLength(0);
+		}
+	iInputLine = aSourceLine;
+
+	// discard any LF character from the begining of the line (this is abit strange?)
+	while(iInputLine.Length() > 0 && (iInputLine[0] == KImcvLF || iInputLine[0] == KImcvCR))
+		iInputLine.Delete(0, 1);
+
+	// remove the CR at the end but only if there's stuff before it
+	while(iInputLine.Length() > 0 && (iInputLine[iInputLine.Length() - 1] == KImcvLF || iInputLine[iInputLine.Length() - 1] == KImcvCR))
+		iInputLine.Delete(iInputLine.Length() - 1, 1);
+
+	// if the newly read line is now empty, then don't read any more through this tokeniser
+	iLastToken = !iInputLine.Length();
+
+	// only bother with the rest of the parsing if there's any data left
+	if(iInputLine.Length() > 0 || iOutputLine->Length() > 0)
+		{
+		// check whether we're on the next field or still on the current one
+		if(!iFirstLine && iInputLine.Length() > 0 && iInputLine[0] != KImcvSP && iInputLine[0] != KImcvTab)
+			{
+			// we've read the first line of the next field
+			iBufferedInput = iInputLine;
+			endOfField = ETrue; // flag the fact that the current field is ready for parsing
+			}
+		else // the line belongs in the current field, but without any leading whitespace
+			{
+			// find the first non-whitespace character
+			const TUint8* ptr = iInputLine.Ptr();
+			while((*ptr == KImcvSP || *ptr == KImcvTab) && (ptr - iInputLine.Ptr() < iInputLine.Length())) ptr++;
+		
+			// make sure we're not about to exceed the buffer
+			if((iOutputLine->Length() + iInputLine.Length()) > iOutputLine->Des().MaxLength())
+				iOutputLine = iOutputLine->ReAlloc(iOutputLine->Length() + iInputLine.Length());
+
+			// now copy the remaining data into the buffer
+			iOutputLine->Des().Append(iInputLine.Right(iInputLine.Length() - (ptr - iInputLine.Ptr())));
+			}
+		}
+	else
+		hitEof = ETrue;		//this means that EEndOfHeader is set if a line of zero length is parsed - ie. (clean CRLF - CRLF) = 0.
+	iFirstLine = EFalse;
+
+	if(endOfField || iLastToken)
+		{ 
+		// only parse the input when we have a whole field, 
+		// or we just found the blank line that
+		// separates the body from the header
+		if(MatchAndRemoveL(KImcvFromPrompt))
+			iHeaderPart = EFrom;
+		else if(MatchAndRemoveL(KImcvReplyToPrompt))
+			iHeaderPart = EReplyTo;
+		else if(MatchAndRemoveL(KImcvToPrompt))
+			iHeaderPart = ETo;
+		else if(MatchAndRemoveL(KImcvCcPrompt))
+			iHeaderPart = ECc;
+		else if(MatchAndRemoveL(KImcvBccPrompt))
+			iHeaderPart = EBcc;
+		else if(MatchAndRemoveL(KImcvSubjectPrompt))
+			iHeaderPart = ESubject;
+		else if(MatchAndRemoveL(KImcvDatePrompt))
+			iHeaderPart = EDate;
+		else if(MatchAndRemoveL(KImcvMessageIdPrompt))
+			{
+			iHeaderPart = EMessageId;
+			RemoveSurroundingCharacters(KImcvLeftChevron, KImcvRightChevron, *iOutputLine);
+			}
+		else if (PriorityAndReceiptsMatchAndRemoveL(EPriority))
+			iHeaderPart=EPriority;
+		else if (PriorityAndReceiptsMatchAndRemoveL(EReturnReceiptTo))
+			iHeaderPart=EReturnReceiptTo;
+		else if(hitEof)
+			iHeaderPart = EEndOfHeader;
+		else
+			{
+			iHeaderPart = EUnknown;
+			iImRecvConvert->iMimeParser->ParseLineL(*iOutputLine);
+			}
+		}
+	else 
+		iHeaderPart = ENotFinished;
+	}
+
+
+/**
+PriorityAndReceiptsMatchAndRemoveL()
+
+@param aPriority
+*/
+TBool CLocalRfc822Token::PriorityAndReceiptsMatchAndRemoveL(THeaderPart aPriority)
+	{
+	CDesC8Array* fields=new (ELeave)CDesC8ArrayFlat(6);
+	CleanupStack::PushL(fields);
+	if (aPriority==EPriority)
+		CImcvUtils::PriorityFieldsL(*fields);
+	else if (aPriority==EReturnReceiptTo)
+		CImcvUtils::ReceiptFieldsL(*fields);
+	else
+		{
+		CleanupStack::PopAndDestroy(); //fields
+		return EFalse;
+		}
+	TInt count=fields->Count();
+	TBool matched=EFalse;
+	for (TInt i=0;i<count;i++)
+		{
+		if (MatchAndRemoveL((*fields)[i]))
+			{
+			matched=ETrue;
+			break;
+			}
+		}
+	CleanupStack::PopAndDestroy(); //fields
+	return matched;
+	}
+
+
+/**
+MatchAndRemoveL()
+
+@param aString
+@return
+TBool
+*/
+TBool CLocalRfc822Token::MatchAndRemoveL(const TDesC8& aString)
+	{
+	TInt comparison;
+	TInt stringLength = aString.Length();
+	TInt desLength = (*iOutputLine).Length();
+	TInt compareLength = stringLength > desLength ? desLength : stringLength;
+	TPtrC8 left((*iOutputLine).Left(compareLength));
+	
+	// now see whether the current line contains the search string
+	comparison = left.CompareF(aString);
+	if(!comparison)
+		{
+		// found the match string at the start of the output line, so remove it
+		// get rid of any whitespace betweebn the tag and the data while we have a chance
+		if (!i822FieldsExist)
+			i822FieldsExist=ETrue;
+		TInt whitespaceLength=0;
+		TInt maxLength=desLength-stringLength;
+		const TUint8* ptr = (*iOutputLine).Ptr();
+		while(whitespaceLength <= maxLength && (ptr[stringLength+whitespaceLength] == KImcvSP || ptr[stringLength+whitespaceLength] == KImcvTab))
+			whitespaceLength++;
+		(iOutputLine->Des()).Delete(0, stringLength+whitespaceLength);
+		}
+	return (comparison==0);
+	}
+
+//****************************************************************************************
+//             Class CLocalImRecvConvert
+//****************************************************************************************
+
+
+/**
+NewLC()
+Static factory constructor. Uses two phase construction 
+and pushes the newly created object into the Cleanup stack.
+
+@param anFs
+@param aServerEntry
+@param aMsgType
+@param aEmailServiceId
+@leave KErrNoMemory
+@return
+A pointer to the newly created CLocalImRecvConvert object.
+*/
+CLocalImRecvConvert* CLocalImRecvConvert::NewLC(RFs& anFs, CMsvServerEntry* aServerEntry, 
+												TUid aMsgType, TMsvId aEmailServiceId)
+	{
+	CLocalImRecvConvert* self = new (ELeave) CLocalImRecvConvert(anFs, aServerEntry, aMsgType, 
+																		aEmailServiceId);
+	CleanupStack::PushL(self);
+	self->ConstructL(anFs);
+	return self;
+	}
+
+
+/**
+NewL()
+Static factory constructor. Uses two phase 
+construction.
+
+@param anFs
+@param aServerEntry
+@param aMsgType
+@param aEmailServiceId
+@leave KErrNoMemory
+@return
+A pointer to the newly created CLocalImRecvConvert object.
+*/
+CLocalImRecvConvert* CLocalImRecvConvert::NewL(RFs& anFs, CMsvServerEntry* aServerEntry, 
+												TUid aMsgType, TMsvId aEmailServiceId)
+	{
+	CLocalImRecvConvert* self = CLocalImRecvConvert::NewLC(anFs, aServerEntry, aMsgType, 
+																aEmailServiceId);
+	CleanupStack::Pop();
+	return self;
+	}
+
+  
+/**
+ConstructL()
+
+@param anFs
+*/
+void CLocalImRecvConvert::ConstructL(RFs& anFs)
+	{
+	iFsSession = &anFs;  
+
+	RResourceFile resFile;
+	OpenResourceFileL(resFile, anFs);	// NB leaves if file not found
+
+	// make sure the resource file will be closed if anything goes wrong
+	// CloseResourceFile is declared in IMUTDLL.H and defined in IMUTDLL.CPP
+	TCleanupItem close( CloseResourceFile, &resFile );
+	CleanupStack::PushL( close );
+	
+	// Read iStore8BitData flag.
+	HBufC8* buf = resFile.AllocReadLC( STORE_8BIT_BODY_TEXT );
+	TResourceReader reader;
+	reader.SetBuffer(buf);
+	iStore8BitData = reader.ReadInt8();
+	CleanupStack::PopAndDestroy(buf);
+
+	buf = resFile.AllocReadLC( REMOVED_ATTACHMENT_TAG );
+	reader.SetBuffer(buf);
+	iRemovedAttachmentTag = reader.ReadTPtrC().AllocL();
+	CleanupStack::PopAndDestroy(buf);
+	
+	buf = resFile.AllocReadLC( DEFAULT_ATTACHMENT_NAME );
+	reader.SetBuffer(buf);
+	iDefaultAttachmentName = reader.ReadTPtrC().AllocL();
+	CleanupStack::PopAndDestroy(buf);
+	buf = resFile.AllocReadLC(PARTIAL_DOWNLOAD_FOOTER_MESSAGE);
+	reader.SetBuffer(buf);
+	iPartialEmailFooter = (reader.ReadTPtrC()).AllocL();
+	CleanupStack::PopAndDestroy(buf);
+	buf = NULL;
+	CleanupStack::PopAndDestroy(&resFile); // resFile (Close resfile)
+
+	// create CImHeader object to store Rfc822 header info...
+	iOutputHeader = CImHeader::NewLC();	// PushL(iHeader)
+	CleanupStack::Pop();				// iHeader
+
+	if (iStore8BitData)
+		{
+		//Create body text storage helper.
+		iBodyText = CMsvBodyText::NewL();
+		}
+	else
+		{
+		// create CRichText object to store body...
+		iParaLayer = CParaFormatLayer::NewL();
+		iCharLayer = CCharFormatLayer::NewL();
+		iOutputBody = CRichText::NewL(iParaLayer, iCharLayer);
+		}
+	
+	// Create Rfc822 filter object...
+	iRfc822Token = CLocalRfc822Token::NewLC(); // PushL(iRfc822Token)
+	CleanupStack::Pop();				  // iRfc822Token
+	iRfc822Token->SetImRecvConvert(this);
+
+	// Create converter objects...
+	iCharacterConverter = CCnvCharacterSetConverter::NewL();
+	iCharConv = CImConvertCharconv::NewL(*iCharacterConverter, anFs);
+	iHeaderConverter = CImConvertHeader::NewL(*iCharConv); 
+
+	
+	// Create MIME filter object...
+	iMimeParser = CLocalMimeParser::NewL(*this);
+	
+	
+	// logfile stuff
+	iImcvLog=NULL;
+
+#ifdef __IMUT_LOGGING	
+	TRAPD(err,iImcvLog=CImLog::NewL(KLogFilePath, EAppend));
+	UNUSED_VAR( err );
+#endif
+
+	iRootEntryId = EntryId();
+
+	iNotFinishedRfc822Header = ETrue;
+	
+	iEmailEntry = new (ELeave) TMsvEmailEntry;
+	iReceivingHeadersOnly=EFalse;	
+
+	iParent = new (ELeave) CArrayFixFlat<TParentDetails>(3);
+
+	iFirstBoundaryReached=EFalse;
+
+	ResetL();
+	
+	RECVLOG( KNewLogHeader )
+	}
+
+
+/**
+CLocalImRecvConvert()
+
+@param anFs
+@param aServerEntry
+@param aMsgType
+@param aEmailServiceId
+*/
+CLocalImRecvConvert::CLocalImRecvConvert(RFs& anFs, CMsvServerEntry* aServerEntry, 
+							   TUid aMsgType, TMsvId aEmailServiceId)
+				: iServerEntry(aServerEntry), iNewMsgType(aMsgType), iDefaultEntryType(ETextEntry), 
+			  	  iEmailServiceId(aEmailServiceId), iAttachmentFile(anFs)
+	{
+	__DECLARE_NAME(_S("CLocalImRecvConvert"));
+	}
+
+  
+/**
+~CLocalImRecvConvert()
+Destructor
+*/
+CLocalImRecvConvert::~CLocalImRecvConvert()
+	{
+	delete iEmailEntry;
+	iEmailEntry=NULL;
+	delete iOutputHeader;
+	iOutputHeader=NULL;
+	delete iBodyText;
+	iBodyText=NULL;
+	delete iBodyBuf;
+	iBodyBuf=NULL;
+	delete iParaLayer;
+	iParaLayer=NULL;
+	delete iCharLayer;
+	iCharLayer=NULL;
+	delete iOutputBody;
+	iOutputBody=NULL;
+	delete iRemovedAttachmentTag;
+	iRemovedAttachmentTag=NULL;
+	delete iDefaultAttachmentName;
+	iDefaultAttachmentName=NULL;
+	delete iRfc822Token;
+	iRfc822Token=NULL;
+	delete iMimeParser;
+	iMimeParser=NULL;
+	delete iHeaderConverter;
+	iHeaderConverter=NULL;
+	delete iCharConv;
+	iCharConv=NULL;
+	delete iCharacterConverter;
+	iCharacterConverter=NULL;
+	delete iAttachmentFullPath;
+	iAttachmentFullPath=NULL;
+	delete iImcvUtils;
+	iImcvUtils=NULL;
+	delete iParent;
+	iParent=NULL;
+	RECVLOG(KDeleted)
+	delete iImcvLog;
+	iImcvLog=NULL;
+	delete iPartialEmailFooter;
+	iPartialEmailFooter=NULL;
+	}
+
+
+/**
+ResetForHeadersL()
+This function is used in preference to ResetL() when the owner
+only wishes to create  email entries in the remote mailbox - 
+they do not wish to create any stores associated with the message
+entry
+
+*/
+void CLocalImRecvConvert::ResetForHeadersL()
+	{
+	ResetL();
+	iReceivingHeadersOnly=ETrue;
+	}
+
+/**
+ResetL()
+
+*/
+void CLocalImRecvConvert::ResetL()
+	{
+	RECVLOG(KReset) 
+	iBodyId=KMsvNullIndexEntryId;
+	iSizeOfAttachmentsRemoved=0;
+
+	User::LeaveIfError(iServerEntry->SetEntry(iRootEntryId));
+	
+	iReceivingHeadersOnly=EFalse;
+	iMessageEntryCalled=EFalse;
+	iLeaveError=KErrNone; 		
+	iCurrentMultipartFolderEntryId=0;
+
+	TParentDetails parent;
+	parent.iAttachment=parent.iMHTML=EFalse;
+	parent.iSize=0;
+	iParent->InsertL(0,parent);
+
+	delete iEmailEntry;
+	iEmailEntry=NULL;
+	iEmailEntry = new (ELeave) TMsvEmailEntry;
+
+	// "iSavingAttachments" commands this code to store attachments in files.
+	// Currently this is always set to ETrue as we intend to save all attachments
+	// However, if the user wishes to discard (ie do not save) any 
+	// attachments in incoming email messages - then this member variable
+	// may be set to EFalse by the inline accessor function "SaveAllAttachments(TBool)"
+	iSavingAttachments=ETrue;
+	iAttachmentFileState=EFileIsClosed;
+
+	// iLeaveError contains the error value of any functions that leaves (ie CRichText::InsertL)
+	// or any returned error value that generates a leave from within CLocalImRecvConvert (ie RFile::Create)
+
+	iGlobalIndent=0;
+	iLongestLine=50;
+	
+	iImPriority=EMsvMediumPriority;
+	delete iImcvUtils;
+	iImcvUtils=NULL;
+	iImcvUtils=CImcvUtils::NewL();
+
+	// reset internal date
+	iTimeDate.HomeTime();
+	
+	iMimeParser->Reset();
+	
+	iNewEntry=EFalse; //EFalse if the entry was moved to. ETrue if the entry was just created
+	iTopMessagePart=KMsvNullIndexEntryId; //A value of NULL indicates the next entry created is a main message entry
+	ResetForNewEntryL(iDefaultEntryType);
+	iMIMEPart_822Header = EFalse;
+	iPartialEmail=EFalse;
+
+	RECVLOG(KReseted) 
+	}
+
+
+/**
+ResetForNewEntryL()
+
+@param entryType
+*/
+void CLocalImRecvConvert::ResetForNewEntryL(TValidEntryType entryType)
+	{
+	RECVLOG(KResetForNewEntry) 
+
+	iFinishedHeader = EFalse;
+
+	iPreviousLineLength = 0;
+	iPreviousTrailingWhitespace = 0;
+	iLastChar = 0;
+
+	// Reset the new entry state
+	ResetForNonMimeEntryL();
+
+	// Clear the storage classes
+	iMimeParser->ResetForNewEntry();
+	iRfc822Token->Reset();
+
+	iEmailPart = KNoPart;
+	iEntryType=entryType;
+
+	if (iEntryType==EMessageEntry)
+		{
+		iEmailPart = KParentPart;
+		iMimeParser->SetMessageFolderType(EFolderTypeRFC822);
+		}
+	}
+
+
+/**
+ResetForNonMimeEntryL()
+
+*/
+void CLocalImRecvConvert::ResetForNonMimeEntryL()
+	{
+	iEntryType = ETextEntry;
+	RECVLOG(KResetForNonMimeEntry) 
+
+	iSkipData = EFalse;
+	iPrepared = EFalse;
+	iNewNonMIMEBodyPart=ETrue;
+	iEncounteredLineEndingInCarriageReturn=EFalse;
+
+	iAlgorithm = ENoAlgorithm;
+	iCurrentPartIsRichText = ETrue;	
+	CloseAttachmentFileL();
+	iEntryDataSize = 0;
+	
+	if (iStore8BitData)
+		{
+		//Create a buffer to hold the body text as it is down loaded.
+		delete iBodyBuf;
+		iBodyBuf = NULL;
+		iBodyBuf = CBufSeg::NewL(KBodyTextChunkSizeBytes);
+		}
+	else
+		{
+		iOutputBody->Reset();
+		}
+	
+	iAttachmentName.Zero();
+	iFinalLine = EFalse;
+
+	iOutputHeader->Reset();
+	iEmptyHeaderSize=iOutputHeader->DataSize();
+	RECVLOG(KResetedForNonMimeEntry) 
+	}
+
+
+/**
+ParseNextField()
+
+@param aSourceLine
+*/
+TInt CLocalImRecvConvert::ParseNextField(const TDesC8& aSourceLine) 
+	{
+	__ASSERT_DEBUG(iRootEntryId!=KMsvNullIndexEntryId, gPanic(KPanicServiceIdNotValid));
+	RECVLOG_OUT(aSourceLine);
+
+	// If we are temporarily on the null entry then move back to the entry we are working on
+	if ((iLeaveError == KErrNone) && (iServerEntry->Entry().Id() == KMsvNullIndexEntryId))
+		iLeaveError = iServerEntry->SetEntry(iSavedEntryId);
+
+	if(iLeaveError==KErrNone)
+		TRAP(iLeaveError, ParseNextLineL(aSourceLine));		
+
+	// Save the current entry id for later.
+	if (iLeaveError==KErrNone)
+		iSavedEntryId = iServerEntry->Entry().Id();
+
+	TUid type = iServerEntry->Entry().iType;
+	if( type != KUidMsvMessageEntry    &&
+		type != KUidMsvEmailTextEntry  &&
+		type != KUidMsvEmailHtmlEntry  &&
+		type != KUidMsvAttachmentEntry)
+		{
+	// Set the current id to null so that we aren't locking any folders
+	iServerEntry->SetEntry(KMsvNullIndexEntryId);
+		}
+
+	return iLeaveError;
+	}
+
+
+/**
+ParseNextLineL()
+
+@param aSourceLine
+*/
+void CLocalImRecvConvert::ParseNextLineL(const TDesC8& aSourceLine)
+	{
+	iParsedMimeBoundaryLast=0;
+	if(!iFinishedHeader)
+		{
+		// start by getting the next token from the header
+		iRfc822Token->ParseNextLineL(aSourceLine);
+
+		switch(iRfc822Token->iHeaderPart)
+			{
+			case CLocalRfc822Token::EUnknown:
+			case CLocalRfc822Token::ENotFinished:
+				RECVLOG(KPartLine)
+				break;
+			case CLocalRfc822Token::EFrom:
+				iOutputHeader->SetFromL(*iRfc822Token->OutputLine());
+				LOGGING(KFound,KImcvFromPrompt);
+				break;
+			case CLocalRfc822Token::EReplyTo:
+				iOutputHeader->SetReplyToL(*iRfc822Token->OutputLine());
+				LOGGING(KFound,KImcvReplyToPrompt);
+				break;
+			case CLocalRfc822Token::ETo:
+				ParseRecipientListL(iOutputHeader->ToRecipients());
+				LOGGING(KFound,KImcvToPrompt);
+				break;
+			case CLocalRfc822Token::ECc: 
+				ParseRecipientListL(iOutputHeader->CcRecipients());
+				LOGGING(KFound,KImcvCcPrompt);
+				break;
+			case CLocalRfc822Token::EBcc: 
+				ParseRecipientListL(iOutputHeader->BccRecipients());
+				LOGGING(KFound,KImcvBccPrompt);
+				break;
+			case CLocalRfc822Token::ESubject:
+				iOutputHeader->SetSubjectL(*iRfc822Token->OutputLine());
+				LOGGING(KFound,KImcvSubjectPrompt);
+				break;
+			case CLocalRfc822Token::EDate:
+				iRfc822Date.ParseDateField(*iRfc822Token->OutputLine() , iTimeDate); 
+				if (iEmailEntry->Id() != iTopMessagePart)
+					{
+					iEmailEntry->iDate = iTimeDate;
+					}
+				LOGGING(KFound,KImcvDatePrompt);
+				break;
+			case CLocalRfc822Token::EMessageId:
+				iOutputHeader->SetImMsgIdL(*iRfc822Token->OutputLine());
+				LOGGING(KFound,KImcvMessageIdPrompt);
+				break;
+			case CLocalRfc822Token::EPriority:
+				iImPriority=iImcvUtils->EvaluatePriorityText(*iRfc822Token->OutputLine());
+				LOGGING(KFound,KImcvPriorityPrompt);
+				break;
+			case CLocalRfc822Token::EReturnReceiptTo:
+				iOutputHeader->SetReceiptAddressL(*iRfc822Token->OutputLine());
+				LOGGING(KFound,KReturnReceiptTo);
+				break;
+			case CLocalRfc822Token::EEndOfHeader:
+				// the next line goes in the body part
+				iFinishedHeader = ETrue;
+				RECVLOG(KEndOFHeader)
+				break;
+			default:
+				RECVLOG(KEndOFHeader)
+				break;
+			}
+
+
+		if(iRfc822Token->iHeaderPart != CLocalRfc822Token::ENotFinished)
+			{
+			// Now that we've used the data, we also need to clear the output line from the tokeniser....
+			iRfc822Token->OutputLine()->Des() = KNullDesC8;
+
+			// whatever part we just read, we may also have read the empty line that separates
+			// the header from the body
+			if((iFinishedHeader = iRfc822Token->LastToken()) != EFalse)	//iFinishedHeader set to 1 on CRLF-
+				{
+				RECVLOG(KLastToken);
+				iNotFinishedRfc822Header = EFalse;
+
+				iHeaderConverter->SetMessageType(iMimeParser->MessageIsMime());
+				iHeaderConverter->DecodeAllHeaderFieldsL(*iOutputHeader);
+
+				if (iMimeParser->MessageIsMime())
+					EndOfHeaderMIMEProcessingL();
+				else
+					EndOfHeaderProcessingL();
+
+				if (iStore8BitData)
+					{
+					iBodyText->SetDefaultCharacterSet(iCharConv->SystemDefaultCharset());
+					if ( iMimeParser->MessageIsMime() && iMimeParser->ContentType()==EMimeText )
+						iBodyText->SetCharacterSet(iMimeParser->CurrentCharsetL());
+					else
+						iBodyText->SetCharacterSet(0);
+					}
+				else
+					{
+					// Get charset for decoding.
+					if ( iMimeParser->MessageIsMime() && iMimeParser->ContentType()==EMimeText )
+						iCharConv->PrepareToConvertToFromOurCharsetL(iMimeParser->CurrentCharsetL());
+					else
+						iCharConv->PrepareToConvertToFromOurCharsetL(iCharConv->SystemDefaultCharset());
+					}
+				}
+			}
+		}
+	else if (iReceivingHeadersOnly == EFalse)
+		{	
+		//Set to EFalse when a single line is to be skipped (ie boundary line)
+		iCommitLine=ETrue; 
+
+		// read one line of the message body if I am processing a whole email message
+		if(iMimeParser->MessageIsMime())
+			ParseMimeLineL(aSourceLine);
+		else
+			ParseBodyLineL(aSourceLine);	
+
+		if((iCommitLine) && (!iSkipData))
+			DecodeAndStoreLineL(aSourceLine);
+		}
+	}
+
+
+/**
+MessageEntryDetailsL()
+
+@return
+*/
+TMsvEmailEntry CLocalImRecvConvert::MessageEntryDetailsL()
+	{
+	iMessageEntryCalled=ETrue;
+	CloseAttachmentFileL();
+
+	// A message requiring manual termination and not part way through a MIME part header
+	if( iTopMessagePart==EntryId() && iFinishedHeader) 
+		StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader);
+	else
+		{
+		User::LeaveIfError(iServerEntry->SetEntry(iTopMessagePart));         
+		delete iEmailEntry;
+		iEmailEntry=NULL;
+		iEmailEntry = new (ELeave) TMsvEmailEntry(iServerEntry->Entry());
+		}
+		
+	return *iEmailEntry;
+	}
+
+
+/**
+MessageCompleteL()
+
+@param aEmailEntry
+*/
+void CLocalImRecvConvert::MessageCompleteL(TMsvEmailEntry aEmailEntry)
+	{
+	// Restore the entry context
+	if (iServerEntry->Entry().Id() == KMsvNullIndexEntryId)
+		User::LeaveIfError(iServerEntry->SetEntry(iSavedEntryId));
+
+	__ASSERT_DEBUG(iMessageEntryCalled, gPanic(KPanicMessageEntryNotCalled));
+	__ASSERT_DEBUG(aEmailEntry.Id()==iTopMessagePart, gPanic(KPanicMessageEntryIdHasChanged)); // Id should be set to iTopMessagePart
+
+	// Called ResetL() to reset object instead of ResetForHeadersL()
+	__ASSERT_DEBUG(iReceivingHeadersOnly, gPanic(KPanicIncorrectResetState)); 
+
+	if(iEmailEntry)
+		{
+		if (iEmailEntry->Id())
+			{
+			if(iLeaveError==KErrNone)
+				{
+				// a remote email header cannot have any attachments or be marked as complete...
+				aEmailEntry.SetAttachment(EFalse);
+				aEmailEntry.SetMHTMLEmail(EFalse);
+				aEmailEntry.SetComplete(EFalse);
+				User::LeaveIfError(iServerEntry->ChangeEntry(aEmailEntry));
+				RECVLOG(KHeaderComplete)
+				}
+			else
+				{
+				if (!iPopulateMessage)
+					{
+					TMsvId currentId = EntryId();
+					User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent()));			
+					User::LeaveIfError(iServerEntry->DeleteEntry(currentId));
+					}
+				User::Leave(iLeaveError);
+				}
+			}
+		}
+
+	// Save the entry context and move it to null so that we're not locking any folders
+	iSavedEntryId = iServerEntry->Entry().Id();
+	User::LeaveIfError(iServerEntry->SetEntry(KMsvNullIndexEntryId));
+	}
+
+
+/**
+MessageCompleteL()
+
+@param aPartialDownload
+*/
+void CLocalImRecvConvert::MessageCompleteL(TBool aPartialDownload)
+	{
+	iPartialEmail=aPartialDownload;
+	MessageCompleteL();
+	}
+  
+
+/**
+MessageCompleteL()
+*/
+void CLocalImRecvConvert::MessageCompleteL()
+	{
+	// Restore the entry context
+	RECVLOG(KStartMessageComplete)
+	if (iServerEntry->Entry().Id() == KMsvNullIndexEntryId)
+		User::LeaveIfError(iServerEntry->SetEntry(iSavedEntryId));
+
+	if (iParsedMimeBoundaryLast==EFalse && iAttachmentFileState==EFileIsOpen && iPartialEmail!=EFalse)
+		{
+		iAttachmentFileState=EFileTopIncomplete;
+		}
+
+	CloseAttachmentFileL();
+
+	if(!iEmailEntry->Id())
+		return;
+
+	if(iLeaveError!=KErrNone)
+		{
+		User::Leave(iLeaveError);
+		}
+
+	if (EntryId()!=iTopMessagePart)
+		{
+		iEmailEntry->SetComplete(ETrue);
+		StoreEntryStreamsL(KStoreBodyText);
+		MoveToParentEntryL();
+
+		if( iTopMessagePart==EntryId() && iFinishedHeader) 
+			{
+			iEmailEntry->SetVisible(ETrue);
+			iEmailEntry->SetInPreparation(EFalse);
+			iEmailEntry->SetBodyTextComplete(ETrue);
+			iEmailEntry->SetComplete(ETrue);
+
+			// Main message.
+			StoreMessageEntryDetailsL();
+			return;
+			}
+		else if(iEmailEntry->iType == KUidMsvMessageEntry)
+			{
+			StoreMessageEntryDetailsL();
+			MoveToParentEntryL();
+			StoreMessageEntryDetailsL();
+			}
+		}
+
+	// A message requiring manual termination and not part way through 
+	// a MIME part header.
+
+	User::LeaveIfError(iServerEntry->SetEntry(iTopMessagePart));         
+	if(NULL!=iEmailEntry)
+		{
+		delete iEmailEntry;
+		iEmailEntry=NULL;
+		}
+	iEmailEntry = new (ELeave) TMsvEmailEntry(iServerEntry->Entry());
+	iEmailEntry->SetVisible(ETrue);
+	iEmailEntry->SetInPreparation(EFalse);
+	iEmailEntry->SetComplete(ETrue);
+	iEmailEntry->SetBodyTextComplete(ETrue);
+
+	iEmailEntry->SetAttachment(iParent->At(0).iAttachment);
+	iEmailEntry->SetMHTMLEmail(iParent->At(0).iMHTML);
+
+	if(iEmailEntry->MHTMLEmail() == EFalse && iEmailEntry->Attachment() == EFalse && iRelatedAttachments !=EFalse)
+		{
+		iEmailEntry->SetAttachment(ETrue);
+		}
+	iRelatedAttachments=EFalse;
+	
+	iEmailEntry->iSize=iParent->At(0).iSize;
+	iEmailEntry->SetMessageFolderType(iParent->At(0).iFolder);
+
+	User::LeaveIfError(iServerEntry->ChangeEntry(*iEmailEntry));
+
+	// Save the entry context and move it to null so that we're not locking any folders
+	iSavedEntryId = iServerEntry->Entry().Id();
+	User::LeaveIfError(iServerEntry->SetEntry(KMsvNullIndexEntryId));
+	RECVLOG(KMessageComplete)
+	}
+
+
+/**
+PrepareDecoder()
+
+*/
+void CLocalImRecvConvert::PrepareDecoder()
+	{
+	switch(iMimeParser->ContentEncoding())
+		{
+		case EEncodingTypeNone:
+		case EEncodingType7Bit:
+		case EEncodingType8Bit:
+			iAlgorithm = ENoAlgorithm;
+			RECVLOG(KCollectingData7)
+			break;
+		case EEncodingTypeQP:
+			iAlgorithm = EQPDecode;
+			RECVLOG(KCollectingDataQP)
+			break;
+		case EEncodingTypeBASE64:
+			iAlgorithm = EBase64Decode;
+			RECVLOG(KCollectingBase64)
+			break;	
+		case EEncodingTypeUU:
+			iAlgorithm = EUUDecode;
+			RECVLOG(KCollectingUU)
+			break;	
+		default:	// EEncodingTypeUnknown, EEncodingTypeNone, EEncodingTypeBinary	
+			iAlgorithm = ENoAlgorithm;
+			break;
+		} // switch
+	iPrepared = ETrue;
+	}
+
+  
+/**
+DecodeAndStoreLineL()
+
+@param aSourceLine
+*/
+void CLocalImRecvConvert::DecodeAndStoreLineL(const TDesC8& aSourceLine)
+	{
+	TInt sourceLineLength=aSourceLine.Length();
+	TBool blankLine = EFalse;
+
+	// create a temporary buffer to write the decoded data into. 
+	// This will always be as long as or shorter than the original.
+	
+	HBufC8* convertedLine = HBufC8::NewLC(sourceLineLength+KConversionRemainderLength);
+	TPtr8 des(convertedLine->Des());
+
+	if(iFinalLine)						
+		{
+		// We've got to the end of encoded section, so set in order to skip all
+		// trailing empty lines & postamble until we reach the next MIME/UUE boundary
+
+		RECVLOG(KSkippingData)
+		iSkipData = ETrue;
+		}
+	else
+		{
+		switch(iAlgorithm)
+			{
+			case EBase64Decode:
+				RECVLOG(KDecodingBase64);
+
+				iB64Codec.Decode(aSourceLine, des); 
+				RECVLOG(KDecodedBase64);
+				break;
+			case EUUDecode:
+				RECVLOG(KDecodingUU);
+				//used to end a Mime encoded UU section else no purpose
+				iFinalLine=(aSourceLine.CompareF(KImcvUueLastLine)==0);	
+				if(iFinalLine)
+					iCommitLine=EFalse;
+				else
+					{
+					//returns True on invalid data
+					if((!iFinalLine)&&(iUUCodec.Decode(aSourceLine, des))) 
+						{
+						RECVLOG(KUUEDataCorrupt)
+						if(iAttachmentFileState==EFileIsOpen)
+							{
+							iAttachmentFileState=EFileIsCorrupt;
+							iLeaveError=KErrCorrupt;
+							CloseAttachmentFileL();
+							}
+						else
+							User::Leave(KErrCorrupt);
+						}
+					}
+				RECVLOG(KDecodedUU);
+				break;
+			case EQPDecode:
+				RECVLOG(KDecodingQP);
+				iQPCodec.Decode(aSourceLine, des);
+				RECVLOG(KDecodedQP);
+				break;
+			case ENoAlgorithm:
+				{				
+				// If the data is to be stored in CRichText clean it up before copying it to the buffer
+				TLex8 lex(aSourceLine);
+				blankLine=ETrue;
+				while(blankLine && !lex.Eos())
+					{
+					blankLine = (lex.Peek()==KImcvSP || lex.Peek()==KImcvTab 
+						|| lex.Peek()==KImcvCR || lex.Peek()==KImcvLF);
+					lex.Inc();
+					}
+				des.Copy(aSourceLine);
+				}				
+			default:
+				break;
+			} // end switch
+	
+			// Commits the decoded data to the appropriate store or trashes the line 
+			if(iCommitLine) 
+				{
+				if (iLeftOver.Length())
+					{
+					des.Insert(0, iLeftOver);
+					iLeftOver.SetLength(0);
+					}
+
+				if(iCurrentPartIsRichText)
+					{
+					if (iStore8BitData)
+						iBodyBuf->InsertL(iBodyBuf->Size(), des);
+					else
+						WriteToBodyL(des, blankLine);
+					}
+				else
+					WriteToAttachmentL(des);
+				}
+		} // end else
+
+	CleanupStack::PopAndDestroy(); // convertedLine
+	}
+
+
+/**
+ParseMimeLineL()
+
+@param aSourceLine
+*/
+void CLocalImRecvConvert::ParseMimeLineL(const TDesC8& aSourceLine)
+	{
+
+	if(!iMimeParser->IsBoundary(aSourceLine))
+		{
+		if(!iPrepared) // first line of the body
+			{		
+			if (iMIMEPart_822Header)
+				{
+				// missing 822 part header. Revert to default.
+				EndOfHeaderMIMEProcessingL();
+				iMIMEPart_822Header=EFalse;
+				}
+
+			PrepareDecoder();
+			}
+
+		if (CheckUUEStartL(aSourceLine))
+			{
+			iAlgorithm=EUUDecode;
+			iCommitLine=EFalse;
+			}
+		}
+	else
+		{
+		// found a MIME boundary so store the current parts data and update its entry.
+
+		RECVLOG(KFoundMIMEBoundary)
+		iCommitLine=EFalse; //Dont store this line as its a boundary.
+
+		if(!iFirstBoundaryReached && iEntryType==EFolderEntry)
+			{
+			iFirstBoundaryReached=ETrue;
+			if (!iCurrentMultipartFolderEntryId)
+				iCurrentMultipartFolderEntryId = EntryId();
+			MoveToParentEntryL();
+			ResetForNewEntryL(iDefaultEntryType);
+			return; // First boundary encountered.
+			}
+
+		CloseAttachmentFileL();
+		if(iNewEntry)
+			{
+			iEmailEntry->SetComplete(ETrue);
+			iEmailEntry->SetBodyTextComplete(ETrue);
+			StoreEntryStreamsL(KStoreMIMEHeader | KStoreBodyText);
+			if (iBodyId==KMsvNullIndexEntryId)
+				{
+				iBodyId=iEmailEntry->Id();
+				}
+			}
+
+		iSkipData = EFalse;
+
+		// check whether we just found the terminating boundary...
+		if(iMimeParser->IsTerminatingBoundary())
+			{
+			RECVLOG(KRemoveBoundary);
+			iMimeParser->RemoveBoundary();
+			RECVLOG(KRemovedBoundary);
+			iMIMEPart_822Header = EFalse;
+
+			if (EntryId()!=iTopMessagePart)
+				{
+				if(iEmailPart==KParentPart)
+					{
+					// rfc822 message which is not  not multipart.
+					iEmailPart=KNoPart;
+					MoveToParentEntryL();				
+
+					// Embedded message
+					iEmailEntry->SetComplete(ETrue);
+					iEmailEntry->SetBodyTextComplete(ETrue);
+					StoreMessageEntryDetailsL();
+					}
+				else if (iEmailEntry->iType==KUidMsvMessageEntry)
+					{
+					// Moving up from a multi embedded rfc822 message.
+					iEmailEntry->SetComplete(ETrue);
+					iEmailEntry->SetBodyTextComplete(ETrue);
+					StoreMessageEntryDetailsL();
+					}
+				}
+
+			MoveToParentEntryL();
+			iEntryDataSize = iEmailEntry->iSize;
+
+			if(iServerEntry->Entry().iType == KUidMsvFolderEntry)
+				{
+				iCurrentMultipartFolderEntryId = EntryId();
+				}
+			else if (EntryId()!=iTopMessagePart)
+				{
+				if(iEmailEntry->iType == KUidMsvMessageEntry)
+					{
+					iEmailEntry->SetComplete(ETrue);
+					iEmailEntry->SetBodyTextComplete(ETrue);
+					StoreMessageEntryDetailsL();
+					}
+				MoveToParentEntryL();
+				iEntryDataSize += iEmailEntry->iSize;
+				}
+
+			if(!iNewEntry)
+				ResetForNonMimeEntryL();
+
+			RECVLOG(KSkippingData)
+			iSkipData = ETrue;
+			iDefaultEntryType=ETextEntry;
+			}
+		else // if regular boundary
+			{ 
+			RECVLOG(KSectionHeader)
+			if(iEmailPart==KParentPart && EntryId()!=iTopMessagePart)
+				{
+				// rfc822 message which is not  not multipart.
+				iEmailPart=KNoPart;
+				MoveToParentEntryL();
+				// Embedded message
+				iEmailEntry->SetComplete(ETrue);
+				iEmailEntry->SetBodyTextComplete(ETrue);
+				StoreMessageEntryDetailsL();
+				}
+
+			if (!iCurrentMultipartFolderEntryId && iEmailPart==KNoPart)
+				MoveToParentEntryL();
+
+			ResetForNewEntryL(iDefaultEntryType);
+			}
+		}
+	}
+
+  
+/**
+EndOfHeaderProcessingL()
+
+*/
+void CLocalImRecvConvert::EndOfHeaderProcessingL()
+	{	
+	CreateEntryL();
+	StoreEntryStreamsL(KStore822Header);
+	iEntryDataSize = 0;
+	}
+
+
+/**
+EndOfHeaderMIMEProcessingL()
+Have just finished processing header, what next.. ?
+All MIME entry entry creation takes place here.
+
+*/
+void CLocalImRecvConvert::EndOfHeaderMIMEProcessingL()
+	{	
+	if (iMimeParser->IsMessageDigest())
+		iDefaultEntryType=EMessageEntry;
+
+	if (iMimeParser->VCard() || iMimeParser->VCalendar())
+		{
+		iCurrentPartIsRichText = EFalse;	
+		iEntryType = EAttachmentEntry;
+		}
+
+	// Don't create entry if an embedded message header. 
+	if (!iMIMEPart_822Header || iTopMessagePart==EntryId() )
+		CreateEntryL(); 
+
+	if (!iMIMEPart_822Header && !iMimeParser->MimeFieldsExist() && iDefaultEntryType==EMessageEntry)
+		{
+		// MIME header not present. So expecting embedded 822 header
+		iEmailPart = KParentPart;
+		iMIMEPart_822Header=ETrue;
+		iEntryType=ETextEntry;
+		}
+	else if (iMimeParser->ContentType()==EMimeMessage)
+		{
+		// Having received A MIME header of type message/..., store and continue.
+
+		StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader);
+		iMimeParser->ResetForNewEntry();
+		iMIMEPart_822Header=ETrue;
+
+		// Non-multipart embedded message.
+		if (iTopMessagePart==EntryId())
+			{
+			iEntryType = EMessageEntry;
+			ResetForNonMimeEntryL();
+			}
+		else
+			iEntryType=ETextEntry;
+		}
+	else if ( (iTopMessagePart==EntryId() || iMIMEPart_822Header)&&(!iReceivingHeadersOnly) )
+		{
+		// Main rfc822 header or embedded header.
+
+		TImEmailFolderType folderType=iMimeParser->MessageFolderType();
+		if (iMIMEPart_822Header)
+			{
+			iEmailEntry->iDetails.Set(iOutputHeader->From());
+			iEmailEntry->iDescription.Set(iOutputHeader->Subject());
+			iMIMEPart_822Header=EFalse;
+			}
+
+		if (iRfc822Token->i822FieldsExist)
+			StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader);
+		else
+			StoreEntryStreamsL(KStoreMIMEHeader);
+
+
+		if (iMimeParser->ContentType()==EMimeMultipart)
+			{	
+			RECVLOG(KSkippingData)
+			ResetForNewEntryL(EFolderEntry);
+			iMimeParser->SetMessageFolderType(folderType);
+			iSkipData = ETrue;
+			iEmailPart = KMultiPart;
+			iCurrentMultipartFolderEntryId=0;
+			}
+		else 
+			{
+			// Not multipart but some header data to store.
+			iEntryDataSize = 0;
+			}
+
+		CreateEntryL();
+		}
+
+	iRfc822Token->i822FieldsExist=EFalse;
+	iMimeParser->ResetMimeFieldsExist();
+	
+	iFinishedHeader = iMIMEPart_822Header ? EFalse:ETrue;
+	iSkipData = iMimeParser->ContentType()==EMimeMultipart ? ETrue:EFalse;
+	}
+
+
+/**
+ParseBodyLineL()
+Non Mime body parsing
+
+@param aSourceLine
+*/
+void CLocalImRecvConvert::ParseBodyLineL(const TDesC8& aSourceLine)
+	{
+	TInt len=aSourceLine.Length();
+	iTopPartialDownloadCounter+=len; // added for TOP. increment the number of bytes of the attachment downloaded so far
+	TMsvId id=0;
+	if (iBodyId==KMsvNullIndexEntryId)
+		{
+		iBodyId=iEmailEntry->Id();
+		}
+
+	// first check whether this line is a UUEncode start boundary
+	if(CheckUUEStartL(aSourceLine)) 
+		{
+		RECVLOG(KFoundUUEStartBoundary)
+		TFileName tempStore = iAttachmentName;
+		id = EntryId();
+		if (!iNewNonMIMEBodyPart || id!=iTopMessagePart) // main message entry
+			{
+			iEmailEntry->SetComplete(ETrue);
+			iEmailEntry->SetBodyTextComplete(ETrue);
+			StoreEntryStreamsL(KStoreBodyText);
+			}
+		MoveToParentEntryL();
+		if ( !CreateNonMIMEFolderEntryL(id))
+			ResetForNonMimeEntryL();
+			
+		iEntryType = EAttachmentEntry;
+		CreateEntryL();
+		SetAttachmentName(tempStore);
+		
+		iCurrentPartIsRichText = EFalse;
+		iAlgorithm=EUUDecode;
+		iCommitLine=EFalse;
+		if(!iSavingAttachments)
+			{
+			RECVLOG(KSkippingData)
+			iSkipData=ETrue;
+			}
+		iNewNonMIMEBodyPart=EFalse;
+		}
+	else if(aSourceLine.CompareF(KImcvUueEnd)==0) // Checks for the UUEncode end boundary
+		{
+		RECVLOG(KFoundUUEEndBoundary)
+		CloseAttachmentFileL();
+		StoreEntryDataL();
+		MoveToParentEntryL();
+		iSkipData = EFalse;
+		iCommitLine=EFalse;
+		iNewNonMIMEBodyPart=ETrue; 
+		}
+	else if (iNewNonMIMEBodyPart && !( len==2 && aSourceLine[0]==KImcvCR && aSourceLine[1]==KImcvLF ))
+		{
+		id = EntryId();
+		if (!iNewNonMIMEBodyPart || id!=iTopMessagePart)
+			{
+			iEmailEntry->SetComplete(ETrue);
+			iEmailEntry->SetBodyTextComplete(ETrue);
+			StoreEntryStreamsL(KStoreBodyText);
+			}
+		MoveToParentEntryL();
+		if ( !CreateNonMIMEFolderEntryL(id))
+			ResetForNonMimeEntryL();
+		iAlgorithm=ENoAlgorithm;
+		iEntryType = ETextEntry;
+		CreateEntryL();
+		iNewNonMIMEBodyPart=EFalse;
+		}	
+	}
+
+
+/**
+CreateNonMIMEFolderEntryL()
+
+@param aCurrentId
+@return
+*/
+TBool CLocalImRecvConvert::CreateNonMIMEFolderEntryL(TMsvId aCurrentId)
+	{
+	if ( aCurrentId==iTopMessagePart || iCurrentMultipartFolderEntryId )
+		return EFalse;
+
+	// Create Folder.
+	iServerEntry->SetEntry(iTopMessagePart); 
+	iEmailPart = KMultiPart;
+	iEntryType = EFolderEntry;
+	CreateEntryL();
+
+	// Move existing child entry under folder.
+	TMsvId destId = EntryId();
+	iServerEntry->SetEntry(iTopMessagePart); 
+	iServerEntry->MoveEntryWithinService(aCurrentId, destId);
+	User::LeaveIfError(iServerEntry->SetEntry(aCurrentId));
+	User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent())); 
+
+	// Create MimeHeader.
+	iEmailEntry->SetMessageFolderType(iMimeParser->MessageFolderType());
+
+	RECVLOG(KResetForNewEntry) 
+
+	iMimeParser->ResetForNewEntry();
+	
+	if (iStore8BitData)
+		{
+		//Create a buffer to hold the body text as it is down loaded.
+		delete iBodyBuf;
+		iBodyBuf = NULL;
+		iBodyBuf = CBufFlat::NewL(KBodyTextChunkSizeBytes);
+		}
+	else
+		{
+		iOutputBody->Reset();
+		}
+		
+	ResetForNonMimeEntryL(); 
+	RECVLOG(KResetedForNewEntry) 
+	return ETrue;
+	}
+
+
+/**
+CreateAttachmentL()
+
+@return
+*/
+TBool CLocalImRecvConvert::CreateAttachmentL()
+	{
+	// Get and set Attachment File path
+	TFileName filepath;
+	// added to support TOP command. Reset the download counter each time we have a new
+	// attachment
+	iTopPartialDownloadCounter = 0; 
+
+	// Need to check that the complete filename: iAttachmentFullPath & iAttachmentName	
+	// does not exceed 256 characters. Greater than this and it cannot be saved as a file.
+
+	TBool addExtension=ETrue;
+	if(iAttachmentName.Length() == 0)	//i.e. problem with Attachment name
+	    {
+		// No filename present. Generate one.
+		if(iMimeParser->ContentDescription().Length()!=0)
+			{
+			// Use ContentDescription() as default name 
+			// - as this is more informative than the default
+
+			TLex sourceLineLex = iMimeParser->ContentDescription();
+			ExtractFilename(sourceLineLex, iAttachmentName);
+			}
+		else
+			iAttachmentName = *iDefaultAttachmentName;
+		}
+	else
+		{
+		// Filename present. Check it is valid.
+		ReplaceInvalidCharacters(iAttachmentName);
+		if (iAttachmentName.Locate(KImcvFullStop)!=KErrNotFound)
+			addExtension=EFalse;
+		}
+	if (addExtension)
+		AddFileExtension();
+
+	CMsvStore* store = iServerEntry->EditStoreL(); 
+	CleanupStack::PushL(store);
+	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
+	RFile file; 
+	store->AttachmentManagerExtensionsL().CreateAttachmentL(iAttachmentName,file,attachment);
+	
+	iAttachmentFile.SetFileHandle(file,TImAttachmentFile::EImFileWrite);
+	store->CommitL();
+	CleanupStack::PopAndDestroy(store); // store
+
+	if(KErrNone!=iLeaveError)
+		{
+		iAttachmentFileState=EFileFailedToOpen;
+		CloseAttachmentFileL();
+		return EFalse;
+		}
+
+	iAttachmentFileState=EFileIsOpen;
+	return ETrue;
+	}
+
+
+/**
+WriteToAttachmentL()
+
+@param text
+*/
+void CLocalImRecvConvert::WriteToAttachmentL(const TDesC8& text)
+	{
+	if ( (iAttachmentFileState==EFileIsClosed || iAttachmentFileState==EFileNotOpen) 
+		&& CreateAttachmentL() && iEntryType!=EHtmlEntry)
+			iEmailEntry->SetAttachment(ETrue);
+	
+	if(iAttachmentFileState!=EFileIsOpen || !text.Length())
+		{
+		RECVLOG(KSkippingData)
+		iSkipData = ETrue;
+		}
+
+	// write decoded data into a file if there is any data there to write.
+
+	RECVLOG(KWritingToFile)
+
+	// Convert text before writing to attachment.
+	
+	// Store as Binary files..
+	iLeaveError=iAttachmentFile.WriteFile(text);
+
+	if(KErrNone==iLeaveError)
+		iEntryDataSize += text.Length();
+	else	
+		{
+		// the file write failed (eg.there is no space left), set new file state and skip 
+		RECVLOG(KFailedToWriteToFile)
+		iAttachmentFileState=EFileIsIncomplete;
+		CloseAttachmentFileL();
+		}
+	RECVLOG(KWroteToFile)
+	}
+
+
+/**
+CloseAttachmentFileL()
+
+*/
+void CLocalImRecvConvert::CloseAttachmentFileL()
+	{
+	// If anything bad happened a message is sent to the parts CRichText
+	switch(iAttachmentFileState)
+		{
+		case EFileNotOpen:
+			iAttachmentFileState=EFileIsClosed;
+		case EFileIsClosed: //do nothing - this shouldn't happen	
+			break;
+		case EFileIsOpen:		//successful attachment decode
+			RECVLOG(KClosingAttachFile)
+			iAttachmentFile.CloseFile();
+			iAttachmentFileState=EFileIsClosed;
+			iEmailEntry->SetComplete(ETrue);
+			break;
+		case EFileIsIncomplete:		// file write failed
+		case EFileFailedToOpen:		// can't open attach file
+		case EFileIsCorrupt:		// UU data being decoded is corrupt
+			RECVLOG(KClosingAttachFile)
+			iAttachmentFile.CloseFile();	//file has to be closed before it can be deleted
+			RECVLOG(KDeletingAttachFile)
+			{ 
+			// NOTE - need the braces to stop error for re-definition of store
+			CMsvStore* store = iServerEntry->EditStoreL(); 
+			CleanupStack::PushL(store);
+		
+			// Remove the attachment and commit the store.	
+			store->AttachmentManagerExtensionsL().RemoveAttachmentL(0);
+			store->CommitL();
+			CleanupStack::PopAndDestroy(store);
+			}
+			iEmailEntry->SetAttachment(EFalse);
+			iAttachmentFileState=EFileIsClosed;
+			RECVLOG(KDeletedAttachFile)
+
+			if(iSavingAttachments && !iStore8BitData)
+				{
+				WriteToBodyL(KImcvParagraph);
+				WriteToBodyL(*iRemovedAttachmentTag);	//lost attachment - notify user
+				TBuf8<KMaxFileName> name;
+				name.Copy(iAttachmentName); //16 to 8
+				WriteToBodyL(name);
+				WriteToBodyL(KImcvParagraph);
+				}
+
+			User::Leave(iLeaveError);
+			// Skip any remaining encoded data in message
+			break;
+		case EFileTopIncomplete:
+			RECVLOG(KClosingAttachFile)
+			iAttachmentFile.CloseFile();	//file has to be closed before it can be deleted
+
+			// added for TOP command. Ensure we know correct amount of data for later redownload
+			iSizeOfAttachmentsRemoved+=iTopPartialDownloadCounter;
+
+
+			RECVLOG(KDeletingAttachFile)
+			{ 
+			// NOTE - need the braces to stop error for re-definition of store
+			CMsvStore* store = iServerEntry->EditStoreL(); 
+			CleanupStack::PushL(store);
+		
+			// Remove the attachment and commit the store.	
+			store->AttachmentManagerExtensionsL().RemoveAttachmentL(0);
+			store->CommitL();
+			CleanupStack::PopAndDestroy(store);
+			}
+			iEmailEntry->SetAttachment(EFalse);
+			iAttachmentFileState=EFileIsClosed;
+			RECVLOG(KDeletedAttachFile);
+			TMsvId id = EntryId();
+			TMsvId parent = iServerEntry->Entry().Parent();
+			MoveToParentEntryL();
+			TMsvId setTo=iServerEntry->Entry().Id();
+			if(setTo!=parent)
+				{
+				iServerEntry->SetEntry(parent);
+				}
+			User::LeaveIfError(iServerEntry->DeleteEntry(id));			
+			iServerEntry->SetEntry(setTo);
+			break;
+		}
+	}
+
+
+/**
+LineIsAllWhitespace()
+
+@return
+*/
+TBool CLocalImRecvConvert::LineIsAllWhitespace()
+	{// returns 1 if all elements of the current line are whitespace
+	TBool	spaceFound = 1;
+	TLex8	aLex = iLineLex;
+
+	while (spaceFound && aLex.Peek()!=KImcvCR)
+		{
+		if (aLex.Peek()==KImcvSP)
+			{
+			spaceFound = 1;
+			aLex.Inc();
+			}	
+		else spaceFound = 0;
+		}
+	return (spaceFound);
+	}
+
+  
+/**
+CheckUUEStartL()
+
+@param aSourceLine
+@return
+*/
+TBool CLocalImRecvConvert::CheckUUEStartL(const TDesC8& aSourceLine)
+	{
+	// Checks if the descriptor contains the UUE begin header
+	// Extracts the file name if it is
+	
+	TInt sourceLength = aSourceLine.Length();
+	if(sourceLength < KImcvUueStart().Length()+3) // can't be it, it's not long enough
+		return EFalse;
+
+	if(!aSourceLine.Left(KImcvUueStart().Length()).CompareF(KImcvUueStart)) // start of line might be UUE boundary
+		{
+		// we also need to check that the next three chars are numbers - Unix file access code
+		const TUint8* _ptr = aSourceLine.Ptr();
+		TInt length=KImcvUueStart().Length();// this defines length as 6 ie. "b e g i n  " 
+		if(TChar(_ptr[length]).IsDigit() && TChar(_ptr[length+1]).IsDigit() && TChar(_ptr[length+2]).IsDigit())
+			{
+			// we've found 'begin ###' at the start of a line -
+			// that's about as good as we can do 
+			// now grab the file name and paste it into the document
+			// Extract filename from string, removing any surrounding quote marks
+
+			HBufC16* pBuf16 = HBufC16::NewLC(aSourceLine.Length());
+			pBuf16->Des().Copy(aSourceLine);
+			TLex sourceLineLex = pBuf16->Ptr();
+			//parse until start of filename and mark
+			length+=3;					// length (init'd to 6 above) now equals 9 ie. "begin ###"
+			sourceLineLex.Inc(length);	// skips "begin ###"
+			sourceLineLex.SkipSpace();	// skips any leading whitespace
+
+			ExtractFilename(sourceLineLex, iAttachmentName);
+			CleanupStack::PopAndDestroy(); // pBuf8
+			return ETrue;
+			}
+		}
+		
+	return EFalse;
+	}
+
+  
+/**
+AddFileExtension()
+*/
+void CLocalImRecvConvert::AddFileExtension()
+	{
+	switch (iMimeParser->ContentType())
+		{
+		case EMimeText:
+			// Add on extension to make opening file from email editor possible.
+
+			if ( iMimeParser->ContentSubType()==KImcvHtml )
+				iAttachmentName.Append(KHtmlExtension);
+			else if (iMimeParser->VCard() || iMimeParser->VCalendar())
+				iAttachmentName.Append(KVCardExtension);
+			else //if ( iMimeParser->ContentSubType()==KImcvPlain)
+				iAttachmentName.Append(KTextExtension);
+			break;
+		case EMimeImage:
+		case EMimeAudio:
+		case EMimeVideo:
+			if ( (iMimeParser->ContentSubType()==KImcvBmp) 
+					|| (iMimeParser->ContentSubType()==KImcvGif)
+					|| (iMimeParser->ContentSubType()==KImcvJpeg)
+					|| (iMimeParser->ContentSubType()==KImcvTiff)
+					|| (iMimeParser->ContentSubType()==KImcvWav) )
+				{
+				TBuf<KMaxExtensionLength> buf;
+				buf.Copy(iMimeParser->ContentSubType());
+				iAttachmentName.Append(KImcvFullStop);
+				iAttachmentName.Append(buf);
+				}
+			break;
+		default:
+			break;
+		} // End switch
+	}
+
+  
+/**
+WriteToBodyL()
+
+@param aText
+@param aBlankLine
+*/
+void CLocalImRecvConvert::WriteToBodyL(const TDesC8& aText, TBool aBlankLine)
+	{
+	RECVLOG(KWritingToBody)
+
+	if(aText.Length() && aText[aText.Length()-1]==CEditableText::ELineBreak )
+		RECVLOG(KLineHasLineBreak)
+	TInt pos = iOutputBody->DocumentLength();
+
+	// Add bits of body text, converting along the way, till no characters left
+	// .. to convert.
+
+	if(aBlankLine)
+		{
+		RECVLOG(KBlankLine);
+		iOutputBody->InsertL(pos, CEditableText::EParagraphDelimiter);
+		pos++;
+		return;
+		}
+
+	// Convert text before writing to body.
+	TInt rem = 0;
+	HBufC16* text16=HBufC16::NewLC(aText.Length());
+	TPtr16 ptr16(text16->Des());
+	TInt unconvertedChars, firstPos; // not used 
+	rem = iCharConv->ConvertToOurCharsetL(aText, ptr16, unconvertedChars, firstPos);
+	if (rem < 0) // error
+		{
+		// Copy unconverted characters.
+		Append(ptr16, aText);
+		iOutputBody->InsertL(pos, ptr16);
+		CleanupStack::PopAndDestroy(); // text16
+		return;
+		}
+	else if (rem && rem < KConversionRemainderLength)
+		iLeftOver.Copy(aText.Right(rem));	
+	
+	// Make sure that the line is not CRLF terminated 
+	// - replace with a line break if necessary.
+
+	TInt length = ptr16.Length();
+	switch(iAlgorithm)
+		{
+		case EBase64Decode:
+		case EUUDecode:
+			{
+			// Check for CRLF throughout the string.
+
+			if (!length)
+				break; // String length zero.
+
+			if (iEncounteredLineEndingInCarriageReturn)
+				{
+				pos--; // overwrite the stored CR.
+				ptr16[0] = CEditableText::ELineBreak;
+				}
+			iEncounteredLineEndingInCarriageReturn = ptr16[length-1]==KImcvCR ? ETrue:EFalse;
+
+			TInt start = 0;
+			TInt offset = ptr16.Find(KImcvCRLF16);
+
+			while (offset != KErrNotFound)
+				{
+				ptr16[offset] = CEditableText::ELineBreak;
+				const TDesC& buf = ptr16.Mid(start, offset-start+1);
+				iOutputBody->InsertL(pos, buf);
+				pos += buf.Length();
+				start=offset+2; // Skip the LF char.
+				offset = ptr16.Find(KImcvCRLF16);
+				} 
+
+			if (start<length)
+				{
+				const TDesC& buf = ptr16.Right(length-start);
+				iOutputBody->InsertL(pos, buf);
+				pos += buf.Length();
+				}
+			}
+			break;
+
+		case EQPDecode:
+		case ENoAlgorithm:
+		default:
+			// Check for CRLF at end of line.
+			if(length>=2 && ptr16[length-2]==KImcvCR && ptr16[length-1]==KImcvLF)
+				{
+				ptr16[length-2] = CEditableText::ELineBreak;
+				ptr16.SetLength(length-1);
+				}	
+
+			const TDesC& buf = text16->Des();
+			iOutputBody->InsertL(pos, buf);
+			pos += buf.Length();
+		}	
+
+	CleanupStack::PopAndDestroy(text16);
+	
+	RECVLOG(KWroteToBody)
+	}
+
+
+/**
+WriteToBodyL()
+
+@param aText
+*/
+void CLocalImRecvConvert::WriteToBodyL(const TDesC16& aText)  
+	{
+	RECVLOG(KWritingToBody)
+	if (aText.Length() && aText[aText.Length()-1]==CEditableText::ELineBreak)
+		RECVLOG(KLineHasLineBreak)
+
+	TInt pos = iOutputBody->Read(0).Length();
+	// get the text in before the paragraph marker that's always there
+	pos = pos-1 < 0 ? 0 : pos-1;
+	iOutputBody->InsertL(pos,aText);
+	
+	RECVLOG(KWroteToBody)
+	}
+
+  
+/**
+ParseRecipientListL()
+
+@param aList
+*/
+void CLocalImRecvConvert::ParseRecipientListL(CDesCArray& aList)
+	{
+	HBufC8* pBuf = HBufC8::NewLC(KMaxIMailHeaderReadLineLength);
+	TPtrC8 source(iRfc822Token->OutputLine()->Ptr(), iRfc822Token->OutputLine()->Length());
+	const TUint8* ptr = source.Ptr();
+	TUint8 lookFor = 0;
+	TInt count = 0;
+	TBool finishedEntry = EFalse;
+
+	// get past white space
+	while(*ptr&&((*ptr==KImcvSP)||(*ptr==KImcvSemiColon))) ptr++;
+
+	while(*ptr&&((ptr-source.Ptr())<(source.Length())))
+		{
+		if(!pBuf->Length())
+			{
+			finishedEntry = EFalse;
+			}
+
+		switch(*ptr)
+			{
+			case KImcvLeftBracket:
+				if(lookFor==KImcvRightBracket)
+					count++;
+				else
+					{
+					lookFor = KImcvRightBracket;
+					count = 1;
+					}
+				break;
+			case KImcvLeftChevron:
+				if(lookFor==KImcvRightChevron)
+					count++;
+				else
+					{
+					lookFor = KImcvRightChevron;
+					count = 1;
+					}
+				break;
+			case KImcvDoubleQuote:
+ 				lookFor = (TUint8)(lookFor==KImcvDoubleQuote ? 0 : KImcvDoubleQuote);
+				count = (lookFor ? 1 : 0);
+				break;
+			case KImcvRightBracket:
+			case KImcvRightChevron:
+				count -= (*ptr == lookFor ? 1 : 0);
+				lookFor = (TUint8)((*ptr == lookFor)&&(count == 0) ? 0 : lookFor);
+				break;
+			case KImcvComma:
+			case KImcvSemiColon:
+				finishedEntry = !lookFor;
+				break;
+			}
+
+		if(!finishedEntry)
+			{
+			// check we're not about to blow the buffer
+			if(pBuf->Length() >= pBuf->Des().MaxLength())
+				{
+				pBuf = pBuf->ReAlloc(pBuf->Length() + 64); // arbitrary extension
+				}
+			pBuf->Des().Append((TChar)*ptr);
+			// move to the next character
+			ptr++;
+			}
+		else
+			{
+			// that's it! store the address away
+			HBufC16* pBuf16 = HBufC16::NewLC(pBuf->Des().Length());
+			pBuf16->Des().Copy(pBuf->Des());
+			aList.AppendL( (HBufC16&) *pBuf16 );
+			CleanupStack::PopAndDestroy(); // pBuf16
+			pBuf->Des().SetLength(0);
+
+			// get past the separator
+			ptr++;
+
+			// get past white space (& any other separators)
+			while(*ptr && (*ptr==KImcvSP || *ptr==KImcvTab || *ptr==KImcvComma || *ptr==KImcvSemiColon)) ptr++;
+			}
+		}
+		// catch the last name in the list
+		if (pBuf)
+			{
+			TInt recipientLength = pBuf->Length();
+			if (recipientLength)
+				{
+				HBufC16* pBuf16 = HBufC16::NewLC(recipientLength);
+				pBuf16->Des().Copy(*pBuf);
+				aList.AppendL(*pBuf16);
+				CleanupStack::PopAndDestroy(); // pBuf16
+				}
+			}
+
+		CleanupStack::PopAndDestroy(); // pBuf
+	}
+
+
+/**
+ExtractFilename()
+
+@param aLex
+@param rFileName
+*/
+void CLocalImRecvConvert::ExtractFilename(TLex& aLex, TDes& rFileName)
+	{
+	// This function steps through the filename extracting the bare name and checking 
+	//  the length is less than the max of 256 for EPOC ;checks that all chars are legal for EPOC32
+	
+	TChar endChar = KImcvSemiColon;
+
+	aLex.SkipSpace();
+	
+	if (aLex.Peek()==KImcvDoubleQuote)
+		{
+		aLex.Inc();	// step over the " character
+		endChar = KImcvDoubleQuote;
+		}
+
+	aLex.Mark();	// marks where we are as this is the first char of the filename
+	
+	TInt fileNameLength = 0;
+	TInt maxFileNameLength = rFileName.MaxLength();
+
+	while(!aLex.Eos() && aLex.Peek()!=endChar && aLex.Peek()!=KImcvCR && fileNameLength < maxFileNameLength)	
+		//spools through the string until the end and marks char before quote (such that 
+		//  it extracts only the filename), EOS or before the maximum buffer length is exceeded 
+		{
+		fileNameLength++;
+		aLex.Inc();
+		}
+
+	TPtrC marked = aLex.MarkedToken(); 
+	rFileName.Copy(marked);
+	
+	ReplaceInvalidCharacters(rFileName);
+	}
+
+
+/**
+SetAttachmentName()
+
+@param aFileName
+*/
+void CLocalImRecvConvert::SetAttachmentName(TDes& aFileName)
+	{
+	ReplaceInvalidCharacters(aFileName);
+	iAttachmentName.Zero();
+
+	TUint delimiter = '.';
+	TInt  maxLength = iAttachmentName.MaxLength();
+	
+	__ASSERT_DEBUG(
+		maxLength >= aFileName.Length(), gPanic(KPanicReadLengthTooLarge)
+		);
+
+	iAttachmentName.Copy(aFileName);
+	TInt attachmentLen = iAttachmentName.Length();
+	if (attachmentLen == 0)
+		iAttachmentName = *iDefaultAttachmentName;
+	else if (iAttachmentName[0] == delimiter && maxLength >= attachmentLen + iDefaultAttachmentName->Length())
+		iAttachmentName.Insert(0, *iDefaultAttachmentName);
+	}
+
+	
+/**
+ReplaceInvalidCharacters()
+
+@param rFileName
+*/
+void CLocalImRecvConvert::ReplaceInvalidCharacters(TDes& rFileName)
+	{
+	TInt length = rFileName.Length();
+	for(TInt index=0; index < length; index++)
+		{
+		//parse extracted filename and replace any illegal chars with a default.
+
+		if(IsIllegalChar((TUint)rFileName[index]))
+			rFileName[index] = KImcvDefaultChar;
+		}
+	}
+
+
+/**
+StoreEntryStreamsL()
+*/
+void CLocalImRecvConvert::StoreEntryStreamsL()	
+	{
+	StoreEntryStreamsL(KStoreBodyText|KStore822Header|KStoreMIMEHeader);
+	}
+
+
+/**
+StoreEntryStreamsL()
+
+@param aSettings
+*/
+void CLocalImRecvConvert::StoreEntryStreamsL(TInt aSettings)	
+	{
+	RECVLOG(KStartStoringEntryStream);
+	if (iReceivingHeadersOnly==EFalse)
+		{
+		CMsvStore* entryStore = NULL;
+		TBool commitStore = EFalse;
+
+		TRAPD(error, entryStore = iServerEntry->EditStoreL());
+		if(error==KErrNone) // if store does not exist then the entry is the wrong type
+			{
+			CleanupStack::PushL(entryStore);
+
+			if (aSettings & KStore822Header)
+				Store822HeaderL(*entryStore, commitStore);
+			
+			if (aSettings & KStoreMIMEHeader)
+				StoreMIMEHeaderL(*entryStore, commitStore);
+
+			if (aSettings & KStoreBodyText)
+				StoreBodyTextL(*entryStore, commitStore);
+
+			// only commit to the store if I wrote something into it
+			if (commitStore)
+				{
+				RECVLOG(KStoringEntryStream);
+				entryStore->CommitL();
+				}
+
+			StoreEntryDataL();
+			CleanupStack::PopAndDestroy(); //entryStore		
+			}
+
+		}
+	RECVLOG(KDoneStoringEntryStream);
+	}
+
+
+/**
+Store822HeaderL()
+
+@param aStore
+@param aCommit 
+*/
+void CLocalImRecvConvert::Store822HeaderL(CMsvStore& aStore, TBool& aCommit)	
+	{
+	if(iEmptyHeaderSize<(iOutputHeader->DataSize()))
+		{
+		iEntryDataSize += iOutputHeader->DataSize()-iEmptyHeaderSize;
+		RECVLOG(KStoringHeader);
+		iOutputHeader->StoreL(aStore);	
+		RECVLOG(KStoredHeader);
+		aCommit = ETrue;
+		}
+	}
+
+
+/**
+StoreMIMEHeaderL()
+
+@param aStore
+@param aCommit
+*/
+void CLocalImRecvConvert::StoreMIMEHeaderL(CMsvStore& aStore, TBool& aCommit)	
+	{
+	if(iMimeParser->MimeHeaderSize())
+		{
+		RECVLOG(KStoringMIMEHeader);
+ 		iMimeParser->StoreMimeHeaderWithoutCommitL(aStore);
+		aCommit = ETrue;
+		RECVLOG(KStoredMIMEHeader);
+		}
+	}
+
+
+/**
+StoreBodyTextL()
+
+@param aStore
+@param aCommit
+*/
+void CLocalImRecvConvert::StoreBodyTextL(CMsvStore& aStore, TBool& aCommit)	
+	{
+	if (iStore8BitData)
+		{
+		if(iBodyBuf->Size())
+			{
+			iEntryDataSize += iBodyBuf->Size();
+			RECVLOG(KStoring8BitBody);
+			iBodyText->StoreL(aStore, *iBodyBuf);
+			aCommit = ETrue;
+			RECVLOG(KStored8BitBody);
+			}
+		}
+	else
+		{
+		if(iOutputBody->DocumentLength())
+			{
+			iEntryDataSize += iOutputBody->DocumentLength();
+			RECVLOG(KStoringBody);
+			aStore.StoreBodyTextL(*iOutputBody);
+			aCommit = ETrue;
+			RECVLOG(KStoredBody);
+			}
+		}
+	}
+
+
+/**
+StoreEntryDataL()
+
+@return
+*/
+TBool CLocalImRecvConvert::StoreEntryDataL()
+	{
+	// NB function should only be called if a whole email is being processed
+	TBool commit=EFalse;
+	RECVLOG(KUpdatingEntry)
+
+	if (iEmailEntry->iType==KUidMsvMessageEntry)
+		iParent->At(0).iSize += iEntryDataSize;
+	else
+		{
+		iEmailEntry->iSize += iEntryDataSize;
+		if (iEntryType==EAttachmentEntry || iEntryType==EHtmlEntry)
+			iEmailEntry->iDetails.Set(iAttachmentName);
+		}
+	User::LeaveIfError(iServerEntry->ChangeEntry(*iEmailEntry));
+
+	RECVLOG(KUpdatedEntry)
+	return commit;	// if I wrote data into the store, tell owner	
+	}
+
+
+/**
+MoveToParentEntryL()
+*/
+void CLocalImRecvConvert::MoveToParentEntryL()
+	{
+	// This function changes the context to the current entry's parent entry.
+	RECVLOG(KMoveToParentEntry)
+
+	// Change context to the parent entry	
+	if (EntryId()==iTopMessagePart)
+		return; // Already there.
+
+	User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent())); 
+
+	iNewEntry = EFalse;
+	
+	// only read and write to store if this is a real email message; headers stored in
+	// the remote mailbox do not require any store information.
+	if (iReceivingHeadersOnly)
+		{
+		RECVLOG(KIgnoringStreams)
+		return;
+		}
+
+	TBool allowAttachmentFlag=ETrue;
+	if(iServerEntry->Entry().iType == KUidMsvFolderEntry)
+		{
+		// Current entry is a folder entry signifying a MIME multipart.
+		// Change context to the parent entry
+		
+		TMsvEmailEntry entry = (TMsvEmailEntry) iServerEntry->Entry();
+		iCurrentMultipartFolderEntryId = EntryId();
+		allowAttachmentFlag = !(entry.MessageFolderType()==EFolderTypeRelated || 
+								entry.MessageFolderType()==EFolderTypeAlternative);
+	
+
+		if (EntryId()!=iTopMessagePart)
+			User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent())); 
+		}
+
+	TBool childIsAttachment = (iEmailEntry->Attachment() || iEmailEntry->iType == KUidMsvMessageEntry) ? ETrue:EFalse;
+	TBool childIsMHTML=EFalse;
+	// Dont want the flag propogated 'up' past a message entry.
+	if(iEmailEntry->iType != KUidMsvMessageEntry)
+		childIsMHTML = iEmailEntry->MHTMLEmail() ? ETrue:EFalse;
+
+	//Make the parent entry the current entry 
+	if (NULL!=iEmailEntry)
+		{
+		delete iEmailEntry;
+		iEmailEntry=NULL;
+		}
+	iEmailEntry = new (ELeave) TMsvEmailEntry(iServerEntry->Entry());
+
+	if (!iParent->Count())
+		{
+		TParentDetails parentDetails;
+		iParent->InsertL(0,parentDetails);
+		}
+
+	if (! iParent->At(0).iAttachment)
+		{
+		iParent->At(0).iAttachment=(childIsAttachment && allowAttachmentFlag)? ETrue:EFalse;
+
+		// if we aren't allowing attachments because of the folder type
+		// remember there where attachments and check at the end whether
+		// it was an MHTML message or not.
+		if(childIsAttachment && !allowAttachmentFlag)
+			{
+			iRelatedAttachments=ETrue;
+			}
+		}
+	if (!iParent->At(0).iMHTML)
+		iParent->At(0).iMHTML = childIsMHTML ? ETrue:EFalse;
+	iParent->At(0).iSize += iEntryDataSize;
+
+	iOutputHeader->Reset();
+	iEmptyHeaderSize=iOutputHeader->DataSize();
+	iMimeParser->ResetForNewEntry();
+
+	iEntryDataSize=0;
+
+	RECVLOG(KMovedToParentEntry)
+	}
+
+/**
+WritePartialFooterL()
+Helper function to add the partial footer to the email if it exists
+
+@param aAmountLeft
+*/
+void CLocalImRecvConvert::WritePartialFooterL(TInt aAmountLeft)
+	{
+	TMsvId msgId=iBodyId;
+	if (msgId==KMsvNullIndexEntryId)
+		return;
+	TMsvId id = iServerEntry->Entry().Id();
+	if (iServerEntry->SetEntry(msgId)==KErrNone)
+		{
+		TBool storePresent = iServerEntry->HasStoreL();
+		if (storePresent && iPartialEmailFooter->Length()>0 && aAmountLeft>0)
+			{
+			CMsvStore* store = iServerEntry->ReadStoreL();
+			CleanupStack::PushL(store);
+			if (store->HasBodyTextL())
+				{
+				iOutputBody->Reset();
+				store->RestoreBodyTextL(*iOutputBody);
+				CleanupStack::PopAndDestroy(store);
+				HBufC* msg=NULL;
+				if (iPartialEmailFooter->Find(KIntegerKey)!=KErrNotFound)
+					{
+					// display k left on the server, rounded up if between 1 and 1023 bytes
+					TInt kBytesLeft = aAmountLeft / 1024;
+					if(kBytesLeft == 0)
+						kBytesLeft = 1;
+					msg = HBufC::NewLC(iPartialEmailFooter->Length()+KSpaceToAddNumber);
+					msg->Des().Format(*iPartialEmailFooter,kBytesLeft);
+					}
+				else
+					{
+					msg = iPartialEmailFooter->AllocLC();
+					}
+				iOutputBody->AppendParagraphL();
+				TInt length = iOutputBody->DocumentLength();
+				iOutputBody->InsertL(length,*msg);
+				CleanupStack::PopAndDestroy(msg);
+				store=NULL;
+				store = iServerEntry->EditStoreL();
+				CleanupStack::PushL(store);
+				store->StoreBodyTextL(*iOutputBody);
+				store->Commit();
+				CleanupStack::PopAndDestroy(store);
+				}
+			else
+				{
+				CleanupStack::PopAndDestroy(store);
+				}
+			}
+		}
+	iServerEntry->SetEntry(id);
+	}
+
+
+/**
+CreateEntryL()
+*/
+void CLocalImRecvConvert::CreateEntryL()
+	{
+	RECVLOG(KCreatingEntry);
+	if (NULL!=iEmailEntry)
+		{
+		delete iEmailEntry;
+		iEmailEntry=NULL;
+		}
+
+	if (iCurrentMultipartFolderEntryId)
+		{
+		User::LeaveIfError(iServerEntry->SetEntry(iCurrentMultipartFolderEntryId));
+		iCurrentMultipartFolderEntryId=0;
+		}
+		
+	iEmailEntry = new (ELeave) TMsvEmailEntry;
+
+	TValidEntryType previousEntryType = iEntryType;
+	if (!iTopMessagePart || iMIMEPart_822Header)
+		{
+		// At the main header, want to create a message entry.
+		// The stored iEntryType will indicate ( from header info) the next entry to be created.
+		// Save temporarily.
+		// Also applies to the special case where a message contains ony 1 embedded message.
+
+		previousEntryType=iEntryType;
+		iEntryType=EMessageEntry;
+		}
+
+	if ((iPopulateMessage) && (!iTopMessagePart))
+	// If this is the root of a message that is being populated then do not create it.
+		{
+		User::LeaveIfError(iServerEntry->SetEntry(iRootEntryId));
+		*iEmailEntry = iServerEntry->Entry();
+		iTopMessagePart=iRootEntryId;
+
+		// Delete all the children of the message entry.  This is needed because if the
+		// message has been purged, the entries will still exist.  When the message is populated,
+		// new entries are created.  If the original entries are not removed, then duplicate 
+		// entries will exist.
+		CMsvEntrySelection*	children = new(ELeave) CMsvEntrySelection;
+		CleanupStack::PushL(children);
+		User::LeaveIfError(iServerEntry->GetChildren(*children));
+		if (children->Count())
+			iServerEntry->DeleteEntries(*children);
+		CleanupStack::PopAndDestroy(children);
+		}
+	else
+		{
+		iEmailEntry->iMtm=iNewMsgType;
+		iEmailEntry->iServiceId = iEmailServiceId;
+		iEmailEntry->SetComplete(EFalse);
+		iEmailEntry->iSize = 0;
+		iEmailEntry->SetVisible(ETrue);
+		iEmailEntry->SetInPreparation(EFalse);
+		iEmailEntry->SetReceipt(EFalse);
+
+		iEmailEntry->SetVCard(iMimeParser->VCard());
+		iEmailEntry->SetVCalendar(iMimeParser->VCalendar());
+		iEmailEntry->SetMessageFolderType(iMimeParser->MessageFolderType());
+		iEmailEntry->SetPriority(iImPriority);
+		iEmailEntry->SetNew(EFalse);
+
+		if(iOutputHeader->ReceiptAddress().Length()>0)
+			iEmailEntry->SetReceipt(ETrue);
+
+		iEmailEntry->iDate=iTimeDate;
+		switch(iEntryType)
+			{
+			case EMessageEntry:
+				if(!iTopMessagePart)
+					{
+					iEmailEntry->SetUnread(ETrue);
+					iEmailEntry->SetNew(ETrue);
+					iEmailEntry->SetVisible(EFalse);
+					iEmailEntry->SetInPreparation(ETrue);
+					iEmailEntry->SetSendingState(KMsvSendStateNotApplicable);
+					}
+				else
+					{
+					TParentDetails parentDetails;
+					parentDetails.iMHTML=EFalse;
+			        parentDetails.iAttachment=EFalse;
+					parentDetails.iSize=0;
+					iParent->InsertL(0,parentDetails);
+					}
+				iEmailEntry->iType=KUidMsvMessageEntry;
+				iEmailEntry->iDetails.Set(iOutputHeader->From());
+				iEmailEntry->iDescription.Set(iOutputHeader->Subject());
+				break;
+			case EFolderEntry:
+				iEmailEntry->iType=KUidMsvFolderEntry;
+				if (iMimeParser->MessageFolderType()==EFolderTypeUnknown)
+					{
+					// Get folder type of parent (the message)
+					TMsvEmailEntry entry=iServerEntry->Entry();
+					iEmailEntry->SetMessageFolderType(entry.MessageFolderType());
+					}
+				break;
+			case EAttachmentEntry:
+				iEmailEntry->iType=KUidMsvAttachmentEntry;
+				iEmailEntry->iDetails.Set(iAttachmentName);
+				iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
+				break; 
+			case ETextEntry:
+				if ( iMimeParser->ContentDisposition()!=KImcvAttachment)
+					iEmailEntry->iType=KUidMsvEmailTextEntry;
+				else 
+					{
+					iEmailEntry->iType=KUidMsvAttachmentEntry;
+					iEmailEntry->iDetails.Set(iAttachmentName);
+					iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
+					}
+				break;
+			case EHtmlEntry:
+				iEmailEntry->iType=KUidMsvEmailHtmlEntry;
+				// If disposition not set or is inline..
+				if ( iMimeParser->ContentDisposition()==KImcvAttachment)
+					iEmailEntry->iType=KUidMsvAttachmentEntry;
+				else
+					iEmailEntry->SetMHTMLEmail(ETrue);
+				iEmailEntry->iDetails.Set(iAttachmentName);
+				iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
+				break;
+			default:
+				iEmailEntry->iType=KUidMsvAttachmentEntry;
+				iEmailEntry->iDetails.Set(iAttachmentName);
+				iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
+			}
+
+		User::LeaveIfError(iServerEntry->CreateEntry(*iEmailEntry));
+		User::LeaveIfError(iServerEntry->SetEntry(iEmailEntry->Id()));
+		if(!iTopMessagePart)
+			iTopMessagePart=iEmailEntry->Id();
+
+		//if (iEntryType==EHtmlEntry && iAttachmentFileState!=EFileIsOpen)
+		//	CreateAttachmentL();
+		}
+
+	iEntryType=previousEntryType;
+	iNewEntry = ETrue;
+	RECVLOG(KCreatedEntry);
+	}
+
+
+/**
+Logging()
+
+@param aString1
+@param aString2
+*/
+void CLocalImRecvConvert::Logging(const TDesC8& aString1, const TDesC8& aString2)  
+	{
+	TBuf8<1024> aBuf(aString1);
+
+	aBuf.Append(aString2);
+	RECVLOG(aBuf);
+	}
+
+
+/**
+StoreMessageEntryDetailsL()
+*/
+ void CLocalImRecvConvert::StoreMessageEntryDetailsL()  
+	{
+	iEmailEntry->SetAttachment(iParent->At(0).iAttachment);
+	iEmailEntry->SetMHTMLEmail(iParent->At(0).iMHTML);
+
+	if(iEmailEntry->MHTMLEmail() == EFalse && iEmailEntry->Attachment() == EFalse && iRelatedAttachments !=EFalse)
+		{
+		iEmailEntry->SetAttachment(ETrue);
+		}
+	iRelatedAttachments=EFalse;
+	
+	iEmailEntry->iSize=iParent->At(0).iSize;
+	iEmailEntry->SetMessageFolderType(iParent->At(0).iFolder);
+	StoreEntryDataL();
+
+	if (iParent->Count()>1)
+		{
+		iParent->At(1).iSize+=iEmailEntry->iSize;
+		iParent->Delete(0);
+		}
+	else
+		{
+		iParent->At(0).iAttachment=iParent->At(0).iMHTML=EFalse;
+		iParent->At(0).iSize=0;
+		}
+	}
+
+
+/**
+DeletedAttachmentSize()
+
+@return
+*/ 
+ TInt CLocalImRecvConvert::DeletedAttachmentSize()  
+	{
+	return iSizeOfAttachmentsRemoved;
+	}
+
+/****************************************************************************
+	Class CLocalMimeParser functions
+*****************************************************************************/
+
+/**
+NewLC()
+Static factory constructor. Uses two phase construction 
+and pushes the newly created object into the Cleanup stack.
+
+@param aImRecvConvert
+@return
+*/    
+CLocalMimeParser* CLocalMimeParser::NewLC(CLocalImRecvConvert& aImRecvConvert)  
+	{
+	CLocalMimeParser* self = new (ELeave) CLocalMimeParser(aImRecvConvert);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+
+/**
+NewL()
+Static factory constructor. Uses two phase construction.
+
+@param aImRecvConvert
+@return
+*/
+ CLocalMimeParser* CLocalMimeParser::NewL(CLocalImRecvConvert& aImRecvConvert)  
+	{
+	CLocalMimeParser* self = CLocalMimeParser::NewLC(aImRecvConvert);
+	CleanupStack::Pop();
+	return self;
+	}
+
+
+/**
+CLocalMimeParser()
+
+@param aImRecvConvert
+@return
+*/
+CLocalMimeParser::CLocalMimeParser(CLocalImRecvConvert& aImRecvConvert): iImRecvConvert(aImRecvConvert), 
+											iStartId(NULL)
+
+	{
+	__DECLARE_NAME(_S("CLocalMimeParser"));
+	}
+
+
+/**
+ConstructL()
+*/
+void CLocalMimeParser::ConstructL() 
+	{
+	iMimeHeader = CImMimeHeader::NewL();
+	// Create a Desc array to store the boundary strings of a Mime message
+	iBoundaryText = new (ELeave) CDesC8ArrayFlat(3);
+	
+	// Set charset default value
+	iDefaultCharset=iImRecvConvert.CharacterConverter().DefaultCharset();
+	iCharset = iDefaultCharset;
+	ResetMimeFieldsExist();
+
+	Reset();
+	}
+
+
+/**
+~CLocalMimeParser()
+*/
+CLocalMimeParser::~CLocalMimeParser() 
+	{
+	delete iMimeHeader;
+	iMimeHeader=NULL;
+	delete iBoundaryText;
+	iBoundaryText=NULL;
+	delete iMimeHeaderLine;
+	iMimeHeaderLine=NULL;
+	delete iStartId;
+	iStartId=NULL;
+	}
+
+
+/**
+Reset() 
+*/
+void CLocalMimeParser::Reset() 
+	{
+	iBoundaryText->Reset();
+	iBoundaryIndex = 0;
+	iBoundaryLength = 0;
+	isMime = EFalse;
+	
+	ResetForNewEntry();
+	}
+
+
+/**
+ResetForNewEntry()
+*/
+void CLocalMimeParser::ResetForNewEntry()
+	{
+	iMimeHeader->Reset();
+	iEmptyMimeHeaderSize=iMimeHeader->Size();
+		
+	iContentType = EMimeUnknownContent;
+	iContentEncoding = EEncodingTypeNone;
+	iContentDescription.Zero();
+	iVCard = EFalse;
+	iVCalendar = EFalse;
+	iStartPart=EFalse;
+	iMessageFolderType = EFolderTypeUnknown;
+	iTerminatingBoundary = EFalse;
+	iBoundaryFound = EFalse;
+	}
+
+
+/**
+RestoreMimeParserL()
+
+@param entryStore
+*/
+void CLocalMimeParser::RestoreMimeParserL(CMsvStore& entryStore)
+	{
+	iMimeHeader->RestoreL(entryStore);
+	if(iMimeHeader->ContentType().Compare(KImcvText)==0)
+		iContentType=EMimeText; 
+	else
+	if(iMimeHeader->ContentType().Compare(KImcvMessage)==0)
+		iContentType=EMimeMessage;
+	else
+	if(iMimeHeader->ContentType().Compare(KImcvMultipart)==0)
+		iContentType=EMimeMultipart; 
+	else
+	if(iMimeHeader->ContentType().Compare(KImcvImage)==0)
+		iContentType=EMimeImage; 
+	else
+	if(iMimeHeader->ContentType().Compare(KImcvApplication)==0)
+		iContentType=EMimeApplication; 
+	else
+	if(iMimeHeader->ContentType().Compare(KImcvAudio)==0)
+		iContentType=EMimeAudio; 
+	else
+	if(iMimeHeader->ContentType().Compare(KImcvVideo)==0)
+		iContentType=EMimeVideo; 
+	else
+		iContentType=EMimeUnknownContent; 
+
+	}
+
+
+/**
+ParseLineL()
+
+@param aSourceLine
+*/
+void CLocalMimeParser::ParseLineL(const TDesC8& aSourceLine)
+	{
+	if(iMimeHeaderLine==NULL)
+		{
+		iMimeHeaderLine = HBufC8::NewL(aSourceLine.Length());
+		*iMimeHeaderLine = aSourceLine;
+		}
+	
+	iLex = *iMimeHeaderLine;
+
+	// find out whether the current line has anything to do with currently understood MIME Content tokens
+	if(!iMimeHeaderLine->MatchF(KImcvMime) || !iMimeHeaderLine->MatchF(KImcvContent))
+		{ 
+		if(MatchAndRemoveToken(KImcvMimePrompt))
+			DoMimeVersion();
+		else if(MatchAndRemoveToken(KImcvContentType))
+			DoContentTypeL();
+		else if(MatchAndRemoveToken(KImcvContentLocation))
+			DoContentLocationL();
+		else if(MatchAndRemoveToken(KImcvContentTransferEncoding))
+			DoEncodingL();
+		else if(MatchAndRemoveToken(KImcvContentId))
+			{
+			RemoveSurroundingCharacters(KImcvLeftChevron, KImcvRightChevron, *iMimeHeaderLine);
+			DoContentIdL();
+			}
+		else if(MatchAndRemoveToken(KImcvContentDescription))
+			DoDescriptionL();
+		else if(MatchAndRemoveToken(KImcvContentDisposition))
+			DoDispositionL();
+		else if(MatchAndRemoveToken(KImcvContentBase))
+			DoContentBaseL();
+		}
+		
+	delete iMimeHeaderLine;	// clean up and null pointer iff CompleteMimeHeader and no foldover append req'd
+	iMimeHeaderLine=NULL;
+	}
+
+
+/**
+DoMimeVersion()
+*/
+void CLocalMimeParser::DoMimeVersion()
+	{
+	// extract the MIME version from a header line which we already know
+	// has 'MIME-Version' start of it.
+	if(MatchAndRemoveToken(KImcvMimeVersion))
+		iCorrectMimeVersion = ETrue;
+	}
+
+
+/**
+DoContentIdL()
+*/
+void CLocalMimeParser::DoContentIdL()
+	{
+	iMimeHeader->SetContentIDL(iMimeHeaderLine->Des());
+	if(iStartId && iStartId->CompareF(iMimeHeaderLine->Des())==KErrNone)
+		iStartPart=ETrue;
+	}
+
+
+/**
+DoContentLocationL()
+*/
+void CLocalMimeParser::DoContentLocationL()
+	{
+	TInt len = (*iMimeHeaderLine).Length();
+	if (len == 0)
+		return;
+			
+	RemoveSurroundingCharacters(KImcvQuote, KImcvQuote, *iMimeHeaderLine);
+
+	HBufC16* locationBuf = HBufC16::NewL( len );
+	CleanupStack::PushL(locationBuf);
+	TPtr locationPtr(locationBuf->Des());
+	iImRecvConvert.iHeaderConverter->DecodeHeaderFieldL( iMimeHeaderLine->Des(), locationPtr);
+	iMimeHeader->SetContentLocationL(locationPtr);
+	CleanupStack::PopAndDestroy(); // locationBuf
+	}
+
+
+/**
+DoContentBaseL()
+*/
+void CLocalMimeParser::DoContentBaseL()
+	{
+	RemoveSurroundingCharacters(KImcvQuote, KImcvQuote, *iMimeHeaderLine);
+	iMimeHeader->SetContentBaseL(iMimeHeaderLine->Des());
+	}
+
+
+/**
+DoAttachmentTypeL()
+*/
+void CLocalMimeParser::DoAttachmentTypeL()
+	{
+	iImRecvConvert.iEntryType = CLocalImRecvConvert::EAttachmentEntry;
+	iImRecvConvert.iCurrentPartIsRichText = EFalse;	
+
+	if(MatchAndRemoveToken(KImcvForwardSlash))
+		{
+		if(MatchAndRemoveToken(KImcvBmp))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvBmp);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvGif))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvGif);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvJpeg))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvJpeg);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvTiff))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvTiff);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvWav))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvWav);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvZip))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvZip);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvOctetStream))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvOctetStream);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvExe))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvExe);
+			}
+		else
+		if(MatchAndRemoveToken(KImcvCmd))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvCmd);
+			}
+		else
+		if(MatchAndRemoveToken(KTImcvDrm))
+			{ // added this to handle DRM files
+			iMimeHeader->SetContentSubTypeL(KTImcvDrm);
+			}
+		}
+	}
+
+
+/**
+DoMessageTypeL()
+*/
+void CLocalMimeParser::DoMessageTypeL()
+	{
+	iImRecvConvert.iEntryType = CLocalImRecvConvert::EMessageEntry;
+	iImRecvConvert.iEmailPart = CLocalImRecvConvert::KParentPart;
+	
+	iContentType=EMimeMessage; 
+	iMimeHeader->SetContentTypeL(KImcvMessage);
+
+	if(MatchAndRemoveToken(KImcvForwardSlash))
+		{
+		if(MatchAndRemoveToken(KImcvRfc822))
+			{
+			//iMessageFolderType=EFolderTypeRFC822;
+			iMimeHeader->SetContentSubTypeL(KImcvRfc822);
+			}
+		else if(MatchAndRemoveToken(KImcvExternal))
+			{
+			iMessageFolderType=EFolderTypeExternal;
+			iMimeHeader->SetContentSubTypeL(KImcvExternal);
+			}
+		else if(MatchAndRemoveToken(KImcvPartial))
+			{
+			iMessageFolderType=EFolderTypePartial;
+			iMimeHeader->SetContentSubTypeL(KImcvPartial);
+			}
+		else if(MatchAndRemoveToken(KImcvDeliveryStatus))
+			{
+			// We do not process this part. So store as text.
+			iMimeHeader->SetContentSubTypeL(KImcvDeliveryStatus);
+			iImRecvConvert.iEntryType = CLocalImRecvConvert::EAttachmentEntry;
+			iImRecvConvert.iEmailPart = CLocalImRecvConvert::KNoPart;
+			iContentType=EMimeUnknownContent; 
+			iImRecvConvert.iCurrentPartIsRichText=EFalse;
+			iImRecvConvert.iAttachmentName.Copy(KImcvDeliveryStatus);
+			iImRecvConvert.iAttachmentName.Append(KTextExtension);
+			}
+		else
+			{
+			iMessageFolderType=EFolderTypeUnknown;
+			iMimeHeader->SetContentSubTypeL(KImcvUnknown);
+			}
+		}	
+	}
+
+
+/**
+DoMultipartTypeForNonMIMEL()
+*/
+void CLocalMimeParser::DoMultipartTypeForNonMIMEL()
+	{
+	ResetForNewEntry();
+	iMessageFolderType=EFolderTypeMixed;
+	iMimeHeader->SetContentTypeL(KImcvMultipart);
+	iMimeHeader->SetContentSubTypeL(KImcvMixed);
+	}
+
+
+/**
+DoMultipartTypeL()
+*/
+void CLocalMimeParser::DoMultipartTypeL()
+	{
+	iImRecvConvert.iEntryType = CLocalImRecvConvert::EFolderEntry;
+	iImRecvConvert.iEmailPart = CLocalImRecvConvert::KMultiPart;
+	
+	iContentType=EMimeMultipart;
+	iMimeHeader->SetContentTypeL(KImcvMultipart);
+
+	if(MatchAndRemoveToken(KImcvForwardSlash))
+		{
+		if(MatchAndRemoveToken(KImcvMixed))
+			{
+			iMessageFolderType=EFolderTypeMixed;
+			iMimeHeader->SetContentSubTypeL(KImcvMixed);
+			}
+		else if(MatchAndRemoveToken(KImcvRelated))
+			{
+			iMessageFolderType=EFolderTypeRelated;
+			iMimeHeader->SetContentSubTypeL(KImcvRelated);
+			}
+		else if(MatchAndRemoveToken(KImcvAlternative))
+			{
+			iMessageFolderType=EFolderTypeAlternative;
+			iMimeHeader->SetContentSubTypeL(KImcvAlternative);
+			}
+		else if(MatchAndRemoveToken(KImcvEncrypted))
+			{
+//	Add this when Encryption is handled iMessageFolderType=EFolderTypeEncrypted;
+			iMimeHeader->SetContentSubTypeL(KImcvEncrypted);
+			}
+		else if(MatchAndRemoveToken(KImcvParallel))
+			{
+			iMessageFolderType=EFolderTypeParallel;
+			iMimeHeader->SetContentSubTypeL(KImcvParallel);
+			}
+		else if(MatchAndRemoveToken(KImcvDigest))
+			{
+			iMessageFolderType=EFolderTypeDigest;
+			iMimeHeader->SetContentSubTypeL(KImcvDigest);
+			isMessageDigest=ETrue;
+			}
+		else if(MatchAndRemoveToken(KImcvSigned))
+			{
+//	Add this when Signed is handled	iMessageFolderType=EFolderTypeSigned;
+			iMimeHeader->SetContentSubTypeL(KImcvSigned);
+			}
+		else if(MatchAndRemoveToken(KImcvReport))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvReport);
+			}
+		else
+			{
+			iMessageFolderType=EFolderTypeUnknown;
+			iMimeHeader->SetContentSubTypeL(KImcvUnknown);
+			}
+		}
+
+	if (iMessageFolderType==EFolderTypeRelated)
+		iImRecvConvert.iParent->At(0).iFolder=iMessageFolderType; 
+
+	// Find any parameters specific to a Multipart content type	
+
+	HBufC8* paramValue = NULL;
+
+	// Extracts the boundary string
+
+	ExtractParameterInfoL(KImcvBoundary, paramValue);
+	if( paramValue!=NULL ) 
+		{
+		CleanupStack::PushL(paramValue);
+		iBoundaryFound = ETrue;
+		iImRecvConvert.iEmailPart = CLocalImRecvConvert::KMultiPart;
+		SetBoundaryL(*paramValue);
+		CleanupStack::PopAndDestroy(paramValue);
+		}
+
+	// Extracts start ID if it has been defined;
+
+	ExtractParameterInfoL(KImcvStartPart, paramValue);
+	if( paramValue!=NULL )
+		{
+		delete iStartId;
+		iStartId=NULL;
+		iStartId = paramValue;
+		}
+	}
+
+
+/**
+DoTextTypeL()
+*/
+void CLocalMimeParser::DoTextTypeL()
+	{
+	HBufC8* paramValue = NULL;
+	
+	iImRecvConvert.iEntryType = CLocalImRecvConvert::ETextEntry;
+	iContentType=EMimeText;		
+	iMimeHeader->SetContentTypeL(KImcvText);
+
+	if(MatchAndRemoveToken(KImcvForwardSlash))
+		{
+		if(MatchAndRemoveToken(KImcvPlain))
+			iMimeHeader->SetContentSubTypeL(KImcvPlain);
+		else
+		if(MatchAndRemoveToken(KImcvHtml))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvHtml);
+			iImRecvConvert.iEntryType = CLocalImRecvConvert::EHtmlEntry;
+			iImRecvConvert.iCurrentPartIsRichText = EFalse;	
+			}
+		else
+		if(MatchAndRemoveToken(KImcvDirectory))
+			{
+			iMimeHeader->SetContentSubTypeL(KImcvDirectory);
+			iMimeHeader->ContentTypeParams().AppendL(KImcvProfile);
+			ExtractParameterInfoL(KImcvProfile, paramValue);
+			// Assume at right context, the email message, not attachment.
+			
+			iMessageFolderType=EFolderTypeDirectory;
+			if( paramValue!=NULL )
+				{
+				CleanupStack::PushL(paramValue);
+				iMimeHeader->ContentTypeParams().AppendL(*paramValue);
+				if(paramValue->MatchF(KImcvVCard) == 0)
+					{
+					iVCard=ETrue;
+					}
+				CleanupStack::PopAndDestroy(paramValue);
+				}
+			}
+		if(MatchAndRemoveToken(KImcvVCalender))
+			iVCalendar=ETrue;
+
+		// Extract the charset value, 
+
+		ExtractParameterInfoL(KImcvCharset, paramValue);
+
+		if(paramValue!=NULL)
+			{
+			CleanupStack::PushL(paramValue);
+			// check if at top level header or Mime part header
+
+			TUint charsetUid = iImRecvConvert.CharacterConverter().GetMimeCharsetUidL(*paramValue); 
+			if(iImRecvConvert.NotFinishedRfc822Header() == EFalse)
+				iCharset=charsetUid;
+
+			// Store in CMimeHeader::iContentTypeParams
+			iMimeHeader->ContentTypeParams().AppendL(KImcvCharset);
+			iMimeHeader->ContentTypeParams().AppendL(*paramValue);
+			CleanupStack::PopAndDestroy(paramValue);
+
+			if (!iImRecvConvert.CharacterConverter().PrepareToConvertToFromOurCharsetL(charsetUid))
+				charsetUid=KUidMsvCharsetNone;
+			iMimeHeader->SetMimeCharset(charsetUid);
+			}
+		else
+			iMimeHeader->SetMimeCharset(iDefaultCharset);
+		}
+	}
+
+
+/**
+DoContentTypeL()
+*/
+void CLocalMimeParser::DoContentTypeL()
+	{
+	RemoveSurroundingCharacters(KImcvLeftChevron, KImcvRightChevron, *iMimeHeaderLine);
+
+	if(MatchAndRemoveToken(KImcvText))
+		DoTextTypeL();
+	else
+	if(MatchAndRemoveToken(KImcvMultipart))
+		DoMultipartTypeL();
+	else
+	if(MatchAndRemoveToken(KImcvMessage))
+		DoMessageTypeL();
+	else
+	if(MatchAndRemoveToken(KImcvImage))
+		{	
+		iContentType=EMimeImage; 
+		iMimeHeader->SetContentTypeL(KImcvImage);
+		DoAttachmentTypeL();
+		}
+	else
+	if(MatchAndRemoveToken(KImcvApplication))
+		{
+		iContentType=EMimeApplication; 
+		iMimeHeader->SetContentTypeL(KImcvApplication);
+		DoAttachmentTypeL();
+		}
+	else
+	if(MatchAndRemoveToken(KImcvAudio))
+		{
+		iContentType=EMimeAudio; 
+		iMimeHeader->SetContentTypeL(KImcvAudio);
+		DoAttachmentTypeL();
+		}
+	else
+	if(MatchAndRemoveToken(KImcvVideo))
+		{
+		iContentType=EMimeVideo; 
+		iMimeHeader->SetContentTypeL(KImcvVideo);
+		DoAttachmentTypeL();
+		}
+	else
+		{
+		iContentType=EMimeUnknownContent; 
+		iMimeHeader->SetContentTypeL(KImcvUnknown);
+		}
+
+	// Extract the filename if it exists
+	HBufC* paramStore = HBufC::NewLC(MaxMimeParameterValueLength);
+	HBufC8* paramStore8 = HBufC8::NewLC(KMimeEncodedParameterSize);
+	TPtr paramValue(paramStore->Des());
+	TPtr8 paramValue8(paramStore8->Des());
+
+	ExtractParameterInfoL(KImcvMimeTypeName, paramValue,paramValue8);
+	if(paramValue.Length())
+		{
+		iMimeHeader->ContentTypeParams().AppendL(KImcvMimeTypeName);
+		iMimeHeader->ContentTypeParams().AppendL(paramValue8);
+		iImRecvConvert.SetAttachmentName(paramValue);
+		}
+	
+	CleanupStack::PopAndDestroy(2,paramStore); 
+	}
+
+
+/**
+DoEncodingL()
+*/
+void CLocalMimeParser::DoEncodingL()
+	{
+	iMimeHeader->SetContentTransferEncodingL(*iMimeHeaderLine);
+
+	switch ((*iMimeHeaderLine)[0])
+		{
+		case '7': // 7bit
+			iContentEncoding = EEncodingType7Bit;
+			break;
+		case '8': // 8bit
+			iContentEncoding = EEncodingType8Bit;
+			break;
+		case 'q': // quoted-printable
+		case 'Q': 
+			iContentEncoding = EEncodingTypeQP;
+			break;
+		case 'b': // binary or base64
+		case 'B':
+			iContentEncoding = ((*iMimeHeaderLine)[1] == 'i' || (*iMimeHeaderLine)[1] == 'I' ? EEncodingTypeBinary : EEncodingTypeBASE64);
+			break;
+		case 'x': //in order to support UU encoded within a MIME message
+		case 'X':
+			iContentEncoding = ((*iMimeHeaderLine).FindF(KImcvXUUString)==KErrNotFound ? EEncodingTypeUnknown : EEncodingTypeUU);
+			break;
+		default:
+			iContentEncoding = EEncodingTypeUnknown;
+			break;
+		}
+	}
+
+
+/**
+DoDescriptionL()
+*/
+void CLocalMimeParser::DoDescriptionL()
+	{
+	TPtrC8 marked(iMimeHeaderLine->Des());
+	if (marked.Length()>KMaxFileName)
+		marked.Set(marked.Left(KMaxFileName));
+
+	iContentDescription.Copy(marked);
+
+	// remove the CRLF
+
+	TInt length = iContentDescription.Length();
+	if (length>2)
+		{
+		if (iContentDescription[length-2]==KImcvCR && iContentDescription[length-1]==KImcvLF)
+			iContentDescription.SetLength(length-2);
+		}
+	iMimeHeader->SetContentDescriptionL(marked);
+	}
+
+
+/**
+DoDispositionL()
+*/
+void CLocalMimeParser::DoDispositionL()
+	{
+	TBool inLine = EFalse;
+	if(MatchAndRemoveToken(KImcvAttachment))
+		{
+		iMimeHeader->SetContentDispositionL(KImcvAttachment);
+		if (iMimeHeader->ContentSubType()!=KImcvRfc822)
+			{
+			iImRecvConvert.iCurrentPartIsRichText = EFalse;	
+			}
+		if (iImRecvConvert.iEntryType!=CLocalImRecvConvert::EMessageEntry)
+			{
+			iImRecvConvert.iEntryType = CLocalImRecvConvert::EAttachmentEntry;
+			}
+		}
+	else if(MatchAndRemoveToken(KImcvInline))
+		inLine = ETrue;
+
+	// Extract the filename if it exists, unless we already have a name for it	
+	if(!iImRecvConvert.iAttachmentName.Length())
+		{
+		HBufC* paramStore = HBufC::NewLC(KHeaderBufferLength);
+		TPtr paramValue(paramStore->Des());
+		HBufC8* paramStore8 = HBufC8::NewLC(KMimeEncodedParameterSize);
+		TPtr8 paramValue8(paramStore8->Des());
+
+		ExtractParameterInfoL(KImcvMimeDispositionFilename, paramValue,paramValue8);
+		if(paramValue.Length())
+			{
+			iMimeHeader->ContentTypeParams().AppendL(KImcvMimeDispositionFilename);
+			iMimeHeader->ContentTypeParams().AppendL(paramValue8);
+			iImRecvConvert.SetAttachmentName(paramValue);
+			}
+
+		CleanupStack::PopAndDestroy(2,paramStore); // paramStore, paramStore8
+		}
+
+		if(inLine)
+ 		{
+ 		// Content Disposition set to inline
+ 		if (iImRecvConvert.iAttachmentName.Length())
+ 			// filename exists
+ 			{
+ 			iMimeHeader->SetContentDispositionL(KImcvAttachment);
+ 			iImRecvConvert.iCurrentPartIsRichText = EFalse;	
+			if (iImRecvConvert.iEntryType!=CLocalImRecvConvert::EMessageEntry)
+ 				{
+ 				iImRecvConvert.iEntryType = CLocalImRecvConvert::EAttachmentEntry;
+ 				}
+ 			}
+ 		else
+ 			iMimeHeader->SetContentDispositionL(KImcvInline);
+ 		}
+	}
+
+
+/**
+ContentSubType()
+
+@return
+*/  
+TPtrC8 CLocalMimeParser::ContentSubType() const  
+	{
+	return iMimeHeader->ContentSubType();;
+	}
+
+
+/**
+VCard()
+
+@return
+*/  
+TBool CLocalMimeParser::VCard() const  
+	{
+	return iVCard;
+	}
+
+
+/**
+VCalendar()
+
+@return
+*/  
+TBool CLocalMimeParser::VCalendar() const  	
+	{
+	return iVCalendar;
+	}
+
+
+/**
+StartPart()
+
+@return
+*/  
+TBool CLocalMimeParser::StartPart() const  
+	{
+	return iStartPart;
+	}
+
+
+/**
+MessageFolderType()
+
+@return
+*/  
+TImEmailFolderType CLocalMimeParser::MessageFolderType() const  
+	{
+	return iMessageFolderType;
+	}
+
+
+/**
+SetMessageFolderType()
+
+@param aFolderType
+*/  
+void CLocalMimeParser::SetMessageFolderType(TImEmailFolderType aFolderType)  
+	{
+	iMessageFolderType=aFolderType;
+	}
+
+
+/**
+SetBoundaryL()
+
+@param aBoundaryText
+*/  
+void CLocalMimeParser::SetBoundaryL(const TDesC8& aBoundaryText)  
+	{
+	TBuf8<KMaxBoundaryTextLength+2> tempBoundary(KImcvMimeBoundaryStartEnd);
+	// From RFC 1521, (Boundaries) must be no longer than 70 characters.
+	// Including beginning and end "--" 
+	if (aBoundaryText.Length()>70)
+		tempBoundary.Append(aBoundaryText.Left(70));
+	else
+		tempBoundary.Append(aBoundaryText);
+	iBoundaryText->AppendL(tempBoundary);
+
+	iBoundaryIndex = iBoundaryText->MdcaCount(); //iBoundaryIndex stores a count value not the index here
+	iBoundaryIndex = (iBoundaryIndex)? --iBoundaryIndex: 0;
+	iBoundaryLength = iBoundaryText->MdcaPoint(iBoundaryIndex).Length();
+	}
+
+
+/**
+IsBoundary()
+
+@param aSourceLine
+ @return
+*/
+TBool CLocalMimeParser::IsBoundary(const TDesC8& aSourceLine)
+	{
+	if(iBoundaryText->MdcaCount())
+		{
+		TInt found = 0;
+		TInt aLineLength = aSourceLine.Length();
+		TInt compareLength = aLineLength > iBoundaryLength ? iBoundaryLength : aLineLength;
+		TPtrC8 tempSourceLine(aSourceLine.Ptr(), compareLength);
+	
+		TInt error = iBoundaryText->Find(tempSourceLine, found, ECmpNormal);
+
+		if(error||(!iBoundaryLength))
+			return KBoundaryNotFound;
+	
+		// The following code is executed only if aSourceLine is a boundary
+		if(found != iBoundaryIndex)
+			{
+			iReceiveError = (iReceiveError)? iReceiveError: KBoundaryError;
+			iBoundaryIndex = found;
+			iBoundaryText->Delete(found++);
+			}
+	
+		if(aLineLength >= iBoundaryLength+4) // allow for CRLF & then check for the double hyphen
+			{
+			if((aSourceLine[iBoundaryLength] == KImcvHyphen) && (aSourceLine[iBoundaryLength+1] == KImcvHyphen))
+				iTerminatingBoundary = ETrue; // this is a terminating boundary
+			}
+		else
+			iTerminatingBoundary = EFalse;
+	
+		return KBoundaryFound;
+		}
+	
+	return KBoundaryNotFound;
+	}
+
+
+/**
+RemoveBoundary()
+*/
+void CLocalMimeParser::RemoveBoundary()
+	{
+	iBoundaryText->Delete(iBoundaryIndex);
+	if(iBoundaryText->MdcaCount())
+		{
+		iBoundaryIndex = iBoundaryText->MdcaCount(); //iBoundaryIndex stores a count value not the index here
+	
+		iBoundaryIndex = (iBoundaryIndex)? --iBoundaryIndex: 0;
+		iBoundaryLength = iBoundaryText->MdcaPoint(iBoundaryIndex).Length();
+		}
+	}
+
+
+/**
+MatchAndRemoveToken()
+
+@param aToken
+@return
+*/
+TBool CLocalMimeParser::MatchAndRemoveToken( const TDesC8& aToken )
+	{
+	TInt comparison;
+	TInt tokenLength = aToken.Length();
+	TInt desLength = (*iMimeHeaderLine).Length();
+	TInt compareLength = tokenLength > desLength ? desLength : tokenLength;
+	TPtrC8 left((*iMimeHeaderLine).Left(compareLength));
+	
+	// now see whether the current line contains the search string
+	comparison = left.CompareF(aToken);
+	if (!comparison)
+		{
+		// found the match string at the start of the output line, so remove it
+		iMimeFieldsExist=ETrue;
+		isMime=ETrue;
+		// get rid of any whitespace betweebn the tag and the data while we have a chance
+		TInt whitespaceLength=0;
+		TInt maxLength=desLength-tokenLength;
+		const TUint8* ptr = (*iMimeHeaderLine).Ptr();
+		while ( whitespaceLength <= maxLength && (ptr[tokenLength+whitespaceLength] == KImcvSP || ptr[tokenLength+whitespaceLength] == KImcvTab) )
+			whitespaceLength++;
+		iMimeHeaderLine->Des().Delete(0, tokenLength+whitespaceLength);
+
+		// Reset iLex, so its length is updated.
+		iLex = *iMimeHeaderLine;
+		}
+	return (comparison==0);
+	}
+
+
+/**
+IsSpecialChar()
+
+@param aChar
+@return
+*/
+TBool CLocalMimeParser::IsSpecialChar( const TUint8 aChar )
+	{
+	return (aChar == '(' || aChar == ')' || aChar == '<' || aChar == '>' || aChar == '@' 
+		 || aChar == ',' || aChar == ';' || aChar == ':' || aChar == '\\'|| aChar == '"' 
+		 || aChar == '/' || aChar == '[' || aChar == ']' || aChar == '?' || aChar == '=');
+	}
+
+
+/**
+ExtractParameterInfoL()
+Implicitly the parameter ASSUMED TO BE is not encoded as return parameter, rBuffer,
+is 8 bit. iLex should currently be pointing at the space after content-type description.
+
+@param aTag
+@param rBuffer
+*/
+void CLocalMimeParser::ExtractParameterInfoL(const TDesC8& aTag, HBufC8*& rBuffer)
+	{	
+	rBuffer = NULL;
+
+	TLexMark8 mark;
+	TInt offset;
+
+	if( (offset=iLex.Remainder().FindF(aTag)) != KErrNotFound )
+		{
+		// move past the tag	
+		iLex.Inc(offset+aTag.Length());
+
+		// Default : no charset info or folding
+		// move forward to the start of the boundary string itself.
+
+		while (iLex.Peek() != KImcvEquals  && !iLex.Eos())
+			iLex.Inc(); 
+
+		TPtrC8 paramBuffer(ExtractParameterString(mark));
+		if( paramBuffer.Length() > 0 )
+			{
+			rBuffer = paramBuffer.AllocL();
+			}
+		}
+	}
+
+
+/**
+ExtractParameterInfoL()
+iLex should currently be pointing at the space after content-type description.
+
+@param aTag
+@param rBuffer
+@param rBuffer8
+*/
+void CLocalMimeParser::ExtractParameterInfoL(const TDesC8& aTag, TDes16& rBuffer, TDes8& rBuffer8)
+	{
+	TInt offset;
+
+	rBuffer.Copy(KNullDesC);
+
+	// we need to extract the <aTag> text from the same line
+	// iLex should currently be pointing at the space after content-type description
+
+	if( (offset=iLex.Remainder().FindF(aTag))!=KErrNotFound )
+		{
+		// Check which type of encoding present.
+
+		TLexMark8 initMark;
+		iLex.Mark(initMark);
+		TLexMark8 mark;
+		iLex.Inc(offset+aTag.Length()); 	// move past the tag
+
+		const TPtrC8 param = ExtractParameterString(mark);
+
+		rBuffer8.Copy(param);
+
+		if ( ParseRfc2047ParameterInfoL(param, rBuffer) == EFalse )
+			{
+			iLex.UnGetToMark(initMark);
+			ParseRfc2231ParameterInfoL(aTag, rBuffer, offset );
+			}
+		}
+	}
+
+
+/**
+ParseRfc2047ParameterInfoL()
+Detect encoding of form =?charset?Q?" Text "?=
+
+@param aParam
+@param rBuffer
+@return
+*/
+TBool CLocalMimeParser::ParseRfc2047ParameterInfoL(const TDesC8& aParam, TDes& rBuffer)
+	{
+	TBool parameterPresent = EFalse;
+
+	// Check for =? somewhere in text.
+
+	if ( aParam.Find(KImcvEncodedWordStart) != KErrNotFound )
+		{
+		// Make assumption that '=?' appearing in parameter means 
+		//it is part of encoding
+	
+		parameterPresent = ETrue;
+		iImRecvConvert.iHeaderConverter->DecodeHeaderFieldL(aParam, rBuffer);
+		}
+	return parameterPresent;
+	}
+
+
+/**
+ParseRfc2231ParameterInfoL()
+For extracting parameter data following Mime header fields, in the format
+*(;tag=data). As specified in rfc2231
+Assumes parameter data seperated by ';'
+Takes tag(name) of parameter as input, returning a descriptor with the data
+
+@param aTag
+@param rBuffer
+@param aOffset
+@return
+*/
+TBool CLocalMimeParser::ParseRfc2231ParameterInfoL(const TDesC8& aTag, TDes& rBuffer, TInt aOffset)
+	{
+	TBool parameterPresent = ETrue;
+
+	// For storing extracted parameter information
+
+	HBufC8* info = HBufC8::NewLC(KHeaderBufferLength);
+
+	// For storing information relating to parameter extraction/conversion
+
+	TInt count = 0;
+
+	TPtrC8 charset8;
+	TPtrC8 language8;
+	
+	// Following rfc 2231, parameter may be encoded & folded in the following way
+	//
+	// <name>*0*=us-ascii'en'<encoded data>
+	// <name>*1*=< more encoded data>
+	// <name>*2=<unencoded info>
+
+	do 
+		{
+		// move past the tag	
+		iLex.Inc(aOffset+aTag.Length());
+
+		if (iLex.Peek() != KImcvAny) 
+			{
+			// Default : no charset info or folding
+			// move forward to the start of the boundary string itself
+
+			while (iLex.Peek() != KImcvEquals  && !iLex.Eos())
+				iLex.Inc();
+			}
+		else	// *, Parameter is encoded
+			{
+			iLex.Inc(); // Past '*'
+
+			// If parameter folded :- need to get several bits of data and join together.
+		
+			if ( iLex.Peek()!=KImcvEquals) // Get Number
+				{
+				iLex.Mark(); // Beginnig of number
+				iLex.Inc();
+				while (iLex.Peek() != KImcvEquals && iLex.Peek() != KImcvAny && !iLex.Eos())
+					iLex.Inc(); 
+				TPtrC8 numPtr = iLex.MarkedToken();
+				TLex8 lex(numPtr);
+				lex.Val(count);  // Store number in count.
+
+				if (iLex.Peek() == KImcvAny)
+					iLex.Inc(); // Past *
+				}
+
+
+			// Must get charset & language information etc..
+
+			if (!count)
+				{
+
+				iLex.Inc(); // Past '='
+
+				if (iLex.Peek()==KImcvQuote)
+					iLex.Inc(); 
+
+				// Extract CHARSET token
+				iLex.Mark();
+				while (iLex.Peek() != KImcvSingleQuote && !iLex.Eos())
+					iLex.Inc(); 
+				TPtrC8 marked = iLex.MarkedToken();
+
+				charset8.Set(marked );
+				iLex.Inc(); // Past ' 
+
+				// Extract LANGUAGE token
+				iLex.Mark();
+				while (iLex.Peek() != KImcvSingleQuote && !iLex.Eos())
+					iLex.Inc(); 
+				TPtrC8 marked1 = iLex.MarkedToken();
+				language8.Set(marked1);
+				}
+
+			} // else, param encoded
+				
+		TLexMark8 mark;
+		TPtrC8 param = ExtractParameterString(mark);
+
+		// Save parameter data
+		TInt maxlen=info->Des().MaxLength();
+		if ((*info).Length() + param.Length() > maxlen )
+			{
+			info = info->ReAllocL(maxlen + param.Length() + MaxMimeParameterValueLength);
+		 CleanupStack::Pop();
+			CleanupStack::PushL(info); 
+			}
+		info->Des().Append( param );
+
+
+		} while( ( aOffset=iLex.Remainder().FindF(aTag))!=KErrNotFound );
+
+	TPtr8 infoPtr(info->Des());	
+	
+	DecodeRfc2231ParameterInfoL( infoPtr, rBuffer, charset8/*, language8*/ );
+
+	CleanupStack::PopAndDestroy(info); 
+	return parameterPresent;
+	}
+
+
+/**
+DecodeRfc2231ParameterInfoL()
+
+@param aInput
+@param rBufOut
+@param aCharset
+@return
+*/
+TBool CLocalMimeParser::DecodeRfc2231ParameterInfoL(TDes8& aInput, TDes& rBufOut, TPtrC8 aCharset/*, TPtrC8 aLanguage*/)
+	{
+	HBufC8* QPdecodedbuf = HBufC8::NewLC( aInput.Length() );
+	TPtr8 ptr(QPdecodedbuf->Des());
+
+	iImRecvConvert.iQPCodec.SetQPChar(KImcvPercentSign);
+	iImRecvConvert.iQPCodec.Decode( aInput, ptr);
+	iImRecvConvert.iQPCodec.SetQPChar(KImcvEquals);
+
+	// Convert parameter, based on charset supplied.
+	CImConvertCharconv& charconv = iImRecvConvert.CharacterConverter();
+	TUint id = charconv.GetMimeCharsetUidL( aCharset);
+
+	if(id==KUidMsvCharsetNone)
+		{
+		id=charconv.SystemDefaultCharset();
+		}
+
+	if (!charconv.PrepareToConvertToFromOurCharsetL(id))
+		{
+		rBufOut.Copy(ptr);
+		}
+	else
+		{
+		// Charset found, so do conversion
+		TInt unconverted;
+		TInt indexOfFirst;
+		TInt rem = charconv.ConvertToOurCharsetL(ptr, rBufOut, unconverted, indexOfFirst);
+		if (rem < 0) // error
+			Append(rBufOut, ptr);
+		else if (rem && rem < KConversionRemainderLength)
+			rBufOut.Copy(ptr);	
+
+		}
+	
+	CleanupStack::PopAndDestroy(QPdecodedbuf);
+	return ETrue;
+	}
+
+
+/**
+ExtractParameterString()
+Check for delimiter & mark parameter text string
+
+@param rMark
+@return
+*/
+TPtrC8 CLocalMimeParser::ExtractParameterString(TLexMark8& rMark)
+	{
+	// move on to the first char of the boundary ; this MIGHT be a double-quote
+
+	TBool delimited = EFalse;
+	iLex.Inc();
+				
+	if ( iLex.Peek() == KImcvDoubleQuote )
+		{
+		delimited = ETrue;
+		iLex.Inc();
+		}
+
+	while ( iLex.Peek().IsSpace() )
+		iLex.Inc();
+
+	iLex.Mark( rMark );
+
+	TBool finished = EFalse;
+	while ( !finished  && !iLex.Eos() )
+		{
+		iLex.Inc();
+
+		if ( delimited )
+			finished = (iLex.Peek() == KImcvDoubleQuote);
+		else
+			finished = ( iLex.Peek().IsSpace() || IsSpecialChar((TUint8)iLex.Peek()) );
+		} 
+
+	return iLex.MarkedToken( rMark );
+	}
+
+
+/**
+CurrentCharsetL()
+Which charset to use .. ? If the body part charset set, use that.
+else if the main header charset set, use that... else default to us-ascii.
+
+@return
+*/
+TUint CLocalMimeParser::CurrentCharsetL() const
+	{
+	TPtrC8 paramCharset = GetContentTypeValue(KImcvCharset);
+
+	TUint charsetId;
+	if (paramCharset.Length())
+		// charset parameter present.
+		charsetId = iImRecvConvert.CharacterConverter().GetMimeCharsetUidL(paramCharset);
+	else if (iCharset) 
+		// Main Mime header has default charset value.
+		charsetId = iCharset;
+	else
+		charsetId = iDefaultCharset;
+
+	return charsetId;		
+	}
+
+
+/**
+GetContentTypeValue()
+
+@param aContentTypeParameter
+@return
+*/
+const TPtrC8 CLocalMimeParser::GetContentTypeValue(const TDesC8& aContentTypeParameter) const
+	{
+	CDesC8Array& contentTypeParams = iMimeHeader->ContentTypeParams();
+	__ASSERT_DEBUG(!(contentTypeParams.Count()&1), User::Invariant());
+
+	TInt result;
+	if (KErrNone == contentTypeParams.Find(aContentTypeParameter,result,ECmpFolded8))
+		{
+		result++;
+		if ((result&1) && result <= contentTypeParams.Count())    
+			{       
+			// check result+1 is odd & entry exists
+			return iMimeHeader->ContentTypeParams()[result];
+			}
+		}
+	return TPtrC8();        // couldn't find match so return an empty descriptor
+	}
+
+
+/**s
+EntryId()
+
+@return
+*/
+TMsvId CLocalImRecvConvert::EntryId()
+	{
+	// If we are temporarily on the null entry then return the saved entry
+	if (iServerEntry->Entry().Id() == KMsvNullIndexEntryId)
+		{
+		return iSavedEntryId;
+		}
+	else
+		{
+		return iServerEntry->Entry().Id();
+		}
+	}