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