email/imap4mtm/imapsession/src/cimapbodystructurebuilder.cpp
changeset 80 8b14b30db193
equal deleted inserted replaced
79:2981cb3aa489 80:8b14b30db193
       
     1 // Copyright (c) 2006-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 "cimapbodystructurebuilder.h"
       
    17 
       
    18 #include "cimapatom.h"
       
    19 #include "cimapatomwalker.h"
       
    20 #include "cimapatomparser.h"
       
    21 #include "cimapbodystructure.h"
       
    22 #include "cimapfetchresponse.h"
       
    23 #include "cimapsessionconsts.h"
       
    24 #include "cimapcommand.h"
       
    25 #include "imappaniccodes.h"
       
    26 
       
    27 
       
    28 CImapBodyStructureBuilder* CImapBodyStructureBuilder::NewL(CImapFetchResponse& aFetchResponse, TInt aLogId)
       
    29 // static method
       
    30 	{
       
    31 	CImapBodyStructureBuilder* self = new(ELeave)CImapBodyStructureBuilder(aFetchResponse, aLogId);
       
    32 	CleanupStack::PushL(self);
       
    33 	self->ConstructL();
       
    34 	CleanupStack::Pop(self);
       
    35 	return self;
       
    36 	}
       
    37 CImapBodyStructureBuilder::CImapBodyStructureBuilder(CImapFetchResponse& aFetchResponse, TInt aLogId)
       
    38 	: iFetchResponse(aFetchResponse)
       
    39 	, iBodyStructureOwned(ETrue)
       
    40 	, iProcessBlockState(EWaitLine)
       
    41 	, iLogId(aLogId)
       
    42 	{}
       
    43 	
       
    44 void CImapBodyStructureBuilder::ConstructL()
       
    45 	{
       
    46 	iAtomParser = CImapAtomParser::NewL(EFalse, iLogId);
       
    47 	iAtomWalker = CImapAtomWalker::NewL(iLogId);
       
    48 	}
       
    49 	
       
    50 CImapBodyStructureBuilder::~CImapBodyStructureBuilder()
       
    51 	{
       
    52 	delete iAtomWalker;
       
    53 	delete iAtomParser;
       
    54 	
       
    55 	// NOTE
       
    56 	//
       
    57 	// CImapBodyStructure is a tree data strucutre, where any CImapBodyStructure owns and 
       
    58 	// is responssible for destroying its children.
       
    59 	//
       
    60 	// iBodyStructureStack[0] is the root bodystructure 
       
    61 	// ownership of the which is usually passed to CImapFetchResponse object before we get here
       
    62 	// So destroying iBodyStructureStack[0] will cause all its children to be destroyed too.
       
    63 	//
       
    64 	// With the exception of the root bodystructure, iBodyStructureStack does not own any 
       
    65 	// of the objects it points to, and MUST NOT destroy them.
       
    66 	
       
    67 	if (iBodyStructureOwned)
       
    68 		{
       
    69 		if (iBodyStructureStack.Count() > 0)
       
    70 			{
       
    71 			// delete the root bodystructure.
       
    72 			delete iBodyStructureStack[0];
       
    73 			}
       
    74 		}
       
    75 	iBodyStructureStack.Close(); // And DO NOT destroy the data that is pointed to.
       
    76 	}
       
    77 
       
    78 /**
       
    79 Parses a block of incoming data from the session.
       
    80 ProcessBlockL() should be called repeatedly with more data until it returns EFalse to 
       
    81 indicate that enough data has been received.
       
    82 This method parses the incoming data into an atom tree as the data is received.
       
    83 When the last block of data is received, the method will then parse the complete atom tree,
       
    84 populating iFetchResponse with a fully initialised CImapBodyStructure tree.
       
    85 @param aData either a line or literal block of data.
       
    86 @return Whether ProcessBlockL() expects to be called again with the next block of data from the session.
       
    87 */
       
    88 TBool CImapBodyStructureBuilder::ProcessBlockL(const TDesC8& aData)
       
    89 	{
       
    90 	TBool wantMore = ETrue;
       
    91 	switch (iProcessBlockState)
       
    92 		{
       
    93 		case EWaitLine:
       
    94 			{
       
    95 			wantMore = iAtomParser->ProcessLineL(aData);
       
    96 			
       
    97 			if (!wantMore)
       
    98 				{				
       
    99 				iAtomWalker->SetRootL(iAtomParser->RootAtom());
       
   100 				
       
   101 				// Get to the first "("
       
   102 				__ASSERT_ALWAYS(iAtomWalker->CurrentDes(EFalse).Length()==0, CImapCommand::CorruptDataL(iLogId));
       
   103 				__ASSERT_ALWAYS(iAtomWalker->PeekAcross() == NULL, CImapCommand::CorruptDataL(iLogId));
       
   104 					
       
   105 				iAtomWalker->WalkDownL();
       
   106 				__ASSERT_ALWAYS(iAtomWalker->CurrentMatch(KImapTxtOpenBracket()), CImapCommand::CorruptDataL(iLogId));
       
   107 				
       
   108 				iProcessBlockState = EParsing;
       
   109 				ParseLoopL();
       
   110 				
       
   111 				TransferBufferOwnershipToFetchResponseL();
       
   112 				}
       
   113 			else
       
   114 				{
       
   115 				iProcessBlockState = EWaitLiteral;
       
   116 				}
       
   117 			}
       
   118 			break;
       
   119 		case EWaitLiteral:
       
   120 			{
       
   121 			iAtomParser->ProcessLiteralBlockL(aData);
       
   122 			iProcessBlockState = EWaitLine;
       
   123 			}
       
   124 			break;
       
   125 		default:
       
   126 			{
       
   127 			// This is an internal programming error.
       
   128 			__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidProcessBlockState));
       
   129 			wantMore = EFalse;
       
   130 			}
       
   131 			break;
       
   132 		}
       
   133 		
       
   134 	return wantMore;
       
   135 	}
       
   136 
       
   137 /**
       
   138 Assigns the root bodystructure object, and its associated data to iFetchResponse.
       
   139 iFetchResponse takes ownership of the bodystructure and its data.
       
   140 */
       
   141 void CImapBodyStructureBuilder::TransferBufferOwnershipToFetchResponseL()
       
   142 	{
       
   143 	// Check for internal programming errors.
       
   144 	__ASSERT_DEBUG(iBodyStructureOwned, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderRootNotOwned));
       
   145 	__ASSERT_DEBUG(iBodyStructureStack.Count() == 1, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderExpectedRootAtomOnlyOnStack));
       
   146 	__ASSERT_DEBUG(iBodyStructureStack[0] == iBodyStructure, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderCurrentAtomIsNotRoot));
       
   147 	
       
   148 	// Prepare to transfer ownership of bodyStructureData from iAtomParser to iFetchResponse
       
   149 	// bodyStructureData will no longer be owned by iAtomParser
       
   150 	HBufC8* bodyStructureData = iAtomParser->DetachBuffer();
       
   151 	
       
   152 	// Transfer ownership of iBodyStructure and bodyStructureData to iFetchResponse
       
   153 	iFetchResponse.SetBodyStructure(iBodyStructure, bodyStructureData);
       
   154 	
       
   155 	// iBodyStructure is no longer owned by "this" CImapBodyStructureBuilder object.
       
   156 	iBodyStructureOwned = EFalse;
       
   157 	}
       
   158 
       
   159 /**
       
   160 Returns any data that was not parsed by ParseBlockL()
       
   161  - i.e any data that follows the top level BODYSTRUCTURE.
       
   162 This will be a null string until ParseBlockL() has returned EFalse
       
   163 to indicate that it has finished parsing.
       
   164 When non-null, the returned pointer descriptor points into a section of the 
       
   165 aData descriptor that was passed into ParseBlockL().  Consequently, it is
       
   166 only valid while the aData descriptor it points into is valid.
       
   167 @return a descriptor pointing to unparsed data.
       
   168 */
       
   169 TPtrC8 CImapBodyStructureBuilder::UnparsedData()
       
   170 	{
       
   171 	return iAtomParser->UnparsedData();
       
   172 	}	
       
   173 	
       
   174 /**
       
   175 The main loop for parsing the bodystructure.
       
   176 The loop uses a state machine and bodystructure stack in order to handle
       
   177 embedded bodystructures without needing to use recursion.
       
   178 */
       
   179 void CImapBodyStructureBuilder::ParseLoopL()
       
   180 	{
       
   181 	// Check for internal programming error
       
   182 	__ASSERT_DEBUG(iBodyStructureStack.Count() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackNotEmpty));
       
   183 	
       
   184 	TParseStep parseStep = EParseNewBodyStructure;	
       
   185 	
       
   186 	while (parseStep != EParseComplete)
       
   187 		{
       
   188 		switch (parseStep)
       
   189 			{
       
   190 			case EParseNewBodyStructure:
       
   191 				{
       
   192 				// Either at the start of the root body structure,
       
   193 				// Or at the start of an embedded body structure.
       
   194 				PushNewBodyStructureL();
       
   195 				parseStep = ParseBodyStructureTypeL();
       
   196 				}
       
   197 				break;
       
   198 			case EParseBasic:
       
   199 				{
       
   200 				// Found a "basic" bodystructure - i.e. not text, rfc822 or multipart.
       
   201 				ParseBodyTypeBasicL();
       
   202 				ParseBodyExt1PartL();
       
   203 				parseStep = EParseSubStructureComplete;
       
   204 				}
       
   205 				break;
       
   206 			case EParseText:
       
   207 				{
       
   208 				// Found a "TEXT" body structure
       
   209 				ParseBodyTypeTextL();
       
   210 				ParseBodyExt1PartL();
       
   211 				parseStep = EParseSubStructureComplete;
       
   212 				}
       
   213 				break;
       
   214 			case EParseBodyTypeMessageRfc822:
       
   215 				{
       
   216 				// Found a "MESSAGE/RFC822" body structure.
       
   217 				// This contains an embedded bodystructure, so parse up to the structure,
       
   218 				// and then allow the loop to parse the embedded structure.
       
   219 				TRAPD(err, ParseBodyTypeMessageRfc822L());
       
   220 				if(err == KErrImapCorrupt)
       
   221 				    {
       
   222 				parseStep =EParseRemainderMessageRfc822;
       
   223 				    }
       
   224 				else
       
   225 				    {
       
   226                     parseStep = EParseNewBodyStructure;
       
   227 				    }
       
   228 				
       
   229 				}
       
   230 				break;
       
   231 			case EParseRemainderMessageRfc822:
       
   232 				{
       
   233 				// Just finished parsing the embedded bodystructure of a "MESSAGE/RFC822".
       
   234 				// Complete parsing the parent MESSAGE/RFC822 structure here.
       
   235 				ParseRemainderMessageRfc822L();
       
   236 				ParseBodyExt1PartL();
       
   237 				parseStep = EParseSubStructureComplete;
       
   238 				}
       
   239 				break;
       
   240 			case EParseRemainderMultipart:
       
   241 				{
       
   242 				// Just finished parsing the final embedded bodystructure of a MULTIPART structure.
       
   243 				// Complete parsing the parent MULTIPART structure here
       
   244 				ParseRemainderMultipartL();
       
   245 				parseStep = EParseSubStructureComplete;
       
   246 				}
       
   247 				break;
       
   248 			case EParseSubStructureComplete:
       
   249 				{
       
   250 				// Just finished parsing a bodystructure.
       
   251 				// If it is the root bodystructure then we are complete.
       
   252 				// Otherwise, let ParseSubStructureCompleteL() will find out whether it is
       
   253 				// * embedded in a MESSAGE/RFC822 structure - requiring the remainder to be parsed next: EParseRemainderMessageRfc822
       
   254 				// * embedded in a MULTIPART structure in which case
       
   255 				//   > either there is another embedded structure next: EParseNewBodyStructure
       
   256 				//   > or this is the last embedded structure, so we need to parse the multipart remainder: EParseRemainderMultipart
       
   257 					
       
   258 				if (PopBodyStructureL())
       
   259 					{
       
   260 					// we were actually in the root, so we are fully complete.
       
   261 					parseStep = EParseComplete;
       
   262 					}
       
   263 				else
       
   264 					{
       
   265 					// we were in a genuine substructure, so need to walk up and decide what to do.
       
   266 					parseStep = ParseSubStructureCompleteL();
       
   267 					}				
       
   268 				}
       
   269 				break;
       
   270 			default:
       
   271 				{
       
   272 				// This is an internal programming error.
       
   273 				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidParseStep));
       
   274 				User::Leave(KErrGeneral); // avoid an infinite loop.
       
   275 				}
       
   276 			}
       
   277 		}
       
   278 	}
       
   279 
       
   280 /**
       
   281 When the parse loop comes across a new root or embedded bodystructure, it will use this method to...
       
   282   > Create a new CImapBodyStructure object to represent the bodystructure
       
   283   > Push the object onto the stack and make it "current"
       
   284   > Associate an embedded bodystructure with its parent.
       
   285 
       
   286 */
       
   287 void CImapBodyStructureBuilder::PushNewBodyStructureL()
       
   288 	{
       
   289 	// Going to create a new body structure.
       
   290 	// Need to be sure that something (either the stack root or its tree)
       
   291 	// is going to own and ultimatelty destroy it.
       
   292 	__ASSERT_DEBUG(iBodyStructureOwned, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderRootNotOwned));
       
   293 	
       
   294 	CImapBodyStructure* bodyStructure = CImapBodyStructure::NewL();
       
   295 	CleanupStack::PushL(bodyStructure);
       
   296 	
       
   297 	// root bodystructure is iBodyStructureStack[0]
       
   298 	if (iBodyStructure == NULL)
       
   299 		{
       
   300 		// Check for internal programming error
       
   301 		__ASSERT_DEBUG(iBodyStructureStack.Count() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackNotEmpty));
       
   302 		
       
   303 		iBodyStructureStack.AppendL(bodyStructure);
       
   304 		
       
   305 		// ownership is now transferred to the root bodystructure tree
       
   306 		CleanupStack::Pop(bodyStructure);
       
   307 		}
       
   308 	else
       
   309 		{
       
   310 		// Check for internal programming error
       
   311 		__ASSERT_DEBUG(iBodyStructureStack.Count() > 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackIsEmpty));
       
   312 		
       
   313 		iBodyStructure->AppendEmbeddedBodyStructureL(*bodyStructure);
       
   314 										
       
   315 		// ownership is now transferred to the root bodystructure tree
       
   316 		CleanupStack::Pop(bodyStructure);
       
   317 		
       
   318 		iBodyStructureStack.AppendL(bodyStructure);
       
   319 		}
       
   320 	
       
   321 	// This is now the bodystructure that we are parsing.
       
   322 	iBodyStructure = bodyStructure;
       
   323 	}
       
   324 
       
   325 /**
       
   326 Pops a bodystructure from the stack - except the root, which will not be popped.
       
   327 @return whether we were in the root already.
       
   328 */	
       
   329 TBool CImapBodyStructureBuilder::PopBodyStructureL()
       
   330 	{
       
   331 	TBool bRootAlready = EFalse;
       
   332 	TInt stackCount = iBodyStructureStack.Count();
       
   333 
       
   334 	if (stackCount > 1)
       
   335 		{
       
   336 		// Pop the bodystructure stack
       
   337 		--stackCount;
       
   338 		CImapBodyStructure* poppedBs = iBodyStructureStack[stackCount];
       
   339 		iBodyStructureStack.Remove(stackCount); // No need to destroy the bodystructure, as it is now owned by iBodyStructureStack[stackCount-1]
       
   340 		
       
   341 		iBodyStructure = iBodyStructureStack[stackCount-1];
       
   342 		}
       
   343 	else
       
   344 		{
       
   345 		// Check for internal programming error: Not expecting a stack count of 0 or less
       
   346 		__ASSERT_DEBUG(stackCount == 1, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderExpectedRootAtomOnlyOnStack));
       
   347 		bRootAlready = ETrue;
       
   348 		}
       
   349 		
       
   350 	return bRootAlready;
       
   351 	}
       
   352 
       
   353 /**
       
   354 Found the closing bracket of our substructure.
       
   355 Pop the stack, walk up and decide what to do next.
       
   356 If we've reached the root level, then parsing is complete.
       
   357 If our parent is a multipart, then check to see if we have a sibling.  
       
   358 	If not then we have come to the end of our parent's structure too - handle this in a separate loop.
       
   359 If our parent is a Rfc822, then we need to parse the remainder of the Rfc822 structure.
       
   360 	If not then we have come to the end of our parent's structure too - handle this in a separate loop.
       
   361 @return 
       
   362 */
       
   363 CImapBodyStructureBuilder::TParseStep CImapBodyStructureBuilder::ParseSubStructureCompleteL()
       
   364 	{
       
   365 	TParseStep nextStep = EParseComplete;
       
   366 	
       
   367 	iAtomWalker->WalkUpL();
       
   368 	
       
   369 	if (iBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeMultipart)
       
   370 		{
       
   371 		// Expecting either an open bracket for another bodystructure
       
   372 		// or the subtype. 
       
   373 		CImapAtom* peekAcross = iAtomWalker->PeekAcross(); // peekAcross does not need to be destroyed as no ownership is transferred.
       
   374 		if (peekAcross == NULL)
       
   375 			{
       
   376 			// But not expecting "nothing".
       
   377 			CImapCommand::CorruptDataL(iLogId);
       
   378 			}
       
   379 		
       
   380 		if (peekAcross->Match(KImapTxtOpenBracket()))
       
   381 			{
       
   382 			// position the atom walker on the open bracket, ready for ParseBodyStructureTypeL
       
   383 			// to walk down into it.
       
   384 			iAtomWalker->WalkAcrossL(ETrue);
       
   385 			nextStep = EParseNewBodyStructure;
       
   386 			}
       
   387 		else
       
   388 			{
       
   389 			// stay where we are, so that ParseRemainderMultipartL()
       
   390 			// can walk accross to the subtype, as any other Parse method would do
       
   391 			nextStep = EParseRemainderMultipart;
       
   392 			}
       
   393 		}
       
   394 	else if (iBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeMessageRfc822)
       
   395 		{
       
   396 		// stay where we are, so that ParseRemainderMessageRfc822L()
       
   397 		// can walk accross to the body-fld-lines, as any other Parse method would do
       
   398 		nextStep = EParseRemainderMessageRfc822;
       
   399 		}
       
   400 	else
       
   401 		{
       
   402 		// No other bodystruct type has substructures.
       
   403 		// So getting here is an internal programming error.
       
   404 		__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidBodyStructureType));
       
   405 		User::Leave(KErrGeneral);
       
   406 		}
       
   407 			
       
   408 	return nextStep;
       
   409 	}
       
   410 
       
   411 /**
       
   412 body = "(" (body-type-1part / body-type-mpart) ")"
       
   413 
       
   414 This method expects iAtomWalker to be positioned at the opening bracket of a body structure.
       
   415 The method works out the type of the bodystructure, and returns the appropriate next parse 
       
   416 step to the parse loop.
       
   417 For multipart structures, iAtomWalker is left positioned at the opening bracket of the embedded structure.
       
   418 Foa all other structures, iAtomWalker is left positioned at the subtype field.
       
   419 
       
   420 @return The next step for the parse loop to take.  This is one of
       
   421   > EParseNewBodyStructure for MULTIPART structures
       
   422   > EParseText for TEXT structures
       
   423   > EParseBodyTypeMessageRfc822 for MESSAGE/RFC822
       
   424   > EParseBasic for all other structures.
       
   425 */
       
   426 CImapBodyStructureBuilder::TParseStep CImapBodyStructureBuilder::ParseBodyStructureTypeL()
       
   427 	{
       
   428 	// Start at the opening bracket
       
   429 	__ASSERT_ALWAYS(iAtomWalker->CurrentMatch(KImapTxtOpenBracket()), CImapCommand::CorruptDataL(iLogId));
       
   430 	iAtomWalker->WalkDownL();
       
   431 		
       
   432 	// What kind of body type does this represent?	
       
   433 	// Assume Basic, unless we find otherwise.
       
   434 	TParseStep nextStep = EParseBasic;
       
   435 	
       
   436 	// Is it body-type-mpart? - check for opening bracket
       
   437 	// body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart]
       
   438 	if (iAtomWalker->CurrentMatch(KImapTxtOpenBracket()))
       
   439 		{
       
   440 		// According to section 6.4.5 of RFC3501, "MULTIPART" is the correct Type string for
       
   441 		// multipart messages.  This is an implicit value not directly available from the
       
   442 		// bodystructure input string.  So we point the bodystructure object at a constant string instead.
       
   443 		iBodyStructure->SetType(KImapTxtMultipart());
       
   444 		
       
   445 		iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeMultipart);
       
   446 		nextStep = EParseNewBodyStructure;
       
   447 		}
       
   448 	else
       
   449 		{
       
   450 		// body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part]
       
   451 		iBodyStructure->SetType(iAtomWalker->CurrentDes(EFalse)); // media-basic and variants is a string, not an nstring
       
   452 		__ASSERT_ALWAYS(iAtomWalker->PeekDown() == NULL, CImapCommand::CorruptDataL(iLogId));
       
   453 		
       
   454 		iAtomWalker->WalkAcrossL(ETrue);
       
   455 		iBodyStructure->SetSubType(iAtomWalker->CurrentDes(EFalse)); // media-subtype and variants is a string, not an nstring
       
   456 		
       
   457 		if (iBodyStructure->Type().CompareF(KImapTxtText())==0)
       
   458 		// body-type-text = media-text SP body-fields SP body-fld-lines
       
   459 		// 
       
   460 		// media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
       
   461 		// media-subtype = string
       
   462 			{
       
   463 			// we have media-text...
       
   464 			// ... so this is body-type-text
       
   465 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeText);
       
   466 			nextStep = EParseText;
       
   467 			}
       
   468 		else if (iBodyStructure->Type().CompareF(KImapTxtMessage())==0 && iBodyStructure->SubType().CompareF(KImapTxtRfc822())==0)
       
   469 		// body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines
       
   470 		// 
       
   471 		// media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
       
   472 			{
       
   473 			// we have media-message...
       
   474 			// ... so this is body-type-msg
       
   475 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeMessageRfc822);
       
   476 			nextStep = EParseBodyTypeMessageRfc822;
       
   477 			}
       
   478 		else
       
   479 			{
       
   480 			// Not multipart, text or rfc822, so must be basic.
       
   481 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeBasic);
       
   482 			}
       
   483 		}
       
   484 		
       
   485 	return nextStep;	
       
   486 	}
       
   487 	
       
   488 /**
       
   489 body-type-basic = media-basic SP body-fields
       
   490 
       
   491 This method expects media-basict to have been parsed already, as part of ParseBodyStructureTypeL()
       
   492 It expects the atom walker to be positioned at the last atom of media-basic
       
   493 */
       
   494 void CImapBodyStructureBuilder::ParseBodyTypeBasicL()
       
   495 	{
       
   496 	// body-fields
       
   497 	ParseBodyFieldsL();
       
   498 	}
       
   499 	
       
   500 /**
       
   501 body-type-text = media-text SP body-fields SP body-fld-lines
       
   502 
       
   503 This method expects media-text to have been parsed already, as part of ParseBodyStructureTypeL()
       
   504 It expects the atom walker to be positioned at the last atom of media-text
       
   505 */
       
   506 void CImapBodyStructureBuilder::ParseBodyTypeTextL()
       
   507 	{
       
   508 	// body-fields
       
   509 	ParseBodyFieldsL();
       
   510 	
       
   511 	// body-fld-lines = number
       
   512 	iAtomWalker->WalkAcrossL(ETrue);
       
   513 	iBodyStructure->SetBodyLines(iAtomWalker->CurrentDes(EFalse));
       
   514 	}
       
   515 	
       
   516 /**
       
   517 body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines
       
   518 
       
   519 This method parses up to and including envelope.
       
   520 It then returns, allowing the parse loop to parse the nested "body" that is next.
       
   521 Upon completion of the nested "body", ParseRemainderMessageRfc822L() will be called to finish parsing
       
   522 the message body type
       
   523 
       
   524 This method expects media-message to have been parsed already, as part of ParseBodyStructureTypeL()
       
   525 It expects the atom walker to be positioned at the last atom of media-text
       
   526 */
       
   527 void CImapBodyStructureBuilder::ParseBodyTypeMessageRfc822L()
       
   528 	{
       
   529 	// body-fields SP SP body SP body-fld-lines
       
   530 	ParseBodyFieldsL();
       
   531 	//Sometime RFCb22  message has empty evvelopel, in that case we are traping this and  processed.
       
   532     TRAPD(err, ParseEnvelopeL());
       
   533    
       
   534     // Expect a body substructure next.
       
   535     // Position iAtomWalker at the opening bracket, ready for ParseBodyStructureTypeL
       
   536     iAtomWalker->WalkAcrossL(ETrue);
       
   537     if(err == KErrImapCorrupt)
       
   538         CImapCommand::CorruptDataL(iLogId);
       
   539 	}
       
   540 
       
   541 /**
       
   542 body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines
       
   543 
       
   544 ParseBodyTypeMessageRfc822L processes up to and including body-fields.
       
   545 The ParseLoop processes the nested "body"
       
   546 This method processes the remainder - i.e. body-fld-lines
       
   547 It expects the atom walker to be positioned at the field just prior to body-fld-lines
       
   548 */
       
   549 void CImapBodyStructureBuilder::ParseRemainderMessageRfc822L()
       
   550 	{
       
   551 	// body-fld-lines = number
       
   552 	iAtomWalker->WalkAcrossL(ETrue);
       
   553 	iBodyStructure->SetBodyLines(iAtomWalker->CurrentDes(EFalse));
       
   554 	}
       
   555 
       
   556 /**
       
   557 body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP body-fld-enc SP body-fld-octets	
       
   558 
       
   559 This method expects iAtomWalker to be positioned just prior to body-fld-param
       
   560 */
       
   561 void CImapBodyStructureBuilder::ParseBodyFieldsL()
       
   562 	{
       
   563 	ParseBodyFieldParamsL(EFalse);
       
   564 	
       
   565 	// body-fld-id = nstring
       
   566 	iAtomWalker->WalkAcrossL(EFalse);
       
   567 	iBodyStructure->SetBodyId(iAtomWalker->CurrentDes(ETrue)); 
       
   568 	
       
   569 	// body-fld-desc = nstring
       
   570 	iAtomWalker->WalkAcrossL(EFalse);
       
   571 	iBodyStructure->SetBodyDescription(iAtomWalker->CurrentDes(ETrue));
       
   572 	
       
   573 	// body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ "QUOTED-PRINTABLE") DQUOTE) / string
       
   574 	// i.e. it's a string that might be in quotes
       
   575 	iAtomWalker->WalkAcrossL(EFalse);
       
   576 	iBodyStructure->SetBodyEncoding(iAtomWalker->CurrentDes(EFalse));
       
   577 	
       
   578 	// body-fld-octets = number
       
   579 	iAtomWalker->WalkAcrossL(EFalse);
       
   580 	iBodyStructure->SetBodySizeOctets(iAtomWalker->CurrentDes(EFalse));
       
   581 	}
       
   582 	
       
   583 /**
       
   584 body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
       
   585 
       
   586 This method expects iAtomWalker to be positioned just prior to the "(" or "NIL" atom.
       
   587 */
       
   588 void CImapBodyStructureBuilder::ParseBodyFieldParamsL(TBool aStoreAsDisposition)
       
   589 
       
   590 	{
       
   591 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomNil)
       
   592 		{
       
   593 		// there are no params
       
   594 		return;
       
   595 		}
       
   596 	
       
   597 	// Consume the bracket
       
   598 	iAtomWalker->WalkDownL();
       
   599 	
       
   600 	do 
       
   601 		{
       
   602 		CImapBodyStructure::TAttributeValuePair pair;
       
   603 		pair.iAttribute.Set(iAtomWalker->CurrentDes(EFalse));
       
   604 		
       
   605 		iAtomWalker->WalkAcrossL(ETrue);
       
   606 		pair.iValue.Set(iAtomWalker->CurrentDes(EFalse));
       
   607 		
       
   608 		if (aStoreAsDisposition)
       
   609 			{
       
   610 			iBodyStructure->AppendExtDispositionParameterListL(pair);	
       
   611 			}
       
   612 		else
       
   613 			{
       
   614 			iBodyStructure->AppendParameterListL(pair);
       
   615 			}		
       
   616 		} 
       
   617 		while (iAtomWalker->WalkAcrossL(EFalse));
       
   618 		
       
   619 	iAtomWalker->WalkUpL();
       
   620 	}
       
   621 
       
   622 /** 
       
   623 body-fld-dsp = "(" string SP body-fld-param ")" / nil
       
   624 
       
   625 This method expects iAtomWalker to be positioned just prior to the "(" or "NIL" atom.
       
   626 */
       
   627 void CImapBodyStructureBuilder::ParseBodyFieldDispL()
       
   628 	{
       
   629 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomNil)
       
   630 		{
       
   631 		// there are no params
       
   632 		return;
       
   633 		}
       
   634 		
       
   635 	iAtomWalker->WalkDownL();
       
   636 	
       
   637 	// string
       
   638 	iBodyStructure->SetExtDispositionName(iAtomWalker->CurrentDes(EFalse));
       
   639 	
       
   640 	// body-fld-param
       
   641 	ParseBodyFieldParamsL(ETrue);
       
   642 	
       
   643 	iAtomWalker->WalkUpL();	
       
   644 	}
       
   645 	
       
   646 /**
       
   647 body-fld-lang = nstring / "(" string *(SP string) ")"
       
   648 
       
   649 This method should only be called if body-fld-lang is expected.
       
   650 The caller should check first, using iAtomWalker->PeekAcross()
       
   651 */
       
   652 void CImapBodyStructureBuilder::ParseBodyFieldLangL()
       
   653 	{
       
   654 	// Consume the bracket
       
   655 	iAtomWalker->WalkAcrossL(ETrue);
       
   656 	
       
   657 	if (iAtomWalker->CurrentMatch(KImapTxtOpenBracket()))
       
   658 		{
       
   659 		// we have many strings
       
   660 		// "(" string *(SP string) ")"
       
   661 		
       
   662 		iAtomWalker->WalkDownL();
       
   663 				
       
   664 		do 
       
   665 			{
       
   666 			iBodyStructure->AppendExtLanguageListL(iAtomWalker->CurrentDes(EFalse));
       
   667 			
       
   668 			} while (iAtomWalker->WalkAcrossL(EFalse));
       
   669 		
       
   670 		iAtomWalker->WalkUpL();
       
   671 		}
       
   672 	else 
       
   673 		{
       
   674 		// we have a single nstring - only add it if it is non-empty
       
   675 		const TDesC8& language = iAtomWalker->CurrentDes(ETrue);
       
   676 		if (language.Length() > 0)
       
   677 			{
       
   678 			iBodyStructure->AppendExtLanguageListL(language);	
       
   679 			}		
       
   680 		}
       
   681 	}
       
   682 
       
   683 /**
       
   684 body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   685 
       
   686 This only appears in
       
   687 body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part]
       
   688 So, this method treats the body-fld-md5 field as optional
       
   689 */
       
   690 void CImapBodyStructureBuilder::ParseBodyExt1PartL()
       
   691 	{
       
   692 	// Return as soon as a field is not found.
       
   693 	if (iAtomWalker->WalkAcrossL(EFalse))
       
   694 		{
       
   695 		// body-fld-md5 = nstring
       
   696 		iBodyStructure->SetExtMD5(iAtomWalker->CurrentDes(ETrue));
       
   697 		
       
   698 		// [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   699 		ParseCommonOptionalExtensionsL();
       
   700 		}
       
   701 	}
       
   702 
       
   703 /**
       
   704 body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart]
       
   705 This method deals with media-subtype [SP body-ext-mpart]
       
   706 
       
   707 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   708 
       
   709 It expects iAtomWalker to be positioned just prior to media-subtype.
       
   710 */
       
   711 void CImapBodyStructureBuilder::ParseRemainderMultipartL()
       
   712 	{
       
   713 	iAtomWalker->WalkAcrossL(ETrue);
       
   714 	
       
   715 	// media-subtype = string
       
   716 	iBodyStructure->SetSubType(iAtomWalker->CurrentDes(EFalse));
       
   717 	
       
   718 	// The remainder of items are optional.  Return as soon as one is not found.
       
   719 	
       
   720 	// body-fld-param
       
   721 	if (iAtomWalker->PeekAcross())
       
   722 		{
       
   723 		ParseBodyFieldParamsL(EFalse);
       
   724 		
       
   725 		// [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   726 		ParseCommonOptionalExtensionsL();		
       
   727 		}
       
   728 	}
       
   729 	
       
   730 /**
       
   731 body-ext-1part = body-fld-md5   [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   732 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   733 Apart from the first parameter, body extensions for 1 and multi part are the same.
       
   734 So this method parses them in one place.
       
   735 */
       
   736 void CImapBodyStructureBuilder::ParseCommonOptionalExtensionsL()
       
   737 	{
       
   738 	// Return as soon as a field is not found.
       
   739 	
       
   740 	// body-fld-dsp
       
   741 	if (iAtomWalker->PeekAcross())
       
   742 		{
       
   743 		ParseBodyFieldDispL();
       
   744 		
       
   745 		// body-fld-lang
       
   746 		if (iAtomWalker->PeekAcross())
       
   747 			{
       
   748 			ParseBodyFieldLangL();
       
   749 		
       
   750 			// body-fld-loc = nstring
       
   751 			if (iAtomWalker->WalkAcrossL(EFalse))
       
   752 				{
       
   753 				iBodyStructure->SetExtLocation(iAtomWalker->CurrentDes(ETrue));
       
   754 				
       
   755 				// *(SP body-extension)
       
   756 				if (iAtomWalker->PeekAcross())
       
   757 					{
       
   758 					ParseBodyExtensionL();
       
   759 					}
       
   760 				}
       
   761 			}
       
   762 		}
       
   763 	}
       
   764 	
       
   765 /**
       
   766 body-extension = nstring / number / "(" body-extension *(SP body-extension) ")"
       
   767 RFC3501 says:  "Future expansion. Client implementations
       
   768 				MUST accept body-extension fields. Server
       
   769 				implementations MUST NOT generate
       
   770 				body-extension fields except as defined by
       
   771 				future standard or standards-track
       
   772 				revisions of this specification.
       
   773 As body-extension is always at the end of a (sub)bodystructure, it is safe to ignore.
       
   774 This method provides a placeholder for extracting any body-extension data that we might 
       
   775 be interested in, in the future.
       
   776 */
       
   777 void CImapBodyStructureBuilder::ParseBodyExtensionL()
       
   778 	{}
       
   779 
       
   780 /**
       
   781 envelope = "(" env-date SP env-subject SP env-from SP env-sender SP env-reply-to SP env-to SP env-cc SP env-bcc SP env-in-reply-to SP env-message-id ")"
       
   782 
       
   783 This method expects iAtomWalker to be positioned at the opening bracket.
       
   784 */
       
   785 void CImapBodyStructureBuilder::ParseEnvelopeL()
       
   786 	{
       
   787 	// Always expect an open bracket here, so allow atom walker to leave if there is one
       
   788 	iAtomWalker->WalkAcrossL(ETrue);
       
   789 	iAtomWalker->WalkDownL();
       
   790 	
       
   791 	CImapEnvelope& envelope = iBodyStructure->GetRfc822EnvelopeStructureL();
       
   792 		
       
   793 	// env-date = nstring
       
   794 	envelope.SetEnvDate(iAtomWalker->CurrentDes(ETrue));
       
   795 	
       
   796 	// env-subject = nstring
       
   797 	iAtomWalker->WalkAcrossL(ETrue);
       
   798 	envelope.SetEnvSubject(iAtomWalker->CurrentDes(ETrue));
       
   799 	
       
   800 	// This single address structure will be *copied* into various envelope address arrays
       
   801 	CImapEnvelope::TAddress address; // this will copied into many en
       
   802 	
       
   803 	// env-from = "(" 1*address ")" / nil
       
   804 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   805 		{
       
   806 		iAtomWalker->WalkDownL();
       
   807 		do
       
   808 			{
       
   809 			ParseAddressL(address);
       
   810 			envelope.AppendEnvFromL(address);
       
   811 			
       
   812 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   813 		
       
   814 		iAtomWalker->WalkUpL();
       
   815 		}
       
   816 		
       
   817 	// env-sender = "(" 1*address ")" / nil
       
   818 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   819 		{
       
   820 		iAtomWalker->WalkDownL();
       
   821 		do
       
   822 			{
       
   823 			ParseAddressL(address);
       
   824 			envelope.AppendEnvSenderL(address);
       
   825 			
       
   826 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   827 		
       
   828 		iAtomWalker->WalkUpL();
       
   829 		}
       
   830 	// env-reply-to = "(" 1*address ")" / nil
       
   831 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   832 		{
       
   833 		iAtomWalker->WalkDownL();
       
   834 		do
       
   835 			{
       
   836 			ParseAddressL(address);
       
   837 			envelope.AppendEnvReplyToL(address);
       
   838 			
       
   839 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   840 		
       
   841 		iAtomWalker->WalkUpL();
       
   842 		}
       
   843 		
       
   844 	// env-to = "(" 1*address ")" / nil
       
   845 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   846 		{
       
   847 		iAtomWalker->WalkDownL();
       
   848 		do
       
   849 			{
       
   850 			ParseAddressL(address);
       
   851 			envelope.AppendEnvToL(address);
       
   852 			
       
   853 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   854 		
       
   855 		iAtomWalker->WalkUpL();
       
   856 		}
       
   857 		
       
   858 	// env-cc = "(" 1*address ")" / nil
       
   859 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   860 		{
       
   861 		iAtomWalker->WalkDownL();
       
   862 		do
       
   863 			{
       
   864 			ParseAddressL(address);
       
   865 			envelope.AppendEnvCcL(address);
       
   866 			
       
   867 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   868 		
       
   869 		iAtomWalker->WalkUpL();
       
   870 		}
       
   871 		
       
   872 	// env-bcc = "(" 1*address ")" / nil
       
   873 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   874 		{
       
   875 		iAtomWalker->WalkDownL();
       
   876 		do
       
   877 			{
       
   878 			ParseAddressL(address);
       
   879 			envelope.AppendEnvBccL(address);
       
   880 			
       
   881 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   882 		
       
   883 		iAtomWalker->WalkUpL();
       
   884 		}
       
   885 	
       
   886 	// env-in-reply-to = nstring
       
   887 	iAtomWalker->WalkAcrossL(ETrue);
       
   888 	envelope.SetEnvInReplyTo(iAtomWalker->CurrentDes(ETrue));
       
   889 	
       
   890 	// env-message-id = nstring	
       
   891 	iAtomWalker->WalkAcrossL(ETrue);
       
   892 	envelope.SetEnvMessageId(iAtomWalker->CurrentDes(ETrue));
       
   893 	
       
   894 	iAtomWalker->WalkUpL();
       
   895 	}
       
   896 
       
   897 /**
       
   898 address = "(" addr-name SP addr-adl SP addr-mailbox SP addr-host ")"
       
   899 
       
   900 This method expects iAtomWalker to be positioned at the opening bracket.
       
   901 */
       
   902 void CImapBodyStructureBuilder::ParseAddressL(CImapEnvelope::TAddress& aAddress)
       
   903 	{
       
   904 	// Always expect an open bracket here, so allow atom walker to leave if there is one
       
   905 	iAtomWalker->WalkDownL();
       
   906 	
       
   907 	// addr-name = nstring
       
   908 	aAddress.SetName(iAtomWalker->CurrentDes(ETrue));
       
   909 	
       
   910 	// addr-adl = nstring
       
   911 	iAtomWalker->WalkAcrossL(ETrue);
       
   912 	aAddress.SetAdl(iAtomWalker->CurrentDes(ETrue));
       
   913 	
       
   914 	// addr-mailbox = nstring
       
   915 	iAtomWalker->WalkAcrossL(ETrue);
       
   916 	aAddress.SetMailbox(iAtomWalker->CurrentDes(ETrue));
       
   917 	
       
   918 	// addr-host = nstring
       
   919 	iAtomWalker->WalkAcrossL(ETrue);
       
   920 	aAddress.SetHost(iAtomWalker->CurrentDes(ETrue));
       
   921 	
       
   922 	iAtomWalker->WalkUpL();
       
   923 	}