simpleengine/xmlutils/src/simpledocument.cpp
changeset 0 c8caa15ef882
child 11 52d91a16fec3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simpleengine/xmlutils/src/simpledocument.cpp	Tue Feb 02 01:05:17 2010 +0200
@@ -0,0 +1,745 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    Simple Engine
+*
+*/
+
+
+
+
+// INCLUDE FILES
+
+#include <e32def.h>           // First to avoid NULL redefine warning (no #ifndef NULL).
+#include <e32std.h>
+#include <string.h>
+
+#include <imcvcodc.h>
+
+// #include <e32std.h>
+#include <s32strm.h>
+#include <SenBaseElement.h>
+#include <SenBaseAttribute.h>
+#include <SenXmlUtils.h>
+#include <SenXmlReader.h>
+#include <SenDomFragment.h>
+
+#include <multipartparser.h>
+#include <bodypart.h>
+
+// own simple
+#include "simplecommon.h"
+#include "simpleelement.h"
+#include "simplenamespace.h"
+#include "simpleattribute.h"
+#include "simpledocument.h"
+#include "simplebasedocument.h"
+#include "simpleutils.h"
+#include "simplecontent.h"
+
+
+_LIT8 ( KSimpleEntity, "entity");
+
+// Multipart CONSTANTS
+
+const char Multipart_CRLF_Text[] = {"\r\n"};
+const char Multipart_DoubleCRLF_Text[] = {"\r\n\r\n"};
+
+// MACROS
+#define MULTIPART_CONTENT_LOCATION_LENGTH           17
+#define MULTIPART_CONTENT_TYPE_LENGTH               13
+#define MULTIPART_CONTENT_TRANSFER_ENCODING_LENGTH  26
+// violates RFC2045; but upon vodafone request
+#define MULTIPART_CONTENT_ENCODING_LENGTH           17
+#define MULTIPART_CONTENT_LENGTH_LENGTH             15
+#define MULTIPART_LAST_MODIFIED_LENGTH              14
+#define MULTIPART_CONTENT_ID_LENGTH                 11
+
+#define MULTIPART_CONTENT_LOCATION           2
+#define MULTIPART_CONTENT_TRANSFER_ENCODING  3
+#define MULTIPART_CONTENT_TYPE               4
+#define MULTIPART_CONTENT_ID                 5
+
+#define MULTIPART_INTERNET_DATE_STRING_LENGTH       29
+
+#define SLASH_CHAR    '/'
+#define DOT_CHAR      '.'
+#define AT_CHAR       '@'
+#define COLON_CHAR    ':'
+// <scheme>://
+// #define SCHEME_SEPARATOR_LENGTH               3
+// ================= MEMBER FUNCTIONS =======================
+//
+
+// ----------------------------------------------------------
+// CSimpleDocument::CSimpleDocument
+// ----------------------------------------------------------
+//
+CSimpleDocument::CSimpleDocument( )
+: CSimpleBaseDocument()
+    {
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::~CSimpleDocument
+// ----------------------------------------------------------
+//
+CSimpleDocument::~CSimpleDocument()
+    {
+    iContents.ResetAndDestroy();
+    iContents.Close();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::ConstructL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::ConstructL(
+    const TDesC8& aNsUri,
+    const TDesC8& aLocalName )
+    {
+    BaseConstructL(aNsUri, aLocalName);
+    }
+    
+// ----------------------------------------------------------
+// CSimpleDocument::ConstructMultiPartL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::ConstructMultiPartL(
+    const TDesC8& aData, const TDesC8& aBoundary, const TDesC8& aStart )
+    {    
+    _LIT(KUrl, "http://dummy.com/d1/d.html");
+           
+    // body part array
+    RPointerArray<CBodyPart> bodyPartArray;
+    TCleanupItem clItem( ResetAndDestroy, &bodyPartArray  );
+    CleanupStack::PushL( clItem );
+    
+    // remove "..." characters from boundary if needed
+    TPtrC8 pUnQuoted = aBoundary;
+    TInt quoted = aBoundary.Locate('"');
+    if (!quoted)
+        {
+        pUnQuoted.Set( aBoundary.Mid( 1, aBoundary.Length() - 2 ));
+        } 
+    // parse
+    MultipartParser::ParseL( aData, KSimpleMultipartType, pUnQuoted, KUrl, bodyPartArray  );    
+    DoConstructL( bodyPartArray, aStart );
+   
+    CleanupStack::PopAndDestroy( ); // bodyPartArray     
+    }    
+
+// ----------------------------------------------------------
+// CSimpleDocument::ConstructL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::ConstructL(
+    const TDesC8& aXml )
+    {
+    BaseConstructL( aXml );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::NewL
+// ----------------------------------------------------------
+//
+CSimpleDocument* CSimpleDocument::NewL( )
+    {
+    CSimpleDocument* self = new (ELeave) CSimpleDocument( );
+    CleanupStack::PushL( self );
+    self->ConstructL( KSimpleNsDefault, KDocumentLocalName );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::NewL
+// ----------------------------------------------------------
+//
+CSimpleDocument* CSimpleDocument::NewL( const TDesC8& aXml )
+    {
+    CSimpleDocument* self = new (ELeave) CSimpleDocument( );
+    CleanupStack::PushL( self );
+    self->ConstructL( aXml );
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// ----------------------------------------------------------
+// CSimpleDocument::NewInMultiPartL
+// ----------------------------------------------------------
+//
+CSimpleDocument* CSimpleDocument::NewInMultiPartL( 
+    const TDesC8& aData, const TDesC8& aBoundary, const TDesC8& aStart )
+    {
+    CSimpleDocument* self = new (ELeave) CSimpleDocument( );
+    CleanupStack::PushL( self );
+    self->ConstructMultiPartL( aData, aBoundary, aStart );
+    CleanupStack::Pop( self );
+    return self;
+    } 
+    
+// ----------------------------------------------------------
+// CSimpleDocument::GetDirectContentsL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::GetDirectContentsL( 
+    RPointerArray<MSimpleContent>& aContents )
+    {
+    aContents.Reset();
+    TInt myCount = iContents.Count();
+    for ( TInt i = 0; i<myCount; i++ )
+        {
+        User::LeaveIfError( aContents.Append( iContents[i] ));
+        }               
+    }
+    
+// ----------------------------------------------------------
+// CSimpleDocument::AddDirectContentL
+// ----------------------------------------------------------
+//    
+void CSimpleDocument::AddDirectContentL( 
+    MSimpleContent& aContent,
+    TBool aCopyContent )
+    {
+    CSimpleContent* content = CSimpleContent::NewLC(
+        aContent.ContentID(), aContent.ContentType());
+    User::LeaveIfError( iContents.Append( content ));
+    CleanupStack::Pop( content );
+    
+    if ( aCopyContent )
+        {
+        content->CopyBodyL( aContent.Body() );
+        }
+    else
+        {
+        content->SetBody( aContent.GiveBodyOwnerShip() );
+        }                       
+    }
+    
+// ----------------------------------------------------------
+// CSimpleDocument::ValidateXmlL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::ValidateXmlL( const TDesC8& aName )
+    {
+    if ( aName.CompareF( KDocumentLocalName ) )
+        {
+        User::Leave( KErrCorrupt );
+        }
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::EntityURI
+// ----------------------------------------------------------
+//
+const TDesC8* CSimpleDocument::EntityURI()
+    {
+    return Root()->AttrValue( KSimpleEntity );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::SetEntityURIL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::SetEntityURIL( const TDesC8& aValue )
+    {
+    Root()->AddAttr8L( KSimpleEntity, aValue );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::DefaultNamespace
+// ----------------------------------------------------------
+//
+
+TPtrC8 CSimpleDocument::DefaultNamespace()
+    {
+    return CSimpleBaseDocument::DefaultNamespace();
+    }
+
+
+// ----------------------------------------------------------
+// CSimpleDocument::AddNamespaceL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::AddNamespaceL(
+    const TDesC8& aPrefix,
+    const TDesC8& aUri )
+    {
+    CSimpleBaseDocument::AddNamespaceL( aPrefix, aUri );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::NamespacesL
+// ----------------------------------------------------------
+//
+RPointerArray<MSimpleNamespace>& CSimpleDocument::NamespacesL()
+    {
+    return CSimpleBaseDocument::NamespacesL();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::ExternalizeL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::ExternalizeL( RWriteStream& aStream )
+    {
+    
+    // notice: check the max message size 
+    
+    if ( !iContents.Count() )
+        {            
+        // single pidf+xml    
+        CSimpleBaseDocument::ExternalizeL( aStream );
+        }
+    else
+        {
+        RPointerArray<CBodyPart> bodyPartsArray;
+        RPointerArray<HBufC8> bufferArray;
+        
+        TRAPD( err, DoExternalizeMultiPartL( bodyPartsArray, bufferArray, aStream ) );                      
+                               
+        bufferArray.ResetAndDestroy();        
+        bodyPartsArray.ResetAndDestroy();         
+        bufferArray.Close();        
+        bodyPartsArray.Close();        
+        
+        User::LeaveIfError( err );                                                                          
+        }                                                
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::Close
+// ----------------------------------------------------------
+//
+void CSimpleDocument::Close()
+    {
+    CSimpleBaseDocument::Close();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::LocalName
+// ----------------------------------------------------------
+//
+const TDesC8& CSimpleDocument::LocalName()
+    {
+    return CSimpleBaseDocument::LocalName();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::DefNamespaceL
+// ----------------------------------------------------------
+//
+MSimpleNamespace* CSimpleDocument::DefNamespaceL()
+    {
+    return CSimpleBaseDocument::DefNamespaceL();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::HasContent
+// ----------------------------------------------------------
+//
+TBool CSimpleDocument::HasContent()
+    {
+    return CSimpleBaseDocument::HasContent();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::ContentUnicodeL
+// ----------------------------------------------------------
+//
+HBufC* CSimpleDocument::ContentUnicodeL()
+    {
+    return CSimpleBaseDocument::ContentUnicodeL();
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::SetContentUnicodeL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::SetContentUnicodeL( const TDesC& aContent )
+    {
+    CSimpleBaseDocument::SetContentUnicodeL( aContent );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::SimpleElementsL
+// ----------------------------------------------------------
+//
+TInt CSimpleDocument::SimpleElementsL( RPointerArray<MSimpleElement>& aElementArray )
+    {
+    return CSimpleBaseDocument::SimpleElementsL( aElementArray );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::AttrValueLC
+// ----------------------------------------------------------
+//
+HBufC* CSimpleDocument::AttrValueLC( const TDesC8& aName )
+    {
+    return CSimpleBaseDocument::AttrValueLC( aName );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::AttrValue
+// ----------------------------------------------------------
+//
+const TDesC8* CSimpleDocument::AttrValue( const TDesC8& aName )
+    {
+  return CSimpleBaseDocument::AttrValue( aName );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::AddAttrL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::AddAttrL( const TDesC8& aName, const TDesC& aValue )
+    {
+    CSimpleBaseDocument::AddAttrL( aName, aValue );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::SimpleAttributesL
+// ----------------------------------------------------------
+//
+TInt CSimpleDocument::SimpleAttributesL( RPointerArray<MSimpleAttribute>& aArray )
+    {
+    return CSimpleBaseDocument::SimpleAttributesL( aArray );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::SimpleParentL
+// ----------------------------------------------------------
+//
+MSimpleElement* CSimpleDocument::SimpleParentL()
+    {
+    return NULL;
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::DetachSimpleL
+// ----------------------------------------------------------
+//
+void CSimpleDocument::DetachSimpleL()
+    {
+    User::Leave( KErrNotFound );
+    }
+
+
+// ----------------------------------------------------------
+// CSimpleDocument::AddSimpleElementL
+// ----------------------------------------------------------
+//
+MSimpleElement* CSimpleDocument::AddSimpleElementL(
+    const TDesC8& aNsUri,
+    const TDesC8& aLocalName )
+    {
+    return CSimpleBaseDocument::AddSimpleElementL( aNsUri, aLocalName );
+    }
+
+// ----------------------------------------------------------
+// CSimpleDocument::AddSimpleElementL
+// ----------------------------------------------------------
+//
+MSimpleElement* CSimpleDocument::AddSimpleElementL(
+    const TDesC8& aLocalName )
+    {
+    return CSimpleBaseDocument::AddSimpleElementL( aLocalName );
+    }
+
+
+// ----------------------------------------------------------
+// CSimpleDocument::RemoveSimpleElement
+// ----------------------------------------------------------
+//
+void CSimpleDocument::RemoveSimpleElement(
+    const TDesC8& aNsUri,
+    const TDesC8& aLocalName )
+    {
+    CSimpleBaseDocument::RemoveSimpleElement( aNsUri, aLocalName );
+    }
+    
+// ----------------------------------------------------------
+// CSimpleDocument::ResetAndDestroy
+// ----------------------------------------------------------
+//
+void CSimpleDocument::ResetAndDestroy( TAny* aPtrArray )
+    {
+    RPointerArray<CBodyPart>* array =
+    	static_cast<RPointerArray<CBodyPart>*>( aPtrArray );
+    array->ResetAndDestroy();
+    array->Close();	
+    }   
+       
+// ----------------------------------------------------------
+// CSimpleDocument::DoConstructL
+// ----------------------------------------------------------
+//    
+void CSimpleDocument::DoConstructL( 
+    RPointerArray<CBodyPart>& aParts, const TDesC8& aStart )
+    {
+    // Handle body parts one by one
+    TInt size = aParts.Count();
+    TInt i;
+    CBodyPart* cp = NULL;
+    TPtrC8 boundary;
+    TPtrC8 start;
+    
+    TBool pidfOk ( EFalse );
+    
+          
+    for (i = 0; i < size; i++)
+        {
+        cp = aParts[i];      
+                                     
+        if ( (( aStart.Length() > 0 && !aStart.Compare( cp->ContentID()) ) || 
+                !pidfOk ) && 
+             !cp->ContentType().Left(sizeof(KSimpleDocumentType)).CompareF( KSimpleDocumentType ))
+            {
+            // Multipart root is in the pidf+xml format
+            BaseConstructL( cp->Body() );
+            pidfOk = ETrue;
+            }
+        else 
+            {
+            // Direct contents, as a separate MIME multipart parts                           
+            CSimpleContent* cd = CSimpleContent::NewL( 
+                cp->ContentID(), cp->ContentType() );
+            cd->CopyBodyL( cp->Body() );                 
+            CleanupStack::PushL( cd );           
+            User::LeaveIfError( iContents.Append( cd ) );
+            CleanupStack::Pop( cd );           
+            }                  
+        }   
+    }    
+            
+// ------------------------------------------------------------------------- 
+// CSimpleDocument::DoComposeMultiPartL
+// ------------------------------------------------------------------------- 
+HBufC8* CSimpleDocument::DoComposeMultiPartL( RPointerArray<CBodyPart>& aBodyArray,
+                                const TDesC8& aBoundary )
+    {
+    // --(aBoundary)
+    using namespace NSimpleDocument;
+    HBufC8* boundary = HBufC8::NewLC( aBoundary.Length() + 4 );
+    boundary->Des().Format( KBoundary, &aBoundary );
+    
+    // CALCULATE the size of this document.
+    TInt bodySize = 0;
+    //    a. for each CBodyPart
+    //       boundaries + CRLF between headers and body (constant addition)
+    bodySize += (boundary->Length() + strlen(Multipart_CRLF_Text)) * aBodyArray.Count() ;
+    TInt bodyCounter = aBodyArray.Count();
+    for (TInt i = 0; i < bodyCounter; i++)
+        {
+        if (!(aBodyArray[i]->Headers().Length() +
+            aBodyArray[i]->Body().Length()))
+            {
+            // one less boundary
+            bodySize -= boundary->Length() + strlen(Multipart_CRLF_Text);
+            // skip empty bodypart
+            continue;
+            }
+        bodySize += aBodyArray[i]->Headers().Length();
+        //  ensure there are only 2 CRLFs between header and body
+        if (aBodyArray[i]->Headers().Length() > 0)
+            {
+            TPtrC8 bodyHeaders(aBodyArray[i]->Headers().Ptr(), aBodyArray[i]->Headers().Length());
+            TUint newEnd = bodyHeaders.Length() - 1;
+            while( bodyHeaders[ newEnd ] == '\r' || bodyHeaders[ newEnd ] == '\n' )
+                {
+                --newEnd;
+                --bodySize;
+                }
+            // two CRLFs
+            bodySize += strlen(Multipart_CRLF_Text);
+            }
+        bodySize += aBodyArray[i]->Body().Length();
+        //  CRLF (end of body, add one only if there is body AND does not end with CRLF)
+        TPtrC8 bodyBody(aBodyArray[i]->Body().Ptr(), aBodyArray[i]->Body().Length());
+        if (bodyBody.Length() > 0 
+            && bodyBody.Right(2) != TPtrC8((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text)))
+            {
+            bodySize += strlen(Multipart_CRLF_Text);
+            }
+        }
+    // end boundary (boundary - '\r\n' + "--")
+    bodySize += boundary->Length(); 
+    TInt docSize = bodySize; 
+    
+    // CALCULATE the size of Headers
+    using namespace NSimpleDocument::NSimpleMulti;    
+       
+    // extra CRLF for separating header and body
+    docSize += strlen(Multipart_CRLF_Text);
+    //  CALCULATION COMPLETE
+    //  at this point, bodySize contains the size of bodyparts, i.e. Content-Length:
+    //  and docSize contains the size of the entire document (use it to create HBufC8*
+    //  of appropriate size)
+  
+    //  CONSTRUCT MULTIPART DOCUMENT
+    HBufC8* document = HBufC8::NewLC(docSize);
+        
+    TPtr8 docAppend(document->Des());
+           
+    //  BODYPARTS
+    for (TInt i = 0; i < aBodyArray.Count(); i++)
+        {
+        if (!(aBodyArray[i]->Headers().Length() +
+            aBodyArray[i]->Body().Length()))
+            {
+            // skip empty bodypart
+            continue;
+            }
+        docAppend.Append( *boundary );
+        TInt headerLength = aBodyArray[i]->Headers().Length() - 1;
+        while ( headerLength > 0 &&
+                (aBodyArray[i]->Headers()[headerLength] == '\r'
+                || aBodyArray[i]->Headers()[headerLength] == '\n' ))
+            {
+            --headerLength;
+            }
+        docAppend.Append( aBodyArray[i]->Headers().Ptr(), headerLength + 1 );
+
+        if ( headerLength > 0 )
+            {
+            docAppend.Append((TUint8*)Multipart_DoubleCRLF_Text, strlen(Multipart_DoubleCRLF_Text));
+            }
+        else
+            {
+            docAppend.Append((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text));
+            }
+        //  body
+        TPtrC8 opa = aBodyArray[i]->Body();
+        docAppend.Append(aBodyArray[i]->Body());
+        //  CRLF only if body exists and doesn't end with CRLF
+        TPtrC8 bodyBody(aBodyArray[i]->Body().Ptr(), aBodyArray[i]->Body().Length());
+        if (bodyBody.Length() > 0
+            && bodyBody.Right(2) != TPtrC8((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text)))
+            {
+            docAppend.Append((TUint8*)Multipart_CRLF_Text, strlen(Multipart_CRLF_Text));
+            }
+        }
+    //  end boundary
+    docAppend.AppendFormat(KEndBoundary, &aBoundary);
+    CleanupStack::Pop( document );
+    CleanupStack::PopAndDestroy( boundary );
+    return document;
+    } 
+    
+// ------------------------------------------------------------------------- 
+// CSimpleDocument::DoExternalizeMultiPartL
+// -------------------------------------------------------------------------    
+void CSimpleDocument::DoExternalizeMultiPartL( 
+        RPointerArray<CBodyPart>& aBodies, 
+        RPointerArray<HBufC8>& aBuffers,
+        RWriteStream& aStream )
+    {
+    const TReal KB64Expand = 1.5; // reserve room for Base64 encoding
+    const TInt KBufferSize = 500;
+        
+    // Convert all the multipart into CBodyPart.
+           
+    // Let's convert first ROOT element into CBodyPart
+    CBodyPart* root = CBodyPart::NewL();
+    // Add into cleanup array
+    aBodies.Append( root );     
+    CSenElement* e = Root()->BaseElement();
+    
+    // externalize the document into stream
+    CBufFlat* myBuffer = CBufFlat::NewL( KBufferSize );
+    CleanupStack::PushL( myBuffer );        
+    myBuffer->Reset();
+    
+    RBufWriteStream stream( *myBuffer );
+    stream.Open( *myBuffer );  
+    CSimpleBaseDocument::ExternalizeL( stream );
+    stream.Close();
+    
+    // Add content, no need to transfer encode
+    TPtrC8 body ( myBuffer->Ptr(0) );
+    root->SetBody( body ); 
+    
+    // Handle the headers of the ROOT part
+    using namespace NSimpleDocument::NSimpleRoot;
+    
+    // calculate the size of headers
+    TInt headerSize = KContentTypeSize + KCIDSize;
+    HBufC8* headers = HBufC8::NewL( headerSize );  
+    aBuffers.Append( headers );
+    TPtr8 pH(headers->Des());
+    // append to MIME headers for the root part   
+    pH.Append( NSimpleDocument::NSimpleRoot::KContentType );
+    pH.Append( NSimpleDocument::NSimpleRoot::KCID );    
+    root->SetHeaders( pH );    
+                                       
+    // handle the direct contents one by one
+    TInt contCount = iContents.Count();
+    for ( TInt i=0; i<contCount; i++ )
+        { 
+        // Let's convert next element into CBodyPart
+        CBodyPart* cp = CBodyPart::NewL();
+        aBodies.Append( cp );                
+         
+        // Set Headers
+        headerSize = NSimpleDocument::NSimpleContent::KContentTypeSize + 
+                     NSimpleDocument::NSimpleContent::KCIDSize + 
+                     NSimpleDocument::NSimpleContent::KContentEncodingSize;
+        headerSize += (iContents[i])->ContentID().Length();
+        headerSize += (iContents[i])->ContentType().Length();                 
+        
+        headers = HBufC8::NewL( headerSize );
+        // Append to cleanup array  
+        aBuffers.Append( headers );
+        pH.Set( headers->Des() );
+
+        // _LIT8( KMyContentType, "Content-Type: %S\r\n"); 
+        TPtrC8 myValue = (iContents[i])->ContentType();     
+        pH.Format( NSimpleDocument::NSimpleContent::KContentType, &myValue );    
+        myValue.Set((iContents[i])->ContentID() );         
+        pH.AppendFormat( NSimpleDocument::NSimpleContent::KCID, &myValue );            
+        pH.Append( NSimpleDocument::NSimpleContent::KContentEncoding ); 
+        // append to MIME headers           
+        cp->SetHeaders( pH );
+                     
+        // Body
+                    
+        // BASE64 encode
+        HBufC8* body64 = HBufC8::NewL( (iContents[i])->Body().Length() * KB64Expand );  
+        aBuffers.Append( body64 );        
+        TImCodecB64 codec64;
+        codec64.Initialise();        
+        TPtr8 desti8 = body64->Des();  
+        
+        // notice: leave if error?
+        TInt err = codec64.Encode( (iContents[i])->Body(), desti8 );                                 
+        
+        cp->SetBody( body64->Des() );                                                                                 
+        }
+                            
+    // Compose the multipart MIME flat data   
+    HBufC8* entireMsg = NULL;      
+    entireMsg = DoComposeMultiPartL( aBodies, NSimpleDocument::KSimpleBoundary );
+    CleanupStack::PushL( entireMsg );
+    // Finally stream entireMsg, 
+    // Notice: later DoComposeMultiPartL could stream directly?
+    aStream.WriteL( entireMsg->Des() ); 
+    CleanupStack::PopAndDestroy( entireMsg );  
+    CleanupStack::PopAndDestroy( myBuffer );                 
+ 
+    }
+
+
+
+
+