simpleengine/xmlutils/src/simpledocument.cpp
changeset 0 c8caa15ef882
child 18 52d91a16fec3
equal deleted inserted replaced
-1:000000000000 0:c8caa15ef882
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:    Simple Engine
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 
       
    23 #include <e32def.h>           // First to avoid NULL redefine warning (no #ifndef NULL).
       
    24 #include <e32std.h>
       
    25 #include <string.h>
       
    26 
       
    27 #include <imcvcodc.h>
       
    28 
       
    29 // #include <e32std.h>
       
    30 #include <s32strm.h>
       
    31 #include <SenBaseElement.h>
       
    32 #include <SenBaseAttribute.h>
       
    33 #include <SenXmlUtils.h>
       
    34 #include <SenXmlReader.h>
       
    35 #include <SenDomFragment.h>
       
    36 
       
    37 #include <multipartparser.h>
       
    38 #include <bodypart.h>
       
    39 
       
    40 // own simple
       
    41 #include "simplecommon.h"
       
    42 #include "simpleelement.h"
       
    43 #include "simplenamespace.h"
       
    44 #include "simpleattribute.h"
       
    45 #include "simpledocument.h"
       
    46 #include "simplebasedocument.h"
       
    47 #include "simpleutils.h"
       
    48 #include "simplecontent.h"
       
    49 
       
    50 
       
    51 _LIT8 ( KSimpleEntity, "entity");
       
    52 
       
    53 // Multipart CONSTANTS
       
    54 
       
    55 const char Multipart_CRLF_Text[] = {"\r\n"};
       
    56 const char Multipart_DoubleCRLF_Text[] = {"\r\n\r\n"};
       
    57 
       
    58 // MACROS
       
    59 #define MULTIPART_CONTENT_LOCATION_LENGTH           17
       
    60 #define MULTIPART_CONTENT_TYPE_LENGTH               13
       
    61 #define MULTIPART_CONTENT_TRANSFER_ENCODING_LENGTH  26
       
    62 // violates RFC2045; but upon vodafone request
       
    63 #define MULTIPART_CONTENT_ENCODING_LENGTH           17
       
    64 #define MULTIPART_CONTENT_LENGTH_LENGTH             15
       
    65 #define MULTIPART_LAST_MODIFIED_LENGTH              14
       
    66 #define MULTIPART_CONTENT_ID_LENGTH                 11
       
    67 
       
    68 #define MULTIPART_CONTENT_LOCATION           2
       
    69 #define MULTIPART_CONTENT_TRANSFER_ENCODING  3
       
    70 #define MULTIPART_CONTENT_TYPE               4
       
    71 #define MULTIPART_CONTENT_ID                 5
       
    72 
       
    73 #define MULTIPART_INTERNET_DATE_STRING_LENGTH       29
       
    74 
       
    75 #define SLASH_CHAR    '/'
       
    76 #define DOT_CHAR      '.'
       
    77 #define AT_CHAR       '@'
       
    78 #define COLON_CHAR    ':'
       
    79 // <scheme>://
       
    80 // #define SCHEME_SEPARATOR_LENGTH               3
       
    81 // ================= MEMBER FUNCTIONS =======================
       
    82 //
       
    83 
       
    84 // ----------------------------------------------------------
       
    85 // CSimpleDocument::CSimpleDocument
       
    86 // ----------------------------------------------------------
       
    87 //
       
    88 CSimpleDocument::CSimpleDocument( )
       
    89 : CSimpleBaseDocument()
       
    90     {
       
    91     }
       
    92 
       
    93 // ----------------------------------------------------------
       
    94 // CSimpleDocument::~CSimpleDocument
       
    95 // ----------------------------------------------------------
       
    96 //
       
    97 CSimpleDocument::~CSimpleDocument()
       
    98     {
       
    99     iContents.ResetAndDestroy();
       
   100     iContents.Close();
       
   101     }
       
   102 
       
   103 // ----------------------------------------------------------
       
   104 // CSimpleDocument::ConstructL
       
   105 // ----------------------------------------------------------
       
   106 //
       
   107 void CSimpleDocument::ConstructL(
       
   108     const TDesC8& aNsUri,
       
   109     const TDesC8& aLocalName )
       
   110     {
       
   111     BaseConstructL(aNsUri, aLocalName);
       
   112     }
       
   113     
       
   114 // ----------------------------------------------------------
       
   115 // CSimpleDocument::ConstructMultiPartL
       
   116 // ----------------------------------------------------------
       
   117 //
       
   118 void CSimpleDocument::ConstructMultiPartL(
       
   119     const TDesC8& aData, const TDesC8& aBoundary, const TDesC8& aStart )
       
   120     {    
       
   121     _LIT(KUrl, "http://dummy.com/d1/d.html");
       
   122            
       
   123     // body part array
       
   124     RPointerArray<CBodyPart> bodyPartArray;
       
   125     TCleanupItem clItem( ResetAndDestroy, &bodyPartArray  );
       
   126     CleanupStack::PushL( clItem );
       
   127     
       
   128     // remove "..." characters from boundary if needed
       
   129     TPtrC8 pUnQuoted = aBoundary;
       
   130     TInt quoted = aBoundary.Locate('"');
       
   131     if (!quoted)
       
   132         {
       
   133         pUnQuoted.Set( aBoundary.Mid( 1, aBoundary.Length() - 2 ));
       
   134         } 
       
   135     // parse
       
   136     MultipartParser::ParseL( aData, KSimpleMultipartType, pUnQuoted, KUrl, bodyPartArray  );    
       
   137     DoConstructL( bodyPartArray, aStart );
       
   138    
       
   139     CleanupStack::PopAndDestroy( ); // bodyPartArray     
       
   140     }    
       
   141 
       
   142 // ----------------------------------------------------------
       
   143 // CSimpleDocument::ConstructL
       
   144 // ----------------------------------------------------------
       
   145 //
       
   146 void CSimpleDocument::ConstructL(
       
   147     const TDesC8& aXml )
       
   148     {
       
   149     BaseConstructL( aXml );
       
   150     }
       
   151 
       
   152 // ----------------------------------------------------------
       
   153 // CSimpleDocument::NewL
       
   154 // ----------------------------------------------------------
       
   155 //
       
   156 CSimpleDocument* CSimpleDocument::NewL( )
       
   157     {
       
   158     CSimpleDocument* self = new (ELeave) CSimpleDocument( );
       
   159     CleanupStack::PushL( self );
       
   160     self->ConstructL( KSimpleNsDefault, KDocumentLocalName );
       
   161     CleanupStack::Pop( self );
       
   162     return self;
       
   163     }
       
   164 
       
   165 // ----------------------------------------------------------
       
   166 // CSimpleDocument::NewL
       
   167 // ----------------------------------------------------------
       
   168 //
       
   169 CSimpleDocument* CSimpleDocument::NewL( const TDesC8& aXml )
       
   170     {
       
   171     CSimpleDocument* self = new (ELeave) CSimpleDocument( );
       
   172     CleanupStack::PushL( self );
       
   173     self->ConstructL( aXml );
       
   174     CleanupStack::Pop( self );
       
   175     return self;
       
   176     }
       
   177     
       
   178 // ----------------------------------------------------------
       
   179 // CSimpleDocument::NewInMultiPartL
       
   180 // ----------------------------------------------------------
       
   181 //
       
   182 CSimpleDocument* CSimpleDocument::NewInMultiPartL( 
       
   183     const TDesC8& aData, const TDesC8& aBoundary, const TDesC8& aStart )
       
   184     {
       
   185     CSimpleDocument* self = new (ELeave) CSimpleDocument( );
       
   186     CleanupStack::PushL( self );
       
   187     self->ConstructMultiPartL( aData, aBoundary, aStart );
       
   188     CleanupStack::Pop( self );
       
   189     return self;
       
   190     } 
       
   191     
       
   192 // ----------------------------------------------------------
       
   193 // CSimpleDocument::GetDirectContentsL
       
   194 // ----------------------------------------------------------
       
   195 //
       
   196 void CSimpleDocument::GetDirectContentsL( 
       
   197     RPointerArray<MSimpleContent>& aContents )
       
   198     {
       
   199     aContents.Reset();
       
   200     TInt myCount = iContents.Count();
       
   201     for ( TInt i = 0; i<myCount; i++ )
       
   202         {
       
   203         User::LeaveIfError( aContents.Append( iContents[i] ));
       
   204         }               
       
   205     }
       
   206     
       
   207 // ----------------------------------------------------------
       
   208 // CSimpleDocument::AddDirectContentL
       
   209 // ----------------------------------------------------------
       
   210 //    
       
   211 void CSimpleDocument::AddDirectContentL( 
       
   212     MSimpleContent& aContent,
       
   213     TBool aCopyContent )
       
   214     {
       
   215     CSimpleContent* content = CSimpleContent::NewLC(
       
   216         aContent.ContentID(), aContent.ContentType());
       
   217     User::LeaveIfError( iContents.Append( content ));
       
   218     CleanupStack::Pop( content );
       
   219     
       
   220     if ( aCopyContent )
       
   221         {
       
   222         content->CopyBodyL( aContent.Body() );
       
   223         }
       
   224     else
       
   225         {
       
   226         content->SetBody( aContent.GiveBodyOwnerShip() );
       
   227         }                       
       
   228     }
       
   229     
       
   230 // ----------------------------------------------------------
       
   231 // CSimpleDocument::ValidateXmlL
       
   232 // ----------------------------------------------------------
       
   233 //
       
   234 void CSimpleDocument::ValidateXmlL( const TDesC8& aName )
       
   235     {
       
   236     if ( aName.CompareF( KDocumentLocalName ) )
       
   237         {
       
   238         User::Leave( KErrCorrupt );
       
   239         }
       
   240     }
       
   241 
       
   242 // ----------------------------------------------------------
       
   243 // CSimpleDocument::EntityURI
       
   244 // ----------------------------------------------------------
       
   245 //
       
   246 const TDesC8* CSimpleDocument::EntityURI()
       
   247     {
       
   248     return Root()->AttrValue( KSimpleEntity );
       
   249     }
       
   250 
       
   251 // ----------------------------------------------------------
       
   252 // CSimpleDocument::SetEntityURIL
       
   253 // ----------------------------------------------------------
       
   254 //
       
   255 void CSimpleDocument::SetEntityURIL( const TDesC8& aValue )
       
   256     {
       
   257     Root()->AddAttr8L( KSimpleEntity, aValue );
       
   258     }
       
   259 
       
   260 // ----------------------------------------------------------
       
   261 // CSimpleDocument::DefaultNamespace
       
   262 // ----------------------------------------------------------
       
   263 //
       
   264 
       
   265 TPtrC8 CSimpleDocument::DefaultNamespace()
       
   266     {
       
   267     return CSimpleBaseDocument::DefaultNamespace();
       
   268     }
       
   269 
       
   270 
       
   271 // ----------------------------------------------------------
       
   272 // CSimpleDocument::AddNamespaceL
       
   273 // ----------------------------------------------------------
       
   274 //
       
   275 void CSimpleDocument::AddNamespaceL(
       
   276     const TDesC8& aPrefix,
       
   277     const TDesC8& aUri )
       
   278     {
       
   279     CSimpleBaseDocument::AddNamespaceL( aPrefix, aUri );
       
   280     }
       
   281 
       
   282 // ----------------------------------------------------------
       
   283 // CSimpleDocument::NamespacesL
       
   284 // ----------------------------------------------------------
       
   285 //
       
   286 RPointerArray<MSimpleNamespace>& CSimpleDocument::NamespacesL()
       
   287     {
       
   288     return CSimpleBaseDocument::NamespacesL();
       
   289     }
       
   290 
       
   291 // ----------------------------------------------------------
       
   292 // CSimpleDocument::ExternalizeL
       
   293 // ----------------------------------------------------------
       
   294 //
       
   295 void CSimpleDocument::ExternalizeL( RWriteStream& aStream )
       
   296     {
       
   297     
       
   298     // notice: check the max message size 
       
   299     
       
   300     if ( !iContents.Count() )
       
   301         {            
       
   302         // single pidf+xml    
       
   303         CSimpleBaseDocument::ExternalizeL( aStream );
       
   304         }
       
   305     else
       
   306         {
       
   307         RPointerArray<CBodyPart> bodyPartsArray;
       
   308         RPointerArray<HBufC8> bufferArray;
       
   309         
       
   310         TRAPD( err, DoExternalizeMultiPartL( bodyPartsArray, bufferArray, aStream ) );                      
       
   311                                
       
   312         bufferArray.ResetAndDestroy();        
       
   313         bodyPartsArray.ResetAndDestroy();         
       
   314         bufferArray.Close();        
       
   315         bodyPartsArray.Close();        
       
   316         
       
   317         User::LeaveIfError( err );                                                                          
       
   318         }                                                
       
   319     }
       
   320 
       
   321 // ----------------------------------------------------------
       
   322 // CSimpleDocument::Close
       
   323 // ----------------------------------------------------------
       
   324 //
       
   325 void CSimpleDocument::Close()
       
   326     {
       
   327     CSimpleBaseDocument::Close();
       
   328     }
       
   329 
       
   330 // ----------------------------------------------------------
       
   331 // CSimpleDocument::LocalName
       
   332 // ----------------------------------------------------------
       
   333 //
       
   334 const TDesC8& CSimpleDocument::LocalName()
       
   335     {
       
   336     return CSimpleBaseDocument::LocalName();
       
   337     }
       
   338 
       
   339 // ----------------------------------------------------------
       
   340 // CSimpleDocument::DefNamespaceL
       
   341 // ----------------------------------------------------------
       
   342 //
       
   343 MSimpleNamespace* CSimpleDocument::DefNamespaceL()
       
   344     {
       
   345     return CSimpleBaseDocument::DefNamespaceL();
       
   346     }
       
   347 
       
   348 // ----------------------------------------------------------
       
   349 // CSimpleDocument::HasContent
       
   350 // ----------------------------------------------------------
       
   351 //
       
   352 TBool CSimpleDocument::HasContent()
       
   353     {
       
   354     return CSimpleBaseDocument::HasContent();
       
   355     }
       
   356 
       
   357 // ----------------------------------------------------------
       
   358 // CSimpleDocument::ContentUnicodeL
       
   359 // ----------------------------------------------------------
       
   360 //
       
   361 HBufC* CSimpleDocument::ContentUnicodeL()
       
   362     {
       
   363     return CSimpleBaseDocument::ContentUnicodeL();
       
   364     }
       
   365 
       
   366 // ----------------------------------------------------------
       
   367 // CSimpleDocument::SetContentUnicodeL
       
   368 // ----------------------------------------------------------
       
   369 //
       
   370 void CSimpleDocument::SetContentUnicodeL( const TDesC& aContent )
       
   371     {
       
   372     CSimpleBaseDocument::SetContentUnicodeL( aContent );
       
   373     }
       
   374 
       
   375 // ----------------------------------------------------------
       
   376 // CSimpleDocument::SimpleElementsL
       
   377 // ----------------------------------------------------------
       
   378 //
       
   379 TInt CSimpleDocument::SimpleElementsL( RPointerArray<MSimpleElement>& aElementArray )
       
   380     {
       
   381     return CSimpleBaseDocument::SimpleElementsL( aElementArray );
       
   382     }
       
   383 
       
   384 // ----------------------------------------------------------
       
   385 // CSimpleDocument::AttrValueLC
       
   386 // ----------------------------------------------------------
       
   387 //
       
   388 HBufC* CSimpleDocument::AttrValueLC( const TDesC8& aName )
       
   389     {
       
   390     return CSimpleBaseDocument::AttrValueLC( aName );
       
   391     }
       
   392 
       
   393 // ----------------------------------------------------------
       
   394 // CSimpleDocument::AttrValue
       
   395 // ----------------------------------------------------------
       
   396 //
       
   397 const TDesC8* CSimpleDocument::AttrValue( const TDesC8& aName )
       
   398     {
       
   399   return CSimpleBaseDocument::AttrValue( aName );
       
   400     }
       
   401 
       
   402 // ----------------------------------------------------------
       
   403 // CSimpleDocument::AddAttrL
       
   404 // ----------------------------------------------------------
       
   405 //
       
   406 void CSimpleDocument::AddAttrL( const TDesC8& aName, const TDesC& aValue )
       
   407     {
       
   408     CSimpleBaseDocument::AddAttrL( aName, aValue );
       
   409     }
       
   410 
       
   411 // ----------------------------------------------------------
       
   412 // CSimpleDocument::SimpleAttributesL
       
   413 // ----------------------------------------------------------
       
   414 //
       
   415 TInt CSimpleDocument::SimpleAttributesL( RPointerArray<MSimpleAttribute>& aArray )
       
   416     {
       
   417     return CSimpleBaseDocument::SimpleAttributesL( aArray );
       
   418     }
       
   419 
       
   420 // ----------------------------------------------------------
       
   421 // CSimpleDocument::SimpleParentL
       
   422 // ----------------------------------------------------------
       
   423 //
       
   424 MSimpleElement* CSimpleDocument::SimpleParentL()
       
   425     {
       
   426     return NULL;
       
   427     }
       
   428 
       
   429 // ----------------------------------------------------------
       
   430 // CSimpleDocument::DetachSimpleL
       
   431 // ----------------------------------------------------------
       
   432 //
       
   433 void CSimpleDocument::DetachSimpleL()
       
   434     {
       
   435     User::Leave( KErrNotFound );
       
   436     }
       
   437 
       
   438 
       
   439 // ----------------------------------------------------------
       
   440 // CSimpleDocument::AddSimpleElementL
       
   441 // ----------------------------------------------------------
       
   442 //
       
   443 MSimpleElement* CSimpleDocument::AddSimpleElementL(
       
   444     const TDesC8& aNsUri,
       
   445     const TDesC8& aLocalName )
       
   446     {
       
   447     return CSimpleBaseDocument::AddSimpleElementL( aNsUri, aLocalName );
       
   448     }
       
   449 
       
   450 // ----------------------------------------------------------
       
   451 // CSimpleDocument::AddSimpleElementL
       
   452 // ----------------------------------------------------------
       
   453 //
       
   454 MSimpleElement* CSimpleDocument::AddSimpleElementL(
       
   455     const TDesC8& aLocalName )
       
   456     {
       
   457     return CSimpleBaseDocument::AddSimpleElementL( aLocalName );
       
   458     }
       
   459 
       
   460 
       
   461 // ----------------------------------------------------------
       
   462 // CSimpleDocument::RemoveSimpleElement
       
   463 // ----------------------------------------------------------
       
   464 //
       
   465 void CSimpleDocument::RemoveSimpleElement(
       
   466     const TDesC8& aNsUri,
       
   467     const TDesC8& aLocalName )
       
   468     {
       
   469     CSimpleBaseDocument::RemoveSimpleElement( aNsUri, aLocalName );
       
   470     }
       
   471     
       
   472 // ----------------------------------------------------------
       
   473 // CSimpleDocument::ResetAndDestroy
       
   474 // ----------------------------------------------------------
       
   475 //
       
   476 void CSimpleDocument::ResetAndDestroy( TAny* aPtrArray )
       
   477     {
       
   478     RPointerArray<CBodyPart>* array =
       
   479     	static_cast<RPointerArray<CBodyPart>*>( aPtrArray );
       
   480     array->ResetAndDestroy();
       
   481     array->Close();	
       
   482     }   
       
   483        
       
   484 // ----------------------------------------------------------
       
   485 // CSimpleDocument::DoConstructL
       
   486 // ----------------------------------------------------------
       
   487 //    
       
   488 void CSimpleDocument::DoConstructL( 
       
   489     RPointerArray<CBodyPart>& aParts, const TDesC8& aStart )
       
   490     {
       
   491     // Handle body parts one by one
       
   492     TInt size = aParts.Count();
       
   493     TInt i;
       
   494     CBodyPart* cp = NULL;
       
   495     TPtrC8 boundary;
       
   496     TPtrC8 start;
       
   497     
       
   498     TBool pidfOk ( EFalse );
       
   499     
       
   500           
       
   501     for (i = 0; i < size; i++)
       
   502         {
       
   503         cp = aParts[i];      
       
   504                                      
       
   505         if ( (( aStart.Length() > 0 && !aStart.Compare( cp->ContentID()) ) || 
       
   506                 !pidfOk ) && 
       
   507              !cp->ContentType().Left(sizeof(KSimpleDocumentType)).CompareF( KSimpleDocumentType ))
       
   508             {
       
   509             // Multipart root is in the pidf+xml format
       
   510             BaseConstructL( cp->Body() );
       
   511             pidfOk = ETrue;
       
   512             }
       
   513         else 
       
   514             {
       
   515             // Direct contents, as a separate MIME multipart parts                           
       
   516             CSimpleContent* cd = CSimpleContent::NewL( 
       
   517                 cp->ContentID(), cp->ContentType() );
       
   518             cd->CopyBodyL( cp->Body() );                 
       
   519             CleanupStack::PushL( cd );           
       
   520             User::LeaveIfError( iContents.Append( cd ) );
       
   521             CleanupStack::Pop( cd );           
       
   522             }                  
       
   523         }   
       
   524     }    
       
   525             
       
   526 // ------------------------------------------------------------------------- 
       
   527 // CSimpleDocument::DoComposeMultiPartL
       
   528 // ------------------------------------------------------------------------- 
       
   529 HBufC8* CSimpleDocument::DoComposeMultiPartL( RPointerArray<CBodyPart>& aBodyArray,
       
   530                                 const TDesC8& aBoundary )
       
   531     {
       
   532     // --(aBoundary)
       
   533     using namespace NSimpleDocument;
       
   534     HBufC8* boundary = HBufC8::NewLC( aBoundary.Length() + 4 );
       
   535     boundary->Des().Format( KBoundary, &aBoundary );
       
   536     
       
   537     // CALCULATE the size of this document.
       
   538     TInt bodySize = 0;
       
   539     //    a. for each CBodyPart
       
   540     //       boundaries + CRLF between headers and body (constant addition)
       
   541     bodySize += (boundary->Length() + strlen(Multipart_CRLF_Text)) * aBodyArray.Count() ;
       
   542     TInt bodyCounter = aBodyArray.Count();
       
   543     for (TInt i = 0; i < bodyCounter; i++)
       
   544         {
       
   545         if (!(aBodyArray[i]->Headers().Length() +
       
   546             aBodyArray[i]->Body().Length()))
       
   547             {
       
   548             // one less boundary
       
   549             bodySize -= boundary->Length() + strlen(Multipart_CRLF_Text);
       
   550             // skip empty bodypart
       
   551             continue;
       
   552             }
       
   553         bodySize += aBodyArray[i]->Headers().Length();
       
   554         //  ensure there are only 2 CRLFs between header and body
       
   555         if (aBodyArray[i]->Headers().Length() > 0)
       
   556             {
       
   557             TPtrC8 bodyHeaders(aBodyArray[i]->Headers().Ptr(), aBodyArray[i]->Headers().Length());
       
   558             TUint newEnd = bodyHeaders.Length() - 1;
       
   559             while( bodyHeaders[ newEnd ] == '\r' || bodyHeaders[ newEnd ] == '\n' )
       
   560                 {
       
   561                 --newEnd;
       
   562                 --bodySize;
       
   563                 }
       
   564             // two CRLFs
       
   565             bodySize += strlen(Multipart_CRLF_Text);
       
   566             }
       
   567         bodySize += aBodyArray[i]->Body().Length();
       
   568         //  CRLF (end of body, add one only if there is body AND does not end with CRLF)
       
   569         TPtrC8 bodyBody(aBodyArray[i]->Body().Ptr(), aBodyArray[i]->Body().Length());
       
   570         if (bodyBody.Length() > 0 
       
   571             && bodyBody.Right(2) != TPtrC8((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text)))
       
   572             {
       
   573             bodySize += strlen(Multipart_CRLF_Text);
       
   574             }
       
   575         }
       
   576     // end boundary (boundary - '\r\n' + "--")
       
   577     bodySize += boundary->Length(); 
       
   578     TInt docSize = bodySize; 
       
   579     
       
   580     // CALCULATE the size of Headers
       
   581     using namespace NSimpleDocument::NSimpleMulti;    
       
   582        
       
   583     // extra CRLF for separating header and body
       
   584     docSize += strlen(Multipart_CRLF_Text);
       
   585     //  CALCULATION COMPLETE
       
   586     //  at this point, bodySize contains the size of bodyparts, i.e. Content-Length:
       
   587     //  and docSize contains the size of the entire document (use it to create HBufC8*
       
   588     //  of appropriate size)
       
   589   
       
   590     //  CONSTRUCT MULTIPART DOCUMENT
       
   591     HBufC8* document = HBufC8::NewLC(docSize);
       
   592         
       
   593     TPtr8 docAppend(document->Des());
       
   594            
       
   595     //  BODYPARTS
       
   596     for (TInt i = 0; i < aBodyArray.Count(); i++)
       
   597         {
       
   598         if (!(aBodyArray[i]->Headers().Length() +
       
   599             aBodyArray[i]->Body().Length()))
       
   600             {
       
   601             // skip empty bodypart
       
   602             continue;
       
   603             }
       
   604         docAppend.Append( *boundary );
       
   605         TInt headerLength = aBodyArray[i]->Headers().Length() - 1;
       
   606         while ( headerLength > 0 &&
       
   607                 (aBodyArray[i]->Headers()[headerLength] == '\r'
       
   608                 || aBodyArray[i]->Headers()[headerLength] == '\n' ))
       
   609             {
       
   610             --headerLength;
       
   611             }
       
   612         docAppend.Append( aBodyArray[i]->Headers().Ptr(), headerLength + 1 );
       
   613 
       
   614         if ( headerLength > 0 )
       
   615             {
       
   616             docAppend.Append((TUint8*)Multipart_DoubleCRLF_Text, strlen(Multipart_DoubleCRLF_Text));
       
   617             }
       
   618         else
       
   619             {
       
   620             docAppend.Append((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text));
       
   621             }
       
   622         //  body
       
   623         TPtrC8 opa = aBodyArray[i]->Body();
       
   624         docAppend.Append(aBodyArray[i]->Body());
       
   625         //  CRLF only if body exists and doesn't end with CRLF
       
   626         TPtrC8 bodyBody(aBodyArray[i]->Body().Ptr(), aBodyArray[i]->Body().Length());
       
   627         if (bodyBody.Length() > 0
       
   628             && bodyBody.Right(2) != TPtrC8((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text)))
       
   629             {
       
   630             docAppend.Append((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text));
       
   631             }
       
   632         }
       
   633     //  end boundary
       
   634     docAppend.AppendFormat(KEndBoundary, &aBoundary);
       
   635     CleanupStack::Pop( document );
       
   636     CleanupStack::PopAndDestroy( boundary );
       
   637     return document;
       
   638     } 
       
   639     
       
   640 // ------------------------------------------------------------------------- 
       
   641 // CSimpleDocument::DoExternalizeMultiPartL
       
   642 // -------------------------------------------------------------------------    
       
   643 void CSimpleDocument::DoExternalizeMultiPartL( 
       
   644         RPointerArray<CBodyPart>& aBodies, 
       
   645         RPointerArray<HBufC8>& aBuffers,
       
   646         RWriteStream& aStream )
       
   647     {
       
   648     const TReal KB64Expand = 1.5; // reserve room for Base64 encoding
       
   649     const TInt KBufferSize = 500;
       
   650         
       
   651     // Convert all the multipart into CBodyPart.
       
   652            
       
   653     // Let's convert first ROOT element into CBodyPart
       
   654     CBodyPart* root = CBodyPart::NewL();
       
   655     // Add into cleanup array
       
   656     aBodies.Append( root );     
       
   657     CSenElement* e = Root()->BaseElement();
       
   658     
       
   659     // externalize the document into stream
       
   660     CBufFlat* myBuffer = CBufFlat::NewL( KBufferSize );
       
   661     CleanupStack::PushL( myBuffer );        
       
   662     myBuffer->Reset();
       
   663     
       
   664     RBufWriteStream stream( *myBuffer );
       
   665     stream.Open( *myBuffer );  
       
   666     CSimpleBaseDocument::ExternalizeL( stream );
       
   667     stream.Close();
       
   668     
       
   669     // Add content, no need to transfer encode
       
   670     TPtrC8 body ( myBuffer->Ptr(0) );
       
   671     root->SetBody( body ); 
       
   672     
       
   673     // Handle the headers of the ROOT part
       
   674     using namespace NSimpleDocument::NSimpleRoot;
       
   675     
       
   676     // calculate the size of headers
       
   677     TInt headerSize = KContentTypeSize + KCIDSize;
       
   678     HBufC8* headers = HBufC8::NewL( headerSize );  
       
   679     aBuffers.Append( headers );
       
   680     TPtr8 pH(headers->Des());
       
   681     // append to MIME headers for the root part   
       
   682     pH.Append( NSimpleDocument::NSimpleRoot::KContentType );
       
   683     pH.Append( NSimpleDocument::NSimpleRoot::KCID );    
       
   684     root->SetHeaders( pH );    
       
   685                                        
       
   686     // handle the direct contents one by one
       
   687     TInt contCount = iContents.Count();
       
   688     for ( TInt i=0; i<contCount; i++ )
       
   689         { 
       
   690         // Let's convert next element into CBodyPart
       
   691         CBodyPart* cp = CBodyPart::NewL();
       
   692         aBodies.Append( cp );                
       
   693          
       
   694         // Set Headers
       
   695         headerSize = NSimpleDocument::NSimpleContent::KContentTypeSize + 
       
   696                      NSimpleDocument::NSimpleContent::KCIDSize + 
       
   697                      NSimpleDocument::NSimpleContent::KContentEncodingSize;
       
   698         headerSize += (iContents[i])->ContentID().Length();
       
   699         headerSize += (iContents[i])->ContentType().Length();                 
       
   700         
       
   701         headers = HBufC8::NewL( headerSize );
       
   702         // Append to cleanup array  
       
   703         aBuffers.Append( headers );
       
   704         pH.Set( headers->Des() );
       
   705 
       
   706         // _LIT8( KMyContentType, "Content-Type: %S\r\n"); 
       
   707         TPtrC8 myValue = (iContents[i])->ContentType();     
       
   708         pH.Format( NSimpleDocument::NSimpleContent::KContentType, &myValue );    
       
   709         myValue.Set((iContents[i])->ContentID() );         
       
   710         pH.AppendFormat( NSimpleDocument::NSimpleContent::KCID, &myValue );            
       
   711         pH.Append( NSimpleDocument::NSimpleContent::KContentEncoding ); 
       
   712         // append to MIME headers           
       
   713         cp->SetHeaders( pH );
       
   714                      
       
   715         // Body
       
   716                     
       
   717         // BASE64 encode
       
   718         HBufC8* body64 = HBufC8::NewL( (iContents[i])->Body().Length() * KB64Expand );  
       
   719         aBuffers.Append( body64 );        
       
   720         TImCodecB64 codec64;
       
   721         codec64.Initialise();        
       
   722         TPtr8 desti8 = body64->Des();  
       
   723         
       
   724         // notice: leave if error?
       
   725         TInt err = codec64.Encode( (iContents[i])->Body(), desti8 );                                 
       
   726         
       
   727         cp->SetBody( body64->Des() );                                                                                 
       
   728         }
       
   729                             
       
   730     // Compose the multipart MIME flat data   
       
   731     HBufC8* entireMsg = NULL;      
       
   732     entireMsg = DoComposeMultiPartL( aBodies, NSimpleDocument::KSimpleBoundary );
       
   733     CleanupStack::PushL( entireMsg );
       
   734     // Finally stream entireMsg, 
       
   735     // Notice: later DoComposeMultiPartL could stream directly?
       
   736     aStream.WriteL( entireMsg->Des() ); 
       
   737     CleanupStack::PopAndDestroy( entireMsg );  
       
   738     CleanupStack::PopAndDestroy( myBuffer );                 
       
   739  
       
   740     }
       
   741 
       
   742 
       
   743 
       
   744 
       
   745