mmsengine/mmscodec/src/mmsencode.cpp
changeset 0 72b543305e3a
child 17 caea42e26caa
child 23 238255e8b033
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmsengine/mmscodec/src/mmsencode.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,5037 @@
+/*
+* Copyright (c) 2002-2009 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:  
+*     binary encoding of a multimedia message
+*
+*/
+
+
+
+//#define CONTENT_DISPOSITION_TEST
+
+// INCLUDE FILES
+#include    <e32std.h>
+#include    <apparc.h>
+#include    <s32mem.h>
+#include    <msventry.h>
+#include    <utf.h>
+#include    <e32math.h>
+#include    <msvids.h>
+#include    <escapeutils.h>
+#include    <badesca.h>
+#include    <mmsvattachmentmanager.h>
+#include    <mmsvattachmentmanagersync.h>
+#include    <cmsvmimeheaders.h>
+#include    <imcvcodc.h>
+
+#include    <msgtextutils.h>
+#include    <msvstore.h>
+#include    <charconv.h>
+
+#include    <centralrepository.h>          // link against centralrepository.lib
+#include    "MmsEnginePrivateCRKeys.h"
+
+#include    "mmsheaders.h"
+#include    "mmsconst.h"
+#include    "mmscodec.h"
+#include    "mmsencode.h"
+#include    "mmsservercommon.h"
+#include    "mmssession.h"
+#include    "mmsgenutils.h"
+#include    "mmserrors.h"
+#include    "mmsentrywrapper.h"
+#include    "mmsmmboxmessageheaders.h"
+#include    "mmsmmboxviewheaders.h"
+#include    "mmssendingchain.h"
+
+const TInt KMmsExtra = 1024; // extra memory left for others
+const TInt KMmsShortIntegerLimit127 = 127; // limit for short integer length
+const TInt KMmsOneByteLimit = 0x100;
+const TInt KMmsTwoByteLimit = 0x10000;
+const TInt KMmsThreeByteLimit = 0x1000000;
+const TInt KMms2 = 2;
+const TInt KMms3 = 3;
+const TInt KMms4 = 4;
+const TInt KMms5 = 5;
+const TInt KMms7 = 7;
+const TInt KMms8 = 8;
+const TInt KMms24 = 24; // shift of three half bytes
+const TInt KMms30 = 30; // upper limit for short length encoding
+const TUint8 KMms0x80 = 0x80; // 128
+const TUint8 KMms0x7F = 0x7F; // 127
+const TUint8 KMms0xFF = 0xFF;
+const TInt KMmsMaxCidLength = 18;
+// max filename length according to MMS conformance specs
+const TInt KMmsMaxFileNameLength = 40;
+// if 40 bytes are encoded in base 64, the result is 56 bytes
+// (two bytes of padding are needed to make the number divisible by 3)
+const TInt KMaxEncodingLength = 56;
+// Maximum length of output buffer needed for encoding the filename
+// Max 56 bytes for actual encoding and 12 bytes for character set (utf8)
+// and encoding scheme indicator 68 for final result, but we allocate
+// the maximum Mime header length to be sure everything fits.
+const TInt KMaxNameBufferLength = 75;
+const TInt KMmsEncodingExtraLength = 12;
+const TInt KMmsPreambleLength = 10;
+_LIT8( KMmsQuotedPreamble, "=?utf-8?Q?" );
+_LIT8( KMmsBase64Preamble, "=?utf-8?B?" );
+_LIT8( KMmsEncodingTrailer, "?=" );
+const TInt KMmsIntUnderscore = 0x5F; // underscore
+
+
+enum TMmsMachineStates
+    {
+    EMmsIdle,
+    EMmsEncodingHeaders,
+    EMmsEncodingAttachments,
+    EMmsFinished
+    };
+    
+// These are the stages for chunked encoding.
+// The chunked encoding is synchronous, so the stages are different
+// from the machine states.    
+enum TMmsChunkedEncodingStages
+    {
+    EMmsHeaders,
+    EMmsAttachmentHeaders,
+    EMmsAttachmentData
+    };
+    
+// ==================== LOCAL FUNCTIONS ====================
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------------------------
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+// All member variables are automatically zeroed in the constructor
+// of a class derived from CBase.
+// Priority is set slightly above standard (1 instead of 0) to make sure
+// that message is sent as soon as possible (user input has priority 10).
+// Variables related to chunked encoding are initialized to indicate
+// one complete chunk only.
+// ---------------------------------------------------------------------------
+//
+CMmsEncode::CMmsEncode()
+    :CMsgActive ( KMmsActiveObjectPriority ),
+    iState ( EMmsIdle ),
+    iOverallDataSize ( -1 ),
+    iLastChunk ( ETrue ),
+    iOnlyOneChunk( ETrue )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// Symbian OS default constructor can leave.
+// ---------------------------------------------------------------------------
+//
+void CMmsEncode::ConstructL( RFs& aFs )
+    {
+    iFs = aFs;
+    CActiveScheduler::Add( this );
+    }
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CMmsEncode* CMmsEncode::NewL( RFs& aFs )
+    {
+    CMmsEncode* self = new ( ELeave ) CMmsEncode;
+    
+    CleanupStack::PushL( self );
+    self->ConstructL( aFs );
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+    
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CMmsEncode::~CMmsEncode()
+    {
+
+    Cancel();
+    
+    if ( iFileOpen )
+        {
+        iAttachFile.Close();
+        iFileOpen = EFalse;
+        }
+    
+    // Do not delete pointers that were presents from the caller.
+    // The caller still owns that data
+    delete iMimeHeaders; // this is ours too.
+   
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMmsEncode::StartL(
+    MMmsEntryWrapper& aEntryWrapper,
+    CMmsHeaders& aMmsHeaders,
+    CBufFlat& aEncodeBuffer,
+    TRequestStatus& aStatus )
+    {
+
+    // This is the entry point for encoding all PDUs that contain both headers
+    // and data.
+    // For normal use the only PDUs in this category would be M-send.req and
+    // M-MBox-Upload.req, but for testing purposes the following PDUs may
+    // also be handled using this entry point:
+    // M-retrieve.conf (for testing purposes)
+    // M-Mbox-View.conf (for testing purposes)
+    // M-Mbox-Descr (for testing purposes) 
+
+    // Old asynchronous encoding is retained.
+    // Reset sets all chunk-related variables to indicate one chunk which is the last one
+    Reset();
+
+    iEntryWrapper = &aEntryWrapper;
+    iMmsHeaders = &aMmsHeaders;
+    iEncodeBuffer = &aEncodeBuffer;
+
+    if ( iMimeHeaders )
+        {
+        iMimeHeaders->Reset();
+        }
+    else
+        {
+        iMimeHeaders = CMsvMimeHeaders::NewL();
+        }
+
+    // We need to know the message entry ID
+    // The wrapper originally points to the message entry
+    
+    TMsvEntry indexEntry;
+    iError = iEntryWrapper->GetIndexEntry( indexEntry );
+    iCurrentMessageId = indexEntry.Id();
+    
+    CMsvStore* store = iEntryWrapper->ReadStoreL();
+    CleanupStack::PushL( store );
+
+    // Only new attachment structure is supported    
+    MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+    iNumberOfAttachments = attachMan.AttachmentCount();
+    
+    CleanupStack::PopAndDestroy( store );
+    
+    Queue( aStatus );
+    
+    iStatus = KRequestPending;
+    SetActive();
+    // Pretend that we called an asynchronous service
+    // in order to get into the state machine loop
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, iError );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMmsEncode::EncodeHeadersL(
+    CMmsHeaders& aMmsHeaders,
+    CBufFlat& aEncodeBuffer )
+    {
+    // This function is used to encode all PDUs that contain only headers,
+    // not data. Some are responses sent to MMSC, some are requests that
+    // contain headers only.
+    // Nothing is read from storage, everything to be encoded is contained
+    // in the headers.
+    // No active object is invoked, this is a synchronous function
+    
+    // Old one-chunk encoding is retained for encoding headers only.
+    // Reset sets all chunk-related variables to indicate one chunk which is the last one
+    Reset(); // also sets iError to KErrNone
+
+    iMmsHeaders = &aMmsHeaders;
+    iEncodeBuffer = &aEncodeBuffer;
+
+    // start from the beginning
+    iPosition = 0;
+    // we discard old contents of the buffer in case we must expand it
+    iEncodeBuffer->Reset();
+    
+    // We are a bit greedy here so that we don't need
+    // to change the code if there is a minor change in the specs.
+    iEncodeBuffer->ResizeL( iMmsHeaders->Size() + KMMSBufferExtra );
+
+    // encode message depending on type
+    // these are all types that contain headers only, never data
+    switch ( iMmsHeaders->MessageType() )
+        {
+        case KMmsMessageTypeMNotifyRespInd:
+            EncodeNotifyResponse();
+            break;
+        case KMmsMessageTypeAcknowledgeInd:
+            EncodeAcknowledgeIndication();
+            break;
+        case KMmsMessageTypeMNotificationInd:
+            EncodeMmsNotificationL();
+            break;
+        case KMmsMessageTypeForwardReq:
+            EncodeForwardRequestL();
+            break;
+        case KMmsMessageTypeReadRecInd:
+            EncodeReadReplyL();
+            break;
+        case KMmsMessageTypeMboxStoreReq:
+            EncodeMMBoxStoreRequestL();
+            break;
+        case KMmsMessageTypeMboxViewReq:
+            // This may contain keywords. Reserve some extra space
+            EncodeMMBoxViewRequestL();
+            break;
+        case KMmsMessageTypeMBoxDeleteReq:
+        case KMmsMessageTypeDeleteReq:
+            EncodeDeleteRequestL();
+            break;
+        case KMmsMessageTypeCancelConf:
+            EncodeCancelResponse();
+            break;
+        case KMmsMessageTypeReadOrigInd:
+            // This is for testing purposes.
+            // identical to ReadRecInd except for PDU type
+            // This would be the PDU sent to originator by MMSC
+            EncodeReadReplyL();
+            break;
+        case KMmsMessageTypeMSendConf:
+            // for testing purposes
+            EncodeSendConfirmationL();
+            break;
+        case KMmsMessageTypeDeliveryInd:
+            // for testing purposes
+            EncodeDeliveryReportL();
+            break;
+        case KMmsMessageTypeForwardConf:
+            // for testing purposes
+            EncodeForwardConfirmationL();
+            break;
+        case KMmsMessageTypeMboxStoreConf:
+            // for testing purposes
+            EncodeMMBoxStoreConfirmationL();
+            break;
+        case KMmsMessageTypeMBoxUploadConf:
+            // for testing purposes
+            EncodeMMBoxUploadConfirmationL();
+            break;
+        case KMmsMessageTypeMBoxDeleteConf:
+        case KMmsMessageTypeDeleteConf:
+            // for testing purposes
+            EncodeDeleteConfirmationL();
+            break;
+        case KMmsMessageTypeCancelReq:
+            // for testing purposes
+            EncodeCancelRequest();
+            break;
+#ifdef __WINS__
+        case KMmsMessageTypeMSendReq:
+            EncodeSendRequestHeadersL();
+            break;
+        case KMmsMessageTypeMBoxUploadReq:
+            // This type has attachments and headers
+            // This function encodes headers only
+            EncodeMMBoxUploadRequestL();
+            break;
+        case KMmsMessageTypeMRetrieveConf:
+            // for test purposes
+            EncodeRetrieveConfirmationL();
+            break;
+        case KMmsMessageTypeMboxViewConf:
+            // for test purposes
+            EncodeMMBoxViewConfirmationL();
+            break;
+        case KMmsMessageTypeMBoxDescr:
+            // for test purposes
+            EncodeMMBoxDescriptionL();
+            break;
+#endif
+        default:
+            // Illegal message type.
+            iEncodeBuffer->Reset();
+            iPosition = 0;
+            break;
+        }
+
+    // Remove slack to keep garbage out from the end of the file
+    iEncodeBuffer->ResizeL( iPosition );
+    // Dump the buffer contents into file if requested
+    Dump();
+    
+    iOverallDataSize = iEncodeBuffer->Size();
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+EXPORT_C void CMmsEncode::StartChunkedL(
+    MMmsEntryWrapper& aEntryWrapper,
+    CMmsHeaders& aMmsHeaders,
+    CBufFlat& aEncodeBuffer,
+    TRequestStatus& aStatus )
+    {
+    
+    // This is the entry point for chunked encoding all PDUs that contain both headers
+    // and data.
+    
+    // Reset sets all chunk-related variables to indicate one chunk which is the last one
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode: Start chunked") );
+#endif
+    Reset(); // also sets iError to KErrNone
+    iDataSupplierStage = EMmsHeaders;
+    
+    iEntryWrapper = &aEntryWrapper;
+    iMmsHeaders = &aMmsHeaders;
+    iEncodeBuffer = &aEncodeBuffer;
+
+    if ( iMimeHeaders )
+        {
+        iMimeHeaders->Reset();
+        }
+    else
+        {
+        iMimeHeaders = CMsvMimeHeaders::NewL();
+        }
+        
+    // We need to know the message entry ID
+    // The wrapper originally points to the message entry
+    
+    TMsvEntry indexEntry;
+    iError = iEntryWrapper->GetIndexEntry( indexEntry );
+    iCurrentMessageId = indexEntry.Id();
+    
+    // Encode headers to the buffer
+    // The rest will follow when next data chunk is requested.
+    EncodeHeadersChunkedL();
+    
+	aStatus=KRequestPending;
+    TRequestStatus* status = &aStatus;
+    User::RequestComplete( status, iError );
+    }
+    
+    
+// ---------------------------------------------------------
+// From class MMmsCodecDataSupplier
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::GetNextDataPart( TPtrC8& aDataPart, TBool& aLastDataChunk )
+    {
+    TInt error = KErrNone;
+    if ( !iEncodeBuffer || iEncodeBuffer->Size() == 0 )
+        {
+        // called out of context or no message data available
+        error = KErrNotFound;
+        }
+    else
+        {
+        aDataPart.Set( iEncodeBuffer->BackPtr( iPosition ) ); 
+        }
+    aLastDataChunk = iLastChunk;
+    
+    return error;
+    }
+    
+// ---------------------------------------------------------
+// From class MMmsCodecDataSupplier
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::ReleaseData()
+    {
+    if ( iOnlyOneChunk )
+        {
+        // if we have only one chunk we always point to the beginning
+        // the buffer gets cleared when all data has been handled
+        return KErrNone;
+        }
+    
+    iPosition = 0;
+    
+    // encode next data part into the buffer
+    
+    if ( iDataSupplierStage == EMmsAttachmentHeaders && iNumberOfAttachments == 0 )
+        {
+        iLastChunk = ETrue;
+        iDataSupplierStage = EMmsHeaders;
+        }
+    else if ( iDataSupplierStage == EMmsAttachmentHeaders )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- data supplier stage: Attachment headers") );
+#endif
+        iError = iEntryWrapper->SetCurrentEntry( iCurrentMessageId );
+        if ( iError != KErrNone )
+            {
+            return iError;
+            }
+        
+        iCurrentFileSize = 0;
+        CMsvStore* store = NULL;
+        TRAP( iError, 
+            {
+            store = iEntryWrapper->ReadStoreL();
+            CleanupStack::PushL( store );
+            MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+            iCurrentFileSize = EncodeHeadersAndGetFileL( attachMan );
+            CleanupStack::PopAndDestroy( store );
+            });
+        if ( iError != KErrNone )
+            {
+            return iError;
+            }
+            
+        // Now we have the attachment headers in our buffer.
+        // If there is room, put data there, too
+        
+        if ( iBufferSize - iPosition >= iCurrentFileSize )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- enough room left in buffer for attachment data") );
+#endif
+            EncodeAttachmentData( iAttachFile, iCurrentFileSize );
+            iPosition += iCurrentFileSize;
+            iAttachFile.Close();
+            iFileOpen = EFalse;
+            iCurrentAttachment++;
+            if ( iCurrentAttachment >= iNumberOfAttachments )
+                {
+                iLastChunk = ETrue;
+                iDataSupplierStage = EMmsHeaders;
+                }
+            else
+                {
+                // one attachment finished - move to next one
+                iDataSupplierStage = EMmsAttachmentHeaders;
+                }
+            }
+        else
+            {
+            iDataSupplierStage = EMmsAttachmentData;
+            }
+        }
+    else if ( iDataSupplierStage == EMmsAttachmentData )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- data supplier stage: Attachment data") );
+#endif
+        // Add as much attachment data as possible.
+        // Attachment file is now open, check position
+        TInt filePosition = 0;
+        iError = iAttachFile.Seek( ESeekCurrent, filePosition );
+        if ( iError != KErrNone )
+            {
+            return iError;
+            }
+        TInt dataLeft = iCurrentFileSize - filePosition;
+        TInt roomLeft = iBufferSize - iPosition;
+        if ( roomLeft >= dataLeft )
+            {
+            EncodeAttachmentData( iAttachFile, dataLeft );
+            iPosition += dataLeft;
+            iAttachFile.Close();
+            iFileOpen = EFalse;
+            iCurrentAttachment++;
+            if ( iCurrentAttachment >= iNumberOfAttachments )
+                {
+                iLastChunk = ETrue;
+                iDataSupplierStage = EMmsHeaders;
+                }
+            else
+                {
+                // one attachment finished - move to next one
+                iDataSupplierStage = EMmsAttachmentHeaders;
+                }
+            }
+        else
+            {
+            // we have more data than fits into buffer
+            EncodeAttachmentData( iAttachFile, roomLeft );
+            iPosition += roomLeft;
+            // We don't close the file because we still have data.
+            // We stay in EMmsAttachmentHeaders state
+            }
+        }
+    else
+        {
+        // do nothing, keep LINT happy
+        }
+#ifndef _NO_MMSS_LOGGING_
+    if ( iDataSupplierStage == EMmsHeaders )
+        {
+        TMmsLogger::Log( _L("- last chunk released") );
+        TMmsLogger::Log( _L("- data supplier stage: MMS headers") );
+        }
+#endif
+    // If we have reached the end and have been asked to release data
+    // we have nothing left to do.    
+    
+    // dump what we got into file - if needed
+    if ( iPosition > 0 )
+        {
+        DumpAppend();
+        }
+    return iError;
+    }
+    
+// ---------------------------------------------------------
+// From class MMmsCodecDataSupplier
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::OverallDataSize()
+    {
+    // If we have encoded all data, iOverallDataSize contains the 
+    // actual amount of data.
+    // If we are doing chunked encoding, it contains -1.
+    return iOverallDataSize;
+    }
+
+    
+// ---------------------------------------------------------
+// From class MMmsCodecDataSupplier
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::ResetSupplier()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode: ResetSupplier") );
+#endif
+    if ( iOnlyOneChunk )
+        {
+        // if we have only one chunk we always point to the beginning
+        // the buffer gets cleared when all data has been handled
+        return KErrNone;
+        }
+    
+    // start data from the beginning
+    iError = KErrNone;
+    iDataSupplierStage = EMmsHeaders;
+    TRAP( iError, EncodeHeadersChunkedL() );
+    
+    return iError;
+    }
+
+// ---------------------------------------------------------
+// From class CMsgActive
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::DoRunL()
+    {
+
+    // This routine takes the state machine through the states
+    // until an error is encountered or the cycle completes.
+
+    if ( iError != KErrNone )
+        {
+        // We encountered an error, and cannot continue
+        // For the time being we just give up without trying
+        // to do any decent cleanup.
+        iStatus = iError;
+        // If we return from DoRunL without becoming active again,
+        // RunL completes.
+        return;
+        }
+
+    if ( iState != EMmsFinished )
+        {
+        SelectNextState();
+        // If appropriate, ChangeStateL makes us active again
+        ChangeStateL();
+        }
+    else
+        {
+        // We are done, we must become idle again
+        FinishL();
+        iStatus = iError;
+        // If we return from DoRunL without becoming active again,
+        // RunL completes.
+        }
+    // As we are using standard Mentact RunL, we must leave
+    // if we have encountered an error, and do not want to continue
+
+    if ( iError != KErrNone && !IsActive() )
+        {
+        iPosition = 0;
+        FinishL();
+        User::Leave( iError );
+        }
+    }
+
+// ---------------------------------------------------------
+// From class CMsgActive
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::DoComplete( TInt& /* aStatus */ )
+    {
+    // We are exiting the loop - we say we are idle now
+    iState = EMmsIdle;
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::SelectNextState()
+    {
+
+    // If appropriate, the functions called within the switch statement
+    // will make us active again. If all is done, the asynchronous request
+    // will complete
+
+    switch ( iState )
+        {
+        case EMmsIdle:
+            // start the loop
+            iState = EMmsEncodingHeaders;
+            break;
+        case EMmsEncodingHeaders:
+            if ( iNumberOfAttachments > 0 )
+                {
+                iState = EMmsEncodingAttachments;
+                }
+            else
+                {
+                iState = EMmsFinished;
+                }
+            break;
+        case EMmsEncodingAttachments:
+            // if there are more attachments, don't change state
+            if ( iCurrentAttachment >= iNumberOfAttachments )
+                {
+                iState = EMmsFinished;
+                }
+            break;
+        case EMmsFinished:
+            // No more states
+            iState = EMmsIdle;
+            break;
+        default:
+            // Illegal state
+            break;
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::ChangeStateL()
+    {
+    switch ( iState )
+        {
+        case EMmsEncodingHeaders:
+            EncodeHeadersL();
+            break;
+        case EMmsEncodingAttachments:
+            EncodeAttachmentL();
+            iCurrentAttachment++;
+            break;
+        case EMmsFinished:
+            FinishL();
+            break;
+        default:
+            // Should not be here anymore
+            break;
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::Reset()
+    {
+    // close open file in case operation has ended with error
+    // and the attachment file is still open
+    if ( iFileOpen )
+        {
+        iAttachFile.Close();
+        iFileOpen = EFalse;
+        }
+
+    iNumberOfAttachments = 0;
+    iCurrentAttachment = 0;
+    iError = KErrNone;
+    iCurrentMessageId = KMsvNullIndexEntryId;
+    iOverallDataSize = -1;
+    iLastChunk = ETrue;
+    iOnlyOneChunk = ETrue;
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeHeadersL()
+    {
+
+    // start from the beginning
+    iPosition = 0;
+    // we discard old contents of the buffer in case we must expand it
+    iEncodeBuffer->Reset();
+    
+    // calculate space needed and resize buffer
+    TInt size = 0;
+    size += iMmsHeaders->Size();
+    
+    User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
+    CMsvStore* store = iEntryWrapper->ReadStoreL();
+    CleanupStack::PushL( store );
+    // AttachmentsSize function asks actual size from files
+    // in case the info in CMsvAttachment is not up to date.
+    // This function leaves if the attachment file is not found.
+    // A message cannot be sent if it refers to attachment files that no
+    // longer exist.
+    size += iEntryWrapper->AttachmentsSizeL( *store );
+    CleanupStack::PopAndDestroy( store );
+    store = NULL;
+        
+    size += KMMSBufferExtra; // this is just an estimate of header size...
+    // extra needed if lots of attachments.
+    size += KMMSAttachmentExtra * iNumberOfAttachments;
+    TMemoryInfoV1Buf memory;
+    UserHal::MemoryInfo( memory );
+    TInt available = memory().iFreeRamInBytes;
+    // check that buffer fits, leave a little memory for others too.
+    if ( size > ( available - KMmsExtra ) )
+        {
+        // message is too big - don't even try
+        iError = KMmsErrorMessageTooBig;
+        }
+
+    if ( iError == KErrNone )
+        {
+        iEncodeBuffer->ResizeL( size );
+        EncodeRequestHeadersL();
+        }
+
+    iStatus = KRequestPending;
+    SetActive();
+  
+    // We complete ourselves.
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, iError );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeHeadersChunkedL()
+    {
+    // The first step of chunked encoding
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: start") );
+#endif /* _NO_MMSS_LOGGING_ */
+    User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
+    
+    /* Korean req: 415-5434
+     * Get the target encoding MIB enum from cenrep and encode MMS text objects using coresponding conversion plugins
+     */
+    TInt temp;
+    iTargetEncodingType = 0;
+    CRepository* repository = CRepository::NewLC( KUidMmsServerMtm );    
+    if ( repository->Get( KMmsEncodingType, temp ) == KErrNone )
+        {
+        iTargetEncodingType = temp;
+        }
+    CleanupStack::PopAndDestroy( repository );
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: target encoding type: %d"), iTargetEncodingType );
+#endif /* _NO_MMSS_LOGGING_ */
+
+    if( iTargetEncodingType != 0 )
+        {
+        TRAPD( err, PreProcessAttachmentDataL() );
+
+#ifndef _NO_MMSS_LOGGING_
+    /* if any error, korean specific encoding failed, But this should not stop from sending MMS using
+     * existing default encoding. Hence just log the error and continue in any case
+     */
+        if( err != KErrNone )
+            {
+            TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: PreProcessAttachmentDataL error: %d"), err );
+            }
+#endif /* _NO_MMSS_LOGGING_ */
+        }
+    
+    //Open store for read-only purpose
+    CMsvStore* store = iEntryWrapper->ReadStoreL();
+    CleanupStack::PushL( store );
+    
+    // Only new attachment structure is supported    
+    MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+    iNumberOfAttachments = attachMan.AttachmentCount();
+    
+    TInt size = 0;
+    size += iMmsHeaders->Size();
+    size += KMMSBufferExtra; // this is just an estimate of header size...
+    // The buffer must be at least big enough to hold all headers
+    iBufferSize = Max( KMmsChunkedBufferSize, size );
+    
+    // extra needed if lots of attachments.
+    // AttachmentsSize function asks actual size from files
+    // in case the info in CMsvAttachment is not up to date.
+    // This function leaves if the attachment file is not found.
+    // A message cannot be sent if it refers to attachment files that no
+    // longer exist.
+    size += iEntryWrapper->AttachmentsSizeL( *store );
+    size += KMMSAttachmentExtra * iNumberOfAttachments;
+    CleanupStack::PopAndDestroy( store );
+    store = NULL;
+
+    if ( iBufferSize > size )
+        {
+        // Our message is small enough to be sent in one chunk.
+        // It does not make sense to send the message in small chunks
+        // it the total is only a few kilobytes
+        iBufferSize = size;
+        iOnlyOneChunk = ETrue;
+        iLastChunk = ETrue;
+        }
+    else
+        {
+        // we need several chunks
+        iOnlyOneChunk = EFalse;
+        iLastChunk = EFalse;
+        }
+        
+    // start from the beginning
+    iPosition = 0;
+    iEncodeBuffer->Reset();
+    // This leaves if unable to resize.
+    // We try to keep our buffer small enough so that this does not leave.
+    iEncodeBuffer->ResizeL( iBufferSize );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: MMS buff Size(Approx): %d"), iBufferSize );
+#endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
+
+    EncodeRequestHeadersL();
+    
+    TInt i = 0;
+    if ( iOnlyOneChunk )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: only one chunk") );
+#endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
+        for ( i = 0; ( i < iNumberOfAttachments ) && ( iError == KErrNone ); i++ )
+            {
+            iCurrentAttachment = i;
+            // encode attachments, too, as we have decided that our message
+            // is small enough to fit into the buffer as one chunk
+            // DoEncodeAttachment always encodes iCurrentAttachment
+            // and updates buffer position as needed.
+            DoEncodeAttachmentL();
+            // If something goes wrong, DoEncodeAttachmentL() sets iError,
+            // and StartChunkedL will complete the caller with error.
+            }
+        iEncodeBuffer->ResizeL( iPosition );
+        iOverallDataSize = iEncodeBuffer->Size();
+        }
+    else
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: Multiple chunks") );
+#endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
+        // chunked sending - but it should be possible to calculate data size
+        iOverallDataSize = iPosition; // This is the amount taken by headers
+        // The message is small enough to be sent as one chunk
+        for ( i = 0; ( i < iNumberOfAttachments ) && ( iError == KErrNone ); i++ )
+            {
+            iCurrentAttachment = i;
+            // encode attachments, too, as we have decided that our message
+            // is small enough to fit into the buffer as one chunk
+            // DoEncodeAttachment always encodes iCurrentAttachment
+            // and updates buffer position as needed.
+            iOverallDataSize += DoGetAttachmentEncodingLengthL();
+            // If something goes wrong, DoEncodeAttachmentL() sets iError,
+            // and StartChunkedL will complete the caller with error.
+            }
+        iCurrentAttachment = 0;
+        iDataSupplierStage = EMmsAttachmentHeaders;
+        if ( iError != KErrNone )
+            {
+            iOverallDataSize = -1;
+            }
+        }
+     
+    // Dump headers. More data will follow    
+    Dump();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: end") );
+#endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeAttachmentL()
+    {
+
+    DoEncodeAttachmentL();
+    
+    if ( iError != KErrNone )
+        {
+        // If we return without becoming active again, RunL completes
+        // we cannot send this message, because we cannot access attachments
+        return;
+        }
+
+    iStatus = KRequestPending;
+    SetActive();
+  
+    // Now we indicate we already did it.
+    TRequestStatus* status = &iStatus;
+    User::RequestComplete( status, iError );
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::DoEncodeAttachmentL()
+    {
+    
+    // Encode one part
+    // We must calculate length of headers and content type
+    
+    User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
+        
+    CMsvStore* store = iEntryWrapper->ReadStoreL();
+    CleanupStack::PushL( store );
+    MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+    
+    TInt size = 0;
+    size = EncodeHeadersAndGetFileL( attachMan );
+    if ( iError != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( store );
+        return;
+        }
+    
+    // The data read function will not leave
+    EncodeAttachmentData( iAttachFile, size );
+    iPosition += size;
+    iAttachFile.Close();
+
+    CleanupStack::PopAndDestroy( store );
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::DoGetAttachmentEncodingLengthL()
+    {
+    
+    // calculate length of headers and content type
+    
+    User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
+        
+    CMsvStore* store = iEntryWrapper->ReadStoreL();
+    CleanupStack::PushL( store );
+    MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+    
+    TInt size = 0;
+    size = GetHeadersAndFileSizeL( attachMan );
+    CleanupStack::PopAndDestroy( store );
+    return size;
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::EncodeHeadersAndGetFileL( MMsvAttachmentManager& aAttachMan )
+    {
+    
+    CMsvAttachment* attachmentInfo = NULL;
+    attachmentInfo = aAttachMan.GetAttachmentInfoL( iCurrentAttachment );
+    CleanupStack::PushL( attachmentInfo );
+    
+    iMimeHeaders->RestoreL( *attachmentInfo );
+        
+    // We don't trust the info, we ask the file itself
+    // Someone outside the messaging system may have changed the file
+    // without changing the attachment info
+    TInt size = 0;
+    if ( iFileOpen )
+        {
+        // close file in case we have been reset while the file is still open
+        iAttachFile.Close();
+        iFileOpen = EFalse;
+        }
+    iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment );
+    iError = iAttachFile.Size( size );
+    iAttachFile.Close();
+
+    if ( iError != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( attachmentInfo );
+        return size;
+        }
+
+    // calculate the length of the headers
+    TBool foundName = EFalse;
+    TUint contentTypeSize = 0;
+    TInt8 contentType = -1; // indicate not found
+    TPtrC8 contentTypeString;
+
+    TUint headerSize = 0;
+    
+    HBufC8* buf8 = CalculateAttachmentHeaderLengthL(
+        *attachmentInfo,
+        headerSize,    
+        foundName,
+        contentTypeSize,
+        contentType,
+        contentTypeString );
+     
+    CleanupStack::PushL( buf8 );
+        
+    // We have calculated the header length, now we can encode:
+
+    TPtrC8 nameString;
+    if ( !foundName && buf8 )
+        {
+        nameString.Set( buf8->Des() );
+        }
+        
+    EncodeAttachmentHeadersL(
+        size,
+        headerSize,
+        foundName,
+        contentTypeSize,
+        contentType,
+        contentTypeString,
+        nameString );
+
+    // now we have put the name all over, we can destroy the buffer
+    CleanupStack::PopAndDestroy( buf8 );
+    buf8 = NULL;
+    CleanupStack::PopAndDestroy( attachmentInfo );
+    attachmentInfo = NULL;
+    
+    // Now just write all the data octets
+    iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment );
+    iFileOpen = ETrue;
+    
+    return size;
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::GetHeadersAndFileSizeL( MMsvAttachmentManager& aAttachMan )
+    {
+    
+    CMsvAttachment* attachmentInfo = NULL;
+    attachmentInfo = aAttachMan.GetAttachmentInfoL( iCurrentAttachment );
+    CleanupStack::PushL( attachmentInfo );
+    
+    iMimeHeaders->RestoreL( *attachmentInfo );
+        
+    // We don't trust the info, we ask the file itself
+    // Someone outside the messaging system may have changed the file
+    // without changing the attachment info
+    TInt size = 0;
+    if ( iFileOpen )
+        {
+        // close file in case we have been reset while the file is still open
+        iAttachFile.Close();
+        iFileOpen = EFalse;
+        }
+    iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment );
+    iError = iAttachFile.Size( size );
+    iAttachFile.Close();
+
+    if ( iError != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( attachmentInfo );
+        return 0;
+        }
+
+    // calculate the length of the headers
+    TBool foundName = EFalse;
+    TUint contentTypeSize = 0;
+    TInt8 contentType = -1; // indicate not found
+    TPtrC8 contentTypeString;
+
+    TUint headerSize = 0;
+    
+    HBufC8* buf8 = CalculateAttachmentHeaderLengthL(
+        *attachmentInfo,
+        headerSize,    
+        foundName,
+        contentTypeSize,
+        contentType,
+        contentTypeString );
+        
+    delete buf8; // This is not needed
+    buf8 = NULL;     
+     
+    CleanupStack::PopAndDestroy( attachmentInfo );
+    attachmentInfo = NULL;
+    
+    // We have calculated the header length, now we still need the
+    // uintvar lengths:
+    
+    size += GetUintvarLength( size ); // encoding size for attachment length
+    size += headerSize;
+    size += GetUintvarLength( headerSize ); // encoding size for header length
+ 
+    return size;
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+HBufC8* CMmsEncode::CalculateAttachmentHeaderLengthL(
+    CMsvAttachment& aAttachmentInfo,
+    TUint& aHeaderLength,
+    TBool& aFoundName,
+    TUint& aContentTypeSize,
+    TInt8& aContentType,
+    TPtrC8& aContentTypeString  )
+    {
+    
+    TInt numNonSafe = 0; // number of characters in filename that would require encoding
+    // Not all content types have parameters.
+    // The only parameter we can handle to some extent
+    // is the character set parameter for text content types.
+    // The name parameter will always be added if not already present
+    
+    // Check if we have well-known media.
+    aContentType = -1; // indicate not found
+    aContentTypeString.Set( aAttachmentInfo.MimeType() );
+    if ( aContentTypeString.Length() == 0 )
+        {
+        // take type from mime headers
+        HBufC8* tempContentType = HBufC8::NewL(
+            iMimeHeaders->ContentType().Length() +
+            iMimeHeaders->ContentSubType().Length() + 1 );
+        CleanupStack::PushL( tempContentType );
+        tempContentType->Des().Copy( iMimeHeaders->ContentType() );
+        if ( ( iMimeHeaders->ContentType().Find( KMmsSlash8 ) !=
+            ( iMimeHeaders->ContentType().Length() - 1 ) ) &&
+            ( iMimeHeaders->ContentSubType().Find( KMmsSlash8 ) != 0 ) &&
+            ( iMimeHeaders->ContentSubType().Length() != 0 ) )
+            {
+            tempContentType->Des().Append( KMmsSlash8 );
+            }
+        tempContentType->Des().Append( iMimeHeaders->ContentSubType() );
+        aAttachmentInfo.SetMimeTypeL( tempContentType->Des() );
+        CleanupStack::PopAndDestroy( tempContentType );
+        aContentTypeString.Set( aAttachmentInfo.MimeType() );
+        }
+        
+    TInt8 i;
+    for ( i = 0; i < KNumberContentTypes && aContentType < 0; i++ )
+        {
+        if ( aContentTypeString.CompareF(
+            TPtrC8( KContentTypeTable[i] ) ) == 0 )
+            {
+            aContentType = i;
+            }
+        }
+    if ( aContentTypeString.Length() == 0 )
+        {
+        aContentTypeString.Set( KMmsUnknownType );
+        aContentType = -1;
+        }
+        
+    // we always add the name parameter to content type, so we always
+    // use the general form. If no name is given, we use the original filename
+    // If the name parameter is defined, we use it.
+
+    aFoundName = EFalse;
+    iFileName.SetLength( 0 );
+
+    aHeaderLength = 0;
+    // add media type length
+    if ( aContentType >= 0 )
+        {
+        // well-known media
+        aHeaderLength += 1;
+        }
+    else
+        {
+        // Extension media
+        aHeaderLength += aContentTypeString.Length();
+        aHeaderLength += 1; // terminating zero
+        }
+
+    // If we have paramters, we must calculate their length.
+    if ( iMimeHeaders->MimeCharset() != 0 )
+        {
+        // charset has well-known encoding
+        aHeaderLength += 1;
+        if ( iMimeHeaders->MimeCharset() <= KMmsShortIntegerLimit127 )
+            {
+            // short integer
+            aHeaderLength += 1;
+            }
+        else if ( iMimeHeaders->MimeCharset() < KMmsOneByteLimit )
+            {
+            // long integer, short length + 1 byte of value
+            aHeaderLength += KMms2;
+            }
+        else if ( iMimeHeaders->MimeCharset() < KMmsTwoByteLimit )
+            {
+            // long integer, short length + 2 bytes of value
+            // so far I don't know any IANA numbers that would
+            // take more than two hex bytes.
+            aHeaderLength += KMms3;
+            }
+        else if ( iMimeHeaders->MimeCharset() < KMmsThreeByteLimit )
+            {
+            // long integer, short length + 3 bytes of value
+            aHeaderLength += KMms4;
+            }
+        else
+            {
+            // long integer, short length + 4 bytes of value
+            // cannot be longer than this in any case
+            aHeaderLength += KMms5;
+            }
+        }
+    // Then the rest of the parameters, unknown,
+    // sent as text strings
+    // If "name" attribute has been defined, we use it.
+    // if it is not added, we must add it.
+    // We must ensure that we don't add it twice...
+    
+    TInt mimeHeaderCount = iMimeHeaders->ContentTypeParams().MdcaCount();
+
+    for ( i = 0; i < mimeHeaderCount; i++ )
+        {
+        // If we have corrupted parameters (length of name is zero)
+        // we skip the name/value pair.
+        // value may be zero, it will be encoded as just the terminating zero
+        if ( i%2 == 0 &&
+            iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() == 0 )
+            {
+            i++;
+            }
+        else
+            {
+            // 8-byte string size + terminating zero
+            // If parameter has no value, it still must have
+            // the "no-value" indicator (just the terminating zero.)
+            if ( iMimeHeaders->ContentTypeParams().MdcaPoint( i ).CompareF(
+                KWspNameString ) == 0 && i%2 == 0 )
+                {
+                if ( ( i + 1 ) < mimeHeaderCount && 
+                    IsStringSafe( iMimeHeaders->ContentTypeParams().MdcaPoint( i + 1 ),
+                    numNonSafe ) )
+                    {
+                    // We always move the name to the first item.
+                    // It may be this parameter or something else
+                    
+                    // Content type parameters are 8-bit strings.
+                    // We can use the name only if it is safe, otherwise it may contain some
+                    // unknown encoding (maybe utf-8).
+                    iFileName.Copy( ( iMimeHeaders->ContentTypeParams().
+                       MdcaPoint( i + 1 ) ).Right( KMmsMaxFileName ) );
+                    i++;
+                    }
+                else
+                    {
+                    // Skip the next field as it can only be used if it is safe
+                    i++;
+                    }
+                }
+            else
+                {
+                aHeaderLength += iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() + 1;
+                }
+            }
+        }
+    if ( ( iMimeHeaders->ContentTypeParams().MdcaCount() % 2 ) == 1 )
+        {
+        // Odd number. Obviously last paramter has no value.
+        // Add the "no value" token
+        aHeaderLength++;
+        }
+
+    // include name parameter to content-type
+
+    // if the name was not among our mime headers,
+    // we must add it.
+    TInt nameLength = 0;
+
+    // We prefer the suggested filename as the content type name parameter.
+    // If version is 1.3 or later, we can encode a non-safe filename.
+    // If suggested filename is not safe, but we already have a safe filename
+    // in iFilename, we don't override it if version is 1.2 or lower
+    if ( iMimeHeaders->SuggestedFilename().Length() > 0 )
+        {
+        if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ||
+             IsStringSafe( iMimeHeaders->SuggestedFilename() ) ||
+             iFileName.Length() == 0 )
+            {
+            iFileName.Copy( iMimeHeaders->SuggestedFilename().Right( KMmsMaxFileName ) );
+            }
+        }
+        
+    TParse* parse = NULL;
+    // If we don't have a filename suggestion so far, we just use the
+    // actual filename the attachment manager has used to save the file.    
+    if ( iFileName.Length() == 0 )
+        {
+        parse = new( ELeave )TParse;
+        CleanupStack::PushL( parse );
+        // aAttachmentInfo.FilePath() is an actual Symbian filename including path
+        // so it never can be too long to fit into TParse or TFilename 
+        parse->Set( aAttachmentInfo.FilePath(), NULL, NULL );
+        iFileName.Copy( parse->NameAndExt() );
+        CleanupStack::PopAndDestroy( parse );
+        parse = NULL;
+        }
+
+    // Last effort:
+    // If our version is 1.2 or lower and the filename suggestion so far
+    // is not safe, we try content-location. It is always safe
+        
+    if ( iMmsHeaders->MmsVersion() <= KMmsVersion12 &&
+        !IsStringSafe( iFileName ) )
+        {
+        if ( iMimeHeaders->ContentLocation().Length() > 0 )
+            {
+            // content location should be safe.
+            // However, we must make sure it contains no URI escapes.
+            // for example space is legal in filename, but not in URI.
+            HBufC16* decoded = NULL;
+            TRAPD( error, ( decoded = EscapeUtils::EscapeDecodeL(
+                iMimeHeaders->ContentLocation() ) ) );
+            if ( error == KErrNone )
+                {
+                iFileName.Copy( decoded->Des().Right( KMmsMaxFileName ) );
+                delete decoded;
+                decoded = NULL;
+                }
+            else
+                {
+                iFileName.Copy( iMimeHeaders->ContentLocation().Right( KMmsMaxFileName ) );
+                }
+            }
+        }
+        
+    // remove leading and trailing spaces just in case...    
+    iFileName.Trim();    
+        
+    // We should now make sure that the filename is not too long.
+    // According to MMS conformance specs, the maximum should be 40 characters
+    // It is unclear if the characters mean the total length or the length
+    // after conversion to utf-8, but as a first approximation we try
+    // to ensure that the total does not exceed 40 characters
+    
+    nameLength = iFileName.Length();
+    
+    if ( nameLength > KMmsMaxFileNameLength )
+        {
+        parse = new( ELeave )TParse;
+        CleanupStack::PushL( parse );
+        parse->Set( aAttachmentInfo.FilePath(), NULL, NULL );
+        iFileName.Copy( parse->Name().Left( KMmsMaxFileNameLength - parse->Ext().Length() ) );
+        iFileName.Append( parse->Ext() );
+        CleanupStack::PopAndDestroy( parse );
+        parse = NULL;
+        nameLength = iFileName.Length();
+        }
+
+    // If encoding version is <=1.2, make filename safe,
+    // otherwise use MIME encoding (either base64 or quoted printable)
+    
+    HBufC8* buf8 = NULL;
+
+    TPtrC16 originalName;
+    TBuf16<1> oneCharacter;
+    originalName.Set( iFileName );
+
+    TInt j;
+    
+    if ( IsStringSafe( iFileName ) )
+        {
+        // filename only contains us-ascii characters - use as is 
+        buf8 = HBufC8::NewL( nameLength );
+        CleanupStack::PushL( buf8 );
+        buf8->Des().Copy( iFileName );      
+        }
+    else
+        {
+        if ( iMmsHeaders->MmsVersion() <= KMmsVersion12 )
+            {
+            // if version is <= 1.2, the filename must be us-ascii
+            // replace all illegal characters by underscore
+            buf8 = HBufC8::NewL( nameLength );
+            CleanupStack::PushL( buf8 );
+            for ( j = 0; j < nameLength; j++ )
+                {
+                oneCharacter.Copy( originalName.Mid( j, 1 ) );
+                if ( !IsStringSafe( oneCharacter ) )
+                    {
+                    _LIT( KMmsUnderscore, "_" );
+                    oneCharacter.Copy( KMmsUnderscore );
+                    }
+                buf8->Des().Append( oneCharacter );
+                }
+            }
+        else
+            {
+            // MMS encapsulation version is 1.3 or later
+            // Using non-ascii characters in filename parameter is allowed
+            // The filename must be encoded either using base64 or quoted printable
+            HBufC8* temp = NULL;
+            temp = CnvUtfConverter::ConvertFromUnicodeToUtf8L( originalName );
+            CleanupStack::PushL( temp );
+            // Now we have the filename in utf-8.
+            // We must check if it contains non-ascii, and if it does,
+            // we must use base64 or quoted-printable encoding.
+            TInt numNonSafe;
+            // Actually we know already that we are not safe. We just need
+            // to get the number of non-ascii characters
+            IsStringSafe( temp->Des(), numNonSafe );
+            // We prefer quoted printable as it looks nicer in case we have mostly ascii,
+            // and it leaves extension in cleartext anyway
+            if ( ( temp->Des().Length() + ( KMms2 * numNonSafe ) ) <= KMaxEncodingLength )
+                {
+                // use quoted printable, but first convert spaces to underscores
+                TInt spacePosition = temp->Des().Find( KSpace8 );
+                while ( spacePosition != KErrNotFound )
+                    {
+                    temp->Des()[ spacePosition ] = KMmsIntUnderscore;
+                    spacePosition = temp->Des().Find( KSpace8 );
+                    }
+                buf8 = EncodeQuotedPrintableWordL( temp->Des() );
+                }
+            else
+                {
+                // use base64
+                // We have not restricted the filename length in utf-8 format,
+                // so it may be way longer than 40 bytes.
+                // However, we can calculate the length the buffer needs, so we
+                // can try. However, we may end up with some soft line break in 
+                // the middle of the parameter which may not be acceptable.
+                buf8 = EncodeBase64WordL( temp->Des() );
+                }
+            
+            CleanupStack::PopAndDestroy( temp );
+            
+            CleanupStack::PushL( buf8 );
+            // we must change nameLength here
+            }
+        }
+
+    // The name is now in buf8, either just copied or encoded
+    nameLength = buf8->Des().Length();
+
+    if ( aFoundName == EFalse )
+        {
+        // well-known encoding for the header itself
+        aHeaderLength++;
+        aHeaderLength += nameLength;
+        aHeaderLength += 1; // terminating zero
+        }
+
+    aContentTypeSize = aHeaderLength;
+
+    // As we have general form (at least name parameter), we need to indicate the length
+    if ( aContentTypeSize <= KMms30 )
+        {
+        // short length
+        aHeaderLength += 1;
+        }
+    else
+        {
+        // length quote + at least one byte of uintvar
+        aHeaderLength += KMms2;
+        // Expecting over 128 bytes is paranoid.
+        if ( aContentTypeSize >= KMms0x7F )
+            {
+            aHeaderLength++;
+            }
+        }
+        
+    // Now the rest of the mime headers:
+
+    // Content-location
+    // just a short integer + a null terminated string
+
+    if ( iMimeHeaders->ContentLocation().Length() > 0 )
+        {
+        aHeaderLength += 1; // encoding of header as short integer
+
+        // If we want to make sure we are safe,
+        // we must call IsStringSafe() function.
+
+        // We just assume we are safe now.
+        aHeaderLength += iMimeHeaders->ContentLocation().Length();
+        aHeaderLength += 1; // terminating zero
+        }
+
+   // Content-ID
+
+    if ( iMimeHeaders->ContentId().Length() > 0 )
+        {
+        aHeaderLength += 1; // encoding of header as short integer
+        // add terminating zero and preceding quote.
+        // (needed according to WSP 1.3)
+        aHeaderLength += iMimeHeaders->ContentId().Length() + KMms2;
+        if ( iMimeHeaders->ContentId().Find( KMmsLeftAngle ) != 0 )
+            {
+            aHeaderLength += KMms2; // we must add angle bracket
+            }
+        }
+        
+    // x-type parameters
+    // Must be stored as name/value pairs like content-type parameters
+    // X-parameter[i] = parameter name
+    // X-parameter[i+1] = parameter value
+    
+    for ( i = 0; i < iMimeHeaders->XTypeParams().MdcaCount(); i++ )
+        {
+        // If we have corrupted parameters (length of name is zero)
+        // we skip the name/value pair.
+        // value may be zero, it will be encoded as just the terminating zero
+        if ( i%2 == 0 &&
+            ( iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() == 0  ||
+            iMimeHeaders->XTypeParams().MdcaPoint( i ).CompareF( 
+            KMmsSeparateDeliveryOmaXHeader ) == 0 ) )
+            {
+            // We skip the header and its value if
+            // a) the header length is 0
+            // b) the header is X-Oma-Drm-Separate-Delivery
+            i++;
+            }
+        else
+            {
+            aHeaderLength += iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() + 1;
+            }
+        }
+    if ( ( iMimeHeaders->XTypeParams().MdcaCount() % 2 ) == 1 )
+        {
+        // Odd number. Obviously last paramter has no value.
+        // Add the "no value" token
+        aHeaderLength++;
+        }
+        
+    // THESE ARE NOT IMPLEMENTED
+
+    // Content-disposition & parameters
+    // Content-description
+    // Content-base
+    // Relative path
+    // version
+
+#ifdef CONTENT_DISPOSITION_TEST
+// not supported
+
+    // We generate a general header for content disposition
+    // for tests we use the actual filename.
+    // In real life the user's filename should not be
+    // sent out to the world
+
+    // Fixed coding: 
+    // Content Disposition, value length, attachment, filename,
+    // actual filename + terminating 0
+
+    // attachment, filename, terminating zero
+    // content disposition should be text-string, not quoted text string
+    TInt contentDispositionLength = KMms3 + nameLength;
+
+    TInt valueLengthLength = 1;
+    if ( contentDispositionLength > KMms30 )
+        {
+        // lengths 0 - 30 are encoded using "short length"
+        valueLengthLength++;
+        // 
+        if ( contentDispositionLength > ShortIntegerLimit127 )
+            {
+            valueLengthLength++;
+            }
+        // Should never be longer than this.
+        // I don't think anybody has a filename that is longer than 16383 bytes.
+        }
+
+    aHeaderLength += valueLengthLength + contentDispositionLength + 1;
+#endif
+
+    CleanupStack::Pop( buf8 );
+    return buf8; // caller will delete this afterwards
+    
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeAttachmentHeadersL(
+    TUint aSize,
+    TUint aHeaderSize,
+    TBool aFoundName,
+    TUint aContentTypeSize,
+    TInt8 aContentType,
+    TPtrC8& aContentTypeString,
+    TPtrC8& aNameString )
+    {
+    
+    EncodeUintvar( aHeaderSize );
+
+    EncodeUintvar( aSize );
+
+    TUint8 temp = 0; // used to set the high bit for integers
+
+    // if we have character set (or other parameters),
+    // we must use general encoding
+
+    EncodeValueLength( aContentTypeSize );
+
+    if ( aContentType >= 0 )
+        {
+        temp = aContentType | KMms0x80;
+        iEncodeBuffer->Write( iPosition, &temp, 1 );
+        iPosition++;
+        }
+    else
+        {
+        // we assume this is a safe string
+        EncodeTextString( aContentTypeString );
+        }
+    
+    // Then content type parameters. Mainly character set,
+    // but maybe something else, too
+
+    temp = KWspCharset | KMms0x80; // encode as short integer
+    EncodeOptionalInteger( temp, iMimeHeaders->MimeCharset() );
+
+    // if we didn't find "Name" parameter among our paramters, we
+    // put it first.
+
+    // we need the name later anyway...
+
+    if ( !aFoundName )
+        {
+        temp = KWspName | KMms0x80; // encode as short integer
+        EncodeHeaderAndTextString( temp, aNameString );
+        }
+
+    // Then the rest of content type parameters, just text strings.
+    
+    TInt i = 0;
+    
+    for ( i = 0; i < iMimeHeaders->ContentTypeParams().MdcaCount(); i++ )
+        {
+        // If we have corrupted parameters (length of name is zero)
+        // we skip the name/value pair.
+        // value may be zero, it will be encoded as just the terminating zero
+        if ( i%2 == 0 &&
+            iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() == 0 )
+            {
+            i++;
+            }
+        else
+            {
+            // 8-byte string + terminating zero
+            // If parameter has no value, it still must have
+            // the "no-value" indicator (just the terminating zero.)
+            // The ContentTypeParameters function provides
+            // an empty string in this case.
+            if ( iMimeHeaders->ContentTypeParams().MdcaPoint( i ).CompareF(
+                KWspNameString ) == 0 && i%2 == 0 ) 
+                {
+                if ( aFoundName )
+                    {
+                    temp = KWspName | KMms0x80; // encode as short integer
+                    iEncodeBuffer->Write( iPosition, &temp, 1 );
+                    iPosition++;
+                    }
+                else
+                    {
+                    // we can use name from mime headers only if it is "safe"
+                    // (contains only us-ascii characters)
+                    // If the name is not safe, the parameter value is skipped
+                    i++;
+                    }
+                }
+            else
+                {
+                EncodeTextString(
+                    iMimeHeaders->ContentTypeParams().MdcaPoint( i ) );
+                }
+            }
+        }
+    if ( ( iMimeHeaders->ContentTypeParams().MdcaCount() % 2 ) == 1 )
+        {
+        // Odd number. Obviously last paramter has no value.
+        // Add the "no value" token
+        iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+        iPosition++;
+        }
+
+    // content-location
+    temp = KWspContentLocation | KMms0x80; // encode as short integer
+    EncodeOptionalStringL( temp, iMimeHeaders->ContentLocation() );
+
+    // content-id
+    if ( iMimeHeaders->ContentId().Length() > 0 )
+        {
+        HBufC8* tempContentId = HBufC8::NewL( iMimeHeaders->ContentId().Length() + KMms2 );
+        CleanupStack::PushL( tempContentId );
+        if ( iMimeHeaders->ContentId().Find( KMmsLeftAngle ) != 0 )
+            {
+            tempContentId->Des().Copy( KMmsLeftAngle );
+            tempContentId->Des().Append( iMimeHeaders->ContentId() );
+            tempContentId->Des().Append( KMmsRightAngle );
+            }
+        else
+            {
+            tempContentId->Des().Copy( iMimeHeaders->ContentId() );
+            }
+        temp = KWspContentId | KMms0x80; // encode as short integer
+        iEncodeBuffer->Write( iPosition, &temp, 1 );
+        iPosition++;
+        EncodeQuotedTextString( tempContentId->Des() );
+        CleanupStack::PopAndDestroy( tempContentId );
+        }
+
+#ifdef CONTENT_DISPOSITION_TEST
+// not supported
+     temp = 0x2E | KMms0x80; // content disposition
+     iEncodeBuffer->Write( iPosition, &temp, 1 );
+     iPosition++;
+     EncodeValueLength( contentDispositionLength );
+     temp = 0x81; // attachment
+     iEncodeBuffer->Write( iPosition, &temp, 1 );
+     iPosition++;
+     temp = 0x06 | KMms0x80; // filename
+     // filename should be text-string, not quoted
+     EncodeHeaderAndTextString( temp, buf8->Des() );
+#endif
+
+        // x-type parameters
+    for ( i = 0; i < iMimeHeaders->XTypeParams().MdcaCount(); i++ )
+        {
+        // If we have corrupted parameters (length of name is zero)
+        // we skip the name/value pair.
+        // value may be zero, it will be encoded as just the terminating zero
+        if ( i%2 == 0 &&
+            ( iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() == 0  ||
+            iMimeHeaders->XTypeParams().MdcaPoint( i ).CompareF( 
+            KMmsSeparateDeliveryOmaXHeader ) == 0 ) )
+            {
+            // We skip the header and its value if
+            // a) the header length is 0
+            // b) the header is X-Oma-Drm-Separate-Delivery
+            i++;
+            }
+        else
+            {
+            // 8-byte string + terminating zero
+            // If parameter has no value, it still must have
+            // the "no-value" indicator (just the terminating zero.)
+            // The ContentTypeParameters function provides
+            // an empty string in this case.
+            EncodeTextString( iMimeHeaders->XTypeParams().MdcaPoint( i ) );
+            }
+        }
+    if ( ( iMimeHeaders->XTypeParams().MdcaCount() % 2 ) == 1 )
+        {
+        // Odd number. Obviously last paramter has no value.
+        // Add the "no value" token
+        iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+        iPosition++;
+        }
+        
+    // End of MIME headers
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeAttachmentData( RFile& aAttachFile, TInt aSize )
+    {
+    // read the attachment file
+    // set up a pointer to point to iEncodeBuffer at iPosition
+    TPtr8 pos = iEncodeBuffer->Ptr( iPosition );
+    // Attachemnt may be a file attacment or a linked file.
+    // The file pointer will point to unread part if file is read in chunks
+    iError = aAttachFile.Read( pos, aSize );
+    }
+    
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::FinishL()
+    {
+
+    // Remove slack to keep garbage out from the end of the file
+    iEncodeBuffer->ResizeL( iPosition );
+    iOverallDataSize = iEncodeBuffer->Size();
+    iState = EMmsIdle;
+    
+    // Dump the buffer contents into file if requested
+    Dump();
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeRequestHeadersL()
+    {
+    // encode message depending on type
+    switch ( iMmsHeaders->MessageType() )
+        {
+        // KMmsMessageTypeMNotifyRespInd and KMmsMessageTypeAcknowledgeInd and all other PDUs
+        // that contain only headers and no data should be handled by
+        // using function
+        // EncodeHeadersL(CMmsHeaders& aMmsHeaders,CBufFlat& aEncodeBuffer)
+        case KMmsMessageTypeMSendReq:
+            EncodeSendRequestHeadersL();
+            break;
+        case KMmsMessageTypeMBoxUploadReq:
+            // This type has attachments and headers
+            EncodeMMBoxUploadRequestL();
+            break;
+        case KMmsMessageTypeMRetrieveConf:
+            // for test purposes
+            EncodeRetrieveConfirmationL();
+            break;
+        case KMmsMessageTypeMboxViewConf:
+            // for test purposes
+            EncodeMMBoxViewConfirmationL();
+            break;
+        case KMmsMessageTypeMBoxDescr:
+            // for test purposes
+            EncodeMMBoxDescriptionL();
+            break;
+        default:
+            iError = KMmsErrorUnknownMessageType;
+            break;
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeSendRequestHeadersL()
+    {
+        
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMSendReq,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    // if we have set a date, insert it
+    EncodeDate( iMmsHeaders->Date() );
+
+    // If we have set the sender, encode it
+    // If not, we ask MMSC to add the sender
+    EncodeSenderL( iMmsHeaders->Sender() );
+
+    // All recipient lists. If no recipients in some of the lists,
+    // nothing is encoded, no need to check separately
+    EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
+    EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
+    EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc );
+
+    // Subject
+    EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
+
+    // Message class
+    EncodeOptionalByte( KMmsAssignedMessageClass,
+        iMmsHeaders->MessageClass() );
+
+    // Expiration time
+    EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
+        iMmsHeaders->ExpiryInterval(),
+        iMmsHeaders->ExpiryDate() );
+
+    // Delivery time
+    EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime,
+        iMmsHeaders->DeliveryTimeInterval(),
+        iMmsHeaders->DeliveryDate() );
+
+    // Priority
+    EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() );
+    
+    // Sender visibility
+    EncodeOptionalByte( KMmsAssignedSenderVisibility,
+        iMmsHeaders->SenderVisibility() );
+
+    // Delivery report
+    EncodeOptionalByte( KMmsAssignedDeliveryReport,
+        iMmsHeaders->DeliveryReport() );
+
+    // Read reply
+    EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
+
+    // MMS encapsulation 1.1 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion1 )
+        {
+        // Do we want to specify reply charging
+        if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested ||
+            iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly )
+            {
+            // Reply charging value
+            EncodeOptionalByte( KMmsAssignedReplyCharging,
+                iMmsHeaders->ReplyCharging() );
+            // Reply charging deadline
+            EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
+                iMmsHeaders->ReplyChargingInterval(),
+                iMmsHeaders->ReplyChargingDate() );
+            // Reply charging size
+            EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
+            }
+        // Reply charging ID
+        EncodeOptionalString( KMmsAssignedReplyChargingID,
+            iMmsHeaders->ReplyChargingId() );
+        }
+
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
+        {
+        // MMBox related headers - optional
+        if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+            {
+            // X-Mms-MM-Store
+            EncodeOptionalByte( KMmsAssignedMmsStore,
+                iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() );
+            if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() == KMmsYes )
+                {
+                // X-Mms-MM-State
+                EncodeOptionalByte( KMmsAssignedMMState,
+                    iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
+                // X-MMs-MM-Flags
+                // The keyword token should always be "add" or "remove"
+                EncodeKeywordArrayL();
+                }
+            }
+        }
+
+    // Add encapsulation version 1.3 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
+        {
+        // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
+        EncodeApplicationHeadersL();
+        // X-Mms-Content-Class
+        EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() );
+        // X-Mms-DRM-Content
+        EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() );
+        // X-Mms-Adaptation-Allowed
+        EncodeOptionalByte( KMmsAssignedAdaptationAllowed, iMmsHeaders->AdaptationAllowed() );
+        }
+
+    // Get Root TMsvId from headers if set
+    TMsvAttachmentId rootId = iMmsHeaders->MessageRoot();
+
+    TInt error = KErrNone;
+    // If we are handling headers only, we may not have iEntryWrapper
+    if ( iEntryWrapper )
+        {
+        CMsvStore* store = iEntryWrapper->ReadStoreL();
+        CleanupStack::PushL( store );
+        MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+        TRAP( error,
+            {
+            CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL(
+                (TMsvAttachmentId) rootId );
+            delete attachmentInfo; // we just wanted to check that it was found
+            }
+            );
+        CleanupStack::PopAndDestroy( store );
+        }
+        
+    // If we have a valid root part, we send the message as multipart/related.
+    // Otherwise we send it as multipart mixed.
+    // We don't try to guess what the root is supposed to be, if it
+    // is not specified or does not point to an existing attachment.
+
+    if ( error == KErrNone && rootId != 0 && iEntryWrapper )
+        {
+        EncodeMultipartRelatedHeaderL( rootId );
+        }
+    else
+        {
+        EncodeMultipartMixedHeaderL();
+        }
+        
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeNotifyResponse()
+    {
+
+    // version may be current version or 1.0
+    // Only byte is used. iMmsHeaders controls the value.
+
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMNotifyRespInd, iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // insert message status
+    EncodeMandatoryByte( KMmsAssignedStatus, iMmsHeaders->Status() );
+
+    // insert report allowed if present
+    EncodeOptionalByte( KMmsAssignedReportAllowed,
+        iMmsHeaders->ReportAllowed() );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeAcknowledgeIndication()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeAcknowledgeInd,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    // insert report allowed if present
+    EncodeOptionalByte( KMmsAssignedReportAllowed,
+        iMmsHeaders->ReportAllowed() );
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMmsNotificationL()
+    {
+
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMNotificationInd,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    // for notification sender is optional - added only if it is known
+    if ( iMmsHeaders->Sender().Length() > 0 )
+        {
+        EncodeSenderL( iMmsHeaders->Sender() );
+        }
+
+    EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
+
+    EncodeOptionalByte( KMmsAssignedDeliveryReport,
+        iMmsHeaders->DeliveryReport() );
+
+    EncodeOptionalByte( KMmsAssignedMessageClass,
+        iMmsHeaders->MessageClass() );
+
+    iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageSize, 1 );
+    iPosition++;
+
+    TInt64 size = iMmsHeaders->MessageSize();
+    EncodeLongInteger( size );
+
+    EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
+        iMmsHeaders->ExpiryInterval(),
+        iMmsHeaders->ExpiryDate() );
+
+    // version 1.1 fields - optional
+    // reply-charging
+    // reply-charging deadline
+    // reply-charging size
+    // reply-charging ID
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion1 )
+        {
+        // Do we want to specify
+        if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted ||
+            iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly )
+            {
+            // Reply charging value
+            EncodeOptionalByte( KMmsAssignedReplyCharging,
+                iMmsHeaders->ReplyCharging() );
+            // Reply charging deadline
+            EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
+                iMmsHeaders->ReplyChargingInterval(),
+                iMmsHeaders->ReplyChargingDate() );
+            // Reply charging size
+            EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
+            }
+        // if this is a reply, we may specify the ID
+        // Reply charging ID
+        EncodeOptionalString( KMmsAssignedReplyChargingID,
+            iMmsHeaders->ReplyChargingId() );
+        }
+
+    // version 1.2 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
+        {
+        // MMBox headers
+        if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+            {
+            EncodeOptionalByte( KMmsAssignedStored,
+                iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStored() );
+            }
+
+        // Distribution indicator
+        EncodeOptionalByte( KMmsAssignedDistributionIndicator,
+            iMmsHeaders->DistributionIndicator() );
+        }
+
+    // Element descriptor
+    // This is somewhat a mystery - not implemented
+    
+    // version 1.3 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
+        {
+        // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
+        EncodeApplicationHeadersL();
+        // X-Mms-Recommended-Retrieval-Mode
+        EncodeOptionalByte( KMmsAssignedRecommendedRetrievalMode,
+            iMmsHeaders->RecommendedRetrievalMode() );
+        // X-Mms-Recommended-Retrieval-Mode-Text
+        EncodeOptionalStringL( KMmsAssignedRecommendedRetrievalModeText,
+            iMmsHeaders->RecommendedRetrievalModeText() );
+        // X-Mms-Content-Class
+        EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() );
+        // X-Mms-DRM-Content
+        EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() );
+        // X-Mms-Replace-ID
+        EncodeOptionalString( KMmsAssignedReplaceId, iMmsHeaders->ReplaceCancelId() );
+        }
+
+    // We keep this as the last one, though it does not really matter
+    // Mandatory content-location
+    // this must be USASCII or URL encoded
+    EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+        iMmsHeaders->ContentLocation() );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeSendConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMSendConf,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    EncodeMandatoryByte( KMmsAssignedResponseStatus,
+        iMmsHeaders->ResponseStatus() );
+
+    EncodeOptionalStringL( KMmsAssignedResponseText,
+        iMmsHeaders->ResponseText() );
+
+    // if send confirmation returns error, it might not contain message id
+    EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
+
+    // MMBox related headers - optional
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        EncodeOptionalByte( KMmsAssignedStoreStatus,
+            iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
+        EncodeOptionalStringL( KMmsAssignedStoreStatusText,
+            iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
+        if ( iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ==
+            KMmsStatusOk )
+            {
+            // this must be USASCII or URL encoded
+            // If message was stored to MMBox, this is mandatory
+            EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+                iMmsHeaders->ContentLocation() );
+            }
+        }
+    
+#endif
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeRetrieveConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMRetrieveConf,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    // message id
+    EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
+
+    // if we have set a date, insert it
+    EncodeDate( iMmsHeaders->Date() );
+
+    // If we have set the sender, encode it
+    if ( iMmsHeaders->Sender().Length() > 0 )
+        {
+        EncodeSenderL( iMmsHeaders->Sender() );
+        }
+
+    // previously sent by array
+    TInt i;
+    TUint oldPosition;
+    TUint length;
+    for ( i = 0; i < iMmsHeaders->PreviouslySentList().Count(); i++ )
+        {
+        oldPosition = iPosition;
+        length = 0;
+        // Encode once just to find out filed length
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
+        length += iPosition - oldPosition;
+        iPosition = oldPosition;
+        iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentBy, 1 );
+        iPosition++;
+        EncodeValueLength( length );
+        // now we have added length, do the actual encoding
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
+        oldPosition = iPosition;
+        length = 0;
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
+        length += iPosition - oldPosition;
+        iPosition = oldPosition;
+        iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentDate, 1 );
+        iPosition++;
+        EncodeValueLength( length );
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
+        }
+
+    // All recipient lists. If no recipients in some of the lists,
+    // nothing is encoded, no need to check separately
+    EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
+    EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
+    // no Bcc in retrieve confirmation
+
+    // Subject
+    EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
+
+    // MMBox headers
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        // X-Mms-MM-State
+        EncodeOptionalByte( KMmsAssignedMMState,
+            iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
+        // X-MMs-MM-Flags
+        // The keyword token should always be "add" or "remove"
+        EncodeKeywordArrayL();
+        }
+
+    // Message class
+    EncodeOptionalByte( KMmsAssignedMessageClass,
+        iMmsHeaders->MessageClass() );
+
+    // Priority
+    EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() );
+    
+    // Delivery report
+    EncodeOptionalByte( KMmsAssignedDeliveryReport,
+        iMmsHeaders->DeliveryReport() );
+
+    // Read reply
+    EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
+
+    // MMS encapsulation 1.1 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion1 )
+        {
+        // Do we want to specify reply charging
+        if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted ||
+            iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly )
+            {
+            // Reply charging value
+            EncodeOptionalByte( KMmsAssignedReplyCharging,
+                iMmsHeaders->ReplyCharging() );
+            // Reply charging deadline
+            EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
+                iMmsHeaders->ReplyChargingInterval(),
+                iMmsHeaders->ReplyChargingDate() );
+            // Reply charging size
+            EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
+            }
+        // Reply charging ID
+        EncodeOptionalString( KMmsAssignedReplyChargingID,
+            iMmsHeaders->ReplyChargingId() );
+        // status of the operation
+        EncodeOptionalByte( KMmsAssignedRetrieveStatus,
+            iMmsHeaders->ResponseStatus() );
+
+        EncodeOptionalStringL( KMmsAssignedRetrieveText,
+            iMmsHeaders->ResponseText() );
+        }
+
+    // version 1.2 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
+        {
+        // Distribution indicator
+        EncodeOptionalByte( KMmsAssignedDistributionIndicator,
+            iMmsHeaders->DistributionIndicator() );
+        }
+
+    // version 1.3 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
+        {
+        // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
+        EncodeApplicationHeadersL();
+        // X-Mms-Content-Class
+        EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() );
+        // X-Mms-DRM-Content
+        EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() );
+        // X-Mms-Replace-ID
+        EncodeOptionalString( KMmsAssignedReplaceId, iMmsHeaders->ReplaceCancelId() );
+        }
+
+    // Start pointer
+    TUint ii = 0;
+    // Get Root TMsvId from headers if set
+    TMsvId rootId = iMmsHeaders->MessageRoot();
+
+    TInt error = KErrNone;
+    if ( iEntryWrapper )
+        {
+        CMsvStore* store = iEntryWrapper->ReadStoreL();
+        CleanupStack::PushL( store );
+        MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+        TRAP( error,
+            {
+            CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL(
+                (TMsvAttachmentId) rootId );
+            delete attachmentInfo; // we just wanted to check that it was found
+            }
+            );
+        CleanupStack::PopAndDestroy( store );
+        }
+        
+    // If we have a valid root part, we send the message as multipart/related.
+    // Otherwise we send it as multipart mixed.
+    // We don't try to guess what the root is supposed to be, if it
+    // is not specified or does not point to an existing attachment.
+
+    if ( error == KErrNone && rootId != 0 && iEntryWrapper )
+        {
+        EncodeMultipartRelatedHeaderL( rootId );
+        }
+    else
+        {
+        EncodeMultipartMixedHeaderL();
+        }
+
+    
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeDeliveryReportL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeDeliveryInd, TPtrC8(),
+        iMmsHeaders->MmsVersion() );
+
+    EncodeHeaderAndTextString( KMmsAssignedMessageId,
+        iMmsHeaders->MessageId() );
+
+    EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
+
+    // if we have set a date, insert it
+    EncodeDate( iMmsHeaders->Date() );
+
+    // insert message status
+    EncodeMandatoryByte( KMmsAssignedStatus, iMmsHeaders->Status() );
+    
+    // version 1.3 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
+        {
+        // X-Mms-Status-Text
+        // Status text is stored in the same place as response text and retrieve
+        // text as only one of them can appear in any PDU
+        EncodeOptionalStringL( KMmsAssignedStatusText,
+            iMmsHeaders->ResponseText() );
+        // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
+        EncodeApplicationHeadersL();
+        }
+    
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeForwardRequestL()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeForwardReq,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    // if we have set a date, insert it
+    EncodeDate( iMmsHeaders->Date() );
+
+    // If we have set the sender, encode it
+    // If not, we ask MMSC to add the sender
+    EncodeSenderL( iMmsHeaders->Sender() );
+
+    // All recipient lists. If no recipients in some of the lists,
+    // nothing is encoded, no need to check separately
+    EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
+    EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
+    EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc );
+
+    // Expiration time
+    EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
+        iMmsHeaders->ExpiryInterval(),
+        iMmsHeaders->ExpiryDate() );
+
+    // Delivery time
+    EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime,
+        iMmsHeaders->DeliveryTimeInterval(),
+        iMmsHeaders->DeliveryDate() );
+
+    // Delivery report allowed
+    EncodeOptionalByte( KMmsAssignedReportAllowed,
+        iMmsHeaders->ReportAllowed() );
+
+    // Delivery report
+    EncodeOptionalByte( KMmsAssignedDeliveryReport,
+        iMmsHeaders->DeliveryReport() );
+
+    // Read reply
+    EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
+
+    // version 1.2 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
+        {
+        // MMBox related headers - optional
+        if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+            {
+            // X-Mms-MM-Store
+            EncodeOptionalByte( KMmsAssignedMmsStore,
+                iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() );
+            if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() == KMmsYes ||
+                 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStored() == KMmsYes )
+                {
+                // X-Mms-MM-State
+                EncodeOptionalByte( KMmsAssignedMMState,
+                    iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
+                // X-MMs-MM-Flags
+                // The keyword token should always be "add" or "remove"
+                EncodeKeywordArrayL();
+                }
+            }
+        }
+        
+    // version 1.3 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
+        {
+        // Do we want to specify reply charging
+        if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested ||
+            iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly )
+            {
+            // Reply charging value
+            EncodeOptionalByte( KMmsAssignedReplyCharging,
+                iMmsHeaders->ReplyCharging() );
+            // Reply charging deadline
+            EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
+                iMmsHeaders->ReplyChargingInterval(),
+                iMmsHeaders->ReplyChargingDate() );
+            // Reply charging size
+            EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
+            }
+        }
+
+    // Mandatory content-location
+    // this must be USASCII or URL encoded
+    EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+        iMmsHeaders->ContentLocation() );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeForwardConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeForwardConf,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    EncodeMandatoryByte( KMmsAssignedResponseStatus,
+        iMmsHeaders->ResponseStatus() );
+
+    EncodeOptionalStringL( KMmsAssignedResponseText,
+        iMmsHeaders->ResponseText() );
+
+    EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
+
+    // MMBox related headers - optional
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        EncodeOptionalByte( KMmsAssignedStoreStatus,
+            iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
+        EncodeOptionalStringL( KMmsAssignedStoreStatusText,
+            iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
+        if ( iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ==
+            KMmsStatusOk )
+            {
+            // this must be USASCII or URL encoded
+            // If message was stored to MMBox, this is mandatory
+            EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+                iMmsHeaders->ContentLocation() );
+            }
+        }
+    
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeReadReplyL()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( iMmsHeaders->MessageType(), TPtrC8(), iMmsHeaders->MmsVersion() );
+
+    // message id
+    EncodeHeaderAndTextString( KMmsAssignedMessageId,
+        iMmsHeaders->MessageId() );
+
+    // originator of the original message
+    EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
+
+    // If we have set the sender, encode it
+    // If not, we ask MMSC to add the sender
+    EncodeSenderL( iMmsHeaders->Sender() );
+
+    // if we have set a date, insert it
+    EncodeDate( iMmsHeaders->Date() );
+
+    EncodeMandatoryByte( KMmsAssignedReadStatus, iMmsHeaders->ReadStatus() );
+    
+    // version 1.3 headers - optional
+    if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
+        {
+        // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
+        EncodeApplicationHeadersL();
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxStoreRequestL()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMboxStoreReq, iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // this must be USASCII or URL encoded
+    EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+        iMmsHeaders->ContentLocation() );
+
+    // MMBox headers
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        // X-Mms-MM-State
+        EncodeOptionalByte( KMmsAssignedMMState,
+            iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
+        // X-MMs-MM-Flags
+        // The keyword token should always be "add" or "remove"
+        EncodeKeywordArrayL();
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxStoreConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMboxStoreConf, iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // this must be USASCII or URL encoded
+    EncodeOptionalString( KMmsAssignedContentLocation,
+        iMmsHeaders->ContentLocation() );
+
+    EncodeMandatoryByte( KMmsAssignedStoreStatus,
+        iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
+
+    EncodeOptionalStringL( KMmsAssignedStoreStatusText,
+        iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
+
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxViewRequestL()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMboxViewReq, iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // Insert content location header. There may be more than one
+    EncodeContentLocationArray();
+
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        // X-MMs-MM-Flags. The token should always be "filter"
+        EncodeKeywordArrayL();
+        }
+
+    if ( iMmsHeaders->ReadOnlyMMBoxViewHeaders() )
+        {
+        CMmsMMBoxViewHeaders& viewHeaders = iMmsHeaders->MMBoxViewHeadersL();
+        
+        // states used as filter
+        // X-Mms-MM-State may appear multiple times in view request
+        EncodeMMBoxStates( viewHeaders.MMStateArray() ); 
+
+        // start
+        EncodeOptionalInteger( KMmsAssignedStart, viewHeaders.MmsStart() );
+        // limit
+        if ( viewHeaders.MmsLimit() != KMaxTUint32 )
+            {
+            // 0 means no message information, absence means all remaining
+            // messages.
+            // If header has value KMaxTUint32, it means that info about all
+            // remaining messages is wanted.
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedLimit, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MmsLimit() );
+            }
+
+        EncodeAttributes( viewHeaders.AttributeArray() );
+        // request totals
+        EncodeOptionalByte( KMmsAssignedTotals, viewHeaders.MmsTotals() );
+        // request quotas
+        EncodeOptionalByte( KMmsAssignedQuotas, viewHeaders.MmsQuotas() );
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxViewConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMboxViewConf,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+
+    EncodeMandatoryByte( KMmsAssignedResponseStatus,
+        iMmsHeaders->ResponseStatus() );
+
+    EncodeOptionalStringL( KMmsAssignedResponseText,
+        iMmsHeaders->ResponseText() );
+
+    EncodeContentLocationArray();
+
+    // MMBox headers
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        // X-MMs-MM-Flags. The token should always be "filter"
+        EncodeKeywordArrayL();
+        }
+    
+    if ( iMmsHeaders->ReadOnlyMMBoxViewHeaders() )
+        {
+        CMmsMMBoxViewHeaders& viewHeaders = iMmsHeaders->MMBoxViewHeadersL();
+
+        // states used as filter
+        // X-Mms-MM-State may appear multiple times in view request
+        EncodeMMBoxStates( viewHeaders.MMStateArray() ); 
+
+        // start
+        EncodeOptionalInteger( KMmsAssignedStart, viewHeaders.MmsStart() );
+        // limit
+        if ( viewHeaders.MmsLimit() != KMaxTUint32 )
+            {
+            // 0 means no message information, absence means all remaining
+            // messages.
+            // If header has value KMaxTUint32, it means that info about
+            // all remaining messages is wanted.
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedLimit, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MmsLimit() );
+            }
+        EncodeAttributes( viewHeaders.AttributeArray() );
+
+        // totals
+        TUint oldPosition = iPosition;
+        TUint length = 0;
+
+        if ( viewHeaders.MMBoxTotalNumber() != KMaxTUint32 )
+            {
+            oldPosition = iPosition;
+            EncodeInteger( viewHeaders.MMBoxTotalNumber() );
+            length = iPosition - oldPosition;
+            length += 1; // quota token
+            iPosition = oldPosition;
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxTotals, 1 );
+            iPosition++;
+            EncodeValueLength( length );
+            iEncodeBuffer->Write( iPosition, &KMmsMessageCountToken, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MMBoxTotalNumber() );
+            }
+
+        if ( viewHeaders.MMBoxTotalSize() != KMaxTUint32 )
+            {
+            oldPosition = iPosition;
+            EncodeInteger( viewHeaders.MMBoxTotalSize() );
+            length = iPosition - oldPosition;
+            length += 1; // quota token
+            iPosition = oldPosition;
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxTotals, 1 );
+            iPosition++;
+            EncodeValueLength( length );
+            iEncodeBuffer->Write( iPosition, &KMmsMessageSizeToken, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MMBoxTotalSize() );
+            }
+
+        // quotas
+        if ( viewHeaders.MMBoxQuotaNumber() != KMaxTUint32 )
+            {
+            oldPosition = iPosition;
+            EncodeInteger( viewHeaders.MMBoxQuotaNumber() );
+            length = iPosition - oldPosition;
+            length += 1; // quota token
+            iPosition = oldPosition;
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxQuotas, 1 );
+            iPosition++;
+            EncodeValueLength( length );
+            iEncodeBuffer->Write( iPosition, &KMmsMessageCountToken, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MMBoxQuotaNumber() );
+            }
+
+        if ( viewHeaders.MMBoxQuotaSize() != KMaxTUint32 )
+            {
+            oldPosition = iPosition;
+            EncodeInteger( viewHeaders.MMBoxQuotaSize() );
+            length = iPosition - oldPosition;
+            length += 1; // quota token
+            iPosition = oldPosition;
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxQuotas, 1 );
+            iPosition++;
+            EncodeValueLength( length );
+            iEncodeBuffer->Write( iPosition, &KMmsMessageSizeToken, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MMBoxQuotaSize() );
+            }
+
+        // Message count
+        // This should in principle come from the viewHeaders.MmsMessageCount()
+        // But in this context the number of messages will be the number of
+        // attachments available in this entry
+
+        // However, we will use the viewHeaders.MmsMessageCount() to generate
+        // the header so that we can test that the decoding part can handle
+        // possible conflict between message number and the number of parts
+        // in the multipart structure. This header is optional. KMaxTUint32
+        // will mean unspecified.
+
+        if ( viewHeaders.MmsMessageCount() != KMaxTUint32 )
+            {
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageCount, 1 );
+            iPosition++;
+            EncodeInteger( viewHeaders.MmsMessageCount() );
+            }
+        }
+
+    if ( iNumberOfAttachments == 0 )
+        {
+        EncodeMandatoryByte( KMmsAssignedContentType, KMmsAssignedAny );
+        }
+    else
+        {
+        EncodeMultipartMixedHeaderL();
+        }
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxUploadRequestL()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMBoxUploadReq, iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // MMBox headers
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        // X-Mms-MM-State
+        EncodeOptionalByte( KMmsAssignedMMState,
+            iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
+        // X-MMs-MM-Flags
+        // The keyword token should always be "add" or "remove"
+        EncodeKeywordArrayL();
+        }
+
+    // Get Root TMsvId from headers if set
+    TMsvAttachmentId rootId = iMmsHeaders->MessageRoot();
+
+    // Find the matching id from attachment list
+    
+    TInt error = KErrNone;
+    if ( iEntryWrapper )
+        {
+        CMsvStore* store = iEntryWrapper->ReadStoreL();
+        CleanupStack::PushL( store );
+        // Only new attachment structure is supported    
+        MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+        TRAP( error,
+            {
+            CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL(
+                (TMsvAttachmentId) rootId );
+            delete attachmentInfo; // we just wanted to check that it was found
+            }
+            );
+        CleanupStack::PopAndDestroy( store );
+        }
+    
+    // If we have a valid root part, we send the message as multipart/related.
+    // Otherwise we send it as multipart mixed.
+    // We don't try to guess what the root is supposed to be, if it
+    // is not specified or does not point to an existing attachment.
+
+    // actually the content should be an MMS PDU as in M-MBox-Descr PDU
+    // It is unclear if if should be wrapped in a multipart structure 
+    // (containing only one header)
+    // or if the content type should be application/vnd.wap.mms-message
+    if ( error == KErrNone && rootId != 0 && iEntryWrapper )
+        {
+        EncodeMultipartRelatedHeaderL( rootId );
+        }
+    else
+        {
+        EncodeMultipartMixedHeaderL();
+        }
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxUploadConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeMBoxUploadConf, iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // this must be USASCII or URL encoded
+    EncodeOptionalString( KMmsAssignedContentLocation,
+        iMmsHeaders->ContentLocation() );
+
+    EncodeMandatoryByte( KMmsAssignedStoreStatus,
+        iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
+
+    EncodeOptionalStringL( KMmsAssignedStoreStatusText,
+        iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeDeleteRequestL()
+    {
+    // Insert message type, TID and version number
+    
+    EncodeStartingHeaders( iMmsHeaders->MessageType(), iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // Insert content location header. There may be more than one
+    EncodeContentLocationArray();
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeDeleteConfirmationL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( iMmsHeaders->MessageType(), iMmsHeaders->Tid(),
+        iMmsHeaders->MmsVersion() );
+
+    // content location, response status and response text headers have
+    // different format from other PDUs
+
+    const RPointerArray<CMmsDeleteResultArray>& resultArray = 
+        iMmsHeaders->DeleteResultArray();
+
+    TInt i;
+    TInt length = 0;
+    TInt oldPosition = 0;
+    TUint oldIndex = KMaxTUint32;
+
+    for ( i = 0; i < resultArray.Count(); i++ )
+        {
+        TUint index = resultArray[i]->Order();
+        if ( index != oldIndex )
+            {
+            // We add status and status text only once, there may be more
+            // than one content location with the same status
+            oldIndex = index;
+            if ( resultArray[i]->ResponseStatus() != 0 )
+                {
+                oldPosition = iPosition;
+                length = 0;
+                // Encode once just to find out field length
+                EncodeInteger( index );
+                length += iPosition - oldPosition;
+                length ++; // response status is only one byte
+                iPosition = oldPosition;
+                // now we have calculated length, do the actual encoding
+                iEncodeBuffer->Write( iPosition, &KMmsAssignedResponseStatus, 1 );
+                iPosition++;
+                EncodeValueLength( length );
+                EncodeInteger( index );
+                TUint8 value = (TUint8) resultArray[i]->ResponseStatus();
+                iEncodeBuffer->Write( iPosition, &value, 1 );
+                iPosition++;
+                }
+            if ( resultArray[i]->ResponseText().Length() > 0 )
+                {
+                oldPosition = iPosition;
+                length = 0;
+                // Encode once just to find out field length
+                EncodeInteger( index );
+                EncodeTextStringL( resultArray[i]->ResponseText() );
+                length += iPosition - oldPosition;
+                iPosition = oldPosition;
+                // now we have calculated length, do the actual encoding
+                iEncodeBuffer->Write( iPosition, &KMmsAssignedResponseText, 1 );
+                iPosition++;
+                EncodeValueLength( length );
+                EncodeInteger( index );
+                EncodeTextStringL( resultArray[i]->ResponseText() );
+                }
+            }
+        if ( resultArray[i]->ContentLocation().Length() > 0 )
+            {
+            oldPosition = iPosition;
+            length = 0;
+            // Encode once just to find out field length
+            EncodeInteger( index );
+            EncodeTextString( resultArray[i]->ContentLocation() );
+            length += iPosition - oldPosition;
+            iPosition = oldPosition;
+            // now we have calculated length, do the actual encoding
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedContentLocation, 1 );
+            iPosition++;
+            EncodeValueLength( length );
+            EncodeInteger( index );
+            EncodeTextString( resultArray[i]->ContentLocation() );
+            }
+        }
+#endif
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxDescriptionL()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    EncodeMandatoryByte( KMmsAssignedMessageType, KMmsMessageTypeMBoxDescr );
+
+    // this must be USASCII or URL encoded
+    EncodeOptionalString( KMmsAssignedContentLocation,
+        iMmsHeaders->ContentLocation() );
+
+    EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
+
+    // MMBox headers
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        // X-Mms-MM-State
+        EncodeOptionalByte( KMmsAssignedMMState,
+            iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
+        // X-MMs-MM-Flags
+        // The keyword token should always be "add" or "remove"
+        EncodeKeywordArrayL();
+        }
+
+    // if we have set a date, insert it
+    EncodeDate( iMmsHeaders->Date() );
+    
+    // sender is optional
+    if ( iMmsHeaders->Sender().Length() > 0 )
+        {
+        EncodeSenderL( iMmsHeaders->Sender() );
+        }
+
+    // All recipient lists. If no recipients in some of the lists,
+    // nothing is encoded, no need to check separately
+    EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
+    EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
+    EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc );
+
+    // Message class
+    EncodeOptionalByte( KMmsAssignedMessageClass,
+        iMmsHeaders->MessageClass() );
+
+    // Subject
+    EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
+
+    // Priority
+    EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() );
+    
+    // Delivery time
+    EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime,
+        iMmsHeaders->DeliveryTimeInterval(),
+        iMmsHeaders->DeliveryDate() );
+
+    // Expiration time
+    EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
+        iMmsHeaders->ExpiryInterval(),
+        iMmsHeaders->ExpiryDate() );
+
+    // Delivery report
+    EncodeOptionalByte( KMmsAssignedDeliveryReport,
+        iMmsHeaders->DeliveryReport() );
+
+    // Read reply
+    EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
+
+    if ( iMmsHeaders->MessageSize() > 0 )
+        {
+        iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageSize, 1 );
+        iPosition++;
+        TInt64 size = iMmsHeaders->MessageSize();
+        EncodeLongInteger( size );
+        }
+
+    // MMBox description appears from 1.2 onwards - no use to check if we are
+    // 1.1 or later.
+    // Do we want to specify reply charging
+    if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested ||
+        iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly ||
+        iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted ||
+        iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly )
+        {
+        // Reply charging value
+        EncodeOptionalByte( KMmsAssignedReplyCharging,
+            iMmsHeaders->ReplyCharging() );
+        // Reply charging deadline
+        EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
+            iMmsHeaders->ReplyChargingInterval(),
+            iMmsHeaders->ReplyChargingDate() );
+        // Reply charging size
+        EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
+        }
+    // Reply charging ID
+    EncodeOptionalString( KMmsAssignedReplyChargingID,
+        iMmsHeaders->ReplyChargingId() );
+
+    TInt i;
+    TUint oldPosition;
+    TUint length;
+    for ( i = 0; i < iMmsHeaders->PreviouslySentList().Count(); i++ )
+        {
+        oldPosition = iPosition;
+        length = 0;
+        // Encode once just to find out field length
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
+        length += iPosition - oldPosition;
+        iPosition = oldPosition;
+        iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentBy, 1 );
+        iPosition++;
+        EncodeValueLength( length );
+        // now we have added length, do the actual encoding
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
+        oldPosition = iPosition;
+        length = 0;
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
+        length += iPosition - oldPosition;
+        iPosition = oldPosition;
+        iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentDate, 1 );
+        iPosition++;
+        EncodeValueLength( length );
+        EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
+        EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
+        }
+
+    if ( iNumberOfAttachments > 0 )
+        {
+        EncodeMultipartMixedHeaderL();
+        }
+
+#endif
+    }
+
+// ---------------------------------------------------------
+// 8-bit version (no conversions)
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeTextString( const TDesC8& aString )
+    {
+    // Only Content-Id needs a quoted string, for example
+    // "<agjrfnjr>
+    // content-id encoding uses a separate function that adds the quote.
+    // EncodeQuotedTextString
+
+    // Check if we need a Quote (This does not mean the quoted string.)
+    TInt length = aString.Length();
+    if ( length > 0 && aString[0] >= KMms0x80 )
+        {
+        iEncodeBuffer->Write( iPosition, &KMmsQuote, 1 );
+        iPosition++;
+        }
+
+    iEncodeBuffer->Write( iPosition, aString, length );
+    iPosition += length;
+
+    iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+    iPosition++;
+
+    }
+
+// ---------------------------------------------------------
+// 8-bit version (no conversions)
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeQuotedTextString( const TDesC8& aString )
+    {
+    // Before this function is called, the caller must check
+    // that the length of the string is not 0. Otherwise this
+    // makes no sense. You cannot quote a zero-length string
+
+    // We need quoted string for content-id.
+    // So far for nothing else.
+    // (for the filename in MIME headers, too, just in case)
+
+    // We add one quote to the beginning, nothing to the end.
+    // As we start with a quote, we don't need to check for the special
+    // Quote that is needed if a string starts with a character above 128
+    TInt length = aString.Length();
+    iEncodeBuffer->Write( iPosition, &KMmsStringQuote, 1 );
+    iPosition++;
+
+    iEncodeBuffer->Write( iPosition, aString, length );
+    iPosition += length;
+
+    iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+    iPosition++;
+
+    }
+
+// ---------------------------------------------------------
+// unicode version
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeTextStringL( const TDesC& aString )
+    {
+
+    // What about a RFC2068 quoted strings - 
+    // see explanation in EncodeTextString( const TDesC8& aString ) function
+
+    TInt i = 0;
+    TInt length = aString.Length();
+
+    TBool safe = IsStringSafe( aString );
+
+    // If the string can be encoded as ASCII, go ahead
+    if ( safe )
+        {
+        TUint8 character;
+        // No need to check if we need a quote - if we are safe, we have 
+        // no characters >= 128.
+
+        for ( i = 0; i < aString.Length(); i++ )
+            {
+            character = TUint8( aString[i] & KMms0xFF );
+            iEncodeBuffer->Write( iPosition, &character, 1 );
+            iPosition++;
+            }
+        iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+        iPosition++;
+        }
+    else
+        {
+        // if our length is 0, we are safe, no need to check the 
+        // length here anymore
+        // we must convert to utf-8
+        
+        //one ucs-2 character should never produce more than 4 bytes when converted to utf-8
+        HBufC8* buffer = HBufC8::NewL( aString.Length() * KMms4 ); // paranoid.
+        // we don't leave while we need buffer
+        TPtr8 buf8 = buffer->Des();
+
+        // if conversion fails, something is really seriously wrong
+        iError = CnvUtfConverter::ConvertFromUnicodeToUtf8( buf8, aString );
+
+        length = buf8.Length();
+        // utf8 character set encoding needs one byte (fits into short integer)
+        length += KMms2; // add character set encoding byte and trailing NULL
+        
+        if ( buf8[0] >= KMms0x80 ) // 128
+            {
+            length++; // we will need a quote byte at the start...
+            }
+        
+        EncodeValueLength( length );
+
+        // add one byte of character set
+        // this is a short integer, high bit must be set
+        TUint8 charset = KMmsUtf8 | KMms0x80;
+
+        iEncodeBuffer->Write( iPosition, &charset, 1 );
+        iPosition++;
+
+        // Check if we need a quote
+        if ( buf8[0] >= KMms0x80 ) // 128
+            {
+            iEncodeBuffer->Write( iPosition, &KMmsQuote, 1 );
+            iPosition++;
+            }
+        
+        // Then write the string itself
+        iEncodeBuffer->Write( iPosition, buf8, buf8.Length() );
+        iPosition += buf8.Length();
+
+        // Add terminating NULL
+        iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+        iPosition++;
+
+        delete buffer;
+        buffer = NULL;
+        }
+    
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeDate( const TInt64& aDate)
+    {
+
+    if ( aDate == 0 )
+        {
+        return;
+        }
+
+    iEncodeBuffer->Write( iPosition, &KMmsAssignedDate, 1 );
+    iPosition++;
+
+    EncodeLongInteger( aDate );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeLongInteger( const TInt64& aLongInteger )
+    {
+
+    TUint8 length = 0; // number of bytes we will need
+    // The long integer will take 8 bytes or less
+    TUint8 array[KMms8];
+
+    TInt64 temp = aLongInteger;
+    TInt i = 0;
+    TInt64 reminder = 0;
+
+    for ( i = 7; i >= 0; i-- )
+        {
+        reminder = temp % 0x100;
+        temp = temp / 0x100;
+        array[i] = TInt8 ( I64INT( reminder ) ) ;
+        }
+
+    length = KMms8;
+    i = 0;
+    // The array has 8 elements, so this is safe.
+    while( ( i < KMms8 ) && ( array[i] == 0 ) )
+        {
+        i++;
+        length--;
+        }
+
+    // a zero should be coded as short integer.
+    // However, if there is a valid reason to code a zero as a long integer,
+    // we allow it. The caller should know what he is doing.
+    if ( length == 0 )
+        {
+        length = 1;
+        }
+
+    // write short length
+    iEncodeBuffer->Write( iPosition, &length, 1 );
+    iPosition++;
+
+    // write as many bytes as were non-zero
+    // array index will stay withing limits because of the way it was calculated
+    iEncodeBuffer->Write( iPosition, &(array[KMms8 - length] ), length );
+    iPosition+= length;
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeInteger( TUint aInteger )
+    {
+    // KMms1 = 1
+    // KMms2 = 2
+    // KMms3 = 3
+    // KMms4 = 4
+    // KMms5 = 5
+    // etc.
+    
+    TUint8 byte = 0;
+
+    if ( aInteger <= KMmsShortIntegerLimit127 )
+        {
+        byte = ( TInt8 ) aInteger;
+        byte |= KMms0x80;
+        iEncodeBuffer->Write( iPosition, &byte, 1);
+        iPosition++;
+        return; // this was easy
+        }
+
+    TUint8 length = KMms4; // number of bytes we will need
+    TUint8 array[KMms4];
+
+    TUint temp = aInteger;
+    byte = TInt8( ( temp >> KMms24 ) & KMms0xFF );
+
+    while ( byte == 0 && length > 0 )
+        {
+        length--;
+        temp = temp << KMms8;
+        byte = TInt8( ( temp >> KMms24 ) & KMms0xFF );
+        }
+
+    TUint i = 0;
+    for ( i = 0; i < length; i++ )
+        {
+        array[i] = TInt8( ( temp >> ( KMms8 * ( KMms3 - i ) ) ) & KMms0xFF );
+        }
+
+    // write short length
+    iEncodeBuffer->Write( iPosition, &length, 1 );
+    iPosition++;
+
+    // write as many bytes as were non-zero
+    // aInteger was tested in the beginning - it needs at least one byte
+    // So length is at least 1 and the array has been properly initialized.
+    iEncodeBuffer->Write( iPosition, &array[0], length );
+    iPosition+= length;
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeSenderL( const TPtrC& aSender )
+    {
+    
+    iEncodeBuffer->Write( iPosition, &KMmsAssignedFrom, 1 );
+    iPosition++;
+
+    // We must insert value length.
+
+    if ( aSender.Length() == 0 )
+        {
+        // The MMSC must insert our address
+        TUint8 length;
+        length = 1;
+        iEncodeBuffer->Write( iPosition, &length, 1 );
+        iPosition++;
+        iEncodeBuffer->Write( iPosition, &KMmsInsertAddressToken, 1 );
+        iPosition++;
+        return;
+        }
+    
+    // Now we must insert something
+    TUint length = 1; // address present token
+
+    if ( aSender.Find( KMiuMau ) != KErrNotFound )
+        {
+        TBool safe = IsStringSafe( aSender );
+        if ( safe )
+            {
+            // this was easy, just ASCII, no conversion
+            length += aSender.Length();
+            length ++; // room for terminating zero
+            }
+        else // not USASCII, charset must be specified
+            {
+            // worst case scenario.
+            // must be encoded as UTF-8, value length and character set
+            // must be added
+        
+            // one ucs-2 character will not produce more than 4 bytes when converted to utf-8
+            HBufC8* buffer = HBufC8::NewL( aSender.Length() * KMms4 ); // paranoid.
+            // we don't need to push buffer onto cleanup stack, as we don't
+            // leave while we are using it
+            TPtr8 buf8 = buffer->Des();
+
+            // if we get error here, something is badly wrong
+            iError = CnvUtfConverter::ConvertFromUnicodeToUtf8( buf8, aSender );
+
+            length += buf8.Length();
+            // utf8 character set encoding needs one byte (short integer)
+            length += KMms2; // add character set encoding byte and trailing NULL
+        
+            if ( buf8[0] >= KMms0x80 ) // 128
+                {
+                length++; // we will need a quote byte at the start...
+                }
+            delete buffer;
+            buffer = NULL;
+            }
+        }
+    else // no miumau found
+        {
+        // phone number, must be ASCII
+        length += aSender.Length();
+        length ++; // room for terminating zero
+        length += KMmsPlmnLength; // type indication
+        // this should be the length, if we have a phone number (no alias.)
+        }
+
+    EncodeValueLength( length );
+
+    iEncodeBuffer->Write( iPosition, &KMmsAddressPresentToken, 1 );
+    iPosition++;
+
+    // If the address contains some non-ascii characters,
+    // it must be converted to utf-8
+    
+    EncodeAddressL( aSender );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeAddressL( const TPtrC& aAddress )
+    {
+    // Supports only address types PLMN and email.
+    // If the address string contains a @ character,
+    // it is interpreted as an email
+
+    // Internal alias is removed
+
+    TMmsAddressType addressType = EMmsAddressTypeUnknown;
+    HBufC* realAddress = HBufC::NewL( aAddress.Length() );
+    CleanupStack::PushL( realAddress );
+
+    TInt error = KErrNone;
+
+    TPtr realAddressPointer = realAddress->Des();
+    error = TMmsGenUtils::AddressTypeAndRealAddress(
+        aAddress,
+        addressType,
+        realAddressPointer,
+        aAddress.Length());
+
+    if ( error != KErrNone || addressType == EMmsAddressTypeUnknown )
+        {
+        // could not resolve. Send unchanged
+        realAddress->Des().Copy( aAddress );
+        if ( aAddress.Find( KMiuMau ) != KErrNotFound )
+            {
+            addressType = EMmsAddressTypeEmail;
+            }
+        else
+            {
+            addressType = EMmsAddressTypeMobile;
+            }
+        }
+        
+    if ( addressType == EMmsAddressTypeEmail )
+        {
+        // email address
+        // If the address contains only ASCII characters,
+        // it can be sent as text string, if not, it must be sent as utf-8
+
+        EncodeTextStringL( *realAddress );
+
+        }
+    else
+        {
+        // must be a phone number
+        // We expect for now that the format is correct as is
+        // All legal characters present in a phone number are ASCII
+
+        TInt i = 0;
+        TUint8 character = 0;
+        realAddressPointer = realAddress->Des();
+        for ( i = 0; i < realAddress->Length(); i++ )
+            {
+            // The array index is safe because i is always < realAddress->Length().
+            character = TUint8( realAddressPointer[i] & KMms0xFF );
+            iEncodeBuffer->Write( iPosition, &character, 1 );
+            iPosition++;
+            }
+        iEncodeBuffer->Write( iPosition, KMmsPlmn, KMmsPlmnLength );
+        iPosition += KMmsPlmnLength;
+        iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
+        iPosition++;
+        }
+    CleanupStack::PopAndDestroy( realAddress );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeValueLength( TUint aLength )
+    {
+
+    TUint8 shortLength = 0;
+
+    if ( aLength <= KMms30 )
+        {
+        // short length
+        shortLength = TUint8( aLength ) ;
+        iEncodeBuffer->Write( iPosition, &shortLength, 1 );
+        iPosition++;
+        }
+    else
+        {
+        iEncodeBuffer->Write( iPosition, &KMmsLengthQuote, 1 );
+        iPosition++;
+        EncodeUintvar( aLength );
+        }
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeUintvar( TUint aInteger )
+    {
+
+    // The value is split into 7 bit chunks, and continue bit set
+    // when needed.
+
+    // No more than 5 bytes will be produced
+    TUint8 buffer[KMms5];
+    TUint temp = aInteger;
+    TInt i;
+
+    for ( i = 0; i < KMms5; i++ )            
+        {
+        buffer[KMms4 - i] = TUint8( temp & KMms0x7F );
+        temp >>= KMms7;
+        }
+
+    i = 0;
+    // buffer indexes are safe because the buffer has been defined long enough.
+    while ( i < KMms4 && buffer[i] == 0 )
+        {
+        i++;
+        }
+    
+    TInt j;
+
+    for ( j = i; j < KMms4; j++ )
+        {
+        // buffer indexes are safe because the buffer has been defined long enough.
+        buffer[j] |= KMms0x80; // set Continue bit, but never to last
+        }
+
+    // buffer indexes are safe because the buffer has been defined long enough.
+    iEncodeBuffer->Write( iPosition, &buffer[i], KMms5 - i );
+    iPosition += KMms5 - i;
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TInt CMmsEncode::GetUintvarLength( TUint aInteger )
+    {
+
+    // The value is split into 7 bit chunks, and continue bit set
+    // when needed.
+
+    // No more than 5 bytes will be produced
+    TUint8 buffer[KMms5];
+    TUint temp = aInteger;
+    TInt i;
+
+    for (i = 0; i < KMms5; i++ )            
+        {
+        buffer[KMms4 - i] = TUint8( temp & KMms0x7F );
+        temp >>= KMms7;
+        }
+
+    i = 0;
+    // buffer indexes are safe because the buffer has been defined long enough.
+    while ( i < KMms4 && buffer[i] == 0 )
+        {
+        i++;
+        }
+    
+    return KMms5 - i;
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeRecipientL( const CDesCArray& aRecipientList,
+    TMmsRecipients aType )
+    {
+
+    TInt i;
+    TInt size = aRecipientList.Count();
+    if ( size == 0 )
+        {
+        return;
+        }
+
+    TUint8 recipientType = KMmsAssignedTo;
+
+    switch ( aType )
+        {
+        case EMmsTo:
+            recipientType = KMmsAssignedTo;
+            break;
+        case EMmsCc:
+            recipientType = KMmsAssignedCc;
+            break;
+        case EMmsBcc:
+            recipientType = KMmsAssignedBcc;
+            break;
+        default:
+            break;
+        }
+
+    for ( i = 0; i < size; i++ )
+        {
+        // check for fakes
+        if ( aRecipientList[i].Length() > 0 )
+            {
+            iEncodeBuffer->Write( iPosition, &recipientType, 1 );
+            iPosition++;
+
+            EncodeAddressL( aRecipientList[i] );
+            }
+
+        }
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeOptionalStringL( TUint8 aHeader,
+    const TPtrC16& aString )
+    {
+
+    if ( aString.Length() == 0 )
+        {
+        return;
+        }
+
+    iEncodeBuffer->Write( iPosition, &aHeader, 1 );
+    iPosition++;
+
+    EncodeTextStringL( aString );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeOptionalString( TUint8 aHeader, const TPtrC8& aString )
+    {
+
+    if ( aString.Length() == 0 )
+        {
+        return;
+        }
+
+    EncodeHeaderAndTextString( aHeader, aString );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeIntervalOrDate( TInt aInterval, const TInt64& aDate )
+    {
+
+    TInt64 temp = 0;
+    TUint8 token = 0;
+
+    if ( aDate != 0 )
+        {
+        temp = aDate;
+        token = KMmsAbsoluteToken;
+        }
+    else
+        {
+        temp = aInterval;
+        token = KMmsRelativeToken;
+        }
+
+    // calculate value length
+
+    TUint length = KMms8;
+    TUint mask = 0xff000000;
+
+    while ( ( I64HIGH( temp ) & mask ) == 0 && length > KMms4)
+        {
+        mask >>= KMms8;
+        length--;
+        }
+
+    mask = 0xff000000;
+
+    // Test if the whole high half was zero
+    if ( I64HIGH( temp ) == 0 )
+        {
+        while ( ( I64LOW( temp ) & mask ) == 0 && length > 1)
+            {
+            mask >>= KMms8;
+            length--;
+            }   
+        }
+
+    // now add short length and absolute/relative token
+
+    length += KMms2;
+
+    EncodeValueLength( length );
+
+    iEncodeBuffer->Write( iPosition, &token, 1 );
+    iPosition++;
+
+    EncodeLongInteger( temp );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeReplyChargingSize( TInt aReplyChargingSize )
+    {
+    if ( aReplyChargingSize == 0 )
+        {
+        return;
+        }
+    TInt64 size = aReplyChargingSize;
+    iEncodeBuffer->Write( iPosition, &KMmsAssignedReplyChargingSize, 1 );
+    iPosition++;
+
+    EncodeLongInteger( size );
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeOptionalByte( TUint8 aHeader, TInt aValue )
+    {
+    if ( aValue == 0 )
+        {
+        return; // not set, nothing to encode, header is optional
+        }
+    EncodeMandatoryByte( aHeader, aValue );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMandatoryByte( TUint8 aHeader, TInt aValue )
+    {
+    // When ecoding mandatory byte even value 0 is allowed.
+    // It will become 0x80, and be correctly decoded back to 0.
+    TUint8 value = TUint8 ( aValue ) | KMms0x80 ;
+
+    iEncodeBuffer->Write( iPosition, &aHeader, 1 );
+    iPosition++;
+
+    iEncodeBuffer->Write( iPosition, &value, 1 );
+    iPosition++;
+    }
+
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeOptionalIntervalOrDate( TUint8 aHeader,
+            TInt aInterval,
+            const TInt64& aDate )
+    {
+    if ( aInterval == 0 && aDate == 0 )
+        {
+        return; // not set, nothing to encode, header is optional
+        }
+
+    iEncodeBuffer->Write( iPosition, &aHeader, 1 );
+    iPosition++;
+
+    EncodeIntervalOrDate( aInterval, aDate );
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeHeaderAndTextString( TUint8 aHeader,
+    const TDesC8& aString )
+    {
+
+    iEncodeBuffer->Write( iPosition, &aHeader, 1 );
+    iPosition++;
+
+    EncodeTextString( aString );
+
+    }
+
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsEncode::IsStringSafe( const TDesC& aString )
+    {
+
+    // Very simple check to see if string is "safe" ASCII
+    // Used for headers, which are short strings
+
+    TInt i;
+    TBool safe = ETrue;
+
+    for ( i = 0; i < aString.Length() && safe; i++ )
+        {
+        if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii )
+            {
+            safe = EFalse;
+            }
+        }
+    return safe;
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsEncode::IsStringSafe( const TDesC8& aString, TInt& aNumNonSafe  )
+    {
+
+    // Very simple check to see if string is "safe" ASCII
+    // Used for headers, which are short strings
+    // spaces count as non-safe because their number must be taken into
+    // account when calculating the length
+
+    const TInt KIntQuestion = 0x3F;
+    const TInt KIntEquals = 0x3D;
+    
+    TInt i;
+    aNumNonSafe = 0;
+    TBool safe = ETrue;
+
+    for ( i = 0; i < aString.Length()/* && safe*/; i++ )
+        {
+        if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii )
+            {
+            safe = EFalse;
+            aNumNonSafe++;
+            }
+        if ( aString[i] == KIntQuestion || aString[i] == KIntEquals )
+            {
+            // These are safe but must be encoded if quoted printable
+            // encoding is used. The number is needed to check the header length
+            aNumNonSafe++;
+            }
+        if ( aString[i] == KMmsIntUnderscore )
+            {
+            // This must always be encoded as base64 because Symbian
+            // does not encode underscores when quoted printable is used.
+            aNumNonSafe = KMaxEncodingLength;
+            }
+        
+        }
+    return safe;
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMultipartRelatedHeaderL( const TMsvAttachmentId aRootId )
+    {
+
+    iEncodeBuffer->Write( iPosition, &KMmsAssignedContentType, 1 );
+    iPosition++;
+
+    // We have parameters (start), so we must use Content-general-form
+
+    // We need the content-id for the root part. If it is not defined already,
+    // we must generate one.
+
+    TUint headerLength = 1; // one byte for well known media
+    TInt cleanupCount = 0; // we must keep track what we have on store
+
+    User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
+        
+    CMsvStore* store = iEntryWrapper->EditStoreL();
+    CleanupStack::PushL( store ); cleanupCount++;
+    MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+    CMsvAttachment* attachmentInfo = NULL;
+    attachmentInfo = attachMan.GetAttachmentInfoL( (TMsvAttachmentId) aRootId );
+    CleanupStack::PushL( attachmentInfo ); cleanupCount++;
+    
+    iMimeHeaders->RestoreL( *attachmentInfo );
+
+    if ( iError != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( cleanupCount ); 
+        return;
+        }
+
+    TPtrC8 cid = iMimeHeaders->ContentId();
+    TBufC8<KMmsMaxCidLength> target;
+
+    // If cid has not been defined, we must generate one
+    if ( cid.Length() == 0 )
+        {
+        TTime now;
+        now.UniversalTime();
+        TInt random;
+        TInt64 seed = now.Int64();
+        random = Math::Rand( seed );
+        // type conversions irrelevant - just creating a magic number for content id
+        target.Des().Num( random );
+        target.Des().Insert(0, KMmsLeftAngle );
+        target.Des().Append( KMmsRightAngle );
+        cid.Set( target.Des() );
+        // exclude the angle brackets
+        iMimeHeaders->SetContentIdL( cid.Mid( 1, cid.Length() - KMms2 ) );
+        // save the cid to be present when we create the attachment headers
+        // If this does not succeed, the message will have no root.
+        MMsvAttachmentManagerSync& attachManSync = 
+            store->AttachmentManagerExtensionsL();
+        iMimeHeaders->StoreL( *attachmentInfo );
+        attachManSync.ModifyAttachmentInfoL( attachmentInfo );
+        // attachment manager now own attachemnt info
+        CleanupStack::Pop( attachmentInfo ); cleanupCount--;
+        store->CommitL();
+        attachmentInfo = attachMan.GetAttachmentInfoL( (TMsvAttachmentId) aRootId );
+        CleanupStack::PushL( attachmentInfo ); cleanupCount++;
+        }
+
+    // add start header length &
+    // assigned number for start parameter, and terminating zero for cid
+    headerLength += cid.Length() + KMms2;
+    if ( cid.Find( KMmsLeftAngle ) != 0 )
+        {
+        headerLength += KMms2; // we must add angle bracket
+        }
+
+    // Then the length of the content-type header...
+    TPtrC8 contentTypeString = iMimeHeaders->ContentType();
+    
+     HBufC8* tempContentType = HBufC8::NewL( iMimeHeaders->ContentType().Length() +
+         iMimeHeaders->ContentSubType().Length() + 1 );
+     CleanupStack::PushL( tempContentType );
+     tempContentType->Des().Copy( iMimeHeaders->ContentType() );
+     if ( ( iMimeHeaders->ContentType().Find( KMmsSlash8 ) !=
+        ( iMimeHeaders->ContentType().Length() - 1 ) ) &&
+        ( iMimeHeaders->ContentSubType().Find( KMmsSlash8 ) != 0 ) &&
+        ( iMimeHeaders->ContentSubType().Length() != 0 ) )
+        {
+        tempContentType->Des().Append( KMmsSlash8 );
+        }
+    tempContentType->Des().Append( iMimeHeaders->ContentSubType() );
+    attachmentInfo->SetMimeTypeL( tempContentType->Des() );
+    CleanupStack::PopAndDestroy( tempContentType );
+    contentTypeString.Set( attachmentInfo->MimeType() );
+
+    if ( contentTypeString.Length() == 0 )
+        {
+        // We need a content type...
+        // If we don't know, we say "Any"
+        contentTypeString.Set( KMmsAny );
+        }
+    // Check if we have well-known media.
+    TInt8 rootContentType = -1;
+
+    TInt8 i = 0;
+    for ( i = 0; i < KNumberContentTypes && rootContentType < 0; i++ )
+        {
+        if ( contentTypeString.CompareF( TPtrC8( KContentTypeTable[i] ) ) == 0 )
+            {
+            rootContentType = i;
+            }
+        }
+        
+    // start parameter assignment
+    headerLength += 1;
+    if ( rootContentType != -1 )
+        {
+        // well known content type
+        headerLength += 1;
+        }
+    else
+        {
+        // string + terminating zero
+        headerLength += contentTypeString.Length() + 1;
+        }
+        
+    TPtrC8 appIdPtr;
+    appIdPtr.Set( KMmsJavaApplicationId ); 
+    // Java application id parameters added to content-type        
+    if ( iMmsHeaders->ApplicId().Length() > 0 )
+        {
+        headerLength += appIdPtr.Length() + 1 ;
+        headerLength += iMmsHeaders->ApplicId().Length() + 1;
+        }
+    appIdPtr.Set( KMmsJavaReplyApplicationId );    
+    if ( iMmsHeaders->ReplyApplicId().Length() > 0 )
+        {
+        headerLength += appIdPtr.Length() + 1 ;
+        headerLength += iMmsHeaders->ReplyApplicId().Length() + 1;
+        }
+
+    // write general encoding length
+    EncodeValueLength( headerLength );
+
+    // Then the Media Type with parameters
+        
+    // We are multipart/related, which is a well-known media
+    // encode as short integer
+    TUint8 byte = KMmsAssignedApplicationVndWapMultipartRelated | KMms0x80;
+    iEncodeBuffer->Write( iPosition, &byte, 1 );
+    iPosition++;
+
+    // Then the start parameter and cid text string
+    byte = KWspStart | KMms0x80;
+    
+    if ( cid.Length() > 0 )
+        {
+        HBufC8* tempContentId = HBufC8::NewL( iMimeHeaders->ContentId().Length() + KMms2 );
+        CleanupStack::PushL( tempContentId );
+        if ( cid.Find( KMmsLeftAngle ) != 0 )
+            {
+            tempContentId->Des().Copy( KMmsLeftAngle );
+            tempContentId->Des().Append( cid );
+            tempContentId->Des().Append( KMmsRightAngle );
+            }
+        else
+            {
+            tempContentId->Des().Copy( cid );
+            }
+        EncodeHeaderAndTextString( byte, tempContentId->Des() );
+        CleanupStack::PopAndDestroy( tempContentId );
+        }
+
+
+    // next the content type of the root part
+    byte = KWspRelatedType | KMms0x80;
+    // and the actual type either as a well-known media type
+    // or a text string.
+
+    if ( rootContentType != -1 )
+        {
+        // Well known content type.
+        // EncodeMandatoryByte will set the high bit
+        EncodeMandatoryByte( byte, rootContentType );
+        }
+    else
+        {
+        // string + terminating zero
+        EncodeHeaderAndTextString( byte, contentTypeString );
+        }
+       
+    if ( iMmsHeaders->ApplicId().Length() > 0 ||
+        iMmsHeaders->ReplyApplicId().Length() > 0 )
+        {
+        EncodeApplicationIdParametersL();
+        }
+            
+    // encode number of parts
+    EncodeUintvar( iNumberOfAttachments );
+    
+    // get rid of stuff we put on stack
+    CleanupStack::PopAndDestroy( cleanupCount ); 
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMultipartMixedHeaderL()
+    {
+    
+    // If Java has added application id or reply-to application id, 
+    // even multipart/mxed type needs parameters.
+    
+    TUint headerLength = 0; // assume no parameters
+    
+    if ( iMmsHeaders->ApplicId().Length() > 0 ||
+        iMmsHeaders->ReplyApplicId().Length() > 0 )
+        {
+        headerLength = 1; // one byte for well known media
+        TPtrC8 appIdPtr;
+        appIdPtr.Set( KMmsJavaApplicationId ); 
+        if ( iMmsHeaders->ApplicId().Length() > 0 )
+            {
+            headerLength += appIdPtr.Length() + 1 ;
+            headerLength += iMmsHeaders->ApplicId().Length() + 1;
+            }
+        appIdPtr.Set( KMmsJavaReplyApplicationId );    
+        if ( iMmsHeaders->ReplyApplicId().Length() > 0 )
+            {
+            headerLength += appIdPtr.Length() + 1 ;
+            headerLength += iMmsHeaders->ReplyApplicId().Length() + 1;
+            }
+        }
+
+    iEncodeBuffer->Write( iPosition, &KMmsAssignedContentType, 1 );
+    iPosition++;
+    
+    if ( headerLength > 0 )
+        {
+        // write general encoding length
+        EncodeValueLength( headerLength );
+        }
+
+    // encode as short integer
+    TUint8 contentType = KMmsAssignedApplicationVndWapMultipartMixed | KMms0x80;
+    iEncodeBuffer->Write( iPosition, &contentType, 1 );
+    iPosition++;
+
+    if ( iMmsHeaders->ApplicId().Length() > 0 ||
+        iMmsHeaders->ReplyApplicId().Length() > 0 )
+        {
+        EncodeApplicationIdParametersL();
+        }
+
+    // No more parameters for multipart/mixed, actual parts follow
+
+    // encode number of parts
+    EncodeUintvar( iNumberOfAttachments );
+    
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeKeywordArrayL()
+    {
+    TInt i = 0;
+    TInt length = 0;
+
+    // caller must check that iMmsHeaders->ReadOnlyMMBoxMessageHeaders() is not NULL
+    CMmsMMBoxMessageHeaders& temp = iMmsHeaders->MMBoxMessageHeadersL();
+    for ( i = 0; i < temp.KeywordArray().Count(); i++ )
+        {
+        length = temp.KeywordArray()[i]->Keyword().Length();
+        if ( length > 0 )
+            {
+            iEncodeBuffer->Write( iPosition, &KMmsAssignedMMFlags, 1 );
+            iPosition++;
+            // do some fake encoding to get the text length
+            TUint oldPosition = iPosition; // we will return here
+            EncodeTextStringL( temp.KeywordArray()[i]->Keyword() );
+            length = iPosition - oldPosition;
+            iPosition = oldPosition; // return to original place
+            length += 1; // token must come before string
+            EncodeValueLength( length );
+            TUint8 token = (TUint8) temp.KeywordArray()[i]->Token();
+            if ( iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewReq ||
+                 iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewConf ||
+                 iMmsHeaders->MessageType() == KMmsMessageTypeMBoxDescr )
+                {
+                // the token must always be filter for MMbox PDUs
+                token = KMmsFilterToken;
+                }
+            iEncodeBuffer->Write( iPosition, &token, 1 );
+            iPosition++;
+            EncodeTextStringL( temp.KeywordArray()[i]->Keyword() );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeOptionalInteger( TUint8 aHeader, TUint aValue )
+    {
+    if ( aValue == 0 )
+        {
+        return; // not set, nothing to encode, header is optional
+        }
+
+    iEncodeBuffer->Write( iPosition, &aHeader, 1 );
+    iPosition++;
+
+    EncodeInteger( aValue );
+
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeAttributes( RArray<TUint>& aAttributeArray )
+    {
+    TInt i;
+
+    for ( i = 0; i < aAttributeArray.Count(); i++ )
+        {
+        EncodeMandatoryByte( KMmsAssignedAttributes, aAttributeArray[i] );
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeMMBoxStates( RArray<TInt>& aStateArray )
+    {
+    TInt i;
+
+    for ( i = 0; i < aStateArray.Count(); i++ )
+        {
+        EncodeMandatoryByte( KMmsAssignedMMState, aStateArray[i] );
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeContentLocationArray()
+    {
+    TBool mustCheck = EFalse;
+    if ( iMmsHeaders->ContentLocation().Length() > 0 )
+        {
+        mustCheck = ETrue;
+        EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+            iMmsHeaders->ContentLocation() );
+        }
+    // If there is content location array, encode it, too.
+    // A content-location should never occur in both places, but we still check
+
+    TInt i = 0;
+    if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
+        {
+        for ( i = 0;
+            i < iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList().Count();
+            i++ )
+            {
+            if ( !( mustCheck && iMmsHeaders->ContentLocation().Compare(
+                iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList()[i] ) == 0 ) )
+                {
+                // the content location in the list does not appear as
+                // separate header, we must add it
+                EncodeHeaderAndTextString( KMmsAssignedContentLocation,
+                    iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList()[i] );
+                }
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeStartingHeaders( TInt aMessageType,
+    const TPtrC8& aTID, TInt aVersion )
+    {
+    // EncodeMandatoryByte will always set the high bit.
+    
+    // Message type
+    EncodeMandatoryByte( KMmsAssignedMessageType, aMessageType );
+    // TID if present
+    EncodeOptionalString( KMmsAssignedTID, aTID );
+    // MMS encapsulation version
+    EncodeMandatoryByte( KMmsAssignedMmsVersion, aVersion );
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsEncode::EncodeApplicationIdParametersL()
+    {
+    if ( iMmsHeaders->ApplicId().Length() > 0 )
+        {
+        EncodeTextString( KMmsJavaApplicationId );
+        EncodeTextStringL( iMmsHeaders->ApplicId() );
+        }
+    if ( iMmsHeaders->ReplyApplicId().Length() > 0 )
+        {
+        EncodeTextString( KMmsJavaReplyApplicationId );
+        EncodeTextStringL( iMmsHeaders->ReplyApplicId() );
+        }
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+void CMmsEncode::Dump()
+    {
+    // no dump if not logging
+#ifndef _NO_MMSS_LOGGING_
+    TInt error = KErrNone;
+    // if no can do, sorry.
+    TRAP( error,
+        {
+        if ( iEntryWrapper )
+            {
+            if ( ( iEntryWrapper->GetDumpFlag() ) &&
+                iEncodeBuffer &&
+                iEncodeBuffer->Size() > 0 )
+                {
+                iFileName = KMmsDefaultLogDirectory;
+                TUint att;
+                if ( iFs.Att( iFileName, att ) == KErrNone )
+                    {
+                    _LIT( KRelated, "Sent.mms");
+                    iParse.Set( iFileName, &KRelated, NULL );
+                    iFileName = iParse.FullName();
+                    User::LeaveIfError( CApaApplication::GenerateFileName(
+                        iFs, iFileName ) );
+                    RFile file;
+                    User::LeaveIfError( file.Create( iFs, iFileName,
+                        EFileWrite | EFileShareExclusive ) );
+                    // for message id generation
+                    iParse.Set( iFileName, NULL, NULL );
+
+                    // the data is supposed to be in the encode buffer
+                    TPtr8 ptr = iEncodeBuffer->BackPtr( iPosition );
+                    file.Write( ptr );
+                    file.Flush();
+
+                    // done - close files
+                    file.Close();
+                    }
+                }
+            }
+        }
+    );
+    if ( error != KErrNone )
+        {
+        TMmsLogger::Log( _L("Dump left with error %d"), error );
+        }
+#endif
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+void CMmsEncode::DumpAppend()
+    {
+    
+    // no dump if not logging
+#ifndef _NO_MMSS_LOGGING_
+    TInt error = KErrNone;
+    // if no can do, sorry.
+    TRAP( error,
+        {
+        if ( iEntryWrapper )
+            {
+            if ( ( iEntryWrapper->GetDumpFlag() ) &&
+                iEncodeBuffer &&
+                iEncodeBuffer->Size() > 0 )
+                {
+                iFileName = KMmsDefaultLogDirectory;
+                TUint att;
+                if ( iFs.Att( iFileName, att ) == KErrNone )
+                    {
+                    RFile file;
+                    iFileName = iParse.FullName();
+                    User::LeaveIfError( file.Open( iFs, iFileName,
+                       EFileWrite | EFileShareExclusive ) );
+                    TInt position = 0; // seek to end
+                    file.Seek( ESeekEnd, position );
+                    // the data is supposed to be in the encode buffer
+                    TPtr8 ptr = iEncodeBuffer->BackPtr( iPosition );
+                    file.Write( ptr );
+                    file.Flush();
+                    // done - close files
+                    file.Close();
+                    }
+                }
+            }
+        }
+    );
+    if ( error != KErrNone )
+        {
+        TMmsLogger::Log( _L("DumpAppend left with error %d"), error );
+        }
+#endif
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+void CMmsEncode::EncodeApplicationHeadersL()
+    {
+// Application headers are only supported in WINS for testing purposes
+// Complete support for routing messages to arbitrary applications
+// requires support for selecting which applications are allowed
+// to send messages etc.    
+#ifdef __WINS__
+    // The optional string functions check the length
+    // and return without doing anything if the length of the string is 0
+    if ( IsStringSafe( iMmsHeaders->ApplicId() ) )
+        {
+        // We only send this header if it is us-ascii only
+        // There is no encoding defined, so if this is converted
+        // from unicode to some other character set there is 
+        // no guarantee that the recipient can decode it.
+        EncodeOptionalStringL( KMmsAssignedApplicId, iMmsHeaders->ApplicId() );
+        }
+        
+    if ( IsStringSafe( iMmsHeaders->ReplyApplicId() ) )
+        {
+        EncodeOptionalStringL( KMmsAssignedReplyApplicId, iMmsHeaders->ReplyApplicId() );
+        }
+
+    EncodeOptionalString( KMmsAssignedAuxApplicInfo, iMmsHeaders->AuxApplicInfo() );
+#endif    
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+void CMmsEncode::EncodeCancelRequest()
+    {
+// implemented for test purposes
+#ifdef __WINS__
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeCancelReq,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+        
+    EncodeOptionalString( KMmsAssignedCancelId, iMmsHeaders->ReplaceCancelId() );
+#endif    
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+void CMmsEncode::EncodeCancelResponse()
+    {
+    // Insert message type, TID and version number
+    EncodeStartingHeaders( KMmsMessageTypeCancelConf,
+        iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
+        
+    EncodeOptionalByte( KMmsAssignedCancelStatus, iMmsHeaders->CancelStatus() );   
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+HBufC8* CMmsEncode::EncodeQuotedPrintableWordL( const TPtrC8& aSource )
+    {
+    // We have calculated that it fits
+    
+    TInt bufferLength = KMaxNameBufferLength;
+    
+    HBufC8* buffer = HBufC8::NewL( bufferLength );
+    CleanupStack::PushL( buffer );
+    TPtr8 ptr = buffer->Des();
+    buffer->Des().Copy( KMmsQuotedPreamble );
+    ptr.SetLength( bufferLength );
+    TPtr8 encodeBuffer = ptr.MidTPtr( KMmsPreambleLength );
+    encodeBuffer.SetLength( 0 ); // empty the buffer
+    
+    TImCodecQP encoder;
+
+    // The function would return the number of characters written to the buffer.
+    // We don't do anything with the result, so we ignore the return value.
+    encoder.Encode( aSource, encodeBuffer );
+    
+    ptr.SetLength( encodeBuffer.Length() + KMmsPreambleLength );
+    
+    buffer->Des().Append( KMmsEncodingTrailer );
+    CleanupStack::Pop( buffer );
+    return buffer;
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+HBufC8* CMmsEncode::EncodeBase64WordL( const TPtrC8& aSource )
+    {
+    // ((length + 2)/3)*4  3 bytes alwaus produces 4 encoded bytes. Allow filler
+    TInt bufferLength = KMmsEncodingExtraLength + ( aSource.Length() + KMms2 ) / KMms3 * KMms4;
+    
+    HBufC8* buffer = HBufC8::NewL( bufferLength );
+    CleanupStack::PushL( buffer );
+    TPtr8 ptr = buffer->Des();
+    buffer->Des().Copy( KMmsBase64Preamble );
+    ptr.SetLength( bufferLength );
+
+    TPtr8 encodeBuffer = ptr.MidTPtr( KMmsPreambleLength );
+    encodeBuffer.SetLength( 0 ); // empty the buffer
+
+    TImCodecB64 encoder;
+
+    // It is rather unclear what this function actually returns (no documentation found). 
+    // Therefore we just ignore the result.
+    // Our buffer is long enough for the result to always fit.
+    encoder.Encode( aSource, encodeBuffer );
+    
+    ptr.SetLength( encodeBuffer.Length() + KMmsPreambleLength );
+    
+    buffer->Des().Append( KMmsEncodingTrailer );
+    CleanupStack::Pop( buffer );
+    return buffer;
+    }
+    
+
+// ---------------------------------------------------------
+// CMmsEncode::PreProcessAttachmentDataL
+// Open the message store(Edit mode) and process attachments for further encoding in required encoding type.
+// Update the message store accordingly with the new encoding type and data in the corresponding attachments.
+// ---------------------------------------------------------
+void CMmsEncode::PreProcessAttachmentDataL()
+    {
+    TInt error = KErrNone;
+    RFile attachFile;
+    TBool retVal = EFalse;
+    TInt currAttachI;
+    
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- start ") );
+#endif /* _NO_MMSS_LOGGING_ */
+    CMsvStore* editStore = iEntryWrapper->EditStoreL();
+    CleanupStack::PushL( editStore );
+
+    MMsvAttachmentManager& attachMan = editStore->AttachmentManagerL();
+    MMsvAttachmentManagerSync& attachManagerSync = editStore->AttachmentManagerExtensionsL();
+    TInt numberOfAttachments = attachMan.AttachmentCount();
+    CMsvAttachment* attachmentInfo = NULL;
+    iTextUtils = CMsgTextUtils::NewL( iFs );
+    
+    for ( currAttachI = 0; ( currAttachI < numberOfAttachments ) && ( error == KErrNone ); currAttachI++ )
+        {
+        //gets the ownership from attachment manager
+        attachmentInfo = attachMan.GetAttachmentInfoL( currAttachI );
+        CleanupStack::PushL( attachmentInfo );       
+        iMimeHeaders->RestoreL( *attachmentInfo );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- Attchment:%d "), currAttachI );
+#endif /* _NO_MMSS_LOGGING_ */
+        
+        if ( iFileOpen )
+            {
+            // close any file in case we have been reset while the file is still open
+            iAttachFile.Close();
+            iFileOpen = EFalse;
+            }
+
+        retVal = CheckAndUpdateAttachmentL(*attachmentInfo, *iMimeHeaders);
+
+        if( retVal )
+            {
+            TRAPD( 
+                    err,
+                    attachManagerSync.ModifyAttachmentInfoL(attachmentInfo);
+                    editStore->CommitL();
+                  );
+#ifndef _NO_MMSS_LOGGING_
+            if(err != KErrNone)
+                {
+                TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: store commit error: %d"), err );
+                }
+            else
+                {
+                TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: store commit success") );                
+                }
+#endif /* _NO_MMSS_LOGGING_ */
+            /*  attachmentInfo ownership is transfered to attachment manager
+             *  Hence, JUST pop attachmentInfo, DO NOT Destroy.
+             */
+            CleanupStack::Pop( attachmentInfo );
+            }
+        else
+            {
+            CleanupStack::PopAndDestroy( attachmentInfo );
+            attachmentInfo = NULL;
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: Tgt encoding NOT Reqd.") );                
+#endif /* _NO_MMSS_LOGGING_ */
+            }
+        }
+    CleanupStack::PopAndDestroy( editStore );
+    
+    delete iTextUtils;
+    iTextUtils = NULL;
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- end ") );
+#endif /* _NO_MMSS_LOGGING_ */
+    }
+
+// ---------------------------------------------------------
+// CMmsEncode::CheckAndUpdateAttachmentL
+// Check and proceed if given attachment can be encoded using target encoding type based on its content type.
+// Returns False if target encoding is not supported for this content type.
+// ---------------------------------------------------------
+TBool CMmsEncode::CheckAndUpdateAttachmentL( CMsvAttachment& aAttachmentInfo,
+                                             CMsvMimeHeaders& aMimeHeaders )
+    {
+    //get the content type string... and set to attachment if required
+    TInt contentType = -1; // indicate not found
+    TPtrC8 contentTypeString;
+    TBool retVal = EFalse;
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- start ") );
+#endif /* _NO_MMSS_LOGGING_ */
+
+    HBufC8* tempContentType = NULL;
+    contentTypeString.Set( aAttachmentInfo.MimeType() );
+    if ( contentTypeString.Length() == 0 )
+        {
+        // take type from mime headers
+        TInt cotentLength = aMimeHeaders.ContentType().Length();
+        TInt subCotentLength = aMimeHeaders.ContentSubType().Length();
+        tempContentType = HBufC8::NewL( cotentLength + subCotentLength + 1 );
+        CleanupStack::PushL( tempContentType );
+        tempContentType->Des().Copy( aMimeHeaders.ContentType() );
+        if ( ( aMimeHeaders.ContentType().Find( KMmsSlash8 ) != ( cotentLength - 1 ) ) &&
+             ( aMimeHeaders.ContentSubType().Find( KMmsSlash8 ) != 0 ) && ( subCotentLength != 0 ) )
+            {
+            tempContentType->Des().Append( KMmsSlash8 );
+            }
+        tempContentType->Des().Append( aMimeHeaders.ContentSubType() );
+        aAttachmentInfo.SetMimeTypeL( tempContentType->Des() );
+        contentTypeString.Set( aAttachmentInfo.MimeType() );
+        }
+        
+    //map the content type string to content type
+    TInt8 i;
+    for ( i = 0; i < KNumberContentTypes && contentType < 0; i++ )
+        {
+        if ( contentTypeString.CompareF( TPtrC8( KContentTypeTable[i] ) ) == 0 )
+            {
+            contentType = i;
+            }
+        }
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- content type:%d" ), contentType );
+#endif /* _NO_MMSS_LOGGING_ */
+    //check if this content type need to be encoded using korean specific
+    if( IsConversionSupportedContentType( contentType ) )
+        {
+        /* Do the attachment data conversion from "src type" to "target type" for the given "attached file". 
+         * Target type encodng MIB enum is obtained from cenrep.
+         */
+        retVal = ProcessAndConvertAttachmentDataL( aMimeHeaders.MimeCharset(),
+                                                   iTargetEncodingType,
+                                                   aAttachmentInfo);
+        if( retVal )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- conv success: Tgt Enc: %d"), iTargetEncodingType );
+#endif /* _NO_MMSS_LOGGING_ */
+            //set new charset type in headers and update attachment info
+            aMimeHeaders.SetMimeCharset( iTargetEncodingType );
+            aMimeHeaders.StoreL(aAttachmentInfo); // save the new charset to attachment as well
+            /* mimetype might get reset to original mimeheader content type.
+             * ensure the full content type(if created from mime content and subcontent) is set to attachment
+             */
+            if( tempContentType != NULL )
+                {
+                aAttachmentInfo.SetMimeTypeL( tempContentType->Des() );
+                CleanupStack::PopAndDestroy( tempContentType );                
+                }
+            }
+        }
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- End , retVal: %d"), retVal );
+#endif /* _NO_MMSS_LOGGING_ */
+    return retVal;
+    }
+    
+// ---------------------------------------------------------
+// CMmsEncode::ProcessAndConvertAttachmentDataL
+// converts of attachment data from source to target encoding type.
+// |src charset buffer| --->coverted to ---> |unicode buffer| ---> converted to ---> |target charset|
+// Returns false if data is already int target format, or plugins are missing, or file operation issues.
+// ---------------------------------------------------------
+TBool CMmsEncode::ProcessAndConvertAttachmentDataL( TUint aSrcCharSetMIBEnum,
+                                                    TUint aTargetCharSetMIBEnum, 
+                                                    CMsvAttachment& aAttachmentInfo)
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- start ") );
+#endif /* _NO_MMSS_LOGGING_ */
+    if( aSrcCharSetMIBEnum == aTargetCharSetMIBEnum )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- src and dest are same ") );
+#endif /* _NO_MMSS_LOGGING_ */
+        //if source and target charset MIB enums are same.  
+        return EFalse; // no conversion 
+        }
+        
+    //get source and target charset mapping here. if any error, return
+    TUint srcCharSetId = iTextUtils->MibIdToCharconvIdL( aSrcCharSetMIBEnum );
+    TUint targetCharSetId = iTextUtils->MibIdToCharconvIdL( aTargetCharSetMIBEnum );
+    if( srcCharSetId == targetCharSetId || KDefaultCharConvCharset == targetCharSetId)
+        {
+        /* If target charset plugin is missing, then default is returned. 
+           Do not encode to any target encoding type, send data as is .
+         */ 
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- missing plugin: Tgt Charset %x"), targetCharSetId );
+#endif /* _NO_MMSS_LOGGING_ */
+        return EFalse;
+        }
+    
+    RFile attachFile;
+    TInt error;
+
+    const TDesC& fileName = aAttachmentInfo.FilePath();
+    error = attachFile.Open(iFs, fileName, EFileWrite);
+    if(error != KErrNone)
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file: %s, open error: %d"), fileName, error );
+#endif /* _NO_MMSS_LOGGING_ */
+        attachFile.Close();
+        return EFalse;
+        }
+
+    TInt maxLength;
+    error = attachFile.Size(maxLength);
+    if( error != KErrNone || maxLength == 0 )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file size: %d, error: %d"), maxLength, error );
+#endif /* _NO_MMSS_LOGGING_ */
+        attachFile.Close();
+        return EFalse;
+        }
+
+    //read the original file data into srcBuffer
+    TInt cleanupCount = 0;    
+    HBufC8* srcBuffer = HBufC8::NewLC( maxLength );
+    cleanupCount++;
+    
+    TPtr8 srcPtr = srcBuffer->Des();
+    attachFile.Read( srcPtr, maxLength );
+        
+    //intermediate buffer in the form of unicode. 
+    HBufC16* unicodeBuffer(NULL);
+
+    //Convert, scrBuffer to unicode format if not already in unicode format
+    if(srcCharSetId != 0)
+        {
+        //Convert from respective foreign charset to unicode buffer.
+        //returns buf16 pointer descriptor
+        TRAPD(err, unicodeBuffer = iTextUtils->ConvertToUnicodeL(srcPtr, srcCharSetId) );
+        if( err != KErrNone )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: ConvertToUnicodeL error: %d"), err );
+#endif /* _NO_MMSS_LOGGING_ */
+            delete unicodeBuffer;
+            attachFile.Close();
+            CleanupStack::PopAndDestroy( cleanupCount, srcBuffer ); // srcBuffer
+            return EFalse;
+            }
+        CleanupStack::PushL( unicodeBuffer );
+        cleanupCount++;
+        }
+    else
+        {
+        TInt unicodeStdHeaderWordLE = 0xFEFF;
+        TInt unicodeStdHeaderWordBE = 0xFFFE;
+        //data is already in unicode format. need to extract the data to 16-bit buffer
+        unicodeBuffer = HBufC16::NewLC( maxLength/2 );//maxlength value is in terms of bytes
+        cleanupCount++;
+        
+        TPtr16 ptr = unicodeBuffer->Des();
+        iTextUtils->ConvertPtrToDesC16(srcPtr, ptr);
+        /* In case if attachment is UTF-16 format, it will have the UTF-16 representation word(2 butes)
+         * at the start. Find and delete it before passing the data for conversion
+         */ 
+        if( ptr[0] == unicodeStdHeaderWordLE || ptr[0] == unicodeStdHeaderWordBE )
+            {
+            ptr.Delete(0, 1);
+            }
+        }
+
+    //Now convert unicode buffer to respective target charset type.
+    if( targetCharSetId != 0 )
+        {
+        // reset this file and write new encoded data to it directly
+        error = attachFile.SetSize(0);
+#ifndef _NO_MMSS_LOGGING_
+        if( error != KErrNone )
+            {
+            TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file size: %d, error: %d"), maxLength, error );
+            //attachFile.Close();
+            //return EFalse;
+            }
+#endif /* _NO_MMSS_LOGGING_ */
+        
+        /* convert to target charset id.
+         * Ideally, this should not leave with plugin-NOT-found, since it it already verified
+         */
+        iTextUtils->ConvertToFileL(*unicodeBuffer, attachFile, targetCharSetId );
+        }
+    else
+        {
+        TPtr16 ptr = unicodeBuffer->Des();
+        //Reset/erase old file content.
+        TInt err = attachFile.SetSize(0);
+
+        //write new encoded data to file using write stream
+        RFileWriteStream writer( attachFile );
+        writer.PushL();
+        writer.WriteL( ptr );
+        //writer.CommitL();
+        writer.Pop();
+        writer.Close();
+        }
+    //close file
+    attachFile.Close();
+    CleanupStack::PopAndDestroy( cleanupCount, srcBuffer ); //unicodeBuffer, srcBuffer
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- End, retVal: TRUE") );
+#endif /* _NO_MMSS_LOGGING_ */
+    return ETrue;
+    }
+
+
+// ---------------------------------------------------------
+// CMmsEncode::IsConversionSupportedContentType
+// checks if input content type is supported for target encoding
+// ---------------------------------------------------------
+TBool CMmsEncode::IsConversionSupportedContentType( TInt aContentType )
+    {
+    /* Currently only "text/plain" content types are supported for korean encoding.
+     * Add to the switch case, if any new content type can be supported as well.
+     * 
+     * IMPORTANT: 
+     * Ensure the values added map to corresponding content type entry in the table KContentTypeTable[],
+     * defined in ../inc/mmscodec.h
+     */
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::IsConversionSupportedContentType- start: %d "), aContentType );
+#endif /* _NO_MMSS_LOGGING_ */
+    TBool retVal = EFalse;
+    switch( aContentType )
+        {
+        case 0x03 :           // "text/plain" 
+            {
+            retVal = ETrue;
+            break;
+            }
+        default:
+            //do nothing
+            break;// to avoid compile errors/warning
+        }
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsEncode::IsConversionSupportedContentType- end ") );
+#endif /* _NO_MMSS_LOGGING_ */
+    return retVal;
+    }
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+//  End of File