mmsengine/mmscodec/src/mmsencode.cpp
changeset 31 ebfee66fde93
child 44 36f374c67aa8
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 /*
       
     2 * Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *     binary encoding of a multimedia message
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 //#define CONTENT_DISPOSITION_TEST
       
    22 
       
    23 // INCLUDE FILES
       
    24 #include    <e32std.h>
       
    25 #include    <apparc.h>
       
    26 #include    <s32mem.h>
       
    27 #include    <msventry.h>
       
    28 #include    <utf.h>
       
    29 #include    <e32math.h>
       
    30 #include    <msvids.h>
       
    31 #include    <escapeutils.h>
       
    32 #include    <badesca.h>
       
    33 #include    <mmsvattachmentmanager.h>
       
    34 #include    <mmsvattachmentmanagersync.h>
       
    35 #include    <cmsvmimeheaders.h>
       
    36 #include    <imcvcodc.h>
       
    37 
       
    38 #include    <msgtextutils.h>
       
    39 #include    <msvstore.h>
       
    40 #include    <charconv.h>
       
    41 
       
    42 #include    <centralrepository.h>          // link against centralrepository.lib
       
    43 #include    "MmsEnginePrivateCRKeys.h"
       
    44 
       
    45 #include    "mmsheaders.h"
       
    46 #include    "mmsconst.h"
       
    47 #include    "mmscodec.h"
       
    48 #include    "mmsencode.h"
       
    49 #include    "mmsservercommon.h"
       
    50 #include    "mmssession.h"
       
    51 #include    "mmsgenutils.h"
       
    52 #include    "mmserrors.h"
       
    53 #include    "mmsentrywrapper.h"
       
    54 #include    "mmsmmboxmessageheaders.h"
       
    55 #include    "mmsmmboxviewheaders.h"
       
    56 #include    "mmssendingchain.h"
       
    57 
       
    58 const TInt KMmsExtra = 1024; // extra memory left for others
       
    59 const TInt KMmsShortIntegerLimit127 = 127; // limit for short integer length
       
    60 const TInt KMmsOneByteLimit = 0x100;
       
    61 const TInt KMmsTwoByteLimit = 0x10000;
       
    62 const TInt KMmsThreeByteLimit = 0x1000000;
       
    63 const TInt KMms2 = 2;
       
    64 const TInt KMms3 = 3;
       
    65 const TInt KMms4 = 4;
       
    66 const TInt KMms5 = 5;
       
    67 const TInt KMms7 = 7;
       
    68 const TInt KMms8 = 8;
       
    69 const TInt KMms24 = 24; // shift of three half bytes
       
    70 const TInt KMms30 = 30; // upper limit for short length encoding
       
    71 const TUint8 KMms0x80 = 0x80; // 128
       
    72 const TUint8 KMms0x7F = 0x7F; // 127
       
    73 const TUint8 KMms0xFF = 0xFF;
       
    74 const TInt KMmsMaxCidLength = 18;
       
    75 // max filename length according to MMS conformance specs
       
    76 const TInt KMmsMaxFileNameLength = 40;
       
    77 // if 40 bytes are encoded in base 64, the result is 56 bytes
       
    78 // (two bytes of padding are needed to make the number divisible by 3)
       
    79 const TInt KMaxEncodingLength = 56;
       
    80 // Maximum length of output buffer needed for encoding the filename
       
    81 // Max 56 bytes for actual encoding and 12 bytes for character set (utf8)
       
    82 // and encoding scheme indicator 68 for final result, but we allocate
       
    83 // the maximum Mime header length to be sure everything fits.
       
    84 const TInt KMaxNameBufferLength = 75;
       
    85 const TInt KMmsEncodingExtraLength = 12;
       
    86 const TInt KMmsPreambleLength = 10;
       
    87 _LIT8( KMmsQuotedPreamble, "=?utf-8?Q?" );
       
    88 _LIT8( KMmsBase64Preamble, "=?utf-8?B?" );
       
    89 _LIT8( KMmsEncodingTrailer, "?=" );
       
    90 const TInt KMmsIntUnderscore = 0x5F; // underscore
       
    91 
       
    92 
       
    93 enum TMmsMachineStates
       
    94     {
       
    95     EMmsIdle,
       
    96     EMmsEncodingHeaders,
       
    97     EMmsEncodingAttachments,
       
    98     EMmsFinished
       
    99     };
       
   100     
       
   101 // These are the stages for chunked encoding.
       
   102 // The chunked encoding is synchronous, so the stages are different
       
   103 // from the machine states.    
       
   104 enum TMmsChunkedEncodingStages
       
   105     {
       
   106     EMmsHeaders,
       
   107     EMmsAttachmentHeaders,
       
   108     EMmsAttachmentData
       
   109     };
       
   110     
       
   111 // ==================== LOCAL FUNCTIONS ====================
       
   112 
       
   113 // ================= MEMBER FUNCTIONS =======================
       
   114 
       
   115 // ---------------------------------------------------------------------------
       
   116 // C++ default constructor can NOT contain any code, that
       
   117 // might leave.
       
   118 //
       
   119 // All member variables are automatically zeroed in the constructor
       
   120 // of a class derived from CBase.
       
   121 // Priority is set slightly above standard (1 instead of 0) to make sure
       
   122 // that message is sent as soon as possible (user input has priority 10).
       
   123 // Variables related to chunked encoding are initialized to indicate
       
   124 // one complete chunk only.
       
   125 // ---------------------------------------------------------------------------
       
   126 //
       
   127 CMmsEncode::CMmsEncode()
       
   128     :CMsgActive ( KMmsActiveObjectPriority ),
       
   129     iState ( EMmsIdle ),
       
   130     iOverallDataSize ( -1 ),
       
   131     iLastChunk ( ETrue ),
       
   132     iOnlyOneChunk( ETrue )
       
   133     {
       
   134     }
       
   135 
       
   136 // ---------------------------------------------------------------------------
       
   137 // Symbian OS default constructor can leave.
       
   138 // ---------------------------------------------------------------------------
       
   139 //
       
   140 void CMmsEncode::ConstructL( RFs& aFs )
       
   141     {
       
   142     iFs = aFs;
       
   143     CActiveScheduler::Add( this );
       
   144     }
       
   145 
       
   146 // ---------------------------------------------------------------------------
       
   147 // Two-phased constructor.
       
   148 // ---------------------------------------------------------------------------
       
   149 //
       
   150 EXPORT_C CMmsEncode* CMmsEncode::NewL( RFs& aFs )
       
   151     {
       
   152     CMmsEncode* self = new ( ELeave ) CMmsEncode;
       
   153     
       
   154     CleanupStack::PushL( self );
       
   155     self->ConstructL( aFs );
       
   156     CleanupStack::Pop( self );
       
   157 
       
   158     return self;
       
   159     }
       
   160 
       
   161     
       
   162 // ---------------------------------------------------------------------------
       
   163 // Destructor
       
   164 // ---------------------------------------------------------------------------
       
   165 //
       
   166 CMmsEncode::~CMmsEncode()
       
   167     {
       
   168 
       
   169     Cancel();
       
   170     
       
   171     if ( iFileOpen )
       
   172         {
       
   173         iAttachFile.Close();
       
   174         iFileOpen = EFalse;
       
   175         }
       
   176     
       
   177     // Do not delete pointers that were presents from the caller.
       
   178     // The caller still owns that data
       
   179     delete iMimeHeaders; // this is ours too.
       
   180    
       
   181     }
       
   182 
       
   183 // ---------------------------------------------------------
       
   184 //
       
   185 // ---------------------------------------------------------
       
   186 //
       
   187 EXPORT_C void CMmsEncode::StartL(
       
   188     MMmsEntryWrapper& aEntryWrapper,
       
   189     CMmsHeaders& aMmsHeaders,
       
   190     CBufFlat& aEncodeBuffer,
       
   191     TRequestStatus& aStatus )
       
   192     {
       
   193 
       
   194     // This is the entry point for encoding all PDUs that contain both headers
       
   195     // and data.
       
   196     // For normal use the only PDUs in this category would be M-send.req and
       
   197     // M-MBox-Upload.req, but for testing purposes the following PDUs may
       
   198     // also be handled using this entry point:
       
   199     // M-retrieve.conf (for testing purposes)
       
   200     // M-Mbox-View.conf (for testing purposes)
       
   201     // M-Mbox-Descr (for testing purposes) 
       
   202 
       
   203     // Old asynchronous encoding is retained.
       
   204     // Reset sets all chunk-related variables to indicate one chunk which is the last one
       
   205     Reset();
       
   206 
       
   207     iEntryWrapper = &aEntryWrapper;
       
   208     iMmsHeaders = &aMmsHeaders;
       
   209     iEncodeBuffer = &aEncodeBuffer;
       
   210 
       
   211     if ( iMimeHeaders )
       
   212         {
       
   213         iMimeHeaders->Reset();
       
   214         }
       
   215     else
       
   216         {
       
   217         iMimeHeaders = CMsvMimeHeaders::NewL();
       
   218         }
       
   219 
       
   220     // We need to know the message entry ID
       
   221     // The wrapper originally points to the message entry
       
   222     
       
   223     TMsvEntry indexEntry;
       
   224     iError = iEntryWrapper->GetIndexEntry( indexEntry );
       
   225     iCurrentMessageId = indexEntry.Id();
       
   226     
       
   227     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
   228     CleanupStack::PushL( store );
       
   229 
       
   230     // Only new attachment structure is supported    
       
   231     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
   232     iNumberOfAttachments = attachMan.AttachmentCount();
       
   233     
       
   234     CleanupStack::PopAndDestroy( store );
       
   235     
       
   236     Queue( aStatus );
       
   237     
       
   238     iStatus = KRequestPending;
       
   239     SetActive();
       
   240     // Pretend that we called an asynchronous service
       
   241     // in order to get into the state machine loop
       
   242     TRequestStatus* status = &iStatus;
       
   243     User::RequestComplete( status, iError );
       
   244 
       
   245     }
       
   246 
       
   247 // ---------------------------------------------------------
       
   248 //
       
   249 // ---------------------------------------------------------
       
   250 //
       
   251 EXPORT_C void CMmsEncode::EncodeHeadersL(
       
   252     CMmsHeaders& aMmsHeaders,
       
   253     CBufFlat& aEncodeBuffer )
       
   254     {
       
   255     // This function is used to encode all PDUs that contain only headers,
       
   256     // not data. Some are responses sent to MMSC, some are requests that
       
   257     // contain headers only.
       
   258     // Nothing is read from storage, everything to be encoded is contained
       
   259     // in the headers.
       
   260     // No active object is invoked, this is a synchronous function
       
   261     
       
   262     // Old one-chunk encoding is retained for encoding headers only.
       
   263     // Reset sets all chunk-related variables to indicate one chunk which is the last one
       
   264     Reset(); // also sets iError to KErrNone
       
   265 
       
   266     iMmsHeaders = &aMmsHeaders;
       
   267     iEncodeBuffer = &aEncodeBuffer;
       
   268 
       
   269     // start from the beginning
       
   270     iPosition = 0;
       
   271     // we discard old contents of the buffer in case we must expand it
       
   272     iEncodeBuffer->Reset();
       
   273     
       
   274     // We are a bit greedy here so that we don't need
       
   275     // to change the code if there is a minor change in the specs.
       
   276     iEncodeBuffer->ResizeL( iMmsHeaders->Size() + KMMSBufferExtra );
       
   277 
       
   278     // encode message depending on type
       
   279     // these are all types that contain headers only, never data
       
   280     switch ( iMmsHeaders->MessageType() )
       
   281         {
       
   282         case KMmsMessageTypeMNotifyRespInd:
       
   283             EncodeNotifyResponse();
       
   284             break;
       
   285         case KMmsMessageTypeAcknowledgeInd:
       
   286             EncodeAcknowledgeIndication();
       
   287             break;
       
   288         case KMmsMessageTypeMNotificationInd:
       
   289             EncodeMmsNotificationL();
       
   290             break;
       
   291         case KMmsMessageTypeForwardReq:
       
   292             EncodeForwardRequestL();
       
   293             break;
       
   294         case KMmsMessageTypeReadRecInd:
       
   295             EncodeReadReplyL();
       
   296             break;
       
   297         case KMmsMessageTypeMboxStoreReq:
       
   298             EncodeMMBoxStoreRequestL();
       
   299             break;
       
   300         case KMmsMessageTypeMboxViewReq:
       
   301             // This may contain keywords. Reserve some extra space
       
   302             EncodeMMBoxViewRequestL();
       
   303             break;
       
   304         case KMmsMessageTypeMBoxDeleteReq:
       
   305         case KMmsMessageTypeDeleteReq:
       
   306             EncodeDeleteRequestL();
       
   307             break;
       
   308         case KMmsMessageTypeCancelConf:
       
   309             EncodeCancelResponse();
       
   310             break;
       
   311         case KMmsMessageTypeReadOrigInd:
       
   312             // This is for testing purposes.
       
   313             // identical to ReadRecInd except for PDU type
       
   314             // This would be the PDU sent to originator by MMSC
       
   315             EncodeReadReplyL();
       
   316             break;
       
   317         case KMmsMessageTypeMSendConf:
       
   318             // for testing purposes
       
   319             EncodeSendConfirmationL();
       
   320             break;
       
   321         case KMmsMessageTypeDeliveryInd:
       
   322             // for testing purposes
       
   323             EncodeDeliveryReportL();
       
   324             break;
       
   325         case KMmsMessageTypeForwardConf:
       
   326             // for testing purposes
       
   327             EncodeForwardConfirmationL();
       
   328             break;
       
   329         case KMmsMessageTypeMboxStoreConf:
       
   330             // for testing purposes
       
   331             EncodeMMBoxStoreConfirmationL();
       
   332             break;
       
   333         case KMmsMessageTypeMBoxUploadConf:
       
   334             // for testing purposes
       
   335             EncodeMMBoxUploadConfirmationL();
       
   336             break;
       
   337         case KMmsMessageTypeMBoxDeleteConf:
       
   338         case KMmsMessageTypeDeleteConf:
       
   339             // for testing purposes
       
   340             EncodeDeleteConfirmationL();
       
   341             break;
       
   342         case KMmsMessageTypeCancelReq:
       
   343             // for testing purposes
       
   344             EncodeCancelRequest();
       
   345             break;
       
   346 #ifdef __WINS__
       
   347         case KMmsMessageTypeMSendReq:
       
   348             EncodeSendRequestHeadersL();
       
   349             break;
       
   350         case KMmsMessageTypeMBoxUploadReq:
       
   351             // This type has attachments and headers
       
   352             // This function encodes headers only
       
   353             EncodeMMBoxUploadRequestL();
       
   354             break;
       
   355         case KMmsMessageTypeMRetrieveConf:
       
   356             // for test purposes
       
   357             EncodeRetrieveConfirmationL();
       
   358             break;
       
   359         case KMmsMessageTypeMboxViewConf:
       
   360             // for test purposes
       
   361             EncodeMMBoxViewConfirmationL();
       
   362             break;
       
   363         case KMmsMessageTypeMBoxDescr:
       
   364             // for test purposes
       
   365             EncodeMMBoxDescriptionL();
       
   366             break;
       
   367 #endif
       
   368         default:
       
   369             // Illegal message type.
       
   370             iEncodeBuffer->Reset();
       
   371             iPosition = 0;
       
   372             break;
       
   373         }
       
   374 
       
   375     // Remove slack to keep garbage out from the end of the file
       
   376     iEncodeBuffer->ResizeL( iPosition );
       
   377     // Dump the buffer contents into file if requested
       
   378     Dump();
       
   379     
       
   380     iOverallDataSize = iEncodeBuffer->Size();
       
   381 
       
   382     }
       
   383     
       
   384 // ---------------------------------------------------------
       
   385 //
       
   386 // ---------------------------------------------------------
       
   387 //
       
   388 EXPORT_C void CMmsEncode::StartChunkedL(
       
   389     MMmsEntryWrapper& aEntryWrapper,
       
   390     CMmsHeaders& aMmsHeaders,
       
   391     CBufFlat& aEncodeBuffer,
       
   392     TRequestStatus& aStatus )
       
   393     {
       
   394     
       
   395     // This is the entry point for chunked encoding all PDUs that contain both headers
       
   396     // and data.
       
   397     
       
   398     // Reset sets all chunk-related variables to indicate one chunk which is the last one
       
   399 #ifndef _NO_MMSS_LOGGING_
       
   400     TMmsLogger::Log( _L("CMmsEncode: Start chunked") );
       
   401 #endif
       
   402     Reset(); // also sets iError to KErrNone
       
   403     iDataSupplierStage = EMmsHeaders;
       
   404     
       
   405     iEntryWrapper = &aEntryWrapper;
       
   406     iMmsHeaders = &aMmsHeaders;
       
   407     iEncodeBuffer = &aEncodeBuffer;
       
   408 
       
   409     if ( iMimeHeaders )
       
   410         {
       
   411         iMimeHeaders->Reset();
       
   412         }
       
   413     else
       
   414         {
       
   415         iMimeHeaders = CMsvMimeHeaders::NewL();
       
   416         }
       
   417         
       
   418     // We need to know the message entry ID
       
   419     // The wrapper originally points to the message entry
       
   420     
       
   421     TMsvEntry indexEntry;
       
   422     iError = iEntryWrapper->GetIndexEntry( indexEntry );
       
   423     iCurrentMessageId = indexEntry.Id();
       
   424     
       
   425     // Encode headers to the buffer
       
   426     // The rest will follow when next data chunk is requested.
       
   427     EncodeHeadersChunkedL();
       
   428     
       
   429 	aStatus=KRequestPending;
       
   430     TRequestStatus* status = &aStatus;
       
   431     User::RequestComplete( status, iError );
       
   432     }
       
   433     
       
   434     
       
   435 // ---------------------------------------------------------
       
   436 // From class MMmsCodecDataSupplier
       
   437 //
       
   438 // ---------------------------------------------------------
       
   439 //
       
   440 TInt CMmsEncode::GetNextDataPart( TPtrC8& aDataPart, TBool& aLastDataChunk )
       
   441     {
       
   442     TInt error = KErrNone;
       
   443     if ( !iEncodeBuffer || iEncodeBuffer->Size() == 0 )
       
   444         {
       
   445         // called out of context or no message data available
       
   446         error = KErrNotFound;
       
   447         }
       
   448     else
       
   449         {
       
   450         aDataPart.Set( iEncodeBuffer->BackPtr( iPosition ) ); 
       
   451         }
       
   452     aLastDataChunk = iLastChunk;
       
   453     
       
   454     return error;
       
   455     }
       
   456     
       
   457 // ---------------------------------------------------------
       
   458 // From class MMmsCodecDataSupplier
       
   459 //
       
   460 // ---------------------------------------------------------
       
   461 //
       
   462 TInt CMmsEncode::ReleaseData()
       
   463     {
       
   464     if ( iOnlyOneChunk )
       
   465         {
       
   466         // if we have only one chunk we always point to the beginning
       
   467         // the buffer gets cleared when all data has been handled
       
   468         return KErrNone;
       
   469         }
       
   470     
       
   471     iPosition = 0;
       
   472     
       
   473     // encode next data part into the buffer
       
   474     
       
   475     if ( iDataSupplierStage == EMmsAttachmentHeaders && iNumberOfAttachments == 0 )
       
   476         {
       
   477         iLastChunk = ETrue;
       
   478         iDataSupplierStage = EMmsHeaders;
       
   479         }
       
   480     else if ( iDataSupplierStage == EMmsAttachmentHeaders )
       
   481         {
       
   482 #ifndef _NO_MMSS_LOGGING_
       
   483         TMmsLogger::Log( _L("- data supplier stage: Attachment headers") );
       
   484 #endif
       
   485         iError = iEntryWrapper->SetCurrentEntry( iCurrentMessageId );
       
   486         if ( iError != KErrNone )
       
   487             {
       
   488             return iError;
       
   489             }
       
   490         
       
   491         iCurrentFileSize = 0;
       
   492         CMsvStore* store = NULL;
       
   493         TRAP( iError, 
       
   494             {
       
   495             store = iEntryWrapper->ReadStoreL();
       
   496             CleanupStack::PushL( store );
       
   497             MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
   498             iCurrentFileSize = EncodeHeadersAndGetFileL( attachMan );
       
   499             CleanupStack::PopAndDestroy( store );
       
   500             });
       
   501         if ( iError != KErrNone )
       
   502             {
       
   503             return iError;
       
   504             }
       
   505             
       
   506         // Now we have the attachment headers in our buffer.
       
   507         // If there is room, put data there, too
       
   508         
       
   509         if ( iBufferSize - iPosition >= iCurrentFileSize )
       
   510             {
       
   511 #ifndef _NO_MMSS_LOGGING_
       
   512             TMmsLogger::Log( _L("- enough room left in buffer for attachment data") );
       
   513 #endif
       
   514             EncodeAttachmentData( iAttachFile, iCurrentFileSize );
       
   515             iPosition += iCurrentFileSize;
       
   516             iAttachFile.Close();
       
   517             iFileOpen = EFalse;
       
   518             iCurrentAttachment++;
       
   519             if ( iCurrentAttachment >= iNumberOfAttachments )
       
   520                 {
       
   521                 iLastChunk = ETrue;
       
   522                 iDataSupplierStage = EMmsHeaders;
       
   523                 }
       
   524             else
       
   525                 {
       
   526                 // one attachment finished - move to next one
       
   527                 iDataSupplierStage = EMmsAttachmentHeaders;
       
   528                 }
       
   529             }
       
   530         else
       
   531             {
       
   532             iDataSupplierStage = EMmsAttachmentData;
       
   533             }
       
   534         }
       
   535     else if ( iDataSupplierStage == EMmsAttachmentData )
       
   536         {
       
   537 #ifndef _NO_MMSS_LOGGING_
       
   538         TMmsLogger::Log( _L("- data supplier stage: Attachment data") );
       
   539 #endif
       
   540         // Add as much attachment data as possible.
       
   541         // Attachment file is now open, check position
       
   542         TInt filePosition = 0;
       
   543         iError = iAttachFile.Seek( ESeekCurrent, filePosition );
       
   544         if ( iError != KErrNone )
       
   545             {
       
   546             return iError;
       
   547             }
       
   548         TInt dataLeft = iCurrentFileSize - filePosition;
       
   549         TInt roomLeft = iBufferSize - iPosition;
       
   550         if ( roomLeft >= dataLeft )
       
   551             {
       
   552             EncodeAttachmentData( iAttachFile, dataLeft );
       
   553             iPosition += dataLeft;
       
   554             iAttachFile.Close();
       
   555             iFileOpen = EFalse;
       
   556             iCurrentAttachment++;
       
   557             if ( iCurrentAttachment >= iNumberOfAttachments )
       
   558                 {
       
   559                 iLastChunk = ETrue;
       
   560                 iDataSupplierStage = EMmsHeaders;
       
   561                 }
       
   562             else
       
   563                 {
       
   564                 // one attachment finished - move to next one
       
   565                 iDataSupplierStage = EMmsAttachmentHeaders;
       
   566                 }
       
   567             }
       
   568         else
       
   569             {
       
   570             // we have more data than fits into buffer
       
   571             EncodeAttachmentData( iAttachFile, roomLeft );
       
   572             iPosition += roomLeft;
       
   573             // We don't close the file because we still have data.
       
   574             // We stay in EMmsAttachmentHeaders state
       
   575             }
       
   576         }
       
   577     else
       
   578         {
       
   579         // do nothing, keep LINT happy
       
   580         }
       
   581 #ifndef _NO_MMSS_LOGGING_
       
   582     if ( iDataSupplierStage == EMmsHeaders )
       
   583         {
       
   584         TMmsLogger::Log( _L("- last chunk released") );
       
   585         TMmsLogger::Log( _L("- data supplier stage: MMS headers") );
       
   586         }
       
   587 #endif
       
   588     // If we have reached the end and have been asked to release data
       
   589     // we have nothing left to do.    
       
   590     
       
   591     // dump what we got into file - if needed
       
   592     if ( iPosition > 0 )
       
   593         {
       
   594         DumpAppend();
       
   595         }
       
   596     return iError;
       
   597     }
       
   598     
       
   599 // ---------------------------------------------------------
       
   600 // From class MMmsCodecDataSupplier
       
   601 //
       
   602 // ---------------------------------------------------------
       
   603 //
       
   604 TInt CMmsEncode::OverallDataSize()
       
   605     {
       
   606     // If we have encoded all data, iOverallDataSize contains the 
       
   607     // actual amount of data.
       
   608     // If we are doing chunked encoding, it contains -1.
       
   609     return iOverallDataSize;
       
   610     }
       
   611 
       
   612     
       
   613 // ---------------------------------------------------------
       
   614 // From class MMmsCodecDataSupplier
       
   615 //
       
   616 // ---------------------------------------------------------
       
   617 //
       
   618 TInt CMmsEncode::ResetSupplier()
       
   619     {
       
   620 #ifndef _NO_MMSS_LOGGING_
       
   621     TMmsLogger::Log( _L("CMmsEncode: ResetSupplier") );
       
   622 #endif
       
   623     if ( iOnlyOneChunk )
       
   624         {
       
   625         // if we have only one chunk we always point to the beginning
       
   626         // the buffer gets cleared when all data has been handled
       
   627         return KErrNone;
       
   628         }
       
   629     
       
   630     // start data from the beginning
       
   631     iError = KErrNone;
       
   632     iDataSupplierStage = EMmsHeaders;
       
   633     TRAP( iError, EncodeHeadersChunkedL() );
       
   634     
       
   635     return iError;
       
   636     }
       
   637 
       
   638 // ---------------------------------------------------------
       
   639 // From class CMsgActive
       
   640 //
       
   641 // ---------------------------------------------------------
       
   642 //
       
   643 void CMmsEncode::DoRunL()
       
   644     {
       
   645 
       
   646     // This routine takes the state machine through the states
       
   647     // until an error is encountered or the cycle completes.
       
   648 
       
   649     if ( iError != KErrNone )
       
   650         {
       
   651         // We encountered an error, and cannot continue
       
   652         // For the time being we just give up without trying
       
   653         // to do any decent cleanup.
       
   654         iStatus = iError;
       
   655         // If we return from DoRunL without becoming active again,
       
   656         // RunL completes.
       
   657         return;
       
   658         }
       
   659 
       
   660     if ( iState != EMmsFinished )
       
   661         {
       
   662         SelectNextState();
       
   663         // If appropriate, ChangeStateL makes us active again
       
   664         ChangeStateL();
       
   665         }
       
   666     else
       
   667         {
       
   668         // We are done, we must become idle again
       
   669         FinishL();
       
   670         iStatus = iError;
       
   671         // If we return from DoRunL without becoming active again,
       
   672         // RunL completes.
       
   673         }
       
   674     // As we are using standard Mentact RunL, we must leave
       
   675     // if we have encountered an error, and do not want to continue
       
   676 
       
   677     if ( iError != KErrNone && !IsActive() )
       
   678         {
       
   679         iPosition = 0;
       
   680         FinishL();
       
   681         User::Leave( iError );
       
   682         }
       
   683     }
       
   684 
       
   685 // ---------------------------------------------------------
       
   686 // From class CMsgActive
       
   687 //
       
   688 // ---------------------------------------------------------
       
   689 //
       
   690 void CMmsEncode::DoComplete( TInt& /* aStatus */ )
       
   691     {
       
   692     // We are exiting the loop - we say we are idle now
       
   693     iState = EMmsIdle;
       
   694     }
       
   695 
       
   696 // ---------------------------------------------------------
       
   697 //
       
   698 // ---------------------------------------------------------
       
   699 //
       
   700 void CMmsEncode::SelectNextState()
       
   701     {
       
   702 
       
   703     // If appropriate, the functions called within the switch statement
       
   704     // will make us active again. If all is done, the asynchronous request
       
   705     // will complete
       
   706 
       
   707     switch ( iState )
       
   708         {
       
   709         case EMmsIdle:
       
   710             // start the loop
       
   711             iState = EMmsEncodingHeaders;
       
   712             break;
       
   713         case EMmsEncodingHeaders:
       
   714             if ( iNumberOfAttachments > 0 )
       
   715                 {
       
   716                 iState = EMmsEncodingAttachments;
       
   717                 }
       
   718             else
       
   719                 {
       
   720                 iState = EMmsFinished;
       
   721                 }
       
   722             break;
       
   723         case EMmsEncodingAttachments:
       
   724             // if there are more attachments, don't change state
       
   725             if ( iCurrentAttachment >= iNumberOfAttachments )
       
   726                 {
       
   727                 iState = EMmsFinished;
       
   728                 }
       
   729             break;
       
   730         case EMmsFinished:
       
   731             // No more states
       
   732             iState = EMmsIdle;
       
   733             break;
       
   734         default:
       
   735             // Illegal state
       
   736             break;
       
   737         }
       
   738     }
       
   739 
       
   740 // ---------------------------------------------------------
       
   741 //
       
   742 // ---------------------------------------------------------
       
   743 //
       
   744 void CMmsEncode::ChangeStateL()
       
   745     {
       
   746     switch ( iState )
       
   747         {
       
   748         case EMmsEncodingHeaders:
       
   749             EncodeHeadersL();
       
   750             break;
       
   751         case EMmsEncodingAttachments:
       
   752             EncodeAttachmentL();
       
   753             iCurrentAttachment++;
       
   754             break;
       
   755         case EMmsFinished:
       
   756             FinishL();
       
   757             break;
       
   758         default:
       
   759             // Should not be here anymore
       
   760             break;
       
   761         }
       
   762     }
       
   763 
       
   764 // ---------------------------------------------------------
       
   765 //
       
   766 // ---------------------------------------------------------
       
   767 //
       
   768 void CMmsEncode::Reset()
       
   769     {
       
   770     // close open file in case operation has ended with error
       
   771     // and the attachment file is still open
       
   772     if ( iFileOpen )
       
   773         {
       
   774         iAttachFile.Close();
       
   775         iFileOpen = EFalse;
       
   776         }
       
   777 
       
   778     iNumberOfAttachments = 0;
       
   779     iCurrentAttachment = 0;
       
   780     iError = KErrNone;
       
   781     iCurrentMessageId = KMsvNullIndexEntryId;
       
   782     iOverallDataSize = -1;
       
   783     iLastChunk = ETrue;
       
   784     iOnlyOneChunk = ETrue;
       
   785     }
       
   786 
       
   787 // ---------------------------------------------------------
       
   788 //
       
   789 // ---------------------------------------------------------
       
   790 //
       
   791 void CMmsEncode::EncodeHeadersL()
       
   792     {
       
   793 
       
   794     // start from the beginning
       
   795     iPosition = 0;
       
   796     // we discard old contents of the buffer in case we must expand it
       
   797     iEncodeBuffer->Reset();
       
   798     
       
   799     // calculate space needed and resize buffer
       
   800     TInt size = 0;
       
   801     size += iMmsHeaders->Size();
       
   802     
       
   803     User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
       
   804     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
   805     CleanupStack::PushL( store );
       
   806     // AttachmentsSize function asks actual size from files
       
   807     // in case the info in CMsvAttachment is not up to date.
       
   808     // This function leaves if the attachment file is not found.
       
   809     // A message cannot be sent if it refers to attachment files that no
       
   810     // longer exist.
       
   811     size += iEntryWrapper->AttachmentsSizeL( *store );
       
   812     CleanupStack::PopAndDestroy( store );
       
   813     store = NULL;
       
   814         
       
   815     size += KMMSBufferExtra; // this is just an estimate of header size...
       
   816     // extra needed if lots of attachments.
       
   817     size += KMMSAttachmentExtra * iNumberOfAttachments;
       
   818     TMemoryInfoV1Buf memory;
       
   819     UserHal::MemoryInfo( memory );
       
   820     TInt available = memory().iFreeRamInBytes;
       
   821     // check that buffer fits, leave a little memory for others too.
       
   822     if ( size > ( available - KMmsExtra ) )
       
   823         {
       
   824         // message is too big - don't even try
       
   825         iError = KMmsErrorMessageTooBig;
       
   826         }
       
   827 
       
   828     if ( iError == KErrNone )
       
   829         {
       
   830         iEncodeBuffer->ResizeL( size );
       
   831         EncodeRequestHeadersL();
       
   832         }
       
   833 
       
   834     iStatus = KRequestPending;
       
   835     SetActive();
       
   836   
       
   837     // We complete ourselves.
       
   838     TRequestStatus* status = &iStatus;
       
   839     User::RequestComplete( status, iError );
       
   840 
       
   841     }
       
   842 
       
   843 // ---------------------------------------------------------
       
   844 //
       
   845 // ---------------------------------------------------------
       
   846 //
       
   847 void CMmsEncode::EncodeHeadersChunkedL()
       
   848     {
       
   849     // The first step of chunked encoding
       
   850 #ifndef _NO_MMSS_LOGGING_
       
   851     TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: start") );
       
   852 #endif /* _NO_MMSS_LOGGING_ */
       
   853     User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
       
   854     
       
   855     /* Korean req: 415-5434
       
   856      * Get the target encoding MIB enum from cenrep and encode MMS text objects using corresponding conversion plugins
       
   857      */
       
   858     TInt temp;
       
   859     iTargetEncodingType = 0;
       
   860     CRepository* repository = CRepository::NewLC( KUidMmsServerMtm );    
       
   861     if ( repository->Get( KMmsEncodingType, temp ) == KErrNone )
       
   862         {
       
   863         iTargetEncodingType = temp;
       
   864         }
       
   865     CleanupStack::PopAndDestroy( repository );
       
   866 #ifndef _NO_MMSS_LOGGING_
       
   867     TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: target encoding type: %d"), iTargetEncodingType );
       
   868 #endif /* _NO_MMSS_LOGGING_ */
       
   869 
       
   870     if( iTargetEncodingType != 0 )
       
   871         {
       
   872         TRAPD( err, PreProcessAttachmentDataL() );
       
   873 
       
   874 #ifndef _NO_MMSS_LOGGING_
       
   875     /* if any error, korean specific encoding failed, But this should not stop from sending MMS using
       
   876      * existing default encoding. Hence just log the error and continue in any case
       
   877      */
       
   878         if( err != KErrNone )
       
   879             {
       
   880             TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: PreProcessAttachmentDataL error: %d"), err );
       
   881             }
       
   882 #endif /* _NO_MMSS_LOGGING_ */
       
   883         }
       
   884     
       
   885     //Open store for read-only purpose
       
   886     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
   887     CleanupStack::PushL( store );
       
   888     
       
   889     // Only new attachment structure is supported    
       
   890     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
   891     iNumberOfAttachments = attachMan.AttachmentCount();
       
   892     
       
   893     TInt size = 0;
       
   894     size += iMmsHeaders->Size();
       
   895     size += KMMSBufferExtra; // this is just an estimate of header size...
       
   896     // The buffer must be at least big enough to hold all headers
       
   897     iBufferSize = Max( KMmsChunkedBufferSize, size );
       
   898     
       
   899     // extra needed if lots of attachments.
       
   900     // AttachmentsSize function asks actual size from files
       
   901     // in case the info in CMsvAttachment is not up to date.
       
   902     // This function leaves if the attachment file is not found.
       
   903     // A message cannot be sent if it refers to attachment files that no
       
   904     // longer exist.
       
   905     size += iEntryWrapper->AttachmentsSizeL( *store );
       
   906     size += KMMSAttachmentExtra * iNumberOfAttachments;
       
   907     CleanupStack::PopAndDestroy( store );
       
   908     store = NULL;
       
   909 
       
   910     if ( iBufferSize > size )
       
   911         {
       
   912         // Our message is small enough to be sent in one chunk.
       
   913         // It does not make sense to send the message in small chunks
       
   914         // it the total is only a few kilobytes
       
   915         iBufferSize = size;
       
   916         iOnlyOneChunk = ETrue;
       
   917         iLastChunk = ETrue;
       
   918         }
       
   919     else
       
   920         {
       
   921         // we need several chunks
       
   922         iOnlyOneChunk = EFalse;
       
   923         iLastChunk = EFalse;
       
   924         }
       
   925         
       
   926     // start from the beginning
       
   927     iPosition = 0;
       
   928     iEncodeBuffer->Reset();
       
   929     // This leaves if unable to resize.
       
   930     // We try to keep our buffer small enough so that this does not leave.
       
   931     iEncodeBuffer->ResizeL( iBufferSize );
       
   932 #ifndef _NO_MMSS_LOGGING_
       
   933         TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: MMS buff Size(Approx): %d"), iBufferSize );
       
   934 #endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
       
   935 
       
   936     EncodeRequestHeadersL();
       
   937     
       
   938     TInt i = 0;
       
   939     if ( iOnlyOneChunk )
       
   940         {
       
   941 #ifndef _NO_MMSS_LOGGING_
       
   942         TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: only one chunk") );
       
   943 #endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
       
   944         for ( i = 0; ( i < iNumberOfAttachments ) && ( iError == KErrNone ); ++i )
       
   945             {
       
   946             iCurrentAttachment = i;
       
   947             // encode attachments, too, as we have decided that our message
       
   948             // is small enough to fit into the buffer as one chunk
       
   949             // DoEncodeAttachment always encodes iCurrentAttachment
       
   950             // and updates buffer position as needed.
       
   951             DoEncodeAttachmentL();
       
   952             // If something goes wrong, DoEncodeAttachmentL() sets iError,
       
   953             // and StartChunkedL will complete the caller with error.
       
   954             }
       
   955         iEncodeBuffer->ResizeL( iPosition );
       
   956         iOverallDataSize = iEncodeBuffer->Size();
       
   957         }
       
   958     else
       
   959         {
       
   960 #ifndef _NO_MMSS_LOGGING_
       
   961         TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: Multiple chunks") );
       
   962 #endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
       
   963         // chunked sending - but it should be possible to calculate data size
       
   964         iOverallDataSize = iPosition; // This is the amount taken by headers
       
   965         // The message is small enough to be sent as one chunk
       
   966         for ( i = 0; ( i < iNumberOfAttachments ) && ( iError == KErrNone ); ++i )
       
   967             {
       
   968             iCurrentAttachment = i;
       
   969             // encode attachments, too, as we have decided that our message
       
   970             // is small enough to fit into the buffer as one chunk
       
   971             // DoEncodeAttachment always encodes iCurrentAttachment
       
   972             // and updates buffer position as needed.
       
   973             iOverallDataSize += DoGetAttachmentEncodingLengthL();
       
   974             // If something goes wrong, DoEncodeAttachmentL() sets iError,
       
   975             // and StartChunkedL will complete the caller with error.
       
   976             }
       
   977         iCurrentAttachment = 0;
       
   978         iDataSupplierStage = EMmsAttachmentHeaders;
       
   979         if ( iError != KErrNone )
       
   980             {
       
   981             iOverallDataSize = -1;
       
   982             }
       
   983         }
       
   984      
       
   985     // Dump headers. More data will follow    
       
   986     Dump();
       
   987 #ifndef _NO_MMSS_LOGGING_
       
   988     TMmsLogger::Log( _L("CMmsEncode::EncodeHeadersChunkedL:: end") );
       
   989 #endif /* _NO_MMSS_LOGGING_ */        // The message is small enough to be sent as one chunk
       
   990     }
       
   991 
       
   992 // ---------------------------------------------------------
       
   993 //
       
   994 // ---------------------------------------------------------
       
   995 //
       
   996 void CMmsEncode::EncodeAttachmentL()
       
   997     {
       
   998 
       
   999     DoEncodeAttachmentL();
       
  1000     
       
  1001     if ( iError != KErrNone )
       
  1002         {
       
  1003         // If we return without becoming active again, RunL completes
       
  1004         // we cannot send this message, because we cannot access attachments
       
  1005         return;
       
  1006         }
       
  1007 
       
  1008     iStatus = KRequestPending;
       
  1009     SetActive();
       
  1010   
       
  1011     // Now we indicate we already did it.
       
  1012     TRequestStatus* status = &iStatus;
       
  1013     User::RequestComplete( status, iError );
       
  1014 
       
  1015     }
       
  1016     
       
  1017 // ---------------------------------------------------------
       
  1018 //
       
  1019 // ---------------------------------------------------------
       
  1020 //
       
  1021 void CMmsEncode::DoEncodeAttachmentL()
       
  1022     {
       
  1023     
       
  1024     // Encode one part
       
  1025     // We must calculate length of headers and content type
       
  1026     
       
  1027     User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
       
  1028         
       
  1029     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  1030     CleanupStack::PushL( store );
       
  1031     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  1032     
       
  1033     TInt size = 0;
       
  1034     size = EncodeHeadersAndGetFileL( attachMan );
       
  1035     if ( iError != KErrNone )
       
  1036         {
       
  1037         CleanupStack::PopAndDestroy( store );
       
  1038         return;
       
  1039         }
       
  1040     
       
  1041     // The data read function will not leave
       
  1042     EncodeAttachmentData( iAttachFile, size );
       
  1043     iPosition += size;
       
  1044     iAttachFile.Close();
       
  1045 
       
  1046     CleanupStack::PopAndDestroy( store );
       
  1047 
       
  1048     }
       
  1049     
       
  1050 // ---------------------------------------------------------
       
  1051 //
       
  1052 // ---------------------------------------------------------
       
  1053 //
       
  1054 TInt CMmsEncode::DoGetAttachmentEncodingLengthL()
       
  1055     {
       
  1056     
       
  1057     // calculate length of headers and content type
       
  1058     
       
  1059     User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
       
  1060         
       
  1061     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  1062     CleanupStack::PushL( store );
       
  1063     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  1064     
       
  1065     TInt size = 0;
       
  1066     size = GetHeadersAndFileSizeL( attachMan );
       
  1067     CleanupStack::PopAndDestroy( store );
       
  1068     return size;
       
  1069 
       
  1070     }
       
  1071     
       
  1072 // ---------------------------------------------------------
       
  1073 //
       
  1074 // ---------------------------------------------------------
       
  1075 //
       
  1076 TInt CMmsEncode::EncodeHeadersAndGetFileL( MMsvAttachmentManager& aAttachMan )
       
  1077     {
       
  1078     
       
  1079     CMsvAttachment* attachmentInfo = NULL;
       
  1080     attachmentInfo = aAttachMan.GetAttachmentInfoL( iCurrentAttachment );
       
  1081     CleanupStack::PushL( attachmentInfo );
       
  1082     
       
  1083     iMimeHeaders->RestoreL( *attachmentInfo );
       
  1084         
       
  1085     // We don't trust the info, we ask the file itself
       
  1086     // Someone outside the messaging system may have changed the file
       
  1087     // without changing the attachment info
       
  1088     TInt size = 0;
       
  1089     if ( iFileOpen )
       
  1090         {
       
  1091         // close file in case we have been reset while the file is still open
       
  1092         iAttachFile.Close();
       
  1093         iFileOpen = EFalse;
       
  1094         }
       
  1095     iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment );
       
  1096     iError = iAttachFile.Size( size );
       
  1097     iAttachFile.Close();
       
  1098 
       
  1099     if ( iError != KErrNone )
       
  1100         {
       
  1101         CleanupStack::PopAndDestroy( attachmentInfo );
       
  1102         return size;
       
  1103         }
       
  1104 
       
  1105     // calculate the length of the headers
       
  1106     TBool foundName = EFalse;
       
  1107     TUint contentTypeSize = 0;
       
  1108     TInt8 contentType = -1; // indicate not found
       
  1109     TPtrC8 contentTypeString;
       
  1110 
       
  1111     TUint headerSize = 0;
       
  1112     
       
  1113     HBufC8* buf8 = CalculateAttachmentHeaderLengthL(
       
  1114         *attachmentInfo,
       
  1115         headerSize,    
       
  1116         foundName,
       
  1117         contentTypeSize,
       
  1118         contentType,
       
  1119         contentTypeString );
       
  1120      
       
  1121     CleanupStack::PushL( buf8 );
       
  1122         
       
  1123     // We have calculated the header length, now we can encode:
       
  1124 
       
  1125     TPtrC8 nameString;
       
  1126     if ( !foundName && buf8 )
       
  1127         {
       
  1128         nameString.Set( buf8->Des() );
       
  1129         }
       
  1130         
       
  1131     EncodeAttachmentHeadersL(
       
  1132         size,
       
  1133         headerSize,
       
  1134         foundName,
       
  1135         contentTypeSize,
       
  1136         contentType,
       
  1137         contentTypeString,
       
  1138         nameString );
       
  1139 
       
  1140     // now we have put the name all over, we can destroy the buffer
       
  1141     CleanupStack::PopAndDestroy( buf8 );
       
  1142     buf8 = NULL;
       
  1143     CleanupStack::PopAndDestroy( attachmentInfo );
       
  1144     attachmentInfo = NULL;
       
  1145     
       
  1146     // Now just write all the data octets
       
  1147     iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment );
       
  1148     iFileOpen = ETrue;
       
  1149     
       
  1150     return size;
       
  1151     }
       
  1152 
       
  1153 // ---------------------------------------------------------
       
  1154 //
       
  1155 // ---------------------------------------------------------
       
  1156 //
       
  1157 TInt CMmsEncode::GetHeadersAndFileSizeL( MMsvAttachmentManager& aAttachMan )
       
  1158     {
       
  1159     
       
  1160     CMsvAttachment* attachmentInfo = NULL;
       
  1161     attachmentInfo = aAttachMan.GetAttachmentInfoL( iCurrentAttachment );
       
  1162     CleanupStack::PushL( attachmentInfo );
       
  1163     
       
  1164     iMimeHeaders->RestoreL( *attachmentInfo );
       
  1165         
       
  1166     // We don't trust the info, we ask the file itself
       
  1167     // Someone outside the messaging system may have changed the file
       
  1168     // without changing the attachment info
       
  1169     TInt size = 0;
       
  1170     if ( iFileOpen )
       
  1171         {
       
  1172         // close file in case we have been reset while the file is still open
       
  1173         iAttachFile.Close();
       
  1174         iFileOpen = EFalse;
       
  1175         }
       
  1176     iAttachFile = aAttachMan.GetAttachmentFileL( iCurrentAttachment );
       
  1177     iError = iAttachFile.Size( size );
       
  1178     iAttachFile.Close();
       
  1179 
       
  1180     if ( iError != KErrNone )
       
  1181         {
       
  1182         CleanupStack::PopAndDestroy( attachmentInfo );
       
  1183         return 0;
       
  1184         }
       
  1185 
       
  1186     // calculate the length of the headers
       
  1187     TBool foundName = EFalse;
       
  1188     TUint contentTypeSize = 0;
       
  1189     TInt8 contentType = -1; // indicate not found
       
  1190     TPtrC8 contentTypeString;
       
  1191 
       
  1192     TUint headerSize = 0;
       
  1193     
       
  1194     HBufC8* buf8 = CalculateAttachmentHeaderLengthL(
       
  1195         *attachmentInfo,
       
  1196         headerSize,    
       
  1197         foundName,
       
  1198         contentTypeSize,
       
  1199         contentType,
       
  1200         contentTypeString );
       
  1201         
       
  1202     delete buf8; // This is not needed
       
  1203     buf8 = NULL;     
       
  1204      
       
  1205     CleanupStack::PopAndDestroy( attachmentInfo );
       
  1206     attachmentInfo = NULL;
       
  1207     
       
  1208     // We have calculated the header length, now we still need the
       
  1209     // uintvar lengths:
       
  1210     
       
  1211     size += GetUintvarLength( size ); // encoding size for attachment length
       
  1212     size += headerSize;
       
  1213     size += GetUintvarLength( headerSize ); // encoding size for header length
       
  1214  
       
  1215     return size;
       
  1216     }
       
  1217 
       
  1218 // ---------------------------------------------------------
       
  1219 //
       
  1220 // ---------------------------------------------------------
       
  1221 //
       
  1222 HBufC8* CMmsEncode::CalculateAttachmentHeaderLengthL(
       
  1223     CMsvAttachment& aAttachmentInfo,
       
  1224     TUint& aHeaderLength,
       
  1225     TBool& aFoundName,
       
  1226     TUint& aContentTypeSize,
       
  1227     TInt8& aContentType,
       
  1228     TPtrC8& aContentTypeString  )
       
  1229     {
       
  1230     
       
  1231     TInt numNonSafe = 0; // number of characters in filename that would require encoding
       
  1232     // Not all content types have parameters.
       
  1233     // The only parameter we can handle to some extent
       
  1234     // is the character set parameter for text content types.
       
  1235     // The name parameter will always be added if not already present
       
  1236     
       
  1237     // Check if we have well-known media.
       
  1238     aContentType = -1; // indicate not found
       
  1239     aContentTypeString.Set( aAttachmentInfo.MimeType() );
       
  1240     if ( aContentTypeString.Length() == 0 )
       
  1241         {
       
  1242         // take type from mime headers
       
  1243         HBufC8* tempContentType = HBufC8::NewL(
       
  1244             iMimeHeaders->ContentType().Length() +
       
  1245             iMimeHeaders->ContentSubType().Length() + 1 );
       
  1246         CleanupStack::PushL( tempContentType );
       
  1247         tempContentType->Des().Copy( iMimeHeaders->ContentType() );
       
  1248         if ( ( iMimeHeaders->ContentType().Find( KMmsSlash8 ) !=
       
  1249             ( iMimeHeaders->ContentType().Length() - 1 ) ) &&
       
  1250             ( iMimeHeaders->ContentSubType().Find( KMmsSlash8 ) != 0 ) &&
       
  1251             ( iMimeHeaders->ContentSubType().Length() != 0 ) )
       
  1252             {
       
  1253             tempContentType->Des().Append( KMmsSlash8 );
       
  1254             }
       
  1255         tempContentType->Des().Append( iMimeHeaders->ContentSubType() );
       
  1256         aAttachmentInfo.SetMimeTypeL( tempContentType->Des() );
       
  1257         CleanupStack::PopAndDestroy( tempContentType );
       
  1258         aContentTypeString.Set( aAttachmentInfo.MimeType() );
       
  1259         }
       
  1260         
       
  1261     TInt8 i;
       
  1262     for ( i = 0; i < KNumberContentTypes && aContentType < 0; ++i )
       
  1263         {
       
  1264         if ( aContentTypeString.CompareF(
       
  1265             TPtrC8( KContentTypeTable[i] ) ) == 0 )
       
  1266             {
       
  1267             aContentType = i;
       
  1268             }
       
  1269         }
       
  1270     if ( aContentTypeString.Length() == 0 )
       
  1271         {
       
  1272         aContentTypeString.Set( KMmsUnknownType );
       
  1273         aContentType = -1;
       
  1274         }
       
  1275         
       
  1276     // we always add the name parameter to content type, so we always
       
  1277     // use the general form. If no name is given, we use the original filename
       
  1278     // If the name parameter is defined, we use it.
       
  1279 
       
  1280     aFoundName = EFalse;
       
  1281     iFileName.SetLength( 0 );
       
  1282 
       
  1283     aHeaderLength = 0;
       
  1284     // add media type length
       
  1285     if ( aContentType >= 0 )
       
  1286         {
       
  1287         // well-known media
       
  1288         aHeaderLength += 1;
       
  1289         }
       
  1290     else
       
  1291         {
       
  1292         // Extension media
       
  1293         aHeaderLength += aContentTypeString.Length();
       
  1294         aHeaderLength += 1; // terminating zero
       
  1295         }
       
  1296 
       
  1297     // If we have parameters, we must calculate their length.
       
  1298     if ( iMimeHeaders->MimeCharset() != 0 )
       
  1299         {
       
  1300         // charset has well-known encoding
       
  1301         aHeaderLength += 1;
       
  1302         if ( iMimeHeaders->MimeCharset() <= KMmsShortIntegerLimit127 )
       
  1303             {
       
  1304             // short integer
       
  1305             aHeaderLength += 1;
       
  1306             }
       
  1307         else if ( iMimeHeaders->MimeCharset() < KMmsOneByteLimit )
       
  1308             {
       
  1309             // long integer, short length + 1 byte of value
       
  1310             aHeaderLength += KMms2;
       
  1311             }
       
  1312         else if ( iMimeHeaders->MimeCharset() < KMmsTwoByteLimit )
       
  1313             {
       
  1314             // long integer, short length + 2 bytes of value
       
  1315             // so far I don't know any IANA numbers that would
       
  1316             // take more than two hex bytes.
       
  1317             aHeaderLength += KMms3;
       
  1318             }
       
  1319         else if ( iMimeHeaders->MimeCharset() < KMmsThreeByteLimit )
       
  1320             {
       
  1321             // long integer, short length + 3 bytes of value
       
  1322             aHeaderLength += KMms4;
       
  1323             }
       
  1324         else
       
  1325             {
       
  1326             // long integer, short length + 4 bytes of value
       
  1327             // cannot be longer than this in any case
       
  1328             aHeaderLength += KMms5;
       
  1329             }
       
  1330         }
       
  1331     // Then the rest of the parameters, unknown,
       
  1332     // sent as text strings
       
  1333     // If "name" attribute has been defined, we use it.
       
  1334     // if it is not added, we must add it.
       
  1335     // We must ensure that we don't add it twice...
       
  1336     
       
  1337     TInt mimeHeaderCount = iMimeHeaders->ContentTypeParams().MdcaCount();
       
  1338 
       
  1339     for ( i = 0; i < mimeHeaderCount; i++ )
       
  1340         {
       
  1341         // If we have corrupted parameters (length of name is zero)
       
  1342         // we skip the name/value pair.
       
  1343         // value may be zero, it will be encoded as just the terminating zero
       
  1344         if ( i%2 == 0 &&
       
  1345             iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() == 0 )
       
  1346             {
       
  1347             i++;
       
  1348             }
       
  1349         else
       
  1350             {
       
  1351             // 8-byte string size + terminating zero
       
  1352             // If parameter has no value, it still must have
       
  1353             // the "no-value" indicator (just the terminating zero.)
       
  1354             if ( iMimeHeaders->ContentTypeParams().MdcaPoint( i ).CompareF(
       
  1355                 KWspNameString ) == 0 && i%2 == 0 )
       
  1356                 {
       
  1357                 if ( ( i + 1 ) < mimeHeaderCount && 
       
  1358                     IsStringSafe( iMimeHeaders->ContentTypeParams().MdcaPoint( i + 1 ),
       
  1359                     numNonSafe ) )
       
  1360                     {
       
  1361                     // We always move the name to the first item.
       
  1362                     // It may be this parameter or something else
       
  1363                     
       
  1364                     // Content type parameters are 8-bit strings.
       
  1365                     // We can use the name only if it is safe, otherwise it may contain some
       
  1366                     // unknown encoding (maybe utf-8).
       
  1367                     iFileName.Copy( ( iMimeHeaders->ContentTypeParams().
       
  1368                        MdcaPoint( i + 1 ) ).Right( KMmsMaxFileName ) );
       
  1369                     i++;
       
  1370                     }
       
  1371                 else
       
  1372                     {
       
  1373                     // Skip the next field as it can only be used if it is safe
       
  1374                     i++;
       
  1375                     }
       
  1376                 }
       
  1377             else
       
  1378                 {
       
  1379                 aHeaderLength += iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() + 1;
       
  1380                 }
       
  1381             }
       
  1382         }
       
  1383     if ( ( iMimeHeaders->ContentTypeParams().MdcaCount() % 2 ) == 1 )
       
  1384         {
       
  1385         // Odd number. Obviously last parameter has no value.
       
  1386         // Add the "no value" token
       
  1387         aHeaderLength++;
       
  1388         }
       
  1389 
       
  1390     // include name parameter to content-type
       
  1391 
       
  1392     // if the name was not among our mime headers,
       
  1393     // we must add it.
       
  1394     TInt nameLength = 0;
       
  1395 
       
  1396     // We prefer the suggested filename as the content type name parameter.
       
  1397     // If version is 1.3 or later, we can encode a non-safe filename.
       
  1398     // If suggested filename is not safe, but we already have a safe filename
       
  1399     // in iFilename, we don't override it if version is 1.2 or lower
       
  1400     if ( iMimeHeaders->SuggestedFilename().Length() > 0 )
       
  1401         {
       
  1402         if ( iMmsHeaders->MmsVersion() > KMmsVersion12 ||
       
  1403              IsStringSafe( iMimeHeaders->SuggestedFilename() ) ||
       
  1404              iFileName.Length() == 0 )
       
  1405             {
       
  1406             iFileName.Copy( iMimeHeaders->SuggestedFilename().Right( KMmsMaxFileName ) );
       
  1407             }
       
  1408         }
       
  1409         
       
  1410     TParse* parse = NULL;
       
  1411     // If we don't have a filename suggestion so far, we just use the
       
  1412     // actual filename the attachment manager has used to save the file.    
       
  1413     if ( iFileName.Length() == 0 )
       
  1414         {
       
  1415         parse = new( ELeave )TParse;
       
  1416         CleanupStack::PushL( parse );
       
  1417         // aAttachmentInfo.FilePath() is an actual Symbian filename including path
       
  1418         // so it never can be too long to fit into TParse or TFilename 
       
  1419         parse->Set( aAttachmentInfo.FilePath(), NULL, NULL );
       
  1420         iFileName.Copy( parse->NameAndExt() );
       
  1421         CleanupStack::PopAndDestroy( parse );
       
  1422         parse = NULL;
       
  1423         }
       
  1424 
       
  1425     // Last effort:
       
  1426     // If our version is 1.2 or lower and the filename suggestion so far
       
  1427     // is not safe, we try content-location. It is always safe
       
  1428         
       
  1429     if ( iMmsHeaders->MmsVersion() <= KMmsVersion12 &&
       
  1430         !IsStringSafe( iFileName ) )
       
  1431         {
       
  1432         if ( iMimeHeaders->ContentLocation().Length() > 0 )
       
  1433             {
       
  1434             // content location should be safe.
       
  1435             // However, we must make sure it contains no URI escapes.
       
  1436             // for example space is legal in filename, but not in URI.
       
  1437             HBufC16* decoded = NULL;
       
  1438             TRAPD( error, ( decoded = EscapeUtils::EscapeDecodeL(
       
  1439                 iMimeHeaders->ContentLocation() ) ) );
       
  1440             if ( error == KErrNone )
       
  1441                 {
       
  1442                 iFileName.Copy( decoded->Des().Right( KMmsMaxFileName ) );
       
  1443                 delete decoded;
       
  1444                 decoded = NULL;
       
  1445                 }
       
  1446             else
       
  1447                 {
       
  1448                 iFileName.Copy( iMimeHeaders->ContentLocation().Right( KMmsMaxFileName ) );
       
  1449                 }
       
  1450             }
       
  1451         }
       
  1452         
       
  1453     // remove leading and trailing spaces just in case...    
       
  1454     iFileName.Trim();    
       
  1455         
       
  1456     // We should now make sure that the filename is not too long.
       
  1457     // According to MMS conformance specs, the maximum should be 40 characters
       
  1458     // It is unclear if the characters mean the total length or the length
       
  1459     // after conversion to utf-8, but as a first approximation we try
       
  1460     // to ensure that the total does not exceed 40 characters
       
  1461     
       
  1462     nameLength = iFileName.Length();
       
  1463     
       
  1464     if ( nameLength > KMmsMaxFileNameLength )
       
  1465         {
       
  1466         parse = new( ELeave )TParse;
       
  1467         CleanupStack::PushL( parse );
       
  1468         parse->Set( aAttachmentInfo.FilePath(), NULL, NULL );
       
  1469         iFileName.Copy( parse->Name().Left( KMmsMaxFileNameLength - parse->Ext().Length() ) );
       
  1470         iFileName.Append( parse->Ext() );
       
  1471         CleanupStack::PopAndDestroy( parse );
       
  1472         parse = NULL;
       
  1473         nameLength = iFileName.Length();
       
  1474         }
       
  1475 
       
  1476     // If encoding version is <=1.2, make filename safe,
       
  1477     // otherwise use MIME encoding (either base64 or quoted printable)
       
  1478     
       
  1479     HBufC8* buf8 = NULL;
       
  1480 
       
  1481     TPtrC16 originalName;
       
  1482     TBuf16<1> oneCharacter;
       
  1483     originalName.Set( iFileName );
       
  1484 
       
  1485     TInt j;
       
  1486     
       
  1487     if ( IsStringSafe( iFileName ) )
       
  1488         {
       
  1489         // filename only contains us-ascii characters - use as is 
       
  1490         buf8 = HBufC8::NewL( nameLength );
       
  1491         CleanupStack::PushL( buf8 );
       
  1492         buf8->Des().Copy( iFileName );      
       
  1493         }
       
  1494     else
       
  1495         {
       
  1496         if ( iMmsHeaders->MmsVersion() <= KMmsVersion12 )
       
  1497             {
       
  1498             // if version is <= 1.2, the filename must be us-ascii
       
  1499             // replace all illegal characters by underscore
       
  1500             buf8 = HBufC8::NewL( nameLength );
       
  1501             CleanupStack::PushL( buf8 );
       
  1502             for ( j = 0; j < nameLength; ++j )
       
  1503                 {
       
  1504                 oneCharacter.Copy( originalName.Mid( j, 1 ) );
       
  1505                 if ( !IsStringSafe( oneCharacter ) )
       
  1506                     {
       
  1507                     _LIT( KMmsUnderscore, "_" );
       
  1508                     oneCharacter.Copy( KMmsUnderscore );
       
  1509                     }
       
  1510                 buf8->Des().Append( oneCharacter );
       
  1511                 }
       
  1512             }
       
  1513         else
       
  1514             {
       
  1515             // MMS encapsulation version is 1.3 or later
       
  1516             // Using non-ascii characters in filename parameter is allowed
       
  1517             // The filename must be encoded either using base64 or quoted printable
       
  1518             HBufC8* temp = NULL;
       
  1519             temp = CnvUtfConverter::ConvertFromUnicodeToUtf8L( originalName );
       
  1520             CleanupStack::PushL( temp );
       
  1521             // Now we have the filename in utf-8.
       
  1522             // We must check if it contains non-ascii, and if it does,
       
  1523             // we must use base64 or quoted-printable encoding.
       
  1524             TInt numNonSafe;
       
  1525             // Actually we know already that we are not safe. We just need
       
  1526             // to get the number of non-ascii characters
       
  1527             IsStringSafe( temp->Des(), numNonSafe );
       
  1528             // We prefer quoted printable as it looks nicer in case we have mostly ascii,
       
  1529             // and it leaves extension in cleartext anyway
       
  1530             if ( ( temp->Des().Length() + ( KMms2 * numNonSafe ) ) <= KMaxEncodingLength )
       
  1531                 {
       
  1532                 // use quoted printable, but first convert spaces to underscores
       
  1533                 TInt spacePosition = temp->Des().Find( KSpace8 );
       
  1534                 while ( spacePosition != KErrNotFound )
       
  1535                     {
       
  1536                     temp->Des()[ spacePosition ] = KMmsIntUnderscore;
       
  1537                     spacePosition = temp->Des().Find( KSpace8 );
       
  1538                     }
       
  1539                 buf8 = EncodeQuotedPrintableWordL( temp->Des() );
       
  1540                 }
       
  1541             else
       
  1542                 {
       
  1543                 // use base64
       
  1544                 // We have not restricted the filename length in utf-8 format,
       
  1545                 // so it may be way longer than 40 bytes.
       
  1546                 // However, we can calculate the length the buffer needs, so we
       
  1547                 // can try. However, we may end up with some soft line break in 
       
  1548                 // the middle of the parameter which may not be acceptable.
       
  1549                 buf8 = EncodeBase64WordL( temp->Des() );
       
  1550                 }
       
  1551             
       
  1552             CleanupStack::PopAndDestroy( temp );
       
  1553             
       
  1554             CleanupStack::PushL( buf8 );
       
  1555             // we must change nameLength here
       
  1556             }
       
  1557         }
       
  1558 
       
  1559     // The name is now in buf8, either just copied or encoded
       
  1560     nameLength = buf8->Des().Length();
       
  1561 
       
  1562     if ( aFoundName == EFalse )
       
  1563         {
       
  1564         // well-known encoding for the header itself
       
  1565         aHeaderLength++;
       
  1566         aHeaderLength += nameLength;
       
  1567         aHeaderLength += 1; // terminating zero
       
  1568         }
       
  1569 
       
  1570     aContentTypeSize = aHeaderLength;
       
  1571 
       
  1572     // As we have general form (at least name parameter), we need to indicate the length
       
  1573     if ( aContentTypeSize <= KMms30 )
       
  1574         {
       
  1575         // short length
       
  1576         aHeaderLength += 1;
       
  1577         }
       
  1578     else
       
  1579         {
       
  1580         // length quote + at least one byte of uintvar
       
  1581         aHeaderLength += KMms2;
       
  1582         // Expecting over 128 bytes is paranoid.
       
  1583         if ( aContentTypeSize >= KMms0x7F )
       
  1584             {
       
  1585             aHeaderLength++;
       
  1586             }
       
  1587         }
       
  1588         
       
  1589     // Now the rest of the mime headers:
       
  1590 
       
  1591     // Content-location
       
  1592     // just a short integer + a null terminated string
       
  1593 
       
  1594     if ( iMimeHeaders->ContentLocation().Length() > 0 )
       
  1595         {
       
  1596         aHeaderLength += 1; // encoding of header as short integer
       
  1597 
       
  1598         // If we want to make sure we are safe,
       
  1599         // we must call IsStringSafe() function.
       
  1600 
       
  1601         // We just assume we are safe now.
       
  1602         aHeaderLength += iMimeHeaders->ContentLocation().Length();
       
  1603         aHeaderLength += 1; // terminating zero
       
  1604         }
       
  1605 
       
  1606    // Content-ID
       
  1607 
       
  1608     if ( iMimeHeaders->ContentId().Length() > 0 )
       
  1609         {
       
  1610         aHeaderLength += 1; // encoding of header as short integer
       
  1611         // add terminating zero and preceding quote.
       
  1612         // (needed according to WSP 1.3)
       
  1613         aHeaderLength += iMimeHeaders->ContentId().Length() + KMms2;
       
  1614         if ( iMimeHeaders->ContentId().Find( KMmsLeftAngle ) != 0 )
       
  1615             {
       
  1616             aHeaderLength += KMms2; // we must add angle bracket
       
  1617             }
       
  1618         }
       
  1619         
       
  1620     // x-type parameters
       
  1621     // Must be stored as name/value pairs like content-type parameters
       
  1622     // X-parameter[i] = parameter name
       
  1623     // X-parameter[i+1] = parameter value
       
  1624     
       
  1625     for ( i = 0; i < iMimeHeaders->XTypeParams().MdcaCount(); ++i )
       
  1626         {
       
  1627         // If we have corrupted parameters (length of name is zero)
       
  1628         // we skip the name/value pair.
       
  1629         // value may be zero, it will be encoded as just the terminating zero
       
  1630         if ( i%2 == 0 &&
       
  1631             ( iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() == 0  ||
       
  1632             iMimeHeaders->XTypeParams().MdcaPoint( i ).CompareF( 
       
  1633             KMmsSeparateDeliveryOmaXHeader ) == 0 ) )
       
  1634             {
       
  1635             // We skip the header and its value if
       
  1636             // a) the header length is 0
       
  1637             // b) the header is X-Oma-Drm-Separate-Delivery
       
  1638             i++;
       
  1639             }
       
  1640         else
       
  1641             {
       
  1642             aHeaderLength += iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() + 1;
       
  1643             }
       
  1644         }
       
  1645     if ( ( iMimeHeaders->XTypeParams().MdcaCount() % 2 ) == 1 )
       
  1646         {
       
  1647         // Odd number. Obviously last parameter has no value.
       
  1648         // Add the "no value" token
       
  1649         aHeaderLength++;
       
  1650         }
       
  1651         
       
  1652     // THESE ARE NOT IMPLEMENTED
       
  1653 
       
  1654     // Content-disposition & parameters
       
  1655     // Content-description
       
  1656     // Content-base
       
  1657     // Relative path
       
  1658     // version
       
  1659 
       
  1660 #ifdef CONTENT_DISPOSITION_TEST
       
  1661 // not supported
       
  1662 
       
  1663     // We generate a general header for content disposition
       
  1664     // for tests we use the actual filename.
       
  1665     // In real life the user's filename should not be
       
  1666     // sent out to the world
       
  1667 
       
  1668     // Fixed coding: 
       
  1669     // Content Disposition, value length, attachment, filename,
       
  1670     // actual filename + terminating 0
       
  1671 
       
  1672     // attachment, filename, terminating zero
       
  1673     // content disposition should be text-string, not quoted text string
       
  1674     TInt contentDispositionLength = KMms3 + nameLength;
       
  1675 
       
  1676     TInt valueLengthLength = 1;
       
  1677     if ( contentDispositionLength > KMms30 )
       
  1678         {
       
  1679         // lengths 0 - 30 are encoded using "short length"
       
  1680         valueLengthLength++;
       
  1681         // 
       
  1682         if ( contentDispositionLength > ShortIntegerLimit127 )
       
  1683             {
       
  1684             valueLengthLength++;
       
  1685             }
       
  1686         // Should never be longer than this.
       
  1687         // I don't think anybody has a filename that is longer than 16383 bytes.
       
  1688         }
       
  1689 
       
  1690     aHeaderLength += valueLengthLength + contentDispositionLength + 1;
       
  1691 #endif
       
  1692 
       
  1693     CleanupStack::Pop( buf8 );
       
  1694     return buf8; // caller will delete this afterwards
       
  1695     
       
  1696     }
       
  1697 
       
  1698 // ---------------------------------------------------------
       
  1699 //
       
  1700 // ---------------------------------------------------------
       
  1701 //
       
  1702 void CMmsEncode::EncodeAttachmentHeadersL(
       
  1703     TUint aSize,
       
  1704     TUint aHeaderSize,
       
  1705     TBool aFoundName,
       
  1706     TUint aContentTypeSize,
       
  1707     TInt8 aContentType,
       
  1708     TPtrC8& aContentTypeString,
       
  1709     TPtrC8& aNameString )
       
  1710     {
       
  1711     
       
  1712     EncodeUintvar( aHeaderSize );
       
  1713 
       
  1714     EncodeUintvar( aSize );
       
  1715 
       
  1716     TUint8 temp = 0; // used to set the high bit for integers
       
  1717 
       
  1718     // if we have character set (or other parameters),
       
  1719     // we must use general encoding
       
  1720 
       
  1721     EncodeValueLength( aContentTypeSize );
       
  1722 
       
  1723     if ( aContentType >= 0 )
       
  1724         {
       
  1725         temp = aContentType | KMms0x80;
       
  1726         iEncodeBuffer->Write( iPosition, &temp, 1 );
       
  1727         iPosition++;
       
  1728         }
       
  1729     else
       
  1730         {
       
  1731         // we assume this is a safe string
       
  1732         EncodeTextString( aContentTypeString );
       
  1733         }
       
  1734     
       
  1735     // Then content type parameters. Mainly character set,
       
  1736     // but maybe something else, too
       
  1737 
       
  1738     temp = KWspCharset | KMms0x80; // encode as short integer
       
  1739     EncodeOptionalInteger( temp, iMimeHeaders->MimeCharset() );
       
  1740 
       
  1741     // if we didn't find "Name" parameter among our parameters, we
       
  1742     // put it first.
       
  1743 
       
  1744     // we need the name later anyway...
       
  1745 
       
  1746     if ( !aFoundName )
       
  1747         {
       
  1748         temp = KWspName | KMms0x80; // encode as short integer
       
  1749         EncodeHeaderAndTextString( temp, aNameString );
       
  1750         }
       
  1751 
       
  1752     // Then the rest of content type parameters, just text strings.
       
  1753     
       
  1754     TInt i = 0;
       
  1755     
       
  1756     for ( i = 0; i < iMimeHeaders->ContentTypeParams().MdcaCount(); ++i )
       
  1757         {
       
  1758         // If we have corrupted parameters (length of name is zero)
       
  1759         // we skip the name/value pair.
       
  1760         // value may be zero, it will be encoded as just the terminating zero
       
  1761         if ( i%2 == 0 &&
       
  1762             iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() == 0 )
       
  1763             {
       
  1764             i++;
       
  1765             }
       
  1766         else
       
  1767             {
       
  1768             // 8-byte string + terminating zero
       
  1769             // If parameter has no value, it still must have
       
  1770             // the "no-value" indicator (just the terminating zero.)
       
  1771             // The ContentTypeParameters function provides
       
  1772             // an empty string in this case.
       
  1773             if ( iMimeHeaders->ContentTypeParams().MdcaPoint( i ).CompareF(
       
  1774                 KWspNameString ) == 0 && i%2 == 0 ) 
       
  1775                 {
       
  1776                 if ( aFoundName )
       
  1777                     {
       
  1778                     temp = KWspName | KMms0x80; // encode as short integer
       
  1779                     iEncodeBuffer->Write( iPosition, &temp, 1 );
       
  1780                     iPosition++;
       
  1781                     }
       
  1782                 else
       
  1783                     {
       
  1784                     // we can use name from mime headers only if it is "safe"
       
  1785                     // (contains only us-ascii characters)
       
  1786                     // If the name is not safe, the parameter value is skipped
       
  1787                     i++;
       
  1788                     }
       
  1789                 }
       
  1790             else
       
  1791                 {
       
  1792                 EncodeTextString(
       
  1793                     iMimeHeaders->ContentTypeParams().MdcaPoint( i ) );
       
  1794                 }
       
  1795             }
       
  1796         }
       
  1797     if ( ( iMimeHeaders->ContentTypeParams().MdcaCount() % 2 ) == 1 )
       
  1798         {
       
  1799         // Odd number. Obviously last parameter has no value.
       
  1800         // Add the "no value" token
       
  1801         iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  1802         iPosition++;
       
  1803         }
       
  1804 
       
  1805     // content-location
       
  1806     temp = KWspContentLocation | KMms0x80; // encode as short integer
       
  1807     EncodeOptionalStringL( temp, iMimeHeaders->ContentLocation() );
       
  1808 
       
  1809     // content-id
       
  1810     if ( iMimeHeaders->ContentId().Length() > 0 )
       
  1811         {
       
  1812         HBufC8* tempContentId = HBufC8::NewL( iMimeHeaders->ContentId().Length() + KMms2 );
       
  1813         CleanupStack::PushL( tempContentId );
       
  1814         if ( iMimeHeaders->ContentId().Find( KMmsLeftAngle ) != 0 )
       
  1815             {
       
  1816             tempContentId->Des().Copy( KMmsLeftAngle );
       
  1817             tempContentId->Des().Append( iMimeHeaders->ContentId() );
       
  1818             tempContentId->Des().Append( KMmsRightAngle );
       
  1819             }
       
  1820         else
       
  1821             {
       
  1822             tempContentId->Des().Copy( iMimeHeaders->ContentId() );
       
  1823             }
       
  1824         temp = KWspContentId | KMms0x80; // encode as short integer
       
  1825         iEncodeBuffer->Write( iPosition, &temp, 1 );
       
  1826         iPosition++;
       
  1827         EncodeQuotedTextString( tempContentId->Des() );
       
  1828         CleanupStack::PopAndDestroy( tempContentId );
       
  1829         }
       
  1830 
       
  1831 #ifdef CONTENT_DISPOSITION_TEST
       
  1832 // not supported
       
  1833      temp = 0x2E | KMms0x80; // content disposition
       
  1834      iEncodeBuffer->Write( iPosition, &temp, 1 );
       
  1835      iPosition++;
       
  1836      EncodeValueLength( contentDispositionLength );
       
  1837      temp = 0x81; // attachment
       
  1838      iEncodeBuffer->Write( iPosition, &temp, 1 );
       
  1839      iPosition++;
       
  1840      temp = 0x06 | KMms0x80; // filename
       
  1841      // filename should be text-string, not quoted
       
  1842      EncodeHeaderAndTextString( temp, buf8->Des() );
       
  1843 #endif
       
  1844 
       
  1845         // x-type parameters
       
  1846     for ( i = 0; i < iMimeHeaders->XTypeParams().MdcaCount(); ++i )
       
  1847         {
       
  1848         // If we have corrupted parameters (length of name is zero)
       
  1849         // we skip the name/value pair.
       
  1850         // value may be zero, it will be encoded as just the terminating zero
       
  1851         if ( i%2 == 0 &&
       
  1852             ( iMimeHeaders->XTypeParams().MdcaPoint( i ).Length() == 0  ||
       
  1853             iMimeHeaders->XTypeParams().MdcaPoint( i ).CompareF( 
       
  1854             KMmsSeparateDeliveryOmaXHeader ) == 0 ) )
       
  1855             {
       
  1856             // We skip the header and its value if
       
  1857             // a) the header length is 0
       
  1858             // b) the header is X-Oma-Drm-Separate-Delivery
       
  1859             i++;
       
  1860             }
       
  1861         else
       
  1862             {
       
  1863             // 8-byte string + terminating zero
       
  1864             // If parameter has no value, it still must have
       
  1865             // the "no-value" indicator (just the terminating zero.)
       
  1866             // The ContentTypeParameters function provides
       
  1867             // an empty string in this case.
       
  1868             EncodeTextString( iMimeHeaders->XTypeParams().MdcaPoint( i ) );
       
  1869             }
       
  1870         }
       
  1871     if ( ( iMimeHeaders->XTypeParams().MdcaCount() % 2 ) == 1 )
       
  1872         {
       
  1873         // Odd number. Obviously last parameter has no value.
       
  1874         // Add the "no value" token
       
  1875         iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  1876         iPosition++;
       
  1877         }
       
  1878         
       
  1879     // End of MIME headers
       
  1880 
       
  1881     }
       
  1882     
       
  1883 // ---------------------------------------------------------
       
  1884 //
       
  1885 // ---------------------------------------------------------
       
  1886 //
       
  1887 void CMmsEncode::EncodeAttachmentData( RFile& aAttachFile, TInt aSize )
       
  1888     {
       
  1889     // read the attachment file
       
  1890     // set up a pointer to point to iEncodeBuffer at iPosition
       
  1891     TPtr8 pos = iEncodeBuffer->Ptr( iPosition );
       
  1892     // Attachemnt may be a file attacment or a linked file.
       
  1893     // The file pointer will point to unread part if file is read in chunks
       
  1894     iError = aAttachFile.Read( pos, aSize );
       
  1895     }
       
  1896     
       
  1897 
       
  1898 // ---------------------------------------------------------
       
  1899 //
       
  1900 // ---------------------------------------------------------
       
  1901 //
       
  1902 void CMmsEncode::FinishL()
       
  1903     {
       
  1904 
       
  1905     // Remove slack to keep garbage out from the end of the file
       
  1906     iEncodeBuffer->ResizeL( iPosition );
       
  1907     iOverallDataSize = iEncodeBuffer->Size();
       
  1908     iState = EMmsIdle;
       
  1909     
       
  1910     // Dump the buffer contents into file if requested
       
  1911     Dump();
       
  1912 
       
  1913     }
       
  1914     
       
  1915 // ---------------------------------------------------------
       
  1916 //
       
  1917 // ---------------------------------------------------------
       
  1918 //
       
  1919 void CMmsEncode::EncodeRequestHeadersL()
       
  1920     {
       
  1921     // encode message depending on type
       
  1922     switch ( iMmsHeaders->MessageType() )
       
  1923         {
       
  1924         // KMmsMessageTypeMNotifyRespInd and KMmsMessageTypeAcknowledgeInd and all other PDUs
       
  1925         // that contain only headers and no data should be handled by
       
  1926         // using function
       
  1927         // EncodeHeadersL(CMmsHeaders& aMmsHeaders,CBufFlat& aEncodeBuffer)
       
  1928         case KMmsMessageTypeMSendReq:
       
  1929             EncodeSendRequestHeadersL();
       
  1930             break;
       
  1931         case KMmsMessageTypeMBoxUploadReq:
       
  1932             // This type has attachments and headers
       
  1933             EncodeMMBoxUploadRequestL();
       
  1934             break;
       
  1935         case KMmsMessageTypeMRetrieveConf:
       
  1936             // for test purposes
       
  1937             EncodeRetrieveConfirmationL();
       
  1938             break;
       
  1939         case KMmsMessageTypeMboxViewConf:
       
  1940             // for test purposes
       
  1941             EncodeMMBoxViewConfirmationL();
       
  1942             break;
       
  1943         case KMmsMessageTypeMBoxDescr:
       
  1944             // for test purposes
       
  1945             EncodeMMBoxDescriptionL();
       
  1946             break;
       
  1947         default:
       
  1948             iError = KMmsErrorUnknownMessageType;
       
  1949             break;
       
  1950         }
       
  1951     }
       
  1952 
       
  1953 // ---------------------------------------------------------
       
  1954 //
       
  1955 // ---------------------------------------------------------
       
  1956 //
       
  1957 void CMmsEncode::EncodeSendRequestHeadersL()
       
  1958     {
       
  1959         
       
  1960     // Insert message type, TID and version number
       
  1961     EncodeStartingHeaders( KMmsMessageTypeMSendReq,
       
  1962         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  1963 
       
  1964     // if we have set a date, insert it
       
  1965     EncodeDate( iMmsHeaders->Date() );
       
  1966 
       
  1967     // If we have set the sender, encode it
       
  1968     // If not, we ask MMSC to add the sender
       
  1969     EncodeSenderL( iMmsHeaders->Sender() );
       
  1970 
       
  1971     // All recipient lists. If no recipients in some of the lists,
       
  1972     // nothing is encoded, no need to check separately
       
  1973     EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
       
  1974     EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
       
  1975     EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc );
       
  1976 
       
  1977     // Subject
       
  1978     EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
       
  1979 
       
  1980     // Message class
       
  1981     EncodeOptionalByte( KMmsAssignedMessageClass,
       
  1982         iMmsHeaders->MessageClass() );
       
  1983 
       
  1984     // Expiration time
       
  1985     EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
       
  1986         iMmsHeaders->ExpiryInterval(),
       
  1987         iMmsHeaders->ExpiryDate() );
       
  1988 
       
  1989     // Delivery time
       
  1990     EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime,
       
  1991         iMmsHeaders->DeliveryTimeInterval(),
       
  1992         iMmsHeaders->DeliveryDate() );
       
  1993 
       
  1994     // Priority
       
  1995     EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() );
       
  1996     
       
  1997     // Sender visibility
       
  1998     EncodeOptionalByte( KMmsAssignedSenderVisibility,
       
  1999         iMmsHeaders->SenderVisibility() );
       
  2000 
       
  2001     // Delivery report
       
  2002     EncodeOptionalByte( KMmsAssignedDeliveryReport,
       
  2003         iMmsHeaders->DeliveryReport() );
       
  2004 
       
  2005     // Read reply
       
  2006     EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
       
  2007 
       
  2008     // MMS encapsulation 1.1 headers - optional
       
  2009     if ( iMmsHeaders->MmsVersion() > KMmsVersion1 )
       
  2010         {
       
  2011         // Do we want to specify reply charging
       
  2012         if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested ||
       
  2013             iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly )
       
  2014             {
       
  2015             // Reply charging value
       
  2016             EncodeOptionalByte( KMmsAssignedReplyCharging,
       
  2017                 iMmsHeaders->ReplyCharging() );
       
  2018             // Reply charging deadline
       
  2019             EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
       
  2020                 iMmsHeaders->ReplyChargingInterval(),
       
  2021                 iMmsHeaders->ReplyChargingDate() );
       
  2022             // Reply charging size
       
  2023             EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
       
  2024             }
       
  2025         // Reply charging ID
       
  2026         EncodeOptionalString( KMmsAssignedReplyChargingID,
       
  2027             iMmsHeaders->ReplyChargingId() );
       
  2028         }
       
  2029 
       
  2030     if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
       
  2031         {
       
  2032         // MMBox related headers - optional
       
  2033         if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2034             {
       
  2035             // X-Mms-MM-Store
       
  2036             EncodeOptionalByte( KMmsAssignedMmsStore,
       
  2037                 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() );
       
  2038             if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() == KMmsYes )
       
  2039                 {
       
  2040                 // X-Mms-MM-State
       
  2041                 EncodeOptionalByte( KMmsAssignedMMState,
       
  2042                     iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
       
  2043                 // X-MMs-MM-Flags
       
  2044                 // The keyword token should always be "add" or "remove"
       
  2045                 EncodeKeywordArrayL();
       
  2046                 }
       
  2047             }
       
  2048         }
       
  2049 
       
  2050     // Add encapsulation version 1.3 headers - optional
       
  2051     if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
       
  2052         {
       
  2053         // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
       
  2054         EncodeApplicationHeadersL();
       
  2055         // X-Mms-Content-Class
       
  2056         EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() );
       
  2057         // X-Mms-DRM-Content
       
  2058         EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() );
       
  2059         // X-Mms-Adaptation-Allowed
       
  2060         EncodeOptionalByte( KMmsAssignedAdaptationAllowed, iMmsHeaders->AdaptationAllowed() );
       
  2061         }
       
  2062 
       
  2063     // Get Root TMsvId from headers if set
       
  2064     TMsvAttachmentId rootId = iMmsHeaders->MessageRoot();
       
  2065 
       
  2066     TInt error = KErrNone;
       
  2067     // If we are handling headers only, we may not have iEntryWrapper
       
  2068     if ( iEntryWrapper )
       
  2069         {
       
  2070         CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  2071         CleanupStack::PushL( store );
       
  2072         MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  2073         TRAP( error,
       
  2074             {
       
  2075             CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL(
       
  2076                 (TMsvAttachmentId) rootId );
       
  2077             delete attachmentInfo; // we just wanted to check that it was found
       
  2078             }
       
  2079             );
       
  2080         CleanupStack::PopAndDestroy( store );
       
  2081         }
       
  2082         
       
  2083     // If we have a valid root part, we send the message as multipart/related.
       
  2084     // Otherwise we send it as multipart mixed.
       
  2085     // We don't try to guess what the root is supposed to be, if it
       
  2086     // is not specified or does not point to an existing attachment.
       
  2087 
       
  2088     if ( error == KErrNone && rootId != 0 && iEntryWrapper )
       
  2089         {
       
  2090         EncodeMultipartRelatedHeaderL( rootId );
       
  2091         }
       
  2092     else
       
  2093         {
       
  2094         EncodeMultipartMixedHeaderL();
       
  2095         }
       
  2096         
       
  2097     }
       
  2098 
       
  2099 // ---------------------------------------------------------
       
  2100 //
       
  2101 // ---------------------------------------------------------
       
  2102 //
       
  2103 void CMmsEncode::EncodeNotifyResponse()
       
  2104     {
       
  2105 
       
  2106     // version may be current version or 1.0
       
  2107     // Only byte is used. iMmsHeaders controls the value.
       
  2108 
       
  2109     // Insert message type, TID and version number
       
  2110     EncodeStartingHeaders( KMmsMessageTypeMNotifyRespInd, iMmsHeaders->Tid(),
       
  2111         iMmsHeaders->MmsVersion() );
       
  2112 
       
  2113     // insert message status
       
  2114     EncodeMandatoryByte( KMmsAssignedStatus, iMmsHeaders->Status() );
       
  2115 
       
  2116     // insert report allowed if present
       
  2117     EncodeOptionalByte( KMmsAssignedReportAllowed,
       
  2118         iMmsHeaders->ReportAllowed() );
       
  2119 
       
  2120     }
       
  2121 
       
  2122 // ---------------------------------------------------------
       
  2123 //
       
  2124 // ---------------------------------------------------------
       
  2125 //
       
  2126 void CMmsEncode::EncodeAcknowledgeIndication()
       
  2127     {
       
  2128     // Insert message type, TID and version number
       
  2129     EncodeStartingHeaders( KMmsMessageTypeAcknowledgeInd,
       
  2130         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2131 
       
  2132     // insert report allowed if present
       
  2133     EncodeOptionalByte( KMmsAssignedReportAllowed,
       
  2134         iMmsHeaders->ReportAllowed() );
       
  2135     }
       
  2136 
       
  2137 // ---------------------------------------------------------
       
  2138 //
       
  2139 // ---------------------------------------------------------
       
  2140 //
       
  2141 void CMmsEncode::EncodeMmsNotificationL()
       
  2142     {
       
  2143 
       
  2144     // Insert message type, TID and version number
       
  2145     EncodeStartingHeaders( KMmsMessageTypeMNotificationInd,
       
  2146         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2147 
       
  2148     // for notification sender is optional - added only if it is known
       
  2149     if ( iMmsHeaders->Sender().Length() > 0 )
       
  2150         {
       
  2151         EncodeSenderL( iMmsHeaders->Sender() );
       
  2152         }
       
  2153 
       
  2154     EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
       
  2155 
       
  2156     EncodeOptionalByte( KMmsAssignedDeliveryReport,
       
  2157         iMmsHeaders->DeliveryReport() );
       
  2158 
       
  2159     EncodeOptionalByte( KMmsAssignedMessageClass,
       
  2160         iMmsHeaders->MessageClass() );
       
  2161 
       
  2162     iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageSize, 1 );
       
  2163     iPosition++;
       
  2164 
       
  2165     TInt64 size = iMmsHeaders->MessageSize();
       
  2166     EncodeLongInteger( size );
       
  2167 
       
  2168     EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
       
  2169         iMmsHeaders->ExpiryInterval(),
       
  2170         iMmsHeaders->ExpiryDate() );
       
  2171 
       
  2172     // version 1.1 fields - optional
       
  2173     // reply-charging
       
  2174     // reply-charging deadline
       
  2175     // reply-charging size
       
  2176     // reply-charging ID
       
  2177     if ( iMmsHeaders->MmsVersion() > KMmsVersion1 )
       
  2178         {
       
  2179         // Do we want to specify
       
  2180         if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted ||
       
  2181             iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly )
       
  2182             {
       
  2183             // Reply charging value
       
  2184             EncodeOptionalByte( KMmsAssignedReplyCharging,
       
  2185                 iMmsHeaders->ReplyCharging() );
       
  2186             // Reply charging deadline
       
  2187             EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
       
  2188                 iMmsHeaders->ReplyChargingInterval(),
       
  2189                 iMmsHeaders->ReplyChargingDate() );
       
  2190             // Reply charging size
       
  2191             EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
       
  2192             }
       
  2193         // if this is a reply, we may specify the ID
       
  2194         // Reply charging ID
       
  2195         EncodeOptionalString( KMmsAssignedReplyChargingID,
       
  2196             iMmsHeaders->ReplyChargingId() );
       
  2197         }
       
  2198 
       
  2199     // version 1.2 headers - optional
       
  2200     if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
       
  2201         {
       
  2202         // MMBox headers
       
  2203         if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2204             {
       
  2205             EncodeOptionalByte( KMmsAssignedStored,
       
  2206                 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStored() );
       
  2207             }
       
  2208 
       
  2209         // Distribution indicator
       
  2210         EncodeOptionalByte( KMmsAssignedDistributionIndicator,
       
  2211             iMmsHeaders->DistributionIndicator() );
       
  2212         }
       
  2213 
       
  2214     // Element descriptor
       
  2215     // This is somewhat a mystery - not implemented
       
  2216     
       
  2217     // version 1.3 headers - optional
       
  2218     if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
       
  2219         {
       
  2220         // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
       
  2221         EncodeApplicationHeadersL();
       
  2222         // X-Mms-Recommended-Retrieval-Mode
       
  2223         EncodeOptionalByte( KMmsAssignedRecommendedRetrievalMode,
       
  2224             iMmsHeaders->RecommendedRetrievalMode() );
       
  2225         // X-Mms-Recommended-Retrieval-Mode-Text
       
  2226         EncodeOptionalStringL( KMmsAssignedRecommendedRetrievalModeText,
       
  2227             iMmsHeaders->RecommendedRetrievalModeText() );
       
  2228         // X-Mms-Content-Class
       
  2229         EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() );
       
  2230         // X-Mms-DRM-Content
       
  2231         EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() );
       
  2232         // X-Mms-Replace-ID
       
  2233         EncodeOptionalString( KMmsAssignedReplaceId, iMmsHeaders->ReplaceCancelId() );
       
  2234         }
       
  2235 
       
  2236     // We keep this as the last one, though it does not really matter
       
  2237     // Mandatory content-location
       
  2238     // this must be USASCII or URL encoded
       
  2239     EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  2240         iMmsHeaders->ContentLocation() );
       
  2241 
       
  2242     }
       
  2243 
       
  2244 // ---------------------------------------------------------
       
  2245 //
       
  2246 // ---------------------------------------------------------
       
  2247 //
       
  2248 void CMmsEncode::EncodeSendConfirmationL()
       
  2249     {
       
  2250 // implemented for test purposes
       
  2251 #ifdef __WINS__
       
  2252     // Insert message type, TID and version number
       
  2253     EncodeStartingHeaders( KMmsMessageTypeMSendConf,
       
  2254         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2255 
       
  2256     EncodeMandatoryByte( KMmsAssignedResponseStatus,
       
  2257         iMmsHeaders->ResponseStatus() );
       
  2258 
       
  2259     EncodeOptionalStringL( KMmsAssignedResponseText,
       
  2260         iMmsHeaders->ResponseText() );
       
  2261 
       
  2262     // if send confirmation returns error, it might not contain message id
       
  2263     EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
       
  2264 
       
  2265     // MMBox related headers - optional
       
  2266     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2267         {
       
  2268         EncodeOptionalByte( KMmsAssignedStoreStatus,
       
  2269             iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
       
  2270         EncodeOptionalStringL( KMmsAssignedStoreStatusText,
       
  2271             iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
       
  2272         if ( iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ==
       
  2273             KMmsStatusOk )
       
  2274             {
       
  2275             // this must be USASCII or URL encoded
       
  2276             // If message was stored to MMBox, this is mandatory
       
  2277             EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  2278                 iMmsHeaders->ContentLocation() );
       
  2279             }
       
  2280         }
       
  2281     
       
  2282 #endif
       
  2283 
       
  2284     }
       
  2285 
       
  2286 // ---------------------------------------------------------
       
  2287 //
       
  2288 // ---------------------------------------------------------
       
  2289 //
       
  2290 void CMmsEncode::EncodeRetrieveConfirmationL()
       
  2291     {
       
  2292 // implemented for test purposes
       
  2293 #ifdef __WINS__
       
  2294 
       
  2295     // Insert message type, TID and version number
       
  2296     EncodeStartingHeaders( KMmsMessageTypeMRetrieveConf,
       
  2297         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2298 
       
  2299     // message id
       
  2300     EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
       
  2301 
       
  2302     // if we have set a date, insert it
       
  2303     EncodeDate( iMmsHeaders->Date() );
       
  2304 
       
  2305     // If we have set the sender, encode it
       
  2306     if ( iMmsHeaders->Sender().Length() > 0 )
       
  2307         {
       
  2308         EncodeSenderL( iMmsHeaders->Sender() );
       
  2309         }
       
  2310 
       
  2311     // previously sent by array
       
  2312     TInt i;
       
  2313     TUint oldPosition;
       
  2314     TUint length;
       
  2315     for ( i = 0; i < iMmsHeaders->PreviouslySentList().Count(); ++i )
       
  2316         {
       
  2317         oldPosition = iPosition;
       
  2318         length = 0;
       
  2319         // Encode once just to find out filed length
       
  2320         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  2321         EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
       
  2322         length += iPosition - oldPosition;
       
  2323         iPosition = oldPosition;
       
  2324         iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentBy, 1 );
       
  2325         iPosition++;
       
  2326         EncodeValueLength( length );
       
  2327         // now we have added length, do the actual encoding
       
  2328         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  2329         EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
       
  2330         oldPosition = iPosition;
       
  2331         length = 0;
       
  2332         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  2333         EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
       
  2334         length += iPosition - oldPosition;
       
  2335         iPosition = oldPosition;
       
  2336         iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentDate, 1 );
       
  2337         iPosition++;
       
  2338         EncodeValueLength( length );
       
  2339         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  2340         EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
       
  2341         }
       
  2342 
       
  2343     // All recipient lists. If no recipients in some of the lists,
       
  2344     // nothing is encoded, no need to check separately
       
  2345     EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
       
  2346     EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
       
  2347     // no Bcc in retrieve confirmation
       
  2348 
       
  2349     // Subject
       
  2350     EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
       
  2351 
       
  2352     // MMBox headers
       
  2353     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2354         {
       
  2355         // X-Mms-MM-State
       
  2356         EncodeOptionalByte( KMmsAssignedMMState,
       
  2357             iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
       
  2358         // X-MMs-MM-Flags
       
  2359         // The keyword token should always be "add" or "remove"
       
  2360         EncodeKeywordArrayL();
       
  2361         }
       
  2362 
       
  2363     // Message class
       
  2364     EncodeOptionalByte( KMmsAssignedMessageClass,
       
  2365         iMmsHeaders->MessageClass() );
       
  2366 
       
  2367     // Priority
       
  2368     EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() );
       
  2369     
       
  2370     // Delivery report
       
  2371     EncodeOptionalByte( KMmsAssignedDeliveryReport,
       
  2372         iMmsHeaders->DeliveryReport() );
       
  2373 
       
  2374     // Read reply
       
  2375     EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
       
  2376 
       
  2377     // MMS encapsulation 1.1 headers - optional
       
  2378     if ( iMmsHeaders->MmsVersion() > KMmsVersion1 )
       
  2379         {
       
  2380         // Do we want to specify reply charging
       
  2381         if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted ||
       
  2382             iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly )
       
  2383             {
       
  2384             // Reply charging value
       
  2385             EncodeOptionalByte( KMmsAssignedReplyCharging,
       
  2386                 iMmsHeaders->ReplyCharging() );
       
  2387             // Reply charging deadline
       
  2388             EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
       
  2389                 iMmsHeaders->ReplyChargingInterval(),
       
  2390                 iMmsHeaders->ReplyChargingDate() );
       
  2391             // Reply charging size
       
  2392             EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
       
  2393             }
       
  2394         // Reply charging ID
       
  2395         EncodeOptionalString( KMmsAssignedReplyChargingID,
       
  2396             iMmsHeaders->ReplyChargingId() );
       
  2397         // status of the operation
       
  2398         EncodeOptionalByte( KMmsAssignedRetrieveStatus,
       
  2399             iMmsHeaders->ResponseStatus() );
       
  2400 
       
  2401         EncodeOptionalStringL( KMmsAssignedRetrieveText,
       
  2402             iMmsHeaders->ResponseText() );
       
  2403         }
       
  2404 
       
  2405     // version 1.2 headers - optional
       
  2406     if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
       
  2407         {
       
  2408         // Distribution indicator
       
  2409         EncodeOptionalByte( KMmsAssignedDistributionIndicator,
       
  2410             iMmsHeaders->DistributionIndicator() );
       
  2411         }
       
  2412 
       
  2413     // version 1.3 headers - optional
       
  2414     if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
       
  2415         {
       
  2416         // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
       
  2417         EncodeApplicationHeadersL();
       
  2418         // X-Mms-Content-Class
       
  2419         EncodeOptionalByte( KMmsAssignedContentClass, iMmsHeaders->ContentClass() );
       
  2420         // X-Mms-DRM-Content
       
  2421         EncodeOptionalByte( KMmsAssignedDrmContent, iMmsHeaders->DrmContent() );
       
  2422         // X-Mms-Replace-ID
       
  2423         EncodeOptionalString( KMmsAssignedReplaceId, iMmsHeaders->ReplaceCancelId() );
       
  2424         }
       
  2425 
       
  2426     // Start pointer
       
  2427     TUint ii = 0;
       
  2428     // Get Root TMsvId from headers if set
       
  2429     TMsvId rootId = iMmsHeaders->MessageRoot();
       
  2430 
       
  2431     TInt error = KErrNone;
       
  2432     if ( iEntryWrapper )
       
  2433         {
       
  2434         CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  2435         CleanupStack::PushL( store );
       
  2436         MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  2437         TRAP( error,
       
  2438             {
       
  2439             CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL(
       
  2440                 (TMsvAttachmentId) rootId );
       
  2441             delete attachmentInfo; // we just wanted to check that it was found
       
  2442             }
       
  2443             );
       
  2444         CleanupStack::PopAndDestroy( store );
       
  2445         }
       
  2446         
       
  2447     // If we have a valid root part, we send the message as multipart/related.
       
  2448     // Otherwise we send it as multipart mixed.
       
  2449     // We don't try to guess what the root is supposed to be, if it
       
  2450     // is not specified or does not point to an existing attachment.
       
  2451 
       
  2452     if ( error == KErrNone && rootId != 0 && iEntryWrapper )
       
  2453         {
       
  2454         EncodeMultipartRelatedHeaderL( rootId );
       
  2455         }
       
  2456     else
       
  2457         {
       
  2458         EncodeMultipartMixedHeaderL();
       
  2459         }
       
  2460 
       
  2461     
       
  2462 #endif
       
  2463     }
       
  2464 
       
  2465 // ---------------------------------------------------------
       
  2466 //
       
  2467 // ---------------------------------------------------------
       
  2468 //
       
  2469 void CMmsEncode::EncodeDeliveryReportL()
       
  2470     {
       
  2471 // implemented for test purposes
       
  2472 #ifdef __WINS__
       
  2473 
       
  2474     // Insert message type, TID and version number
       
  2475     EncodeStartingHeaders( KMmsMessageTypeDeliveryInd, TPtrC8(),
       
  2476         iMmsHeaders->MmsVersion() );
       
  2477 
       
  2478     EncodeHeaderAndTextString( KMmsAssignedMessageId,
       
  2479         iMmsHeaders->MessageId() );
       
  2480 
       
  2481     EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
       
  2482 
       
  2483     // if we have set a date, insert it
       
  2484     EncodeDate( iMmsHeaders->Date() );
       
  2485 
       
  2486     // insert message status
       
  2487     EncodeMandatoryByte( KMmsAssignedStatus, iMmsHeaders->Status() );
       
  2488     
       
  2489     // version 1.3 headers - optional
       
  2490     if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
       
  2491         {
       
  2492         // X-Mms-Status-Text
       
  2493         // Status text is stored in the same place as response text and retrieve
       
  2494         // text as only one of them can appear in any PDU
       
  2495         EncodeOptionalStringL( KMmsAssignedStatusText,
       
  2496             iMmsHeaders->ResponseText() );
       
  2497         // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
       
  2498         EncodeApplicationHeadersL();
       
  2499         }
       
  2500     
       
  2501 #endif
       
  2502     }
       
  2503 
       
  2504 // ---------------------------------------------------------
       
  2505 //
       
  2506 // ---------------------------------------------------------
       
  2507 //
       
  2508 void CMmsEncode::EncodeForwardRequestL()
       
  2509     {
       
  2510     // Insert message type, TID and version number
       
  2511     EncodeStartingHeaders( KMmsMessageTypeForwardReq,
       
  2512         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2513 
       
  2514     // if we have set a date, insert it
       
  2515     EncodeDate( iMmsHeaders->Date() );
       
  2516 
       
  2517     // If we have set the sender, encode it
       
  2518     // If not, we ask MMSC to add the sender
       
  2519     EncodeSenderL( iMmsHeaders->Sender() );
       
  2520 
       
  2521     // All recipient lists. If no recipients in some of the lists,
       
  2522     // nothing is encoded, no need to check separately
       
  2523     EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
       
  2524     EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
       
  2525     EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc );
       
  2526 
       
  2527     // Expiration time
       
  2528     EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
       
  2529         iMmsHeaders->ExpiryInterval(),
       
  2530         iMmsHeaders->ExpiryDate() );
       
  2531 
       
  2532     // Delivery time
       
  2533     EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime,
       
  2534         iMmsHeaders->DeliveryTimeInterval(),
       
  2535         iMmsHeaders->DeliveryDate() );
       
  2536 
       
  2537     // Delivery report allowed
       
  2538     EncodeOptionalByte( KMmsAssignedReportAllowed,
       
  2539         iMmsHeaders->ReportAllowed() );
       
  2540 
       
  2541     // Delivery report
       
  2542     EncodeOptionalByte( KMmsAssignedDeliveryReport,
       
  2543         iMmsHeaders->DeliveryReport() );
       
  2544 
       
  2545     // Read reply
       
  2546     EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
       
  2547 
       
  2548     // version 1.2 headers - optional
       
  2549     if ( iMmsHeaders->MmsVersion() > KMmsVersion11 )
       
  2550         {
       
  2551         // MMBox related headers - optional
       
  2552         if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2553             {
       
  2554             // X-Mms-MM-Store
       
  2555             EncodeOptionalByte( KMmsAssignedMmsStore,
       
  2556                 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() );
       
  2557             if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStore() == KMmsYes ||
       
  2558                  iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsStored() == KMmsYes )
       
  2559                 {
       
  2560                 // X-Mms-MM-State
       
  2561                 EncodeOptionalByte( KMmsAssignedMMState,
       
  2562                     iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
       
  2563                 // X-MMs-MM-Flags
       
  2564                 // The keyword token should always be "add" or "remove"
       
  2565                 EncodeKeywordArrayL();
       
  2566                 }
       
  2567             }
       
  2568         }
       
  2569         
       
  2570     // version 1.3 headers - optional
       
  2571     if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
       
  2572         {
       
  2573         // Do we want to specify reply charging
       
  2574         if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested ||
       
  2575             iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly )
       
  2576             {
       
  2577             // Reply charging value
       
  2578             EncodeOptionalByte( KMmsAssignedReplyCharging,
       
  2579                 iMmsHeaders->ReplyCharging() );
       
  2580             // Reply charging deadline
       
  2581             EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
       
  2582                 iMmsHeaders->ReplyChargingInterval(),
       
  2583                 iMmsHeaders->ReplyChargingDate() );
       
  2584             // Reply charging size
       
  2585             EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
       
  2586             }
       
  2587         }
       
  2588 
       
  2589     // Mandatory content-location
       
  2590     // this must be USASCII or URL encoded
       
  2591     EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  2592         iMmsHeaders->ContentLocation() );
       
  2593 
       
  2594     }
       
  2595 
       
  2596 // ---------------------------------------------------------
       
  2597 //
       
  2598 // ---------------------------------------------------------
       
  2599 //
       
  2600 void CMmsEncode::EncodeForwardConfirmationL()
       
  2601     {
       
  2602 // implemented for test purposes
       
  2603 #ifdef __WINS__
       
  2604     // Insert message type, TID and version number
       
  2605     EncodeStartingHeaders( KMmsMessageTypeForwardConf,
       
  2606         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2607 
       
  2608     EncodeMandatoryByte( KMmsAssignedResponseStatus,
       
  2609         iMmsHeaders->ResponseStatus() );
       
  2610 
       
  2611     EncodeOptionalStringL( KMmsAssignedResponseText,
       
  2612         iMmsHeaders->ResponseText() );
       
  2613 
       
  2614     EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
       
  2615 
       
  2616     // MMBox related headers - optional
       
  2617     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2618         {
       
  2619         EncodeOptionalByte( KMmsAssignedStoreStatus,
       
  2620             iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
       
  2621         EncodeOptionalStringL( KMmsAssignedStoreStatusText,
       
  2622             iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
       
  2623         if ( iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() ==
       
  2624             KMmsStatusOk )
       
  2625             {
       
  2626             // this must be USASCII or URL encoded
       
  2627             // If message was stored to MMBox, this is mandatory
       
  2628             EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  2629                 iMmsHeaders->ContentLocation() );
       
  2630             }
       
  2631         }
       
  2632     
       
  2633 #endif
       
  2634     }
       
  2635 
       
  2636 // ---------------------------------------------------------
       
  2637 //
       
  2638 // ---------------------------------------------------------
       
  2639 //
       
  2640 void CMmsEncode::EncodeReadReplyL()
       
  2641     {
       
  2642     // Insert message type, TID and version number
       
  2643     EncodeStartingHeaders( iMmsHeaders->MessageType(), TPtrC8(), iMmsHeaders->MmsVersion() );
       
  2644 
       
  2645     // message id
       
  2646     EncodeHeaderAndTextString( KMmsAssignedMessageId,
       
  2647         iMmsHeaders->MessageId() );
       
  2648 
       
  2649     // originator of the original message
       
  2650     EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
       
  2651 
       
  2652     // If we have set the sender, encode it
       
  2653     // If not, we ask MMSC to add the sender
       
  2654     EncodeSenderL( iMmsHeaders->Sender() );
       
  2655 
       
  2656     // if we have set a date, insert it
       
  2657     EncodeDate( iMmsHeaders->Date() );
       
  2658 
       
  2659     EncodeMandatoryByte( KMmsAssignedReadStatus, iMmsHeaders->ReadStatus() );
       
  2660     
       
  2661     // version 1.3 headers - optional
       
  2662     if ( iMmsHeaders->MmsVersion() > KMmsVersion12 )
       
  2663         {
       
  2664         // X-Mms-Applic-ID, X-Mms-Reply-Applic-ID and X-Mms-Aux-Applic-Info
       
  2665         EncodeApplicationHeadersL();
       
  2666         }
       
  2667     }
       
  2668 
       
  2669 // ---------------------------------------------------------
       
  2670 //
       
  2671 // ---------------------------------------------------------
       
  2672 //
       
  2673 void CMmsEncode::EncodeMMBoxStoreRequestL()
       
  2674     {
       
  2675     // Insert message type, TID and version number
       
  2676     EncodeStartingHeaders( KMmsMessageTypeMboxStoreReq, iMmsHeaders->Tid(),
       
  2677         iMmsHeaders->MmsVersion() );
       
  2678 
       
  2679     // this must be USASCII or URL encoded
       
  2680     EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  2681         iMmsHeaders->ContentLocation() );
       
  2682 
       
  2683     // MMBox headers
       
  2684     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2685         {
       
  2686         // X-Mms-MM-State
       
  2687         EncodeOptionalByte( KMmsAssignedMMState,
       
  2688             iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
       
  2689         // X-MMs-MM-Flags
       
  2690         // The keyword token should always be "add" or "remove"
       
  2691         EncodeKeywordArrayL();
       
  2692         }
       
  2693     }
       
  2694 
       
  2695 // ---------------------------------------------------------
       
  2696 //
       
  2697 // ---------------------------------------------------------
       
  2698 //
       
  2699 void CMmsEncode::EncodeMMBoxStoreConfirmationL()
       
  2700     {
       
  2701 // implemented for test purposes
       
  2702 #ifdef __WINS__
       
  2703     // Insert message type, TID and version number
       
  2704     EncodeStartingHeaders( KMmsMessageTypeMboxStoreConf, iMmsHeaders->Tid(),
       
  2705         iMmsHeaders->MmsVersion() );
       
  2706 
       
  2707     // this must be USASCII or URL encoded
       
  2708     EncodeOptionalString( KMmsAssignedContentLocation,
       
  2709         iMmsHeaders->ContentLocation() );
       
  2710 
       
  2711     EncodeMandatoryByte( KMmsAssignedStoreStatus,
       
  2712         iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
       
  2713 
       
  2714     EncodeOptionalStringL( KMmsAssignedStoreStatusText,
       
  2715         iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
       
  2716 
       
  2717 #endif
       
  2718     }
       
  2719 
       
  2720 // ---------------------------------------------------------
       
  2721 //
       
  2722 // ---------------------------------------------------------
       
  2723 //
       
  2724 void CMmsEncode::EncodeMMBoxViewRequestL()
       
  2725     {
       
  2726     // Insert message type, TID and version number
       
  2727     EncodeStartingHeaders( KMmsMessageTypeMboxViewReq, iMmsHeaders->Tid(),
       
  2728         iMmsHeaders->MmsVersion() );
       
  2729 
       
  2730     // Insert content location header. There may be more than one
       
  2731     EncodeContentLocationArray();
       
  2732 
       
  2733     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2734         {
       
  2735         // X-MMs-MM-Flags. The token should always be "filter"
       
  2736         EncodeKeywordArrayL();
       
  2737         }
       
  2738 
       
  2739     if ( iMmsHeaders->ReadOnlyMMBoxViewHeaders() )
       
  2740         {
       
  2741         CMmsMMBoxViewHeaders& viewHeaders = iMmsHeaders->MMBoxViewHeadersL();
       
  2742         
       
  2743         // states used as filter
       
  2744         // X-Mms-MM-State may appear multiple times in view request
       
  2745         EncodeMMBoxStates( viewHeaders.MMStateArray() ); 
       
  2746 
       
  2747         // start
       
  2748         EncodeOptionalInteger( KMmsAssignedStart, viewHeaders.MmsStart() );
       
  2749         // limit
       
  2750         if ( viewHeaders.MmsLimit() != KMaxTUint32 )
       
  2751             {
       
  2752             // 0 means no message information, absence means all remaining
       
  2753             // messages.
       
  2754             // If header has value KMaxTUint32, it means that info about all
       
  2755             // remaining messages is wanted.
       
  2756             iEncodeBuffer->Write( iPosition, &KMmsAssignedLimit, 1 );
       
  2757             iPosition++;
       
  2758             EncodeInteger( viewHeaders.MmsLimit() );
       
  2759             }
       
  2760 
       
  2761         EncodeAttributes( viewHeaders.AttributeArray() );
       
  2762         // request totals
       
  2763         EncodeOptionalByte( KMmsAssignedTotals, viewHeaders.MmsTotals() );
       
  2764         // request quotas
       
  2765         EncodeOptionalByte( KMmsAssignedQuotas, viewHeaders.MmsQuotas() );
       
  2766         }
       
  2767     }
       
  2768 
       
  2769 // ---------------------------------------------------------
       
  2770 //
       
  2771 // ---------------------------------------------------------
       
  2772 //
       
  2773 void CMmsEncode::EncodeMMBoxViewConfirmationL()
       
  2774     {
       
  2775 // implemented for test purposes
       
  2776 #ifdef __WINS__
       
  2777     // Insert message type, TID and version number
       
  2778     EncodeStartingHeaders( KMmsMessageTypeMboxViewConf,
       
  2779         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  2780 
       
  2781     EncodeMandatoryByte( KMmsAssignedResponseStatus,
       
  2782         iMmsHeaders->ResponseStatus() );
       
  2783 
       
  2784     EncodeOptionalStringL( KMmsAssignedResponseText,
       
  2785         iMmsHeaders->ResponseText() );
       
  2786 
       
  2787     EncodeContentLocationArray();
       
  2788 
       
  2789     // MMBox headers
       
  2790     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2791         {
       
  2792         // X-MMs-MM-Flags. The token should always be "filter"
       
  2793         EncodeKeywordArrayL();
       
  2794         }
       
  2795     
       
  2796     if ( iMmsHeaders->ReadOnlyMMBoxViewHeaders() )
       
  2797         {
       
  2798         CMmsMMBoxViewHeaders& viewHeaders = iMmsHeaders->MMBoxViewHeadersL();
       
  2799 
       
  2800         // states used as filter
       
  2801         // X-Mms-MM-State may appear multiple times in view request
       
  2802         EncodeMMBoxStates( viewHeaders.MMStateArray() ); 
       
  2803 
       
  2804         // start
       
  2805         EncodeOptionalInteger( KMmsAssignedStart, viewHeaders.MmsStart() );
       
  2806         // limit
       
  2807         if ( viewHeaders.MmsLimit() != KMaxTUint32 )
       
  2808             {
       
  2809             // 0 means no message information, absence means all remaining
       
  2810             // messages.
       
  2811             // If header has value KMaxTUint32, it means that info about
       
  2812             // all remaining messages is wanted.
       
  2813             iEncodeBuffer->Write( iPosition, &KMmsAssignedLimit, 1 );
       
  2814             iPosition++;
       
  2815             EncodeInteger( viewHeaders.MmsLimit() );
       
  2816             }
       
  2817         EncodeAttributes( viewHeaders.AttributeArray() );
       
  2818 
       
  2819         // totals
       
  2820         TUint oldPosition = iPosition;
       
  2821         TUint length = 0;
       
  2822 
       
  2823         if ( viewHeaders.MMBoxTotalNumber() != KMaxTUint32 )
       
  2824             {
       
  2825             oldPosition = iPosition;
       
  2826             EncodeInteger( viewHeaders.MMBoxTotalNumber() );
       
  2827             length = iPosition - oldPosition;
       
  2828             length += 1; // quota token
       
  2829             iPosition = oldPosition;
       
  2830             iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxTotals, 1 );
       
  2831             iPosition++;
       
  2832             EncodeValueLength( length );
       
  2833             iEncodeBuffer->Write( iPosition, &KMmsMessageCountToken, 1 );
       
  2834             iPosition++;
       
  2835             EncodeInteger( viewHeaders.MMBoxTotalNumber() );
       
  2836             }
       
  2837 
       
  2838         if ( viewHeaders.MMBoxTotalSize() != KMaxTUint32 )
       
  2839             {
       
  2840             oldPosition = iPosition;
       
  2841             EncodeInteger( viewHeaders.MMBoxTotalSize() );
       
  2842             length = iPosition - oldPosition;
       
  2843             length += 1; // quota token
       
  2844             iPosition = oldPosition;
       
  2845             iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxTotals, 1 );
       
  2846             iPosition++;
       
  2847             EncodeValueLength( length );
       
  2848             iEncodeBuffer->Write( iPosition, &KMmsMessageSizeToken, 1 );
       
  2849             iPosition++;
       
  2850             EncodeInteger( viewHeaders.MMBoxTotalSize() );
       
  2851             }
       
  2852 
       
  2853         // quotas
       
  2854         if ( viewHeaders.MMBoxQuotaNumber() != KMaxTUint32 )
       
  2855             {
       
  2856             oldPosition = iPosition;
       
  2857             EncodeInteger( viewHeaders.MMBoxQuotaNumber() );
       
  2858             length = iPosition - oldPosition;
       
  2859             length += 1; // quota token
       
  2860             iPosition = oldPosition;
       
  2861             iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxQuotas, 1 );
       
  2862             iPosition++;
       
  2863             EncodeValueLength( length );
       
  2864             iEncodeBuffer->Write( iPosition, &KMmsMessageCountToken, 1 );
       
  2865             iPosition++;
       
  2866             EncodeInteger( viewHeaders.MMBoxQuotaNumber() );
       
  2867             }
       
  2868 
       
  2869         if ( viewHeaders.MMBoxQuotaSize() != KMaxTUint32 )
       
  2870             {
       
  2871             oldPosition = iPosition;
       
  2872             EncodeInteger( viewHeaders.MMBoxQuotaSize() );
       
  2873             length = iPosition - oldPosition;
       
  2874             length += 1; // quota token
       
  2875             iPosition = oldPosition;
       
  2876             iEncodeBuffer->Write( iPosition, &KMmsAssignedMboxQuotas, 1 );
       
  2877             iPosition++;
       
  2878             EncodeValueLength( length );
       
  2879             iEncodeBuffer->Write( iPosition, &KMmsMessageSizeToken, 1 );
       
  2880             iPosition++;
       
  2881             EncodeInteger( viewHeaders.MMBoxQuotaSize() );
       
  2882             }
       
  2883 
       
  2884         // Message count
       
  2885         // This should in principle come from the viewHeaders.MmsMessageCount()
       
  2886         // But in this context the number of messages will be the number of
       
  2887         // attachments available in this entry
       
  2888 
       
  2889         // However, we will use the viewHeaders.MmsMessageCount() to generate
       
  2890         // the header so that we can test that the decoding part can handle
       
  2891         // possible conflict between message number and the number of parts
       
  2892         // in the multipart structure. This header is optional. KMaxTUint32
       
  2893         // will mean unspecified.
       
  2894 
       
  2895         if ( viewHeaders.MmsMessageCount() != KMaxTUint32 )
       
  2896             {
       
  2897             iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageCount, 1 );
       
  2898             iPosition++;
       
  2899             EncodeInteger( viewHeaders.MmsMessageCount() );
       
  2900             }
       
  2901         }
       
  2902 
       
  2903     if ( iNumberOfAttachments == 0 )
       
  2904         {
       
  2905         EncodeMandatoryByte( KMmsAssignedContentType, KMmsAssignedAny );
       
  2906         }
       
  2907     else
       
  2908         {
       
  2909         EncodeMultipartMixedHeaderL();
       
  2910         }
       
  2911 #endif
       
  2912     }
       
  2913 
       
  2914 // ---------------------------------------------------------
       
  2915 //
       
  2916 // ---------------------------------------------------------
       
  2917 //
       
  2918 void CMmsEncode::EncodeMMBoxUploadRequestL()
       
  2919     {
       
  2920     // Insert message type, TID and version number
       
  2921     EncodeStartingHeaders( KMmsMessageTypeMBoxUploadReq, iMmsHeaders->Tid(),
       
  2922         iMmsHeaders->MmsVersion() );
       
  2923 
       
  2924     // MMBox headers
       
  2925     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  2926         {
       
  2927         // X-Mms-MM-State
       
  2928         EncodeOptionalByte( KMmsAssignedMMState,
       
  2929             iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
       
  2930         // X-MMs-MM-Flags
       
  2931         // The keyword token should always be "add" or "remove"
       
  2932         EncodeKeywordArrayL();
       
  2933         }
       
  2934 
       
  2935     // Get Root TMsvId from headers if set
       
  2936     TMsvAttachmentId rootId = iMmsHeaders->MessageRoot();
       
  2937 
       
  2938     // Find the matching id from attachment list
       
  2939     
       
  2940     TInt error = KErrNone;
       
  2941     if ( iEntryWrapper )
       
  2942         {
       
  2943         CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  2944         CleanupStack::PushL( store );
       
  2945         // Only new attachment structure is supported    
       
  2946         MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  2947         TRAP( error,
       
  2948             {
       
  2949             CMsvAttachment* attachmentInfo = attachMan.GetAttachmentInfoL(
       
  2950                 (TMsvAttachmentId) rootId );
       
  2951             delete attachmentInfo; // we just wanted to check that it was found
       
  2952             }
       
  2953             );
       
  2954         CleanupStack::PopAndDestroy( store );
       
  2955         }
       
  2956     
       
  2957     // If we have a valid root part, we send the message as multipart/related.
       
  2958     // Otherwise we send it as multipart mixed.
       
  2959     // We don't try to guess what the root is supposed to be, if it
       
  2960     // is not specified or does not point to an existing attachment.
       
  2961 
       
  2962     // actually the content should be an MMS PDU as in M-MBox-Descr PDU
       
  2963     // It is unclear if if should be wrapped in a multipart structure 
       
  2964     // (containing only one header)
       
  2965     // or if the content type should be application/vnd.wap.mms-message
       
  2966     if ( error == KErrNone && rootId != 0 && iEntryWrapper )
       
  2967         {
       
  2968         EncodeMultipartRelatedHeaderL( rootId );
       
  2969         }
       
  2970     else
       
  2971         {
       
  2972         EncodeMultipartMixedHeaderL();
       
  2973         }
       
  2974 
       
  2975     }
       
  2976 
       
  2977 // ---------------------------------------------------------
       
  2978 //
       
  2979 // ---------------------------------------------------------
       
  2980 //
       
  2981 void CMmsEncode::EncodeMMBoxUploadConfirmationL()
       
  2982     {
       
  2983 // implemented for test purposes
       
  2984 #ifdef __WINS__
       
  2985     // Insert message type, TID and version number
       
  2986     EncodeStartingHeaders( KMmsMessageTypeMBoxUploadConf, iMmsHeaders->Tid(),
       
  2987         iMmsHeaders->MmsVersion() );
       
  2988 
       
  2989     // this must be USASCII or URL encoded
       
  2990     EncodeOptionalString( KMmsAssignedContentLocation,
       
  2991         iMmsHeaders->ContentLocation() );
       
  2992 
       
  2993     EncodeMandatoryByte( KMmsAssignedStoreStatus,
       
  2994         iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatus() );
       
  2995 
       
  2996     EncodeOptionalStringL( KMmsAssignedStoreStatusText,
       
  2997         iMmsHeaders->MMBoxMessageHeadersL().MmsStoreStatusText() );
       
  2998 #endif
       
  2999     }
       
  3000 
       
  3001 // ---------------------------------------------------------
       
  3002 //
       
  3003 // ---------------------------------------------------------
       
  3004 //
       
  3005 void CMmsEncode::EncodeDeleteRequestL()
       
  3006     {
       
  3007     // Insert message type, TID and version number
       
  3008     
       
  3009     EncodeStartingHeaders( iMmsHeaders->MessageType(), iMmsHeaders->Tid(),
       
  3010         iMmsHeaders->MmsVersion() );
       
  3011 
       
  3012     // Insert content location header. There may be more than one
       
  3013     EncodeContentLocationArray();
       
  3014     }
       
  3015 
       
  3016 // ---------------------------------------------------------
       
  3017 //
       
  3018 // ---------------------------------------------------------
       
  3019 //
       
  3020 void CMmsEncode::EncodeDeleteConfirmationL()
       
  3021     {
       
  3022 // implemented for test purposes
       
  3023 #ifdef __WINS__
       
  3024     // Insert message type, TID and version number
       
  3025     EncodeStartingHeaders( iMmsHeaders->MessageType(), iMmsHeaders->Tid(),
       
  3026         iMmsHeaders->MmsVersion() );
       
  3027 
       
  3028     // content location, response status and response text headers have
       
  3029     // different format from other PDUs
       
  3030 
       
  3031     const RPointerArray<CMmsDeleteResultArray>& resultArray = 
       
  3032         iMmsHeaders->DeleteResultArray();
       
  3033 
       
  3034     TInt i;
       
  3035     TInt length = 0;
       
  3036     TInt oldPosition = 0;
       
  3037     TUint oldIndex = KMaxTUint32;
       
  3038 
       
  3039     for ( i = 0; i < resultArray.Count(); i++ )
       
  3040         {
       
  3041         TUint index = resultArray[i]->Order();
       
  3042         if ( index != oldIndex )
       
  3043             {
       
  3044             // We add status and status text only once, there may be more
       
  3045             // than one content location with the same status
       
  3046             oldIndex = index;
       
  3047             if ( resultArray[i]->ResponseStatus() != 0 )
       
  3048                 {
       
  3049                 oldPosition = iPosition;
       
  3050                 length = 0;
       
  3051                 // Encode once just to find out field length
       
  3052                 EncodeInteger( index );
       
  3053                 length += iPosition - oldPosition;
       
  3054                 length ++; // response status is only one byte
       
  3055                 iPosition = oldPosition;
       
  3056                 // now we have calculated length, do the actual encoding
       
  3057                 iEncodeBuffer->Write( iPosition, &KMmsAssignedResponseStatus, 1 );
       
  3058                 iPosition++;
       
  3059                 EncodeValueLength( length );
       
  3060                 EncodeInteger( index );
       
  3061                 TUint8 value = (TUint8) resultArray[i]->ResponseStatus();
       
  3062                 iEncodeBuffer->Write( iPosition, &value, 1 );
       
  3063                 iPosition++;
       
  3064                 }
       
  3065             if ( resultArray[i]->ResponseText().Length() > 0 )
       
  3066                 {
       
  3067                 oldPosition = iPosition;
       
  3068                 length = 0;
       
  3069                 // Encode once just to find out field length
       
  3070                 EncodeInteger( index );
       
  3071                 EncodeTextStringL( resultArray[i]->ResponseText() );
       
  3072                 length += iPosition - oldPosition;
       
  3073                 iPosition = oldPosition;
       
  3074                 // now we have calculated length, do the actual encoding
       
  3075                 iEncodeBuffer->Write( iPosition, &KMmsAssignedResponseText, 1 );
       
  3076                 iPosition++;
       
  3077                 EncodeValueLength( length );
       
  3078                 EncodeInteger( index );
       
  3079                 EncodeTextStringL( resultArray[i]->ResponseText() );
       
  3080                 }
       
  3081             }
       
  3082         if ( resultArray[i]->ContentLocation().Length() > 0 )
       
  3083             {
       
  3084             oldPosition = iPosition;
       
  3085             length = 0;
       
  3086             // Encode once just to find out field length
       
  3087             EncodeInteger( index );
       
  3088             EncodeTextString( resultArray[i]->ContentLocation() );
       
  3089             length += iPosition - oldPosition;
       
  3090             iPosition = oldPosition;
       
  3091             // now we have calculated length, do the actual encoding
       
  3092             iEncodeBuffer->Write( iPosition, &KMmsAssignedContentLocation, 1 );
       
  3093             iPosition++;
       
  3094             EncodeValueLength( length );
       
  3095             EncodeInteger( index );
       
  3096             EncodeTextString( resultArray[i]->ContentLocation() );
       
  3097             }
       
  3098         }
       
  3099 #endif
       
  3100     }
       
  3101 
       
  3102 // ---------------------------------------------------------
       
  3103 //
       
  3104 // ---------------------------------------------------------
       
  3105 //
       
  3106 void CMmsEncode::EncodeMMBoxDescriptionL()
       
  3107     {
       
  3108 // implemented for test purposes
       
  3109 #ifdef __WINS__
       
  3110     EncodeMandatoryByte( KMmsAssignedMessageType, KMmsMessageTypeMBoxDescr );
       
  3111 
       
  3112     // this must be USASCII or URL encoded
       
  3113     EncodeOptionalString( KMmsAssignedContentLocation,
       
  3114         iMmsHeaders->ContentLocation() );
       
  3115 
       
  3116     EncodeOptionalString( KMmsAssignedMessageId, iMmsHeaders->MessageId() );
       
  3117 
       
  3118     // MMBox headers
       
  3119     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  3120         {
       
  3121         // X-Mms-MM-State
       
  3122         EncodeOptionalByte( KMmsAssignedMMState,
       
  3123             iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->MmsMMState() );
       
  3124         // X-MMs-MM-Flags
       
  3125         // The keyword token should always be "add" or "remove"
       
  3126         EncodeKeywordArrayL();
       
  3127         }
       
  3128 
       
  3129     // if we have set a date, insert it
       
  3130     EncodeDate( iMmsHeaders->Date() );
       
  3131     
       
  3132     // sender is optional
       
  3133     if ( iMmsHeaders->Sender().Length() > 0 )
       
  3134         {
       
  3135         EncodeSenderL( iMmsHeaders->Sender() );
       
  3136         }
       
  3137 
       
  3138     // All recipient lists. If no recipients in some of the lists,
       
  3139     // nothing is encoded, no need to check separately
       
  3140     EncodeRecipientL( iMmsHeaders->ToRecipients(), EMmsTo );
       
  3141     EncodeRecipientL( iMmsHeaders->CcRecipients(), EMmsCc );
       
  3142     EncodeRecipientL( iMmsHeaders->BccRecipients(), EMmsBcc );
       
  3143 
       
  3144     // Message class
       
  3145     EncodeOptionalByte( KMmsAssignedMessageClass,
       
  3146         iMmsHeaders->MessageClass() );
       
  3147 
       
  3148     // Subject
       
  3149     EncodeOptionalStringL( KMmsAssignedSubject, iMmsHeaders->Subject() );
       
  3150 
       
  3151     // Priority
       
  3152     EncodeOptionalByte( KMmsAssignedPriority, iMmsHeaders->MessagePriority() );
       
  3153     
       
  3154     // Delivery time
       
  3155     EncodeOptionalIntervalOrDate( KMmsAssignedDeliveryTime,
       
  3156         iMmsHeaders->DeliveryTimeInterval(),
       
  3157         iMmsHeaders->DeliveryDate() );
       
  3158 
       
  3159     // Expiration time
       
  3160     EncodeOptionalIntervalOrDate( KMmsAssignedExpiry,
       
  3161         iMmsHeaders->ExpiryInterval(),
       
  3162         iMmsHeaders->ExpiryDate() );
       
  3163 
       
  3164     // Delivery report
       
  3165     EncodeOptionalByte( KMmsAssignedDeliveryReport,
       
  3166         iMmsHeaders->DeliveryReport() );
       
  3167 
       
  3168     // Read reply
       
  3169     EncodeOptionalByte( KMmsAssignedReadReply, iMmsHeaders->ReadReply() );
       
  3170 
       
  3171     if ( iMmsHeaders->MessageSize() > 0 )
       
  3172         {
       
  3173         iEncodeBuffer->Write( iPosition, &KMmsAssignedMessageSize, 1 );
       
  3174         iPosition++;
       
  3175         TInt64 size = iMmsHeaders->MessageSize();
       
  3176         EncodeLongInteger( size );
       
  3177         }
       
  3178 
       
  3179     // MMBox description appears from 1.2 onwards - no use to check if we are
       
  3180     // 1.1 or later.
       
  3181     // Do we want to specify reply charging
       
  3182     if ( iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequested ||
       
  3183         iMmsHeaders->ReplyCharging() == KMmsReplyChargingRequestedTextOnly ||
       
  3184         iMmsHeaders->ReplyCharging() == KMmsReplyChargingAccepted ||
       
  3185         iMmsHeaders->ReplyCharging() == KMmsReplyChargingAcceptedTextOnly )
       
  3186         {
       
  3187         // Reply charging value
       
  3188         EncodeOptionalByte( KMmsAssignedReplyCharging,
       
  3189             iMmsHeaders->ReplyCharging() );
       
  3190         // Reply charging deadline
       
  3191         EncodeOptionalIntervalOrDate( KMmsAssignedReplyChargingDeadline,
       
  3192             iMmsHeaders->ReplyChargingInterval(),
       
  3193             iMmsHeaders->ReplyChargingDate() );
       
  3194         // Reply charging size
       
  3195         EncodeReplyChargingSize( iMmsHeaders->ReplyChargingSize() );
       
  3196         }
       
  3197     // Reply charging ID
       
  3198     EncodeOptionalString( KMmsAssignedReplyChargingID,
       
  3199         iMmsHeaders->ReplyChargingId() );
       
  3200 
       
  3201     TInt i;
       
  3202     TUint oldPosition;
       
  3203     TUint length;
       
  3204     for ( i = 0; i < iMmsHeaders->PreviouslySentList().Count(); ++i )
       
  3205         {
       
  3206         oldPosition = iPosition;
       
  3207         length = 0;
       
  3208         // Encode once just to find out field length
       
  3209         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  3210         EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
       
  3211         length += iPosition - oldPosition;
       
  3212         iPosition = oldPosition;
       
  3213         iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentBy, 1 );
       
  3214         iPosition++;
       
  3215         EncodeValueLength( length );
       
  3216         // now we have added length, do the actual encoding
       
  3217         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  3218         EncodeAddressL( iMmsHeaders->PreviouslySentList()[i]->Sender() );
       
  3219         oldPosition = iPosition;
       
  3220         length = 0;
       
  3221         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  3222         EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
       
  3223         length += iPosition - oldPosition;
       
  3224         iPosition = oldPosition;
       
  3225         iEncodeBuffer->Write( iPosition, &KMmsAssignedPreviouslySentDate, 1 );
       
  3226         iPosition++;
       
  3227         EncodeValueLength( length );
       
  3228         EncodeInteger( iMmsHeaders->PreviouslySentList()[i]->Order() );
       
  3229         EncodeLongInteger( iMmsHeaders->PreviouslySentList()[i]->Date() );
       
  3230         }
       
  3231 
       
  3232     if ( iNumberOfAttachments > 0 )
       
  3233         {
       
  3234         EncodeMultipartMixedHeaderL();
       
  3235         }
       
  3236 
       
  3237 #endif
       
  3238     }
       
  3239 
       
  3240 // ---------------------------------------------------------
       
  3241 // 8-bit version (no conversions)
       
  3242 // ---------------------------------------------------------
       
  3243 //
       
  3244 void CMmsEncode::EncodeTextString( const TDesC8& aString )
       
  3245     {
       
  3246     // Only Content-Id needs a quoted string, for example
       
  3247     // "<agjrfnjr>
       
  3248     // content-id encoding uses a separate function that adds the quote.
       
  3249     // EncodeQuotedTextString
       
  3250 
       
  3251     // Check if we need a Quote (This does not mean the quoted string.)
       
  3252     TInt length = aString.Length();
       
  3253     if ( length > 0 && aString[0] >= KMms0x80 )
       
  3254         {
       
  3255         iEncodeBuffer->Write( iPosition, &KMmsQuote, 1 );
       
  3256         iPosition++;
       
  3257         }
       
  3258 
       
  3259     iEncodeBuffer->Write( iPosition, aString, length );
       
  3260     iPosition += length;
       
  3261 
       
  3262     iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  3263     iPosition++;
       
  3264 
       
  3265     }
       
  3266 
       
  3267 // ---------------------------------------------------------
       
  3268 // 8-bit version (no conversions)
       
  3269 // ---------------------------------------------------------
       
  3270 //
       
  3271 void CMmsEncode::EncodeQuotedTextString( const TDesC8& aString )
       
  3272     {
       
  3273     // Before this function is called, the caller must check
       
  3274     // that the length of the string is not 0. Otherwise this
       
  3275     // makes no sense. You cannot quote a zero-length string
       
  3276 
       
  3277     // We need quoted string for content-id.
       
  3278     // So far for nothing else.
       
  3279     // (for the filename in MIME headers, too, just in case)
       
  3280 
       
  3281     // We add one quote to the beginning, nothing to the end.
       
  3282     // As we start with a quote, we don't need to check for the special
       
  3283     // Quote that is needed if a string starts with a character above 128
       
  3284     TInt length = aString.Length();
       
  3285     iEncodeBuffer->Write( iPosition, &KMmsStringQuote, 1 );
       
  3286     iPosition++;
       
  3287 
       
  3288     iEncodeBuffer->Write( iPosition, aString, length );
       
  3289     iPosition += length;
       
  3290 
       
  3291     iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  3292     iPosition++;
       
  3293 
       
  3294     }
       
  3295 
       
  3296 // ---------------------------------------------------------
       
  3297 // unicode version
       
  3298 // ---------------------------------------------------------
       
  3299 //
       
  3300 void CMmsEncode::EncodeTextStringL( const TDesC& aString )
       
  3301     {
       
  3302 
       
  3303     // What about a RFC2068 quoted strings - 
       
  3304     // see explanation in EncodeTextString( const TDesC8& aString ) function
       
  3305 
       
  3306     TInt i = 0;
       
  3307     TInt length = aString.Length();
       
  3308 
       
  3309     TBool safe = IsStringSafe( aString );
       
  3310 
       
  3311     // If the string can be encoded as ASCII, go ahead
       
  3312     if ( safe )
       
  3313         {
       
  3314         TUint8 character;
       
  3315         // No need to check if we need a quote - if we are safe, we have 
       
  3316         // no characters >= 128.
       
  3317 
       
  3318         for ( i = 0; i < aString.Length(); ++i )
       
  3319             {
       
  3320             character = TUint8( aString[i] & KMms0xFF );
       
  3321             iEncodeBuffer->Write( iPosition, &character, 1 );
       
  3322             iPosition++;
       
  3323             }
       
  3324         iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  3325         iPosition++;
       
  3326         }
       
  3327     else
       
  3328         {
       
  3329         // if our length is 0, we are safe, no need to check the 
       
  3330         // length here anymore
       
  3331         // we must convert to utf-8
       
  3332         
       
  3333         //one ucs-2 character should never produce more than 4 bytes when converted to utf-8
       
  3334         HBufC8* buffer = HBufC8::NewL( aString.Length() * KMms4 ); // paranoid.
       
  3335         // we don't leave while we need buffer
       
  3336         TPtr8 buf8 = buffer->Des();
       
  3337 
       
  3338         // if conversion fails, something is really seriously wrong
       
  3339         iError = CnvUtfConverter::ConvertFromUnicodeToUtf8( buf8, aString );
       
  3340 
       
  3341         length = buf8.Length();
       
  3342         // utf8 character set encoding needs one byte (fits into short integer)
       
  3343         length += KMms2; // add character set encoding byte and trailing NULL
       
  3344         
       
  3345         if ( buf8[0] >= KMms0x80 ) // 128
       
  3346             {
       
  3347             length++; // we will need a quote byte at the start...
       
  3348             }
       
  3349         
       
  3350         EncodeValueLength( length );
       
  3351 
       
  3352         // add one byte of character set
       
  3353         // this is a short integer, high bit must be set
       
  3354         TUint8 charset = KMmsUtf8 | KMms0x80;
       
  3355 
       
  3356         iEncodeBuffer->Write( iPosition, &charset, 1 );
       
  3357         iPosition++;
       
  3358 
       
  3359         // Check if we need a quote
       
  3360         if ( buf8[0] >= KMms0x80 ) // 128
       
  3361             {
       
  3362             iEncodeBuffer->Write( iPosition, &KMmsQuote, 1 );
       
  3363             iPosition++;
       
  3364             }
       
  3365         
       
  3366         // Then write the string itself
       
  3367         iEncodeBuffer->Write( iPosition, buf8, buf8.Length() );
       
  3368         iPosition += buf8.Length();
       
  3369 
       
  3370         // Add terminating NULL
       
  3371         iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  3372         iPosition++;
       
  3373 
       
  3374         delete buffer;
       
  3375         buffer = NULL;
       
  3376         }
       
  3377     
       
  3378     }
       
  3379 
       
  3380 // ---------------------------------------------------------
       
  3381 //
       
  3382 // ---------------------------------------------------------
       
  3383 //
       
  3384 void CMmsEncode::EncodeDate( const TInt64& aDate)
       
  3385     {
       
  3386 
       
  3387     if ( aDate == 0 )
       
  3388         {
       
  3389         return;
       
  3390         }
       
  3391 
       
  3392     iEncodeBuffer->Write( iPosition, &KMmsAssignedDate, 1 );
       
  3393     iPosition++;
       
  3394 
       
  3395     EncodeLongInteger( aDate );
       
  3396 
       
  3397     }
       
  3398 
       
  3399 // ---------------------------------------------------------
       
  3400 //
       
  3401 // ---------------------------------------------------------
       
  3402 //
       
  3403 void CMmsEncode::EncodeLongInteger( const TInt64& aLongInteger )
       
  3404     {
       
  3405 
       
  3406     TUint8 length = 0; // number of bytes we will need
       
  3407     // The long integer will take 8 bytes or less
       
  3408     TUint8 array[KMms8];
       
  3409 
       
  3410     TInt64 temp = aLongInteger;
       
  3411     TInt i = 0;
       
  3412     TInt64 reminder = 0;
       
  3413 
       
  3414     for ( i = 7; i >= 0; --i )
       
  3415         {
       
  3416         reminder = temp % 0x100;
       
  3417         temp = temp / 0x100;
       
  3418         array[i] = TInt8 ( I64INT( reminder ) ) ;
       
  3419         }
       
  3420 
       
  3421     length = KMms8;
       
  3422     i = 0;
       
  3423     // The array has 8 elements, so this is safe.
       
  3424     while( ( i < KMms8 ) && ( array[i] == 0 ) )
       
  3425         {
       
  3426         i++;
       
  3427         length--;
       
  3428         }
       
  3429 
       
  3430     // a zero should be coded as short integer.
       
  3431     // However, if there is a valid reason to code a zero as a long integer,
       
  3432     // we allow it. The caller should know what he is doing.
       
  3433     if ( length == 0 )
       
  3434         {
       
  3435         length = 1;
       
  3436         }
       
  3437 
       
  3438     // write short length
       
  3439     iEncodeBuffer->Write( iPosition, &length, 1 );
       
  3440     iPosition++;
       
  3441 
       
  3442     // write as many bytes as were non-zero
       
  3443     // array index will stay withing limits because of the way it was calculated
       
  3444     iEncodeBuffer->Write( iPosition, &(array[KMms8 - length] ), length );
       
  3445     iPosition+= length;
       
  3446 
       
  3447     }
       
  3448 
       
  3449 // ---------------------------------------------------------
       
  3450 //
       
  3451 // ---------------------------------------------------------
       
  3452 //
       
  3453 void CMmsEncode::EncodeInteger( TUint aInteger )
       
  3454     {
       
  3455     // KMms1 = 1
       
  3456     // KMms2 = 2
       
  3457     // KMms3 = 3
       
  3458     // KMms4 = 4
       
  3459     // KMms5 = 5
       
  3460     // etc.
       
  3461     
       
  3462     TUint8 byte = 0;
       
  3463 
       
  3464     if ( aInteger <= KMmsShortIntegerLimit127 )
       
  3465         {
       
  3466         byte = ( TInt8 ) aInteger;
       
  3467         byte |= KMms0x80;
       
  3468         iEncodeBuffer->Write( iPosition, &byte, 1);
       
  3469         iPosition++;
       
  3470         return; // this was easy
       
  3471         }
       
  3472 
       
  3473     TUint8 length = KMms4; // number of bytes we will need
       
  3474     TUint8 array[KMms4];
       
  3475 
       
  3476     TUint temp = aInteger;
       
  3477     byte = TInt8( ( temp >> KMms24 ) & KMms0xFF );
       
  3478 
       
  3479     while ( byte == 0 && length > 0 )
       
  3480         {
       
  3481         length--;
       
  3482         temp = temp << KMms8;
       
  3483         byte = TInt8( ( temp >> KMms24 ) & KMms0xFF );
       
  3484         }
       
  3485 
       
  3486     TUint i = 0;
       
  3487     for ( i = 0; i < length; ++i )
       
  3488         {
       
  3489         array[i] = TInt8( ( temp >> ( KMms8 * ( KMms3 - i ) ) ) & KMms0xFF );
       
  3490         }
       
  3491 
       
  3492     // write short length
       
  3493     iEncodeBuffer->Write( iPosition, &length, 1 );
       
  3494     iPosition++;
       
  3495 
       
  3496     // write as many bytes as were non-zero
       
  3497     // aInteger was tested in the beginning - it needs at least one byte
       
  3498     // So length is at least 1 and the array has been properly initialized.
       
  3499     iEncodeBuffer->Write( iPosition, &array[0], length );
       
  3500     iPosition+= length;
       
  3501 
       
  3502     }
       
  3503 
       
  3504 // ---------------------------------------------------------
       
  3505 //
       
  3506 // ---------------------------------------------------------
       
  3507 //
       
  3508 void CMmsEncode::EncodeSenderL( const TPtrC& aSender )
       
  3509     {
       
  3510     
       
  3511     iEncodeBuffer->Write( iPosition, &KMmsAssignedFrom, 1 );
       
  3512     iPosition++;
       
  3513 
       
  3514     // We must insert value length.
       
  3515 
       
  3516     if ( aSender.Length() == 0 )
       
  3517         {
       
  3518         // The MMSC must insert our address
       
  3519         TUint8 length;
       
  3520         length = 1;
       
  3521         iEncodeBuffer->Write( iPosition, &length, 1 );
       
  3522         iPosition++;
       
  3523         iEncodeBuffer->Write( iPosition, &KMmsInsertAddressToken, 1 );
       
  3524         iPosition++;
       
  3525         return;
       
  3526         }
       
  3527     
       
  3528     // Now we must insert something
       
  3529     TUint length = 1; // address present token
       
  3530 
       
  3531     if ( aSender.Find( KMiuMau ) != KErrNotFound )
       
  3532         {
       
  3533         TBool safe = IsStringSafe( aSender );
       
  3534         if ( safe )
       
  3535             {
       
  3536             // this was easy, just ASCII, no conversion
       
  3537             length += aSender.Length();
       
  3538             length ++; // room for terminating zero
       
  3539             }
       
  3540         else // not USASCII, charset must be specified
       
  3541             {
       
  3542             // worst case scenario.
       
  3543             // must be encoded as UTF-8, value length and character set
       
  3544             // must be added
       
  3545         
       
  3546             // one ucs-2 character will not produce more than 4 bytes when converted to utf-8
       
  3547             HBufC8* buffer = HBufC8::NewL( aSender.Length() * KMms4 ); // paranoid.
       
  3548             // we don't need to push buffer onto cleanup stack, as we don't
       
  3549             // leave while we are using it
       
  3550             TPtr8 buf8 = buffer->Des();
       
  3551 
       
  3552             // if we get error here, something is badly wrong
       
  3553             iError = CnvUtfConverter::ConvertFromUnicodeToUtf8( buf8, aSender );
       
  3554 
       
  3555             length += buf8.Length();
       
  3556             // utf8 character set encoding needs one byte (short integer)
       
  3557             length += KMms2; // add character set encoding byte and trailing NULL
       
  3558         
       
  3559             if ( buf8[0] >= KMms0x80 ) // 128
       
  3560                 {
       
  3561                 length++; // we will need a quote byte at the start...
       
  3562                 }
       
  3563             delete buffer;
       
  3564             buffer = NULL;
       
  3565             }
       
  3566         }
       
  3567     else // no miumau found
       
  3568         {
       
  3569         // phone number, must be ASCII
       
  3570         length += aSender.Length();
       
  3571         length ++; // room for terminating zero
       
  3572         length += KMmsPlmnLength; // type indication
       
  3573         // this should be the length, if we have a phone number (no alias.)
       
  3574         }
       
  3575 
       
  3576     EncodeValueLength( length );
       
  3577 
       
  3578     iEncodeBuffer->Write( iPosition, &KMmsAddressPresentToken, 1 );
       
  3579     iPosition++;
       
  3580 
       
  3581     // If the address contains some non-ascii characters,
       
  3582     // it must be converted to utf-8
       
  3583     
       
  3584     EncodeAddressL( aSender );
       
  3585 
       
  3586     }
       
  3587 
       
  3588 // ---------------------------------------------------------
       
  3589 //
       
  3590 // ---------------------------------------------------------
       
  3591 //
       
  3592 void CMmsEncode::EncodeAddressL( const TPtrC& aAddress )
       
  3593     {
       
  3594     // Supports only address types PLMN and email.
       
  3595     // If the address string contains a @ character,
       
  3596     // it is interpreted as an email
       
  3597 
       
  3598     // Internal alias is removed
       
  3599 
       
  3600     TMmsAddressType addressType = EMmsAddressTypeUnknown;
       
  3601     HBufC* realAddress = HBufC::NewL( aAddress.Length() );
       
  3602     CleanupStack::PushL( realAddress );
       
  3603 
       
  3604     TInt error = KErrNone;
       
  3605 
       
  3606     TPtr realAddressPointer = realAddress->Des();
       
  3607     error = TMmsGenUtils::AddressTypeAndRealAddress(
       
  3608         aAddress,
       
  3609         addressType,
       
  3610         realAddressPointer,
       
  3611         aAddress.Length());
       
  3612 
       
  3613     if ( error != KErrNone || addressType == EMmsAddressTypeUnknown )
       
  3614         {
       
  3615         // could not resolve. Send unchanged
       
  3616         realAddress->Des().Copy( aAddress );
       
  3617         if ( aAddress.Find( KMiuMau ) != KErrNotFound )
       
  3618             {
       
  3619             addressType = EMmsAddressTypeEmail;
       
  3620             }
       
  3621         else
       
  3622             {
       
  3623             addressType = EMmsAddressTypeMobile;
       
  3624             }
       
  3625         }
       
  3626         
       
  3627     if ( addressType == EMmsAddressTypeEmail )
       
  3628         {
       
  3629         // email address
       
  3630         // If the address contains only ASCII characters,
       
  3631         // it can be sent as text string, if not, it must be sent as utf-8
       
  3632 
       
  3633         EncodeTextStringL( *realAddress );
       
  3634 
       
  3635         }
       
  3636     else
       
  3637         {
       
  3638         // must be a phone number
       
  3639         // We expect for now that the format is correct as is
       
  3640         // All legal characters present in a phone number are ASCII
       
  3641 
       
  3642         TInt i = 0;
       
  3643         TUint8 character = 0;
       
  3644         realAddressPointer = realAddress->Des();
       
  3645         for ( i = 0; i < realAddress->Length(); ++i )
       
  3646             {
       
  3647             // The array index is safe because i is always < realAddress->Length().
       
  3648             character = TUint8( realAddressPointer[i] & KMms0xFF );
       
  3649             iEncodeBuffer->Write( iPosition, &character, 1 );
       
  3650             iPosition++;
       
  3651             }
       
  3652         iEncodeBuffer->Write( iPosition, KMmsPlmn, KMmsPlmnLength );
       
  3653         iPosition += KMmsPlmnLength;
       
  3654         iEncodeBuffer->Write( iPosition, &KMmsNull, 1 );
       
  3655         iPosition++;
       
  3656         }
       
  3657     CleanupStack::PopAndDestroy( realAddress );
       
  3658 
       
  3659     }
       
  3660 
       
  3661 // ---------------------------------------------------------
       
  3662 //
       
  3663 // ---------------------------------------------------------
       
  3664 //
       
  3665 void CMmsEncode::EncodeValueLength( TUint aLength )
       
  3666     {
       
  3667 
       
  3668     TUint8 shortLength = 0;
       
  3669 
       
  3670     if ( aLength <= KMms30 )
       
  3671         {
       
  3672         // short length
       
  3673         shortLength = TUint8( aLength ) ;
       
  3674         iEncodeBuffer->Write( iPosition, &shortLength, 1 );
       
  3675         iPosition++;
       
  3676         }
       
  3677     else
       
  3678         {
       
  3679         iEncodeBuffer->Write( iPosition, &KMmsLengthQuote, 1 );
       
  3680         iPosition++;
       
  3681         EncodeUintvar( aLength );
       
  3682         }
       
  3683 
       
  3684     }
       
  3685 
       
  3686 // ---------------------------------------------------------
       
  3687 //
       
  3688 // ---------------------------------------------------------
       
  3689 //
       
  3690 void CMmsEncode::EncodeUintvar( TUint aInteger )
       
  3691     {
       
  3692 
       
  3693     // The value is split into 7 bit chunks, and continue bit set
       
  3694     // when needed.
       
  3695 
       
  3696     // No more than 5 bytes will be produced
       
  3697     TUint8 buffer[KMms5];
       
  3698     TUint temp = aInteger;
       
  3699     TInt i;
       
  3700 
       
  3701     for ( i = 0; i < KMms5; ++i )            
       
  3702         {
       
  3703         buffer[KMms4 - i] = TUint8( temp & KMms0x7F );
       
  3704         temp >>= KMms7;
       
  3705         }
       
  3706 
       
  3707     i = 0;
       
  3708     // buffer indexes are safe because the buffer has been defined long enough.
       
  3709     while ( i < KMms4 && buffer[i] == 0 )
       
  3710         {
       
  3711         i++;
       
  3712         }
       
  3713     
       
  3714     TInt j;
       
  3715 
       
  3716     for ( j = i; j < KMms4; ++j )
       
  3717         {
       
  3718         // buffer indexes are safe because the buffer has been defined long enough.
       
  3719         buffer[j] |= KMms0x80; // set Continue bit, but never to last
       
  3720         }
       
  3721 
       
  3722     // buffer indexes are safe because the buffer has been defined long enough.
       
  3723     iEncodeBuffer->Write( iPosition, &buffer[i], KMms5 - i );
       
  3724     iPosition += KMms5 - i;
       
  3725 
       
  3726     }
       
  3727 
       
  3728 // ---------------------------------------------------------
       
  3729 //
       
  3730 // ---------------------------------------------------------
       
  3731 //
       
  3732 TInt CMmsEncode::GetUintvarLength( TUint aInteger )
       
  3733     {
       
  3734 
       
  3735     // The value is split into 7 bit chunks, and continue bit set
       
  3736     // when needed.
       
  3737 
       
  3738     // No more than 5 bytes will be produced
       
  3739     TUint8 buffer[KMms5];
       
  3740     TUint temp = aInteger;
       
  3741     TInt i;
       
  3742 
       
  3743     for (i = 0; i < KMms5; ++i )            
       
  3744         {
       
  3745         buffer[KMms4 - i] = TUint8( temp & KMms0x7F );
       
  3746         temp >>= KMms7;
       
  3747         }
       
  3748 
       
  3749     i = 0;
       
  3750     // buffer indexes are safe because the buffer has been defined long enough.
       
  3751     while ( i < KMms4 && buffer[i] == 0 )
       
  3752         {
       
  3753         i++;
       
  3754         }
       
  3755     
       
  3756     return KMms5 - i;
       
  3757 
       
  3758     }
       
  3759 
       
  3760 // ---------------------------------------------------------
       
  3761 //
       
  3762 // ---------------------------------------------------------
       
  3763 //
       
  3764 void CMmsEncode::EncodeRecipientL( const CDesCArray& aRecipientList,
       
  3765     TMmsRecipients aType )
       
  3766     {
       
  3767 
       
  3768     TInt i;
       
  3769     TInt size = aRecipientList.Count();
       
  3770     if ( size == 0 )
       
  3771         {
       
  3772         return;
       
  3773         }
       
  3774 
       
  3775     TUint8 recipientType = KMmsAssignedTo;
       
  3776 
       
  3777     switch ( aType )
       
  3778         {
       
  3779         case EMmsTo:
       
  3780             recipientType = KMmsAssignedTo;
       
  3781             break;
       
  3782         case EMmsCc:
       
  3783             recipientType = KMmsAssignedCc;
       
  3784             break;
       
  3785         case EMmsBcc:
       
  3786             recipientType = KMmsAssignedBcc;
       
  3787             break;
       
  3788         default:
       
  3789             break;
       
  3790         }
       
  3791 
       
  3792     for ( i = 0; i < size; ++i )
       
  3793         {
       
  3794         // check for fakes
       
  3795         if ( aRecipientList[i].Length() > 0 )
       
  3796             {
       
  3797             iEncodeBuffer->Write( iPosition, &recipientType, 1 );
       
  3798             iPosition++;
       
  3799 
       
  3800             EncodeAddressL( aRecipientList[i] );
       
  3801             }
       
  3802 
       
  3803         }
       
  3804 
       
  3805     }
       
  3806 
       
  3807 // ---------------------------------------------------------
       
  3808 //
       
  3809 // ---------------------------------------------------------
       
  3810 //
       
  3811 void CMmsEncode::EncodeOptionalStringL( TUint8 aHeader,
       
  3812     const TPtrC16& aString )
       
  3813     {
       
  3814 
       
  3815     if ( aString.Length() == 0 )
       
  3816         {
       
  3817         return;
       
  3818         }
       
  3819 
       
  3820     iEncodeBuffer->Write( iPosition, &aHeader, 1 );
       
  3821     iPosition++;
       
  3822 
       
  3823     EncodeTextStringL( aString );
       
  3824 
       
  3825     }
       
  3826 
       
  3827 // ---------------------------------------------------------
       
  3828 //
       
  3829 // ---------------------------------------------------------
       
  3830 //
       
  3831 void CMmsEncode::EncodeOptionalString( TUint8 aHeader, const TPtrC8& aString )
       
  3832     {
       
  3833 
       
  3834     if ( aString.Length() == 0 )
       
  3835         {
       
  3836         return;
       
  3837         }
       
  3838 
       
  3839     EncodeHeaderAndTextString( aHeader, aString );
       
  3840 
       
  3841     }
       
  3842 
       
  3843 // ---------------------------------------------------------
       
  3844 //
       
  3845 // ---------------------------------------------------------
       
  3846 //
       
  3847 void CMmsEncode::EncodeIntervalOrDate( TInt aInterval, const TInt64& aDate )
       
  3848     {
       
  3849 
       
  3850     TInt64 temp = 0;
       
  3851     TUint8 token = 0;
       
  3852 
       
  3853     if ( aDate != 0 )
       
  3854         {
       
  3855         temp = aDate;
       
  3856         token = KMmsAbsoluteToken;
       
  3857         }
       
  3858     else
       
  3859         {
       
  3860         temp = aInterval;
       
  3861         token = KMmsRelativeToken;
       
  3862         }
       
  3863 
       
  3864     // calculate value length
       
  3865 
       
  3866     TUint length = KMms8;
       
  3867     TUint mask = 0xff000000;
       
  3868 
       
  3869     while ( ( I64HIGH( temp ) & mask ) == 0 && length > KMms4)
       
  3870         {
       
  3871         mask >>= KMms8;
       
  3872         length--;
       
  3873         }
       
  3874 
       
  3875     mask = 0xff000000;
       
  3876 
       
  3877     // Test if the whole high half was zero
       
  3878     if ( I64HIGH( temp ) == 0 )
       
  3879         {
       
  3880         while ( ( I64LOW( temp ) & mask ) == 0 && length > 1)
       
  3881             {
       
  3882             mask >>= KMms8;
       
  3883             length--;
       
  3884             }   
       
  3885         }
       
  3886 
       
  3887     // now add short length and absolute/relative token
       
  3888 
       
  3889     length += KMms2;
       
  3890 
       
  3891     EncodeValueLength( length );
       
  3892 
       
  3893     iEncodeBuffer->Write( iPosition, &token, 1 );
       
  3894     iPosition++;
       
  3895 
       
  3896     EncodeLongInteger( temp );
       
  3897 
       
  3898     }
       
  3899 
       
  3900 // ---------------------------------------------------------
       
  3901 //
       
  3902 // ---------------------------------------------------------
       
  3903 //
       
  3904 void CMmsEncode::EncodeReplyChargingSize( TInt aReplyChargingSize )
       
  3905     {
       
  3906     if ( aReplyChargingSize == 0 )
       
  3907         {
       
  3908         return;
       
  3909         }
       
  3910     TInt64 size = aReplyChargingSize;
       
  3911     iEncodeBuffer->Write( iPosition, &KMmsAssignedReplyChargingSize, 1 );
       
  3912     iPosition++;
       
  3913 
       
  3914     EncodeLongInteger( size );
       
  3915     }
       
  3916 
       
  3917 // ---------------------------------------------------------
       
  3918 //
       
  3919 // ---------------------------------------------------------
       
  3920 //
       
  3921 void CMmsEncode::EncodeOptionalByte( TUint8 aHeader, TInt aValue )
       
  3922     {
       
  3923     if ( aValue == 0 )
       
  3924         {
       
  3925         return; // not set, nothing to encode, header is optional
       
  3926         }
       
  3927     EncodeMandatoryByte( aHeader, aValue );
       
  3928 
       
  3929     }
       
  3930 
       
  3931 // ---------------------------------------------------------
       
  3932 //
       
  3933 // ---------------------------------------------------------
       
  3934 //
       
  3935 void CMmsEncode::EncodeMandatoryByte( TUint8 aHeader, TInt aValue )
       
  3936     {
       
  3937     // When ecoding mandatory byte even value 0 is allowed.
       
  3938     // It will become 0x80, and be correctly decoded back to 0.
       
  3939     TUint8 value = TUint8 ( aValue ) | KMms0x80 ;
       
  3940 
       
  3941     iEncodeBuffer->Write( iPosition, &aHeader, 1 );
       
  3942     iPosition++;
       
  3943 
       
  3944     iEncodeBuffer->Write( iPosition, &value, 1 );
       
  3945     iPosition++;
       
  3946     }
       
  3947 
       
  3948 
       
  3949 // ---------------------------------------------------------
       
  3950 //
       
  3951 // ---------------------------------------------------------
       
  3952 //
       
  3953 void CMmsEncode::EncodeOptionalIntervalOrDate( TUint8 aHeader,
       
  3954             TInt aInterval,
       
  3955             const TInt64& aDate )
       
  3956     {
       
  3957     if ( aInterval == 0 && aDate == 0 )
       
  3958         {
       
  3959         return; // not set, nothing to encode, header is optional
       
  3960         }
       
  3961 
       
  3962     iEncodeBuffer->Write( iPosition, &aHeader, 1 );
       
  3963     iPosition++;
       
  3964 
       
  3965     EncodeIntervalOrDate( aInterval, aDate );
       
  3966     }
       
  3967 
       
  3968 // ---------------------------------------------------------
       
  3969 //
       
  3970 // ---------------------------------------------------------
       
  3971 //
       
  3972 void CMmsEncode::EncodeHeaderAndTextString( TUint8 aHeader,
       
  3973     const TDesC8& aString )
       
  3974     {
       
  3975 
       
  3976     iEncodeBuffer->Write( iPosition, &aHeader, 1 );
       
  3977     iPosition++;
       
  3978 
       
  3979     EncodeTextString( aString );
       
  3980 
       
  3981     }
       
  3982 
       
  3983 
       
  3984 // ---------------------------------------------------------
       
  3985 //
       
  3986 // ---------------------------------------------------------
       
  3987 //
       
  3988 TBool CMmsEncode::IsStringSafe( const TDesC& aString )
       
  3989     {
       
  3990 
       
  3991     // Very simple check to see if string is "safe" ASCII
       
  3992     // Used for headers, which are short strings
       
  3993 
       
  3994     TInt i;
       
  3995     TBool safe = ETrue;
       
  3996 
       
  3997     for ( i = 0; i < aString.Length() && safe; ++i )
       
  3998         {
       
  3999         if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii )
       
  4000             {
       
  4001             safe = EFalse;
       
  4002             }
       
  4003         }
       
  4004     return safe;
       
  4005 
       
  4006     }
       
  4007 
       
  4008 // ---------------------------------------------------------
       
  4009 //
       
  4010 // ---------------------------------------------------------
       
  4011 //
       
  4012 TBool CMmsEncode::IsStringSafe( const TDesC8& aString, TInt& aNumNonSafe  )
       
  4013     {
       
  4014 
       
  4015     // Very simple check to see if string is "safe" ASCII
       
  4016     // Used for headers, which are short strings
       
  4017     // spaces count as non-safe because their number must be taken into
       
  4018     // account when calculating the length
       
  4019 
       
  4020     const TInt KIntQuestion = 0x3F;
       
  4021     const TInt KIntEquals = 0x3D;
       
  4022     
       
  4023     TInt i;
       
  4024     aNumNonSafe = 0;
       
  4025     TBool safe = ETrue;
       
  4026 
       
  4027     for ( i = 0; i < aString.Length()/* && safe*/; ++i )
       
  4028         {
       
  4029         if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii )
       
  4030             {
       
  4031             safe = EFalse;
       
  4032             aNumNonSafe++;
       
  4033             }
       
  4034         if ( aString[i] == KIntQuestion || aString[i] == KIntEquals )
       
  4035             {
       
  4036             // These are safe but must be encoded if quoted printable
       
  4037             // encoding is used. The number is needed to check the header length
       
  4038             aNumNonSafe++;
       
  4039             }
       
  4040         if ( aString[i] == KMmsIntUnderscore )
       
  4041             {
       
  4042             // This must always be encoded as base64 because Symbian
       
  4043             // does not encode underscores when quoted printable is used.
       
  4044             aNumNonSafe = KMaxEncodingLength;
       
  4045             }
       
  4046         
       
  4047         }
       
  4048     return safe;
       
  4049 
       
  4050     }
       
  4051 
       
  4052 // ---------------------------------------------------------
       
  4053 //
       
  4054 // ---------------------------------------------------------
       
  4055 //
       
  4056 void CMmsEncode::EncodeMultipartRelatedHeaderL( const TMsvAttachmentId aRootId )
       
  4057     {
       
  4058 
       
  4059     iEncodeBuffer->Write( iPosition, &KMmsAssignedContentType, 1 );
       
  4060     iPosition++;
       
  4061 
       
  4062     // We have parameters (start), so we must use Content-general-form
       
  4063 
       
  4064     // We need the content-id for the root part. If it is not defined already,
       
  4065     // we must generate one.
       
  4066 
       
  4067     TUint headerLength = 1; // one byte for well known media
       
  4068     TInt cleanupCount = 0; // we must keep track what we have on store
       
  4069 
       
  4070     User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iCurrentMessageId ) );
       
  4071         
       
  4072     CMsvStore* store = iEntryWrapper->EditStoreL();
       
  4073     CleanupStack::PushL( store ); cleanupCount++;
       
  4074     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  4075     CMsvAttachment* attachmentInfo = NULL;
       
  4076     attachmentInfo = attachMan.GetAttachmentInfoL( (TMsvAttachmentId) aRootId );
       
  4077     CleanupStack::PushL( attachmentInfo ); cleanupCount++;
       
  4078     
       
  4079     iMimeHeaders->RestoreL( *attachmentInfo );
       
  4080 
       
  4081     if ( iError != KErrNone )
       
  4082         {
       
  4083         CleanupStack::PopAndDestroy( cleanupCount ); 
       
  4084         return;
       
  4085         }
       
  4086 
       
  4087     TPtrC8 cid = iMimeHeaders->ContentId();
       
  4088     TBufC8<KMmsMaxCidLength> target;
       
  4089 
       
  4090     // If cid has not been defined, we must generate one
       
  4091     if ( cid.Length() == 0 )
       
  4092         {
       
  4093         TTime now;
       
  4094         now.UniversalTime();
       
  4095         TInt random;
       
  4096         TInt64 seed = now.Int64();
       
  4097         random = Math::Rand( seed );
       
  4098         // type conversions irrelevant - just creating a magic number for content id
       
  4099         target.Des().Num( random );
       
  4100         target.Des().Insert(0, KMmsLeftAngle );
       
  4101         target.Des().Append( KMmsRightAngle );
       
  4102         cid.Set( target.Des() );
       
  4103         // exclude the angle brackets
       
  4104         iMimeHeaders->SetContentIdL( cid.Mid( 1, cid.Length() - KMms2 ) );
       
  4105         // save the cid to be present when we create the attachment headers
       
  4106         // If this does not succeed, the message will have no root.
       
  4107         MMsvAttachmentManagerSync& attachManSync = 
       
  4108             store->AttachmentManagerExtensionsL();
       
  4109         iMimeHeaders->StoreL( *attachmentInfo );
       
  4110         attachManSync.ModifyAttachmentInfoL( attachmentInfo );
       
  4111         // attachment manager now own attachemnt info
       
  4112         CleanupStack::Pop( attachmentInfo ); cleanupCount--;
       
  4113         store->CommitL();
       
  4114         attachmentInfo = attachMan.GetAttachmentInfoL( (TMsvAttachmentId) aRootId );
       
  4115         CleanupStack::PushL( attachmentInfo ); cleanupCount++;
       
  4116         }
       
  4117 
       
  4118     // add start header length &
       
  4119     // assigned number for start parameter, and terminating zero for cid
       
  4120     headerLength += cid.Length() + KMms2;
       
  4121     if ( cid.Find( KMmsLeftAngle ) != 0 )
       
  4122         {
       
  4123         headerLength += KMms2; // we must add angle bracket
       
  4124         }
       
  4125 
       
  4126     // Then the length of the content-type header...
       
  4127     TPtrC8 contentTypeString = iMimeHeaders->ContentType();
       
  4128     
       
  4129      HBufC8* tempContentType = HBufC8::NewL( iMimeHeaders->ContentType().Length() +
       
  4130          iMimeHeaders->ContentSubType().Length() + 1 );
       
  4131      CleanupStack::PushL( tempContentType );
       
  4132      tempContentType->Des().Copy( iMimeHeaders->ContentType() );
       
  4133      if ( ( iMimeHeaders->ContentType().Find( KMmsSlash8 ) !=
       
  4134         ( iMimeHeaders->ContentType().Length() - 1 ) ) &&
       
  4135         ( iMimeHeaders->ContentSubType().Find( KMmsSlash8 ) != 0 ) &&
       
  4136         ( iMimeHeaders->ContentSubType().Length() != 0 ) )
       
  4137         {
       
  4138         tempContentType->Des().Append( KMmsSlash8 );
       
  4139         }
       
  4140     tempContentType->Des().Append( iMimeHeaders->ContentSubType() );
       
  4141     attachmentInfo->SetMimeTypeL( tempContentType->Des() );
       
  4142     CleanupStack::PopAndDestroy( tempContentType );
       
  4143     contentTypeString.Set( attachmentInfo->MimeType() );
       
  4144 
       
  4145     if ( contentTypeString.Length() == 0 )
       
  4146         {
       
  4147         // We need a content type...
       
  4148         // If we don't know, we say "Any"
       
  4149         contentTypeString.Set( KMmsAny );
       
  4150         }
       
  4151     // Check if we have well-known media.
       
  4152     TInt8 rootContentType = -1;
       
  4153 
       
  4154     TInt8 i = 0;
       
  4155     for ( i = 0; i < KNumberContentTypes && rootContentType < 0; ++i )
       
  4156         {
       
  4157         if ( contentTypeString.CompareF( TPtrC8( KContentTypeTable[i] ) ) == 0 )
       
  4158             {
       
  4159             rootContentType = i;
       
  4160             }
       
  4161         }
       
  4162         
       
  4163     // start parameter assignment
       
  4164     headerLength += 1;
       
  4165     if ( rootContentType != -1 )
       
  4166         {
       
  4167         // well known content type
       
  4168         headerLength += 1;
       
  4169         }
       
  4170     else
       
  4171         {
       
  4172         // string + terminating zero
       
  4173         headerLength += contentTypeString.Length() + 1;
       
  4174         }
       
  4175         
       
  4176     TPtrC8 appIdPtr;
       
  4177     appIdPtr.Set( KMmsJavaApplicationId ); 
       
  4178     // Java application id parameters added to content-type        
       
  4179     if ( iMmsHeaders->ApplicId().Length() > 0 )
       
  4180         {
       
  4181         headerLength += appIdPtr.Length() + 1 ;
       
  4182         headerLength += iMmsHeaders->ApplicId().Length() + 1;
       
  4183         }
       
  4184     appIdPtr.Set( KMmsJavaReplyApplicationId );    
       
  4185     if ( iMmsHeaders->ReplyApplicId().Length() > 0 )
       
  4186         {
       
  4187         headerLength += appIdPtr.Length() + 1 ;
       
  4188         headerLength += iMmsHeaders->ReplyApplicId().Length() + 1;
       
  4189         }
       
  4190 
       
  4191     // write general encoding length
       
  4192     EncodeValueLength( headerLength );
       
  4193 
       
  4194     // Then the Media Type with parameters
       
  4195         
       
  4196     // We are multipart/related, which is a well-known media
       
  4197     // encode as short integer
       
  4198     TUint8 byte = KMmsAssignedApplicationVndWapMultipartRelated | KMms0x80;
       
  4199     iEncodeBuffer->Write( iPosition, &byte, 1 );
       
  4200     iPosition++;
       
  4201 
       
  4202     // Then the start parameter and cid text string
       
  4203     byte = KWspStart | KMms0x80;
       
  4204     
       
  4205     if ( cid.Length() > 0 )
       
  4206         {
       
  4207         HBufC8* tempContentId = HBufC8::NewL( iMimeHeaders->ContentId().Length() + KMms2 );
       
  4208         CleanupStack::PushL( tempContentId );
       
  4209         if ( cid.Find( KMmsLeftAngle ) != 0 )
       
  4210             {
       
  4211             tempContentId->Des().Copy( KMmsLeftAngle );
       
  4212             tempContentId->Des().Append( cid );
       
  4213             tempContentId->Des().Append( KMmsRightAngle );
       
  4214             }
       
  4215         else
       
  4216             {
       
  4217             tempContentId->Des().Copy( cid );
       
  4218             }
       
  4219         EncodeHeaderAndTextString( byte, tempContentId->Des() );
       
  4220         CleanupStack::PopAndDestroy( tempContentId );
       
  4221         }
       
  4222 
       
  4223 
       
  4224     // next the content type of the root part
       
  4225     byte = KWspRelatedType | KMms0x80;
       
  4226     // and the actual type either as a well-known media type
       
  4227     // or a text string.
       
  4228 
       
  4229     if ( rootContentType != -1 )
       
  4230         {
       
  4231         // Well known content type.
       
  4232         // EncodeMandatoryByte will set the high bit
       
  4233         EncodeMandatoryByte( byte, rootContentType );
       
  4234         }
       
  4235     else
       
  4236         {
       
  4237         // string + terminating zero
       
  4238         EncodeHeaderAndTextString( byte, contentTypeString );
       
  4239         }
       
  4240        
       
  4241     if ( iMmsHeaders->ApplicId().Length() > 0 ||
       
  4242         iMmsHeaders->ReplyApplicId().Length() > 0 )
       
  4243         {
       
  4244         EncodeApplicationIdParametersL();
       
  4245         }
       
  4246             
       
  4247     // encode number of parts
       
  4248     EncodeUintvar( iNumberOfAttachments );
       
  4249     
       
  4250     // get rid of stuff we put on stack
       
  4251     CleanupStack::PopAndDestroy( cleanupCount ); 
       
  4252     }
       
  4253 
       
  4254 // ---------------------------------------------------------
       
  4255 //
       
  4256 // ---------------------------------------------------------
       
  4257 //
       
  4258 void CMmsEncode::EncodeMultipartMixedHeaderL()
       
  4259     {
       
  4260     
       
  4261     // If Java has added application id or reply-to application id, 
       
  4262     // even multipart/mxed type needs parameters.
       
  4263     
       
  4264     TUint headerLength = 0; // assume no parameters
       
  4265     
       
  4266     if ( iMmsHeaders->ApplicId().Length() > 0 ||
       
  4267         iMmsHeaders->ReplyApplicId().Length() > 0 )
       
  4268         {
       
  4269         headerLength = 1; // one byte for well known media
       
  4270         TPtrC8 appIdPtr;
       
  4271         appIdPtr.Set( KMmsJavaApplicationId ); 
       
  4272         if ( iMmsHeaders->ApplicId().Length() > 0 )
       
  4273             {
       
  4274             headerLength += appIdPtr.Length() + 1 ;
       
  4275             headerLength += iMmsHeaders->ApplicId().Length() + 1;
       
  4276             }
       
  4277         appIdPtr.Set( KMmsJavaReplyApplicationId );    
       
  4278         if ( iMmsHeaders->ReplyApplicId().Length() > 0 )
       
  4279             {
       
  4280             headerLength += appIdPtr.Length() + 1 ;
       
  4281             headerLength += iMmsHeaders->ReplyApplicId().Length() + 1;
       
  4282             }
       
  4283         }
       
  4284 
       
  4285     iEncodeBuffer->Write( iPosition, &KMmsAssignedContentType, 1 );
       
  4286     iPosition++;
       
  4287     
       
  4288     if ( headerLength > 0 )
       
  4289         {
       
  4290         // write general encoding length
       
  4291         EncodeValueLength( headerLength );
       
  4292         }
       
  4293 
       
  4294     // encode as short integer
       
  4295     TUint8 contentType = KMmsAssignedApplicationVndWapMultipartMixed | KMms0x80;
       
  4296     iEncodeBuffer->Write( iPosition, &contentType, 1 );
       
  4297     iPosition++;
       
  4298 
       
  4299     if ( iMmsHeaders->ApplicId().Length() > 0 ||
       
  4300         iMmsHeaders->ReplyApplicId().Length() > 0 )
       
  4301         {
       
  4302         EncodeApplicationIdParametersL();
       
  4303         }
       
  4304 
       
  4305     // No more parameters for multipart/mixed, actual parts follow
       
  4306 
       
  4307     // encode number of parts
       
  4308     EncodeUintvar( iNumberOfAttachments );
       
  4309     
       
  4310     }
       
  4311 
       
  4312 // ---------------------------------------------------------
       
  4313 //
       
  4314 // ---------------------------------------------------------
       
  4315 //
       
  4316 void CMmsEncode::EncodeKeywordArrayL()
       
  4317     {
       
  4318     TInt i = 0;
       
  4319     TInt length = 0;
       
  4320 
       
  4321     // caller must check that iMmsHeaders->ReadOnlyMMBoxMessageHeaders() is not NULL
       
  4322     CMmsMMBoxMessageHeaders& temp = iMmsHeaders->MMBoxMessageHeadersL();
       
  4323     for ( i = 0; i < temp.KeywordArray().Count(); ++i )
       
  4324         {
       
  4325         length = temp.KeywordArray()[i]->Keyword().Length();
       
  4326         if ( length > 0 )
       
  4327             {
       
  4328             iEncodeBuffer->Write( iPosition, &KMmsAssignedMMFlags, 1 );
       
  4329             iPosition++;
       
  4330             // do some fake encoding to get the text length
       
  4331             TUint oldPosition = iPosition; // we will return here
       
  4332             EncodeTextStringL( temp.KeywordArray()[i]->Keyword() );
       
  4333             length = iPosition - oldPosition;
       
  4334             iPosition = oldPosition; // return to original place
       
  4335             length += 1; // token must come before string
       
  4336             EncodeValueLength( length );
       
  4337             TUint8 token = (TUint8) temp.KeywordArray()[i]->Token();
       
  4338             if ( iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewReq ||
       
  4339                  iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewConf ||
       
  4340                  iMmsHeaders->MessageType() == KMmsMessageTypeMBoxDescr )
       
  4341                 {
       
  4342                 // the token must always be filter for MMbox PDUs
       
  4343                 token = KMmsFilterToken;
       
  4344                 }
       
  4345             iEncodeBuffer->Write( iPosition, &token, 1 );
       
  4346             iPosition++;
       
  4347             EncodeTextStringL( temp.KeywordArray()[i]->Keyword() );
       
  4348             }
       
  4349         }
       
  4350     }
       
  4351 
       
  4352 // ---------------------------------------------------------
       
  4353 //
       
  4354 // ---------------------------------------------------------
       
  4355 //
       
  4356 void CMmsEncode::EncodeOptionalInteger( TUint8 aHeader, TUint aValue )
       
  4357     {
       
  4358     if ( aValue == 0 )
       
  4359         {
       
  4360         return; // not set, nothing to encode, header is optional
       
  4361         }
       
  4362 
       
  4363     iEncodeBuffer->Write( iPosition, &aHeader, 1 );
       
  4364     iPosition++;
       
  4365 
       
  4366     EncodeInteger( aValue );
       
  4367 
       
  4368     }
       
  4369 
       
  4370 // ---------------------------------------------------------
       
  4371 //
       
  4372 // ---------------------------------------------------------
       
  4373 //
       
  4374 void CMmsEncode::EncodeAttributes( RArray<TUint>& aAttributeArray )
       
  4375     {
       
  4376     TInt i;
       
  4377 
       
  4378     for ( i = 0; i < aAttributeArray.Count(); ++i )
       
  4379         {
       
  4380         EncodeMandatoryByte( KMmsAssignedAttributes, aAttributeArray[i] );
       
  4381         }
       
  4382     }
       
  4383 
       
  4384 // ---------------------------------------------------------
       
  4385 //
       
  4386 // ---------------------------------------------------------
       
  4387 //
       
  4388 void CMmsEncode::EncodeMMBoxStates( RArray<TInt>& aStateArray )
       
  4389     {
       
  4390     TInt i;
       
  4391 
       
  4392     for ( i = 0; i < aStateArray.Count(); ++i )
       
  4393         {
       
  4394         EncodeMandatoryByte( KMmsAssignedMMState, aStateArray[i] );
       
  4395         }
       
  4396     }
       
  4397 
       
  4398 // ---------------------------------------------------------
       
  4399 //
       
  4400 // ---------------------------------------------------------
       
  4401 //
       
  4402 void CMmsEncode::EncodeContentLocationArray()
       
  4403     {
       
  4404     TBool mustCheck = EFalse;
       
  4405     if ( iMmsHeaders->ContentLocation().Length() > 0 )
       
  4406         {
       
  4407         mustCheck = ETrue;
       
  4408         EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  4409             iMmsHeaders->ContentLocation() );
       
  4410         }
       
  4411     // If there is content location array, encode it, too.
       
  4412     // A content-location should never occur in both places, but we still check
       
  4413 
       
  4414     TInt i = 0;
       
  4415     if ( iMmsHeaders->ReadOnlyMMBoxMessageHeaders() )
       
  4416         {
       
  4417         for ( i = 0;
       
  4418             i < iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList().Count();
       
  4419             i++ )
       
  4420             {
       
  4421             if ( !( mustCheck && iMmsHeaders->ContentLocation().Compare(
       
  4422                 iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList()[i] ) == 0 ) )
       
  4423                 {
       
  4424                 // the content location in the list does not appear as
       
  4425                 // separate header, we must add it
       
  4426                 EncodeHeaderAndTextString( KMmsAssignedContentLocation,
       
  4427                     iMmsHeaders->ReadOnlyMMBoxMessageHeaders()->ContentLocationList()[i] );
       
  4428                 }
       
  4429             }
       
  4430         }
       
  4431     }
       
  4432 
       
  4433 // ---------------------------------------------------------
       
  4434 //
       
  4435 // ---------------------------------------------------------
       
  4436 //
       
  4437 void CMmsEncode::EncodeStartingHeaders( TInt aMessageType,
       
  4438     const TPtrC8& aTID, TInt aVersion )
       
  4439     {
       
  4440     // EncodeMandatoryByte will always set the high bit.
       
  4441     
       
  4442     // Message type
       
  4443     EncodeMandatoryByte( KMmsAssignedMessageType, aMessageType );
       
  4444     // TID if present
       
  4445     EncodeOptionalString( KMmsAssignedTID, aTID );
       
  4446     // MMS encapsulation version
       
  4447     EncodeMandatoryByte( KMmsAssignedMmsVersion, aVersion );
       
  4448     }
       
  4449     
       
  4450 // ---------------------------------------------------------
       
  4451 //
       
  4452 // ---------------------------------------------------------
       
  4453 //
       
  4454 void CMmsEncode::EncodeApplicationIdParametersL()
       
  4455     {
       
  4456     if ( iMmsHeaders->ApplicId().Length() > 0 )
       
  4457         {
       
  4458         EncodeTextString( KMmsJavaApplicationId );
       
  4459         EncodeTextStringL( iMmsHeaders->ApplicId() );
       
  4460         }
       
  4461     if ( iMmsHeaders->ReplyApplicId().Length() > 0 )
       
  4462         {
       
  4463         EncodeTextString( KMmsJavaReplyApplicationId );
       
  4464         EncodeTextStringL( iMmsHeaders->ReplyApplicId() );
       
  4465         }
       
  4466     }
       
  4467 
       
  4468 // ---------------------------------------------------------
       
  4469 //
       
  4470 // ---------------------------------------------------------
       
  4471 void CMmsEncode::Dump()
       
  4472     {
       
  4473     // no dump if not logging
       
  4474 #ifndef _NO_MMSS_LOGGING_
       
  4475     TInt error = KErrNone;
       
  4476     // if no can do, sorry.
       
  4477     TRAP( error,
       
  4478         {
       
  4479         if ( iEntryWrapper )
       
  4480             {
       
  4481             if ( ( iEntryWrapper->GetDumpFlag() ) &&
       
  4482                 iEncodeBuffer &&
       
  4483                 iEncodeBuffer->Size() > 0 )
       
  4484                 {
       
  4485                 iFileName = KMmsDefaultLogDirectory;
       
  4486                 TUint att;
       
  4487                 if ( iFs.Att( iFileName, att ) == KErrNone )
       
  4488                     {
       
  4489                     _LIT( KRelated, "Sent.mms");
       
  4490                     iParse.Set( iFileName, &KRelated, NULL );
       
  4491                     iFileName = iParse.FullName();
       
  4492                     User::LeaveIfError( CApaApplication::GenerateFileName(
       
  4493                         iFs, iFileName ) );
       
  4494                     RFile file;
       
  4495                     User::LeaveIfError( file.Create( iFs, iFileName,
       
  4496                         EFileWrite | EFileShareExclusive ) );
       
  4497                     // for message id generation
       
  4498                     iParse.Set( iFileName, NULL, NULL );
       
  4499 
       
  4500                     // the data is supposed to be in the encode buffer
       
  4501                     TPtr8 ptr = iEncodeBuffer->BackPtr( iPosition );
       
  4502                     file.Write( ptr );
       
  4503                     file.Flush();
       
  4504 
       
  4505                     // done - close files
       
  4506                     file.Close();
       
  4507                     }
       
  4508                 }
       
  4509             }
       
  4510         }
       
  4511     );
       
  4512     if ( error != KErrNone )
       
  4513         {
       
  4514         TMmsLogger::Log( _L("Dump left with error %d"), error );
       
  4515         }
       
  4516 #endif
       
  4517     }
       
  4518     
       
  4519 // ---------------------------------------------------------
       
  4520 //
       
  4521 // ---------------------------------------------------------
       
  4522 void CMmsEncode::DumpAppend()
       
  4523     {
       
  4524     
       
  4525     // no dump if not logging
       
  4526 #ifndef _NO_MMSS_LOGGING_
       
  4527     TInt error = KErrNone;
       
  4528     // if no can do, sorry.
       
  4529     TRAP( error,
       
  4530         {
       
  4531         if ( iEntryWrapper )
       
  4532             {
       
  4533             if ( ( iEntryWrapper->GetDumpFlag() ) &&
       
  4534                 iEncodeBuffer &&
       
  4535                 iEncodeBuffer->Size() > 0 )
       
  4536                 {
       
  4537                 iFileName = KMmsDefaultLogDirectory;
       
  4538                 TUint att;
       
  4539                 if ( iFs.Att( iFileName, att ) == KErrNone )
       
  4540                     {
       
  4541                     RFile file;
       
  4542                     iFileName = iParse.FullName();
       
  4543                     User::LeaveIfError( file.Open( iFs, iFileName,
       
  4544                        EFileWrite | EFileShareExclusive ) );
       
  4545                     TInt position = 0; // seek to end
       
  4546                     file.Seek( ESeekEnd, position );
       
  4547                     // the data is supposed to be in the encode buffer
       
  4548                     TPtr8 ptr = iEncodeBuffer->BackPtr( iPosition );
       
  4549                     file.Write( ptr );
       
  4550                     file.Flush();
       
  4551                     // done - close files
       
  4552                     file.Close();
       
  4553                     }
       
  4554                 }
       
  4555             }
       
  4556         }
       
  4557     );
       
  4558     if ( error != KErrNone )
       
  4559         {
       
  4560         TMmsLogger::Log( _L("DumpAppend left with error %d"), error );
       
  4561         }
       
  4562 #endif
       
  4563     }
       
  4564     
       
  4565 // ---------------------------------------------------------
       
  4566 //
       
  4567 // ---------------------------------------------------------
       
  4568 void CMmsEncode::EncodeApplicationHeadersL()
       
  4569     {
       
  4570 // Application headers are only supported in WINS for testing purposes
       
  4571 // Complete support for routing messages to arbitrary applications
       
  4572 // requires support for selecting which applications are allowed
       
  4573 // to send messages etc.    
       
  4574 #ifdef __WINS__
       
  4575     // The optional string functions check the length
       
  4576     // and return without doing anything if the length of the string is 0
       
  4577     if ( IsStringSafe( iMmsHeaders->ApplicId() ) )
       
  4578         {
       
  4579         // We only send this header if it is us-ascii only
       
  4580         // There is no encoding defined, so if this is converted
       
  4581         // from unicode to some other character set there is 
       
  4582         // no guarantee that the recipient can decode it.
       
  4583         EncodeOptionalStringL( KMmsAssignedApplicId, iMmsHeaders->ApplicId() );
       
  4584         }
       
  4585         
       
  4586     if ( IsStringSafe( iMmsHeaders->ReplyApplicId() ) )
       
  4587         {
       
  4588         EncodeOptionalStringL( KMmsAssignedReplyApplicId, iMmsHeaders->ReplyApplicId() );
       
  4589         }
       
  4590 
       
  4591     EncodeOptionalString( KMmsAssignedAuxApplicInfo, iMmsHeaders->AuxApplicInfo() );
       
  4592 #endif    
       
  4593     }
       
  4594 
       
  4595 // ---------------------------------------------------------
       
  4596 //
       
  4597 // ---------------------------------------------------------
       
  4598 void CMmsEncode::EncodeCancelRequest()
       
  4599     {
       
  4600 // implemented for test purposes
       
  4601 #ifdef __WINS__
       
  4602     // Insert message type, TID and version number
       
  4603     EncodeStartingHeaders( KMmsMessageTypeCancelReq,
       
  4604         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  4605         
       
  4606     EncodeOptionalString( KMmsAssignedCancelId, iMmsHeaders->ReplaceCancelId() );
       
  4607 #endif    
       
  4608     }
       
  4609 
       
  4610 // ---------------------------------------------------------
       
  4611 //
       
  4612 // ---------------------------------------------------------
       
  4613 void CMmsEncode::EncodeCancelResponse()
       
  4614     {
       
  4615     // Insert message type, TID and version number
       
  4616     EncodeStartingHeaders( KMmsMessageTypeCancelConf,
       
  4617         iMmsHeaders->Tid(), iMmsHeaders->MmsVersion() );
       
  4618         
       
  4619     EncodeOptionalByte( KMmsAssignedCancelStatus, iMmsHeaders->CancelStatus() );   
       
  4620     }
       
  4621 
       
  4622 // ---------------------------------------------------------
       
  4623 //
       
  4624 // ---------------------------------------------------------
       
  4625 HBufC8* CMmsEncode::EncodeQuotedPrintableWordL( const TPtrC8& aSource )
       
  4626     {
       
  4627     // We have calculated that it fits
       
  4628     
       
  4629     TInt bufferLength = KMaxNameBufferLength;
       
  4630     
       
  4631     HBufC8* buffer = HBufC8::NewL( bufferLength );
       
  4632     CleanupStack::PushL( buffer );
       
  4633     TPtr8 ptr = buffer->Des();
       
  4634     buffer->Des().Copy( KMmsQuotedPreamble );
       
  4635     ptr.SetLength( bufferLength );
       
  4636     TPtr8 encodeBuffer = ptr.MidTPtr( KMmsPreambleLength );
       
  4637     encodeBuffer.SetLength( 0 ); // empty the buffer
       
  4638     
       
  4639     TImCodecQP encoder;
       
  4640 
       
  4641     // The function would return the number of characters written to the buffer.
       
  4642     // We don't do anything with the result, so we ignore the return value.
       
  4643     encoder.Encode( aSource, encodeBuffer );
       
  4644     
       
  4645     ptr.SetLength( encodeBuffer.Length() + KMmsPreambleLength );
       
  4646     
       
  4647     buffer->Des().Append( KMmsEncodingTrailer );
       
  4648     CleanupStack::Pop( buffer );
       
  4649     return buffer;
       
  4650     }
       
  4651     
       
  4652 // ---------------------------------------------------------
       
  4653 //
       
  4654 // ---------------------------------------------------------
       
  4655 HBufC8* CMmsEncode::EncodeBase64WordL( const TPtrC8& aSource )
       
  4656     {
       
  4657     // ((length + 2)/3)*4  3 bytes alwaus produces 4 encoded bytes. Allow filler
       
  4658     TInt bufferLength = KMmsEncodingExtraLength + ( aSource.Length() + KMms2 ) / KMms3 * KMms4;
       
  4659     
       
  4660     HBufC8* buffer = HBufC8::NewL( bufferLength );
       
  4661     CleanupStack::PushL( buffer );
       
  4662     TPtr8 ptr = buffer->Des();
       
  4663     buffer->Des().Copy( KMmsBase64Preamble );
       
  4664     ptr.SetLength( bufferLength );
       
  4665 
       
  4666     TPtr8 encodeBuffer = ptr.MidTPtr( KMmsPreambleLength );
       
  4667     encodeBuffer.SetLength( 0 ); // empty the buffer
       
  4668 
       
  4669     TImCodecB64 encoder;
       
  4670 
       
  4671     // It is rather unclear what this function actually returns (no documentation found). 
       
  4672     // Therefore we just ignore the result.
       
  4673     // Our buffer is long enough for the result to always fit.
       
  4674     encoder.Encode( aSource, encodeBuffer );
       
  4675     
       
  4676     ptr.SetLength( encodeBuffer.Length() + KMmsPreambleLength );
       
  4677     
       
  4678     buffer->Des().Append( KMmsEncodingTrailer );
       
  4679     CleanupStack::Pop( buffer );
       
  4680     return buffer;
       
  4681     }
       
  4682     
       
  4683 
       
  4684 // ---------------------------------------------------------
       
  4685 // CMmsEncode::PreProcessAttachmentDataL
       
  4686 // Open the message store(Edit mode) and process attachments for further encoding in required encoding type.
       
  4687 // Update the message store accordingly with the new encoding type and data in the corresponding attachments.
       
  4688 // ---------------------------------------------------------
       
  4689 void CMmsEncode::PreProcessAttachmentDataL()
       
  4690     {
       
  4691     TInt error = KErrNone;
       
  4692     RFile attachFile;
       
  4693     TBool retVal = EFalse;
       
  4694     TInt currAttachI;
       
  4695     
       
  4696 #ifndef _NO_MMSS_LOGGING_
       
  4697     TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- start ") );
       
  4698 #endif /* _NO_MMSS_LOGGING_ */
       
  4699     CMsvStore* editStore = iEntryWrapper->EditStoreL();
       
  4700     CleanupStack::PushL( editStore );
       
  4701 
       
  4702     MMsvAttachmentManager& attachMan = editStore->AttachmentManagerL();
       
  4703     MMsvAttachmentManagerSync& attachManagerSync = editStore->AttachmentManagerExtensionsL();
       
  4704     TInt numberOfAttachments = attachMan.AttachmentCount();
       
  4705     CMsvAttachment* attachmentInfo = NULL;
       
  4706     iTextUtils = CMsgTextUtils::NewL( iFs );
       
  4707     
       
  4708     for ( currAttachI = 0; ( currAttachI < numberOfAttachments ) && ( error == KErrNone ); currAttachI++ )
       
  4709         {
       
  4710         //gets the ownership from attachment manager
       
  4711         attachmentInfo = attachMan.GetAttachmentInfoL( currAttachI );
       
  4712         CleanupStack::PushL( attachmentInfo );       
       
  4713         iMimeHeaders->RestoreL( *attachmentInfo );
       
  4714 #ifndef _NO_MMSS_LOGGING_
       
  4715         TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- Attchment:%d "), currAttachI );
       
  4716 #endif /* _NO_MMSS_LOGGING_ */
       
  4717         
       
  4718         if ( iFileOpen )
       
  4719             {
       
  4720             // close any file in case we have been reset while the file is still open
       
  4721             iAttachFile.Close();
       
  4722             iFileOpen = EFalse;
       
  4723             }
       
  4724 
       
  4725         retVal = CheckAndUpdateAttachmentL(*attachmentInfo, *iMimeHeaders);
       
  4726 
       
  4727         if( retVal )
       
  4728             {
       
  4729             TRAPD( 
       
  4730                     err,
       
  4731                     attachManagerSync.ModifyAttachmentInfoL(attachmentInfo);
       
  4732                     editStore->CommitL();
       
  4733                   );
       
  4734 #ifndef _NO_MMSS_LOGGING_
       
  4735             if(err != KErrNone)
       
  4736                 {
       
  4737                 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: store commit error: %d"), err );
       
  4738                 }
       
  4739             else
       
  4740                 {
       
  4741                 TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: store commit success") );                
       
  4742                 }
       
  4743 #endif /* _NO_MMSS_LOGGING_ */
       
  4744             /*  attachmentInfo ownership is transferred to attachment manager
       
  4745              *  Hence, JUST pop attachmentInfo, DO NOT Destroy.
       
  4746              */
       
  4747             CleanupStack::Pop( attachmentInfo );
       
  4748             }
       
  4749         else
       
  4750             {
       
  4751             CleanupStack::PopAndDestroy( attachmentInfo );
       
  4752             attachmentInfo = NULL;
       
  4753 #ifndef _NO_MMSS_LOGGING_
       
  4754             TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentData:: Tgt encoding NOT Reqd.") );                
       
  4755 #endif /* _NO_MMSS_LOGGING_ */
       
  4756             }
       
  4757         }
       
  4758     CleanupStack::PopAndDestroy( editStore );
       
  4759     
       
  4760     delete iTextUtils;
       
  4761     iTextUtils = NULL;
       
  4762 #ifndef _NO_MMSS_LOGGING_
       
  4763     TMmsLogger::Log( _L("CMmsEncode::PreProcessAttachmentDataL- end ") );
       
  4764 #endif /* _NO_MMSS_LOGGING_ */
       
  4765     }
       
  4766 
       
  4767 // ---------------------------------------------------------
       
  4768 // CMmsEncode::CheckAndUpdateAttachmentL
       
  4769 // Check and proceed if given attachment can be encoded using target encoding type based on its content type.
       
  4770 // Returns False if target encoding is not supported for this content type.
       
  4771 // ---------------------------------------------------------
       
  4772 TBool CMmsEncode::CheckAndUpdateAttachmentL( CMsvAttachment& aAttachmentInfo,
       
  4773                                              CMsvMimeHeaders& aMimeHeaders )
       
  4774     {
       
  4775     //get the content type string... and set to attachment if required
       
  4776     TInt contentType = -1; // indicate not found
       
  4777     TPtrC8 contentTypeString;
       
  4778     TBool retVal = EFalse;
       
  4779 #ifndef _NO_MMSS_LOGGING_
       
  4780     TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- start ") );
       
  4781 #endif /* _NO_MMSS_LOGGING_ */
       
  4782 
       
  4783     HBufC8* tempContentType = NULL;
       
  4784     contentTypeString.Set( aAttachmentInfo.MimeType() );
       
  4785     if ( contentTypeString.Length() == 0 )
       
  4786         {
       
  4787         // take type from mime headers
       
  4788         TInt cotentLength = aMimeHeaders.ContentType().Length();
       
  4789         TInt subCotentLength = aMimeHeaders.ContentSubType().Length();
       
  4790         tempContentType = HBufC8::NewL( cotentLength + subCotentLength + 1 );
       
  4791         CleanupStack::PushL( tempContentType );
       
  4792         tempContentType->Des().Copy( aMimeHeaders.ContentType() );
       
  4793         if ( ( aMimeHeaders.ContentType().Find( KMmsSlash8 ) != ( cotentLength - 1 ) ) &&
       
  4794              ( aMimeHeaders.ContentSubType().Find( KMmsSlash8 ) != 0 ) && ( subCotentLength != 0 ) )
       
  4795             {
       
  4796             tempContentType->Des().Append( KMmsSlash8 );
       
  4797             }
       
  4798         tempContentType->Des().Append( aMimeHeaders.ContentSubType() );
       
  4799         aAttachmentInfo.SetMimeTypeL( tempContentType->Des() );
       
  4800         contentTypeString.Set( aAttachmentInfo.MimeType() );
       
  4801         }
       
  4802         
       
  4803     //map the content type string to content type
       
  4804     TInt8 i;
       
  4805     for ( i = 0; i < KNumberContentTypes && contentType < 0; i++ )
       
  4806         {
       
  4807         if ( contentTypeString.CompareF( TPtrC8( KContentTypeTable[i] ) ) == 0 )
       
  4808             {
       
  4809             contentType = i;
       
  4810             }
       
  4811         }
       
  4812 #ifndef _NO_MMSS_LOGGING_
       
  4813     TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- content type:%d" ), contentType );
       
  4814 #endif /* _NO_MMSS_LOGGING_ */
       
  4815     //check if this content type need to be encoded using korean specific
       
  4816     if( IsConversionSupportedContentType( contentType ) )
       
  4817         {
       
  4818         /* Do the attachment data conversion from "src type" to "target type" for the given "attached file". 
       
  4819          * Target type encodng MIB enum is obtained from cenrep.
       
  4820          */
       
  4821         retVal = ProcessAndConvertAttachmentDataL( aMimeHeaders.MimeCharset(),
       
  4822                                                    iTargetEncodingType,
       
  4823                                                    aAttachmentInfo);
       
  4824         if( retVal )
       
  4825             {
       
  4826 #ifndef _NO_MMSS_LOGGING_
       
  4827             TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- conv success: Tgt Enc: %d"), iTargetEncodingType );
       
  4828 #endif /* _NO_MMSS_LOGGING_ */
       
  4829             //set new charset type in headers and update attachment info
       
  4830             aMimeHeaders.SetMimeCharset( iTargetEncodingType );
       
  4831             aMimeHeaders.StoreL(aAttachmentInfo); // save the new charset to attachment as well
       
  4832             /* mimetype might get reset to original mimeheader content type.
       
  4833              * ensure the full content type(if created from mime content and subcontent) is set to attachment
       
  4834              */
       
  4835             if( tempContentType != NULL )
       
  4836                 {
       
  4837                 aAttachmentInfo.SetMimeTypeL( tempContentType->Des() );
       
  4838                 CleanupStack::PopAndDestroy( tempContentType );                
       
  4839                 }
       
  4840             }
       
  4841         }
       
  4842 #ifndef _NO_MMSS_LOGGING_
       
  4843     TMmsLogger::Log( _L("CMmsEncode::CheckAndUpdateAttachmentL- End , retVal: %d"), retVal );
       
  4844 #endif /* _NO_MMSS_LOGGING_ */
       
  4845     return retVal;
       
  4846     }
       
  4847     
       
  4848 // ---------------------------------------------------------
       
  4849 // CMmsEncode::ProcessAndConvertAttachmentDataL
       
  4850 // converts of attachment data from source to target encoding type.
       
  4851 // |src charset buffer| --->converted to ---> |unicode buffer| ---> converted to ---> |target charset|
       
  4852 // Returns false if data is already int target format, or plugins are missing, or file operation issues.
       
  4853 // ---------------------------------------------------------
       
  4854 TBool CMmsEncode::ProcessAndConvertAttachmentDataL( TUint aSrcCharSetMIBEnum,
       
  4855                                                     TUint aTargetCharSetMIBEnum, 
       
  4856                                                     CMsvAttachment& aAttachmentInfo)
       
  4857     {
       
  4858 #ifndef _NO_MMSS_LOGGING_
       
  4859     TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- start ") );
       
  4860 #endif /* _NO_MMSS_LOGGING_ */
       
  4861     if( aSrcCharSetMIBEnum == aTargetCharSetMIBEnum )
       
  4862         {
       
  4863 #ifndef _NO_MMSS_LOGGING_
       
  4864         TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- src and dest are same ") );
       
  4865 #endif /* _NO_MMSS_LOGGING_ */
       
  4866         //if source and target charset MIB enums are same.  
       
  4867         return EFalse; // no conversion 
       
  4868         }
       
  4869         
       
  4870     //get source and target charset mapping here. if any error, return
       
  4871     TUint srcCharSetId = iTextUtils->MibIdToCharconvIdL( aSrcCharSetMIBEnum );
       
  4872     TUint targetCharSetId = iTextUtils->MibIdToCharconvIdL( aTargetCharSetMIBEnum );
       
  4873     if( srcCharSetId == targetCharSetId || KDefaultCharConvCharset == targetCharSetId)
       
  4874         {
       
  4875         /* If target charset plugin is missing, then default is returned. 
       
  4876            Do not encode to any target encoding type, send data as is .
       
  4877          */ 
       
  4878 #ifndef _NO_MMSS_LOGGING_
       
  4879         TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- missing plugin: Tgt Charset %x"), targetCharSetId );
       
  4880 #endif /* _NO_MMSS_LOGGING_ */
       
  4881         return EFalse;
       
  4882         }
       
  4883     
       
  4884     RFile attachFile;
       
  4885     TInt error;
       
  4886 
       
  4887     const TDesC& fileName = aAttachmentInfo.FilePath();
       
  4888     error = attachFile.Open(iFs, fileName, EFileWrite);
       
  4889     if(error != KErrNone)
       
  4890         {
       
  4891 #ifndef _NO_MMSS_LOGGING_
       
  4892         TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file: %s, open error: %d"), fileName, error );
       
  4893 #endif /* _NO_MMSS_LOGGING_ */
       
  4894         attachFile.Close();
       
  4895         return EFalse;
       
  4896         }
       
  4897 
       
  4898     TInt maxLength;
       
  4899     error = attachFile.Size(maxLength);
       
  4900     if( error != KErrNone || maxLength == 0 )
       
  4901         {
       
  4902 #ifndef _NO_MMSS_LOGGING_
       
  4903         TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file size: %d, error: %d"), maxLength, error );
       
  4904 #endif /* _NO_MMSS_LOGGING_ */
       
  4905         attachFile.Close();
       
  4906         return EFalse;
       
  4907         }
       
  4908 
       
  4909     //read the original file data into srcBuffer
       
  4910     TInt cleanupCount = 0;    
       
  4911     HBufC8* srcBuffer = HBufC8::NewLC( maxLength );
       
  4912     cleanupCount++;
       
  4913     
       
  4914     TPtr8 srcPtr = srcBuffer->Des();
       
  4915     attachFile.Read( srcPtr, maxLength );
       
  4916         
       
  4917     //intermediate buffer in the form of unicode. 
       
  4918     HBufC16* unicodeBuffer(NULL);
       
  4919 
       
  4920     //Convert, scrBuffer to unicode format if not already in unicode format
       
  4921     if(srcCharSetId != 0)
       
  4922         {
       
  4923         //Convert from respective foreign charset to unicode buffer.
       
  4924         //returns buf16 pointer descriptor
       
  4925         TRAPD(err, unicodeBuffer = iTextUtils->ConvertToUnicodeL(srcPtr, srcCharSetId) );
       
  4926         if( err != KErrNone )
       
  4927             {
       
  4928 #ifndef _NO_MMSS_LOGGING_
       
  4929             TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: ConvertToUnicodeL error: %d"), err );
       
  4930 #endif /* _NO_MMSS_LOGGING_ */
       
  4931             delete unicodeBuffer;
       
  4932             attachFile.Close();
       
  4933             CleanupStack::PopAndDestroy( cleanupCount, srcBuffer ); // srcBuffer
       
  4934             return EFalse;
       
  4935             }
       
  4936         CleanupStack::PushL( unicodeBuffer );
       
  4937         cleanupCount++;
       
  4938         }
       
  4939     else
       
  4940         {
       
  4941         TInt unicodeStdHeaderWordLE = 0xFEFF;
       
  4942         TInt unicodeStdHeaderWordBE = 0xFFFE;
       
  4943         //data is already in unicode format. need to extract the data to 16-bit buffer
       
  4944         unicodeBuffer = HBufC16::NewLC( maxLength/2 );//maxlength value is in terms of bytes
       
  4945         cleanupCount++;
       
  4946         
       
  4947         TPtr16 ptr = unicodeBuffer->Des();
       
  4948         iTextUtils->ConvertPtrToDesC16(srcPtr, ptr);
       
  4949         /* In case if attachment is UTF-16 format, it will have the UTF-16 representation word(2 butes)
       
  4950          * at the start. Find and delete it before passing the data for conversion
       
  4951          */ 
       
  4952         if( ptr[0] == unicodeStdHeaderWordLE || ptr[0] == unicodeStdHeaderWordBE )
       
  4953             {
       
  4954             ptr.Delete(0, 1);
       
  4955             }
       
  4956         }
       
  4957 
       
  4958     //Now convert unicode buffer to respective target charset type.
       
  4959     if( targetCharSetId != 0 )
       
  4960         {
       
  4961         // reset this file and write new encoded data to it directly
       
  4962         error = attachFile.SetSize(0);
       
  4963 #ifndef _NO_MMSS_LOGGING_
       
  4964         if( error != KErrNone )
       
  4965             {
       
  4966             TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentData:: file size: %d, error: %d"), maxLength, error );
       
  4967             //attachFile.Close();
       
  4968             //return EFalse;
       
  4969             }
       
  4970 #endif /* _NO_MMSS_LOGGING_ */
       
  4971         
       
  4972         /* convert to target charset id.
       
  4973          * Ideally, this should not leave with plugin-NOT-found, since it it already verified
       
  4974          */
       
  4975         iTextUtils->ConvertToFileL(*unicodeBuffer, attachFile, targetCharSetId );
       
  4976         }
       
  4977     else
       
  4978         {
       
  4979         TPtr16 ptr = unicodeBuffer->Des();
       
  4980         //Reset/erase old file content.
       
  4981         TInt err = attachFile.SetSize(0);
       
  4982 
       
  4983         //write new encoded data to file using write stream
       
  4984         RFileWriteStream writer( attachFile );
       
  4985         writer.PushL();
       
  4986         writer.WriteL( ptr );
       
  4987         //writer.CommitL();
       
  4988         writer.Pop();
       
  4989         writer.Close();
       
  4990         }
       
  4991     //close file
       
  4992     attachFile.Close();
       
  4993     CleanupStack::PopAndDestroy( cleanupCount, srcBuffer ); //unicodeBuffer, srcBuffer
       
  4994 #ifndef _NO_MMSS_LOGGING_
       
  4995     TMmsLogger::Log( _L("CMmsEncode::ProcessAndConvertAttachmentDataL- End, retVal: TRUE") );
       
  4996 #endif /* _NO_MMSS_LOGGING_ */
       
  4997     return ETrue;
       
  4998     }
       
  4999 
       
  5000 
       
  5001 // ---------------------------------------------------------
       
  5002 // CMmsEncode::IsConversionSupportedContentType
       
  5003 // checks if input content type is supported for target encoding
       
  5004 // ---------------------------------------------------------
       
  5005 TBool CMmsEncode::IsConversionSupportedContentType( TInt aContentType )
       
  5006     {
       
  5007     /* Currently only "text/plain" content types are supported for korean encoding.
       
  5008      * Add to the switch case, if any new content type can be supported as well.
       
  5009      * 
       
  5010      * IMPORTANT: 
       
  5011      * Ensure the values added map to corresponding content type entry in the table KContentTypeTable[],
       
  5012      * defined in ../inc/mmscodec.h
       
  5013      */
       
  5014 #ifndef _NO_MMSS_LOGGING_
       
  5015     TMmsLogger::Log( _L("CMmsEncode::IsConversionSupportedContentType- start: %d "), aContentType );
       
  5016 #endif /* _NO_MMSS_LOGGING_ */
       
  5017     TBool retVal = EFalse;
       
  5018     switch( aContentType )
       
  5019         {
       
  5020         case 0x03 :           // "text/plain" 
       
  5021             {
       
  5022             retVal = ETrue;
       
  5023             break;
       
  5024             }
       
  5025         default:
       
  5026             //do nothing
       
  5027             break;// to avoid compile errors/warning
       
  5028         }
       
  5029 #ifndef _NO_MMSS_LOGGING_
       
  5030     TMmsLogger::Log( _L("CMmsEncode::IsConversionSupportedContentType- end ") );
       
  5031 #endif /* _NO_MMSS_LOGGING_ */
       
  5032     return retVal;
       
  5033     }
       
  5034 
       
  5035 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  5036 
       
  5037 //  End of File