email/imap4mtm/imapsession/src/cimapbodystructurebuilder.cpp
changeset 31 ebfee66fde93
parent 0 72b543305e3a
child 33 94cccd85bd25
child 40 224522e33db9
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     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 				ParseBodyTypeMessageRfc822L();
       
   220 				parseStep = EParseNewBodyStructure;
       
   221 				}
       
   222 				break;
       
   223 			case EParseRemainderMessageRfc822:
       
   224 				{
       
   225 				// Just finished parsing the embedded bodystructure of a "MESSAGE/RFC822".
       
   226 				// Complete parsing the parent MESSAGE/RFC822 structure here.
       
   227 				ParseRemainderMessageRfc822L();
       
   228 				ParseBodyExt1PartL();
       
   229 				parseStep = EParseSubStructureComplete;
       
   230 				}
       
   231 				break;
       
   232 			case EParseRemainderMultipart:
       
   233 				{
       
   234 				// Just finished parsing the final embedded bodystructure of a MULTIPART structure.
       
   235 				// Complete parsing the parent MULTIPART structure here
       
   236 				ParseRemainderMultipartL();
       
   237 				parseStep = EParseSubStructureComplete;
       
   238 				}
       
   239 				break;
       
   240 			case EParseSubStructureComplete:
       
   241 				{
       
   242 				// Just finished parsing a bodystructure.
       
   243 				// If it is the root bodystructure then we are complete.
       
   244 				// Otherwise, let ParseSubStructureCompleteL() will find out whether it is
       
   245 				// * embedded in a MESSAGE/RFC822 structure - requiring the remainder to be parsed next: EParseRemainderMessageRfc822
       
   246 				// * embedded in a MULTIPART structure in which case
       
   247 				//   > either there is another embedded structure next: EParseNewBodyStructure
       
   248 				//   > or this is the last embedded structure, so we need to parse the multipart remainder: EParseRemainderMultipart
       
   249 					
       
   250 				if (PopBodyStructureL())
       
   251 					{
       
   252 					// we were actually in the root, so we are fully complete.
       
   253 					parseStep = EParseComplete;
       
   254 					}
       
   255 				else
       
   256 					{
       
   257 					// we were in a genuine substructure, so need to walk up and decide what to do.
       
   258 					parseStep = ParseSubStructureCompleteL();
       
   259 					}				
       
   260 				}
       
   261 				break;
       
   262 			default:
       
   263 				{
       
   264 				// This is an internal programming error.
       
   265 				__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidParseStep));
       
   266 				User::Leave(KErrGeneral); // avoid an infinite loop.
       
   267 				}
       
   268 			}
       
   269 		}
       
   270 	}
       
   271 
       
   272 /**
       
   273 When the parse loop comes across a new root or embedded bodystructure, it will use this method to...
       
   274   > Create a new CImapBodyStructure object to represent the bodystructure
       
   275   > Push the object onto the stack and make it "current"
       
   276   > Associate an embedded bodystructure with its parent.
       
   277 
       
   278 */
       
   279 void CImapBodyStructureBuilder::PushNewBodyStructureL()
       
   280 	{
       
   281 	// Going to create a new body structure.
       
   282 	// Need to be sure that something (either the stack root or its tree)
       
   283 	// is going to own and ultimatelty destroy it.
       
   284 	__ASSERT_DEBUG(iBodyStructureOwned, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderRootNotOwned));
       
   285 	
       
   286 	CImapBodyStructure* bodyStructure = CImapBodyStructure::NewL();
       
   287 	CleanupStack::PushL(bodyStructure);
       
   288 	
       
   289 	// root bodystructure is iBodyStructureStack[0]
       
   290 	if (iBodyStructure == NULL)
       
   291 		{
       
   292 		// Check for internal programming error
       
   293 		__ASSERT_DEBUG(iBodyStructureStack.Count() == 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackNotEmpty));
       
   294 		
       
   295 		iBodyStructureStack.AppendL(bodyStructure);
       
   296 		
       
   297 		// ownership is now transferred to the root bodystructure tree
       
   298 		CleanupStack::Pop(bodyStructure);
       
   299 		}
       
   300 	else
       
   301 		{
       
   302 		// Check for internal programming error
       
   303 		__ASSERT_DEBUG(iBodyStructureStack.Count() > 0, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderStackIsEmpty));
       
   304 		
       
   305 		iBodyStructure->AppendEmbeddedBodyStructureL(*bodyStructure);
       
   306 										
       
   307 		// ownership is now transferred to the root bodystructure tree
       
   308 		CleanupStack::Pop(bodyStructure);
       
   309 		
       
   310 		iBodyStructureStack.AppendL(bodyStructure);
       
   311 		}
       
   312 	
       
   313 	// This is now the bodystructure that we are parsing.
       
   314 	iBodyStructure = bodyStructure;
       
   315 	}
       
   316 
       
   317 /**
       
   318 Pops a bodystructure from the stack - except the root, which will not be popped.
       
   319 @return whether we were in the root already.
       
   320 */	
       
   321 TBool CImapBodyStructureBuilder::PopBodyStructureL()
       
   322 	{
       
   323 	TBool bRootAlready = EFalse;
       
   324 	TInt stackCount = iBodyStructureStack.Count();
       
   325 
       
   326 	if (stackCount > 1)
       
   327 		{
       
   328 		// Pop the bodystructure stack
       
   329 		--stackCount;
       
   330 		CImapBodyStructure* poppedBs = iBodyStructureStack[stackCount];
       
   331 		iBodyStructureStack.Remove(stackCount); // No need to destroy the bodystructure, as it is now owned by iBodyStructureStack[stackCount-1]
       
   332 		
       
   333 		iBodyStructure = iBodyStructureStack[stackCount-1];
       
   334 		}
       
   335 	else
       
   336 		{
       
   337 		// Check for internal programming error: Not expecting a stack count of 0 or less
       
   338 		__ASSERT_DEBUG(stackCount == 1, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderExpectedRootAtomOnlyOnStack));
       
   339 		bRootAlready = ETrue;
       
   340 		}
       
   341 		
       
   342 	return bRootAlready;
       
   343 	}
       
   344 
       
   345 /**
       
   346 Found the closing bracket of our substructure.
       
   347 Pop the stack, walk up and decide what to do next.
       
   348 If we've reached the root level, then parsing is complete.
       
   349 If our parent is a multipart, then check to see if we have a sibling.  
       
   350 	If not then we have come to the end of our parent's structure too - handle this in a separate loop.
       
   351 If our parent is a Rfc822, then we need to parse the remainder of the Rfc822 structure.
       
   352 	If not then we have come to the end of our parent's structure too - handle this in a separate loop.
       
   353 @return 
       
   354 */
       
   355 CImapBodyStructureBuilder::TParseStep CImapBodyStructureBuilder::ParseSubStructureCompleteL()
       
   356 	{
       
   357 	TParseStep nextStep = EParseComplete;
       
   358 	
       
   359 	iAtomWalker->WalkUpL();
       
   360 	
       
   361 	if (iBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeMultipart)
       
   362 		{
       
   363 		// Expecting either an open bracket for another bodystructure
       
   364 		// or the subtype. 
       
   365 		CImapAtom* peekAcross = iAtomWalker->PeekAcross(); // peekAcross does not need to be destroyed as no ownership is transferred.
       
   366 		if (peekAcross == NULL)
       
   367 			{
       
   368 			// But not expecting "nothing".
       
   369 			CImapCommand::CorruptDataL(iLogId);
       
   370 			}
       
   371 		
       
   372 		if (peekAcross->Match(KImapTxtOpenBracket()))
       
   373 			{
       
   374 			// position the atom walker on the open bracket, ready for ParseBodyStructureTypeL
       
   375 			// to walk down into it.
       
   376 			iAtomWalker->WalkAcrossL(ETrue);
       
   377 			nextStep = EParseNewBodyStructure;
       
   378 			}
       
   379 		else
       
   380 			{
       
   381 			// stay where we are, so that ParseRemainderMultipartL()
       
   382 			// can walk accross to the subtype, as any other Parse method would do
       
   383 			nextStep = EParseRemainderMultipart;
       
   384 			}
       
   385 		}
       
   386 	else if (iBodyStructure->BodyStructureType() == CImapBodyStructure::ETypeMessageRfc822)
       
   387 		{
       
   388 		// stay where we are, so that ParseRemainderMessageRfc822L()
       
   389 		// can walk accross to the body-fld-lines, as any other Parse method would do
       
   390 		nextStep = EParseRemainderMessageRfc822;
       
   391 		}
       
   392 	else
       
   393 		{
       
   394 		// No other bodystruct type has substructures.
       
   395 		// So getting here is an internal programming error.
       
   396 		__ASSERT_DEBUG(EFalse, TImapServerPanic::ImapPanic(TImapServerPanic::EBodyStructureBuilderInvalidBodyStructureType));
       
   397 		User::Leave(KErrGeneral);
       
   398 		}
       
   399 			
       
   400 	return nextStep;
       
   401 	}
       
   402 
       
   403 /**
       
   404 body = "(" (body-type-1part / body-type-mpart) ")"
       
   405 
       
   406 This method expects iAtomWalker to be positioned at the opening bracket of a body structure.
       
   407 The method works out the type of the bodystructure, and returns the appropriate next parse 
       
   408 step to the parse loop.
       
   409 For multipart structures, iAtomWalker is left positioned at the opening bracket of the embedded structure.
       
   410 Foa all other structures, iAtomWalker is left positioned at the subtype field.
       
   411 
       
   412 @return The next step for the parse loop to take.  This is one of
       
   413   > EParseNewBodyStructure for MULTIPART structures
       
   414   > EParseText for TEXT structures
       
   415   > EParseBodyTypeMessageRfc822 for MESSAGE/RFC822
       
   416   > EParseBasic for all other structures.
       
   417 */
       
   418 CImapBodyStructureBuilder::TParseStep CImapBodyStructureBuilder::ParseBodyStructureTypeL()
       
   419 	{
       
   420 	// Start at the opening bracket
       
   421 	__ASSERT_ALWAYS(iAtomWalker->CurrentMatch(KImapTxtOpenBracket()), CImapCommand::CorruptDataL(iLogId));
       
   422 	iAtomWalker->WalkDownL();
       
   423 		
       
   424 	// What kind of body type does this represent?	
       
   425 	// Assume Basic, unless we find otherwise.
       
   426 	TParseStep nextStep = EParseBasic;
       
   427 	
       
   428 	// Is it body-type-mpart? - check for opening bracket
       
   429 	// body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart]
       
   430 	if (iAtomWalker->CurrentMatch(KImapTxtOpenBracket()))
       
   431 		{
       
   432 		// According to section 6.4.5 of RFC3501, "MULTIPART" is the correct Type string for
       
   433 		// multipart messages.  This is an implicit value not directly available from the
       
   434 		// bodystructure input string.  So we point the bodystructure object at a constant string instead.
       
   435 		iBodyStructure->SetType(KImapTxtMultipart());
       
   436 		
       
   437 		iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeMultipart);
       
   438 		nextStep = EParseNewBodyStructure;
       
   439 		}
       
   440 	else
       
   441 		{
       
   442 		// body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part]
       
   443 		iBodyStructure->SetType(iAtomWalker->CurrentDes(EFalse)); // media-basic and variants is a string, not an nstring
       
   444 		__ASSERT_ALWAYS(iAtomWalker->PeekDown() == NULL, CImapCommand::CorruptDataL(iLogId));
       
   445 		
       
   446 		iAtomWalker->WalkAcrossL(ETrue);
       
   447 		iBodyStructure->SetSubType(iAtomWalker->CurrentDes(EFalse)); // media-subtype and variants is a string, not an nstring
       
   448 		
       
   449 		if (iBodyStructure->Type().CompareF(KImapTxtText())==0)
       
   450 		// body-type-text = media-text SP body-fields SP body-fld-lines
       
   451 		// 
       
   452 		// media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
       
   453 		// media-subtype = string
       
   454 			{
       
   455 			// we have media-text...
       
   456 			// ... so this is body-type-text
       
   457 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeText);
       
   458 			nextStep = EParseText;
       
   459 			}
       
   460 		else if (iBodyStructure->Type().CompareF(KImapTxtMessage())==0 && iBodyStructure->SubType().CompareF(KImapTxtRfc822())==0)
       
   461 		// body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines
       
   462 		// 
       
   463 		// media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
       
   464 			{
       
   465 			// we have media-message...
       
   466 			// ... so this is body-type-msg
       
   467 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeMessageRfc822);
       
   468 			nextStep = EParseBodyTypeMessageRfc822;
       
   469 			}
       
   470 		else
       
   471 			{
       
   472 			// Not multipart, text or rfc822, so must be basic.
       
   473 			iBodyStructure->SetBodyStructureType(CImapBodyStructure::ETypeBasic);
       
   474 			}
       
   475 		}
       
   476 		
       
   477 	return nextStep;	
       
   478 	}
       
   479 	
       
   480 /**
       
   481 body-type-basic = media-basic SP body-fields
       
   482 
       
   483 This method expects media-basict to have been parsed already, as part of ParseBodyStructureTypeL()
       
   484 It expects the atom walker to be positioned at the last atom of media-basic
       
   485 */
       
   486 void CImapBodyStructureBuilder::ParseBodyTypeBasicL()
       
   487 	{
       
   488 	// body-fields
       
   489 	ParseBodyFieldsL();
       
   490 	}
       
   491 	
       
   492 /**
       
   493 body-type-text = media-text SP body-fields SP body-fld-lines
       
   494 
       
   495 This method expects media-text to have been parsed already, as part of ParseBodyStructureTypeL()
       
   496 It expects the atom walker to be positioned at the last atom of media-text
       
   497 */
       
   498 void CImapBodyStructureBuilder::ParseBodyTypeTextL()
       
   499 	{
       
   500 	// body-fields
       
   501 	ParseBodyFieldsL();
       
   502 	
       
   503 	// body-fld-lines = number
       
   504 	iAtomWalker->WalkAcrossL(ETrue);
       
   505 	iBodyStructure->SetBodyLines(iAtomWalker->CurrentDes(EFalse));
       
   506 	}
       
   507 	
       
   508 /**
       
   509 body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines
       
   510 
       
   511 This method parses up to and including envelope.
       
   512 It then returns, allowing the parse loop to parse the nested "body" that is next.
       
   513 Upon completion of the nested "body", ParseRemainderMessageRfc822L() will be called to finish parsing
       
   514 the message body type
       
   515 
       
   516 This method expects media-message to have been parsed already, as part of ParseBodyStructureTypeL()
       
   517 It expects the atom walker to be positioned at the last atom of media-text
       
   518 */
       
   519 void CImapBodyStructureBuilder::ParseBodyTypeMessageRfc822L()
       
   520 	{
       
   521 	// body-fields SP SP body SP body-fld-lines
       
   522 	ParseBodyFieldsL();
       
   523 	
       
   524 	// envelope
       
   525 	ParseEnvelopeL();
       
   526 	
       
   527 	// Expect a body substructure next.
       
   528 	// Position iAtomWalker at the opening bracket, ready for ParseBodyStructureTypeL
       
   529 	iAtomWalker->WalkAcrossL(ETrue);
       
   530 	}
       
   531 
       
   532 /**
       
   533 body-type-msg = media-message SP body-fields SP envelope SP body SP body-fld-lines
       
   534 
       
   535 ParseBodyTypeMessageRfc822L processes up to and including body-fields.
       
   536 The ParseLoop processes the nested "body"
       
   537 This method processes the remainder - i.e. body-fld-lines
       
   538 It expects the atom walker to be positioned at the field just prior to body-fld-lines
       
   539 */
       
   540 void CImapBodyStructureBuilder::ParseRemainderMessageRfc822L()
       
   541 	{
       
   542 	// body-fld-lines = number
       
   543 	iAtomWalker->WalkAcrossL(ETrue);
       
   544 	iBodyStructure->SetBodyLines(iAtomWalker->CurrentDes(EFalse));
       
   545 	}
       
   546 
       
   547 /**
       
   548 body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP body-fld-enc SP body-fld-octets	
       
   549 
       
   550 This method expects iAtomWalker to be positioned just prior to body-fld-param
       
   551 */
       
   552 void CImapBodyStructureBuilder::ParseBodyFieldsL()
       
   553 	{
       
   554 	ParseBodyFieldParamsL(EFalse);
       
   555 	
       
   556 	// body-fld-id = nstring
       
   557 	iAtomWalker->WalkAcrossL(EFalse);
       
   558 	iBodyStructure->SetBodyId(iAtomWalker->CurrentDes(ETrue)); 
       
   559 	
       
   560 	// body-fld-desc = nstring
       
   561 	iAtomWalker->WalkAcrossL(EFalse);
       
   562 	iBodyStructure->SetBodyDescription(iAtomWalker->CurrentDes(ETrue));
       
   563 	
       
   564 	// body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/ "QUOTED-PRINTABLE") DQUOTE) / string
       
   565 	// i.e. it's a string that might be in quotes
       
   566 	iAtomWalker->WalkAcrossL(EFalse);
       
   567 	iBodyStructure->SetBodyEncoding(iAtomWalker->CurrentDes(EFalse));
       
   568 	
       
   569 	// body-fld-octets = number
       
   570 	iAtomWalker->WalkAcrossL(EFalse);
       
   571 	iBodyStructure->SetBodySizeOctets(iAtomWalker->CurrentDes(EFalse));
       
   572 	}
       
   573 	
       
   574 /**
       
   575 body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
       
   576 
       
   577 This method expects iAtomWalker to be positioned just prior to the "(" or "NIL" atom.
       
   578 */
       
   579 void CImapBodyStructureBuilder::ParseBodyFieldParamsL(TBool aStoreAsDisposition)
       
   580 
       
   581 	{
       
   582 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomNil)
       
   583 		{
       
   584 		// there are no params
       
   585 		return;
       
   586 		}
       
   587 	
       
   588 	// Consume the bracket
       
   589 	iAtomWalker->WalkDownL();
       
   590 	
       
   591 	do 
       
   592 		{
       
   593 		CImapBodyStructure::TAttributeValuePair pair;
       
   594 		pair.iAttribute.Set(iAtomWalker->CurrentDes(EFalse));
       
   595 		
       
   596 		iAtomWalker->WalkAcrossL(ETrue);
       
   597 		pair.iValue.Set(iAtomWalker->CurrentDes(EFalse));
       
   598 		
       
   599 		if (aStoreAsDisposition)
       
   600 			{
       
   601 			iBodyStructure->AppendExtDispositionParameterListL(pair);	
       
   602 			}
       
   603 		else
       
   604 			{
       
   605 			iBodyStructure->AppendParameterListL(pair);
       
   606 			}		
       
   607 		} 
       
   608 		while (iAtomWalker->WalkAcrossL(EFalse));
       
   609 		
       
   610 	iAtomWalker->WalkUpL();
       
   611 	}
       
   612 
       
   613 /** 
       
   614 body-fld-dsp = "(" string SP body-fld-param ")" / nil
       
   615 
       
   616 This method expects iAtomWalker to be positioned just prior to the "(" or "NIL" atom.
       
   617 */
       
   618 void CImapBodyStructureBuilder::ParseBodyFieldDispL()
       
   619 	{
       
   620 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomNil)
       
   621 		{
       
   622 		// there are no params
       
   623 		return;
       
   624 		}
       
   625 		
       
   626 	iAtomWalker->WalkDownL();
       
   627 	
       
   628 	// string
       
   629 	iBodyStructure->SetExtDispositionName(iAtomWalker->CurrentDes(EFalse));
       
   630 	
       
   631 	// body-fld-param
       
   632 	ParseBodyFieldParamsL(ETrue);
       
   633 	
       
   634 	iAtomWalker->WalkUpL();	
       
   635 	}
       
   636 	
       
   637 /**
       
   638 body-fld-lang = nstring / "(" string *(SP string) ")"
       
   639 
       
   640 This method should only be called if body-fld-lang is expected.
       
   641 The caller should check first, using iAtomWalker->PeekAcross()
       
   642 */
       
   643 void CImapBodyStructureBuilder::ParseBodyFieldLangL()
       
   644 	{
       
   645 	// Consume the bracket
       
   646 	iAtomWalker->WalkAcrossL(ETrue);
       
   647 	
       
   648 	if (iAtomWalker->CurrentMatch(KImapTxtOpenBracket()))
       
   649 		{
       
   650 		// we have many strings
       
   651 		// "(" string *(SP string) ")"
       
   652 		
       
   653 		iAtomWalker->WalkDownL();
       
   654 				
       
   655 		do 
       
   656 			{
       
   657 			iBodyStructure->AppendExtLanguageListL(iAtomWalker->CurrentDes(EFalse));
       
   658 			
       
   659 			} while (iAtomWalker->WalkAcrossL(EFalse));
       
   660 		
       
   661 		iAtomWalker->WalkUpL();
       
   662 		}
       
   663 	else 
       
   664 		{
       
   665 		// we have a single nstring - only add it if it is non-empty
       
   666 		const TDesC8& language = iAtomWalker->CurrentDes(ETrue);
       
   667 		if (language.Length() > 0)
       
   668 			{
       
   669 			iBodyStructure->AppendExtLanguageListL(language);	
       
   670 			}		
       
   671 		}
       
   672 	}
       
   673 
       
   674 /**
       
   675 body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   676 
       
   677 This only appears in
       
   678 body-type-1part = (body-type-basic / body-type-msg / body-type-text) [SP body-ext-1part]
       
   679 So, this method treats the body-fld-md5 field as optional
       
   680 */
       
   681 void CImapBodyStructureBuilder::ParseBodyExt1PartL()
       
   682 	{
       
   683 	// Return as soon as a field is not found.
       
   684 	if (iAtomWalker->WalkAcrossL(EFalse))
       
   685 		{
       
   686 		// body-fld-md5 = nstring
       
   687 		iBodyStructure->SetExtMD5(iAtomWalker->CurrentDes(ETrue));
       
   688 		
       
   689 		// [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   690 		ParseCommonOptionalExtensionsL();
       
   691 		}
       
   692 	}
       
   693 
       
   694 /**
       
   695 body-type-mpart = 1*body SP media-subtype [SP body-ext-mpart]
       
   696 This method deals with media-subtype [SP body-ext-mpart]
       
   697 
       
   698 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   699 
       
   700 It expects iAtomWalker to be positioned just prior to media-subtype.
       
   701 */
       
   702 void CImapBodyStructureBuilder::ParseRemainderMultipartL()
       
   703 	{
       
   704 	iAtomWalker->WalkAcrossL(ETrue);
       
   705 	
       
   706 	// media-subtype = string
       
   707 	iBodyStructure->SetSubType(iAtomWalker->CurrentDes(EFalse));
       
   708 	
       
   709 	// The remainder of items are optional.  Return as soon as one is not found.
       
   710 	
       
   711 	// body-fld-param
       
   712 	if (iAtomWalker->PeekAcross())
       
   713 		{
       
   714 		ParseBodyFieldParamsL(EFalse);
       
   715 		
       
   716 		// [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   717 		ParseCommonOptionalExtensionsL();		
       
   718 		}
       
   719 	}
       
   720 	
       
   721 /**
       
   722 body-ext-1part = body-fld-md5   [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   723 body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang [SP body-fld-loc *(SP body-extension)]]]
       
   724 Apart from the first parameter, body extensions for 1 and multi part are the same.
       
   725 So this method parses them in one place.
       
   726 */
       
   727 void CImapBodyStructureBuilder::ParseCommonOptionalExtensionsL()
       
   728 	{
       
   729 	// Return as soon as a field is not found.
       
   730 	
       
   731 	// body-fld-dsp
       
   732 	if (iAtomWalker->PeekAcross())
       
   733 		{
       
   734 		ParseBodyFieldDispL();
       
   735 		
       
   736 		// body-fld-lang
       
   737 		if (iAtomWalker->PeekAcross())
       
   738 			{
       
   739 			ParseBodyFieldLangL();
       
   740 		
       
   741 			// body-fld-loc = nstring
       
   742 			if (iAtomWalker->WalkAcrossL(EFalse))
       
   743 				{
       
   744 				iBodyStructure->SetExtLocation(iAtomWalker->CurrentDes(ETrue));
       
   745 				
       
   746 				// *(SP body-extension)
       
   747 				if (iAtomWalker->PeekAcross())
       
   748 					{
       
   749 					ParseBodyExtensionL();
       
   750 					}
       
   751 				}
       
   752 			}
       
   753 		}
       
   754 	}
       
   755 	
       
   756 /**
       
   757 body-extension = nstring / number / "(" body-extension *(SP body-extension) ")"
       
   758 RFC3501 says:  "Future expansion. Client implementations
       
   759 				MUST accept body-extension fields. Server
       
   760 				implementations MUST NOT generate
       
   761 				body-extension fields except as defined by
       
   762 				future standard or standards-track
       
   763 				revisions of this specification.
       
   764 As body-extension is always at the end of a (sub)bodystructure, it is safe to ignore.
       
   765 This method provides a placeholder for extracting any body-extension data that we might 
       
   766 be interested in, in the future.
       
   767 */
       
   768 void CImapBodyStructureBuilder::ParseBodyExtensionL()
       
   769 	{}
       
   770 
       
   771 /**
       
   772 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 ")"
       
   773 
       
   774 This method expects iAtomWalker to be positioned at the opening bracket.
       
   775 */
       
   776 void CImapBodyStructureBuilder::ParseEnvelopeL()
       
   777 	{
       
   778 	// Always expect an open bracket here, so allow atom walker to leave if there is one
       
   779 	iAtomWalker->WalkAcrossL(ETrue);
       
   780 	iAtomWalker->WalkDownL();
       
   781 	
       
   782 	CImapEnvelope& envelope = iBodyStructure->GetRfc822EnvelopeStructureL();
       
   783 		
       
   784 	// env-date = nstring
       
   785 	envelope.SetEnvDate(iAtomWalker->CurrentDes(ETrue));
       
   786 	
       
   787 	// env-subject = nstring
       
   788 	iAtomWalker->WalkAcrossL(ETrue);
       
   789 	envelope.SetEnvSubject(iAtomWalker->CurrentDes(ETrue));
       
   790 	
       
   791 	// This single address structure will be *copied* into various envelope address arrays
       
   792 	CImapEnvelope::TAddress address; // this will copied into many en
       
   793 	
       
   794 	// env-from = "(" 1*address ")" / nil
       
   795 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   796 		{
       
   797 		iAtomWalker->WalkDownL();
       
   798 		do
       
   799 			{
       
   800 			ParseAddressL(address);
       
   801 			envelope.AppendEnvFromL(address);
       
   802 			
       
   803 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   804 		
       
   805 		iAtomWalker->WalkUpL();
       
   806 		}
       
   807 		
       
   808 	// env-sender = "(" 1*address ")" / nil
       
   809 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   810 		{
       
   811 		iAtomWalker->WalkDownL();
       
   812 		do
       
   813 			{
       
   814 			ParseAddressL(address);
       
   815 			envelope.AppendEnvSenderL(address);
       
   816 			
       
   817 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   818 		
       
   819 		iAtomWalker->WalkUpL();
       
   820 		}
       
   821 	// env-reply-to = "(" 1*address ")" / nil
       
   822 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   823 		{
       
   824 		iAtomWalker->WalkDownL();
       
   825 		do
       
   826 			{
       
   827 			ParseAddressL(address);
       
   828 			envelope.AppendEnvReplyToL(address);
       
   829 			
       
   830 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   831 		
       
   832 		iAtomWalker->WalkUpL();
       
   833 		}
       
   834 		
       
   835 	// env-to = "(" 1*address ")" / nil
       
   836 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   837 		{
       
   838 		iAtomWalker->WalkDownL();
       
   839 		do
       
   840 			{
       
   841 			ParseAddressL(address);
       
   842 			envelope.AppendEnvToL(address);
       
   843 			
       
   844 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   845 		
       
   846 		iAtomWalker->WalkUpL();
       
   847 		}
       
   848 		
       
   849 	// env-cc = "(" 1*address ")" / nil
       
   850 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   851 		{
       
   852 		iAtomWalker->WalkDownL();
       
   853 		do
       
   854 			{
       
   855 			ParseAddressL(address);
       
   856 			envelope.AppendEnvCcL(address);
       
   857 			
       
   858 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   859 		
       
   860 		iAtomWalker->WalkUpL();
       
   861 		}
       
   862 		
       
   863 	// env-bcc = "(" 1*address ")" / nil
       
   864 	if (iAtomWalker->WalkAcrossToNilOrOpenL() == CImapAtomWalker::EAtomOpen)
       
   865 		{
       
   866 		iAtomWalker->WalkDownL();
       
   867 		do
       
   868 			{
       
   869 			ParseAddressL(address);
       
   870 			envelope.AppendEnvBccL(address);
       
   871 			
       
   872 			} while(iAtomWalker->WalkAcrossL(EFalse));
       
   873 		
       
   874 		iAtomWalker->WalkUpL();
       
   875 		}
       
   876 	
       
   877 	// env-in-reply-to = nstring
       
   878 	iAtomWalker->WalkAcrossL(ETrue);
       
   879 	envelope.SetEnvInReplyTo(iAtomWalker->CurrentDes(ETrue));
       
   880 	
       
   881 	// env-message-id = nstring	
       
   882 	iAtomWalker->WalkAcrossL(ETrue);
       
   883 	envelope.SetEnvMessageId(iAtomWalker->CurrentDes(ETrue));
       
   884 	
       
   885 	iAtomWalker->WalkUpL();
       
   886 	}
       
   887 
       
   888 /**
       
   889 address = "(" addr-name SP addr-adl SP addr-mailbox SP addr-host ")"
       
   890 
       
   891 This method expects iAtomWalker to be positioned at the opening bracket.
       
   892 */
       
   893 void CImapBodyStructureBuilder::ParseAddressL(CImapEnvelope::TAddress& aAddress)
       
   894 	{
       
   895 	// Always expect an open bracket here, so allow atom walker to leave if there is one
       
   896 	iAtomWalker->WalkDownL();
       
   897 	
       
   898 	// addr-name = nstring
       
   899 	aAddress.SetName(iAtomWalker->CurrentDes(ETrue));
       
   900 	
       
   901 	// addr-adl = nstring
       
   902 	iAtomWalker->WalkAcrossL(ETrue);
       
   903 	aAddress.SetAdl(iAtomWalker->CurrentDes(ETrue));
       
   904 	
       
   905 	// addr-mailbox = nstring
       
   906 	iAtomWalker->WalkAcrossL(ETrue);
       
   907 	aAddress.SetMailbox(iAtomWalker->CurrentDes(ETrue));
       
   908 	
       
   909 	// addr-host = nstring
       
   910 	iAtomWalker->WalkAcrossL(ETrue);
       
   911 	aAddress.SetHost(iAtomWalker->CurrentDes(ETrue));
       
   912 	
       
   913 	iAtomWalker->WalkUpL();
       
   914 	}