email/pop3andsmtpmtm/servermtmutils/src/imcvrecv.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 52 12db4185673b
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32base.h>
       
    17 #include "IMUTDLL.H"
       
    18 #include "IMCVTEXT.H"
       
    19 #include "IMCVRECV.H"
       
    20 #include "IMCVCODC.H"	// TImConvert
       
    21 #include "IMCVUTIL.H"
       
    22 #include "CMsvPlainBodyTextEntry.H"
       
    23 #include <cmsvplainbodytext.h>
       
    24 
       
    25 #include <miuthdr.h>	// CImHeader
       
    26 #include <miutatch.h>	// TImAttachmentFile
       
    27 #include <msvids.h>
       
    28 #include <txtrich.h>
       
    29 #include <imcm.rsg>		// resource definition for IMCM
       
    30 
       
    31 #include <pop3set.h>	// For including KUidMsgTypePOP3
       
    32 #include <barsread.h>	// TResourceReader
       
    33 
       
    34 #include <cmsvbodytext.h>
       
    35 
       
    36 #ifdef __WINS__
       
    37 #include <e32wins.h>    // for maxfilename lengths
       
    38 #include <msvapi.h>
       
    39 #endif
       
    40 
       
    41 #ifndef __WINS__
       
    42 #include <msvapi.h>
       
    43 #endif
       
    44 #include <cmsvattachment.h> 
       
    45 #include <mmsvattachmentmanager.h>
       
    46 #include <mmsvattachmentmanagersync.h>
       
    47 
       
    48 #ifndef _MSG_NO_LOGGING
       
    49 #define __IMUT_LOGGING
       
    50 _LIT(KLogFilePath, "c:\\logs\\mailtext\\in.txt");
       
    51 _LIT8(KNewLogHeader, "\r\n------ New Receive Session ------\r\n");
       
    52 _LIT8(KFound, "found: ");
       
    53 _LIT8(KFoundIncomplete, "found but incomplete: ");
       
    54 _LIT8(KPartLine, "unknown or part line");
       
    55 _LIT8(KEndOFHeader, "End of header");
       
    56 _LIT8(KSkippingData, "Skipping data");
       
    57 _LIT8(KCollectingData7, "Collecting 7/8-bit data");
       
    58 _LIT8(KCollectingDataQP, "Collecting QP data");
       
    59 _LIT8(KCollectingBase64, "Collecting BASE64 data");
       
    60 _LIT8(KCollectingUU, "Collecting UU data");
       
    61 _LIT8(KDecodingBase64, "Decoding BASE64 data");
       
    62 _LIT8(KDecodedBase64, "Decoded BASE64 data");
       
    63 _LIT8(KDecodingUU, "Decoding UU data");
       
    64 _LIT8(KDecodedUU, "Decoded UU data");
       
    65 _LIT8(KDecodingQP, "Decoding QP data");
       
    66 _LIT8(KDecodedQP, "Decoded QP data");
       
    67 _LIT8(KUUEDataCorrupt, "UU Data is corrupt");
       
    68 _LIT8(KFoundUUEStartBoundary, "UUE start boundary");
       
    69 _LIT8(KFoundUUEEndBoundary, "UUE end boundary");
       
    70 _LIT8(KClosingAttachFile, "Closing attachment file");
       
    71 _LIT8(KDeletingAttachFile, "Deleting attachment file");
       
    72 _LIT8(KDeletedAttachFile, "Deleted attachment file");
       
    73 _LIT8(KFailedToWriteToFile, "Failed to write to attachment file");
       
    74 _LIT8(KSectionHeader, "Section header");
       
    75 _LIT8(KFoundMIMEBoundary, "MIME boundary");
       
    76 _LIT8(KWritingToBody, "writing body");
       
    77 _LIT8(KWroteToBody, "wrote body");
       
    78 _LIT8(KWritingToFile, "writing attachment");
       
    79 _LIT8(KWroteToFile, "wrote attachment");
       
    80 _LIT8(KReset, "Resetting CImRecvConvert");
       
    81 _LIT8(KReseted, "Resetting CImRecvConvert");
       
    82 _LIT8(KDelete, "Deleting CImRecvConvert");
       
    83 _LIT8(KDeleted, "Deleting CImRecvConvert");
       
    84 _LIT8(KLineHasLineBreak, "Linebreak");
       
    85 _LIT8(KLastToken, "That was the last token");
       
    86 _LIT8(KBlankLine, "Blank line");
       
    87 _LIT8(KRemoveBoundary, "Remove boundary");
       
    88 _LIT8(KRemovedBoundary, "Removed boundary");
       
    89 _LIT8(KResetForNewEntry, "Reset for a New Entry");
       
    90 _LIT8(KResetedForNewEntry, "Reseted for a New Entry");
       
    91 _LIT8(KResetForNonMimeEntry, "Reset for a New Non-Mime Entry");
       
    92 _LIT8(KResetedForNonMimeEntry, "Reseted for a New Non-Mime Entry");
       
    93 _LIT8(KCreatingEntry, "Creating Entry");
       
    94 _LIT8(KCreatedEntry, "Created Entry");
       
    95 _LIT8(KUpdatingEntry, "Updating Entry");
       
    96 _LIT8(KUpdatedEntry, "Updated Entry");
       
    97 _LIT8(KMoveToParentEntry, "Moved to parent entry");
       
    98 _LIT8(KMovedToParentEntry, "End of Moved to parent entry");
       
    99 _LIT8(KStoringHeader, "Storing CImHeader");
       
   100 _LIT8(KStoredHeader, "Stored CImHeader");
       
   101 _LIT8(KStoringBody, "Storing CRichText");
       
   102 _LIT8(KStoring8BitBody, "Storing CMsvBodyText");
       
   103 _LIT8(KStoredBody, "Stored CRichText");
       
   104 _LIT8(KStored8BitBody, "Stored CMsvBodyText");
       
   105 _LIT8(KStoringMIMEHeader, "Storing CImMimeHeader");
       
   106 _LIT8(KStoredMIMEHeader, "Stored CImMimeHeader");
       
   107 _LIT8(KIgnoringStreams, "Discarding streams");
       
   108 _LIT8(KStartMessageComplete, "Start Message Complete");
       
   109 _LIT8(KMessageComplete, "Message Complete");
       
   110 _LIT8(KHeaderComplete, "Message Header complete");
       
   111 _LIT8(KReturnReceiptTo, "return-receipt-To is set");
       
   112 _LIT8(KStartStoringEntryStream, "Starting Storing Entry Stream");
       
   113 _LIT8(KStoringEntryStream, "Storing Entry Stream");
       
   114 _LIT8(KDoneStoringEntryStream, "Done Storing Entry Stream");
       
   115 #endif // _MSG_NO_LOGGING
       
   116 
       
   117 // uncomment the line below if logging is to be enabled
       
   118 
       
   119 #if defined(__IMUT_LOGGING)
       
   120 #define RECVLOG(text) (iImcvLog?iImcvLog->AppendComment(text):void(0));
       
   121 #define RECVLOG_OUT(text) (iImcvLog?iImcvLog->AppendOut(text):void(0));
       
   122 #define LOGGING(string1, string2) (Logging(string1, string2));
       
   123 #else
       
   124 #define RECVLOG(text) (void(0));
       
   125 #define RECVLOG_OUT(text) (void(0));
       
   126 #define LOGGING(string1, string2) (void(0));
       
   127 #endif
       
   128 
       
   129 
       
   130 const TInt KBodyTextChunkSizeBytes = 512;
       
   131 
       
   132 _LIT(KIntegerKey,"%d");
       
   133 const TInt KSpaceToAddNumber=20;
       
   134 
       
   135 
       
   136 //----------------------------------------------------------------------------------------  
       
   137 LOCAL_C TBool IsIllegalChar(const TUint aChar)
       
   138 //----------------------------------------------------------------------------------------  
       
   139 	{
       
   140 	// EPOC32 filenames must not contain any of the following chars
       
   141     return (aChar == '*' || aChar == '\\' || aChar == '<' || aChar == '>' ||
       
   142 			aChar == ':'  || aChar == '"' ||  aChar    == '/' || aChar == '|' ||
       
   143 			aChar < ' ' || aChar =='?');
       
   144 	}
       
   145 
       
   146 //----------------------------------------------------------------------------------------
       
   147 LOCAL_C void RemoveSurroundingCharacters( const TUint8& aLeft, const TUint8& aRight, HBufC8& aString)
       
   148 //----------------------------------------------------------------------------------------
       
   149 	{
       
   150 	TPtr8 des = aString.Des();
       
   151 	TInt len  = des.Length();
       
   152 	
       
   153 	if( len>2 && des[0]==aLeft && des[len-1]==aRight )
       
   154 		{
       
   155 		TPtrC8 mid = des.Mid(1, len-1);
       
   156 		des.Copy(mid);
       
   157 		des.SetLength(len-2);
       
   158 		}
       
   159 	}
       
   160 
       
   161 
       
   162 //****************************************************************************************
       
   163 //              Class CRfc822Token Functions
       
   164 //****************************************************************************************
       
   165 
       
   166 //----------------------------------------------------------------------------------------
       
   167 EXPORT_C CRfc822Token* CRfc822Token::NewLC()
       
   168 //----------------------------------------------------------------------------------------
       
   169 	{
       
   170 	CRfc822Token* self = new (ELeave) CRfc822Token;
       
   171 	CleanupStack::PushL(self);
       
   172 	self->ConstructL();
       
   173 	return self;
       
   174 	}
       
   175 
       
   176 //----------------------------------------------------------------------------------------
       
   177 void CRfc822Token::ConstructL()
       
   178 //----------------------------------------------------------------------------------------
       
   179 	{
       
   180 	iOutputLine = HBufC8::NewL(KMaxIMailHeaderReadLineLength+1);
       
   181 	Reset();
       
   182 	}
       
   183 
       
   184 //----------------------------------------------------------------------------------------
       
   185 CRfc822Token::CRfc822Token()
       
   186 //----------------------------------------------------------------------------------------
       
   187 	{
       
   188 	__DECLARE_NAME(_S("CRfc822Token"));
       
   189 	}
       
   190 
       
   191 //----------------------------------------------------------------------------------------
       
   192 EXPORT_C CRfc822Token::~CRfc822Token()
       
   193 //----------------------------------------------------------------------------------------
       
   194 	{
       
   195 	delete iOutputLine;
       
   196 	}
       
   197 
       
   198 //----------------------------------------------------------------------------------------
       
   199 EXPORT_C void CRfc822Token::Reset()
       
   200 //----------------------------------------------------------------------------------------
       
   201 	{
       
   202 	iOutputLine->Des().FillZ();
       
   203 	iBufferedInput.SetLength(0);
       
   204 	iBufferedInput.FillZ();
       
   205 
       
   206 	iLastToken = EFalse;
       
   207 	iFirstLine = ETrue;
       
   208 	i822FieldsExist=EFalse;
       
   209 	}
       
   210 
       
   211 //----------------------------------------------------------------------------------------
       
   212 EXPORT_C void CRfc822Token::ParseNextLineL(const TDesC8& aSourceLine)
       
   213 //----------------------------------------------------------------------------------------
       
   214 	{
       
   215 	TBool hitEof = EFalse;
       
   216 	TBool endOfField = EFalse;
       
   217 	// Always read one more packet than we need so we know we've read the entire field.
       
   218 
       
   219 	// Consequently, we need to check whether there is any buffered input from the
       
   220 	// previous rfc822 field:*******
       
   221 
       
   222 	if(iBufferedInput.Length())
       
   223 		{
       
   224 		// the buffered input is never more than a line of text...
       
   225 		*iOutputLine = iBufferedInput;
       
   226 		
       
   227  		iBufferedInput.FillZ();
       
   228 		iBufferedInput.SetLength(0);
       
   229 		}
       
   230 	iInputLine = aSourceLine;
       
   231 
       
   232 	// discard any LF character from the begining of the line (this is abit strange?)
       
   233 	while(iInputLine.Length() > 0 && (iInputLine[0] == KImcvLF || iInputLine[0] == KImcvCR))
       
   234 		iInputLine.Delete(0, 1);
       
   235 
       
   236 	// remove the CR at the end but only if there's stuff before it
       
   237 	while(iInputLine.Length() > 0 && (iInputLine[iInputLine.Length()-1] == KImcvLF || iInputLine[iInputLine.Length()-1] == KImcvCR))
       
   238 		iInputLine.Delete(iInputLine.Length()-1, 1);
       
   239 
       
   240 	// if the newly read line is now empty, then don't read any more through this tokeniser
       
   241 	iLastToken = !iInputLine.Length();
       
   242 
       
   243 	// only bother with the rest of the parsing if there's any data left
       
   244 	if(iInputLine.Length() > 0 || iOutputLine->Length() > 0)
       
   245 		{
       
   246 		// check whether we're on the next field or still on the current one
       
   247 		if(!iFirstLine && iInputLine.Length() > 0 && iInputLine[0] != KImcvSP && iInputLine[0] != KImcvTab)
       
   248 			{
       
   249 			// we've read the first line of the next field
       
   250 			iBufferedInput = iInputLine;
       
   251 			endOfField = ETrue; // flag the fact that the current field is ready for parsing
       
   252 			}
       
   253 		else // the line belongs in the current field, we need to keep the leading whitespace
       
   254 			 // Folding headers, RFC 2822, section 2.2.3
       
   255 			{
       
   256 			// make sure we're not about to exceed the buffer
       
   257 			//Restricting the field size of the header to 5000, to avoid -4 error
       
   258 			//and which at times ends up in DOS condition [denial of service- user wouldn't be able to download any further mails]. 
       
   259 			if (iOutputLine->Length()<5000)
       
   260 				{
       
   261 				if((iOutputLine->Length() + iInputLine.Length()) > iOutputLine->Des().MaxLength())
       
   262 					iOutputLine = iOutputLine->ReAllocL(iOutputLine->Length() + iInputLine.Length());
       
   263 
       
   264 				// now copy the remaining data into the buffer
       
   265 				iOutputLine->Des().Append(iInputLine);
       
   266 			    }
       
   267 			}
       
   268 		}
       
   269 	else
       
   270 		hitEof = ETrue;		//this means that EEndOfHeader is set if a line of zero length is parsed - ie. (clean CRLF - CRLF) = 0.
       
   271 	iFirstLine = EFalse;
       
   272 
       
   273 	if(endOfField || iLastToken)
       
   274 		{ 
       
   275 		// only parse the input when we have a whole field, 
       
   276 		// or we just found the blank line that
       
   277 		// separates the body from the header
       
   278 		if(MatchAndRemoveL(KImcvFromPrompt))
       
   279 			iHeaderPart = EFrom;
       
   280 		else if(MatchAndRemoveL(KImcvReplyToPrompt))
       
   281 			iHeaderPart = EReplyTo;
       
   282 		else if(MatchAndRemoveL(KImcvToPrompt))
       
   283 			iHeaderPart = ETo;
       
   284 		else if(MatchAndRemoveL(KImcvCcPrompt))
       
   285 			iHeaderPart = ECc;
       
   286 		else if(MatchAndRemoveL(KImcvBccPrompt))
       
   287 			iHeaderPart = EBcc;
       
   288 		else if(MatchAndRemoveL(KImcvSubjectPrompt))
       
   289 			iHeaderPart = ESubject;
       
   290 		else if(MatchAndRemoveL(KImcvDatePrompt))
       
   291 			iHeaderPart = EDate;
       
   292 		else if(MatchAndRemoveL(KImcvReceivedPrompt))
       
   293 			iHeaderPart = EReceived;
       
   294 		else if(MatchAndRemoveL(KImcvMessageIdPrompt))
       
   295 			{
       
   296 			iHeaderPart = EMessageId;
       
   297 			RemoveSurroundingCharacters(KImcvLeftChevron, KImcvRightChevron, *iOutputLine);
       
   298 			}
       
   299 		else if (PriorityAndReceiptsMatchAndRemoveL(EPriority))
       
   300 			iHeaderPart=EPriority;
       
   301 		else if (PriorityAndReceiptsMatchAndRemoveL(EReturnReceiptTo))
       
   302 			iHeaderPart=EReturnReceiptTo;
       
   303 		else if(hitEof)
       
   304 			iHeaderPart = EEndOfHeader;
       
   305 		else
       
   306 			{
       
   307 			iHeaderPart = EUnknown;
       
   308 			iImRecvConvert->iMimeParser->ParseLineL(*iOutputLine);
       
   309 			}
       
   310 		}
       
   311 	else 
       
   312 		iHeaderPart = ENotFinished;
       
   313 	}
       
   314 
       
   315 TBool CRfc822Token::PriorityAndReceiptsMatchAndRemoveL(THeaderPart aPriority)
       
   316 	{
       
   317 	CDesC8Array* fields=new (ELeave)CDesC8ArrayFlat(6);
       
   318 	CleanupStack::PushL(fields);
       
   319 	if (aPriority==EPriority)
       
   320 		CImcvUtils::PriorityFieldsL(*fields);
       
   321 	else if (aPriority==EReturnReceiptTo)
       
   322 		CImcvUtils::ReceiptFieldsL(*fields);
       
   323 	else
       
   324 		{
       
   325 		CleanupStack::PopAndDestroy(); //fields
       
   326 		return EFalse;
       
   327 		}
       
   328 	TInt count=fields->Count();
       
   329 	TBool matched=EFalse;
       
   330 	for (TInt i=0;i<count;i++)
       
   331 		{
       
   332 		if (MatchAndRemoveL((*fields)[i]))
       
   333 			{
       
   334 			matched=ETrue;
       
   335 			break;
       
   336 			}
       
   337 		}
       
   338 	CleanupStack::PopAndDestroy(); //fields
       
   339 	return matched;
       
   340 	}
       
   341 
       
   342 //----------------------------------------------------------------------------------------
       
   343 TBool CRfc822Token::MatchAndRemoveL(const TDesC8& aString)
       
   344 //----------------------------------------------------------------------------------------
       
   345 	{
       
   346 	TInt comparison;
       
   347 	TInt stringLength = aString.Length();
       
   348 	TInt desLength = (*iOutputLine).Length();
       
   349 	TInt compareLength = stringLength > desLength ? desLength : stringLength;
       
   350 	TPtrC8 left((*iOutputLine).Left(compareLength));
       
   351 	
       
   352 	// now see whether the current line contains the search string
       
   353 	comparison = left.CompareF(aString);
       
   354 	if(!comparison)
       
   355 		{
       
   356 		// found the match string at the start of the output line, so remove it
       
   357 		// get rid of any whitespace betweebn the tag and the data while we have a chance
       
   358 		if (!i822FieldsExist)
       
   359 			i822FieldsExist=ETrue;
       
   360 		TInt whitespaceLength=0;
       
   361 		TInt maxLength=desLength-stringLength;
       
   362 		const TUint8* ptr = (*iOutputLine).Ptr();
       
   363 		while(whitespaceLength <= maxLength && (ptr[stringLength+whitespaceLength] == KImcvSP || ptr[stringLength+whitespaceLength] == KImcvTab))
       
   364 			whitespaceLength++;
       
   365 		(iOutputLine->Des()).Delete(0, stringLength+whitespaceLength);
       
   366 		}
       
   367 	return (comparison==0);
       
   368 	}
       
   369 
       
   370 
       
   371 //****************************************************************************************
       
   372 //             Class CImRecvConvert
       
   373 //****************************************************************************************
       
   374 //----------------------------------------------------------------------------------------    
       
   375 EXPORT_C CImRecvConvert* CImRecvConvert::NewLC(RFs& anFs, CMsvServerEntry* aServerEntry, 
       
   376 												TUid aMsgType, TMsvId aEmailServiceId)
       
   377 //----------------------------------------------------------------------------------------  
       
   378 	{
       
   379 	CImRecvConvert* self = new (ELeave) CImRecvConvert(anFs, aServerEntry, aMsgType, 
       
   380 																		aEmailServiceId);
       
   381 	CleanupStack::PushL(self);
       
   382 	self->ConstructL(anFs);
       
   383 	return self;
       
   384 	}
       
   385 
       
   386 //----------------------------------------------------------------------------------------  
       
   387 EXPORT_C CImRecvConvert* CImRecvConvert::NewL(RFs& anFs, CMsvServerEntry* aServerEntry, 
       
   388 												TUid aMsgType, TMsvId aEmailServiceId)
       
   389 //----------------------------------------------------------------------------------------  
       
   390 	{
       
   391 	CImRecvConvert* self = CImRecvConvert::NewLC(anFs, aServerEntry, aMsgType, 
       
   392 																aEmailServiceId);
       
   393 	CleanupStack::Pop();
       
   394 	return self;
       
   395 	}
       
   396 
       
   397 //----------------------------------------------------------------------------------------  
       
   398 void CImRecvConvert::ConstructL(RFs& anFs)
       
   399 //----------------------------------------------------------------------------------------  
       
   400 	{
       
   401 	iFsSession = &anFs;  
       
   402 
       
   403 	RResourceFile resFile;
       
   404 	OpenResourceFileL(resFile, anFs);	// NB leaves if file not found
       
   405 
       
   406 	// make sure the resource file will be closed if anything goes wrong
       
   407 	// CloseResourceFile is declared in IMUTDLL.H and defined in IMUTDLL.CPP
       
   408 	TCleanupItem close( CloseResourceFile, &resFile );
       
   409 	CleanupStack::PushL( close );
       
   410 	
       
   411 	// Read iStore8BitData flag.
       
   412 	HBufC8* buf = resFile.AllocReadLC( STORE_8BIT_BODY_TEXT );
       
   413 	TResourceReader reader;
       
   414 	reader.SetBuffer(buf);
       
   415 	iStore8BitData = reader.ReadInt8();
       
   416 	CleanupStack::PopAndDestroy(buf);
       
   417 	
       
   418 	//read iStorePlainBodyText flag for writing bodytext chunk bu chunk.
       
   419 	buf = resFile.AllocReadLC( STORE_PLAIN_BODY_TEXT );
       
   420 	reader.SetBuffer(buf);
       
   421 	iStorePlainBodyText = reader.ReadInt8();
       
   422 	CleanupStack::PopAndDestroy(buf);
       
   423 
       
   424 
       
   425 	buf = resFile.AllocReadLC( REMOVED_ATTACHMENT_TAG );
       
   426 	reader.SetBuffer(buf);
       
   427 	iRemovedAttachmentTag = reader.ReadTPtrC().AllocL();
       
   428 	CleanupStack::PopAndDestroy(buf);
       
   429 	
       
   430 	buf = resFile.AllocReadLC( DEFAULT_ATTACHMENT_NAME );
       
   431 	reader.SetBuffer(buf);
       
   432 	iDefaultAttachmentName = reader.ReadTPtrC().AllocL();
       
   433 	CleanupStack::PopAndDestroy(buf);
       
   434 
       
   435 	buf = resFile.AllocReadLC(PARTIAL_DOWNLOAD_FOOTER_MESSAGE);
       
   436 	reader.SetBuffer(buf);
       
   437 	if(iStore8BitData)
       
   438 		{
       
   439 		iPartialEmailFooter8 = buf;
       
   440 		CleanupStack::Pop(buf);
       
   441 		}
       
   442 	else
       
   443 		{
       
   444 		iPartialEmailFooter = (reader.ReadTPtrC()).AllocL();
       
   445 		CleanupStack::PopAndDestroy(buf);
       
   446 		}
       
   447 	buf = NULL;
       
   448 	CleanupStack::PopAndDestroy(&resFile); // resFile (Close resfile)
       
   449 
       
   450 	// create CImHeader object to store Rfc822 header info...
       
   451 	iOutputHeader = CImHeader::NewLC();	// PushL(iHeader)
       
   452 	CleanupStack::Pop();				// iHeader
       
   453 	if (iStore8BitData)
       
   454 		{
       
   455 		//Create body text storage helper.
       
   456 		iBodyText = CMsvBodyText::NewL();
       
   457 		}
       
   458 	else
       
   459 		{
       
   460 		// create CRichText object to store body...
       
   461 		iParaLayer = CParaFormatLayer::NewL();
       
   462 		iCharLayer = CCharFormatLayer::NewL();
       
   463 		iOutputBody = CRichText::NewL(iParaLayer, iCharLayer);
       
   464 		}
       
   465 		
       
   466 	// Create Rfc822 filter object...
       
   467 	iRfc822Token = CRfc822Token::NewLC(); // PushL(iRfc822Token)
       
   468 	CleanupStack::Pop();				  // iRfc822Token
       
   469 	iRfc822Token->SetImRecvConvert(this);
       
   470 
       
   471 	// Create converter objects...
       
   472 	iCharacterConverter = CCnvCharacterSetConverter::NewL();
       
   473 	iCharConv = CImConvertCharconv::NewL(*iCharacterConverter, anFs);
       
   474 	iHeaderConverter = CImConvertHeader::NewL(*iCharConv); 
       
   475 		
       
   476 	// Create MIME filter object...
       
   477 	iMimeParser = CMimeParser::NewL(*this);
       
   478 	
       
   479 	
       
   480 	// logfile stuff
       
   481 	iImcvLog=NULL;
       
   482 
       
   483 #ifdef __IMUT_LOGGING	
       
   484 	TRAPD(err,iImcvLog=CImLog::NewL(KLogFilePath, EAppend));
       
   485 #endif
       
   486 
       
   487 	iRootEntryId = EntryId();
       
   488 
       
   489 	iNotFinishedRfc822Header = ETrue;
       
   490 	
       
   491 	iEmailEntry = new (ELeave) TMsvEmailEntry;
       
   492 	iReceivingHeadersOnly=EFalse;	
       
   493 
       
   494 	iParent = new (ELeave) CArrayFixFlat<TParentDetails>(3);
       
   495 
       
   496 	iFirstBoundaryReached=EFalse;
       
   497 
       
   498 	ResetL();
       
   499 	
       
   500 	RECVLOG( KNewLogHeader )
       
   501 	}
       
   502 
       
   503 //----------------------------------------------------------------------------------------  
       
   504 CImRecvConvert::CImRecvConvert(RFs& anFs, CMsvServerEntry* aServerEntry, 
       
   505 							   TUid aMsgType, TMsvId aEmailServiceId)
       
   506 				: iServerEntry(aServerEntry), iNewMsgType(aMsgType), iDefaultEntryType(ETextEntry), 
       
   507 			  	  iEmailServiceId(aEmailServiceId), iAttachmentFile(anFs)
       
   508 //----------------------------------------------------------------------------------------  
       
   509 	{
       
   510 	__DECLARE_NAME(_S("CImRecvConvert"));
       
   511 	}
       
   512 
       
   513 //----------------------------------------------------------------------------------------  
       
   514 EXPORT_C CImRecvConvert::~CImRecvConvert()
       
   515 //----------------------------------------------------------------------------------------  
       
   516 	{
       
   517 	delete iEmailEntry;
       
   518 	delete iOutputHeader;
       
   519 	delete iBodyText;
       
   520 	delete iBodyBuf;
       
   521 	delete iParaLayer;
       
   522 	delete iCharLayer;
       
   523 	delete iOutputBody;
       
   524 	delete iRemovedAttachmentTag;
       
   525 	delete iDefaultAttachmentName;
       
   526 	delete iRfc822Token;
       
   527 	delete iMimeParser;
       
   528 	delete iHeaderConverter;
       
   529 	delete iCharConv;
       
   530 	delete iCharacterConverter;
       
   531 	delete iAttachmentFullPath;
       
   532 	delete iImcvUtils;
       
   533 	delete iParent;
       
   534 	RECVLOG(KDeleted)
       
   535 	delete iImcvLog;
       
   536 	delete iPartialEmailFooter8;
       
   537 	delete iPartialEmailFooter;
       
   538 	delete iPlainBodyTextEntry;
       
   539 	delete iPartialRetrievalBody;
       
   540 	iPartialRetrievalBody=NULL;
       
   541 	}
       
   542 
       
   543 //----------------------------------------------------------------------------------------  
       
   544 EXPORT_C void CImRecvConvert::Cancel()
       
   545 //----------------------------------------------------------------------------------------  
       
   546 	{
       
   547 	if(iAttachmentFileState == EFileIsOpen)
       
   548 		{
       
   549 		iAttachmentFileState = EFileIsIncomplete; //because of cancel during download
       
   550 		}
       
   551 	TRAPD(ignore, CloseAttachmentFileL()); //ensure the file is closed, and deleted
       
   552 	}
       
   553 
       
   554 
       
   555 
       
   556 //----------------------------------------------------------------------------------------  
       
   557 EXPORT_C void CImRecvConvert::ResetForHeadersL()
       
   558 //----------------------------------------------------------------------------------------  
       
   559 	{
       
   560 	// This function is used in preference to ResetL() when the owner
       
   561 	// only wishes to create  email entries in the remote mailbox - 
       
   562 	// they do not wish to create any stores associated with the message
       
   563 	// entry
       
   564 	ResetL();
       
   565 	iReceivingHeadersOnly=ETrue;
       
   566 	}
       
   567 //----------------------------------------------------------------------------------------  
       
   568 EXPORT_C void CImRecvConvert::ResetL()
       
   569 //----------------------------------------------------------------------------------------  
       
   570 	{
       
   571 	RECVLOG(KReset) 
       
   572 
       
   573 	iBodyId = KMsvNullIndexEntryId;
       
   574 	iSizeOfAttachmentsRemoved = 0;
       
   575 
       
   576 	User::LeaveIfError(iServerEntry->SetEntry(iRootEntryId));
       
   577 	
       
   578 	iReceivingHeadersOnly = EFalse;
       
   579 	iMessageEntryCalled = EFalse;
       
   580 	iLeaveError = KErrNone; 		
       
   581 	iCurrentMultipartFolderEntryId = 0;
       
   582 
       
   583 	TParentDetails parent;
       
   584 	parent.iAttachment = EFalse;
       
   585 	parent.iMHTML = EFalse;
       
   586 	parent.iICal = EFalse;
       
   587 	parent.iVCal = EFalse;
       
   588 	parent.iSize = 0;
       
   589 	iParent->InsertL(0,parent);
       
   590 
       
   591 	if(iEmailEntry)
       
   592 		{
       
   593 		delete iEmailEntry;
       
   594 		iEmailEntry = NULL;
       
   595 		}
       
   596 	iEmailEntry = new (ELeave) TMsvEmailEntry;
       
   597 
       
   598 	// "iSavingAttachments" commands this code to store attachments in files.
       
   599 	// Currently this is always set to ETrue as we intend to save all attachments
       
   600 	// However, if the user wishes to discard (ie do not save) any 
       
   601 	// attachments in incoming email messages - then this member variable
       
   602 	// may be set to EFalse by the inline accessor function "SaveAllAttachments(TBool)"
       
   603 	iSavingAttachments = ETrue;
       
   604 	iAttachmentFileState = EFileIsClosed;
       
   605 
       
   606 	// iLeaveError contains the error value of any functions that leaves (ie CRichText::InsertL)
       
   607 	// or any returned error value that generates a leave from within CImRecvConvert (ie RFile::Create)
       
   608 
       
   609 	iGlobalIndent = 0;
       
   610 	iLongestLine = 50;
       
   611 	
       
   612 	iImPriority = EMsvMediumPriority;
       
   613 	delete iImcvUtils;
       
   614 	iImcvUtils = NULL;
       
   615 	iImcvUtils = CImcvUtils::NewL();
       
   616 
       
   617 	// reset internal date
       
   618 	iTimeDate.UniversalTime();
       
   619 	iParsedTime=EFalse;
       
   620 	
       
   621 	iMimeParser->Reset();
       
   622 	
       
   623 	iNewEntry = EFalse; //EFalse if the entry was moved to. ETrue if the entry was just created
       
   624 	iTopMessagePart = KMsvNullIndexEntryId; //A value of NULL indicates the next entry created is a main message entry
       
   625 	ResetForNewEntryL(iDefaultEntryType);
       
   626 	iMIMEPart_822Header = EFalse;
       
   627 	iPartialEmail = EFalse;
       
   628 
       
   629 	RECVLOG(KReseted) 
       
   630 	}
       
   631 
       
   632 //----------------------------------------------------------------------------------------
       
   633 void CImRecvConvert::ResetForNewEntryL(TValidEntryType entryType)
       
   634 //----------------------------------------------------------------------------------------
       
   635 	{
       
   636 	RECVLOG(KResetForNewEntry) 
       
   637 
       
   638 	iFinishedHeader = EFalse;
       
   639 
       
   640 	iPreviousLineLength = 0;
       
   641 	iPreviousTrailingWhitespace = 0;
       
   642 	iLastChar = 0;
       
   643 
       
   644 	// Reset the new entry state
       
   645 	ResetForNonMimeEntryL();
       
   646 
       
   647 	// Clear the storage classes
       
   648 	iMimeParser->ResetForNewEntry();
       
   649 	iRfc822Token->Reset();
       
   650 
       
   651 	iEmailPart = KNoPart;
       
   652 	iEntryType=entryType;
       
   653 
       
   654 	if (iEntryType==EMessageEntry)
       
   655 		{
       
   656 		iEmailPart = KParentPart;
       
   657 		iMimeParser->SetMessageFolderType(EFolderTypeRFC822);
       
   658 		}
       
   659 	}
       
   660 
       
   661 //----------------------------------------------------------------------------------------
       
   662 void CImRecvConvert::ResetForNonMimeEntryL()
       
   663 //----------------------------------------------------------------------------------------
       
   664 	{
       
   665 	iEntryType = ETextEntry;
       
   666 	RECVLOG(KResetForNonMimeEntry) 
       
   667 
       
   668 	iSkipData = EFalse;
       
   669 	iPrepared = EFalse;
       
   670 	iNewNonMIMEBodyPart=ETrue;
       
   671 	iEncounteredLineEndingInCarriageReturn=EFalse;
       
   672 
       
   673 	iAlgorithm = ENoAlgorithm;
       
   674 	iCurrentPartIsRichText = ETrue;	
       
   675 	CloseAttachmentFileL();
       
   676 	iEntryDataSize = 0;
       
   677 	
       
   678 	if (iStore8BitData)
       
   679 		{
       
   680 		//Create a buffer to hold the body text as it is down loaded.
       
   681 		delete iBodyBuf;
       
   682 		iBodyBuf = NULL;
       
   683 		iBodyBuf = CBufSeg::NewL(KBodyTextChunkSizeBytes);
       
   684 		}
       
   685 	else
       
   686 		{
       
   687 		iOutputBody->Reset();
       
   688 		}	
       
   689 	iAttachmentName.Zero();
       
   690 	iFinalLine = EFalse;
       
   691 
       
   692 	iOutputHeader->Reset();
       
   693 	iEmptyHeaderSize=iOutputHeader->DataSize();
       
   694 	RECVLOG(KResetedForNonMimeEntry) 
       
   695 	}
       
   696 
       
   697 //----------------------------------------------------------------------------------------  
       
   698 EXPORT_C TInt CImRecvConvert::ParseNextField(const TDesC8& aSourceLine) 
       
   699 //----------------------------------------------------------------------------------------  
       
   700 	{
       
   701 	__ASSERT_DEBUG(iRootEntryId!=KMsvNullIndexEntryId, gPanic(KPanicServiceIdNotValid));
       
   702 	RECVLOG_OUT(aSourceLine);
       
   703 
       
   704 	// If we are temporarily on the null entry then move back to the entry we are working on
       
   705 	if ((iLeaveError == KErrNone) && (iServerEntry->Entry().Id() == KMsvNullIndexEntryId))
       
   706 		iLeaveError = iServerEntry->SetEntry(iSavedEntryId);
       
   707 
       
   708 	if(iLeaveError==KErrNone)
       
   709 		TRAP(iLeaveError, ParseNextLineL(aSourceLine));		
       
   710 
       
   711 	// Save the current entry id for later.
       
   712 	if (iLeaveError==KErrNone)
       
   713 		iSavedEntryId = iServerEntry->Entry().Id();
       
   714 
       
   715 	TUid type = iServerEntry->Entry().iType;
       
   716 	if( type != KUidMsvMessageEntry    &&
       
   717 		type != KUidMsvEmailTextEntry  &&
       
   718 		type != KUidMsvEmailHtmlEntry  &&
       
   719 		type != KUidMsvAttachmentEntry)
       
   720 		{
       
   721 		// Set the current id to null so that we aren't locking any folders
       
   722 		iServerEntry->SetEntry(KMsvNullIndexEntryId); 
       
   723 		}
       
   724 
       
   725 	return iLeaveError;
       
   726 	}
       
   727 
       
   728 
       
   729 //----------------------------------------------------------------------------------------  
       
   730 void CImRecvConvert::ParseNextLineL(const TDesC8& aSourceLine)
       
   731 //----------------------------------------------------------------------------------------  
       
   732 	{
       
   733 	iParsedMimeBoundaryLast=0;
       
   734 	if(!iFinishedHeader)
       
   735 		{
       
   736 		// start by getting the next token from the header
       
   737 		iRfc822Token->ParseNextLineL(aSourceLine);
       
   738 
       
   739 		switch(iRfc822Token->iHeaderPart)
       
   740 			{
       
   741 			case CRfc822Token::EUnknown:
       
   742 			case CRfc822Token::ENotFinished:
       
   743 				RECVLOG(KPartLine)
       
   744 				break;
       
   745 			case CRfc822Token::EFrom:
       
   746 				iOutputHeader->SetFromL(*iRfc822Token->OutputLine());
       
   747 				LOGGING(KFound,KImcvFromPrompt);
       
   748 				break;
       
   749 			case CRfc822Token::EReplyTo:
       
   750 				iOutputHeader->SetReplyToL(*iRfc822Token->OutputLine());
       
   751 				LOGGING(KFound,KImcvReplyToPrompt);
       
   752 				break;
       
   753 			case CRfc822Token::ETo:
       
   754 				ParseRecipientListL(iOutputHeader->ToRecipients());
       
   755 				LOGGING(KFound,KImcvToPrompt);
       
   756 				break;
       
   757 			case CRfc822Token::ECc: 
       
   758 				ParseRecipientListL(iOutputHeader->CcRecipients());
       
   759 				LOGGING(KFound,KImcvCcPrompt);
       
   760 				break;
       
   761 			case CRfc822Token::EBcc: 
       
   762 				ParseRecipientListL(iOutputHeader->BccRecipients());
       
   763 				LOGGING(KFound,KImcvBccPrompt);
       
   764 				break;
       
   765 			case CRfc822Token::ESubject:
       
   766 				iOutputHeader->SetSubjectL(*iRfc822Token->OutputLine());
       
   767 				LOGGING(KFound,KImcvSubjectPrompt);
       
   768 				break;
       
   769 			case CRfc822Token::EDate:
       
   770 			// if we have not already parsed the date from the received header.
       
   771 				if(!iParsedTime)
       
   772 					{
       
   773 					iRfc822Date.ParseDateField(*iRfc822Token->OutputLine() , iTimeDate);
       
   774 					
       
   775 					//if this is an embedded entry
       
   776 					if (iEmailEntry->Id() != iTopMessagePart)
       
   777 						{
       
   778 						iEmailEntry->iDate = iTimeDate;
       
   779 						}
       
   780 						
       
   781 					LOGGING(KFound,KImcvDatePrompt);	
       
   782 					}
       
   783 				break;
       
   784 			case CRfc822Token::EReceived:
       
   785 				if(!iParsedTime)
       
   786 					{
       
   787 					//	remove the data before the comma, to just leave the date
       
   788 					TPtr8 ptr(iRfc822Token->OutputLine()->Des());
       
   789 					TInt lPos=ptr.Locate(';');
       
   790 
       
   791 					// No point trying to process a date if we did not find the ';' or
       
   792 					// if there is no data after the ';'
       
   793 					if ((lPos != KErrNotFound) && (lPos < ptr.Length() - 2))
       
   794 						{
       
   795 						ptr = ptr.Right(ptr.Length()-lPos-2);
       
   796 						iRfc822Date.ParseDateField(ptr,iTimeDate);
       
   797 					
       
   798 						//if this is an embedded entry
       
   799 						if (iEmailEntry->Id() != iTopMessagePart)
       
   800 							{
       
   801 							iEmailEntry->iDate=iTimeDate;	
       
   802 							}
       
   803 						//indicate that we have the time stamp for the entry
       
   804 						iParsedTime=ETrue;
       
   805 						
       
   806 						LOGGING(KFound,KImcvReceivedPrompt);	
       
   807 						}
       
   808 					else
       
   809 						{
       
   810 						LOGGING(KFoundIncomplete, KImcvReceivedPrompt);
       
   811 						}
       
   812 					}
       
   813 				break;
       
   814 				
       
   815 			case CRfc822Token::EMessageId:
       
   816 				iOutputHeader->SetImMsgIdL(*iRfc822Token->OutputLine());
       
   817 				LOGGING(KFound,KImcvMessageIdPrompt);
       
   818 				break;
       
   819 			case CRfc822Token::EPriority:
       
   820 				iImPriority=iImcvUtils->EvaluatePriorityText(*iRfc822Token->OutputLine());
       
   821 				LOGGING(KFound,KImcvPriorityPrompt);
       
   822 				break;
       
   823 			case CRfc822Token::EReturnReceiptTo:
       
   824 				iOutputHeader->SetReceiptAddressL(*iRfc822Token->OutputLine());
       
   825 				LOGGING(KFound,KReturnReceiptTo);
       
   826 				break;
       
   827 			case CRfc822Token::EEndOfHeader:
       
   828 				// the next line goes in the body part
       
   829 				iFinishedHeader = ETrue;
       
   830 				RECVLOG(KEndOFHeader)
       
   831 				break;
       
   832 			default:
       
   833 				RECVLOG(KEndOFHeader)
       
   834 				break;
       
   835 			}
       
   836 
       
   837 
       
   838 		if(iRfc822Token->iHeaderPart != CRfc822Token::ENotFinished)
       
   839 			{
       
   840 			// Now that we've used the data, we also need to clear the output line from the tokeniser....
       
   841 			iRfc822Token->OutputLine()->Des() = KNullDesC8;
       
   842 
       
   843 			// whatever part we just read, we may also have read the empty line that separates
       
   844 			// the header from the body
       
   845 			if((iFinishedHeader = iRfc822Token->LastToken()) != EFalse)	//iFinishedHeader set to 1 on CRLF-
       
   846 				{
       
   847 				RECVLOG(KLastToken);
       
   848 				iNotFinishedRfc822Header = EFalse;
       
   849 
       
   850 				iHeaderConverter->SetMessageType(iMimeParser->MessageIsMime());
       
   851 				iHeaderConverter->DecodeAllHeaderFieldsL(*iOutputHeader);
       
   852 
       
   853 				if (iMimeParser->MessageIsMime())
       
   854 					EndOfHeaderMIMEProcessingL();
       
   855 				else
       
   856 					EndOfHeaderProcessingL();
       
   857 
       
   858 				// CMsvPlainBodyText will be using for storing bodytext in chunks.
       
   859 				if(iStorePlainBodyText && iEmailEntry->iType==KUidMsvEmailTextEntry)
       
   860 					{	
       
   861 					iFirstLinePlainText = ETrue;
       
   862 					}
       
   863 				else
       
   864 					{
       
   865 					if (iStore8BitData)
       
   866 						{
       
   867 						iBodyText->SetDefaultCharacterSet(iCharConv->SystemDefaultCharset());
       
   868 						if ( iMimeParser->MessageIsMime() && iMimeParser->ContentType()==EMimeText )
       
   869 							iBodyText->SetCharacterSet(iMimeParser->CurrentCharsetL());
       
   870 						else
       
   871 							iBodyText->SetCharacterSet(0);
       
   872 						}
       
   873 					else
       
   874 						{
       
   875 						// Get charset for decoding.
       
   876 						if ( iMimeParser->MessageIsMime() && iMimeParser->ContentType()==EMimeText )
       
   877 							iCharConv->PrepareToConvertToFromOurCharsetL(iMimeParser->CurrentCharsetL());
       
   878 						else
       
   879 							iCharConv->PrepareToConvertToFromOurCharsetL(iCharConv->SystemDefaultCharset());						
       
   880 						}
       
   881 					}
       
   882 				}
       
   883 			}
       
   884 		}
       
   885 	else if (iReceivingHeadersOnly==EFalse)
       
   886 		{	
       
   887 		//Set to EFalse when a single line is to be skipped (ie boundary line)
       
   888 		iCommitLine=ETrue; 
       
   889 
       
   890 		// read one line of the message body if I am processing a whole email message
       
   891 		if(iMimeParser->MessageIsMime())
       
   892 			ParseMimeLineL(aSourceLine);
       
   893 		else
       
   894 			ParseBodyLineL(aSourceLine);	
       
   895 
       
   896 		if((iCommitLine)&&(!iSkipData))
       
   897 			DecodeAndStoreLineL(aSourceLine);
       
   898 		}
       
   899 	}
       
   900 
       
   901 //----------------------------------------------------------------------------------------  
       
   902 EXPORT_C TMsvEmailEntry CImRecvConvert::MessageEntryDetailsL()
       
   903 //----------------------------------------------------------------------------------------  
       
   904 	{
       
   905 
       
   906 	iMessageEntryCalled=ETrue;
       
   907 	CloseAttachmentFileL();
       
   908 
       
   909 	// A message requiring manual termination and not part way through a MIME part header
       
   910 	if( iTopMessagePart==EntryId() && iFinishedHeader) 
       
   911 		StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader);
       
   912 	else
       
   913 		{
       
   914 		User::LeaveIfError(iServerEntry->SetEntry(iTopMessagePart));         
       
   915 		if(iEmailEntry)
       
   916 			{
       
   917 			delete iEmailEntry;
       
   918 			iEmailEntry=NULL;
       
   919 			}
       
   920 	
       
   921 		iEmailEntry = new (ELeave) TMsvEmailEntry(iServerEntry->Entry());
       
   922 		}
       
   923 		
       
   924 	return *iEmailEntry;
       
   925 	}
       
   926 
       
   927 
       
   928 //----------------------------------------------------------------------------------------  
       
   929 EXPORT_C void CImRecvConvert::MessageCompleteL(TMsvEmailEntry aEmailEntry)
       
   930 //----------------------------------------------------------------------------------------  
       
   931 	{
       
   932 	// Restore the entry context
       
   933 	if (iServerEntry->Entry().Id() == KMsvNullIndexEntryId)
       
   934 		User::LeaveIfError(iServerEntry->SetEntry(iSavedEntryId));
       
   935 
       
   936 	__ASSERT_DEBUG(iMessageEntryCalled, gPanic(KPanicMessageEntryNotCalled));
       
   937 	__ASSERT_DEBUG(aEmailEntry.Id()==iTopMessagePart, gPanic(KPanicMessageEntryIdHasChanged)); // Id should be set to iTopMessagePart
       
   938 
       
   939 	// Called ResetL() to reset object instead of ResetForHeadersL()
       
   940 	__ASSERT_DEBUG(iReceivingHeadersOnly, gPanic(KPanicIncorrectResetState)); 
       
   941 
       
   942 	if(iEmailEntry)
       
   943 		{
       
   944 		if (iEmailEntry->Id())
       
   945 			{
       
   946 			if(iLeaveError==KErrNone)
       
   947 				{
       
   948 				// a remote email header cannot have any attachments or be marked as complete...
       
   949 				aEmailEntry.SetAttachment(EFalse);
       
   950 				aEmailEntry.SetMHTMLEmail(EFalse);
       
   951 				aEmailEntry.SetComplete(EFalse);
       
   952 				User::LeaveIfError(iServerEntry->ChangeEntryBulk(aEmailEntry));
       
   953 				RECVLOG(KHeaderComplete)
       
   954 				}
       
   955 			else
       
   956 				{
       
   957 				if (!iPopulateMessage)
       
   958 					{
       
   959 					TMsvId currentId = EntryId();
       
   960 					User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent()));			
       
   961 					User::LeaveIfError(iServerEntry->DeleteEntry(currentId));
       
   962 					}
       
   963 				User::Leave(iLeaveError);
       
   964 				}
       
   965 			}
       
   966 		}
       
   967 
       
   968 	// Save the entry context and move it to null so that we're not locking any folders
       
   969 	iSavedEntryId = iServerEntry->Entry().Id();
       
   970 	User::LeaveIfError(iServerEntry->SetEntry(KMsvNullIndexEntryId));
       
   971 	}
       
   972 
       
   973 
       
   974 EXPORT_C void CImRecvConvert::MessageCompleteL(TBool aPartialDownload)
       
   975 	{
       
   976 	iPartialEmail=aPartialDownload;
       
   977 	MessageCompleteL();
       
   978 	}
       
   979 
       
   980 
       
   981 //----------------------------------------------------------------------------------------  
       
   982 EXPORT_C void CImRecvConvert::MessageCompleteL()
       
   983 //----------------------------------------------------------------------------------------  
       
   984 	{
       
   985 	// Restore the entry context
       
   986 	RECVLOG(KStartMessageComplete)
       
   987 	if (iServerEntry->Entry().Id() == KMsvNullIndexEntryId)
       
   988 		User::LeaveIfError(iServerEntry->SetEntry(iSavedEntryId));
       
   989 
       
   990 	if (iParsedMimeBoundaryLast==EFalse && iAttachmentFileState==EFileIsOpen && iPartialEmail!=EFalse)
       
   991 		{
       
   992 		iAttachmentFileState=EFileTopIncomplete;
       
   993 		}
       
   994 
       
   995 	CloseAttachmentFileL();
       
   996 
       
   997 	if(!iEmailEntry->Id())
       
   998 		return;
       
   999 
       
  1000 	if(iLeaveError!=KErrNone)
       
  1001 		{
       
  1002 		User::Leave(iLeaveError);
       
  1003 		}
       
  1004 
       
  1005 	if (EntryId()!=iTopMessagePart)
       
  1006 		{
       
  1007 		iEmailEntry->SetComplete(ETrue);
       
  1008 		StoreEntryStreamsL(KStoreMIMEHeader | KStoreBodyText);
       
  1009 		MoveToParentEntryL();
       
  1010 
       
  1011 		if( iTopMessagePart==EntryId() && iFinishedHeader) 
       
  1012 			{
       
  1013 			iEmailEntry->SetVisible(ETrue);
       
  1014 			iEmailEntry->SetInPreparation(EFalse);
       
  1015 			iEmailEntry->SetBodyTextComplete(ETrue);
       
  1016 			iEmailEntry->SetComplete(ETrue);
       
  1017 			if(iEmailEntry->PartialDownloaded())
       
  1018 				{
       
  1019 				iEmailEntry->SetPartialDownloaded( EFalse );	
       
  1020 				}
       
  1021 			// Main message.
       
  1022 			StoreMessageEntryDetailsL();
       
  1023 			return;
       
  1024 			}
       
  1025 		else if(iEmailEntry->iType == KUidMsvMessageEntry)
       
  1026 			{
       
  1027 			StoreMessageEntryDetailsL();
       
  1028 			MoveToParentEntryL();
       
  1029 			StoreMessageEntryDetailsL();
       
  1030 			}
       
  1031 		}
       
  1032 
       
  1033 	// A message requiring manual termination and not part way through 
       
  1034 	// a MIME part header.
       
  1035 
       
  1036 	User::LeaveIfError(iServerEntry->SetEntry(iTopMessagePart));         
       
  1037 	if(iEmailEntry)
       
  1038 		{
       
  1039 		delete iEmailEntry;
       
  1040 		iEmailEntry=NULL;
       
  1041 		}
       
  1042 	iEmailEntry = new (ELeave) TMsvEmailEntry(iServerEntry->Entry());
       
  1043 	iEmailEntry->SetVisible(ETrue);
       
  1044 	iEmailEntry->SetInPreparation(EFalse);
       
  1045 	iEmailEntry->SetComplete(ETrue);
       
  1046 	iEmailEntry->SetBodyTextComplete(ETrue);
       
  1047 	if(iEmailEntry->PartialDownloaded())
       
  1048 		{
       
  1049 		iEmailEntry->SetPartialDownloaded( EFalse );	
       
  1050 		}
       
  1051 
       
  1052 	iEmailEntry->SetAttachment(iParent->At(0).iAttachment);
       
  1053 	iEmailEntry->SetMHTMLEmail(iParent->At(0).iMHTML);
       
  1054 	iEmailEntry->SetVCalendar(iParent->At(0).iVCal);
       
  1055 	iEmailEntry->SetICalendar(iParent->At(0).iICal);
       
  1056 	
       
  1057 	if(iEmailEntry->MHTMLEmail() == EFalse && iEmailEntry->Attachment() == EFalse && iRelatedAttachments !=EFalse)
       
  1058 		{
       
  1059 		iEmailEntry->SetAttachment(ETrue);
       
  1060 		}
       
  1061 	iRelatedAttachments=EFalse;
       
  1062 	
       
  1063 	iEmailEntry->iSize=iParent->At(0).iSize;
       
  1064 	iEmailEntry->SetMessageFolderType(iParent->At(0).iFolder);
       
  1065 
       
  1066 	User::LeaveIfError(iServerEntry->ChangeEntry(*iEmailEntry));
       
  1067 
       
  1068 	// Save the entry context and move it to null so that we're not locking any folders
       
  1069 	iSavedEntryId = iServerEntry->Entry().Id();
       
  1070 	User::LeaveIfError(iServerEntry->SetEntry(KMsvNullIndexEntryId));
       
  1071 	RECVLOG(KMessageComplete)
       
  1072 	}
       
  1073 
       
  1074 EXPORT_C void CImRecvConvert::SetCaf(CImCaf& aCaf)
       
  1075 /**
       
  1076 Initialise class CimCaf reference
       
  1077 @param aCaf - Reference to a CAF instance
       
  1078 */
       
  1079 	{
       
  1080 	iCaf = &aCaf;
       
  1081 	}
       
  1082 //----------------------------------------------------------------------------------------  
       
  1083 void CImRecvConvert::PrepareDecoder()
       
  1084 //----------------------------------------------------------------------------------------  
       
  1085 	{
       
  1086 	switch(iMimeParser->ContentEncoding())
       
  1087 		{
       
  1088 		case EEncodingTypeNone:
       
  1089 		case EEncodingType7Bit:
       
  1090 		case EEncodingType8Bit:
       
  1091 			iAlgorithm = ENoAlgorithm;
       
  1092 			RECVLOG(KCollectingData7)
       
  1093 			break;
       
  1094 		case EEncodingTypeQP:
       
  1095 			iAlgorithm = EQPDecode;
       
  1096 			RECVLOG(KCollectingDataQP)
       
  1097 			break;
       
  1098 		case EEncodingTypeBASE64:
       
  1099 			iAlgorithm = EBase64Decode;
       
  1100 			RECVLOG(KCollectingBase64)
       
  1101 			break;	
       
  1102 		case EEncodingTypeUU:
       
  1103 			iAlgorithm = EUUDecode;
       
  1104 			RECVLOG(KCollectingUU)
       
  1105 			break;	
       
  1106 		default:	// EEncodingTypeUnknown, EEncodingTypeNone, EEncodingTypeBinary	
       
  1107 			iAlgorithm = ENoAlgorithm;
       
  1108 			break;
       
  1109 		} // switch
       
  1110 	iPrepared = ETrue;
       
  1111 	}
       
  1112 
       
  1113 
       
  1114 //----------------------------------------------------------------------------------------  
       
  1115 void CImRecvConvert::DecodeAndStoreLineL(const TDesC8& aSourceLine)
       
  1116 //----------------------------------------------------------------------------------------  
       
  1117 	{
       
  1118 	//If bodytext has been stored using chunk storage mechanism.
       
  1119 	if(iFirstLinePlainText && iEmailEntry->iType==KUidMsvEmailTextEntry)
       
  1120 		{
       
  1121 		iBodyId = iEmailEntry->Id();
       
  1122 		
       
  1123 		delete iPlainBodyTextEntry;
       
  1124 		iPlainBodyTextEntry = NULL;
       
  1125 		
       
  1126 		iPlainBodyTextEntry = CMsvPlainBodyTextEntry::NewL(iStore8BitData, *iServerEntry, iMimeParser->CurrentCharsetL(), iCharConv->SystemDefaultCharset());
       
  1127 		iFirstLinePlainText = EFalse;
       
  1128 		}
       
  1129 	
       
  1130 	TInt sourceLineLength=aSourceLine.Length();
       
  1131 	TBool blankLine = EFalse;
       
  1132 	TBool decodeError = EFalse;
       
  1133 
       
  1134 	// create a temporary buffer to write the decoded data into. 
       
  1135 	// This will always be as long as or shorter than the original.
       
  1136 	
       
  1137 	HBufC8* convertedLine = HBufC8::NewLC(sourceLineLength+KConversionRemainderLength);
       
  1138 	TPtr8 des(convertedLine->Des());
       
  1139 
       
  1140 	if(iFinalLine)						
       
  1141 		{
       
  1142 		// We've got to the end of encoded section, so set in order to skip all
       
  1143 		// trailing empty lines & postamble until we reach the next MIME/UUE boundary
       
  1144 
       
  1145 		RECVLOG(KSkippingData)
       
  1146 		iSkipData = ETrue;
       
  1147 		}
       
  1148 	else
       
  1149 		{
       
  1150 		switch(iAlgorithm)
       
  1151 			{
       
  1152 			case EBase64Decode:
       
  1153 				RECVLOG(KDecodingBase64);
       
  1154 				// Keep track of the error so we don't append junk to the body-text
       
  1155 				decodeError = iB64Codec.Decode(aSourceLine, des); 
       
  1156 				RECVLOG(KDecodedBase64);
       
  1157 				break;
       
  1158 			case EUUDecode:
       
  1159 				RECVLOG(KDecodingUU);
       
  1160 				//used to end a Mime encoded UU section else no purpose
       
  1161 				iFinalLine=(aSourceLine.CompareF(KImcvUueLastLine)==0);	
       
  1162 				if(iFinalLine)
       
  1163 					iCommitLine=EFalse;
       
  1164 				else
       
  1165 					{
       
  1166 					//returns True on invalid data
       
  1167 					if((!iFinalLine)&&(iUUCodec.Decode(aSourceLine, des))) 
       
  1168 						{
       
  1169 						RECVLOG(KUUEDataCorrupt)
       
  1170 						if(iAttachmentFileState==EFileIsOpen)
       
  1171 							{
       
  1172 							iAttachmentFileState=EFileIsCorrupt;
       
  1173 							iLeaveError=KErrCorrupt;
       
  1174 							CloseAttachmentFileL();
       
  1175 							}
       
  1176 						else
       
  1177 							User::Leave(KErrCorrupt);
       
  1178 						}
       
  1179 					}
       
  1180 				RECVLOG(KDecodedUU);
       
  1181 				break;
       
  1182 			case EQPDecode:
       
  1183 				RECVLOG(KDecodingQP);
       
  1184 				iQPCodec.Decode(aSourceLine, des);
       
  1185 				RECVLOG(KDecodedQP);
       
  1186 				break;
       
  1187 			case ENoAlgorithm:
       
  1188 				{				
       
  1189 				// If the data is to be stored in CRichText clean it up before copying it to the buffer
       
  1190 				TLex8 lex(aSourceLine);
       
  1191 				blankLine=ETrue;
       
  1192 				while(blankLine && !lex.Eos())
       
  1193 					{
       
  1194 					blankLine = (lex.Peek()==KImcvSP || lex.Peek()==KImcvTab 
       
  1195 						|| lex.Peek()==KImcvCR || lex.Peek()==KImcvLF);
       
  1196 					lex.Inc();
       
  1197 					}
       
  1198 				des.Copy(aSourceLine);
       
  1199 				}				
       
  1200 			default:
       
  1201 				break;
       
  1202 			} // end switch
       
  1203 		// Commits the decoded data to the appropriate store or trashes the line 
       
  1204 		if(iCommitLine && !decodeError) 
       
  1205 			{
       
  1206 			if (iLeftOver.Length())
       
  1207 				{
       
  1208 				des.Insert(0, iLeftOver);
       
  1209 				iLeftOver.SetLength(0);
       
  1210 				}
       
  1211 
       
  1212 			if(iCurrentPartIsRichText)
       
  1213 				{
       
  1214 				if (iBodyId==KMsvNullIndexEntryId)
       
  1215 					{
       
  1216 					iBodyId = iEmailEntry->Id();
       
  1217 					}
       
  1218 				//Store bodytext to message store as chunks.
       
  1219 				if(iStorePlainBodyText && iEmailEntry->iType==KUidMsvEmailTextEntry)
       
  1220 					{
       
  1221 					iPlainBodyTextEntry->AddChunkL(des);
       
  1222 					}
       
  1223 				else
       
  1224 					{
       
  1225  					if (iStore8BitData)
       
  1226 						iBodyBuf->InsertL(iBodyBuf->Size(), des);
       
  1227 					else
       
  1228 						WriteToBodyL(des, blankLine);
       
  1229 						
       
  1230 					}			
       
  1231 				}
       
  1232 			else
       
  1233 				WriteToAttachmentL(des);
       
  1234 			}
       
  1235 		} // end else
       
  1236 
       
  1237 	CleanupStack::PopAndDestroy(); // convertedLine
       
  1238 	}
       
  1239 
       
  1240 
       
  1241 //----------------------------------------------------------------------------------------  
       
  1242 void CImRecvConvert::ParseMimeLineL(const TDesC8& aSourceLine)
       
  1243 //----------------------------------------------------------------------------------------  
       
  1244 	{
       
  1245 	iTopPartialDownloadCounter+=aSourceLine.Length(); // increment the number of bytes of the attachment downloaded so far
       
  1246 	if(!iMimeParser->IsBoundary(aSourceLine))
       
  1247 		{
       
  1248 		if(!iPrepared) // first line of the body
       
  1249 			{		
       
  1250 			if (iMIMEPart_822Header)
       
  1251 				{
       
  1252 				// missing 822 part header. Revert to default.
       
  1253 				EndOfHeaderMIMEProcessingL();
       
  1254 				iMIMEPart_822Header=EFalse;
       
  1255 				}
       
  1256 			PrepareDecoder();
       
  1257 			}
       
  1258 
       
  1259 		if (CheckUUEStartL(aSourceLine))
       
  1260 			{
       
  1261 			iAlgorithm=EUUDecode;
       
  1262 			iCommitLine=EFalse;
       
  1263 			}
       
  1264 			
       
  1265 		/* since aSourceLine is a body part here, Set iSkipData to false,  */	
       
  1266 		iSkipData=EFalse; 
       
  1267 
       
  1268 		}
       
  1269 	else
       
  1270 		{
       
  1271 		iParsedMimeBoundaryLast=ETrue;
       
  1272 		// found a MIME boundary so store the current parts data and update its entry.
       
  1273 
       
  1274 		RECVLOG(KFoundMIMEBoundary)
       
  1275 		iCommitLine=EFalse; //Dont store this line as its a boundary.
       
  1276 
       
  1277 		if(!iFirstBoundaryReached && iEntryType==EFolderEntry)
       
  1278 			{
       
  1279 			iFirstBoundaryReached=ETrue;
       
  1280 			if (!iCurrentMultipartFolderEntryId)
       
  1281 				iCurrentMultipartFolderEntryId = EntryId();
       
  1282 			MoveToParentEntryL();
       
  1283 			ResetForNewEntryL(iDefaultEntryType);
       
  1284 			return; // First boundary encountered.
       
  1285 			}
       
  1286 
       
  1287 		CloseAttachmentFileL();
       
  1288 		if(iNewEntry)
       
  1289 			{
       
  1290 			iEmailEntry->SetComplete(ETrue);
       
  1291 			iEmailEntry->SetBodyTextComplete(ETrue);
       
  1292 			StoreEntryStreamsL(KStoreMIMEHeader | KStoreBodyText);
       
  1293 			
       
  1294 			if (iBodyId==KMsvNullIndexEntryId)
       
  1295 				{
       
  1296 				iBodyId=iEmailEntry->Id();
       
  1297 				}
       
  1298 			}
       
  1299 
       
  1300 		iSkipData = EFalse;
       
  1301 
       
  1302 		// check whether we just found the terminating boundary...
       
  1303 		if(iMimeParser->IsTerminatingBoundary())
       
  1304 			{
       
  1305 			RECVLOG(KRemoveBoundary);
       
  1306 			iMimeParser->RemoveBoundary();
       
  1307 			RECVLOG(KRemovedBoundary);
       
  1308 			iMIMEPart_822Header = EFalse;
       
  1309 
       
  1310 			if (EntryId()!=iTopMessagePart)
       
  1311 				{
       
  1312 				if(iEmailPart==KParentPart)
       
  1313 					{
       
  1314 					// rfc822 message which is not  not multipart.
       
  1315 					iEmailPart=KNoPart;
       
  1316 					MoveToParentEntryL();				
       
  1317 
       
  1318 					// Embedded message
       
  1319 					iEmailEntry->SetComplete(ETrue);
       
  1320 					iEmailEntry->SetBodyTextComplete(ETrue);
       
  1321 					StoreMessageEntryDetailsL();
       
  1322 					}
       
  1323 				else if (iEmailEntry->iType==KUidMsvMessageEntry)
       
  1324 					{
       
  1325 					// Moving up from a multi embedded rfc822 message.
       
  1326 					iEmailEntry->SetComplete(ETrue);
       
  1327 					iEmailEntry->SetBodyTextComplete(ETrue);
       
  1328 					StoreMessageEntryDetailsL();
       
  1329 					}
       
  1330 				}
       
  1331 
       
  1332 			MoveToParentEntryL();
       
  1333 			iEntryDataSize = iEmailEntry->iSize;
       
  1334 
       
  1335 			if(iServerEntry->Entry().iType == KUidMsvFolderEntry)
       
  1336 				{
       
  1337 				iCurrentMultipartFolderEntryId = EntryId();
       
  1338 				}
       
  1339 			else if (EntryId()!=iTopMessagePart)
       
  1340 				{
       
  1341 				if(iEmailEntry->iType == KUidMsvMessageEntry)
       
  1342 					{
       
  1343 					iEmailEntry->SetComplete(ETrue);
       
  1344 					iEmailEntry->SetBodyTextComplete(ETrue);
       
  1345 					StoreMessageEntryDetailsL();
       
  1346 					}
       
  1347 				MoveToParentEntryL();
       
  1348 				iEntryDataSize += iEmailEntry->iSize;
       
  1349 				}
       
  1350 
       
  1351 			if(!iNewEntry)
       
  1352 				ResetForNonMimeEntryL();
       
  1353 
       
  1354 			RECVLOG(KSkippingData)
       
  1355 			iSkipData = ETrue;
       
  1356 			iDefaultEntryType=ETextEntry;
       
  1357 			}
       
  1358 		else // if regular boundary
       
  1359 			{ 
       
  1360 			RECVLOG(KSectionHeader)
       
  1361 			if(iEmailPart==KParentPart && EntryId()!=iTopMessagePart)
       
  1362 				{
       
  1363 				// rfc822 message which is not  not multipart.
       
  1364 				iEmailPart=KNoPart;
       
  1365 				MoveToParentEntryL();
       
  1366 				// Embedded message
       
  1367 				iEmailEntry->SetComplete(ETrue);
       
  1368 				iEmailEntry->SetBodyTextComplete(ETrue);
       
  1369 				StoreMessageEntryDetailsL();
       
  1370 				}
       
  1371 
       
  1372 			if (!iCurrentMultipartFolderEntryId && iEmailPart==KNoPart)
       
  1373 				MoveToParentEntryL();
       
  1374 
       
  1375 			ResetForNewEntryL(iDefaultEntryType);
       
  1376 			}
       
  1377 		}
       
  1378 	}
       
  1379 
       
  1380 //----------------------------------------------------------------------------------------  
       
  1381 void CImRecvConvert::EndOfHeaderProcessingL()
       
  1382 //----------------------------------------------------------------------------------------  
       
  1383 	{	
       
  1384 	CreateEntryL();
       
  1385 	StoreEntryStreamsL(KStore822Header);
       
  1386 	iEntryDataSize = 0;
       
  1387 	}
       
  1388 
       
  1389 
       
  1390 // Have just finished processing header, what next.. ?
       
  1391 // All MIME entry entry creation takes place here.
       
  1392 //
       
  1393 //----------------------------------------------------------------------------------------  
       
  1394 void CImRecvConvert::EndOfHeaderMIMEProcessingL()
       
  1395 //----------------------------------------------------------------------------------------  
       
  1396 	{	
       
  1397 	if (iMimeParser->IsMessageDigest())
       
  1398 		iDefaultEntryType=EMessageEntry;
       
  1399 
       
  1400 	if (iMimeParser->VCard() || iMimeParser->VCalendar() || iMimeParser->ICalendar())
       
  1401 		{
       
  1402 		iCurrentPartIsRichText = EFalse;	
       
  1403 		iEntryType = EAttachmentEntry;
       
  1404 		}
       
  1405 
       
  1406 	// Don't create entry if an embedded message header. 
       
  1407 	if (!iMIMEPart_822Header || iTopMessagePart==EntryId() )
       
  1408 		CreateEntryL(); 
       
  1409 
       
  1410 	if (!iMIMEPart_822Header && !iMimeParser->MimeFieldsExist() && iDefaultEntryType==EMessageEntry)
       
  1411 		{
       
  1412 		// MIME header not present. So expecting embedded 822 header
       
  1413 		iEmailPart = KParentPart;
       
  1414 		iMIMEPart_822Header=ETrue;
       
  1415 		iEntryType=ETextEntry;
       
  1416 		}
       
  1417 	else if (iMimeParser->ContentType()==EMimeMessage)
       
  1418 		{
       
  1419 		// Having received A MIME header of type message/..., store and continue.
       
  1420 
       
  1421 		StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader);
       
  1422 		iMimeParser->ResetForNewEntry();
       
  1423 		iMIMEPart_822Header=ETrue;
       
  1424 
       
  1425 		// Non-multipart embedded message.
       
  1426 		if (iTopMessagePart==EntryId())
       
  1427 			{
       
  1428 			iEntryType = EMessageEntry;
       
  1429 			ResetForNonMimeEntryL();
       
  1430 			}
       
  1431 		else
       
  1432 			iEntryType=ETextEntry;
       
  1433 		}
       
  1434 	else if ( (iTopMessagePart==EntryId() || iMIMEPart_822Header)&&(!iReceivingHeadersOnly) )
       
  1435 		{
       
  1436 		// Main rfc822 header or embedded header.
       
  1437 
       
  1438 		TImEmailFolderType folderType=iMimeParser->MessageFolderType();
       
  1439 		if (iMIMEPart_822Header)
       
  1440 			{
       
  1441 			iEmailEntry->iDetails.Set(iOutputHeader->From());
       
  1442 			iEmailEntry->iDescription.Set(iOutputHeader->Subject());
       
  1443 			iMIMEPart_822Header=EFalse;
       
  1444 			}
       
  1445 
       
  1446 		if (iRfc822Token->i822FieldsExist)
       
  1447 			StoreEntryStreamsL(KStore822Header|KStoreMIMEHeader);
       
  1448 		else
       
  1449 			StoreEntryStreamsL(KStoreMIMEHeader);
       
  1450 
       
  1451 
       
  1452 		if (iMimeParser->ContentType()==EMimeMultipart)
       
  1453 			{	
       
  1454 			RECVLOG(KSkippingData)
       
  1455 			ResetForNewEntryL(EFolderEntry);
       
  1456 			iMimeParser->SetMessageFolderType(folderType);
       
  1457 			iSkipData = ETrue;
       
  1458 			iEmailPart = KMultiPart;
       
  1459 			iCurrentMultipartFolderEntryId=0;
       
  1460 			}
       
  1461 		else 
       
  1462 			{
       
  1463 			// Not multipart but some header data to store.
       
  1464 			iEntryDataSize = 0;
       
  1465 			}
       
  1466 
       
  1467 		CreateEntryL();
       
  1468 		}
       
  1469 
       
  1470 	iRfc822Token->i822FieldsExist=EFalse;
       
  1471 	iMimeParser->ResetMimeFieldsExist();
       
  1472 	
       
  1473 	iFinishedHeader = iMIMEPart_822Header ? EFalse:ETrue;
       
  1474 	iSkipData = iMimeParser->ContentType()==EMimeMultipart ? ETrue:EFalse;
       
  1475 	}
       
  1476 
       
  1477 
       
  1478 // Non Mime body parsing
       
  1479 //----------------------------------------------------------------------------------------  
       
  1480 void CImRecvConvert::ParseBodyLineL(const TDesC8& aSourceLine)
       
  1481 //----------------------------------------------------------------------------------------  
       
  1482 	{
       
  1483 
       
  1484 	TInt len=aSourceLine.Length();
       
  1485 	iTopPartialDownloadCounter+=len; // added for TOP. increment the number of bytes of the attachment downloaded so far
       
  1486 	TMsvId id=0;
       
  1487 	if (iBodyId==KMsvNullIndexEntryId)
       
  1488 		{
       
  1489 		iBodyId=iEmailEntry->Id();
       
  1490 		}
       
  1491 
       
  1492 	// first check whether this line is a UUEncode start boundary
       
  1493 	if(CheckUUEStartL(aSourceLine)) 
       
  1494 		{
       
  1495 		RECVLOG(KFoundUUEStartBoundary)
       
  1496 		TFileName tempStore = iAttachmentName;
       
  1497 		id = EntryId();
       
  1498 		if (!iNewNonMIMEBodyPart || id!=iTopMessagePart) // main message entry
       
  1499 			{
       
  1500 			iEmailEntry->SetComplete(ETrue);
       
  1501 			iEmailEntry->SetBodyTextComplete(ETrue);
       
  1502 			StoreEntryStreamsL(KStoreBodyText);
       
  1503 			}
       
  1504 		MoveToParentEntryL();
       
  1505 		if ( !CreateNonMIMEFolderEntryL(id))
       
  1506 			ResetForNonMimeEntryL();
       
  1507 			
       
  1508 		iEntryType = EAttachmentEntry;
       
  1509 		CreateEntryL();
       
  1510 		SetAttachmentName(tempStore);
       
  1511 		
       
  1512 		iCurrentPartIsRichText = EFalse;
       
  1513 		iAlgorithm=EUUDecode;
       
  1514 		iCommitLine=EFalse;
       
  1515 		if(!iSavingAttachments)
       
  1516 			{
       
  1517 			RECVLOG(KSkippingData)
       
  1518 			iSkipData=ETrue;
       
  1519 			}
       
  1520 		iNewNonMIMEBodyPart=EFalse;
       
  1521 		}
       
  1522 	else if(aSourceLine.CompareF(KImcvUueEnd)==0) // Checks for the UUEncode end boundary
       
  1523 		{
       
  1524 		RECVLOG(KFoundUUEEndBoundary)
       
  1525 		CloseAttachmentFileL();
       
  1526 		StoreEntryDataL();
       
  1527 		MoveToParentEntryL();
       
  1528 		iSkipData = EFalse;
       
  1529 		iCommitLine=EFalse;
       
  1530 		iNewNonMIMEBodyPart=ETrue; 
       
  1531 		}
       
  1532 	else if (iNewNonMIMEBodyPart && !( len==2 && aSourceLine[0]==KImcvCR && aSourceLine[1]==KImcvLF ))
       
  1533 		{
       
  1534 		id = EntryId();
       
  1535 		if (!iNewNonMIMEBodyPart || id!=iTopMessagePart)
       
  1536 			{
       
  1537 			iEmailEntry->SetComplete(ETrue);
       
  1538 			iEmailEntry->SetBodyTextComplete(ETrue);
       
  1539 			StoreEntryStreamsL(KStoreBodyText);
       
  1540 			}
       
  1541 		MoveToParentEntryL();
       
  1542 		if ( !CreateNonMIMEFolderEntryL(id))
       
  1543 			ResetForNonMimeEntryL();
       
  1544 		iAlgorithm=ENoAlgorithm;
       
  1545 		iEntryType = ETextEntry;
       
  1546 		CreateEntryL();
       
  1547 		iNewNonMIMEBodyPart=EFalse;
       
  1548 		}	
       
  1549 	}
       
  1550 
       
  1551 
       
  1552 
       
  1553 //----------------------------------------------------------------------------------------  
       
  1554 TBool CImRecvConvert::CreateNonMIMEFolderEntryL(TMsvId aCurrentId)
       
  1555 //----------------------------------------------------------------------------------------  
       
  1556 	{
       
  1557 	if ( aCurrentId==iTopMessagePart || iCurrentMultipartFolderEntryId )
       
  1558 		return EFalse;
       
  1559 
       
  1560 	// Create Folder.
       
  1561 	iServerEntry->SetEntry(iTopMessagePart); 
       
  1562 	iEmailPart = KMultiPart;
       
  1563 	iEntryType = EFolderEntry;
       
  1564 	CreateEntryL();
       
  1565 
       
  1566 	// Move existing child entry under folder.
       
  1567 	TMsvId destId = EntryId();
       
  1568 	iServerEntry->SetEntry(iTopMessagePart); 
       
  1569 	iServerEntry->MoveEntryWithinService(aCurrentId, destId);
       
  1570 	User::LeaveIfError(iServerEntry->SetEntry(aCurrentId));
       
  1571 	User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent())); 
       
  1572 
       
  1573 	// Create MimeHeader.
       
  1574 	iEmailEntry->SetMessageFolderType(iMimeParser->MessageFolderType());
       
  1575 
       
  1576 	RECVLOG(KResetForNewEntry) 
       
  1577 
       
  1578 	iMimeParser->ResetForNewEntry();
       
  1579 	if (iStore8BitData)
       
  1580 		{
       
  1581 		//Create a buffer to hold the body text as it is down loaded.
       
  1582 		delete iBodyBuf;
       
  1583 		iBodyBuf = NULL;
       
  1584 		iBodyBuf = CBufFlat::NewL(KBodyTextChunkSizeBytes);
       
  1585 		}
       
  1586 	else
       
  1587 		{
       
  1588 		iOutputBody->Reset();
       
  1589 		}
       
  1590 			
       
  1591 	ResetForNonMimeEntryL(); 
       
  1592 	RECVLOG(KResetedForNewEntry) 
       
  1593 	return ETrue;
       
  1594 	}
       
  1595 
       
  1596 
       
  1597 //----------------------------------------------------------------------------------------  
       
  1598 TBool CImRecvConvert::CreateAttachmentL()
       
  1599 //----------------------------------------------------------------------------------------  
       
  1600 	{
       
  1601 	// Get and set Attachment File path
       
  1602 	// added to support TOP command. Reset the download counter each time we have a new
       
  1603 	// attachment
       
  1604 	iTopPartialDownloadCounter = 0; 
       
  1605 
       
  1606 	// Need to check that the complete filename: iAttachmentFullPath & iAttachmentName	
       
  1607 	// does not exceed 256 characters. Greater than this and it cannot be saved as a file.
       
  1608 
       
  1609 	TBool addExtension=ETrue;
       
  1610 	if(iAttachmentName.Length() == 0)	//i.e. problem with Attachment name
       
  1611 	    {
       
  1612 		// No filename present. Generate one.
       
  1613 		if(iMimeParser->ContentDescription().Length()!=0)
       
  1614 			{
       
  1615 			// Use ContentDescription() as default name 
       
  1616 			// - as this is more informative than the default
       
  1617 
       
  1618 			TLex sourceLineLex = iMimeParser->ContentDescription();
       
  1619 			ExtractFilename(sourceLineLex, iAttachmentName);
       
  1620 			}
       
  1621 		else
       
  1622 			iAttachmentName = *iDefaultAttachmentName;
       
  1623 		}
       
  1624 	else
       
  1625 		{
       
  1626 		// Filename present. Check it is valid.
       
  1627 		ReplaceInvalidCharacters(iAttachmentName);
       
  1628 		if (iAttachmentName.Locate(KImcvFullStop)!=KErrNotFound)
       
  1629 			addExtension=EFalse;
       
  1630 		}
       
  1631 
       
  1632 	// Check length.
       
  1633 	TInt maxFilenameLength = KMaxFileName-KMaxExtensionLength;
       
  1634 
       
  1635 	// Truncate filename if too long.
       
  1636 	if (maxFilenameLength < iAttachmentName.Length())
       
  1637 		iAttachmentName.SetLength(maxFilenameLength);
       
  1638 	
       
  1639 	if (addExtension)
       
  1640 		AddFileExtension();
       
  1641 	
       
  1642 	CMsvStore* store = iServerEntry->EditStoreL(); 
       
  1643 	CleanupStack::PushL(store);
       
  1644 	CMsvAttachment* attachment = CMsvAttachment::NewL(CMsvAttachment::EMsvFile);
       
  1645 	CleanupStack::PushL(attachment);
       
  1646 	attachment->SetAttachmentNameL(iAttachmentName);
       
  1647 
       
  1648 	// DEF071099 
       
  1649 	HBufC8* buf = HBufC8::NewLC(iMimeParser->ContentSubType().Length() + iMimeParser->ContentTypeDescription().Length() + 1);
       
  1650 	TPtr8 ptr(buf->Des());
       
  1651 	ptr.Copy(iMimeParser->ContentTypeDescription());
       
  1652 	ptr.Append(KImcvForwardSlash);
       
  1653 	ptr.Append(iMimeParser->ContentSubType());
       
  1654 	
       
  1655 	attachment->SetMimeTypeL(ptr);	
       
  1656 	CleanupStack::PopAndDestroy(buf);
       
  1657 	// DEF071099	
       
  1658 
       
  1659 	RFile file;	
       
  1660 	// Behaviour for attachment creation alters if it's a CAF session
       
  1661 	if(ImCafRegistered())
       
  1662 		{
       
  1663 		iCaf->PrepareProcessingL(); // Init the CAF session
       
  1664 		RFile startFile;
       
  1665 		TFileName suggestedFileName;
       
  1666 		if(iCaf->GetSuggestedAttachmentFileName(suggestedFileName) == KErrNone) // CAF agent may provide a filename
       
  1667 			{
       
  1668 			store->CreateShareProtectedAttachmentL(suggestedFileName,startFile,attachment);
       
  1669 			}
       
  1670 		else
       
  1671 			{
       
  1672 			store->CreateShareProtectedAttachmentL(iAttachmentName,startFile,attachment);
       
  1673 			}
       
  1674 		iCaf->StartProcessing(iDefaultAttachmentName->Des(),attachment->FilePath(),*iServerEntry,startFile); // Init the CAF session
       
  1675 		startFile.Close(); // Safe to close as CimCaf Duplicate()'s
       
  1676 		}
       
  1677 	else
       
  1678 		{
       
  1679 		// Normal behaviour
       
  1680 		store->AttachmentManagerExtensionsL().CreateAttachmentL(iAttachmentName,file,attachment);
       
  1681 		iAttachmentFile.SetFileHandle(file,TImAttachmentFile::EImFileWrite);
       
  1682 		}
       
  1683 	// CreateAttachmentL takes ownership of CMsvAttachment so if call was successful we can pop it here
       
  1684 	CleanupStack::Pop(attachment);
       
  1685 	
       
  1686 	store->CommitL();
       
  1687 	CleanupStack::PopAndDestroy(store);
       
  1688 
       
  1689 	if(KErrNone!=iLeaveError)
       
  1690 		{
       
  1691 		iAttachmentFileState=EFileFailedToOpen;
       
  1692 		CloseAttachmentFileL();
       
  1693 		return EFalse;
       
  1694 		}
       
  1695 
       
  1696 	iAttachmentFileState=EFileIsOpen;
       
  1697 	return ETrue;
       
  1698 	}
       
  1699 
       
  1700 //----------------------------------------------------------------------------------------  
       
  1701 void CImRecvConvert::WriteToAttachmentL(const TDesC8& text)
       
  1702 //----------------------------------------------------------------------------------------  
       
  1703 	{
       
  1704 	if ( (iAttachmentFileState==EFileIsClosed || iAttachmentFileState==EFileNotOpen) 
       
  1705 		&& CreateAttachmentL() && iEntryType!=EHtmlEntry)
       
  1706 			iEmailEntry->SetAttachment(ETrue);
       
  1707 	
       
  1708 	if(iAttachmentFileState!=EFileIsOpen || !text.Length())
       
  1709 		{
       
  1710 		RECVLOG(KSkippingData)
       
  1711 		iSkipData = ETrue;
       
  1712 		}
       
  1713 
       
  1714 	// write decoded data into a file if there is any data there to write.
       
  1715 
       
  1716 	RECVLOG(KWritingToFile)
       
  1717 
       
  1718 	// Convert text before writing to attachment.
       
  1719 	
       
  1720 	if(ImCafProcessing())
       
  1721 		{
       
  1722 		iLeaveError = iCaf->WriteData(text);
       
  1723 		}
       
  1724 	else
       
  1725 		{
       
  1726 		iLeaveError=iAttachmentFile.WriteFile(text);
       
  1727 		}
       
  1728 
       
  1729 	if(KErrNone==iLeaveError)
       
  1730 		iEntryDataSize += text.Length();
       
  1731 	else	
       
  1732 		{
       
  1733 		// the file write failed (eg.there is no space left), set new file state and skip 
       
  1734 		RECVLOG(KFailedToWriteToFile)
       
  1735 		iAttachmentFileState=EFileIsIncomplete;
       
  1736 		CloseAttachmentFileL();
       
  1737 		}
       
  1738 	RECVLOG(KWroteToFile)
       
  1739 	}
       
  1740 
       
  1741 //----------------------------------------------------------------------------------------  
       
  1742 void CImRecvConvert::CloseAttachmentFileL()
       
  1743 //----------------------------------------------------------------------------------------  
       
  1744 	{
       
  1745 	// If anything bad happened a message is sent to the parts CRichText
       
  1746 	switch(iAttachmentFileState)
       
  1747 		{
       
  1748 		case EFileNotOpen:
       
  1749 			iAttachmentFileState=EFileIsClosed;
       
  1750 		case EFileIsClosed: //do nothing - this shouldn't happen	
       
  1751 			break;
       
  1752 		case EFileIsOpen:
       
  1753 			// SUCCESSFUL attachment decode
       
  1754 			RECVLOG(KClosingAttachFile)
       
  1755 			if(ImCafProcessing())
       
  1756 				{
       
  1757 				iCaf->EndProcessingL();
       
  1758 				}
       
  1759 			else
       
  1760 				{
       
  1761 				iAttachmentFile.CloseFile();
       
  1762 				}
       
  1763 			iAttachmentFileState=EFileIsClosed;
       
  1764 			iEmailEntry->SetComplete(ETrue);
       
  1765 			break;
       
  1766 		case EFileIsIncomplete:		// file write failed
       
  1767 		case EFileFailedToOpen:		// can't open attach file
       
  1768 		case EFileIsCorrupt:		// UU data being decoded is corrupt
       
  1769 			RECVLOG(KClosingAttachFile)
       
  1770 			if(ImCafProcessing())
       
  1771 				{
       
  1772 				iCaf->EndProcessingL();
       
  1773 				}
       
  1774 			else
       
  1775 				{
       
  1776 				iAttachmentFile.CloseFile();	//file has to be closed before it can be deleted
       
  1777 				}
       
  1778 			RECVLOG(KDeletingAttachFile)
       
  1779 			{ 
       
  1780 			// NOTE - need the braces to stop error for re-definition of store
       
  1781 			CMsvStore* store = iServerEntry->EditStoreL(); 
       
  1782 			CleanupStack::PushL(store);
       
  1783 			// v2 supports multiple attachments under one attachment entry 
       
  1784 			TInt attachmentCount = store->AttachmentManagerL().AttachmentCount();
       
  1785 			for(TInt i=0;i<attachmentCount;i++)
       
  1786 				{
       
  1787 				// Remove [0] as array is shuffled. Once index[n] is removed n+1 becomes n
       
  1788 				store->AttachmentManagerExtensionsL().RemoveAttachmentL(0);
       
  1789 				}			
       
  1790 			if(attachmentCount)
       
  1791 				{
       
  1792 				store->CommitL();
       
  1793 				}
       
  1794 			CleanupStack::PopAndDestroy(store);
       
  1795 			}
       
  1796 			iEmailEntry->SetAttachment(EFalse);
       
  1797 			iAttachmentFileState=EFileIsClosed;
       
  1798 			RECVLOG(KDeletedAttachFile)
       
  1799 
       
  1800 			if(iSavingAttachments && !iStore8BitData)
       
  1801 				{
       
  1802 				WriteToBodyL(KImcvParagraph);
       
  1803 				WriteToBodyL(*iRemovedAttachmentTag);	//lost attachment - notify user
       
  1804 				TBuf8<KMaxFileName> name;
       
  1805 				name.Copy(iAttachmentName); //16 to 8
       
  1806 				WriteToBodyL(name);
       
  1807 				WriteToBodyL(KImcvParagraph);
       
  1808 				}
       
  1809 
       
  1810 			User::Leave(iLeaveError);
       
  1811 			// Skip any remaining encoded data in message
       
  1812 			break;
       
  1813 		case EFileTopIncomplete:
       
  1814 			RECVLOG(KClosingAttachFile)
       
  1815 			if(ImCafProcessing())
       
  1816 				{
       
  1817 				iCaf->EndProcessingL();
       
  1818 				}
       
  1819 			else
       
  1820 				{
       
  1821 				iAttachmentFile.CloseFile();	//file has to be closed before it can be deleted
       
  1822 				}
       
  1823 
       
  1824 			// added for TOP command. Ensure we know correct amount of data for later redownload
       
  1825 			iSizeOfAttachmentsRemoved+=iTopPartialDownloadCounter;
       
  1826 
       
  1827 
       
  1828 			RECVLOG(KDeletingAttachFile)
       
  1829 			{ 
       
  1830 			// NOTE - need the braces to stop error for re-definition of store
       
  1831 			CMsvStore* store = iServerEntry->EditStoreL(); 
       
  1832 			CleanupStack::PushL(store);
       
  1833 
       
  1834 			TInt attachmentCount = store->AttachmentManagerL().AttachmentCount();
       
  1835 			for(TInt i=0;i<attachmentCount;i++)
       
  1836 				{
       
  1837 				// Remove [0] as array is shuffled. Once index[n] is removed n+1 becomes n
       
  1838 				store->AttachmentManagerExtensionsL().RemoveAttachmentL(0);
       
  1839 				}
       
  1840 			if(attachmentCount)
       
  1841 				{			
       
  1842 				store->CommitL();
       
  1843 				}
       
  1844 			CleanupStack::PopAndDestroy(store);
       
  1845 			}
       
  1846 			iEmailEntry->SetAttachment(EFalse);
       
  1847 			iAttachmentFileState=EFileIsClosed;
       
  1848 			RECVLOG(KDeletedAttachFile);
       
  1849 			TMsvId id = EntryId();
       
  1850 			TMsvId parent = iServerEntry->Entry().Parent();
       
  1851 			MoveToParentEntryL();
       
  1852 			TMsvId setTo=iServerEntry->Entry().Id();
       
  1853 			if(setTo!=parent)
       
  1854 				{
       
  1855 				iServerEntry->SetEntry(parent);
       
  1856 				}
       
  1857 			User::LeaveIfError(iServerEntry->DeleteEntry(id));			
       
  1858 			iServerEntry->SetEntry(setTo);
       
  1859 			break;
       
  1860 		}
       
  1861 	}
       
  1862 
       
  1863 //----------------------------------------------------------------------------------------  				
       
  1864 TBool CImRecvConvert::LineIsAllWhitespace()
       
  1865 //----------------------------------------------------------------------------------------  
       
  1866 	{// returns 1 if all elements of the current line are whitespace
       
  1867 	TBool	spaceFound = 1;
       
  1868 	TLex8	aLex = iLineLex;
       
  1869 
       
  1870 	while (spaceFound && aLex.Peek()!=KImcvCR)
       
  1871 		{
       
  1872 		if (aLex.Peek()==KImcvSP)
       
  1873 			{
       
  1874 			spaceFound = 1;
       
  1875 			aLex.Inc();
       
  1876 			}	
       
  1877 		else spaceFound = 0;
       
  1878 		}
       
  1879 	return (spaceFound);
       
  1880 	}
       
  1881 
       
  1882 //----------------------------------------------------------------------------------------  
       
  1883 TBool CImRecvConvert::CheckUUEStartL(const TDesC8& aSourceLine)
       
  1884 //----------------------------------------------------------------------------------------  
       
  1885 	{
       
  1886 	// Checks if the descriptor contains the UUE begin header
       
  1887 	// Extracts the file name if it is
       
  1888 	
       
  1889 	TInt sourceLength = aSourceLine.Length();
       
  1890 	if(sourceLength < KImcvUueStart().Length()+3) // can't be it, it's not long enough
       
  1891 		return EFalse;
       
  1892 
       
  1893 	if(!aSourceLine.Left(KImcvUueStart().Length()).CompareF(KImcvUueStart)) // start of line might be UUE boundary
       
  1894 		{
       
  1895 		// we also need to check that the next three chars are numbers - Unix file access code
       
  1896 		const TUint8* _ptr = aSourceLine.Ptr();
       
  1897 		TInt length=KImcvUueStart().Length();// this defines length as 6 ie. "b e g i n  " 
       
  1898 		if(TChar(_ptr[length]).IsDigit() && TChar(_ptr[length+1]).IsDigit() && TChar(_ptr[length+2]).IsDigit())
       
  1899 			{
       
  1900 			// we've found 'begin ###' at the start of a line -
       
  1901 			// that's about as good as we can do 
       
  1902 			// now grab the file name and paste it into the document
       
  1903 			// Extract filename from string, removing any surrounding quote marks
       
  1904 
       
  1905 			HBufC16* pBuf16 = HBufC16::NewLC(aSourceLine.Length());
       
  1906 			pBuf16->Des().Copy(aSourceLine);
       
  1907 			TLex sourceLineLex = pBuf16->Ptr();
       
  1908 			//parse until start of filename and mark
       
  1909 			length+=3;					// length (init'd to 6 above) now equals 9 ie. "begin ###"
       
  1910 			sourceLineLex.Inc(length);	// skips "begin ###"
       
  1911 			sourceLineLex.SkipSpace();	// skips any leading whitespace
       
  1912 
       
  1913 			ExtractFilename(sourceLineLex, iAttachmentName);
       
  1914 			CleanupStack::PopAndDestroy(); // pBuf8
       
  1915 			return ETrue;
       
  1916 			}
       
  1917 		}
       
  1918 		
       
  1919 	return EFalse;
       
  1920 	}
       
  1921 
       
  1922 //----------------------------------------------------------------------------------------  
       
  1923 void CImRecvConvert::AddFileExtension()
       
  1924 //----------------------------------------------------------------------------------------  
       
  1925 	{
       
  1926 	switch (iMimeParser->ContentType())
       
  1927 		{
       
  1928 		case EMimeText:
       
  1929 			// Add on extension to make opening file from email editor possible.
       
  1930 
       
  1931 			if ( iMimeParser->ContentSubType()==KImcvHtml )
       
  1932 				{
       
  1933 				iAttachmentName.Append(KHtmlExtension);
       
  1934 				}
       
  1935 			else if ( iMimeParser->ContentSubType()==KImcvRtf )
       
  1936 				{
       
  1937 				iAttachmentName.Append(KRtfExtension);
       
  1938 				}
       
  1939 			else if (iMimeParser->VCard())
       
  1940  				{
       
  1941  				iAttachmentName.Append(KVCardExtension);
       
  1942  				}
       
  1943 			else if (iMimeParser->VCalendar())
       
  1944 				{
       
  1945 				iAttachmentName.Append(KVCalExtension);					
       
  1946 				}				
       
  1947 			else if (iMimeParser->ICalendar())
       
  1948 				{
       
  1949 				iAttachmentName.Append(KICalExtension);
       
  1950 				}
       
  1951 			else //if ( iMimeParser->ContentSubType()==KImcvPlain)
       
  1952 				{
       
  1953 				iAttachmentName.Append(KTextExtension);
       
  1954 				}
       
  1955 			break;
       
  1956 		case EMimeImage:
       
  1957 		case EMimeAudio:
       
  1958 		case EMimeVideo:
       
  1959 			if ( (iMimeParser->ContentSubType()==KImcvBmp) 
       
  1960 					|| (iMimeParser->ContentSubType()==KImcvGif)
       
  1961 					|| (iMimeParser->ContentSubType()==KImcvJpeg)
       
  1962 					|| (iMimeParser->ContentSubType()==KImcvTiff)
       
  1963 					|| (iMimeParser->ContentSubType()==KImcvWav) )
       
  1964 				{
       
  1965 				TBuf<KMaxExtensionLength> buf;
       
  1966 				buf.Copy(iMimeParser->ContentSubType());
       
  1967 				iAttachmentName.Append(KImcvFullStop);
       
  1968 				iAttachmentName.Append(buf);
       
  1969 				}
       
  1970 			break;
       
  1971 		default:
       
  1972 			break;
       
  1973 		} // End switch
       
  1974 	}
       
  1975 
       
  1976 //----------------------------------------------------------------------------------------  
       
  1977 void CImRecvConvert::WriteToBodyL(const TDesC8& aText, TBool aBlankLine)
       
  1978 //----------------------------------------------------------------------------------------  
       
  1979 	{
       
  1980 	RECVLOG(KWritingToBody)
       
  1981 
       
  1982 	if(aText.Length() && aText[aText.Length()-1]==CEditableText::ELineBreak )
       
  1983 		RECVLOG(KLineHasLineBreak)
       
  1984 	TInt pos = iOutputBody->DocumentLength();
       
  1985 
       
  1986 	// Add bits of body text, converting along the way, till no characters left
       
  1987 	// .. to convert.
       
  1988 
       
  1989 	if(aBlankLine)
       
  1990 		{
       
  1991 		RECVLOG(KBlankLine);
       
  1992 		iOutputBody->InsertL(pos, CEditableText::EParagraphDelimiter);
       
  1993 		pos++;
       
  1994 		return;
       
  1995 		}
       
  1996 
       
  1997 	// Convert text before writing to body.
       
  1998 	TInt rem = 0;
       
  1999 	HBufC16* text16=HBufC16::NewLC(aText.Length());
       
  2000 	TPtr16 ptr16(text16->Des());
       
  2001 	TInt unconvertedChars, firstPos; // not used 
       
  2002 	rem = iCharConv->ConvertToOurCharsetL(aText, ptr16, unconvertedChars, firstPos);
       
  2003 	if (rem < 0) // error
       
  2004 		{
       
  2005 		// Copy unconverted characters.
       
  2006 		Append(ptr16, aText);
       
  2007 		iOutputBody->InsertL(pos, ptr16);
       
  2008 		CleanupStack::PopAndDestroy(); // text16
       
  2009 		return;
       
  2010 		}
       
  2011 	else if (rem && rem < KConversionRemainderLength)
       
  2012 		iLeftOver.Copy(aText.Right(rem));	
       
  2013 	
       
  2014 	// Make sure that the line is not CRLF terminated 
       
  2015 	// - replace with a line break if necessary.
       
  2016 
       
  2017 	TInt length = ptr16.Length();
       
  2018 	switch(iAlgorithm)
       
  2019 		{
       
  2020 		case EBase64Decode:
       
  2021 		case EUUDecode:
       
  2022 			{
       
  2023 			// Check for CRLF throughout the string.
       
  2024 
       
  2025 			if (!length)
       
  2026 				break; // String length zero.
       
  2027 
       
  2028 			if (iEncounteredLineEndingInCarriageReturn)
       
  2029 				{
       
  2030 				pos--; // overwrite the stored CR.
       
  2031 				ptr16[0] = CEditableText::ELineBreak;
       
  2032 				}
       
  2033 			iEncounteredLineEndingInCarriageReturn = ptr16[length-1]==KImcvCR ? ETrue:EFalse;
       
  2034 
       
  2035 			TInt start = 0;
       
  2036 			TInt offset = ptr16.Find(KImcvCRLF16);
       
  2037 
       
  2038 			while (offset != KErrNotFound)
       
  2039 				{
       
  2040 				ptr16[offset] = CEditableText::ELineBreak;
       
  2041 				const TDesC& buf = ptr16.Mid(start, offset-start+1);
       
  2042 				iOutputBody->InsertL(pos, buf);
       
  2043 				pos += buf.Length();
       
  2044 				start=offset+2; // Skip the LF char.
       
  2045 				offset = ptr16.Find(KImcvCRLF16);
       
  2046 				} 
       
  2047 
       
  2048 			if (start<length)
       
  2049 				{
       
  2050 				const TDesC& buf = ptr16.Right(length-start);
       
  2051 				iOutputBody->InsertL(pos, buf);
       
  2052 				pos += buf.Length();
       
  2053 				}
       
  2054 			}
       
  2055 			break;
       
  2056 
       
  2057 		case EQPDecode:
       
  2058 		case ENoAlgorithm:
       
  2059 		default:
       
  2060 			// Check for CRLF at end of line.
       
  2061 			if(length>=2 && ptr16[length-2]==KImcvCR && ptr16[length-1]==KImcvLF)
       
  2062 				{
       
  2063 				ptr16[length-2] = CEditableText::ELineBreak;
       
  2064 				ptr16.SetLength(length-1);
       
  2065 				}	
       
  2066 
       
  2067 			const TDesC& buf = text16->Des();
       
  2068 			iOutputBody->InsertL(pos, buf);
       
  2069 			pos += buf.Length();
       
  2070 		}	
       
  2071 
       
  2072 	CleanupStack::PopAndDestroy(text16);
       
  2073 	
       
  2074 	RECVLOG(KWroteToBody)
       
  2075 	}
       
  2076 
       
  2077 //----------------------------------------------------------------------------------------  
       
  2078 void CImRecvConvert::WriteToBodyL(const TDesC16& aText)
       
  2079 //----------------------------------------------------------------------------------------  
       
  2080 	{
       
  2081 	RECVLOG(KWritingToBody)
       
  2082 	if (aText.Length() && aText[aText.Length()-1]==CEditableText::ELineBreak)
       
  2083 		RECVLOG(KLineHasLineBreak)
       
  2084 
       
  2085 	TInt pos = iOutputBody->Read(0).Length();
       
  2086 	// get the text in before the paragraph marker that's always there
       
  2087 	pos = pos-1 < 0 ? 0 : pos-1;
       
  2088 	iOutputBody->InsertL(pos,aText);
       
  2089 	
       
  2090 	RECVLOG(KWroteToBody)
       
  2091 	}
       
  2092 
       
  2093 //----------------------------------------------------------------------------------------  
       
  2094 void CImRecvConvert::ParseRecipientListL(CDesCArray& aList)
       
  2095 //----------------------------------------------------------------------------------------  
       
  2096 	{
       
  2097 	HBufC8* pBuf = HBufC8::NewLC(KMaxIMailHeaderReadLineLength);
       
  2098 	TPtrC8 source(iRfc822Token->OutputLine()->Ptr(), iRfc822Token->OutputLine()->Length());
       
  2099 	const TUint8* ptr = source.Ptr();
       
  2100 	const TUint8* lastCharPtr = ptr + source.Length() - 1;
       
  2101 	TUint8 lookFor = 0;
       
  2102 	TInt count = 0;
       
  2103 	TBool finishedEntry = EFalse;
       
  2104 
       
  2105 	// get past white space
       
  2106 	while(*ptr&&((*ptr==KImcvSP)||(*ptr==KImcvSemiColon))) ptr++;
       
  2107 
       
  2108 	// Entries are separated by commas or semicolons.
       
  2109 	// Separators do not count if they appear within
       
  2110 	// "", <>, () or embedded series of these, eg "(one, two)"
       
  2111 	// so we need to keep track of these, including nesting.
       
  2112 	while(*ptr && ptr <= lastCharPtr)
       
  2113 		{
       
  2114 		if(!pBuf->Length())
       
  2115 			{
       
  2116 			finishedEntry = EFalse;
       
  2117 			}
       
  2118 
       
  2119 		switch(*ptr)
       
  2120 			{
       
  2121 			case KImcvLeftBracket:
       
  2122 				if(lookFor==KImcvRightBracket)
       
  2123 					{ // We've already had a "(", so now we need another one
       
  2124 					count++;
       
  2125 					}
       
  2126 				else if(lookFor==0)
       
  2127 					{ //We weren't looking for anything else, now we need to
       
  2128 					lookFor = KImcvRightBracket;
       
  2129 					count = 1;
       
  2130 					}
       
  2131 				// else we were already looking for something else, ignore this
       
  2132 				break;
       
  2133 			case KImcvLeftChevron:
       
  2134 				if(lookFor==KImcvRightChevron)
       
  2135 					{ //We've already had a "<", so now we need another one
       
  2136 					count++;
       
  2137 					}
       
  2138 				else if(lookFor==0)
       
  2139 					{ //We weren't looking for anything else
       
  2140 					lookFor = KImcvRightChevron;
       
  2141 					count = 1;
       
  2142 					}
       
  2143 				// else we were already looking for something else, ignore this
       
  2144 				break;
       
  2145 			case KImcvDoubleQuote:
       
  2146 				if(lookFor==KImcvDoubleQuote)
       
  2147 					{ // We already had a quote, so this matches it
       
  2148 					lookFor = 0;
       
  2149 					}
       
  2150 				else if(lookFor==0)
       
  2151 					{ //We weren't looking for anything else
       
  2152 					lookFor = KImcvDoubleQuote;
       
  2153 					}
       
  2154 				// else we were already looking for something else, ignore this
       
  2155 				break;
       
  2156 			case KImcvRightBracket:
       
  2157 			case KImcvRightChevron:
       
  2158 				if(*ptr == lookFor)
       
  2159 					{ //If we have found what we were looking for, decrease the count
       
  2160 					count--;
       
  2161 					if(count==0)
       
  2162 						{ // Got everything, now we're not looking for anything
       
  2163 						lookFor = 0;
       
  2164 						}
       
  2165 					// else keep looking for the same thing	again
       
  2166 					}
       
  2167 				// else we're looking for something else, ignore it
       
  2168 				break;
       
  2169 			case KImcvComma:
       
  2170 			case KImcvSemiColon:
       
  2171 				// If we're not looking for anything, we're finished
       
  2172 				if (lookFor == 0)
       
  2173 					finishedEntry = ETrue;
       
  2174 				// else this comma or semicolon is part of a different token, ignore it
       
  2175 				break;
       
  2176 			}
       
  2177 
       
  2178 		if(!finishedEntry)
       
  2179 			{
       
  2180 			// check we're not about to blow the buffer
       
  2181 			if(pBuf->Length() >= pBuf->Des().MaxLength())
       
  2182 				{
       
  2183 				// ReAlloc will delete the original memory pointed to by pBuf
       
  2184 				// so we must take it off the cleanup stack...
       
  2185 				CleanupStack::Pop(pBuf);
       
  2186 				pBuf = pBuf->ReAlloc(pBuf->Length() + 64); // arbitrary extension
       
  2187 				// ...and put the new one on instead
       
  2188 				CleanupStack::PushL(pBuf);
       
  2189 				}
       
  2190 			pBuf->Des().Append((TChar)*ptr);
       
  2191 			// move to the next character
       
  2192 			ptr++;
       
  2193 			}
       
  2194 		else
       
  2195 			{
       
  2196 			// that's it! store the address away
       
  2197 			HBufC16* pBuf16 = HBufC16::NewLC(pBuf->Des().Length());
       
  2198 			pBuf16->Des().Copy(pBuf->Des());
       
  2199 			aList.AppendL( (HBufC16&) *pBuf16 );
       
  2200 			CleanupStack::PopAndDestroy(); // pBuf16
       
  2201 			pBuf->Des().SetLength(0);
       
  2202 			finishedEntry = EFalse; //Ready for next entry
       
  2203 
       
  2204 			// get past the separator
       
  2205 			ptr++;
       
  2206 
       
  2207 			// get past white space (& any other separators)
       
  2208 			while(*ptr && (*ptr==KImcvSP || *ptr==KImcvTab || *ptr==KImcvComma || *ptr==KImcvSemiColon)) ptr++;
       
  2209 			}
       
  2210 		}
       
  2211 		// catch the last name in the list
       
  2212 		if (pBuf)
       
  2213 			{
       
  2214 			TInt recipientLength = pBuf->Length();
       
  2215 			if (recipientLength)
       
  2216 				{
       
  2217 				HBufC16* pBuf16 = HBufC16::NewLC(recipientLength);
       
  2218 				pBuf16->Des().Copy(*pBuf);
       
  2219 				aList.AppendL(*pBuf16);
       
  2220 				CleanupStack::PopAndDestroy(); // pBuf16
       
  2221 				}
       
  2222 			}
       
  2223 
       
  2224 		CleanupStack::PopAndDestroy(); // pBuf
       
  2225 	}
       
  2226 
       
  2227 //----------------------------------------------------------------------------------------
       
  2228 void CImRecvConvert::ExtractFilename(TLex& aLex, TDes& rFileName)
       
  2229 //----------------------------------------------------------------------------------------
       
  2230 	{
       
  2231 	// This function steps through the filename extracting the bare name and checking 
       
  2232 	//  the length is less than the max of 256 for EPOC ;checks that all chars are legal for EPOC32
       
  2233 	
       
  2234 	TChar endChar = KImcvSemiColon;
       
  2235 
       
  2236 	aLex.SkipSpace();
       
  2237 	
       
  2238 	if (aLex.Peek()==KImcvDoubleQuote)
       
  2239 		{
       
  2240 		aLex.Inc();	// step over the " character
       
  2241 		endChar = KImcvDoubleQuote;
       
  2242 		}
       
  2243 
       
  2244 	aLex.Mark();	// marks where we are as this is the first char of the filename
       
  2245 	
       
  2246 	TInt fileNameLength = 0;
       
  2247 	TInt maxFileNameLength = rFileName.MaxLength();
       
  2248 
       
  2249 	while(!aLex.Eos() && aLex.Peek()!=endChar && aLex.Peek()!=KImcvCR && fileNameLength < maxFileNameLength)	
       
  2250 		//spools through the string until the end and marks char before quote (such that 
       
  2251 		//  it extracts only the filename), EOS or before the maximum buffer length is exceeded 
       
  2252 		{
       
  2253 		fileNameLength++;
       
  2254 		aLex.Inc();
       
  2255 		}
       
  2256 
       
  2257 	TPtrC marked = aLex.MarkedToken(); 
       
  2258 	rFileName.Copy(marked);
       
  2259 	
       
  2260 	ReplaceInvalidCharacters(rFileName);
       
  2261 	}
       
  2262 
       
  2263 //----------------------------------------------------------------------------------------
       
  2264 void CImRecvConvert::SetAttachmentName(TDes& aFileName)
       
  2265 //----------------------------------------------------------------------------------------
       
  2266 	{
       
  2267 	ReplaceInvalidCharacters(aFileName);
       
  2268 	iAttachmentName.Zero();
       
  2269 
       
  2270 	TUint delimiter = '.';
       
  2271 	TInt  maxLength = iAttachmentName.MaxLength();
       
  2272 	
       
  2273 	__ASSERT_DEBUG(
       
  2274 		maxLength >= aFileName.Length(), gPanic(KPanicReadLengthTooLarge)
       
  2275 		);
       
  2276 
       
  2277 	iAttachmentName.Copy(aFileName);
       
  2278 	TInt attachmentLen = iAttachmentName.Length();
       
  2279 	if (attachmentLen == 0)
       
  2280 		iAttachmentName = *iDefaultAttachmentName;
       
  2281 	else if (iAttachmentName[0] == delimiter && maxLength >= attachmentLen + iDefaultAttachmentName->Length())
       
  2282 		iAttachmentName.Insert(0, *iDefaultAttachmentName);
       
  2283 	}
       
  2284 
       
  2285 //----------------------------------------------------------------------------------------
       
  2286 void CImRecvConvert::ReplaceInvalidCharacters(TDes& rFileName)
       
  2287 //----------------------------------------------------------------------------------------
       
  2288 	{
       
  2289 	TInt length = rFileName.Length();
       
  2290 	for(TInt index=0; index < length; index++)
       
  2291 		{
       
  2292 		//parse extracted filename and replace any illegal chars with a default.
       
  2293 
       
  2294 		if(IsIllegalChar((TUint)rFileName[index]))
       
  2295 			rFileName[index] = KImcvDefaultChar;
       
  2296 		}
       
  2297 	}
       
  2298 
       
  2299 //----------------------------------------------------------------------------------------
       
  2300 void CImRecvConvert::StoreEntryStreamsL()
       
  2301 //----------------------------------------------------------------------------------------	
       
  2302 	{
       
  2303 	StoreEntryStreamsL(KStoreBodyText|KStore822Header|KStoreMIMEHeader);
       
  2304 	}
       
  2305 
       
  2306 //----------------------------------------------------------------------------------------
       
  2307 void CImRecvConvert::StoreEntryStreamsL(TInt aSettings)
       
  2308 //----------------------------------------------------------------------------------------	
       
  2309 	{
       
  2310 	RECVLOG(KStartStoringEntryStream);
       
  2311 	CMsvStore* entryStore = NULL;
       
  2312 	TBool commitStore = EFalse;
       
  2313 	const TInt KChunkSize = 1024;
       
  2314 
       
  2315 	if (iReceivingHeadersOnly==EFalse)
       
  2316 		{
       
  2317 		//If bodytext has been stored using chunk mechanism.
       
  2318 		if ((aSettings & KStoreBodyText ) && iPlainBodyTextEntry && iEmailEntry->iType==KUidMsvEmailTextEntry)
       
  2319 			{
       
  2320 			iPlainBodyTextEntry->TryCommitL();
       
  2321 			TRAPD(error, entryStore = iServerEntry->ReadStoreL());
       
  2322 			if(error==KErrNone)
       
  2323 				{
       
  2324 				CleanupStack::PushL(entryStore);
       
  2325 				CMsvPlainBodyText* plainBodyText = entryStore->InitialisePlainBodyTextForReadL(KChunkSize);
       
  2326 				iEntryDataSize += plainBodyText->Size();
       
  2327 				delete plainBodyText;
       
  2328 				CleanupStack::PopAndDestroy();//entryStore
       
  2329 				}
       
  2330 			}
       
  2331 
       
  2332 		TRAPD(error, entryStore = iServerEntry->EditStoreL());
       
  2333 		if(error==KErrNone) // if store does not exist then the entry is the wrong type
       
  2334 			{
       
  2335 			CleanupStack::PushL(entryStore);
       
  2336 			if (aSettings & KStore822Header)
       
  2337 				Store822HeaderL(*entryStore, commitStore);
       
  2338 			
       
  2339 			if (aSettings & KStoreMIMEHeader)
       
  2340 				StoreMIMEHeaderL(*entryStore, commitStore);
       
  2341 
       
  2342 			if (aSettings & KStoreBodyText)
       
  2343 				StoreBodyTextL(*entryStore, commitStore);		
       
  2344 							
       
  2345 			// only commit to the store if I wrote something into it
       
  2346 			if (commitStore)
       
  2347 				{
       
  2348 				RECVLOG(KStoringEntryStream);
       
  2349 				entryStore->CommitL();
       
  2350 				}
       
  2351 			StoreEntryDataL();
       
  2352 			CleanupStack::PopAndDestroy(); //entryStore			
       
  2353 			}
       
  2354 		}
       
  2355 	RECVLOG(KDoneStoringEntryStream);
       
  2356 	}
       
  2357 
       
  2358 
       
  2359 //----------------------------------------------------------------------------------------
       
  2360 void CImRecvConvert::Store822HeaderL(CMsvStore& aStore, TBool& aCommit)
       
  2361 //----------------------------------------------------------------------------------------	
       
  2362 	{
       
  2363 	if(iEmptyHeaderSize<(iOutputHeader->DataSize()))
       
  2364 		{
       
  2365 		iEntryDataSize += iOutputHeader->DataSize()-iEmptyHeaderSize;
       
  2366 		RECVLOG(KStoringHeader);
       
  2367 		iOutputHeader->StoreL(aStore);	
       
  2368 		RECVLOG(KStoredHeader);
       
  2369 		aCommit = ETrue;
       
  2370 		}
       
  2371 	}
       
  2372 
       
  2373 //----------------------------------------------------------------------------------------
       
  2374 void CImRecvConvert::StoreMIMEHeaderL(CMsvStore& aStore, TBool& aCommit)
       
  2375 //----------------------------------------------------------------------------------------	
       
  2376 	{
       
  2377 	if(iMimeParser->MimeHeaderSize())
       
  2378 		{
       
  2379 		RECVLOG(KStoringMIMEHeader);
       
  2380  		iMimeParser->StoreMimeHeaderWithoutCommitL(aStore);
       
  2381 		aCommit = ETrue;
       
  2382 		RECVLOG(KStoredMIMEHeader);
       
  2383 		}
       
  2384 	}
       
  2385 
       
  2386 //----------------------------------------------------------------------------------------
       
  2387 void CImRecvConvert::StoreBodyTextL(CMsvStore& aStore, TBool& aCommit)
       
  2388 //----------------------------------------------------------------------------------------	
       
  2389 	{
       
  2390 	if (iStore8BitData)
       
  2391 		{
       
  2392 		if(iBodyBuf->Size())
       
  2393 			{
       
  2394 			iEntryDataSize += iBodyBuf->Size();
       
  2395 			RECVLOG(KStoring8BitBody);
       
  2396 			iBodyText->StoreL(aStore, *iBodyBuf);
       
  2397 			aCommit = ETrue;
       
  2398 			iBodyId=iServerEntry->Entry().Id();
       
  2399 			RECVLOG(KStored8BitBody);
       
  2400 			}
       
  2401 		}
       
  2402 	else
       
  2403 		{
       
  2404 		if(iOutputBody->DocumentLength())
       
  2405 			{
       
  2406 			iEntryDataSize += iOutputBody->DocumentLength();
       
  2407 			RECVLOG(KStoringBody);
       
  2408 			aStore.StoreBodyTextL(*iOutputBody);
       
  2409 			iBodyId=iServerEntry->Entry().Id();
       
  2410 			aCommit = ETrue;
       
  2411 			RECVLOG(KStoredBody);
       
  2412 			}
       
  2413 		}
       
  2414 	
       
  2415 	}
       
  2416 
       
  2417 //----------------------------------------------------------------------------------------
       
  2418 TBool CImRecvConvert::StoreEntryDataL()
       
  2419 //----------------------------------------------------------------------------------------	
       
  2420 	{
       
  2421 	// NB function should only be called if a whole email is being processed
       
  2422 	TBool commit=EFalse;
       
  2423 	RECVLOG(KUpdatingEntry)
       
  2424 
       
  2425 	if (iEmailEntry->iType==KUidMsvMessageEntry)
       
  2426 		iParent->At(0).iSize += iEntryDataSize;
       
  2427 	else
       
  2428 		{
       
  2429 		iEmailEntry->iSize += iEntryDataSize;
       
  2430 		if (iEntryType==EAttachmentEntry || iEntryType==EHtmlEntry)
       
  2431 			iEmailEntry->iDetails.Set(iAttachmentName);
       
  2432 		}
       
  2433 	User::LeaveIfError(iServerEntry->ChangeEntry(*iEmailEntry));
       
  2434 	RECVLOG(KUpdatedEntry)
       
  2435 	return commit;	// if I wrote data into the store, tell owner	
       
  2436 	}
       
  2437 
       
  2438 
       
  2439 //----------------------------------------------------------------------------------------
       
  2440 void CImRecvConvert::MoveToParentEntryL()
       
  2441 //----------------------------------------------------------------------------------------
       
  2442 	{
       
  2443 	// This function changes the context to the current entry's parent entry.
       
  2444 	RECVLOG(KMoveToParentEntry)
       
  2445 
       
  2446 	// Change context to the parent entry	
       
  2447 	if (EntryId()==iTopMessagePart)
       
  2448 		return; // Already there.
       
  2449 
       
  2450 	User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent())); 
       
  2451 
       
  2452 	iNewEntry = EFalse;
       
  2453 	
       
  2454 	// only read and write to store if this is a real email message; headers stored in
       
  2455 	// the remote mailbox do not require any store information.
       
  2456 	if (iReceivingHeadersOnly)
       
  2457 		{
       
  2458 		RECVLOG(KIgnoringStreams)
       
  2459 		return;
       
  2460 		}
       
  2461 
       
  2462 	TBool allowAttachmentFlag=ETrue;
       
  2463 	if(iServerEntry->Entry().iType == KUidMsvFolderEntry)
       
  2464 		{
       
  2465 		// Current entry is a folder entry signifying a MIME multipart.
       
  2466 		// Change context to the parent entry
       
  2467 		
       
  2468 		TMsvEmailEntry entry = (TMsvEmailEntry) iServerEntry->Entry();
       
  2469 		iCurrentMultipartFolderEntryId = EntryId();
       
  2470 		allowAttachmentFlag = !(entry.MessageFolderType()==EFolderTypeRelated || 
       
  2471 								entry.MessageFolderType()==EFolderTypeAlternative);
       
  2472 	
       
  2473 
       
  2474 		if (EntryId()!=iTopMessagePart)
       
  2475 			User::LeaveIfError(iServerEntry->SetEntry(iServerEntry->Entry().Parent())); 
       
  2476 		}
       
  2477 	
       
  2478 	TBool childIsMHTML = EFalse;
       
  2479 	TBool childIsAttachment = EFalse;
       
  2480 	TBool childIsICalendar = EFalse;
       
  2481 	TBool childIsVCalendar = EFalse;
       
  2482 	//Make the parent entry the current entry 
       
  2483 	if(iEmailEntry != NULL)
       
  2484 		{
       
  2485 		childIsAttachment = (iEmailEntry->Attachment() || iEmailEntry->iType == KUidMsvMessageEntry) ? ETrue:EFalse;
       
  2486 		
       
  2487 		childIsICalendar = (iEmailEntry->ICalendar()) ? ETrue:EFalse;
       
  2488 		childIsVCalendar = (iEmailEntry->VCalendar()) ? ETrue:EFalse;
       
  2489 		
       
  2490 		// Dont want the flag propogated 'up' past a message entry.
       
  2491 		if(iEmailEntry->iType != KUidMsvMessageEntry)
       
  2492 			childIsMHTML = iEmailEntry->MHTMLEmail() ? ETrue:EFalse;
       
  2493 
       
  2494 		delete iEmailEntry;
       
  2495 		iEmailEntry=NULL;
       
  2496 		}
       
  2497 
       
  2498 	iEmailEntry = new (ELeave) TMsvEmailEntry(iServerEntry->Entry());
       
  2499 
       
  2500 	if (!iParent->Count())
       
  2501 		{
       
  2502 		TParentDetails parentDetails;
       
  2503 		iParent->InsertL(0,parentDetails);
       
  2504 		}
       
  2505 
       
  2506 	if (! iParent->At(0).iAttachment)
       
  2507 		{
       
  2508 		iParent->At(0).iAttachment=(childIsAttachment && allowAttachmentFlag)? ETrue:EFalse;
       
  2509 
       
  2510 		// if we aren't allowing attachments because of the folder type
       
  2511 		// remember there where attachments and check at the end whether
       
  2512 		// it was an MHTML message or not.
       
  2513 		if(childIsAttachment && !allowAttachmentFlag)
       
  2514 			{
       
  2515 			iRelatedAttachments=ETrue;
       
  2516 			}
       
  2517 		}
       
  2518 	if (!iParent->At(0).iMHTML)
       
  2519 		{
       
  2520 		iParent->At(0).iMHTML = childIsMHTML ? ETrue:EFalse;
       
  2521 		}
       
  2522 		
       
  2523 	if (!iParent->At(0).iICal)
       
  2524 		{
       
  2525 		iParent->At(0).iICal = childIsICalendar ? ETrue:EFalse;
       
  2526 		}
       
  2527 	if (!iParent->At(0).iVCal)
       
  2528 		{
       
  2529 		iParent->At(0).iVCal = childIsVCalendar ? ETrue:EFalse;
       
  2530 		}
       
  2531 	
       
  2532 	iParent->At(0).iSize += iEntryDataSize;
       
  2533 
       
  2534 	iOutputHeader->Reset();
       
  2535 	iEmptyHeaderSize=iOutputHeader->DataSize();
       
  2536 	iMimeParser->ResetForNewEntry();
       
  2537 
       
  2538 	iEntryDataSize=0;
       
  2539 
       
  2540 	RECVLOG(KMovedToParentEntry)
       
  2541 	}
       
  2542 
       
  2543 //----------------------------------------------------------------------------------------
       
  2544 // Helper function to add the partial footer to the email if it exists
       
  2545 //----------------------------------------------------------------------------------------
       
  2546 EXPORT_C void CImRecvConvert::WritePartialFooterL(TInt aAmountLeft)
       
  2547 	{
       
  2548 	if(iStore8BitData)
       
  2549 		{
       
  2550 		WritePartialFooter8L(aAmountLeft);
       
  2551 		return;	
       
  2552 		}
       
  2553 	TMsvId msgId=iBodyId;
       
  2554 
       
  2555 	if (msgId==KMsvNullIndexEntryId)
       
  2556 		return;
       
  2557 	TMsvId id = iServerEntry->Entry().Id();
       
  2558 	if (iServerEntry->SetEntry(msgId)==KErrNone)
       
  2559 		{
       
  2560 		TBool storePresent = iServerEntry->HasStoreL();
       
  2561 		if (storePresent && iPartialEmailFooter->Length()>0 && aAmountLeft>0)
       
  2562 			{
       
  2563 			CMsvStore* store = iServerEntry->ReadStoreL();
       
  2564 			CleanupStack::PushL(store);
       
  2565 			if (store->HasBodyTextL())
       
  2566 				{
       
  2567 				iOutputBody->Reset();
       
  2568 				store->RestoreBodyTextL(*iOutputBody);
       
  2569 				CleanupStack::PopAndDestroy(store);
       
  2570 				store = NULL;
       
  2571 				HBufC* msg=NULL;
       
  2572 				if (iPartialEmailFooter->Find(KIntegerKey)!=KErrNotFound)
       
  2573 					{
       
  2574 					// display k left on the server, rounded up if between 1 and 1023 bytes
       
  2575 					TInt kBytesLeft = aAmountLeft / 1024;
       
  2576 					if(kBytesLeft == 0)
       
  2577 						kBytesLeft = 1;
       
  2578 					msg = HBufC::NewLC(iPartialEmailFooter->Length()+KSpaceToAddNumber);
       
  2579 					msg->Des().Format(*iPartialEmailFooter,kBytesLeft);
       
  2580 					}
       
  2581 				else
       
  2582 					{
       
  2583 					msg = iPartialEmailFooter->AllocLC();
       
  2584 					}
       
  2585 					
       
  2586 				iOutputBody->AppendParagraphL();
       
  2587 				TInt length = iOutputBody->DocumentLength();
       
  2588 				iOutputBody->InsertL(length,*msg);
       
  2589 				
       
  2590 				CleanupStack::PopAndDestroy(msg);
       
  2591 									
       
  2592 				store = iServerEntry->EditStoreL();
       
  2593 				CleanupStack::PushL(store);
       
  2594 				// If chunk storage mechanism is used then add partial download footer
       
  2595 				// information to the body text, using CMsvPlainBodyText.
       
  2596 				if(iStorePlainBodyText)
       
  2597 					{
       
  2598 					CMsvPlainBodyText* plainBodyText = store->InitialisePlainBodyTextForWriteL(iStore8BitData, iMimeParser->CurrentCharsetL(),iCharConv->SystemDefaultCharset());
       
  2599 					CleanupStack::PushL(plainBodyText);
       
  2600 					plainBodyText->StoreRichTextAsPlainTextL(*iOutputBody);			
       
  2601 					plainBodyText->CommitL();
       
  2602 					CleanupStack::PopAndDestroy(plainBodyText);
       
  2603 					}
       
  2604 				else
       
  2605 					{
       
  2606 					store->StoreBodyTextL(*iOutputBody);
       
  2607 					store->Commit();
       
  2608 					}
       
  2609 				CleanupStack::PopAndDestroy(store);
       
  2610 				}
       
  2611 			else
       
  2612 				{
       
  2613 				CleanupStack::PopAndDestroy(store);
       
  2614 				}
       
  2615 			}
       
  2616 		}
       
  2617 	iServerEntry->SetEntry(id);
       
  2618 	}
       
  2619 
       
  2620 void CImRecvConvert::WritePartialFooter8L(TInt aAmountLeft)
       
  2621 	{
       
  2622 	TMsvId msgId=iBodyId;
       
  2623 	if (msgId==KMsvNullIndexEntryId)
       
  2624 		return;
       
  2625 	TMsvId id = iServerEntry->Entry().Id();
       
  2626 	if (iServerEntry->SetEntry(msgId)==KErrNone)
       
  2627 		{
       
  2628 		// TMsvEmailEntry should also be set to CMsvServerEntry
       
  2629 		*iEmailEntry = iServerEntry->Entry();
       
  2630 		TBool storePresent = iServerEntry->HasStoreL();
       
  2631 		if (storePresent && iPartialEmailFooter8->Length()>0 && aAmountLeft>0)
       
  2632 			{
       
  2633 			CMsvStore* store = iServerEntry->ReadStoreL();
       
  2634 			CleanupStack::PushL(store);
       
  2635 			if (store->HasBodyTextL())
       
  2636 				{
       
  2637 				// if Uid does not Exist in Message Store, return KErrNotSupported.
       
  2638 				TInt bufLength = iBodyText->GetBodyLengthL(*store);
       
  2639 				User::LeaveIfError(bufLength);
       
  2640 				HBufC8* bodyBuffer = HBufC8::NewLC(bufLength);
       
  2641 				iBodyBuf->Reset();
       
  2642 				TPtr8 buf = bodyBuffer->Des();
       
  2643 				iBodyText->GetBodyTextL(*store, buf);
       
  2644 				if(!iStorePlainBodyText)
       
  2645 					{
       
  2646 					iBodyBuf->InsertL(0, buf);
       
  2647 					}
       
  2648 				CleanupStack::Pop(bodyBuffer);
       
  2649 				iPartialRetrievalBody=bodyBuffer;
       
  2650 				CleanupStack::PopAndDestroy(store);
       
  2651 			
       
  2652 				HBufC* msg=NULL;
       
  2653 				TResourceReader reader;
       
  2654 				reader.SetBuffer(iPartialEmailFooter8);
       
  2655 				
       
  2656 				if (iPartialEmailFooter8->Find((TDesC8&)KIntegerKey)!=KErrNotFound)
       
  2657 					{
       
  2658 					_LIT8(Ktemp9, "....8 bit....Found KIntegerKey");
       
  2659 					RECVLOG(Ktemp9)
       
  2660 					// display k left on the server, rounded up if between 1 and 1023 bytes
       
  2661 					TInt kBytesLeft = aAmountLeft / 1024;
       
  2662 					if(kBytesLeft == 0)
       
  2663 						{
       
  2664 						kBytesLeft = 1;
       
  2665 						}						
       
  2666 					HBufC* resourceBuf = (reader.ReadTPtrC()).AllocL();
       
  2667 					CleanupStack::PushL(resourceBuf);
       
  2668 					msg = HBufC::NewL(resourceBuf->Length()+ 10);
       
  2669 					msg->Des().Format(*resourceBuf,kBytesLeft);
       
  2670 					CleanupStack::PopAndDestroy(resourceBuf);
       
  2671 					CleanupStack::PushL(msg);	
       
  2672 					}
       
  2673 				else
       
  2674 					{
       
  2675 					msg = (reader.ReadTPtrC()).AllocL();
       
  2676 					CleanupStack::PushL(msg);
       
  2677 					}
       
  2678 				
       
  2679 				HBufC8* footerMsg= HBufC8::NewLC(msg->Size()+ 20);
       
  2680 				if(iBodyText->CharacterSet())
       
  2681 					{
       
  2682 					iCharConv->PrepareToConvertToFromOurCharsetL(iBodyText->CharacterSet());
       
  2683 					}
       
  2684 				else
       
  2685 					{
       
  2686 					iCharConv->PrepareToConvertToFromOurCharsetL(iBodyText->DefaultCharacterSet());	
       
  2687 					}
       
  2688 				TInt numUnconverted = 0;
       
  2689 				TInt unConvertedIndex = 0;
       
  2690 				TPtr8 output(footerMsg->Des());
       
  2691 				TPtr16 input(msg->Des());
       
  2692 				iCharConv->ConvertFromOurCharsetL(input, output, numUnconverted, unConvertedIndex);
       
  2693 				store=NULL;
       
  2694 				store = iServerEntry->EditStoreL();
       
  2695 				CleanupStack::PushL(store);
       
  2696 
       
  2697 				//If its Plain body Text then Partial download footer information
       
  2698 				//is added to the body text, using CMsvPlainBodyText.
       
  2699 				if(iStorePlainBodyText)
       
  2700 					{
       
  2701 					CMsvPlainBodyText* plainBodyText = store->InitialisePlainBodyTextForWriteL(iStore8BitData, iMimeParser->CurrentCharsetL(),iCharConv->SystemDefaultCharset());
       
  2702 					CleanupStack::PushL(plainBodyText);
       
  2703 					plainBodyText->StoreChunkL(*iPartialRetrievalBody);
       
  2704 					plainBodyText->StoreChunkL(KImcvCRLF());
       
  2705 					plainBodyText->StoreChunkL(*footerMsg);
       
  2706 					plainBodyText->CommitL();
       
  2707 					CleanupStack::PopAndDestroy(plainBodyText);
       
  2708 					}
       
  2709 				else
       
  2710 					{
       
  2711 					iBodyBuf->InsertL(iBodyBuf->Size(), KImcvCRLF()); 
       
  2712 					iBodyBuf->InsertL(iBodyBuf->Size(), *footerMsg);
       
  2713 					iBodyText->StoreL(*store, *iBodyBuf);
       
  2714 					store->Commit();
       
  2715 					}
       
  2716 				CleanupStack::PopAndDestroy(3,msg); // msg, footerMsg, store
       
  2717 				}
       
  2718 			else
       
  2719 				{
       
  2720 				CleanupStack::PopAndDestroy(store);
       
  2721 				}
       
  2722 			}
       
  2723 		}
       
  2724 	iServerEntry->SetEntry(id);	
       
  2725 	}
       
  2726 
       
  2727 //----------------------------------------------------------------------------------------
       
  2728 void CImRecvConvert::CreateEntryL()
       
  2729 //----------------------------------------------------------------------------------------
       
  2730 	{
       
  2731 	RECVLOG(KCreatingEntry);
       
  2732 	if(iEmailEntry)
       
  2733 		{
       
  2734 		delete iEmailEntry;
       
  2735 		iEmailEntry=NULL;
       
  2736 		}
       
  2737 
       
  2738 	if (iCurrentMultipartFolderEntryId)
       
  2739 		{
       
  2740 		User::LeaveIfError(iServerEntry->SetEntry(iCurrentMultipartFolderEntryId));
       
  2741 		iCurrentMultipartFolderEntryId=0;
       
  2742 		}
       
  2743 		
       
  2744 	iEmailEntry = new (ELeave) TMsvEmailEntry;
       
  2745 
       
  2746 	TValidEntryType previousEntryType = iEntryType;
       
  2747 	if (!iTopMessagePart || iMIMEPart_822Header)
       
  2748 		{
       
  2749 		// At the main header, want to create a message entry.
       
  2750 		// The stored iEntryType will indicate ( from header info) the next entry to be created.
       
  2751 		// Save temporarily.
       
  2752 		// Also applies to the special case where a message contains ony 1 embedded message.
       
  2753 
       
  2754 		previousEntryType=iEntryType;
       
  2755 		iEntryType=EMessageEntry;
       
  2756 		}
       
  2757 
       
  2758 	if ((iPopulateMessage) && (!iTopMessagePart))
       
  2759 	// If this is the root of a message that is being populated then do not create it.
       
  2760 		{
       
  2761 		User::LeaveIfError(iServerEntry->SetEntry(iRootEntryId));
       
  2762 		*iEmailEntry = iServerEntry->Entry();
       
  2763 		iTopMessagePart=iRootEntryId;
       
  2764 
       
  2765 		// Delete all the children of the message entry.  This is needed because if the
       
  2766 		// message has been purged, the entries will still exist.  When the message is populated,
       
  2767 		// new entries are created.  If the original entries are not removed, then duplicate 
       
  2768 		// entries will exist.
       
  2769 		CMsvEntrySelection*	children = new(ELeave) CMsvEntrySelection;
       
  2770 		CleanupStack::PushL(children);
       
  2771 		User::LeaveIfError(iServerEntry->GetChildren(*children));
       
  2772 		if (children->Count())
       
  2773 			iServerEntry->DeleteEntries(*children);
       
  2774 		CleanupStack::PopAndDestroy(children);
       
  2775 		}
       
  2776 	else
       
  2777 		{
       
  2778 		iEmailEntry->iMtm=iNewMsgType;
       
  2779 		iEmailEntry->iServiceId = iEmailServiceId;
       
  2780 		iEmailEntry->SetComplete(EFalse);
       
  2781 		iEmailEntry->iSize = 0;
       
  2782 		iEmailEntry->SetVisible(ETrue);
       
  2783 		iEmailEntry->SetInPreparation(EFalse);
       
  2784 		iEmailEntry->SetReceipt(EFalse);
       
  2785 
       
  2786 		iEmailEntry->SetVCard(iMimeParser->VCard());
       
  2787 		iEmailEntry->SetVCalendar(iMimeParser->VCalendar());
       
  2788 		iEmailEntry->SetICalendar(iMimeParser->ICalendar());
       
  2789 		iEmailEntry->SetMessageFolderType(iMimeParser->MessageFolderType());
       
  2790 		iEmailEntry->SetPriority(iImPriority);
       
  2791 		iEmailEntry->SetNew(EFalse);
       
  2792 
       
  2793 		if(iOutputHeader->ReceiptAddress().Length()>0)
       
  2794 			iEmailEntry->SetReceipt(ETrue);
       
  2795 
       
  2796 		iEmailEntry->iDate=iTimeDate;
       
  2797 		switch(iEntryType)
       
  2798 			{
       
  2799 			case EMessageEntry:
       
  2800 				iParsedTime=EFalse;
       
  2801 				if(!iTopMessagePart)
       
  2802 					{
       
  2803 					iEmailEntry->SetUnread(ETrue);
       
  2804 					iEmailEntry->SetNew(ETrue);
       
  2805 					iEmailEntry->SetVisible(EFalse);
       
  2806 					iEmailEntry->SetInPreparation(ETrue);
       
  2807 					iEmailEntry->SetSendingState(KMsvSendStateNotApplicable);
       
  2808 					}
       
  2809 				else
       
  2810 					{
       
  2811 					TParentDetails parentDetails;
       
  2812 					parentDetails.iMHTML=EFalse;
       
  2813 			        parentDetails.iAttachment=EFalse;
       
  2814 			        parentDetails.iICal=EFalse;
       
  2815 			        parentDetails.iVCal=EFalse;
       
  2816 					parentDetails.iSize=0;
       
  2817 					iParent->InsertL(0,parentDetails);
       
  2818 					}
       
  2819 				iEmailEntry->iType=KUidMsvMessageEntry;
       
  2820 				iEmailEntry->iDetails.Set(iOutputHeader->From());
       
  2821 				iEmailEntry->iDescription.Set(iOutputHeader->Subject());
       
  2822 				break;
       
  2823 			case EFolderEntry:
       
  2824 				iEmailEntry->iType=KUidMsvFolderEntry;
       
  2825 				if (iMimeParser->MessageFolderType()==EFolderTypeUnknown)
       
  2826 					{
       
  2827 					// Get folder type of parent (the message)
       
  2828 					TMsvEmailEntry entry=iServerEntry->Entry();
       
  2829 					iEmailEntry->SetMessageFolderType(entry.MessageFolderType());
       
  2830 					}
       
  2831 				break;
       
  2832 			case EAttachmentEntry:
       
  2833 				iEmailEntry->iType=KUidMsvAttachmentEntry;
       
  2834 				iEmailEntry->iDetails.Set(iAttachmentName);
       
  2835 				iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
       
  2836 				break; 
       
  2837 			case ETextEntry:
       
  2838 				if ( iMimeParser->ContentDisposition()!=KImcvAttachment)
       
  2839 					{
       
  2840 					iEmailEntry->iType=KUidMsvEmailTextEntry;
       
  2841 					if(iStorePlainBodyText)
       
  2842 						{
       
  2843 						iFirstLinePlainText = ETrue;
       
  2844 						}
       
  2845 					}
       
  2846 				else 
       
  2847 					{
       
  2848 					iEmailEntry->iType=KUidMsvAttachmentEntry;
       
  2849 					iEmailEntry->iDetails.Set(iAttachmentName);
       
  2850 					iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
       
  2851 					}
       
  2852 				break;
       
  2853 			case EHtmlEntry:
       
  2854 				iEmailEntry->iType=KUidMsvEmailHtmlEntry;
       
  2855 				// If disposition not set or is inline..
       
  2856 				if ( iMimeParser->ContentDisposition()==KImcvAttachment)
       
  2857 					iEmailEntry->iType=KUidMsvAttachmentEntry;
       
  2858 				else
       
  2859 					iEmailEntry->SetMHTMLEmail(ETrue);
       
  2860 				iEmailEntry->iDetails.Set(iAttachmentName);
       
  2861 				iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
       
  2862 				break;
       
  2863 			case ERtfEntry:
       
  2864 			default:
       
  2865 				iEmailEntry->iType=KUidMsvAttachmentEntry;
       
  2866 				iEmailEntry->iDetails.Set(iAttachmentName);
       
  2867 				iEmailEntry->iDescription.Set(iMimeParser->ContentDescription());
       
  2868 			}
       
  2869 
       
  2870 		if (iReceivingHeadersOnly)
       
  2871 			{
       
  2872 			User::LeaveIfError(iServerEntry->CreateEntryBulk(*iEmailEntry));
       
  2873 			}
       
  2874 		else
       
  2875 			{
       
  2876 			User::LeaveIfError(iServerEntry->CreateEntry(*iEmailEntry));
       
  2877 			}
       
  2878 		User::LeaveIfError(iServerEntry->SetEntry(iEmailEntry->Id()));
       
  2879 		if(!iTopMessagePart)
       
  2880 			iTopMessagePart=iEmailEntry->Id();
       
  2881 
       
  2882 		//if (iEntryType==EHtmlEntry && iAttachmentFileState!=EFileIsOpen)
       
  2883 		//	CreateAttachmentL();
       
  2884 		}
       
  2885 	
       
  2886 	iEntryType=previousEntryType;
       
  2887 	iNewEntry = ETrue;
       
  2888 	RECVLOG(KCreatedEntry);
       
  2889 	}
       
  2890 
       
  2891 //----------------------------------------------------------------------------------------  
       
  2892 void CImRecvConvert::Logging(const TDesC8& aString1, const TDesC8& aString2)
       
  2893 //----------------------------------------------------------------------------------------  
       
  2894 	{
       
  2895 	TBuf8<1024> aBuf(aString1);
       
  2896 
       
  2897 	aBuf.Append(aString2);
       
  2898 	RECVLOG(aBuf);
       
  2899 	}
       
  2900 
       
  2901 //----------------------------------------------------------------------------------------  
       
  2902 void CImRecvConvert::StoreMessageEntryDetailsL()
       
  2903 //----------------------------------------------------------------------------------------  
       
  2904 	{
       
  2905 	iEmailEntry->SetAttachment(iParent->At(0).iAttachment);
       
  2906 	iEmailEntry->SetMHTMLEmail(iParent->At(0).iMHTML);
       
  2907 	iEmailEntry->SetICalendar(iParent->At(0).iICal);
       
  2908 	iEmailEntry->SetVCalendar(iParent->At(0).iVCal);
       
  2909 
       
  2910 	if(iEmailEntry->MHTMLEmail() == EFalse && iEmailEntry->Attachment() == EFalse && iRelatedAttachments !=EFalse)
       
  2911 		{
       
  2912 		iEmailEntry->SetAttachment(ETrue);
       
  2913 		}
       
  2914 	iRelatedAttachments=EFalse;
       
  2915 	
       
  2916 	iEmailEntry->iSize = iParent->At(0).iSize;
       
  2917 	iEmailEntry->SetMessageFolderType(iParent->At(0).iFolder);
       
  2918 	StoreEntryDataL();
       
  2919 
       
  2920 	if (iParent->Count()>1)
       
  2921 		{
       
  2922 		iParent->At(1).iSize += iEmailEntry->iSize;
       
  2923 		iParent->Delete(0);
       
  2924 		}
       
  2925 	else
       
  2926 		{
       
  2927 		iParent->At(0).iAttachment = EFalse;
       
  2928 		iParent->At(0).iMHTML = EFalse;
       
  2929 		iParent->At(0).iICal = EFalse;
       
  2930 		iParent->At(0).iVCal = EFalse;
       
  2931 		iParent->At(0).iSize = 0;
       
  2932 		}
       
  2933 	}
       
  2934 
       
  2935 //----------------------------------------------------------------------------------------  
       
  2936 EXPORT_C TInt CImRecvConvert::DeletedAttachmentSize()
       
  2937 //----------------------------------------------------------------------------------------  
       
  2938 	{
       
  2939 	return iSizeOfAttachmentsRemoved;
       
  2940 	}
       
  2941 
       
  2942 
       
  2943 /****************************************************************************
       
  2944 	Class CMimeParser functions
       
  2945 *****************************************************************************/
       
  2946 //----------------------------------------------------------------------------------------    
       
  2947 EXPORT_C CMimeParser* CMimeParser::NewLC(CImRecvConvert& aImRecvConvert)
       
  2948 //----------------------------------------------------------------------------------------  
       
  2949 	{
       
  2950 	CMimeParser* self = new (ELeave) CMimeParser(aImRecvConvert);
       
  2951 	CleanupStack::PushL(self);
       
  2952 	self->ConstructL();
       
  2953 	return self;
       
  2954 	}
       
  2955 
       
  2956 //----------------------------------------------------------------------------------------  
       
  2957 EXPORT_C CMimeParser* CMimeParser::NewL(CImRecvConvert& aImRecvConvert)
       
  2958 //----------------------------------------------------------------------------------------  
       
  2959 	{
       
  2960 	CMimeParser* self = CMimeParser::NewLC(aImRecvConvert);
       
  2961 	CleanupStack::Pop();
       
  2962 	return self;
       
  2963 	}
       
  2964 
       
  2965 //----------------------------------------------------------------------------------------
       
  2966 CMimeParser::CMimeParser(CImRecvConvert& aImRecvConvert): iImRecvConvert(aImRecvConvert), 
       
  2967 											iStartId(NULL)
       
  2968 //----------------------------------------------------------------------------------------
       
  2969 	{
       
  2970 	__DECLARE_NAME(_S("CMimeParser"));
       
  2971 	}
       
  2972 
       
  2973 //----------------------------------------------------------------------------------------
       
  2974 void CMimeParser::ConstructL() 
       
  2975 //----------------------------------------------------------------------------------------
       
  2976 	{
       
  2977 	iMimeHeader = CImMimeHeader::NewL();
       
  2978 
       
  2979 	
       
  2980 	// Create a Desc array to store the boundary strings of a Mime message
       
  2981 	iBoundaryText = new (ELeave) CDesC8ArrayFlat(3);
       
  2982 	
       
  2983 	// Set charset default value
       
  2984 	iDefaultCharset=iImRecvConvert.CharacterConverter().DefaultCharset();
       
  2985 	iCharset = iDefaultCharset;
       
  2986 	ResetMimeFieldsExist();
       
  2987 
       
  2988 	Reset();
       
  2989 	}
       
  2990 
       
  2991 //----------------------------------------------------------------------------------------
       
  2992 EXPORT_C CMimeParser::~CMimeParser() 
       
  2993 //----------------------------------------------------------------------------------------
       
  2994 	{
       
  2995 	delete iMimeHeader;
       
  2996 	delete iBoundaryText;
       
  2997 	delete iMimeHeaderLine;
       
  2998 	delete iStartId;
       
  2999 	}
       
  3000 
       
  3001 //----------------------------------------------------------------------------------------
       
  3002 void CMimeParser::Reset() 
       
  3003 //----------------------------------------------------------------------------------------
       
  3004 	{
       
  3005 	iBoundaryText->Reset();
       
  3006 	iBoundaryIndex = 0;
       
  3007 	iBoundaryLength = 0;
       
  3008 	isMime = EFalse;
       
  3009 	
       
  3010 	iCharset = iDefaultCharset;
       
  3011 	ResetForNewEntry();
       
  3012 	}
       
  3013 
       
  3014 //----------------------------------------------------------------------------------------
       
  3015 void CMimeParser::ResetForNewEntry()
       
  3016 //----------------------------------------------------------------------------------------
       
  3017 	{
       
  3018 	
       
  3019 	iMimeHeader->Reset();
       
  3020 	iEmptyMimeHeaderSize=iMimeHeader->Size();
       
  3021 		
       
  3022 	iContentType = EMimeUnknownContent;
       
  3023 	iContentEncoding = EEncodingTypeNone;
       
  3024 	iContentDescription.Zero();
       
  3025 	iVCard = EFalse;
       
  3026 	iVCalendar = EFalse;
       
  3027 	iICalendar = EFalse;
       
  3028 	iStartPart=EFalse;
       
  3029 	iMessageFolderType = EFolderTypeUnknown;
       
  3030 	iTerminatingBoundary = EFalse;
       
  3031 	iBoundaryFound = EFalse;
       
  3032 	}
       
  3033 
       
  3034 //----------------------------------------------------------------------------------------
       
  3035 void CMimeParser::RestoreMimeParserL(CMsvStore& entryStore)
       
  3036 //----------------------------------------------------------------------------------------
       
  3037 	{
       
  3038 	iMimeHeader->RestoreL(entryStore);
       
  3039 
       
  3040 	if(iMimeHeader->ContentType().Compare(KImcvText)==0)
       
  3041 		iContentType=EMimeText; 
       
  3042 	else
       
  3043 	if(iMimeHeader->ContentType().Compare(KImcvMessage)==0)
       
  3044 		iContentType=EMimeMessage;
       
  3045 	else
       
  3046 	if(iMimeHeader->ContentType().Compare(KImcvMultipart)==0)
       
  3047 		iContentType=EMimeMultipart; 
       
  3048 	else
       
  3049 	if(iMimeHeader->ContentType().Compare(KImcvImage)==0)
       
  3050 		iContentType=EMimeImage; 
       
  3051 	else
       
  3052 	if(iMimeHeader->ContentType().Compare(KImcvApplication)==0)
       
  3053 		iContentType=EMimeApplication; 
       
  3054 	else
       
  3055 	if(iMimeHeader->ContentType().Compare(KImcvAudio)==0)
       
  3056 		iContentType=EMimeAudio; 
       
  3057 	else
       
  3058 	if(iMimeHeader->ContentType().Compare(KImcvVideo)==0)
       
  3059 		iContentType=EMimeVideo; 
       
  3060 	else
       
  3061 		iContentType=EMimeUnknownContent; 
       
  3062 
       
  3063 	}
       
  3064 
       
  3065 //----------------------------------------------------------------------------------------
       
  3066 void CMimeParser::ParseLineL(const TDesC8& aSourceLine)
       
  3067 //----------------------------------------------------------------------------------------
       
  3068 	{
       
  3069 	if(iMimeHeaderLine==NULL)
       
  3070 		{
       
  3071 		iMimeHeaderLine = HBufC8::NewL(aSourceLine.Length());
       
  3072 		*iMimeHeaderLine = aSourceLine;
       
  3073 		}
       
  3074 	
       
  3075 	iLex = *iMimeHeaderLine;
       
  3076 
       
  3077 	// find out whether the current line has anything to do with currently understood MIME Content tokens
       
  3078 	if(!iMimeHeaderLine->MatchF(KImcvMime) || !iMimeHeaderLine->MatchF(KImcvContent))
       
  3079 		{ 
       
  3080 		if(MatchAndRemoveToken(KImcvMimePrompt))
       
  3081 			DoMimeVersion();
       
  3082 		else if(MatchAndRemoveToken(KImcvContentType))
       
  3083 			{
       
  3084 			// Check CAF for recognition of content-type in RegisterL()
       
  3085 			if(!iImRecvConvert.iReceivingHeadersOnly)
       
  3086 				{
       
  3087 				// CAF processing.
       
  3088 				// We need to trim any trailing data following and including semicolons
       
  3089 				// If we leave it to the Register method then it has to create a heap buffer
       
  3090 				// to do the manipulation. iMimeHeaderLine is modifiable so do it here.
       
  3091 				TInt orgLength = iMimeHeaderLine->Length();
       
  3092 				TInt endOffset;
       
  3093 				// Get the offset of the semicolon if any
       
  3094 				if((endOffset = iMimeHeaderLine->Locate(KImcvSemiColon)) != KErrNotFound)
       
  3095 					{
       
  3096 			 		// Trim to the content-type token only
       
  3097 					iMimeHeaderLine->Des().SetLength(endOffset);
       
  3098 					}
       
  3099 				// Sets CAF interested if framework to consume
       
  3100 				iImRecvConvert.ImCafRegisterL(iMimeHeaderLine->Des());
       
  3101 				// Restore length of the descriptor for futher processing
       
  3102 				iMimeHeaderLine->Des().SetLength(orgLength);
       
  3103 				}
       
  3104 			DoContentTypeL();
       
  3105 			}
       
  3106 		else if(MatchAndRemoveToken(KImcvContentLocation))
       
  3107 			DoContentLocationL();
       
  3108 		else if(MatchAndRemoveToken(KImcvContentTransferEncoding))
       
  3109 			DoEncodingL();
       
  3110 		else if(MatchAndRemoveToken(KImcvContentId))
       
  3111 			{
       
  3112 			RemoveSurroundingCharacters(KImcvLeftChevron, KImcvRightChevron, *iMimeHeaderLine);
       
  3113 			DoContentIdL();
       
  3114 			}
       
  3115 		else if(MatchAndRemoveToken(KImcvContentDescription))
       
  3116 			DoDescriptionL();
       
  3117 		else if(MatchAndRemoveToken(KImcvContentDisposition))
       
  3118 			DoDispositionL();
       
  3119 		else if(MatchAndRemoveToken(KImcvContentBase))
       
  3120 			DoContentBaseL();
       
  3121 		}
       
  3122 	// Start adding to the CAF metadata if CAF's interested
       
  3123 	if(iImRecvConvert.ImCafRegistered())
       
  3124 		{
       
  3125 		iImRecvConvert.ImAddToCafMetaDataL(aSourceLine);
       
  3126 		}
       
  3127 		
       
  3128 	delete iMimeHeaderLine;	// clean up and null pointer iff CompleteMimeHeader and no foldover append req'd
       
  3129 	iMimeHeaderLine=NULL;
       
  3130 	}
       
  3131 
       
  3132 //----------------------------------------------------------------------------------------
       
  3133 void CMimeParser::DoMimeVersion()
       
  3134 //----------------------------------------------------------------------------------------
       
  3135 	{
       
  3136 	// extract the MIME version from a header line which we already know
       
  3137 	// has 'MIME-Version' start of it.
       
  3138 	if(MatchAndRemoveToken(KImcvMimeVersion))
       
  3139 		iCorrectMimeVersion = ETrue;
       
  3140 	}
       
  3141 
       
  3142 //----------------------------------------------------------------------------------------
       
  3143 void CMimeParser::DoContentIdL()
       
  3144 //----------------------------------------------------------------------------------------
       
  3145 	{
       
  3146 	iMimeHeader->SetContentIDL(iMimeHeaderLine->Des());
       
  3147 	if(iStartId && iStartId->CompareF(iMimeHeaderLine->Des())==KErrNone)
       
  3148 		iStartPart=ETrue;
       
  3149 	}
       
  3150 
       
  3151 //----------------------------------------------------------------------------------------
       
  3152 void CMimeParser::DoContentLocationL()
       
  3153 //----------------------------------------------------------------------------------------
       
  3154 	{
       
  3155 	TInt len = (*iMimeHeaderLine).Length();
       
  3156 	if (len == 0)
       
  3157 		return;
       
  3158 			
       
  3159 	RemoveSurroundingCharacters(KImcvQuote, KImcvQuote, *iMimeHeaderLine);
       
  3160 
       
  3161 	HBufC16* locationBuf = HBufC16::NewL( len );
       
  3162 	CleanupStack::PushL(locationBuf);
       
  3163 	TPtr locationPtr(locationBuf->Des());
       
  3164 	iImRecvConvert.iHeaderConverter->DecodeHeaderFieldL( iMimeHeaderLine->Des(), locationPtr);
       
  3165 	iMimeHeader->SetContentLocationL(locationPtr);
       
  3166 	CleanupStack::PopAndDestroy(); // locationBuf
       
  3167 	}
       
  3168 
       
  3169 //----------------------------------------------------------------------------------------
       
  3170 void CMimeParser::DoContentBaseL()
       
  3171 //----------------------------------------------------------------------------------------
       
  3172 	{
       
  3173 	RemoveSurroundingCharacters(KImcvQuote, KImcvQuote, *iMimeHeaderLine);
       
  3174 	iMimeHeader->SetContentBaseL(iMimeHeaderLine->Des());
       
  3175 	}
       
  3176 
       
  3177 //----------------------------------------------------------------------------------------
       
  3178 void CMimeParser::DoAttachmentTypeL()
       
  3179 //----------------------------------------------------------------------------------------
       
  3180 	{
       
  3181 	iImRecvConvert.iEntryType = CImRecvConvert::EAttachmentEntry;
       
  3182 	iImRecvConvert.iCurrentPartIsRichText = EFalse;	
       
  3183 
       
  3184 	if(MatchAndRemoveToken(KImcvForwardSlash))
       
  3185 		{
       
  3186 		if(MatchAndRemoveToken(KImcvBmp))
       
  3187 			{
       
  3188 			iMimeHeader->SetContentSubTypeL(KImcvBmp);
       
  3189 			}
       
  3190 		else
       
  3191 		if(MatchAndRemoveToken(KImcvGif))
       
  3192 			{
       
  3193 			iMimeHeader->SetContentSubTypeL(KImcvGif);
       
  3194 			}
       
  3195 		else
       
  3196 		if(MatchAndRemoveToken(KImcvJpeg))
       
  3197 			{
       
  3198 			iMimeHeader->SetContentSubTypeL(KImcvJpeg);
       
  3199 			}
       
  3200 		else
       
  3201 		if(MatchAndRemoveToken(KImcvTiff))
       
  3202 			{
       
  3203 			iMimeHeader->SetContentSubTypeL(KImcvTiff);
       
  3204 			}
       
  3205 		else
       
  3206 		if(MatchAndRemoveToken(KImcvWav))
       
  3207 			{
       
  3208 			iMimeHeader->SetContentSubTypeL(KImcvWav);
       
  3209 			}
       
  3210 		else
       
  3211 		if(MatchAndRemoveToken(KImcvZip))
       
  3212 			{
       
  3213 			iMimeHeader->SetContentSubTypeL(KImcvZip);
       
  3214 			}
       
  3215 		else
       
  3216 		if(MatchAndRemoveToken(KImcvOctetStream))
       
  3217 			{
       
  3218 			iMimeHeader->SetContentSubTypeL(KImcvOctetStream);
       
  3219 			}
       
  3220 		else
       
  3221 		if(MatchAndRemoveToken(KImcvExe))
       
  3222 			{
       
  3223 			iMimeHeader->SetContentSubTypeL(KImcvExe);
       
  3224 			}
       
  3225 		else
       
  3226 		if(MatchAndRemoveToken(KImcvCmd))
       
  3227 			{
       
  3228 			iMimeHeader->SetContentSubTypeL(KImcvCmd);
       
  3229 			}
       
  3230 		}
       
  3231 	}
       
  3232 
       
  3233 //----------------------------------------------------------------------------------------
       
  3234 void CMimeParser::DoMessageTypeL()
       
  3235 //----------------------------------------------------------------------------------------
       
  3236 	{
       
  3237 	iImRecvConvert.iEntryType = CImRecvConvert::EMessageEntry;
       
  3238 	iImRecvConvert.iEmailPart = CImRecvConvert::KParentPart;
       
  3239 	
       
  3240 	iContentType=EMimeMessage; 
       
  3241 	iMimeHeader->SetContentTypeL(KImcvMessage);
       
  3242 
       
  3243 	if(MatchAndRemoveToken(KImcvForwardSlash))
       
  3244 		{
       
  3245 		if(MatchAndRemoveToken(KImcvRfc822))
       
  3246 			{
       
  3247 			//iMessageFolderType=EFolderTypeRFC822;
       
  3248 			iMimeHeader->SetContentSubTypeL(KImcvRfc822);
       
  3249 			}
       
  3250 		else if(MatchAndRemoveToken(KImcvExternal))
       
  3251 			{
       
  3252 			iMessageFolderType=EFolderTypeExternal;
       
  3253 			iMimeHeader->SetContentSubTypeL(KImcvExternal);
       
  3254 			}
       
  3255 		else if(MatchAndRemoveToken(KImcvPartial))
       
  3256 			{
       
  3257 			iMessageFolderType=EFolderTypePartial;
       
  3258 			iMimeHeader->SetContentSubTypeL(KImcvPartial);
       
  3259 			}
       
  3260 		else if(MatchAndRemoveToken(KImcvDeliveryStatus))
       
  3261 			{
       
  3262 			// We do not process this part. So store as text.
       
  3263 			iMimeHeader->SetContentSubTypeL(KImcvDeliveryStatus);
       
  3264 			iImRecvConvert.iEntryType = CImRecvConvert::EAttachmentEntry;
       
  3265 			iImRecvConvert.iEmailPart = CImRecvConvert::KNoPart;
       
  3266 			iContentType=EMimeUnknownContent; 
       
  3267 			iImRecvConvert.iCurrentPartIsRichText=EFalse;
       
  3268 			iImRecvConvert.iAttachmentName.Copy(KImcvDeliveryStatus);
       
  3269 			iImRecvConvert.iAttachmentName.Append(KTextExtension);
       
  3270 			}
       
  3271 		else
       
  3272 			{
       
  3273 			iMessageFolderType=EFolderTypeUnknown;
       
  3274 			iMimeHeader->SetContentSubTypeL(KImcvUnknown);
       
  3275 			}
       
  3276 		}	
       
  3277 	}
       
  3278 
       
  3279 
       
  3280 //----------------------------------------------------------------------------------------
       
  3281 void CMimeParser::DoMultipartTypeForNonMIMEL()
       
  3282 //----------------------------------------------------------------------------------------
       
  3283 	{
       
  3284 	ResetForNewEntry();
       
  3285 	iMessageFolderType=EFolderTypeMixed;
       
  3286 	iMimeHeader->SetContentTypeL(KImcvMultipart);
       
  3287 	iMimeHeader->SetContentSubTypeL(KImcvMixed);
       
  3288 	}
       
  3289 
       
  3290 
       
  3291 //----------------------------------------------------------------------------------------
       
  3292 void CMimeParser::DoMultipartTypeL()
       
  3293 //----------------------------------------------------------------------------------------
       
  3294 	{
       
  3295 	iImRecvConvert.iEntryType = CImRecvConvert::EFolderEntry;
       
  3296 	iImRecvConvert.iEmailPart = CImRecvConvert::KMultiPart;
       
  3297 	
       
  3298 	iContentType=EMimeMultipart;
       
  3299 	iMimeHeader->SetContentTypeL(KImcvMultipart);
       
  3300 	if(MatchAndRemoveToken(KImcvForwardSlash))
       
  3301 		{
       
  3302 		if(MatchAndRemoveToken(KImcvMixed))
       
  3303 			{
       
  3304 			iMessageFolderType=EFolderTypeMixed;
       
  3305 			iMimeHeader->SetContentSubTypeL(KImcvMixed);
       
  3306 			}
       
  3307 		else if(MatchAndRemoveToken(KImcvRelated))
       
  3308 			{
       
  3309 			iMessageFolderType=EFolderTypeRelated;
       
  3310 			iMimeHeader->SetContentSubTypeL(KImcvRelated);
       
  3311 			}
       
  3312 		else if(MatchAndRemoveToken(KImcvAlternative))
       
  3313 			{
       
  3314 			iMessageFolderType=EFolderTypeAlternative;
       
  3315 			iMimeHeader->SetContentSubTypeL(KImcvAlternative);
       
  3316 			}
       
  3317 		else if(MatchAndRemoveToken(KImcvEncrypted))
       
  3318 			{
       
  3319 //	Add this when Encryption is handled iMessageFolderType=EFolderTypeEncrypted;
       
  3320 			iMimeHeader->SetContentSubTypeL(KImcvEncrypted);
       
  3321 			}
       
  3322 		else if(MatchAndRemoveToken(KImcvParallel))
       
  3323 			{
       
  3324 			iMessageFolderType=EFolderTypeParallel;
       
  3325 			iMimeHeader->SetContentSubTypeL(KImcvParallel);
       
  3326 			}
       
  3327 		else if(MatchAndRemoveToken(KImcvDigest))
       
  3328 			{
       
  3329 			iMessageFolderType=EFolderTypeDigest;
       
  3330 			iMimeHeader->SetContentSubTypeL(KImcvDigest);
       
  3331 			isMessageDigest=ETrue;
       
  3332 			}
       
  3333 		else if(MatchAndRemoveToken(KImcvSigned))
       
  3334 			{
       
  3335 //	Add this when Signed is handled	iMessageFolderType=EFolderTypeSigned;
       
  3336 			iMimeHeader->SetContentSubTypeL(KImcvSigned);
       
  3337 			}
       
  3338 		else if(MatchAndRemoveToken(KImcvReport))
       
  3339 			{
       
  3340 			iMimeHeader->SetContentSubTypeL(KImcvReport);
       
  3341 			}
       
  3342 		else
       
  3343 			{
       
  3344 			iMessageFolderType=EFolderTypeUnknown;
       
  3345 			iMimeHeader->SetContentSubTypeL(KImcvUnknown);
       
  3346 			}
       
  3347 		}
       
  3348 
       
  3349 	if (iMessageFolderType==EFolderTypeRelated)
       
  3350 		iImRecvConvert.iParent->At(0).iFolder=iMessageFolderType; 
       
  3351 
       
  3352 	// Find any parameters specific to a Multipart content type	
       
  3353 
       
  3354 	HBufC8* paramValue = NULL;
       
  3355 
       
  3356 	// Extracts the boundary string
       
  3357 	ExtractParameterInfoL(KImcvBoundary, paramValue);
       
  3358 	if( paramValue!=NULL ) 
       
  3359 		{
       
  3360 		CleanupStack::PushL(paramValue);
       
  3361 		iBoundaryFound = ETrue;
       
  3362 		iImRecvConvert.iEmailPart = CImRecvConvert::KMultiPart;
       
  3363 		SetBoundaryL(*paramValue);
       
  3364 		CleanupStack::PopAndDestroy(paramValue);
       
  3365 		}
       
  3366 
       
  3367 	// Extracts start ID if it has been defined;
       
  3368 	ExtractParameterInfoL(KImcvStartPart, paramValue);
       
  3369 	if( paramValue!=NULL )
       
  3370 		{
       
  3371 		delete iStartId;
       
  3372 		iStartId = paramValue;
       
  3373 		}
       
  3374 	}
       
  3375 
       
  3376 //----------------------------------------------------------------------------------------
       
  3377 void CMimeParser::DoTextTypeL()
       
  3378 //----------------------------------------------------------------------------------------
       
  3379 	{
       
  3380 	HBufC8* paramValue = NULL;
       
  3381 	
       
  3382 	iImRecvConvert.iEntryType = CImRecvConvert::ETextEntry;
       
  3383 	iContentType=EMimeText;
       
  3384 	iMimeHeader->SetContentTypeL(KImcvText);
       
  3385 
       
  3386 	if(MatchAndRemoveToken(KImcvForwardSlash))
       
  3387 		{
       
  3388 		if(MatchAndRemoveToken(KImcvPlain))
       
  3389 			{
       
  3390 			iMimeHeader->SetContentSubTypeL(KImcvPlain);
       
  3391 			}
       
  3392 		else if(MatchAndRemoveToken(KImcvRtf))
       
  3393 			{
       
  3394 			iMimeHeader->SetContentSubTypeL(KImcvRtf);
       
  3395 			iImRecvConvert.iEntryType = CImRecvConvert::ERtfEntry;
       
  3396 			iImRecvConvert.iCurrentPartIsRichText = EFalse;
       
  3397 			}
       
  3398 		else if(MatchAndRemoveToken(KImcvHtml))
       
  3399 			{
       
  3400 			iMimeHeader->SetContentSubTypeL(KImcvHtml);
       
  3401 			iImRecvConvert.iEntryType = CImRecvConvert::EHtmlEntry;
       
  3402 			iImRecvConvert.iCurrentPartIsRichText = EFalse;	
       
  3403 			}
       
  3404 		else if(MatchAndRemoveToken(KImcvDirectory))
       
  3405 			{
       
  3406 			iMimeHeader->SetContentSubTypeL(KImcvDirectory);
       
  3407 			iMimeHeader->ContentTypeParams().AppendL(KImcvProfile);
       
  3408 			ExtractParameterInfoL(KImcvProfile, paramValue);
       
  3409 			// Assume at right context, the email message, not attachment.
       
  3410 			iMessageFolderType=EFolderTypeDirectory;
       
  3411 			if( paramValue!=NULL )
       
  3412 				{
       
  3413 				CleanupStack::PushL(paramValue);
       
  3414 				iMimeHeader->ContentTypeParams().AppendL(*paramValue);
       
  3415 				if(paramValue->MatchF(KImcvVCard) == 0)
       
  3416 					{
       
  3417 					iVCard=ETrue;
       
  3418 					}
       
  3419 				CleanupStack::PopAndDestroy(paramValue);
       
  3420 				}
       
  3421 			}
       
  3422 		else if(MatchAndRemoveToken(KImcvXVCard))
       
  3423 			{
       
  3424 			iMimeHeader->SetContentSubTypeL(KImcvXVCard);
       
  3425 			iVCard=ETrue;
       
  3426 			}		
       
  3427 		else if(MatchAndRemoveToken(KImcvVCalender))
       
  3428 			{
       
  3429 			iMimeHeader->SetContentSubTypeL(KImcvVCalender);
       
  3430 			iVCalendar=ETrue;
       
  3431 			}	
       
  3432 		else if(MatchAndRemoveToken(KImcvICalendar))
       
  3433 			{
       
  3434 			iMimeHeader->SetContentSubTypeL(KImcvICalendar);
       
  3435 			
       
  3436 			// Get the method value
       
  3437 			ExtractParameterInfoL(KImcvICalendarMethod, paramValue);
       
  3438 			if (paramValue!=NULL)
       
  3439 				{
       
  3440 				CleanupStack::PushL(paramValue);
       
  3441 				iMimeHeader->ContentTypeParams().AppendL(KImcvICalendarMethod);
       
  3442 				iMimeHeader->ContentTypeParams().AppendL(*paramValue);
       
  3443 				CleanupStack::PopAndDestroy(paramValue);
       
  3444 				}
       
  3445 			// Get the component value
       
  3446 			ExtractParameterInfoL(KImcvICalendarComponent, paramValue);
       
  3447 			if (paramValue!=NULL)
       
  3448 				{
       
  3449 				CleanupStack::PushL(paramValue);
       
  3450 				iMimeHeader->ContentTypeParams().AppendL(KImcvICalendarComponent);
       
  3451 				iMimeHeader->ContentTypeParams().AppendL(*paramValue);
       
  3452 				CleanupStack::PopAndDestroy(paramValue);
       
  3453 				}
       
  3454 			iICalendar=ETrue;
       
  3455 			}
       
  3456 
       
  3457 		// Extract the charset value, 
       
  3458 		ExtractParameterInfoL(KImcvCharset, paramValue);
       
  3459 		if(paramValue!=NULL)
       
  3460 			{
       
  3461 			CleanupStack::PushL(paramValue);
       
  3462 			
       
  3463 			// check if at top level header or Mime part header
       
  3464 			TUint charsetUid = iImRecvConvert.CharacterConverter().GetMimeCharsetUidL(*paramValue); 
       
  3465 			if(iImRecvConvert.NotFinishedRfc822Header() == EFalse)
       
  3466 				iCharset=charsetUid;
       
  3467 
       
  3468 			// Store in CMimeHeader::iContentTypeParams
       
  3469 			iMimeHeader->ContentTypeParams().AppendL(KImcvCharset);
       
  3470 			iMimeHeader->ContentTypeParams().AppendL(*paramValue);
       
  3471 			CleanupStack::PopAndDestroy(paramValue);
       
  3472 			
       
  3473 			if (!iImRecvConvert.CharacterConverter().PrepareToConvertToFromOurCharsetL(charsetUid))
       
  3474 				charsetUid=KUidMsvCharsetNone;
       
  3475 			iMimeHeader->SetMimeCharset(charsetUid);
       
  3476 			}
       
  3477 		else
       
  3478 			{
       
  3479 			iMimeHeader->SetMimeCharset(iDefaultCharset);
       
  3480 			}
       
  3481 		}
       
  3482 	}
       
  3483 
       
  3484 //----------------------------------------------------------------------------------------
       
  3485 void CMimeParser::DoContentTypeL()
       
  3486 //----------------------------------------------------------------------------------------
       
  3487 	{
       
  3488 	RemoveSurroundingCharacters(KImcvLeftChevron, KImcvRightChevron, *iMimeHeaderLine);
       
  3489 
       
  3490 	if(MatchAndRemoveToken(KImcvText))
       
  3491 		{
       
  3492 		DoTextTypeL();
       
  3493 		}
       
  3494 	else if(MatchAndRemoveToken(KImcvMultipart))
       
  3495 		{
       
  3496 		DoMultipartTypeL();
       
  3497 		}
       
  3498 	else if(MatchAndRemoveToken(KImcvMessage))
       
  3499 		{
       
  3500 		DoMessageTypeL();
       
  3501 		}
       
  3502 	else if(MatchAndRemoveToken(KImcvImage))
       
  3503 		{	
       
  3504 		iContentType=EMimeImage; 
       
  3505 		iMimeHeader->SetContentTypeL(KImcvImage);
       
  3506 		DoAttachmentTypeL();
       
  3507 		}
       
  3508 	else if(MatchAndRemoveToken(KImcvApplication))
       
  3509 		{
       
  3510 		iContentType=EMimeApplication; 
       
  3511 		iMimeHeader->SetContentTypeL(KImcvApplication);
       
  3512 		DoAttachmentTypeL();
       
  3513 		}
       
  3514 	else if(MatchAndRemoveToken(KImcvAudio))
       
  3515 		{
       
  3516 		iContentType=EMimeAudio; 
       
  3517 		iMimeHeader->SetContentTypeL(KImcvAudio);
       
  3518 		DoAttachmentTypeL();
       
  3519 		}
       
  3520 	else if(MatchAndRemoveToken(KImcvVideo))
       
  3521 		{
       
  3522 		iContentType=EMimeVideo; 
       
  3523 		iMimeHeader->SetContentTypeL(KImcvVideo);
       
  3524 		DoAttachmentTypeL();
       
  3525 		}
       
  3526 	else
       
  3527 		{
       
  3528 		iContentType=EMimeUnknownContent; 
       
  3529 		iMimeHeader->SetContentTypeL(KImcvUnknown);
       
  3530 		}
       
  3531 
       
  3532 	// Extract the filename if it exists
       
  3533 	HBufC* paramStore = HBufC::NewLC(MaxMimeParameterValueLength);
       
  3534 	HBufC8* paramStore8 = NULL;
       
  3535 	TPtr paramValue(paramStore->Des());
       
  3536 	ExtractParameterInfoL(KImcvMimeTypeName, paramValue,paramStore8);
       
  3537 	CleanupStack::PushL(paramStore8);
       
  3538 	if(paramValue.Length())
       
  3539 		{
       
  3540 		iMimeHeader->ContentTypeParams().AppendL(KImcvMimeTypeName);
       
  3541 		TPtr8 paramValue8(paramStore8->Des());
       
  3542 		iMimeHeader->ContentTypeParams().AppendL(paramValue8);
       
  3543 		iImRecvConvert.SetAttachmentName(paramValue);
       
  3544 		}
       
  3545 	
       
  3546 	CleanupStack::PopAndDestroy(2,paramStore); 
       
  3547 	}
       
  3548 
       
  3549 //----------------------------------------------------------------------------------------
       
  3550 void CMimeParser::DoEncodingL()
       
  3551 //----------------------------------------------------------------------------------------
       
  3552 	{
       
  3553 	// Some servers will specify the content transfer encoding field, but leave
       
  3554 	// it's value blank. Check for this, and default to 7 bit if this happens.
       
  3555 	if ((*iMimeHeaderLine).Length() == 0)
       
  3556 		{
       
  3557 		iMimeHeader->SetContentTransferEncodingL(KMiut7BitString);
       
  3558 		iContentEncoding = EEncodingType7Bit;
       
  3559 		return;
       
  3560 		}
       
  3561 
       
  3562 	iMimeHeader->SetContentTransferEncodingL(*iMimeHeaderLine);
       
  3563 	switch ((*iMimeHeaderLine)[0])
       
  3564 		{
       
  3565 		case '7': // 7bit
       
  3566 			iContentEncoding = EEncodingType7Bit;
       
  3567 			break;
       
  3568 		case '8': // 8bit
       
  3569 			iContentEncoding = EEncodingType8Bit;
       
  3570 			break;
       
  3571 		case 'q': // quoted-printable
       
  3572 		case 'Q': 
       
  3573 			iContentEncoding = EEncodingTypeQP;
       
  3574 			break;
       
  3575 		case 'b': // binary or base64
       
  3576 		case 'B':
       
  3577 			if ((*iMimeHeaderLine).Length() <2)
       
  3578 				return;
       
  3579 			iContentEncoding = ((*iMimeHeaderLine)[1] == 'i' || (*iMimeHeaderLine)[1] == 'I' ? EEncodingTypeBinary : EEncodingTypeBASE64);
       
  3580 			break;
       
  3581 		case 'x': //in order to support UU encoded within a MIME message
       
  3582 		case 'X':
       
  3583 			iContentEncoding = ((*iMimeHeaderLine).FindF(KImcvXUUString)==KErrNotFound ? EEncodingTypeUnknown : EEncodingTypeUU);
       
  3584 			break;
       
  3585 		default:
       
  3586 			iContentEncoding = EEncodingTypeUnknown;
       
  3587 			break;
       
  3588 		}
       
  3589 	}
       
  3590 
       
  3591 //----------------------------------------------------------------------------------------
       
  3592 void CMimeParser::DoDescriptionL()
       
  3593 //----------------------------------------------------------------------------------------
       
  3594 	{
       
  3595 	TPtrC8 marked(iMimeHeaderLine->Des());
       
  3596 	if (marked.Length()>KMaxFileName)
       
  3597 		marked.Set(marked.Left(KMaxFileName));
       
  3598 
       
  3599 	iContentDescription.Copy(marked);
       
  3600 
       
  3601 	// remove the CRLF
       
  3602 
       
  3603 	TInt length = iContentDescription.Length();
       
  3604 	if (length>2)
       
  3605 		{
       
  3606 		if (iContentDescription[length-2]==KImcvCR && iContentDescription[length-1]==KImcvLF)
       
  3607 			iContentDescription.SetLength(length-2);
       
  3608 		}
       
  3609 	iMimeHeader->SetContentDescriptionL(marked);
       
  3610 	}
       
  3611 
       
  3612 //----------------------------------------------------------------------------------------
       
  3613 void CMimeParser::DoDispositionL()
       
  3614 //----------------------------------------------------------------------------------------
       
  3615 	{
       
  3616 	TBool inLine = EFalse;
       
  3617 	if(MatchAndRemoveToken(KImcvAttachment))
       
  3618 		{
       
  3619 		iMimeHeader->SetContentDispositionL(KImcvAttachment);
       
  3620 		if (iMimeHeader->ContentSubType()!=KImcvRfc822)
       
  3621 			{
       
  3622 			iImRecvConvert.iCurrentPartIsRichText = EFalse;	
       
  3623 			}
       
  3624 		if (iImRecvConvert.iEntryType!=CImRecvConvert::EMessageEntry)
       
  3625 			{
       
  3626 			iImRecvConvert.iEntryType = CImRecvConvert::EAttachmentEntry;
       
  3627 			}
       
  3628 		}
       
  3629 	else if(MatchAndRemoveToken(KImcvInline))
       
  3630 		inLine = ETrue;
       
  3631 
       
  3632 	// Extract the filename if it exists, unless we already have a name for it	
       
  3633 	if(!iImRecvConvert.iAttachmentName.Length())
       
  3634 		{
       
  3635 		HBufC* paramStore = HBufC::NewLC(KHeaderBufferLength);
       
  3636 		TPtr paramValue(paramStore->Des());
       
  3637 		HBufC8* paramStore8 = NULL;
       
  3638 		ExtractParameterInfoL(KImcvMimeDispositionFilename, paramValue,paramStore8);
       
  3639 		CleanupStack::PushL(paramStore8);
       
  3640 		if(paramValue.Length())
       
  3641 			{
       
  3642 			iMimeHeader->ContentTypeParams().AppendL(KImcvMimeDispositionFilename);
       
  3643 			TPtr8 paramValue8(paramStore8->Des());
       
  3644 			iMimeHeader->ContentTypeParams().AppendL(paramValue8);
       
  3645 			iImRecvConvert.SetAttachmentName(paramValue);
       
  3646 			}
       
  3647 
       
  3648 		CleanupStack::PopAndDestroy(2,paramStore); // paramStore, paramStore8
       
  3649 		}
       
  3650 
       
  3651 		if(inLine)
       
  3652  		{
       
  3653  		// Content Disposition set to inline
       
  3654  		if (iImRecvConvert.iAttachmentName.Length())
       
  3655  			// filename exists
       
  3656  			{
       
  3657  			iMimeHeader->SetContentDispositionL(KImcvAttachment);
       
  3658 
       
  3659 			if (iMimeHeader->ContentSubType()!=KImcvRfc822)
       
  3660 				{
       
  3661 				iImRecvConvert.iCurrentPartIsRichText = EFalse;	
       
  3662 				}
       
  3663 			if (iImRecvConvert.iEntryType!=CImRecvConvert::EMessageEntry)
       
  3664  				{
       
  3665  				iImRecvConvert.iEntryType = CImRecvConvert::EAttachmentEntry;
       
  3666  				}
       
  3667  			}
       
  3668  		else
       
  3669  			iMimeHeader->SetContentDispositionL(KImcvInline);
       
  3670 		}
       
  3671 	}
       
  3672 
       
  3673 //----------------------------------------------------------------------------------------  
       
  3674 TPtrC8 CMimeParser::ContentSubType() const
       
  3675 //----------------------------------------------------------------------------------------  
       
  3676 	{
       
  3677 	return iMimeHeader->ContentSubType();
       
  3678 	}
       
  3679 
       
  3680 //----------------------------------------------------------------------------------------  
       
  3681 TPtrC8 CMimeParser::ContentTypeDescription() const
       
  3682 //----------------------------------------------------------------------------------------  
       
  3683 	{
       
  3684 	return iMimeHeader->ContentType();
       
  3685 	}
       
  3686 
       
  3687 //----------------------------------------------------------------------------------------  
       
  3688 TBool CMimeParser::VCard() const
       
  3689 //----------------------------------------------------------------------------------------  
       
  3690 	{
       
  3691 	return iVCard;
       
  3692 	}
       
  3693 
       
  3694 //----------------------------------------------------------------------------------------  
       
  3695 TBool CMimeParser::VCalendar() const
       
  3696 //----------------------------------------------------------------------------------------  	
       
  3697 	{
       
  3698 	return iVCalendar;
       
  3699 	}
       
  3700 	
       
  3701 //----------------------------------------------------------------------------------------  
       
  3702 TBool CMimeParser::ICalendar() const
       
  3703 //----------------------------------------------------------------------------------------  	
       
  3704 	{
       
  3705 	return iICalendar;
       
  3706 	}
       
  3707 
       
  3708 //----------------------------------------------------------------------------------------  
       
  3709 TBool CMimeParser::StartPart() const
       
  3710 //----------------------------------------------------------------------------------------  
       
  3711 	{
       
  3712 	return iStartPart;
       
  3713 	}
       
  3714 
       
  3715 //----------------------------------------------------------------------------------------  
       
  3716 TImEmailFolderType CMimeParser::MessageFolderType() const
       
  3717 //----------------------------------------------------------------------------------------  
       
  3718 	{
       
  3719 	return iMessageFolderType;
       
  3720 	}
       
  3721 
       
  3722 //----------------------------------------------------------------------------------------  
       
  3723 void CMimeParser::SetMessageFolderType(TImEmailFolderType aFolderType)
       
  3724 //----------------------------------------------------------------------------------------  
       
  3725 	{
       
  3726 	iMessageFolderType=aFolderType;
       
  3727 	}
       
  3728 
       
  3729 //----------------------------------------------------------------------------------------  
       
  3730 void CMimeParser::SetBoundaryL(const TDesC8& aBoundaryText)
       
  3731 //----------------------------------------------------------------------------------------  
       
  3732 	{
       
  3733 	TBuf8<KMaxBoundaryTextLength+2> tempBoundary(KImcvMimeBoundaryStartEnd);
       
  3734 // From RFC 1521, (Boundaries) must be no longer than 70 characters.
       
  3735 // Including beginning and end "--" 
       
  3736 	if (aBoundaryText.Length()>70)
       
  3737 		tempBoundary.Append(aBoundaryText.Left(70));
       
  3738 	else
       
  3739 		tempBoundary.Append(aBoundaryText);
       
  3740 	iBoundaryText->AppendL(tempBoundary);
       
  3741 
       
  3742 	iBoundaryIndex = iBoundaryText->MdcaCount(); //iBoundaryIndex stores a count value not the index here
       
  3743 	iBoundaryIndex = ((iBoundaryIndex > 0)? (iBoundaryIndex-1): 0);
       
  3744 	iBoundaryLength = iBoundaryText->MdcaPoint(iBoundaryIndex).Length();
       
  3745 	}
       
  3746 
       
  3747 //----------------------------------------------------------------------------------------
       
  3748 TBool CMimeParser::IsBoundary(const TDesC8& aSourceLine)
       
  3749 //----------------------------------------------------------------------------------------
       
  3750 	{
       
  3751 	if(iBoundaryText->MdcaCount())
       
  3752 		{
       
  3753 		TInt found = 0;
       
  3754 		TInt aLineLength = aSourceLine.Length();
       
  3755 		TInt compareLength = aLineLength > iBoundaryLength ? iBoundaryLength : aLineLength;
       
  3756 		
       
  3757 		if (aLineLength > 3) 
       
  3758 			{ 
       
  3759 			// To Handle cases when server sends clipped version of mails which does not have closing 
       
  3760 			// boundary.. 
       
  3761 			if (aSourceLine[aLineLength-4] == KImcvHyphen && aSourceLine[aLineLength-3] == KImcvHyphen) 
       
  3762 				{ 
       
  3763 				compareLength =aLineLength-4; 
       
  3764 				}    
       
  3765 			} 
       
  3766 			
       
  3767 		TPtrC8 tempSourceLine(aSourceLine.Ptr(), compareLength);
       
  3768 	
       
  3769 		TInt error = iBoundaryText->Find(tempSourceLine, found, ECmpNormal);
       
  3770 
       
  3771 		if(error||(!iBoundaryLength))
       
  3772 			return KBoundaryNotFound;
       
  3773 	
       
  3774 		// The following code is executed only if aSourceLine is a boundary
       
  3775 		if(found!=iBoundaryIndex)
       
  3776 			{
       
  3777 			iReceiveError = (iReceiveError)? iReceiveError: KBoundaryError;
       
  3778 			iBoundaryIndex = found;
       
  3779 			iBoundaryText->Delete(found++);
       
  3780 			}
       
  3781 	
       
  3782 		if(aLineLength >= compareLength+4) // allow for CRLF & then check for the double hyphen
       
  3783 			{
       
  3784 			if((aSourceLine[compareLength] == KImcvHyphen) && (aSourceLine[compareLength+1] == KImcvHyphen))
       
  3785 				iTerminatingBoundary = ETrue; // this is a terminating boundary
       
  3786 			}
       
  3787 		else
       
  3788 			iTerminatingBoundary = EFalse;
       
  3789 	
       
  3790 		return KBoundaryFound;
       
  3791 		}
       
  3792 	
       
  3793 	return KBoundaryNotFound;
       
  3794 	}
       
  3795 
       
  3796 //----------------------------------------------------------------------------------------
       
  3797 void CMimeParser::RemoveBoundary()
       
  3798 //----------------------------------------------------------------------------------------
       
  3799 	{
       
  3800 	iBoundaryText->Delete(iBoundaryIndex);
       
  3801 	if(iBoundaryText->MdcaCount())
       
  3802 		{
       
  3803 		iBoundaryIndex = iBoundaryText->MdcaCount(); //iBoundaryIndex stores a count value not the index here
       
  3804 	
       
  3805 		iBoundaryIndex = ((iBoundaryIndex > 0)? (iBoundaryIndex-1): 0);
       
  3806 		iBoundaryLength = iBoundaryText->MdcaPoint(iBoundaryIndex).Length();
       
  3807 		}
       
  3808 	}
       
  3809 
       
  3810 //----------------------------------------------------------------------------------------
       
  3811 TBool CMimeParser::MatchAndRemoveToken( const TDesC8& aToken )
       
  3812 //----------------------------------------------------------------------------------------
       
  3813 	{
       
  3814 	TInt comparison;
       
  3815 	TInt tokenLength = aToken.Length();
       
  3816 	TInt desLength = (*iMimeHeaderLine).Length();
       
  3817 	TInt compareLength = tokenLength > desLength ? desLength : tokenLength;
       
  3818 	TPtrC8 left((*iMimeHeaderLine).Left(compareLength));
       
  3819 	
       
  3820 	// now see whether the current line contains the search string
       
  3821 	comparison = left.CompareF(aToken);
       
  3822 	if (!comparison)
       
  3823 		{
       
  3824 		// found the match string at the start of the output line, so remove it
       
  3825 		iMimeFieldsExist=ETrue;
       
  3826 		isMime=ETrue;
       
  3827 		// get rid of any whitespace betweebn the tag and the data while we have a chance
       
  3828 		TInt whitespaceLength=0;
       
  3829 		TInt maxLength=desLength-tokenLength;
       
  3830 		const TUint8* ptr = (*iMimeHeaderLine).Ptr();
       
  3831 		while ( whitespaceLength <= maxLength && (ptr[tokenLength+whitespaceLength] == KImcvSP || ptr[tokenLength+whitespaceLength] == KImcvTab) )
       
  3832 			whitespaceLength++;
       
  3833 		iMimeHeaderLine->Des().Delete(0, tokenLength+whitespaceLength);
       
  3834 
       
  3835 		// Reset iLex, so its length is updated.
       
  3836 		iLex = *iMimeHeaderLine;
       
  3837 		}
       
  3838 	return (comparison==0);
       
  3839 	}
       
  3840 
       
  3841 //----------------------------------------------------------------------------------------
       
  3842 TBool CMimeParser::IsSpecialChar( const TUint8 aChar )
       
  3843 //----------------------------------------------------------------------------------------
       
  3844 	{
       
  3845 	return (aChar == '(' || aChar == ')' || aChar == '<' || aChar == '>' || aChar == '@' 
       
  3846 		 || aChar == ',' || aChar == ';' || aChar == ':' || aChar == '\\'|| aChar == '"' 
       
  3847 		 || aChar == '/' || aChar == '[' || aChar == ']' || aChar == '?' || aChar == '=');
       
  3848 	}
       
  3849 
       
  3850 
       
  3851 
       
  3852 // Implicitly the parameter ASSUMED TO BE is not encoded as return parameter, rBuffer, 
       
  3853 // is 8 bit. iLex should currently be pointing at the space after content-type description.
       
  3854 //----------------------------------------------------------------------------------------
       
  3855 void CMimeParser::ExtractParameterInfoL(const TDesC8& aTag, HBufC8*& rBuffer)
       
  3856 //----------------------------------------------------------------------------------------
       
  3857 	{	
       
  3858 	rBuffer = NULL;
       
  3859 
       
  3860 	TLexMark8 mark;
       
  3861 	TInt offset;	
       
  3862 					
       
  3863 	// Workaround due to this method not being able to 
       
  3864 	// correctly handle multiple content-type parameters			
       
  3865 	iLex = *iMimeHeaderLine;
       
  3866 								
       
  3867 	if( (offset=iLex.Remainder().FindF(aTag)) != KErrNotFound )
       
  3868 		{
       
  3869 		// move past the tag	
       
  3870 		iLex.Inc(offset+aTag.Length());
       
  3871 
       
  3872 		// Default : no charset info or folding
       
  3873 		// move forward to the start of the boundary string itself.
       
  3874 
       
  3875 		while (iLex.Peek() != KImcvEquals  && !iLex.Eos())
       
  3876 			iLex.Inc(); 
       
  3877 
       
  3878 		TPtrC8 paramBuffer(ExtractParameterString(mark));
       
  3879 		if( paramBuffer.Length() > 0 )
       
  3880 			{
       
  3881 			rBuffer = paramBuffer.AllocL();
       
  3882 			}
       
  3883 		}
       
  3884 	}
       
  3885 
       
  3886 /**
       
  3887 Searches the passed parameter list for the specified attribute.
       
  3888  
       
  3889 @param aTag    The name of the attribute to be found
       
  3890 @param aParameterList The string to be searched
       
  3891 @return    TInt   The offset of the data sequence for the first attribute matching aTag
       
  3892 		from the beginning of the passed parameter list data
       
  3893 	    KErrNotFound, if the data sequence cannot be found.
       
  3894 	     Zero, if the length of the search data sequence is zero	 
       
  3895 */
       
  3896 TInt  CMimeParser::FindAttribute(const TDesC8& aTag,const TDesC8& aParameterList)
       
  3897 	{
       
  3898 	TInt offset = KErrNone;
       
  3899 	TInt cumulativeOffset= 0;
       
  3900 	TInt tagLength=aTag.Length();
       
  3901 	TInt aParameterListLength =aParameterList.Length();
       
  3902 	     
       
  3903 	while( offset!= KErrNotFound)	
       
  3904 		{
       
  3905 	   	offset = aParameterList.Mid(cumulativeOffset).FindF(aTag);	  
       
  3906 		if (offset != KErrNotFound)
       
  3907 			{
       
  3908 			// Matching string found - check that it is the correct syntax for an attribute
       
  3909 			// according to RFC2045 and RFC2231
       
  3910 
       
  3911 			// Increment cumulativeOffset - indicates the start of this instance of aTag
       
  3912 			cumulativeOffset+=offset;
       
  3913 
       
  3914 			TBool preCharValid = EFalse;			
       
  3915 
       
  3916 			// Check the preceeding character is OK. 
       
  3917 			// Note that test for cumulativeOffset==0 must be 1st OR'd condition
       
  3918 			if (cumulativeOffset==0 ||  
       
  3919 			 aParameterList[(cumulativeOffset)-1]  == KImcvTab || 
       
  3920 			 aParameterList[(cumulativeOffset)-1]  == KImcvSemiColon || 
       
  3921 			 aParameterList[(cumulativeOffset)-1] == KImcvSP || 
       
  3922 			 aParameterList[(cumulativeOffset)-1] == KImcvCR ||  
       
  3923 			 aParameterList[(cumulativeOffset)-1] == KImcvLF )
       
  3924 				{
       
  3925 				preCharValid = ETrue;
       
  3926 				}
       
  3927 				
       
  3928 			// Check following character is OK
       
  3929 			// Note boundary check must be before character checks
       
  3930 			if ( (preCharValid) &&
       
  3931 			 ((cumulativeOffset+tagLength) < aParameterListLength) &&
       
  3932 			 (( aParameterList[cumulativeOffset+tagLength] == KImcvAny) ||    
       
  3933 			 (aParameterList[cumulativeOffset+tagLength] == KImcvEquals  )))
       
  3934 				{
       
  3935 				// Match found - return the offset into the original string
       
  3936 				return cumulativeOffset;
       
  3937 				}
       
  3938 			else
       
  3939 				{
       
  3940 				// update cumulativeOffset to indicate end of invalid aTag match.
       
  3941 				cumulativeOffset += tagLength;
       
  3942 				}
       
  3943 			}
       
  3944 		}		
       
  3945 
       
  3946 	// no match found
       
  3947 	return KErrNotFound;
       
  3948    	}
       
  3949 
       
  3950 
       
  3951 // iLex should currently be pointing at the space after content-type description.
       
  3952 //----------------------------------------------------------------------------------------
       
  3953 void CMimeParser::ExtractParameterInfoL(const TDesC8& aTag, TDes16& rBuffer, HBufC8*& rBuffer8)
       
  3954 //----------------------------------------------------------------------------------------
       
  3955 	{
       
  3956 	TInt offset;
       
  3957 	
       
  3958 	rBuffer.Copy(KNullDesC);
       
  3959 	
       
  3960 	// we need to extract the <aTag> text from the same line
       
  3961 	// iLex should currently be pointing at the space after content-type description
       
  3962 	if( (offset=FindAttribute(aTag,iLex.Remainder()))!=KErrNotFound )
       
  3963 		{
       
  3964 		// Check which type of encoding present.
       
  3965 		TLexMark8 initMark;
       
  3966 		iLex.Mark(initMark);
       
  3967 		TLexMark8 mark;
       
  3968 		iLex.Inc(offset+aTag.Length()); 	// move past the tag
       
  3969 		const TPtrC8 param = ExtractParameterString(mark);
       
  3970 		if( param.Length() > 0 )
       
  3971 			{
       
  3972 			rBuffer8 = param.AllocLC();
       
  3973 			}
       
  3974 		if ( ParseRfc2047ParameterInfoL(param, rBuffer) == EFalse )
       
  3975 			{
       
  3976 			iLex.UnGetToMark(initMark);
       
  3977 			ParseRfc2231ParameterInfoL(aTag, rBuffer, offset );
       
  3978 			}
       
  3979 			CleanupStack::Pop(rBuffer8);
       
  3980 		}
       
  3981 	}
       
  3982 
       
  3983 
       
  3984 // Detect encoding of form =?charset?Q?" Text "?=
       
  3985 //----------------------------------------------------------------------------------------
       
  3986 TBool CMimeParser::ParseRfc2047ParameterInfoL(const TDesC8& aParam, TDes& rBuffer)
       
  3987 //----------------------------------------------------------------------------------------
       
  3988 	{
       
  3989 	TBool parameterPresent = EFalse;
       
  3990 
       
  3991 	// Check for =? somewhere in text.
       
  3992 
       
  3993 	if ( aParam.Find(KImcvEncodedWordStart) != KErrNotFound )
       
  3994 		{
       
  3995 		// Make assumption that '=?' appearing in parameter means 
       
  3996 		//it is part of encoding
       
  3997 	
       
  3998 		parameterPresent = ETrue;
       
  3999 		iImRecvConvert.iHeaderConverter->DecodeHeaderFieldL(aParam, rBuffer);
       
  4000 		}
       
  4001 	return parameterPresent;
       
  4002 	}
       
  4003 
       
  4004 
       
  4005 // For extracting parameter data following Mime header fields, in the format
       
  4006 //  *(;tag=data).       As specified in rfc2231
       
  4007 // Assumes parameter data seperated by ';'
       
  4008 // Takes tag(name) of parameter as input, returning a descriptor with the data
       
  4009 //----------------------------------------------------------------------------------------
       
  4010 TBool CMimeParser::ParseRfc2231ParameterInfoL(const TDesC8& aTag, TDes& rBuffer, TInt aOffset)
       
  4011 //----------------------------------------------------------------------------------------
       
  4012 	{
       
  4013 TBool parameterPresent = ETrue;
       
  4014 
       
  4015 	// For storing extracted parameter information
       
  4016 
       
  4017 	HBufC8* info = HBufC8::NewLC(KHeaderBufferLength);
       
  4018 
       
  4019 	// For storing information relating to parameter extraction/conversion
       
  4020 
       
  4021 	TInt count = 0;
       
  4022 	TPtrC8 charset8;
       
  4023 	TPtrC8 language8;
       
  4024 	TBool continuation=ETrue; // is RFC2231 section 3 
       
  4025 	
       
  4026 	// Following rfc 2231, parameter may be encoded & folded in the following way
       
  4027 	//
       
  4028 	// <name>*0*=us-ascii'en'<encoded data>
       
  4029 	// <name>*1*=< more encoded data>
       
  4030 	// <name>*2=<unencoded info>
       
  4031 	do 
       
  4032 		{
       
  4033 		// move past the tag	
       
  4034 		iLex.Inc(aOffset+aTag.Length());
       
  4035 		if (iLex.Peek() != KImcvAny) 
       
  4036 			{
       
  4037 			// Default : no charset info or folding
       
  4038 			// move forward to the start of the boundary string itself
       
  4039 
       
  4040 			while (iLex.Peek() != KImcvEquals  && !iLex.Eos())
       
  4041 				{
       
  4042 				
       
  4043 				iLex.Inc();
       
  4044 				}
       
  4045 			}
       
  4046 		else	// *, Parameter is encoded
       
  4047 			{
       
  4048 			iLex.Inc(); // Past '*'
       
  4049 
       
  4050 			// If parameter folded :- need to get several bits of data and join together.
       
  4051 		
       
  4052 			if ( iLex.Peek()!=KImcvEquals) // Get Number
       
  4053 				{
       
  4054 				iLex.Mark(); // Beginnig of number
       
  4055 				iLex.Inc();
       
  4056 				while (iLex.Peek() != KImcvEquals && iLex.Peek() != KImcvAny && !iLex.Eos())
       
  4057 					{
       
  4058 					iLex.Inc(); 
       
  4059 					}
       
  4060 				TPtrC8 numPtr = iLex.MarkedToken();
       
  4061 				TLex8 lex(numPtr);
       
  4062 				lex.Val(count);  // Store number in count.
       
  4063 
       
  4064 				// if * exists,  has language/charset
       
  4065 				if (iLex.Peek() == KImcvAny) 
       
  4066 					{
       
  4067 					iLex.Inc(); // Past *
       
  4068 					// rfc2231 section 4 - has language/charset info
       
  4069 					continuation = EFalse;
       
  4070 					}
       
  4071 				}
       
  4072 
       
  4073 
       
  4074 			// Must get charset & language information etc..
       
  4075 
       
  4076 			if (!count && !continuation)
       
  4077 				{
       
  4078 				iLex.Inc(); // Past '='
       
  4079 
       
  4080 				if (iLex.Peek()==KImcvQuote)
       
  4081 					{
       
  4082 					iLex.Inc(); 
       
  4083 					}
       
  4084 
       
  4085 				// Extract CHARSET token
       
  4086 				iLex.Mark();
       
  4087 				while (iLex.Peek() != KImcvSingleQuote && !iLex.Eos())
       
  4088 					{
       
  4089 					iLex.Inc(); 
       
  4090 					}
       
  4091 				TPtrC8 marked = iLex.MarkedToken();
       
  4092 
       
  4093 				charset8.Set(marked );
       
  4094 				iLex.Inc(); // Past ' 
       
  4095 
       
  4096 				// Extract LANGUAGE token
       
  4097 				iLex.Mark();
       
  4098 				while (iLex.Peek() != KImcvSingleQuote && !iLex.Eos())
       
  4099 					{
       
  4100 					iLex.Inc(); 
       
  4101 					}
       
  4102 				TPtrC8 marked1 = iLex.MarkedToken();
       
  4103 				language8.Set(marked1);
       
  4104 				}
       
  4105 
       
  4106 			} // else, param encoded
       
  4107 
       
  4108 		TLexMark8 mark;
       
  4109 		TPtrC8 param = ExtractParameterString(mark);
       
  4110 		// Save parameter data
       
  4111 		TInt maxlen=info->Des().MaxLength();
       
  4112 		if ((*info).Length() + param.Length() > maxlen )
       
  4113 			{
       
  4114 			info = info->ReAllocL(maxlen + param.Length() + MaxMimeParameterValueLength);
       
  4115 		 	CleanupStack::Pop();
       
  4116 			CleanupStack::PushL(info); 
       
  4117 			}
       
  4118 		info->Des().Append( param );
       
  4119 	} while( ( aOffset=FindAttribute(aTag,iLex.Remainder()))!=KErrNotFound );
       
  4120 
       
  4121 	TPtr8 infoPtr(info->Des());	
       
  4122 	
       
  4123 	DecodeRfc2231ParameterInfoL( infoPtr, rBuffer, charset8/*, language8*/ );
       
  4124 
       
  4125 	CleanupStack::PopAndDestroy(info); 
       
  4126 	return parameterPresent;
       
  4127 	}
       
  4128 
       
  4129 
       
  4130 //----------------------------------------------------------------------------------------
       
  4131 TBool CMimeParser::DecodeRfc2231ParameterInfoL(TDes8& aInput, TDes& rBufOut, 
       
  4132 											   		TPtrC8 aCharset/*, TPtrC8 aLanguage*/)
       
  4133 //----------------------------------------------------------------------------------------
       
  4134 	{
       
  4135 	HBufC8* QPdecodedbuf = HBufC8::NewLC( aInput.Length() );
       
  4136 	TPtr8 ptr(QPdecodedbuf->Des());
       
  4137 
       
  4138 	iImRecvConvert.iQPCodec.SetQPChar(KImcvPercentSign);
       
  4139 	iImRecvConvert.iQPCodec.Decode( aInput, ptr);
       
  4140 	iImRecvConvert.iQPCodec.SetQPChar(KImcvEquals);
       
  4141 
       
  4142 	// Convert parameter, based on charset supplied.
       
  4143 	CImConvertCharconv& charconv = iImRecvConvert.CharacterConverter();
       
  4144 	TUint id = charconv.GetMimeCharsetUidL( aCharset);
       
  4145 
       
  4146 	if(id==KUidMsvCharsetNone)
       
  4147 		{
       
  4148 		id=charconv.SystemDefaultCharset();
       
  4149 		}
       
  4150 
       
  4151 	// DEF055073 - find the maximum length of the descriptor we are filling
       
  4152 	TInt maxLength = rBufOut.MaxLength();
       
  4153 	
       
  4154 	if (!charconv.PrepareToConvertToFromOurCharsetL(id))
       
  4155 		{
       
  4156 		// DEF055073 - Only attempt copy, if ptr will fit inside rBufOut
       
  4157 		if(ptr.Length() <= maxLength)
       
  4158 			{
       
  4159 			rBufOut.Copy(ptr);	
       
  4160 			}
       
  4161 		/* Otherwise, just copy what will fit. This is OK, because 
       
  4162 		 * charconv.ConvertToOurCharsetL also truncates to avoid
       
  4163 		 * an overflow */
       
  4164 		else
       
  4165 			{
       
  4166 			rBufOut.Copy(ptr.Left(maxLength));
       
  4167 			}
       
  4168 		}
       
  4169 	else
       
  4170 		{
       
  4171 		// Charset found, so do conversion
       
  4172 		TInt unconverted;
       
  4173 		TInt indexOfFirst;
       
  4174 		TInt rem = charconv.ConvertToOurCharsetL(ptr, rBufOut, unconverted, indexOfFirst);
       
  4175 		if (rem < 0) // error
       
  4176 			Append(rBufOut, ptr);
       
  4177 		else if (rem && rem < KConversionRemainderLength)
       
  4178 			{
       
  4179 			// DEF055073 - Only attempt copy, if ptr will fit inside rBufOut
       
  4180 			if(ptr.Length() <= maxLength)
       
  4181 				{
       
  4182 				rBufOut.Copy(ptr);	
       
  4183 				}
       
  4184 			/* Otherwise, just copy what will fit. This is OK, because 
       
  4185 			 * charconv.ConvertToOurCharsetL also truncates to avoid
       
  4186 			 * an overflow */
       
  4187 			else
       
  4188 				{
       
  4189 				rBufOut.Copy(ptr.Left(maxLength));
       
  4190 				}
       
  4191 			}
       
  4192 
       
  4193 		}
       
  4194 
       
  4195 	CleanupStack::PopAndDestroy(QPdecodedbuf);
       
  4196 	return ETrue;
       
  4197 	}
       
  4198 
       
  4199 
       
  4200 // Check for delimiter & mark parameter text string
       
  4201 //----------------------------------------------------------------------------------------
       
  4202 TPtrC8 CMimeParser::ExtractParameterString(TLexMark8& rMark)
       
  4203 //----------------------------------------------------------------------------------------
       
  4204 	{
       
  4205 	// move on to the first char of the boundary ; this MIGHT be a double-quote
       
  4206 
       
  4207 	TBool delimited = EFalse;
       
  4208 	TBool encodedWord = EFalse; //Non compliance of RFC-2047 for ContentType & Content Disposition
       
  4209 	iLex.Inc();
       
  4210 				
       
  4211 	if ( iLex.Peek() == KImcvDoubleQuote )
       
  4212 		{
       
  4213 		delimited = ETrue;
       
  4214 		iLex.Inc();
       
  4215 		}
       
  4216 		
       
  4217 	while ( iLex.Peek().IsSpace() )
       
  4218 		{
       
  4219 		iLex.Inc();
       
  4220 		}
       
  4221 
       
  4222 	iLex.Mark( rMark );
       
  4223 			
       
  4224 	//Check if the encoded_word exists, set the flag to parse the string.
       
  4225 	//Ex: Content-Disposition: attachment; filename==?KOI8-R?B?RG9jdW1lbnQ2LnR4dA==?=
       
  4226 	if(iLex.Peek() == KImcvEquals)   //search for QuestionMark followed by Equals	
       
  4227 		{
       
  4228 		iLex.Inc();
       
  4229 		if(iLex.Peek() == KImcvQuestionMark)
       
  4230 			{
       
  4231 			encodedWord = ETrue;
       
  4232 			iLex.Inc();	
       
  4233 			}
       
  4234 		else
       
  4235 			{
       
  4236 			iLex.UnGet();	
       
  4237 			}
       
  4238 		}
       
  4239 		
       
  4240 	TBool finished = EFalse;
       
  4241 	while ( !finished  && !iLex.Eos() )
       
  4242 		{
       
  4243 		iLex.Inc();
       
  4244 
       
  4245 		if ( delimited )
       
  4246 			{
       
  4247 			finished = (iLex.Peek() == KImcvDoubleQuote);
       
  4248 			}
       
  4249 		else if(encodedWord)     //Parse the string if encoded_word exists.
       
  4250 			{                    //Ex: Content-Disposition: attachment; filename==?KOI8-R?B?RG9jdW1lbnQ2LnR4dA==?=
       
  4251 			if(iLex.Peek() == KImcvQuestionMark)    // search for Equals followed by QuestionMark, and set finished flag to ETrue.
       
  4252 				{
       
  4253 				iLex.Inc();
       
  4254 				if(iLex.Peek() == KImcvEquals)
       
  4255 					{
       
  4256 					iLex.Inc();
       
  4257 					finished = ETrue;	
       
  4258 					}
       
  4259 					else
       
  4260 					{
       
  4261 					iLex.UnGet();		
       
  4262 					}
       
  4263 				}
       
  4264 			}			
       
  4265 		else
       
  4266 			{
       
  4267 			finished = ( iLex.Peek().IsSpace() || IsSpecialChar((TUint8)iLex.Peek()) );
       
  4268 		 	}
       
  4269 		} 
       
  4270 
       
  4271 	return iLex.MarkedToken( rMark );
       
  4272 	}
       
  4273 
       
  4274 
       
  4275 // Which charset to use .. ? If the body part charset set, use that.
       
  4276 // else if the main header charset set, use that... else default to us-ascii.
       
  4277 
       
  4278 //----------------------------------------------------------------------------------------
       
  4279 TUint CMimeParser::CurrentCharsetL() const
       
  4280 //----------------------------------------------------------------------------------------
       
  4281 	{
       
  4282 	TPtrC8 paramCharset = GetContentTypeValue(KImcvCharset);
       
  4283 
       
  4284 	TUint charsetId;
       
  4285 	if (paramCharset.Length())
       
  4286 		// charset parameter present.
       
  4287 		charsetId = iImRecvConvert.CharacterConverter().GetMimeCharsetUidL(paramCharset);
       
  4288 	else if (iCharset) 
       
  4289 		// Main Mime header has default charset value.
       
  4290 		charsetId = iCharset;
       
  4291 	else
       
  4292 		charsetId = iDefaultCharset;
       
  4293 
       
  4294 	return charsetId;		
       
  4295 	}
       
  4296 
       
  4297 
       
  4298 //----------------------------------------------------------------------------------------
       
  4299 const TPtrC8 CMimeParser::GetContentTypeValue(const TDesC8& aContentTypeParameter) const
       
  4300 //----------------------------------------------------------------------------------------
       
  4301 	{
       
  4302 	CDesC8Array& contentTypeParams = iMimeHeader->ContentTypeParams();
       
  4303 	__ASSERT_DEBUG(!(contentTypeParams.Count()&1), User::Invariant());
       
  4304 
       
  4305 	TInt result;
       
  4306 	if (KErrNone==contentTypeParams.Find(aContentTypeParameter,result,ECmpFolded8))
       
  4307 		{
       
  4308 		result++;
       
  4309 		if ((result&1) && result <= contentTypeParams.Count())    
       
  4310 			{       
       
  4311 				// check result+1 is odd & entry exists
       
  4312 				return iMimeHeader->ContentTypeParams()[result];
       
  4313 			}
       
  4314 		}
       
  4315 	return TPtrC8();        // couldn't find match so return an empty descriptor
       
  4316 	}
       
  4317 
       
  4318 void CImRecvConvert::ImCafRegisterL(const TDesC8& aMimeLine)
       
  4319 	{
       
  4320 	if(iCaf)
       
  4321 		{
       
  4322 		iCaf->RegisterL(aMimeLine);
       
  4323 		}	
       
  4324 	}
       
  4325 		
       
  4326 void CImRecvConvert::ImAddToCafMetaDataL(const TDesC8& aMimeLine)
       
  4327 	{
       
  4328 	if(iCaf)
       
  4329 		{
       
  4330 		iCaf->AddToMetaDataL(aMimeLine);
       
  4331 		}
       
  4332 	}
       
  4333 
       
  4334 void CImRecvConvert::ImAddToCafMetaDataL(const TDesC8& aField, const TDesC8& aData)
       
  4335 	{
       
  4336 	if(iCaf)
       
  4337 		{
       
  4338 		iCaf->AddToMetaDataL(aField,aData);
       
  4339 		}
       
  4340 	}
       
  4341 
       
  4342 TBool CImRecvConvert::ImCafProcessing() const
       
  4343 	{
       
  4344 	if(iCaf)
       
  4345 		{
       
  4346 		return iCaf->Processing();
       
  4347 		}
       
  4348 	else
       
  4349 		{
       
  4350 		return EFalse;
       
  4351 		}
       
  4352 	}
       
  4353 
       
  4354 TBool CImRecvConvert::ImCafRegistered() const
       
  4355 	{
       
  4356 	if(iCaf)
       
  4357 		{
       
  4358 		return iCaf->Registered();
       
  4359 		}
       
  4360 	else
       
  4361 		{
       
  4362 		return EFalse;
       
  4363 		}	
       
  4364 	}
       
  4365