mmsengine/mmscodec/src/mmsdecode.cpp
changeset 0 72b543305e3a
child 12 caea42e26caa
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 /*
       
     2 * Copyright (c) 2002-2007 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:   Decoding of binary multimedia message
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include    <apparc.h>
       
    21 #include    <s32mem.h>
       
    22 #include    <utf.h>
       
    23 #include    <msvids.h>
       
    24 #include    <escapeutils.h>
       
    25 #include    <e32math.h>
       
    26 #include    <badesca.h>
       
    27 #include    <cmsvmimeheaders.h>
       
    28 #include    <mmsvattachmentmanager.h>
       
    29 #include    <mmsvattachmentmanagersync.h>
       
    30 #include	<fileprotectionresolver.h>
       
    31 #include    <apmstd.h>
       
    32 // Features
       
    33 #include    <featmgr.h>    
       
    34 #include    <bldvariant.hrh>
       
    35 
       
    36 #include    "mmsheaders.h"
       
    37 #include    "mmsconst.h"
       
    38 #include    "mmsdecode.h"
       
    39 #include    "mmscodec.h"
       
    40 #include    "mmsservercommon.h"
       
    41 #include    "mmssession.h"
       
    42 #include    "mmsgenutils.h"
       
    43 #include    "mmsentrywrapper.h"
       
    44 #include    "mmserrors.h"
       
    45 #include    "mmsmmboxmessageheaders.h"
       
    46 #include    "mmsmmboxviewheaders.h"
       
    47 #include    "mmselementdescriptor.h"
       
    48 
       
    49 enum TMmsMachineStates
       
    50     {
       
    51     EMmsIdle,
       
    52     EMmsDecodingHeaders,
       
    53     EMmsDecodingAttachments,
       
    54     EMmsFinished
       
    55     };
       
    56 
       
    57 // These are the stages for chunked encoding.
       
    58 // The chunked encoding is synchronous, so the stages are different
       
    59 // from the machine states.    
       
    60 enum TMmsChunkedDecodingStages
       
    61     {
       
    62     EMmsNotApplicable, // stage used when not doing chunks
       
    63     EMmsHeaders,
       
    64     EMmsAttachmentHeaders,
       
    65     EMmsAttachmentDataStart, // create attachment file and add data
       
    66     EMmsAttachmentDataAppend, // append data to existing attachment
       
    67     EMmsDone
       
    68     };
       
    69 
       
    70 static const CMmsDecode::TMmsExtensionLookup KMmsFileExtensionMatchTable[] =
       
    71     {
       
    72         { _S8( "jpeg" ), _S16( "*.jpg" ) },
       
    73         { _S8( "gif" ), _S16( "*.gif" ) },
       
    74         { _S8( "text" ), _S16( "*.txt" ) },
       
    75         { _S8( "smil" ), _S16( "*.smil" ) },
       
    76         { _S8( "wbmp" ), _S16( "*.wbmp" ) },
       
    77         { _S8( "png" ), _S16( "*.png" ) },
       
    78         { _S8( "amr" ), _S16( "*.amr" ) },
       
    79         { _S8( "vcard" ), _S16( "*.vcf" ) },
       
    80         { _S8( "calendar" ), _S16( "*.vcs" ) },
       
    81         { _S8( "drm.message" ), _S16( "*.dm" ) },
       
    82         { _S8( "drm.content" ), _S16( "*.dcf" ) },
       
    83         { _S8( "drm.rights+xml" ), _S16( "*.dr" ) },
       
    84         { _S8( "drm.rights+wbxml" ), _S16( "*.drc" ) },
       
    85         { _S8( "drm.dcf" ), _S16( "*.odf" ) },
       
    86         // last entries in the table are empty so that
       
    87         // we can find the end of the table
       
    88         { _S8( "" ), _S16( "" ) }
       
    89     };
       
    90     
       
    91 // application specific headers with known handling
       
    92 static const CMmsDecode::TMmsExtensionHeaderLookup KMmsExtensionHeaderLookup[] =
       
    93     {
       
    94         { _S8( "X-Mms-Vodafone-Notif-Text" ), &KMmsAssignedExtendedNotificationText },
       
    95         { _S8( "X-Mms-Vodafone-Notif-EOL" ), &KMmsAssignedExtendedNotificationEOL },
       
    96         // end of table
       
    97         { _S8( "" ), 0 }
       
    98     };
       
    99 
       
   100 _LIT8( KMmsWapMultipartReport, "application/vnd.wap.multipart.report" );
       
   101 // fake assigned number - last one possible
       
   102 const TUint8 KMmsAssignedApplicationVndWapMultipartReport = 0x7F;
       
   103 
       
   104 // a header that is a text string, not assigned number
       
   105 const TUint8 KMmsTextHeader = 0x7F;
       
   106 
       
   107 _LIT8( KMmsExtension, "X-" );
       
   108 
       
   109 #ifndef _NO_MMSS_LOGGING_
       
   110 _LIT16( KLogYes, "-- Yes" );
       
   111 _LIT16( KLogNo, "-- No" );
       
   112 _LIT16( KLogUnknown, "-- Unknown %d" );
       
   113 #endif
       
   114 
       
   115 _LIT8( KmmsSmilMimeType,"application/smil");
       
   116 _LIT8( KMmsSmilSubtype, "smil" );
       
   117 _LIT8( KMmsAudioSubtype, "amr" );
       
   118 _LIT8( KMmsAudioSubtype2, "x-amr" ); // old subtype - someone may send this
       
   119 // main type for audio, don't mark for example "application/amr" as audiomessage
       
   120 // as audiomessage UI can't handle it. UI only handles "audio/amr"
       
   121 _LIT8( KMmsAudioType, "audio" );
       
   122 
       
   123 _LIT8( KMessageClassPersonal, "Personal" );
       
   124 _LIT8( KMessageClassAdvertisement, "Advertisement" );
       
   125 _LIT8( KMessageClassInformational, "Informational" );
       
   126 _LIT8( KMessageClassAuto, "Auto" );
       
   127          
       
   128 #ifndef _NO_MMSS_LOGGING_
       
   129 const TInt KMmsHalfByteShift = 4;
       
   130 const TUint8 KMms0x0F = 0x0F;
       
   131 const TInt KMmsDateFormatLength = 30; // length for date string buffer for logging
       
   132 const TInt KMmsMicroToSeconds = 1000000;
       
   133 #endif
       
   134 const TUint8 KMms0x20 = 0x20; // lowest ascii, space
       
   135 const TInt KMmsMinHeaderLength = 2; // no header can be shorter than this
       
   136 const TInt KMmsBitsInByte = 8;
       
   137 const TInt KMmsMaxIntegerLength = 4;
       
   138 const TInt KMmsMaxLongIntegerLength = 8;
       
   139 const TUint8 KMms0x80 = 0x80; // 128
       
   140 const TUint8 KMms0x7F = 0x7F; // 127
       
   141 const TInt KMms2 = 2; // used to calculate length when converting 8 bit to 16 bit encoding
       
   142 const TUint8 KMms31 = 31; // uintvar indicator
       
   143 const TUint8 KMms32 = 32; // low limit for text string encoding
       
   144 const TUint8 KMms30 = 30; // upper limit for short length encoding
       
   145 const TInt KMmsUintvarShift = 7; // bit shift for decoding uintvars
       
   146 const TInt KMms14 = 14; // atta name length for self-generated names
       
   147 const TInt KMms2k = 2000;
       
   148 const TInt KMmsTestIllegalValue = 255;
       
   149 // ==================== LOCAL FUNCTIONS ====================
       
   150 
       
   151 // ================= MEMBER FUNCTIONS =======================
       
   152 
       
   153 // ---------------------------------------------------------------------------
       
   154 // C++ default constructor can NOT contain any code, that
       
   155 // might leave.
       
   156 // All member variables are automatically zeroed in the constructor
       
   157 // of a class derived from CBase.
       
   158 // ---------------------------------------------------------------------------
       
   159 //
       
   160 CMmsDecode::CMmsDecode()
       
   161     :CMsgActive ( KMmsActiveObjectPriority ),
       
   162     iState ( EMmsIdle )
       
   163     {
       
   164     }
       
   165 
       
   166 // ---------------------------------------------------------------------------
       
   167 // Symbian OS default constructor can leave.
       
   168 // ---------------------------------------------------------------------------
       
   169 //
       
   170 void CMmsDecode::ConstructL(RFs& aFs)
       
   171     {
       
   172     iFs = aFs;
       
   173     iMimeHeaders = CMsvMimeHeaders::NewL();
       
   174     // This is obsolete. Everything is always logged in debug version
       
   175     iLogAllDecoded = ETrue; 
       
   176     CActiveScheduler::Add(this);
       
   177     }
       
   178 
       
   179 // ---------------------------------------------------------------------------
       
   180 // Two-phased constructor.
       
   181 // ---------------------------------------------------------------------------
       
   182 //
       
   183 EXPORT_C CMmsDecode* CMmsDecode::NewL(RFs& aFs)
       
   184     {
       
   185     CMmsDecode* self = new (ELeave) CMmsDecode;
       
   186     
       
   187     CleanupStack::PushL( self );
       
   188     self->ConstructL(aFs);
       
   189     CleanupStack::Pop( self );
       
   190 
       
   191     return self;
       
   192     }
       
   193 
       
   194     
       
   195 // ---------------------------------------------------------------------------
       
   196 // Destructor
       
   197 // ---------------------------------------------------------------------------
       
   198 //
       
   199 CMmsDecode::~CMmsDecode()
       
   200     {
       
   201     Cancel();
       
   202     delete iMimeHeaders;
       
   203     delete iStore; // the store should be committed earlier, not anymore
       
   204     delete iRootContentIdBuffer;
       
   205 
       
   206     }
       
   207 
       
   208 // ---------------------------------------------------------
       
   209 //
       
   210 // ---------------------------------------------------------
       
   211 //
       
   212 EXPORT_C void CMmsDecode::StartL(
       
   213     MMmsEntryWrapper& aEntryWrapper,
       
   214     CMmsHeaders& aMmsHeaders,
       
   215     CBufFlat& aDecodeBuffer,
       
   216     TRequestStatus& aStatus,
       
   217     TInt aStartPosition /* = 0 */,
       
   218     TInt aLength /* = 0 */ )
       
   219     {
       
   220 
       
   221     Reset();
       
   222 
       
   223     iEntryWrapper = &aEntryWrapper;
       
   224     iDecodeBuffer = &aDecodeBuffer;
       
   225     iMmsHeaders = &aMmsHeaders;
       
   226     iDRMFlags = 0;
       
   227     // length will be checked later when we start actual decoding
       
   228     iPosition = aStartPosition;
       
   229     if ( aLength == 0 )
       
   230         {
       
   231         iLength = aDecodeBuffer.Size();
       
   232         }
       
   233     else
       
   234         {
       
   235         iLength = aLength + aStartPosition;
       
   236         }
       
   237 
       
   238     iDumpIncoming = iEntryWrapper->GetDumpFlag();
       
   239 
       
   240     DumpL();
       
   241 
       
   242     Queue(aStatus);
       
   243     
       
   244     CompleteSelf( iError );
       
   245 
       
   246     }
       
   247 
       
   248 // ---------------------------------------------------------
       
   249 //
       
   250 // ---------------------------------------------------------
       
   251 //
       
   252 EXPORT_C void CMmsDecode::DecodeHeadersL(
       
   253     MMmsEntryWrapper& aEntryWrapper,
       
   254     CMmsHeaders& aMmsHeaders,
       
   255     CBufFlat& aDecodeBuffer,
       
   256     TInt aStartPosition /* = 0 */,
       
   257     TInt aLength /* = 0 */,
       
   258     TInt* aNumberOfAttachments /* = 0 */,
       
   259     TInt* aDataStart /* = 0 */ )
       
   260     {
       
   261     // The initial settings are the same as for asynchronous
       
   262     // methods, but decoding just headers is fast enough to
       
   263     // be done synchronously
       
   264 
       
   265     Reset();
       
   266 
       
   267     iEntryWrapper = &aEntryWrapper;
       
   268     iDecodeBuffer = &aDecodeBuffer;
       
   269     iMmsHeaders = &aMmsHeaders;
       
   270     iPosition = aStartPosition;
       
   271     iNumberOfAttachments = 0;
       
   272     iLastHeader = EFalse;
       
   273     
       
   274     if ( aLength == 0 )
       
   275         {
       
   276         iLength = aDecodeBuffer.Size();
       
   277         }
       
   278     else
       
   279         {
       
   280         iLength = aLength + aStartPosition;
       
   281         }
       
   282     if ( aDataStart != 0 )
       
   283         {
       
   284         // Originally point beyound buffer
       
   285         // If data is found, this will be updated
       
   286         *aDataStart = iLength;
       
   287         }
       
   288     if ( aNumberOfAttachments )
       
   289         {
       
   290         // initialize to no attachments
       
   291         *aNumberOfAttachments = 0;
       
   292         }
       
   293 
       
   294     iMmsHeaders->Reset();
       
   295 
       
   296     // Save the time the entry was received into the MMS headers
       
   297     // the value in TMsvEntry may change, but this remains
       
   298     TTime now;      
       
   299     now.UniversalTime();
       
   300     iMmsHeaders->SetReceivingTime( now );
       
   301         
       
   302     iDumpIncoming = iEntryWrapper->GetDumpFlag();
       
   303     DumpL();
       
   304 
       
   305     if ( iLength < KMmsMinHeaderLength )
       
   306         {
       
   307         // cannot decode if nothing to decode
       
   308         // each header is at least 2 bytes. 
       
   309         // If not at least 2 bytes, no can do.
       
   310         iState = EMmsIdle;
       
   311         iError = KErrCorrupt;
       
   312         User::LeaveIfError( iError );
       
   313         }
       
   314 
       
   315     // each header byte must be followed by at least one byte value.
       
   316     // otherwise the message is corrupted
       
   317     // when we reach the header that indicates the start of the attachment
       
   318     // structure, we expect that no headers follow the attachment part
       
   319     // we could handle even headers following the attachments if we
       
   320     // wanted to, but if the specification is followed strictly, the 
       
   321     // attachments are the last part in the message.
       
   322 
       
   323     // each header is at least 2 bytes - header name and value
       
   324     while ( ( iPosition <= iLength - KMmsMinHeaderLength ) &&
       
   325         ( iError != KErrCorrupt ) &&
       
   326         ( !iLastHeader ) )
       
   327         {
       
   328         DecodeOneHeaderL();
       
   329         }
       
   330         
       
   331     iLength = iDecodeBuffer->Size();
       
   332     if ( iPosition >= iLength ||
       
   333         ( iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewConf &&
       
   334           iMmsHeaders->MultipartType() == 0 ) )
       
   335         {
       
   336         // Only content type header, but no actual attachments
       
   337         iNumberOfAttachments = 0;
       
   338         }
       
   339 
       
   340     // If the caller is interested, return the number of attachments we found
       
   341     if ( aNumberOfAttachments )
       
   342         {
       
   343         *aNumberOfAttachments = iNumberOfAttachments;
       
   344         }
       
   345 
       
   346     if ( aDataStart != 0 )
       
   347         {
       
   348         *aDataStart = iPosition;
       
   349         }
       
   350 
       
   351     // WE DON'T SAVE THE MESSAGE HERE.
       
   352     // THE CALLER CONTROLS THE SAVING OF THE MESSAGE
       
   353     // AS WE ONLY DECODE HEADERS, AND DON'T HANDLE
       
   354     // ATTACHMENTS HERE
       
   355     // THERE MAY BE NO ENTRY AVAILABLE FOR SAVING THE HEADERS.
       
   356 
       
   357     // We are done - may be called again...
       
   358     iState = EMmsIdle;
       
   359     User::LeaveIfError( iError );
       
   360 
       
   361     }
       
   362 
       
   363 
       
   364 // ---------------------------------------------------------
       
   365 //
       
   366 // ---------------------------------------------------------
       
   367 //
       
   368 EXPORT_C void CMmsDecode::DecodeAttachmentsL(
       
   369     MMmsEntryWrapper& aEntryWrapper,
       
   370     CMmsHeaders& aMmsHeaders,
       
   371     CBufFlat& aDecodeBuffer,
       
   372     TInt aNumberOfAttachments,
       
   373     TInt& aStartPosition,
       
   374     TRequestStatus& aStatus,
       
   375     TBool aDoNotUpdateParentEntry /* = EFalse*/,
       
   376     TInt aLength /* = 0 */ )
       
   377     {
       
   378 
       
   379     // The parent entry is updated after specified number of attachments
       
   380     // has been handled.
       
   381     // Normally all attachments should be handled together.
       
   382     // Handling only some attachments is a special case
       
   383     
       
   384     // We must get an edit store when we are called the first time.
       
   385     if ( !iStore )
       
   386         {
       
   387         iStore = iEntryWrapper->EditStoreL();
       
   388         }
       
   389 
       
   390     iError = KErrNone; // start with clean slate
       
   391     iDataStart = aStartPosition;
       
   392     iNextStart = aStartPosition;
       
   393     iUpdatedPosition = &aStartPosition;
       
   394     iDoNotUpdateParentEntry = aDoNotUpdateParentEntry;
       
   395 
       
   396     iEntryWrapper = &aEntryWrapper;
       
   397     iMmsHeaders = &aMmsHeaders;
       
   398     iDecodeBuffer = &aDecodeBuffer;
       
   399     iNumberOfAttachments = aNumberOfAttachments;
       
   400     iPosition = aStartPosition;
       
   401     if ( aLength == 0 )
       
   402         {
       
   403         iLength = iDecodeBuffer->Size();
       
   404         }
       
   405     else
       
   406         {
       
   407         iLength = aStartPosition + aLength;
       
   408         }
       
   409     iState = EMmsDecodingAttachments;
       
   410 
       
   411     Queue(aStatus);
       
   412     
       
   413     CompleteSelf( iError );
       
   414     
       
   415     }
       
   416 
       
   417 // ---------------------------------------------------------
       
   418 //
       
   419 // ---------------------------------------------------------
       
   420 //
       
   421 EXPORT_C CMsvMimeHeaders& CMmsDecode::ExtractNextDataPartL(
       
   422     CBufFlat& aDecodeBuffer,
       
   423     TInt& aStartPosition,
       
   424     TInt& aStartOfData,
       
   425     TInt& aLengthOfData)
       
   426     {
       
   427     iMimeHeaders->Reset();
       
   428     iDecodeBuffer = &aDecodeBuffer;
       
   429     iPosition = aStartPosition;
       
   430     iUpdatedPosition = &aStartPosition;
       
   431     iLength = iDecodeBuffer->Size();
       
   432 
       
   433     TInt headersLength = 0;
       
   434     TInt dataLength = 0;
       
   435     
       
   436     // This function is only used to extract next data part from multipart structure
       
   437 
       
   438     headersLength = GetUintvar();
       
   439     dataLength = GetUintvar();
       
   440 
       
   441     aStartOfData = iPosition + headersLength;
       
   442     iDataStart = aStartOfData;
       
   443     aLengthOfData = dataLength;
       
   444     aStartPosition = iDataStart + dataLength;
       
   445 
       
   446     // Extract mime headers
       
   447     // iPosition points to the start of headers
       
   448     // First is content type without actual header field, just value
       
   449     GetAttachmentContentTypeL();
       
   450 
       
   451     while ( iPosition < iDataStart )
       
   452         {
       
   453         DecodeOneContentHeaderL();
       
   454         }
       
   455 
       
   456     return *iMimeHeaders;
       
   457     }
       
   458     
       
   459 // ---------------------------------------------------------
       
   460 //
       
   461 // ---------------------------------------------------------
       
   462 //
       
   463 EXPORT_C void CMmsDecode::CommitStoreL()
       
   464     {
       
   465     if ( iStore )
       
   466         {
       
   467         iStore->CommitL();
       
   468         }
       
   469     }
       
   470     
       
   471 // ---------------------------------------------------------
       
   472 //
       
   473 // ---------------------------------------------------------
       
   474 //
       
   475 EXPORT_C void CMmsDecode::InitializeChunkedMode(
       
   476     MMmsEntryWrapper& aEntryWrapper,
       
   477     CMmsHeaders& aMmsHeaders,
       
   478     CBufFlat& aDecodeBuffer
       
   479     )
       
   480     {
       
   481     Reset();
       
   482     iEntryWrapper = &aEntryWrapper;
       
   483     iMmsHeaders = &aMmsHeaders;
       
   484     iDecodeBuffer = &aDecodeBuffer;
       
   485     iDRMFlags = 0;
       
   486     iPosition = 0;
       
   487     iLength = 0;
       
   488     iRemoveDrm = EFalse;
       
   489     iDumpIncoming = iEntryWrapper->GetDumpFlag();
       
   490     iDecodingStage = EMmsHeaders;
       
   491     
       
   492     TRAP_IGNORE(DumpL());
       
   493     }
       
   494     
       
   495 // ---------------------------------------------------------
       
   496 // from class MMmsCodecDataSink
       
   497 //
       
   498 // ---------------------------------------------------------
       
   499 //
       
   500 TInt CMmsDecode::NextDataPart(
       
   501         CBufFlat& aBuffer,
       
   502         TInt& aPosition,
       
   503         TBool aLastDataChunk )
       
   504     {
       
   505     if ( iDecodingStage == EMmsNotApplicable )
       
   506         {
       
   507         aPosition = 0; // if not chunked, nothing handled by data sink -> keep all.
       
   508         return KErrNone;
       
   509         }
       
   510         
       
   511     TMsvEntry entry;    
       
   512     iEntryWrapper->GetIndexEntry( entry );
       
   513     if ( entry.Id() == KMsvNullIndexEntryId )
       
   514         {
       
   515         // We have no entry, behave as if in non-chunked mode.
       
   516         // We are getting a response that will not be saved
       
   517         // in a message entry, but may be decoded in its entirety
       
   518         // later.
       
   519         aPosition = 0; // if not chunked, nothing handled by data sink -> keep all.
       
   520         return KErrNone;
       
   521         }
       
   522         
       
   523     iDecodeBuffer = &aBuffer;
       
   524     
       
   525     iPosition = aPosition;
       
   526     // Use iLength to tell how much data must be dumped
       
   527     iLength = iDecodeBuffer->Size() - iPosition;
       
   528     TRAP_IGNORE(DumpL());
       
   529     // Use this to check when end of buffer has been reached
       
   530     iLength = iDecodeBuffer->Size();
       
   531     
       
   532     // We must get an edit store when we are called the first time.
       
   533     if ( !iStore && iError == KErrNone )
       
   534         {
       
   535         TRAP( iError, iStore = iEntryWrapper->EditStoreL() );
       
   536         }
       
   537     
       
   538     if ( iError != KErrNone )
       
   539         {
       
   540         return iError;
       
   541         }
       
   542     
       
   543     // clear this to make sure it does not point beyond buffer the next time
       
   544     iOldData = 0;
       
   545     
       
   546     TBool moreDataNeeded = EFalse;
       
   547     if ( iDecodingStage == EMmsHeaders )
       
   548         {
       
   549         // Decode headers and tell if there was enough data to do that
       
   550         moreDataNeeded = SinkHeaders( aLastDataChunk );
       
   551         }
       
   552         
       
   553     // If we have decoded all headers, we must see if we have enough data left
       
   554     // to decode the attachments.    
       
   555     
       
   556     // If we already ran out of data while decoding the MMS headers
       
   557     // we must get more data before even trying the attachments
       
   558     
       
   559     while ( !moreDataNeeded && !( aLastDataChunk && iPosition == iLength ) &&
       
   560         !( iDecodingStage == EMmsDone ) )
       
   561         {
       
   562         if ( iDecodingStage == EMmsAttachmentHeaders )
       
   563             {
       
   564             moreDataNeeded = SinkAttachmentHeaders( aLastDataChunk );
       
   565             }
       
   566             
       
   567         if ( iDecodingStage == EMmsAttachmentDataStart )
       
   568             {
       
   569             SinkAttachmentDataStart();
       
   570             }
       
   571             
       
   572         // If we have a monoblock, we don't know the length - we just write everything we've got    
       
   573         if ( iDecodingStage == EMmsAttachmentDataAppend  &&
       
   574             ( iAttaDataWritten < iCurrentAttaLength  || iCurrentAttaLength < 0 ) )
       
   575             {
       
   576             SinkAttachmentData();
       
   577             }
       
   578             
       
   579         if ( iDecodingStage == EMmsAttachmentDataAppend  &&
       
   580             ( ( iAttaDataWritten < iCurrentAttaLength ) ||
       
   581             ( iCurrentAttaLength < 0 && !aLastDataChunk ) ) )
       
   582             {
       
   583             moreDataNeeded = ETrue;
       
   584             }
       
   585             
       
   586         if ( ( iDecodingStage == EMmsAttachmentDataAppend &&
       
   587             iAttaDataWritten == iCurrentAttaLength ) || aLastDataChunk )
       
   588             {
       
   589             if ( iCurrentAttaLength > 0 )
       
   590                 {
       
   591                 FinishSinkingAttachment( aLastDataChunk );
       
   592                 }
       
   593             }
       
   594             
       
   595         if ( iError != KErrNone && iError != KMmsErrorRemoveDRM )
       
   596             {
       
   597             if ( iDecodingStage == EMmsAttachmentDataAppend )
       
   598                 {
       
   599                 // We try to clean up.
       
   600                 // We ignore the error as we have an error already
       
   601                 TRAP_IGNORE( iEntryWrapper->FinalizeAttachmentL(
       
   602                     *iStore, iCurrentAttaLength, iDRMFlags ) );
       
   603                 }
       
   604             // We cannot continue
       
   605             iDecodingStage = EMmsDone;
       
   606             }
       
   607         }
       
   608 
       
   609     // clear this in case it was set - it's not valid in chunked mode
       
   610     iFakeSubject = 0;
       
   611     iTextPlainLength = 0;
       
   612     
       
   613     if ( aLastDataChunk )
       
   614         {
       
   615         FinalizeSinkingLastChunk();
       
   616         }
       
   617         
       
   618     // remember how much data was left over
       
   619     if ( iPosition > iDecodeBuffer->Size() )
       
   620         {
       
   621         // this is paranoid, but we make sure that the caller will not panic
       
   622         iPosition = iDecodeBuffer->Size();
       
   623         }
       
   624     iOldData = iDecodeBuffer->Size() - iPosition;
       
   625     aPosition = iPosition;
       
   626     
       
   627     if ( iError != KErrNone )
       
   628         {
       
   629 #ifndef _NO_MMSS_LOGGING_
       
   630         TMmsLogger::Log( _L("Chunked decode - error %d, deleting store"), iError );
       
   631 #endif
       
   632         delete iStore;
       
   633         iStore = NULL;
       
   634         }
       
   635     
       
   636     return iError;
       
   637     }
       
   638     
       
   639 // ---------------------------------------------------------
       
   640 // from class MMmsCodecDataSink
       
   641 //
       
   642 // ---------------------------------------------------------
       
   643 //
       
   644 void CMmsDecode::RelaseDataSink()
       
   645     {
       
   646     // store must be released even in case of error
       
   647     delete iStore;
       
   648     iStore = NULL;
       
   649     }
       
   650 
       
   651 // ---------------------------------------------------------
       
   652 // from class MMmsCodecDataSink
       
   653 //
       
   654 // ---------------------------------------------------------
       
   655 //
       
   656 void CMmsDecode::ResetDataSink()
       
   657     {
       
   658     if ( iDecodingStage == EMmsNotApplicable )
       
   659         {
       
   660         // not chunked mode - do nothing
       
   661         return;
       
   662         }
       
   663         
       
   664     TMsvEntry entry;    
       
   665     if ( iEntryWrapper->GetIndexEntry( entry ) == KErrNone && 
       
   666          entry.Id() != KMsvNullIndexEntryId )
       
   667         {
       
   668         if ( !iStore )
       
   669             {
       
   670             TRAP_IGNORE(iStore = iEntryWrapper->EditStoreL());
       
   671             }
       
   672         // This should fail only if we run out of memory.
       
   673         // In that case the whole message entry will be deleted later,
       
   674         // so it does not make sense to return an error here
       
   675         // We just do our best and let the rest of the code to continue
       
   676         TRAP_IGNORE({
       
   677             MMsvAttachmentManager& attaMan = iStore->AttachmentManagerL();
       
   678             MMsvAttachmentManagerSync& attaManSync = iStore->AttachmentManagerExtensionsL();
       
   679             TInt count = attaMan.AttachmentCount();
       
   680             TInt i;
       
   681             // delete all old attachments as we are starting from the beginning
       
   682             for ( i = count - 1; i >= 0; i-- )
       
   683                {
       
   684                attaManSync.RemoveAttachmentL( i );
       
   685                }
       
   686             iStore->CommitL();   
       
   687             });
       
   688         }
       
   689     
       
   690     Reset();
       
   691     iMmsHeaders->Reset();
       
   692     iDRMFlags = 0;
       
   693     iPosition = 0;
       
   694     iLength = 0;
       
   695     iDumpIncoming = iEntryWrapper->GetDumpFlag();
       
   696     iDecodingStage = EMmsHeaders;
       
   697     if ( entry.Id() == KMsvNullIndexEntryId )
       
   698         {
       
   699         // no entry - cannot use chunked mode.
       
   700         iDecodingStage = EMmsNotApplicable;
       
   701         }
       
   702     else    
       
   703         {
       
   704          TRAP_IGNORE(DumpL());
       
   705         }
       
   706     }
       
   707 
       
   708 // ---------------------------------------------------------
       
   709 // From class CMsgActive
       
   710 //
       
   711 // ---------------------------------------------------------
       
   712 //
       
   713 void CMmsDecode::DoRunL()
       
   714     {
       
   715 
       
   716     // This routine takes the state machine through the states
       
   717     // until an error is encountered or the cycle completes.
       
   718 
       
   719     if ( iError != KErrNone )
       
   720         {
       
   721         // We encountered an error, and cannot continue
       
   722         // For the time being we just give up without trying
       
   723         // to do any decent cleanup.
       
   724         iStatus = iError;
       
   725         iState = EMmsIdle;
       
   726         // If we return from DoRunL without becoming active again,
       
   727         // RunL completes.
       
   728         return;
       
   729         }
       
   730 
       
   731     SelectNextState();
       
   732 
       
   733     if ( iState != EMmsFinished )
       
   734         {
       
   735         // If appropriate, ChangeStateL makes us active again
       
   736         ChangeStateL();
       
   737         // If we return from DoRunL without becoming active again,
       
   738         // RunL completes.
       
   739         }
       
   740     else
       
   741         {
       
   742         iUpdatedPosition = NULL; // no longer needed
       
   743         if ( !iDoNotUpdateParentEntry )
       
   744             {
       
   745             FinishL();
       
   746             }
       
   747         else
       
   748             {
       
   749             // store must be released in any case
       
   750             CommitStoreL();
       
   751             delete iStore;
       
   752             iStore = NULL;
       
   753             }
       
   754         iDoNotUpdateParentEntry = EFalse; // default value
       
   755         iState = EMmsIdle;
       
   756         iStatus = iError;
       
   757         // If we return from DoRunL without becoming active again,
       
   758         // RunL completes.
       
   759         }
       
   760 
       
   761     }
       
   762 
       
   763 // ---------------------------------------------------------
       
   764 // From class CMsgActive
       
   765 //
       
   766 // ---------------------------------------------------------
       
   767 //
       
   768 void CMmsDecode::DoComplete( TInt& /* aStatus */ )
       
   769     {
       
   770     // We are exiting the loop - we say we are idle now
       
   771     iState = EMmsIdle;
       
   772     // store must be released in any case - if it is NULL already, nothing happens
       
   773     // Can't leave here anymore
       
   774     TInt error;
       
   775     TRAP( error, CommitStoreL() );
       
   776     delete iStore;
       
   777     iStore = NULL;
       
   778     if ( iError == KErrNone )
       
   779         {
       
   780         iError = error;
       
   781         }
       
   782     }
       
   783 
       
   784 // ---------------------------------------------------------
       
   785 //
       
   786 // ---------------------------------------------------------
       
   787 //
       
   788 void CMmsDecode::SelectNextState()
       
   789     {
       
   790 
       
   791     // If appropiate, the functions called within the switch statement
       
   792     // will make us active again. If all is done, the asynchronous request
       
   793     // will complete
       
   794 
       
   795     switch ( iState )
       
   796         {
       
   797         case EMmsIdle:
       
   798             // start the loop
       
   799             iState = EMmsDecodingHeaders;
       
   800             break;
       
   801         case EMmsDecodingHeaders:
       
   802             if ( iNumberOfAttachments > 0 )
       
   803                 {
       
   804                 iState = EMmsDecodingAttachments;
       
   805                 }
       
   806             else
       
   807                 {
       
   808                 iState = EMmsFinished;
       
   809                 }
       
   810             break;
       
   811         case EMmsDecodingAttachments:
       
   812             if ( iNumberOfAttachments > 0 )
       
   813                 {
       
   814                 iState = EMmsDecodingAttachments;
       
   815                 }
       
   816             else
       
   817                 {
       
   818                 iState = EMmsFinished;
       
   819                 }
       
   820             break;
       
   821         case EMmsFinished:
       
   822             // No more states
       
   823             break;
       
   824         default:
       
   825             // Illegal state
       
   826 #ifndef _NO_MMSS_LOGGING_
       
   827             TMmsLogger::Log( _L("Decode - illegal state %d"), iState );
       
   828 #endif
       
   829             break;
       
   830         }
       
   831     }
       
   832 
       
   833 // ---------------------------------------------------------
       
   834 //
       
   835 // ---------------------------------------------------------
       
   836 //
       
   837 void CMmsDecode::ChangeStateL()
       
   838     {
       
   839     switch ( iState )
       
   840         {
       
   841         case EMmsDecodingHeaders:
       
   842             DecodeHeadersL();
       
   843             break;
       
   844         case EMmsDecodingAttachments:
       
   845             if ( iNumberOfAttachments > KMmsMaxAttachments )
       
   846                 {
       
   847                 // If we have too many attachments, we cannot
       
   848                 // handle the message. This is a temporary
       
   849                 // error code that takes care of denying retries
       
   850                 iError = KMmsErrorEMRUExceeded;
       
   851                 CompleteSelf( iError );
       
   852                 return;
       
   853                 }
       
   854             DecodeOneAttachmentL();
       
   855             iNumberOfAttachments--;
       
   856             if ( iUpdatedPosition )
       
   857                 {
       
   858                 // The user wants to know where to continue
       
   859                 *iUpdatedPosition = iPosition;
       
   860                 }
       
   861             break;
       
   862         default:
       
   863             iState = EMmsIdle;
       
   864             break;
       
   865         }
       
   866     }
       
   867 
       
   868 // ---------------------------------------------------------
       
   869 //
       
   870 // ---------------------------------------------------------
       
   871 //
       
   872 void CMmsDecode::Reset()
       
   873     {
       
   874     iError = KErrNone; // start with clean slate
       
   875     iMimeHeaders->Reset();
       
   876     delete iStore;
       
   877     iStore = NULL; // this is a new message, cannot use old store
       
   878     iUpdatedPosition = NULL;
       
   879     iPosition = 0;
       
   880     iDataStart = 0;
       
   881     iNextStart = 0;
       
   882     iNumberOfAttachments = 0;
       
   883     iLastHeader = EFalse;
       
   884     iTotalSize = 0;
       
   885     iFakeSubject = 0;
       
   886     iCharacterSet = KMmsUsAscii; // if no character set, default is US_ASCII
       
   887     iTextPlainLength = 0;
       
   888     iMultipartType = 0;
       
   889     iRootContentId.Set( TPtrC8() );
       
   890     delete iRootContentIdBuffer;
       
   891     iRootContentIdBuffer = NULL;
       
   892     iRootAttachmentId = 0;
       
   893     iFirstAttachmentId = 0;
       
   894     iFirstTextPlain = 0;
       
   895     iUseForSubject = EFalse;
       
   896     iAttaNumber = 0;
       
   897     iSmilCount = 0;
       
   898     iAudioCount = 0;
       
   899     iPlainTexts = 0;
       
   900     iDoNotUpdateParentEntry = EFalse;
       
   901     iDecodingStage = EMmsNotApplicable;
       
   902     iOldData = 0;
       
   903     iLogAllDecoded = ETrue;
       
   904     }
       
   905 
       
   906 // ---------------------------------------------------------
       
   907 //
       
   908 // ---------------------------------------------------------
       
   909 TBool CMmsDecode::SinkHeaders( TBool aLastDataChunk )
       
   910     {
       
   911     TBool enoughData = ETrue;
       
   912 #ifndef _NO_MMSS_LOGGING_
       
   913         TMmsLogger::Log( _L("Chunked decode - MMS headers"));
       
   914 #endif
       
   915     TInt error = KErrNone;
       
   916     // See if we have a whole header
       
   917     // We must have enough data to contain both the header and its value.
       
   918     // Otherwise we must ask for more data.
       
   919     TRAP ( error,
       
   920         {
       
   921         enoughData = CheckHeaderLength();
       
   922         while ( enoughData &&
       
   923             ( iError != KErrCorrupt ) &&
       
   924             ( !iLastHeader ) )
       
   925             {
       
   926             DecodeOneHeaderL();
       
   927             if ( ( iError != KErrCorrupt ) &&
       
   928                 ( !iLastHeader ) )
       
   929                 {
       
   930                 enoughData = CheckHeaderLength();
       
   931                 }
       
   932             }
       
   933         });
       
   934         
       
   935     if ( iError == KErrNone )
       
   936         {
       
   937         // we should get an error in decoding only if memory runs out
       
   938         // or the message is corrupted
       
   939         iError = error;
       
   940         }
       
   941     // check if we reached the end of the headers and can continue
       
   942     // with attachments
       
   943     if ( iError == KErrNone )
       
   944         {
       
   945         if ( iLastHeader )
       
   946             {
       
   947             // Headers decoded successfully, can continue with attachments
       
   948             // The uintvar specifying then number of attachments was decoded
       
   949             // at the end of the MMS headers in connection with multipart header.
       
   950             // This leaves only if out of disk space or out of memory
       
   951             TRAP( iError, SaveMMSHeadersL() );
       
   952             iDecodingStage = EMmsAttachmentHeaders;
       
   953             }
       
   954         else if ( aLastDataChunk && iPosition >= iLength )
       
   955             {
       
   956             // Headers decoded successfully, but no attachment present
       
   957             // This is an empty message
       
   958             TRAP( iError, SaveMMSHeadersL() );
       
   959             iDecodingStage = EMmsAttachmentHeaders;
       
   960             }
       
   961         else if ( aLastDataChunk && !enoughData )
       
   962             {
       
   963             // we have got something that cannot be decoded
       
   964             iError = KErrCorrupt;
       
   965             iDecodingStage = EMmsDone;
       
   966             }
       
   967         else 
       
   968             {
       
   969             // Do nothing - keep LINT happy
       
   970             }
       
   971         }
       
   972     // return ETrue if more data is needed.    
       
   973     return !enoughData;
       
   974     }
       
   975 
       
   976 // ---------------------------------------------------------
       
   977 //
       
   978 // ---------------------------------------------------------
       
   979 TBool CMmsDecode::SinkAttachmentHeaders( TBool aLastDataChunk )
       
   980     {
       
   981     TBool moreDataNeeded = EFalse;
       
   982     TInt error = KErrNone;
       
   983     
       
   984     // We try to get all attachment headers at one go
       
   985     // It is easier than decoding the attachment headers one by one
       
   986     // As we have headers that tell the total length of attachment
       
   987     // headers we can ask for more data if needed.
       
   988     // The attachment headers are not normally very long, and if they
       
   989     // are, the message is probably corrupted anyway
       
   990     
       
   991 #ifndef _NO_MMSS_LOGGING_
       
   992     TMmsLogger::Log( _L("Chunked decode - Attachment headers"));
       
   993 #endif
       
   994     iAttaDataWritten = 0; // no data yet    
       
   995     iCurrentAttaLength = 0;
       
   996     TInt currentPosition = iPosition;
       
   997     TInt uintvarStart = iPosition;
       
   998     iRemoveDrm = EFalse; // no DRM so far
       
   999     if ( iMultipartType && CheckUintvarLength() )
       
  1000         {
       
  1001         // restore position to start of Uintvar
       
  1002         iPosition = uintvarStart;
       
  1003         TUint attaHeaderLength = GetUintvar();
       
  1004         // got atta header length. Do we still have more data.
       
  1005         uintvarStart = iPosition;
       
  1006         if ( CheckUintvarLength() )
       
  1007             {
       
  1008             iPosition = uintvarStart;
       
  1009             iCurrentAttaLength = GetUintvar();
       
  1010             // attaHeaderLength is the length of content type header and other
       
  1011             // headers combined.
       
  1012             // Do we still have that much data.
       
  1013             if ( iLength - iPosition >= attaHeaderLength )
       
  1014                 {
       
  1015                 // decode headers
       
  1016                 iPosition = currentPosition;
       
  1017                 TRAP( error, DecodeAttachmentHeadersL() );
       
  1018                 if ( iError == KErrNone )
       
  1019                     {
       
  1020                     iError = error;
       
  1021                     }
       
  1022                 if ( iCurrentAttaLength == 0 )
       
  1023                     {
       
  1024                     // if the attachment is empty, we do not create an attachment
       
  1025                     // we should check here if there is any data left
       
  1026                     iDecodingStage = EMmsAttachmentHeaders;
       
  1027                     }
       
  1028                 else if ( iError == KErrNone )
       
  1029                     {
       
  1030                     iDecodingStage = EMmsAttachmentDataStart;
       
  1031                     }
       
  1032                 else
       
  1033                     {
       
  1034                     // do nothing - keep LINT happy
       
  1035                     }
       
  1036                 }
       
  1037             else     
       
  1038                 {
       
  1039                 // not enough data for decoding headers - give up
       
  1040                 // and ask for more data
       
  1041                 iPosition = currentPosition;
       
  1042                 moreDataNeeded = ETrue;
       
  1043 #ifndef _NO_MMSS_LOGGING_
       
  1044                 TMmsLogger::Log( _L("Chunked decode - need more data for atta headers"));
       
  1045 #endif
       
  1046                 }
       
  1047             }
       
  1048         else
       
  1049             {
       
  1050             // not enough data for determining attachment data length - give up
       
  1051             // and ask for more data
       
  1052             iPosition = currentPosition;
       
  1053             moreDataNeeded = ETrue;
       
  1054             }
       
  1055         }
       
  1056     else if ( iMultipartType == 0 && !( iLength - iPosition < KMms2k && !aLastDataChunk ) )
       
  1057         {
       
  1058         // One chunk, no multipart, very bad, try anyway
       
  1059         // We can only guess how much of the data is headers.
       
  1060         TRAP( error, DecodeAttachmentHeadersL() );
       
  1061         if ( iError == KErrNone )
       
  1062             {
       
  1063             iError = error;
       
  1064             }
       
  1065         iCurrentAttaLength = -1; // Don't know
       
  1066         if ( !( aLastDataChunk && iPosition == iLength ) && iError == KErrNone )
       
  1067             {
       
  1068             // There is some data
       
  1069             iDecodingStage = EMmsAttachmentDataStart;
       
  1070             }
       
  1071         else
       
  1072             {
       
  1073             iCurrentAttaLength = 0; // no data
       
  1074             }
       
  1075         }
       
  1076     else
       
  1077         {
       
  1078         // not enough data for determining attachment header length - give up
       
  1079         // and ask for more data
       
  1080         iPosition = currentPosition;
       
  1081         moreDataNeeded = ETrue;
       
  1082         }
       
  1083 
       
  1084     return moreDataNeeded;
       
  1085     }
       
  1086     
       
  1087 // ---------------------------------------------------------
       
  1088 //
       
  1089 // ---------------------------------------------------------
       
  1090 //
       
  1091 void CMmsDecode::SinkAttachmentDataStart()
       
  1092     {
       
  1093     TInt error = KErrNone;
       
  1094     
       
  1095 #ifndef _NO_MMSS_LOGGING_
       
  1096     TMmsLogger::Log( _L("Chunked decode - Attachment data start"));
       
  1097 #endif
       
  1098     // Now the attachment file must be created.
       
  1099     // We should also have enough data
       
  1100     
       
  1101     // First an empty attachment is created. No data is needed for it.
       
  1102     TRAP ( error, iEntryWrapper->CreateEmptyFileAttachmentL(
       
  1103             *iStore,
       
  1104             iParse.NameAndExt(),
       
  1105             *iMimeHeaders,
       
  1106             iCurrentAttachment )
       
  1107         );
       
  1108         
       
  1109     if ( iError == KErrNone && error != KErrNone )
       
  1110         {
       
  1111         iError = error;
       
  1112         }
       
  1113     if ( iError == KErrNone )
       
  1114         {
       
  1115         if ( iUseForSubject )
       
  1116             {
       
  1117             iFirstTextPlain = iCurrentAttachment;
       
  1118             iUseForSubject = EFalse;
       
  1119             }
       
  1120 
       
  1121 #ifndef _NO_MMSS_LOGGING_
       
  1122         TRAP_IGNORE({
       
  1123             MMsvAttachmentManager& attaMan = iStore->AttachmentManagerL();
       
  1124             CMsvAttachment* attaInfo = attaMan.GetAttachmentInfoL( iCurrentAttachment );
       
  1125             TMmsLogger::Log( _L("- Attachment created %S"), &attaInfo->FilePath() );
       
  1126             delete attaInfo;
       
  1127             attaInfo = NULL;
       
  1128             });
       
  1129 #endif
       
  1130         }
       
  1131     if ( iError == KErrNone )
       
  1132         {
       
  1133         iDecodingStage = EMmsAttachmentDataAppend;
       
  1134         }
       
  1135     }
       
  1136     
       
  1137 // ---------------------------------------------------------
       
  1138 //
       
  1139 // ---------------------------------------------------------
       
  1140 //
       
  1141 void CMmsDecode::SinkAttachmentData()
       
  1142     {
       
  1143     TInt error = KErrNone;
       
  1144     // no problem with signed/unsigned comparison - size cannot be signed
       
  1145     if ( iPosition < iDecodeBuffer->Size() )
       
  1146         {
       
  1147         TPtr8 attaDataPtr = iDecodeBuffer->Ptr( iPosition );
       
  1148         if ( attaDataPtr.Length() > iCurrentAttaLength - iAttaDataWritten &&
       
  1149             iCurrentAttaLength > 0 )
       
  1150             {
       
  1151             // If we don't know the amount of attachment data, we write the
       
  1152             // whole buffer
       
  1153             attaDataPtr.SetLength( iCurrentAttaLength - iAttaDataWritten );
       
  1154             }
       
  1155         if ( iError == KMmsErrorRemoveDRM )
       
  1156             {
       
  1157             iRemoveDrm = ETrue;
       
  1158             iError = KErrNone;
       
  1159             }
       
  1160         if ( !iRemoveDrm )
       
  1161             {
       
  1162             // we have data that can be written to the file
       
  1163             TRAP( error,
       
  1164                 iError = iEntryWrapper->ProcessAttachmentDataL( attaDataPtr, iDRMFlags )
       
  1165                 );
       
  1166             if ( iError == KErrNone )
       
  1167                 {
       
  1168                 iError = error;
       
  1169                 }
       
  1170             if ( iError == KMmsErrorRemoveDRM )
       
  1171                 {
       
  1172                 iRemoveDrm = ETrue;
       
  1173                 iError = KErrNone;
       
  1174                 }
       
  1175             }
       
  1176         // if attachment is DRM protected and must be removed, just increase pointers
       
  1177         iPosition += attaDataPtr.Length();
       
  1178         iAttaDataWritten += attaDataPtr.Length();
       
  1179 #ifndef _NO_MMSS_LOGGING_
       
  1180         TMmsLogger::Log( _L("Chunked decode - Attachment data %d, cumulative %d"),
       
  1181         attaDataPtr.Length(), iAttaDataWritten );
       
  1182 #endif
       
  1183         }
       
  1184     }
       
  1185     
       
  1186 // ---------------------------------------------------------
       
  1187 //
       
  1188 // ---------------------------------------------------------
       
  1189 //
       
  1190 void CMmsDecode::FinishSinkingAttachment( TBool aLastDataChunk )
       
  1191     {
       
  1192     TInt error = KErrNone;
       
  1193 #ifndef _NO_MMSS_LOGGING_
       
  1194     TMmsLogger::Log( _L("Chunked decode - Attachment ready"));
       
  1195 #endif
       
  1196     // end of attachment - close file
       
  1197     // This must be called even if the error indicates the DRM file must be removed
       
  1198     // This call does all cleanup and actually removes the DRM attachment if needed.
       
  1199     TRAPD( error2,
       
  1200         error = iEntryWrapper->FinalizeAttachmentL( *iStore, iCurrentAttaLength, iDRMFlags )
       
  1201         );
       
  1202     if ( iError == KErrNone )
       
  1203         {
       
  1204         iError = error;
       
  1205         }
       
  1206     if ( iError == KErrNone )
       
  1207         {
       
  1208         iError = error2;
       
  1209         }
       
  1210     // If DRM handling changed file size, iCurrentAttaLength gets adjusted
       
  1211     if ( iError == KMmsErrorRemoveDRM )
       
  1212         {
       
  1213         // if error == KMmsErrorRemoveDRM all is well, and we can continue
       
  1214         // but we don't have an attachment
       
  1215         iError = KErrNone;
       
  1216         // DRM already removed - flag can be cleared now
       
  1217         iRemoveDrm = EFalse;
       
  1218         }
       
  1219     else if ( iError == KErrNone )
       
  1220         {
       
  1221         iTotalSize += iMimeHeaders->Size() + iCurrentAttaLength;
       
  1222         if ( ( iMultipartType == KMmsAssignedApplicationVndWapMultipartRelated ) &&
       
  1223             ( iRootContentId.Length() > 0 ) &&
       
  1224             ( iRootAttachmentId == 0 ) )
       
  1225             {
       
  1226             // check if content-id's match
       
  1227             if ( iRootContentId.Compare( iMimeHeaders->ContentId() ) == 0 )
       
  1228                 {
       
  1229                 iRootAttachmentId = iCurrentAttachment;
       
  1230                 }
       
  1231             }
       
  1232         }
       
  1233     else
       
  1234         {
       
  1235         // do nothing - keep LINT happy
       
  1236         }
       
  1237     // no problem with signed/unsigned    
       
  1238     if ( !( aLastDataChunk && iPosition == iLength ) &&
       
  1239         ( iAttaNumber < iNumberOfAttachments ) )
       
  1240         {
       
  1241         iDecodingStage = EMmsAttachmentHeaders;
       
  1242         }
       
  1243     else
       
  1244         {
       
  1245         iDecodingStage = EMmsDone;
       
  1246         }
       
  1247     }
       
  1248     
       
  1249 // ---------------------------------------------------------
       
  1250 //
       
  1251 // ---------------------------------------------------------
       
  1252 //
       
  1253 void CMmsDecode::FinalizeSinkingLastChunk()
       
  1254     {
       
  1255     TInt error = KErrNone;
       
  1256     
       
  1257 #ifndef _NO_MMSS_LOGGING_
       
  1258     TMmsLogger::Log( _L("Chunked decode - last chunk"));
       
  1259 #endif
       
  1260     // If we have reached the last chunk, all data should be handled by now
       
  1261     iDecodingStage = EMmsDone;
       
  1262     
       
  1263     // Read possible data from plain text file into encode buffer
       
  1264     // and set iFake subject to point to the buffer
       
  1265     // Must start from 1 because data would never start from 0
       
  1266     // and value 0 indicates no fake subject available.
       
  1267 
       
  1268     // Fake subject handling        
       
  1269     // Our store should still be valid.
       
  1270     // The fake subject handling and multipart/report handling are "best effort"
       
  1271     // Even if the operations fail, the code continues as if no error was encountered.
       
  1272     TInt oldSize = iDecodeBuffer->Size();
       
  1273     TRAP_IGNORE(
       
  1274         {
       
  1275         // if we have no subject but we do have only one text attachment
       
  1276         // we take text from the beginning as subject
       
  1277         // 
       
  1278         if ( iFirstTextPlain && iPlainTexts == 1 && iMmsHeaders->Subject().Length() == 0 )
       
  1279             {
       
  1280             MMsvAttachmentManager& attaMan = iStore->AttachmentManagerL();
       
  1281             RFile textAtta = attaMan.GetAttachmentFileL( iFirstTextPlain );
       
  1282             CleanupClosePushL( textAtta );
       
  1283             iDecodeBuffer->ResizeL( KMmsMaxDescription + 1 );
       
  1284             // We must start from any position > 0
       
  1285             TPtr8 pointer = iDecodeBuffer->Ptr( 1 );
       
  1286             // read text into buffer
       
  1287             error = textAtta.Read( pointer ); 
       
  1288             if ( error == KErrNone )
       
  1289                 {
       
  1290                 iFakeSubject = 1;
       
  1291                 iTextPlainLength = pointer.Length();
       
  1292                 }
       
  1293             CleanupStack::PopAndDestroy( &textAtta ); // textAtta file handle closed
       
  1294             }
       
  1295             
       
  1296         // Multipart/report handling
       
  1297         if ( iMultipartType == KMmsAssignedApplicationVndWapMultipartReport )
       
  1298             {
       
  1299             // we only keep the first part from multipart/report
       
  1300             MMsvAttachmentManager& attaMan = iStore->AttachmentManagerL();
       
  1301             MMsvAttachmentManagerSync& attaManSync = iStore->AttachmentManagerExtensionsL();
       
  1302             TInt count = attaMan.AttachmentCount();
       
  1303             TInt i;
       
  1304             for ( i = count - 1; i > 0; i-- )
       
  1305                 {
       
  1306                 attaManSync.RemoveAttachmentL( i );
       
  1307                 }
       
  1308             }
       
  1309         });
       
  1310     
       
  1311     error = KErrNone;
       
  1312     iLength = iDecodeBuffer->Size();
       
  1313     TRAP( error, FinishL() );
       
  1314     TRAP_IGNORE( CommitStoreL() );
       
  1315     delete iStore;
       
  1316     iStore = NULL;
       
  1317     if ( iError == KErrNone )
       
  1318         {
       
  1319         iError = error;
       
  1320         }
       
  1321     // Restore the original buffer size
       
  1322     // This should actually never leave because we are just  restoring the original size
       
  1323     TRAP_IGNORE( iDecodeBuffer->ResizeL( oldSize ));
       
  1324     iLength = iDecodeBuffer->Size();
       
  1325     }
       
  1326     
       
  1327 // ---------------------------------------------------------
       
  1328 //
       
  1329 // ---------------------------------------------------------
       
  1330 //
       
  1331 void CMmsDecode::DecodeHeadersL()
       
  1332     {
       
  1333 
       
  1334     if ( iLength < KMmsMinHeaderLength )
       
  1335         {
       
  1336         // cannot decode if nothing to decode
       
  1337         // each header is at least 2 bytes. 
       
  1338         // If not at least 2 bytes, no can do.
       
  1339         iError = KErrCorrupt;
       
  1340         }
       
  1341 
       
  1342     iMmsHeaders->Reset();
       
  1343     
       
  1344     // Save the time the entry was received into the MMS headers
       
  1345     // the value in TMsvEntry may change, but this remains
       
  1346     TTime now;      
       
  1347     now.UniversalTime();
       
  1348     iMmsHeaders->SetReceivingTime( now );
       
  1349 
       
  1350     // each header byte must be followed by at least one byte value.
       
  1351     // otherwise the message is corrupted
       
  1352     // when we reach the header that indicates the start of the attachment
       
  1353     // structure, we expect that no headers follow the attachment part.
       
  1354     
       
  1355     // each header is at least 2 bytes - header name and value
       
  1356     while ( ( iPosition <= iLength - KMmsMinHeaderLength ) &&
       
  1357         ( iError != KErrCorrupt ) &&
       
  1358         ( !iLastHeader ) )
       
  1359         {
       
  1360         DecodeOneHeaderL();
       
  1361         }
       
  1362       
       
  1363     SaveMMSHeadersL();    
       
  1364 
       
  1365     TRequestStatus* status = &iStatus;
       
  1366     *status = KRequestPending;
       
  1367     SetActive();
       
  1368 
       
  1369     // Now we indicate we already did everything.
       
  1370     User::RequestComplete( status, iError );
       
  1371 
       
  1372     }
       
  1373     
       
  1374 // ---------------------------------------------------------
       
  1375 //
       
  1376 // ---------------------------------------------------------
       
  1377 //
       
  1378 void CMmsDecode::SaveMMSHeadersL()
       
  1379     {
       
  1380     
       
  1381     // We save the headers only in case we are decoding an incoming
       
  1382     // message. In other cases we deliver the results back to the caller
       
  1383     // in iMmsHeaders.
       
  1384     // Only retrieve confirmation is supposed to contain body that
       
  1385     // needs saving of attachments.
       
  1386 
       
  1387     // We save a message of type KMmsMessageTypeMSendReq as it were an
       
  1388     // incoming message, as during tests we get our own
       
  1389     // send requests back as new messages.
       
  1390     // We also save notifications and delivery reports.
       
  1391     // However, in normal case MMS server calls a different function
       
  1392     // (CMmsDecode::DecodeHeadersL) to decode notifications and delivery
       
  1393     // reports as they do not contain attachments, and delivery reports
       
  1394     // are not saved on disk, but are logged and deleted.
       
  1395     // For testing purposes upload request is saved as an incoming message
       
  1396 
       
  1397     if ( ( iMmsHeaders->MessageType() == KMmsMessageTypeMRetrieveConf ||
       
  1398         iMmsHeaders->MessageType() == KMmsMessageTypeMSendReq ||
       
  1399         iMmsHeaders->MessageType() == KMmsMessageTypeMNotificationInd ||
       
  1400         iMmsHeaders->MessageType() == KMmsMessageTypeDeliveryInd ||
       
  1401         iMmsHeaders->MessageType() == KMmsMessageTypeMBoxUploadReq ) &&
       
  1402         iError == KErrNone )
       
  1403         {
       
  1404         // The entry wrapper must be pointing to our message entry
       
  1405         if ( !iStore )
       
  1406             {
       
  1407             iStore = iEntryWrapper->EditStoreL();
       
  1408             }
       
  1409         iError = iEntryWrapper->DiskSpaceBelowCriticalLevelL( iMmsHeaders->Size() );
       
  1410         if ( iError == KErrNone )
       
  1411             {
       
  1412             iMmsHeaders->StoreL( *iStore );
       
  1413             iStore->CommitL();
       
  1414             }
       
  1415         // the store will be left open until all the attachments have been saved
       
  1416         }
       
  1417 
       
  1418     // Afterwards we must calculate the total message size and
       
  1419     // store it in the entry.
       
  1420     }
       
  1421 
       
  1422 // ---------------------------------------------------------
       
  1423 //
       
  1424 // ---------------------------------------------------------
       
  1425 //
       
  1426 void CMmsDecode::DecodeOneHeaderL()
       
  1427     {
       
  1428 
       
  1429     TInt header;
       
  1430     header = GetHeaderName();
       
  1431 
       
  1432     if ( header == -1 )
       
  1433         {
       
  1434         return; // skip unknown
       
  1435         }
       
  1436 
       
  1437     // Get the corresponding value
       
  1438     
       
  1439     switch ( header )
       
  1440         {
       
  1441         case KMmsAssignedFrom:
       
  1442             DecodeFromHeaderL();
       
  1443             break;
       
  1444         case KMmsAssignedTo:
       
  1445             DecodeToL();
       
  1446             break;
       
  1447         case KMmsAssignedCc:
       
  1448             DecodeCcL();
       
  1449             break;
       
  1450         case KMmsAssignedBcc:
       
  1451             DecodeBccL();
       
  1452             break;
       
  1453         case KMmsAssignedContentLocation:
       
  1454             DecodeContentLocationHeaderL();
       
  1455             break;
       
  1456         case KMmsAssignedDate:
       
  1457             DecodeDateHeaderL();
       
  1458             break;
       
  1459         case KMmsAssignedDeliveryReport:
       
  1460             DecodeDeliveryReportHeader();
       
  1461             break;
       
  1462         case KMmsAssignedDeliveryTime:
       
  1463             DecodeDeliveryTimeL();
       
  1464             break;
       
  1465         case KMmsAssignedExpiry:
       
  1466             DecodeExpiryL();
       
  1467             break;
       
  1468         case KMmsAssignedMessageClass:
       
  1469             DecodeMessageClass();
       
  1470             break;
       
  1471         case KMmsAssignedMessageId:
       
  1472             DecodeMessageIdL();
       
  1473             break;
       
  1474         case KMmsAssignedMessageType:
       
  1475             DecodeMessageType();
       
  1476             break;
       
  1477         case KMmsAssignedMmsVersion:
       
  1478             DecodeMmsVersion();
       
  1479             break;
       
  1480         case KMmsAssignedMessageSize:
       
  1481             DecodeMessageSize();
       
  1482             break;
       
  1483         case KMmsAssignedPriority:
       
  1484             DecodePriority();
       
  1485             break;
       
  1486         case KMmsAssignedReadReply:
       
  1487             DecodeReadReply();
       
  1488             break;
       
  1489         case KMmsAssignedReportAllowed:
       
  1490             DecodeReportAllowed();
       
  1491             break;
       
  1492         case KMmsAssignedResponseStatus:
       
  1493         case KMmsAssignedRetrieveStatus:
       
  1494             DecodeResponseStatusL( header );
       
  1495             break;
       
  1496         case KMmsAssignedResponseText:
       
  1497         case KMmsAssignedRetrieveText:
       
  1498         case KMmsAssignedStatusText:
       
  1499             DecodeResponseTextL( header );
       
  1500             break;
       
  1501         case KMmsAssignedSenderVisibility:
       
  1502             DecodeSenderVisibility();
       
  1503             break;
       
  1504         case KMmsAssignedStatus:
       
  1505             DecodeStatus();
       
  1506             break;
       
  1507         case KMmsAssignedSubject:
       
  1508             DecodeSubjectL();
       
  1509             break;
       
  1510         case KMmsAssignedTID:
       
  1511             DecodeTidL();
       
  1512             break;
       
  1513         case KMmsAssignedContentType:
       
  1514             // Content type is the last header in the PDU
       
  1515             // Number of attachments and last header indicator will be set 
       
  1516             DecodeContentTypeL();
       
  1517             break;
       
  1518         case KMmsAssignedReadStatus:
       
  1519             DecodeReadStatus();
       
  1520             break;
       
  1521         case KMmsAssignedReplyCharging:
       
  1522             DecodeReplyCharging();
       
  1523             break;
       
  1524         case KMmsAssignedReplyChargingDeadline:
       
  1525             DecodeReplyChargingDeadlineL();
       
  1526             break;
       
  1527         case KMmsAssignedReplyChargingID:
       
  1528             DecodeReplyChargingIdL();
       
  1529             break;
       
  1530         case KMmsAssignedReplyChargingSize:
       
  1531             DecodeReplyChargingSize();
       
  1532             break;
       
  1533         case KMmsAssignedPreviouslySentBy:
       
  1534             DecodePreviousSenderL();
       
  1535             break;
       
  1536         case KMmsAssignedPreviouslySentDate:
       
  1537             DecodePreviouslySentDateL();
       
  1538             break;
       
  1539         case KMmsAssignedMmsStore:
       
  1540             DecodeStoreHeaderL();
       
  1541             break;
       
  1542         case KMmsAssignedMMState:
       
  1543             DecodeMMBoxStateL();
       
  1544             break;
       
  1545         case KMmsAssignedMMFlags:
       
  1546             GetKeywordL();
       
  1547             break;
       
  1548         case KMmsAssignedStoreStatus:
       
  1549             DecodeMMBoxStoreStatusL();
       
  1550             break;
       
  1551         case KMmsAssignedStoreStatusText:
       
  1552             DecodeMMBoxStoreStatusTextL();
       
  1553             break;
       
  1554         case KMmsAssignedStored:
       
  1555             DecodeStoredInMMBoxHeaderL();
       
  1556             break;
       
  1557         case KMmsAssignedAttributes:
       
  1558             DecodeAttributesHeaderL();
       
  1559             break;
       
  1560         case KMmsAssignedTotals:
       
  1561             DecodeTotalsL();
       
  1562             break;
       
  1563         case KMmsAssignedMboxTotals:
       
  1564             DecodeMboxTotalsL();
       
  1565             break;
       
  1566         case KMmsAssignedQuotas:
       
  1567             DecodeQuotaHeaderL();
       
  1568             break;
       
  1569         case KMmsAssignedMboxQuotas:
       
  1570             DecodeMBoxQuotasL();
       
  1571             break;
       
  1572         case KMmsAssignedMessageCount:
       
  1573             DecodeMessageCountL();
       
  1574             break;
       
  1575         case KMmsAssignedStart:
       
  1576             DecodeStartInMMBoxViewL();
       
  1577             break;
       
  1578         case KMmsAssignedDistributionIndicator:
       
  1579             DecodeDistributionIndicator();
       
  1580             break;
       
  1581         case KMmsAssignedElementDescriptor:
       
  1582             DecodeElementDescriptorL();
       
  1583             break;
       
  1584         case KMmsAssignedLimit:
       
  1585             DecodeMessageLimitL();
       
  1586             break;
       
  1587         case KMmsAssignedExtendedNotificationText:
       
  1588             DecodeExtNotifTextL();
       
  1589             break;
       
  1590         case KMmsAssignedExtendedNotificationEOL:
       
  1591             DecodeExtNotifEolL();
       
  1592             break;
       
  1593         case KMmsAssignedContentClass:
       
  1594             DecodeContentClass();
       
  1595             break;
       
  1596         case KMmsAssignedDrmContent:
       
  1597             DecodeDrmContentHeader();
       
  1598             break;
       
  1599         case KMmsAssignedAdaptationAllowed:
       
  1600             DecodeAdaptationAllowed();
       
  1601             break;
       
  1602         case KMmsAssignedApplicId:
       
  1603             DecodeApplicationIdL();
       
  1604             break;
       
  1605         case KMmsAssignedReplyApplicId:
       
  1606             DecodeReplyApplicationIdL();
       
  1607             break;
       
  1608         case KMmsAssignedAuxApplicInfo:
       
  1609             DecodeApplicationInfoL();
       
  1610             break;
       
  1611         case KMmsAssignedRecommendedRetrievalMode:
       
  1612             DecodeRecommendedRetrievalMode();
       
  1613             break;
       
  1614         case KMmsAssignedRecommendedRetrievalModeText:
       
  1615             DecodeRecommendedRetrievalModeTextL();
       
  1616             break;
       
  1617         case KMmsAssignedReplaceId:
       
  1618         case KMmsAssignedCancelId:
       
  1619             DecodeCancelReplaceIdL( header );
       
  1620             break;
       
  1621         case KMmsAssignedCancelStatus:
       
  1622             DecodeCancelStatus();
       
  1623             break;
       
  1624         default:
       
  1625 #ifndef _NO_MMSS_LOGGING_
       
  1626             TMmsLogger::Log( _L("- Unsupported header : 0x%02X"), (header & KMms0x7F) );
       
  1627 #endif
       
  1628             // This is an error.
       
  1629             // This is an unknown header, just ignore it.
       
  1630             SkipFieldValue();
       
  1631             break;
       
  1632         }
       
  1633 
       
  1634     }
       
  1635 
       
  1636 // ---------------------------------------------------------
       
  1637 //
       
  1638 // ---------------------------------------------------------
       
  1639 //
       
  1640 TInt CMmsDecode::GetHeaderName()
       
  1641     {
       
  1642 
       
  1643     TInt header;
       
  1644     header = -1; // unknown
       
  1645 
       
  1646     TUint8 byte;
       
  1647 
       
  1648     if ( iPosition > iLength - KMmsMinHeaderLength )
       
  1649         {
       
  1650         iError = KErrCorrupt;
       
  1651         return header;
       
  1652         }
       
  1653 
       
  1654     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1655 
       
  1656     // byte cannot be bigger than 255. No need to test upper limit
       
  1657     if ( byte >= KMms0x80 )
       
  1658         {
       
  1659         // well known header, advance pointer
       
  1660         iPosition++;
       
  1661         header = byte;
       
  1662         return header;
       
  1663         }
       
  1664 
       
  1665     // we cannot handle headers which are not well known.
       
  1666     // however, we should be able to skip them and ignore them.
       
  1667     // If a field name has no encoding, it must be encoded as text.
       
  1668 
       
  1669     // If the header is corrupted, the value may be something
       
  1670     // illegal. We should have a mechanism of skipping
       
  1671     // illegal codings, too, but if the header name is not a
       
  1672     // short integer or a text string, we are so deep in trouble
       
  1673     // that we cannot decode the whole message anyway.
       
  1674 
       
  1675     // We handle some known text headers. Here we check if possible
       
  1676     // text header is one we know. If not, it is skipped.
       
  1677 
       
  1678     TPtrC8 byteString = GetByteString();
       
  1679 
       
  1680     // see if this is in our table
       
  1681     TInt i = 0;
       
  1682     TBool matchFound = EFalse;
       
  1683     TPtrC8 matchTablePointer;
       
  1684     matchTablePointer.Set( KMmsExtensionHeaderLookup[i].extensionHeader );
       
  1685     while ( matchTablePointer.Length() > 0 && !matchFound )
       
  1686         {
       
  1687         if ( matchTablePointer.CompareF( byteString ) == 0 )
       
  1688             {
       
  1689             header = *KMmsExtensionHeaderLookup[i].assignedValue;
       
  1690             matchFound = ETrue;
       
  1691             }
       
  1692         i++;
       
  1693         matchTablePointer.Set( KMmsExtensionHeaderLookup[i].extensionHeader );
       
  1694         }
       
  1695 
       
  1696 #ifndef _NO_MMSS_LOGGING_
       
  1697     // we do not leave because of logging.
       
  1698     TInt error = KErrNone;
       
  1699     TRAP( error,
       
  1700         {
       
  1701         // length - terminating zero
       
  1702         HBufC16* buffer = NULL;
       
  1703         buffer = HBufC16::NewLC( byteString.Length() );
       
  1704         buffer->Des().Copy( byteString );
       
  1705         TPtrC dummy;
       
  1706         // we cannot log indefinitely long strings.
       
  1707         // We get this long strings only if the message is corrupted.
       
  1708         dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  1709         TMmsLogger::Log( _L("- Text header : %S"), &dummy );
       
  1710         CleanupStack::PopAndDestroy( buffer );
       
  1711         });
       
  1712     if ( error != KErrNone )
       
  1713         {
       
  1714         TMmsLogger::Log( _L("- Decode left when reading Text header, error: %d"), error );
       
  1715         }
       
  1716 #endif
       
  1717 
       
  1718     if ( matchFound )
       
  1719         {
       
  1720         return header;
       
  1721         }
       
  1722 
       
  1723     // If we could interpret text headers, it should be done here
       
  1724     // For now we just skip the field value without trying to interpret it.
       
  1725     // As we cannot interpret the header, we must skip the value.
       
  1726     // If a text header match was found in our table, we can interpret the header
       
  1727     // and we leave the value intact
       
  1728 
       
  1729     if ( iPosition < iLength && header == -1 )
       
  1730         {
       
  1731         SkipFieldValue();
       
  1732         }
       
  1733     else
       
  1734         {
       
  1735         iError = KErrCorrupt;
       
  1736         }
       
  1737 
       
  1738     return header;
       
  1739     }
       
  1740 
       
  1741 // ---------------------------------------------------------
       
  1742 //
       
  1743 // ---------------------------------------------------------
       
  1744 //
       
  1745 /*
       
  1746 // not used any more
       
  1747 void CMmsDecode::SkipTextString()
       
  1748     {
       
  1749 
       
  1750     TUint8 byte;
       
  1751 
       
  1752     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1753     iPosition++;
       
  1754 
       
  1755     // don't read beyond buffer
       
  1756     while ( byte != 0 && iPosition < iLength )
       
  1757         {
       
  1758         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1759         iPosition++;
       
  1760         }
       
  1761 
       
  1762     return;
       
  1763     }
       
  1764 */        
       
  1765 
       
  1766 // ---------------------------------------------------------
       
  1767 //
       
  1768 // ---------------------------------------------------------
       
  1769 //
       
  1770 void CMmsDecode::SkipFieldValue()
       
  1771     {
       
  1772 
       
  1773     TUint length;
       
  1774     length = GetValueLength();
       
  1775 #ifndef _NO_MMSS_LOGGING_
       
  1776     // This is an error situation, log always if logging allowed
       
  1777     TMmsLogger::Log( _L("- Skipped field value: %d bytes"), length);
       
  1778 #endif
       
  1779 
       
  1780 #ifndef _NO_MMSS_LOGGING_
       
  1781     // this may produce a long log - but only if the message is weird
       
  1782     TUint i;
       
  1783     TUint8 byte;
       
  1784     TBuf<1> character;
       
  1785     for ( i = iPosition; i < iPosition + length && i < iLength; i++ )
       
  1786         {
       
  1787         iDecodeBuffer->Read(i, &byte, 1);
       
  1788         TUint16 word = byte;
       
  1789         if ( byte >= KMms0x20 && byte < KMms0x7F )
       
  1790             {
       
  1791             character.Copy( &word, 1 );
       
  1792             TMmsLogger::Log( _L("- 0x%02X %S"), byte, &character );
       
  1793             }
       
  1794         else
       
  1795             {
       
  1796             TMmsLogger::Log( _L("- 0x%02X"), byte );
       
  1797             }
       
  1798         }
       
  1799 #endif
       
  1800     iPosition += length;
       
  1801 // if iPosition == iLength, this was the last header, and we are not necessaily corrupted
       
  1802 // If the PDU contains only headers, and the last one is a text header whose value will be
       
  1803 // skipped, we are all right if iPosition == iLength.
       
  1804     if ( iPosition > iLength )
       
  1805         {
       
  1806         iError = KErrCorrupt;
       
  1807         }
       
  1808 
       
  1809     }
       
  1810 
       
  1811 // ---------------------------------------------------------
       
  1812 //
       
  1813 // ---------------------------------------------------------
       
  1814 //
       
  1815 void CMmsDecode::SkipParameterName()
       
  1816     {
       
  1817 
       
  1818     TUint8 byte;
       
  1819 
       
  1820     if ( iPosition >= iLength )
       
  1821         {
       
  1822         return;
       
  1823         }
       
  1824 
       
  1825     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1826 
       
  1827 
       
  1828     // byte cannot be bigger than 255. No need to test upper limit
       
  1829     if ( byte >= KMms0x80 )
       
  1830         {
       
  1831         // well known header, advance pointer and remove high bit
       
  1832         iPosition++;
       
  1833 #ifndef _NO_MMSS_LOGGING_
       
  1834         TMmsLogger::Log( _L("- Skipped parameter: 0x%02X"), byte);
       
  1835 #endif
       
  1836         }
       
  1837     else
       
  1838         {
       
  1839         TPtrC8 byteString = GetByteString();
       
  1840 #ifndef _NO_MMSS_LOGGING_
       
  1841         // we don't leave because of logging
       
  1842         TInt error = KErrNone;
       
  1843         TRAP( error, 
       
  1844             {
       
  1845             HBufC16* buffer = NULL;
       
  1846             buffer = HBufC16::NewLC( byteString.Length() );
       
  1847             buffer->Des().Copy( byteString );
       
  1848             TPtrC dummy;
       
  1849             // we cannot log indefinitely long strings.
       
  1850             // We get this long strings only if the message is corrupted.
       
  1851             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  1852             TMmsLogger::Log( _L("- Skipped parameter : %S"), &dummy ); 
       
  1853             CleanupStack::PopAndDestroy( buffer );
       
  1854             });
       
  1855         if ( error != KErrNone )
       
  1856             {
       
  1857             TMmsLogger::Log( _L("- Decode left when logging skipped parameter, error : %d"),
       
  1858                 error );
       
  1859             }
       
  1860 #endif
       
  1861         }
       
  1862 
       
  1863     }
       
  1864 
       
  1865 
       
  1866 // ---------------------------------------------------------
       
  1867 //
       
  1868 // ---------------------------------------------------------
       
  1869 //
       
  1870 TUint32 CMmsDecode::GetUintvar()
       
  1871     {
       
  1872     
       
  1873     TUint32 uintvar;
       
  1874     uintvar = 0;
       
  1875     TUint8 byte;
       
  1876 
       
  1877     if ( iPosition >= iLength )
       
  1878         {
       
  1879         return uintvar;
       
  1880         }
       
  1881 
       
  1882     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1883     
       
  1884     while ( byte & KMms0x80  && iPosition < iLength - 1 )
       
  1885         {
       
  1886         uintvar += ( byte & KMms0x7F );
       
  1887         uintvar <<= KMmsUintvarShift;
       
  1888         iPosition++;
       
  1889         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1890         }
       
  1891 
       
  1892     // add last byte without shift
       
  1893     uintvar += byte;
       
  1894     iPosition++;
       
  1895     
       
  1896     // If the file is corrupted, the length may be so big it becomes negative
       
  1897     // We must make sure the value is less than maximum signed 32-bit integer.
       
  1898     // 
       
  1899     if ( uintvar > TUint32( KMaxTInt32 ) )
       
  1900         {
       
  1901         uintvar = TUint32( KMaxTInt32 );
       
  1902         }
       
  1903 
       
  1904     return uintvar;
       
  1905     }
       
  1906 
       
  1907 // ---------------------------------------------------------
       
  1908 //
       
  1909 // ---------------------------------------------------------
       
  1910 //
       
  1911 HBufC16* CMmsDecode::DecodeFromL()
       
  1912     {
       
  1913 
       
  1914     TUint8 byte = 0;
       
  1915     TUint length = 0;
       
  1916 
       
  1917     TUint start;
       
  1918     start = iPosition;
       
  1919     length = GetValueLength();
       
  1920 
       
  1921     // Get next token to see, if we have the address present token
       
  1922     if ( iPosition < iLength )
       
  1923         {
       
  1924         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  1925         }
       
  1926 
       
  1927     if ( byte > KMms0x7F )
       
  1928         {
       
  1929         // an encoded token
       
  1930         // It must be address present or be insert address
       
  1931         iPosition++;
       
  1932         if ( iPosition >= iLength )
       
  1933             {
       
  1934             iError = KErrCorrupt;
       
  1935             return HBufC16::NewL( 0 );
       
  1936             }
       
  1937 
       
  1938         // These two are the only two valid ones.
       
  1939         if ( byte != KMmsAddressPresentToken && byte != KMmsInsertAddressToken)
       
  1940             {
       
  1941             // this encoding is a mess.
       
  1942             // try if it resolves as an encoded string without 
       
  1943             // these tokens
       
  1944             iPosition = start;
       
  1945             }
       
  1946         }
       
  1947 
       
  1948     if ( length > 1 )
       
  1949         {
       
  1950         return DecodeAddressL();
       
  1951         }
       
  1952     else
       
  1953         {
       
  1954         return HBufC16::NewL( 0 );
       
  1955         }
       
  1956 
       
  1957     }
       
  1958 
       
  1959 // ---------------------------------------------------------
       
  1960 //
       
  1961 // ---------------------------------------------------------
       
  1962 //
       
  1963 HBufC16* CMmsDecode::DecodeAddressL()
       
  1964     {
       
  1965        
       
  1966     HBufC16* buffer = NULL; // will be allocated by called subroutine
       
  1967 
       
  1968     if ( iPosition >= iLength )
       
  1969         {
       
  1970         return HBufC16::NewL( 0 );
       
  1971         }
       
  1972         
       
  1973     // always use GetEncodedTextStringL(), it handles simple text strings, too
       
  1974 
       
  1975     buffer = GetEncodedTextStringL();
       
  1976 
       
  1977     // If our address contains an appended type specification,
       
  1978     // it must be removed
       
  1979 
       
  1980     TInt position;
       
  1981     TPtr temp = buffer->Des();
       
  1982     _LIT ( KDot, "." );
       
  1983     
       
  1984     position = buffer->FindF( KMmsPlmnu().Ptr(), KMmsPlmnLength );
       
  1985     if ( position != KErrNotFound )
       
  1986         {
       
  1987         temp.SetLength( position );
       
  1988         // remove dots from phone number in order to keep
       
  1989         // plmn number and ipv4 number different.
       
  1990         position = temp.Find( KDot );
       
  1991         while ( position >= 0 )
       
  1992             {
       
  1993             temp.Delete( position, 1 );
       
  1994             position = temp.Find( KDot );
       
  1995             }
       
  1996         }
       
  1997     else
       
  1998         {
       
  1999         position = buffer->FindF( KMmsIpv4u().Ptr(), KMmsIpv4Length );
       
  2000         if ( position != KErrNotFound )
       
  2001             {
       
  2002             temp.SetLength( position );
       
  2003             }
       
  2004         else
       
  2005             {
       
  2006             position = buffer->FindF( KMmsIpv6u().Ptr(), KMmsIpv4Length ); 
       
  2007             if ( position != KErrNotFound )
       
  2008                 {
       
  2009                 temp.SetLength( position );
       
  2010                 }
       
  2011             }
       
  2012         }
       
  2013 
       
  2014     return buffer;
       
  2015     }
       
  2016 
       
  2017 
       
  2018 // ---------------------------------------------------------
       
  2019 //
       
  2020 // ---------------------------------------------------------
       
  2021 //
       
  2022 HBufC16* CMmsDecode::GetSimpleTextStringL( TBool aKeepQuote /*= EFalse*/  )
       
  2023     {
       
  2024     // we don't handle quoted strings.
       
  2025     // they should be present only in application headers, and 
       
  2026     // we don't handle those
       
  2027 
       
  2028     TUint8 byte;
       
  2029     HBufC16* buffer = NULL; // we must know length before trying to allocate
       
  2030     TUint stringLength;
       
  2031     TChar character;
       
  2032 
       
  2033     if ( iPosition >= iLength )
       
  2034         {
       
  2035         return HBufC16::NewL(0);
       
  2036         }
       
  2037     iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2038 
       
  2039     if ( byte == 0 )
       
  2040         {
       
  2041         // empty string.
       
  2042         iPosition++;
       
  2043         return HBufC16::NewL(0);
       
  2044         }
       
  2045 
       
  2046     if ( byte == KMmsQuote )
       
  2047         {
       
  2048         // skip quote
       
  2049         iPosition++;
       
  2050         if ( iPosition >= iLength )
       
  2051             {
       
  2052             return HBufC16::NewL(1);
       
  2053             }
       
  2054         iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2055         }
       
  2056 
       
  2057     TBool foundQuote = EFalse;
       
  2058 
       
  2059     if ( byte == KMmsStringQuote && !aKeepQuote )
       
  2060         {
       
  2061         // skip quote
       
  2062         iPosition++;
       
  2063         foundQuote = ETrue;
       
  2064         if ( iPosition >= iLength )
       
  2065             {
       
  2066             return HBufC16::NewL(0);
       
  2067             }
       
  2068         iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2069         }
       
  2070 
       
  2071     stringLength = iPosition;
       
  2072 
       
  2073     while ( byte != 0 && stringLength < iLength )
       
  2074         {
       
  2075         iDecodeBuffer->Read( stringLength, &byte, 1 );
       
  2076         stringLength++;
       
  2077         }
       
  2078 
       
  2079     // The diffrence of pointers is the actual string length
       
  2080     // including the terminating zero.
       
  2081     stringLength -= iPosition;
       
  2082 
       
  2083     if ( iPosition >= iLength )
       
  2084         {
       
  2085         return HBufC16::NewL(0);
       
  2086         }
       
  2087 
       
  2088     iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2089     if ( byte == 0 )
       
  2090         {
       
  2091         // Empty string. Only terminating zero.
       
  2092         // Must point past the terminating zero at exit
       
  2093         iPosition++;
       
  2094         }
       
  2095 
       
  2096     // Allocate buffer for unicode.
       
  2097     // Check if this is too long,
       
  2098     // (allocating just stringLength left or panicked...)
       
  2099     buffer = HBufC16::NewL( stringLength*KMms2 + KMms2 );
       
  2100 
       
  2101     while ( byte != 0 && iPosition < iLength )
       
  2102         {
       
  2103         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2104         if ( byte != 0 )
       
  2105             {
       
  2106             character = byte;
       
  2107             buffer->Des().Append( character );
       
  2108             }
       
  2109         iPosition++;
       
  2110         }
       
  2111 
       
  2112     if ( foundQuote && buffer->Des().Right( 1 ).Compare( KQuote16 ) == 0 )
       
  2113         {
       
  2114         // if we removed the leading quote, we remove the trailing quote, too.
       
  2115         buffer->Des().Delete( buffer->Des().Length() - 1, 1 );
       
  2116         }
       
  2117     return buffer;
       
  2118         
       
  2119     }
       
  2120 
       
  2121 // ---------------------------------------------------------
       
  2122 //
       
  2123 // ---------------------------------------------------------
       
  2124 //
       
  2125 HBufC16* CMmsDecode::GetEncodedTextStringL()
       
  2126     {
       
  2127 
       
  2128     TUint8 byte;
       
  2129     HBufC16* buffer = NULL; // we must know length before trying to allocate
       
  2130     TUint stringLength = 0;
       
  2131     TUint32 charset = 0;
       
  2132     TUint start;
       
  2133 
       
  2134     if (iPosition >= iLength )
       
  2135         {
       
  2136         iError = KErrCorrupt;
       
  2137         buffer = HBufC16::NewL(0);
       
  2138         return buffer;
       
  2139         }
       
  2140 
       
  2141     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2142 
       
  2143     if ( ( byte > KMms31 && byte < KMms0x80 ) || byte == 0 )
       
  2144         {
       
  2145         // simple text string. Restart.
       
  2146         // (includes empty strings)
       
  2147         // Keep quote because these are strange strings that may contain any
       
  2148         // number of quotes all over the place
       
  2149         buffer = GetSimpleTextStringL( ETrue );
       
  2150         // check if this looks like it needs decoding of MIME stuff (RFC2047)
       
  2151         if ( buffer->Des().FindF( KEqualsQuestion16 ) == KErrNotFound )
       
  2152             {
       
  2153             return buffer;
       
  2154             }
       
  2155         else
       
  2156             {
       
  2157             // contains the magic equals-question mark combination,
       
  2158             // try if MIME decoding succeeds
       
  2159             CleanupStack::PushL( buffer );
       
  2160             HBufC8* buffer8 = HBufC8::NewL( buffer->Des().Length() );
       
  2161             buffer8->Des().Copy( buffer->Des() );
       
  2162             CleanupStack::PushL( buffer8 );
       
  2163             TPtr pointer = buffer->Des();
       
  2164             TRAPD( error,
       
  2165                 TMmsGenUtils::DecodeAndConvertMessageHeaderL( buffer8->Des(), pointer, iFs ) );
       
  2166             if ( error != KErrNone )
       
  2167                 {
       
  2168                 // if did not succeed, keep original as is
       
  2169                 buffer->Des().Copy( buffer8->Des() );
       
  2170                 }
       
  2171             CleanupStack::PopAndDestroy( buffer8 );
       
  2172             CleanupStack::Pop( buffer );
       
  2173             return buffer;
       
  2174             }
       
  2175         }
       
  2176 
       
  2177     iPosition++;
       
  2178 
       
  2179     if (iPosition >= iLength )
       
  2180         {
       
  2181         iError = KErrCorrupt;
       
  2182         buffer = HBufC16::NewL(0);
       
  2183         return buffer;
       
  2184         }
       
  2185 
       
  2186     if ( byte >= KMms0x80 )
       
  2187         {
       
  2188         // the message is corrupted.
       
  2189         iError = KErrCorrupt;
       
  2190         buffer = HBufC16::NewL(0);
       
  2191         return buffer;
       
  2192         }
       
  2193 
       
  2194     if ( byte == KMms31 )
       
  2195         {
       
  2196         stringLength = GetUintvar();
       
  2197         }
       
  2198     else 
       
  2199         {
       
  2200         stringLength = byte;
       
  2201         }
       
  2202 
       
  2203     // Get character set
       
  2204     // Character set must be an integer, short or long
       
  2205 
       
  2206     // check if character set is missing
       
  2207     charset = GetLongOrShortInteger();
       
  2208 #ifndef _NO_MMSS_LOGGING_
       
  2209     if ( charset != 0 )
       
  2210         {
       
  2211         TMmsLogger::Log( _L("- Encoded string charset %d"), charset );
       
  2212         }
       
  2213 #endif
       
  2214 
       
  2215     if ( iPosition >= iLength || iError == KErrCorrupt )
       
  2216         {
       
  2217         iError = KErrCorrupt;
       
  2218         buffer = HBufC16::NewL(0);
       
  2219         return buffer;
       
  2220         }
       
  2221 
       
  2222     // Get text length whatever character set
       
  2223 
       
  2224     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2225 
       
  2226     if ( byte == KMmsQuote )
       
  2227         {
       
  2228         // skip quote
       
  2229         iPosition++;
       
  2230         if (iPosition < iLength)
       
  2231             {
       
  2232             iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2233             }
       
  2234         }
       
  2235 
       
  2236     start = iPosition;
       
  2237     stringLength = 0;
       
  2238     TBool foundQuote = EFalse;
       
  2239 
       
  2240     // Leave quote as is.
       
  2241     // It has turned out that we do not get quoted strings in the WSP format
       
  2242     // with leading quote only. We tend to get either both the leading and
       
  2243     // trailing quote or none at all, so we better not remove the quote.
       
  2244     // If we start seeing WSP quoted strings, we must start checking that
       
  2245     // leading and trailing quotes match.
       
  2246 
       
  2247     /*
       
  2248     if ( byte == KMmsStringQuote )
       
  2249         {
       
  2250         // skip quote
       
  2251         iPosition++;
       
  2252         start++;
       
  2253         foundQuote = ETrue;
       
  2254         }
       
  2255     */
       
  2256 
       
  2257     while ( byte != 0 && iPosition < iLength )
       
  2258         {
       
  2259         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2260         iPosition++;
       
  2261         stringLength++;
       
  2262         }
       
  2263 
       
  2264     // stringLength includes the terminating zero
       
  2265 
       
  2266     // allocate buffer for unicode
       
  2267     // this should be the maximum we'll ever need
       
  2268     if ( stringLength == 0 )
       
  2269         {
       
  2270         // The length of the string == 0
       
  2271         // This is an empty string
       
  2272         // I'm not sure if it is legal or not - but we keep it anyway
       
  2273         if ( iPosition == start )
       
  2274             {
       
  2275             // we did not read anything, the first byte was 0.
       
  2276             // we must advance out pointer beyond it
       
  2277             iPosition++;
       
  2278             }
       
  2279         buffer = HBufC16::NewL(0);
       
  2280         return buffer;
       
  2281         }
       
  2282 
       
  2283     stringLength--; // remove the terminating zero
       
  2284     buffer = HBufC16::NewL( stringLength * KMms2 );
       
  2285 
       
  2286     if ( stringLength == 0 )
       
  2287         {
       
  2288         // buffer has zero length
       
  2289         // I assume this is an empty string
       
  2290         // I'm not sure if it is legal or not
       
  2291         return buffer;
       
  2292         }
       
  2293 
       
  2294     if ( charset == KMmsUtf8 )
       
  2295         {
       
  2296         TPtr8 pointer( iDecodeBuffer->Ptr( start ) );
       
  2297         pointer.SetLength( stringLength );
       
  2298         TInt error;
       
  2299         TPtr16 pointer16 = buffer->Des();
       
  2300         error = CnvUtfConverter::ConvertToUnicodeFromUtf8( pointer16, pointer );
       
  2301         // should check error
       
  2302         if ( error != KErrNone )
       
  2303             {
       
  2304             buffer->Des().Copy( pointer ) ; // could not convert, just copy garbage
       
  2305             }
       
  2306         }
       
  2307     else
       
  2308         {
       
  2309         // other character sets to be implemented...
       
  2310         TPtr8 pointer( iDecodeBuffer->Ptr( start ) );
       
  2311         pointer.SetLength( stringLength );
       
  2312         buffer->Des().Copy( pointer ) ; // just copy without conversion
       
  2313         }
       
  2314  
       
  2315     if ( foundQuote && buffer->Des().Right( 1 ).Compare( KQuote16 ) == 0 )
       
  2316         {
       
  2317         // if we removed the leading quote, we remove the trailing quote, too.
       
  2318         buffer->Des().Delete( buffer->Des().Length() - 1, 1 );
       
  2319         }
       
  2320     return buffer;
       
  2321     }
       
  2322 
       
  2323 // ---------------------------------------------------------
       
  2324 //
       
  2325 // ---------------------------------------------------------
       
  2326 //
       
  2327 TPtrC8 CMmsDecode::GetByteString()
       
  2328     {
       
  2329     
       
  2330     TUint8 byte = 0;
       
  2331     if ( iPosition < iLength )
       
  2332         {
       
  2333         iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2334         }
       
  2335     else
       
  2336         {
       
  2337         return TPtrC8();
       
  2338         }
       
  2339 
       
  2340     TUint start = iPosition;
       
  2341     TUint length = 0;
       
  2342 
       
  2343     if ( byte == 0 )
       
  2344         {
       
  2345         // Empty string, skip over terminating zero.
       
  2346         // Empty string may or may not be legal - we must
       
  2347         // be prepared to accept it.
       
  2348         // The caller must decide if empty value is legal or not.
       
  2349         iPosition++;
       
  2350         return TPtrC8();
       
  2351         }
       
  2352 
       
  2353     TBool foundQuote = EFalse;
       
  2354     if ( ( byte >= KMms32 ) && ( byte <= KMms0x7F ) )
       
  2355         {
       
  2356         if ( byte == KMmsStringQuote )
       
  2357             {
       
  2358             // skip quote
       
  2359             iPosition++;
       
  2360             start++;
       
  2361             foundQuote = ETrue;
       
  2362             }
       
  2363         else if ( byte == KMmsQuote )
       
  2364             {
       
  2365             // We are not supposed to have a string starting with quote here
       
  2366             // but we must be careful and strip the quote in case one exists.
       
  2367             // skip quote
       
  2368             iPosition++;
       
  2369             start++;
       
  2370             }
       
  2371 
       
  2372         // don't read beyond buffer
       
  2373         // byte is between 32 and 127 when we come here.
       
  2374         while ( byte != 0 && iPosition < iLength )
       
  2375             {
       
  2376             iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2377             iPosition++;
       
  2378             }
       
  2379         // now iPosition points beyond terminating zero - if there is one
       
  2380         
       
  2381         length = iPosition - start;
       
  2382         if ( length > 1 )
       
  2383             {
       
  2384             // remove terminating zero if there is one
       
  2385             length--;
       
  2386             }
       
  2387         // If we got a end-of-string immediately after string quote,
       
  2388         // we have nothing left here.
       
  2389         // Or even worse - we have not even the terminating zero
       
  2390         if ( length < 1 )
       
  2391             {
       
  2392             return TPtrC8();
       
  2393             }
       
  2394         TPtr8 pointer( iDecodeBuffer->Ptr( start ) );
       
  2395         pointer.SetLength( length );
       
  2396         // Length is at least one, it was just checked.
       
  2397         if ( foundQuote && ( pointer.Right( 1 )[0] == KMmsStringQuote ) )
       
  2398             {
       
  2399             length--; // decrease length to remove end quote
       
  2400             }
       
  2401         pointer.SetLength( length );
       
  2402         return TPtrC8( pointer );
       
  2403         }
       
  2404     else
       
  2405         {
       
  2406         SkipFieldValue();
       
  2407         return TPtrC8();
       
  2408         }
       
  2409 
       
  2410     }
       
  2411 
       
  2412 // ---------------------------------------------------------
       
  2413 //
       
  2414 // ---------------------------------------------------------
       
  2415 //
       
  2416 TPtrC8 CMmsDecode::GetUtf8String()
       
  2417     {
       
  2418     TUint8 byte = 0;
       
  2419     if ( iPosition < iLength )
       
  2420         {
       
  2421         iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2422         }
       
  2423     else
       
  2424         {
       
  2425         return TPtrC8();
       
  2426         }
       
  2427 
       
  2428     TUint start = iPosition;
       
  2429     TUint length = 0;
       
  2430 
       
  2431     if ( byte == 0 )
       
  2432         {
       
  2433         // Empty string, skip over terminating zero.
       
  2434         // Empty string may or may not be legal - we must
       
  2435         // be prepared to accept it.
       
  2436         // The caller must decide if empty value is legal or not.
       
  2437         iPosition++;
       
  2438         return TPtrC8();
       
  2439         }
       
  2440 
       
  2441     if ( byte == KMmsQuote )
       
  2442         {
       
  2443         // skip quote
       
  2444         iPosition++;
       
  2445         start++;
       
  2446         }
       
  2447 
       
  2448     // don't read beyond buffer
       
  2449     while ( byte != 0 && iPosition < iLength )
       
  2450         {
       
  2451         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2452         iPosition++;
       
  2453         }
       
  2454 
       
  2455     // now iPosition points beyond terminating zero
       
  2456     length = iPosition - start - 1;
       
  2457     // If we got a end-of-string immediately after string quote,
       
  2458     // we have nothing left here.
       
  2459     if ( length < 1 )
       
  2460         {
       
  2461         return TPtrC8();
       
  2462         }
       
  2463     TPtr8 pointer( iDecodeBuffer->Ptr( start ) );
       
  2464     pointer.SetLength( length );
       
  2465     return TPtrC8( pointer );
       
  2466     }
       
  2467 
       
  2468 // ---------------------------------------------------------
       
  2469 //
       
  2470 // ---------------------------------------------------------
       
  2471 //
       
  2472 TUint32 CMmsDecode::GetLongOrShortInteger()
       
  2473     {
       
  2474 
       
  2475     TUint8 byte;
       
  2476     TUint32 integer = 0;
       
  2477 
       
  2478     if ( iPosition >= iLength )
       
  2479         {
       
  2480         return integer;
       
  2481         }
       
  2482 
       
  2483     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2484     iPosition++;
       
  2485     if ( byte & KMms0x80 )
       
  2486         {
       
  2487         integer = byte & KMms0x7F;
       
  2488         return integer;
       
  2489         }
       
  2490 
       
  2491     if ( byte > KMms30 )
       
  2492         {
       
  2493         // Data is corrupted.
       
  2494         iError = KErrCorrupt;
       
  2495         return integer; 
       
  2496         }
       
  2497 
       
  2498     if ( byte > KMmsMaxIntegerLength )
       
  2499         {
       
  2500         // too long.
       
  2501         iError = KErrTooBig;
       
  2502         iPosition--;
       
  2503         // It the caller thinks retry is possible, he must store the
       
  2504         // original starting position.
       
  2505         // So far no case has been found where the retry with very long
       
  2506         // integer would be needed.
       
  2507         SkipFieldValue();
       
  2508         return integer;
       
  2509         }
       
  2510 
       
  2511     TUint i;
       
  2512     TUint length;
       
  2513     length = byte;
       
  2514     for ( i = 0;  i < length && iPosition < iLength; i++)
       
  2515         {
       
  2516         integer <<= KMmsBitsInByte;
       
  2517         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2518         iPosition++;
       
  2519         integer += byte;
       
  2520         }
       
  2521 
       
  2522     return integer;
       
  2523 
       
  2524     }
       
  2525 
       
  2526 // ---------------------------------------------------------
       
  2527 //
       
  2528 // ---------------------------------------------------------
       
  2529 //
       
  2530 TInt64 CMmsDecode::GetVeryLongInteger()
       
  2531     {
       
  2532 
       
  2533     TUint8 byte;
       
  2534     TInt64 veryLongInteger;
       
  2535 
       
  2536     veryLongInteger = 0;
       
  2537 
       
  2538     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2539     iPosition++;
       
  2540     if ( byte & KMms0x80 )
       
  2541         {
       
  2542         veryLongInteger = byte & KMms0x7F;
       
  2543         return veryLongInteger;
       
  2544         }
       
  2545 
       
  2546     if ( byte > KMms30 )
       
  2547         {
       
  2548         // data is corrupted.
       
  2549         iError = KErrCorrupt;
       
  2550         return veryLongInteger; 
       
  2551         }
       
  2552 
       
  2553     if ( byte > KMmsMaxLongIntegerLength )
       
  2554         {
       
  2555         // too long.
       
  2556         iError = KErrTooBig;
       
  2557         iPosition--;
       
  2558         // caller may do whatever he wants, or skip whole field
       
  2559         return veryLongInteger;
       
  2560         }
       
  2561 
       
  2562     TUint i;
       
  2563     TUint length;
       
  2564     length = byte;
       
  2565 
       
  2566     for ( i = 0;  i < length && iPosition < iLength; i++)
       
  2567         {
       
  2568         veryLongInteger <<= KMmsBitsInByte;
       
  2569         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2570         iPosition++;
       
  2571         veryLongInteger += TUint( byte );
       
  2572         }
       
  2573     
       
  2574     return veryLongInteger;
       
  2575     }
       
  2576 
       
  2577 // ---------------------------------------------------------
       
  2578 //
       
  2579 // ---------------------------------------------------------
       
  2580 //
       
  2581 TUint8 CMmsDecode::GetWellKnownFieldValueOrSkip()
       
  2582     {
       
  2583 
       
  2584     TUint8 byte;
       
  2585     byte = 0;
       
  2586     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2587         
       
  2588     // Interpret the length of the field
       
  2589 
       
  2590     // one byte encoded value, this field has no more data
       
  2591     if ( byte >= KMms0x80 )
       
  2592         {
       
  2593         iPosition++;
       
  2594         return byte;
       
  2595         }
       
  2596 
       
  2597     // if not one byte token, skip it
       
  2598     SkipFieldValue();
       
  2599     return byte;  // this is < 128, which is never a legal token
       
  2600 
       
  2601     }
       
  2602 
       
  2603 // ---------------------------------------------------------
       
  2604 //
       
  2605 // ---------------------------------------------------------
       
  2606 //
       
  2607 TUint8 CMmsDecode::GetRelativeOrAbsoluteTime( TInt64& aTime )
       
  2608     {
       
  2609     TUint8 byte;
       
  2610     TInt length;
       
  2611 
       
  2612     // we don't use the length, we just skip it
       
  2613     length = GetValueLength();
       
  2614     if ( ( iPosition + length ) > iLength || iPosition >= iLength )
       
  2615         {
       
  2616         iPosition = iLength;
       
  2617         aTime = 0;
       
  2618         byte = 0;
       
  2619         iError = KErrCorrupt;
       
  2620         return byte;
       
  2621         }
       
  2622     
       
  2623     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2624 
       
  2625     if ( ( byte != KMmsAbsoluteToken ) && ( byte != KMmsRelativeToken ) )
       
  2626         {
       
  2627         // illegal encoding, skip.
       
  2628         iPosition += length;
       
  2629         byte = 0;
       
  2630         aTime = 0;
       
  2631         return byte;
       
  2632         }
       
  2633 
       
  2634     iPosition++;
       
  2635     if ( iPosition >= iLength )
       
  2636         {
       
  2637         iError = KErrCorrupt;
       
  2638         byte = 0;
       
  2639         aTime = 0;
       
  2640         return byte;
       
  2641         }
       
  2642 
       
  2643     aTime = GetVeryLongInteger();
       
  2644 
       
  2645     return byte;
       
  2646     }
       
  2647 
       
  2648 // ---------------------------------------------------------
       
  2649 //
       
  2650 // ---------------------------------------------------------
       
  2651 //
       
  2652 TUint CMmsDecode::GetValueLength()
       
  2653     {
       
  2654     TUint8 byte;
       
  2655     TUint length = 0;
       
  2656 
       
  2657     if ( iPosition >= iLength )
       
  2658         {
       
  2659         return 0;
       
  2660         }
       
  2661 
       
  2662     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2663     
       
  2664     // Interpret the length of the field
       
  2665 
       
  2666     // one byte encoded value, this field has no more data
       
  2667     if ( byte >= KMms0x80 )
       
  2668         {
       
  2669         length = 1;
       
  2670         return length;
       
  2671         }
       
  2672 
       
  2673     // text string
       
  2674     // ( byte >= 128 returned already, so byte must be <=127 if we are here )
       
  2675     if ( byte >= KMms32 )
       
  2676         {
       
  2677         // find the end
       
  2678         length = iPosition;
       
  2679 
       
  2680         while ( byte != 0 && length < iLength )
       
  2681             {
       
  2682             iDecodeBuffer->Read(length, &byte, 1);
       
  2683             length++;
       
  2684             }
       
  2685 
       
  2686         // The difference of pointers is the actual string length
       
  2687         length -= iPosition;
       
  2688 
       
  2689         return length;
       
  2690         }
       
  2691     
       
  2692     // octet followed by a uintvar
       
  2693     if ( byte == KMms31 )
       
  2694         {
       
  2695         iPosition++;
       
  2696         // uintvar can be max 5 bytes, max value of
       
  2697         // result is 32 bits.
       
  2698         // get uintvar
       
  2699         if ( iPosition < iLength )
       
  2700             {
       
  2701             length = GetUintvar();
       
  2702             }
       
  2703         return length;
       
  2704         }
       
  2705 
       
  2706     // remains: octets 0 - 30
       
  2707     // octet followed by the indicated number of data octets
       
  2708     iPosition++;
       
  2709     length = byte;
       
  2710     return length;
       
  2711 
       
  2712     }
       
  2713     
       
  2714     
       
  2715 // ---------------------------------------------------------
       
  2716 //
       
  2717 // ---------------------------------------------------------
       
  2718 //
       
  2719 TBool CMmsDecode::CheckHeaderLength()
       
  2720     {
       
  2721     TInt oldPosition = iPosition;
       
  2722     TBool retVal = ETrue; // optimistic
       
  2723     TUint8 byte;
       
  2724     
       
  2725     TBool checkUintvarData = ETrue;
       
  2726     
       
  2727     if ( iPosition < iLength )
       
  2728         {
       
  2729         // read first byte for some special checks
       
  2730         iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2731         }
       
  2732     else
       
  2733         {
       
  2734         return EFalse;
       
  2735         }
       
  2736     
       
  2737     if ( iDecodingStage == EMmsAttachmentHeaders )
       
  2738         {
       
  2739         if ( ( byte & KMms0x80 ) && ( ( byte & KMms0x7F ) == KWspQValue ) )
       
  2740             {
       
  2741             // Quality factor in attachment headers has strange encoding
       
  2742             checkUintvarData = EFalse;
       
  2743             }
       
  2744         }
       
  2745     
       
  2746     // check header first - uintvar data included
       
  2747     retVal = CheckValueLength( ETrue );
       
  2748     
       
  2749     // The position of the pointer is at the end of the header name
       
  2750     // if the whole header name is in the buffer
       
  2751     
       
  2752     // Check the length of the header
       
  2753     if ( retVal )
       
  2754         {
       
  2755         retVal = CheckValueLength( checkUintvarData );
       
  2756         }
       
  2757         
       
  2758     if ( iDecodingStage == EMmsHeaders )
       
  2759         {
       
  2760         if ( byte == KMmsAssignedContentType && retVal )
       
  2761             {
       
  2762             // we need to have an uintvar specifying the number of attachments
       
  2763             // to follow content type header            
       
  2764             retVal = CheckUintvarLength();
       
  2765             }
       
  2766         }
       
  2767    
       
  2768     // always restore the pointer for decoding
       
  2769     iPosition = oldPosition;
       
  2770     return retVal;
       
  2771     }
       
  2772 
       
  2773 // ---------------------------------------------------------
       
  2774 //
       
  2775 // ---------------------------------------------------------
       
  2776 //
       
  2777 TBool CMmsDecode::CheckValueLength( TBool aCheckUintvarData )
       
  2778     {
       
  2779     TBool retVal = ETrue; // optimistic
       
  2780     
       
  2781     TUint8 byte;
       
  2782     TUint length = 0;
       
  2783     
       
  2784     if ( iPosition >= iLength )
       
  2785         {
       
  2786         return EFalse;
       
  2787         }
       
  2788         
       
  2789     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2790     
       
  2791     // Interpret the length of the field
       
  2792 
       
  2793     if ( byte >= KMms0x80 )
       
  2794         {
       
  2795         // one byte encoded value, this field has no more data
       
  2796         iPosition++;
       
  2797         }
       
  2798     else if ( byte >= KMms32 )
       
  2799         {
       
  2800         // text string - find the end
       
  2801         while ( byte != 0 && iPosition < iLength )
       
  2802             {
       
  2803             iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2804             iPosition++;
       
  2805             }
       
  2806         if ( byte != 0 )
       
  2807             {
       
  2808             // we reached the end of the buffer without finding the terminating 0
       
  2809             // there is not enough data
       
  2810             retVal = EFalse;
       
  2811             }
       
  2812         }
       
  2813     else if ( byte == KMms31 )
       
  2814         {
       
  2815         // octet followed by a uintvar
       
  2816         iPosition++;
       
  2817         // get all bytes belonging to uintvar first to see if we have them all.
       
  2818         TInt uintvarStart = iPosition;
       
  2819         if ( CheckUintvarLength() )
       
  2820             {
       
  2821             // we have an uintvar, do we have all the following bytes
       
  2822             if ( aCheckUintvarData )
       
  2823                 {
       
  2824                 iPosition = uintvarStart;
       
  2825                 // we are asked to check the data, too
       
  2826                 length = GetUintvar();
       
  2827                 if ( ( iLength - iPosition ) < length )
       
  2828                     {
       
  2829                     retVal = EFalse;
       
  2830                     }
       
  2831                 else
       
  2832                     {
       
  2833                     iPosition += length;
       
  2834                     }
       
  2835                 }
       
  2836             }
       
  2837         else
       
  2838             {
       
  2839             // we did not even have the uintvar let alone the data following it
       
  2840             retVal = EFalse;
       
  2841             }
       
  2842         }
       
  2843     else
       
  2844         {
       
  2845         // remains: octets 0 - 30
       
  2846         // octet followed by the indicated number of data octets
       
  2847         iPosition++;
       
  2848         length = byte;
       
  2849         if ( ( iLength - iPosition ) < length )
       
  2850             {
       
  2851             retVal = EFalse;
       
  2852             }
       
  2853         else
       
  2854             {
       
  2855             iPosition += length;
       
  2856             }
       
  2857         }
       
  2858         
       
  2859     return retVal;
       
  2860     }
       
  2861 
       
  2862 
       
  2863 // ---------------------------------------------------------
       
  2864 //
       
  2865 // ---------------------------------------------------------
       
  2866 //
       
  2867 TBool CMmsDecode::CheckUintvarLength()
       
  2868     {
       
  2869     TBool retVal = ETrue; // optimistic
       
  2870     TUint8 byte;
       
  2871     
       
  2872     if ( iPosition >= iLength )
       
  2873         {
       
  2874         return EFalse;
       
  2875         }
       
  2876     
       
  2877     // get all bytes belonging to uintvar to see if we have them all.
       
  2878     iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2879     while ( byte & KMms0x80  && iPosition < iLength - 1 )
       
  2880         {
       
  2881         iPosition++;
       
  2882         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2883         }
       
  2884     iPosition++;
       
  2885     if ( byte & KMms0x80 )
       
  2886         {
       
  2887         // if byte still has high bit set, we have not found
       
  2888         // the end of the uintvar -> there is not enough data
       
  2889         retVal = EFalse;
       
  2890         }
       
  2891                 
       
  2892     return retVal;
       
  2893     }
       
  2894 
       
  2895 // ---------------------------------------------------------
       
  2896 //
       
  2897 // ---------------------------------------------------------
       
  2898 //
       
  2899 TPtrC8 CMmsDecode::GetContentTypeL()
       
  2900     {
       
  2901 
       
  2902     TUint8 byte;
       
  2903     TPtrC8 pointer = TPtrC8();
       
  2904 
       
  2905     if ( iPosition >= iLength )
       
  2906         {
       
  2907         iError = KErrCorrupt;
       
  2908         return pointer;
       
  2909         }
       
  2910 
       
  2911     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  2912 
       
  2913     // Test if it is a well-known media type
       
  2914     if ( byte >= KMms0x80 )
       
  2915         {
       
  2916         iPosition++; // skip the content type byte
       
  2917         byte &= KMms0x7F; // remove the short integer identifier bit
       
  2918         if ( ( byte == KMmsAssignedTextPlain ) )
       
  2919             {
       
  2920             // The beginning of the first text/plain part is used
       
  2921             // to generate a description of the message, if
       
  2922             // no real subject is available.
       
  2923             // Save the starting point of corresponding data.
       
  2924             if ( iDataStart < iLength )
       
  2925                 {
       
  2926                 iFakeSubject = iDataStart;
       
  2927                 }
       
  2928             iUseForSubject = ETrue;
       
  2929             // count the number of plain text attas.
       
  2930             // We use iFakeSubject only if iPlainTexts == 1
       
  2931             iPlainTexts++;
       
  2932             }
       
  2933         // encoded value
       
  2934         if ( byte < KNumberContentTypes )
       
  2935             {
       
  2936             pointer.Set( KContentTypeTable[byte] );
       
  2937             }
       
  2938         else
       
  2939             {
       
  2940             pointer.Set( KContentTypeTable[KMmsUnAssigned] );
       
  2941             }
       
  2942         return pointer;
       
  2943         }
       
  2944     
       
  2945     // Test if it is a text string without parameters
       
  2946     // ( byte >= 128 returned already, byte is <= 127 if we get here )
       
  2947     if ( byte >= KMms32 )
       
  2948         {
       
  2949         // text string
       
  2950         return GetByteString();
       
  2951         }
       
  2952 
       
  2953     // We have the worst case left:
       
  2954     // Content-General-Form = Value-length Media-Type
       
  2955 
       
  2956     TUint mediaLength = 0;
       
  2957     mediaLength = GetValueLength();
       
  2958     TUint start = iPosition;
       
  2959 
       
  2960     if ( iPosition < iLength )
       
  2961         {
       
  2962         pointer.Set( GetContentTypeL() ); // We call ourselves.
       
  2963         }
       
  2964 
       
  2965     // Now we should get the parameters, but we know nothing of
       
  2966     // parameters. For now we just throw them away.
       
  2967     // The handling of parameters of specific media types needs more study
       
  2968     
       
  2969     // The only parameter we care about now is charset.
       
  2970     // its coding should be well-known
       
  2971 
       
  2972     while ( iPosition < start + mediaLength && iPosition < iLength )
       
  2973         {
       
  2974         iDecodeBuffer->Read( iPosition, &byte, 1 );
       
  2975         if ( ( byte & KMms0x80 ) && ( ( byte & KMms0x7F ) == KWspCharset ) )
       
  2976             {
       
  2977             iPosition++;
       
  2978             TUint32 charset;
       
  2979             charset = GetLongOrShortInteger();
       
  2980             iMimeHeaders->SetMimeCharset( charset );
       
  2981             // if this is the part possibly used to generate
       
  2982             // our fake subject, save the character set.
       
  2983             if ( iFakeSubject == iDataStart )
       
  2984                 {
       
  2985                 iCharacterSet = charset;
       
  2986                 }
       
  2987             }
       
  2988         else if ( ( byte & KMms0x80 ) && ( ( byte & KMms0x7F ) == KWspName ) )
       
  2989             {
       
  2990             iPosition++;
       
  2991             // Get name parameter to be suggestion of filename
       
  2992             iMimeHeaders->ContentTypeParams().AppendL( KWspNameString );
       
  2993             iMimeHeaders->ContentTypeParams().AppendL( GetByteString() );
       
  2994             }
       
  2995         else if ( ( byte & KMms0x80 ) && ( ( byte & KMms0x7F ) == KWspQValue ) )
       
  2996             {
       
  2997             iPosition++;
       
  2998             // value encoded as Uintvar, must skip differently than others.
       
  2999             GetUintvar();
       
  3000             }
       
  3001         else
       
  3002             {
       
  3003             if ( byte >= KMms0x20 && byte <= KMms0x7F )
       
  3004                 {
       
  3005                 // text string, save as content type parameter
       
  3006                 // If we don have a pair of two text strings, the message is illegal
       
  3007                 // The code will probably leave at some point
       
  3008                 iMimeHeaders->ContentTypeParams().AppendL( GetByteString() );
       
  3009                 iMimeHeaders->ContentTypeParams().AppendL( GetByteString() );
       
  3010                 }
       
  3011             else
       
  3012                 {
       
  3013                 // skip
       
  3014                 SkipParameterName();
       
  3015                 SkipFieldValue();
       
  3016                 }
       
  3017             }
       
  3018         }
       
  3019         
       
  3020     iPosition = start + mediaLength;
       
  3021 
       
  3022     return pointer;
       
  3023 
       
  3024     }
       
  3025 
       
  3026 // ---------------------------------------------------------
       
  3027 // If the content type is multipart, pointer will be positioned
       
  3028 // to the start of the multipart block (The first attachment)
       
  3029 // ---------------------------------------------------------
       
  3030 //
       
  3031 TUint8 CMmsDecode::GetMultipartContentTypeL()
       
  3032     {
       
  3033 
       
  3034     TUint8 byte;
       
  3035 #ifndef _NO_MMSS_LOGGING_
       
  3036     TPtrC dummy;
       
  3037 #endif
       
  3038 
       
  3039     iMultipartRootType.Set( TPtrC8() ); // clear contents
       
  3040     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  3041     // Test if it is a well-known media type.
       
  3042     if ( byte >= KMms0x80 )
       
  3043         {
       
  3044         byte &= KMms0x7F; // remove the short integer identifier bit
       
  3045         // Test if it is a multipart type.
       
  3046         if ( ( byte >= KMmsAssignedApplicationVndWapMultipart &&
       
  3047             byte <= KMmsAssignedApplicationVndWapMultipartAlternative ) ||
       
  3048             ( byte == KMmsAssignedApplicationVndWapMultipartRelated ) )
       
  3049             {
       
  3050             iPosition++; // skip the content type byte
       
  3051             // Get number of parts in multipart
       
  3052             iNumberOfAttachments = GetUintvar();
       
  3053             }
       
  3054         else
       
  3055             {
       
  3056             byte = 0;
       
  3057             iNumberOfAttachments = 1;
       
  3058             }
       
  3059         // No more data in this header.
       
  3060         // For example multipart/mixed has no parameters
       
  3061         return byte;
       
  3062         }
       
  3063 
       
  3064     // if we get here byte is <= 127 
       
  3065     if ( byte >= KMms32 )
       
  3066         {
       
  3067         // text string, we don't even try to analyze it.
       
  3068         // Nobody should send a well-known media type as a text string,
       
  3069         // and if it is not a well-known type, we don't know what
       
  3070         // to do with it, it will be treated as a monoblock
       
  3071         byte = 0;
       
  3072         iNumberOfAttachments = 1;
       
  3073         return byte;
       
  3074         }
       
  3075 
       
  3076     // The most complicated case: Content-General Form
       
  3077     // Content-General-Form = Value-length Media-Type
       
  3078 
       
  3079     // we save the position in case this is monoblock and
       
  3080     // we must keep the old position to get the content type for
       
  3081     // the attachment.
       
  3082     TUint oldPosition = iPosition;
       
  3083 
       
  3084     TUint mediaLength = 0;
       
  3085     mediaLength = GetValueLength();
       
  3086     TUint start = iPosition;
       
  3087     byte = 0;
       
  3088 
       
  3089     if ( iPosition < iLength )
       
  3090         {
       
  3091         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  3092         }
       
  3093     else
       
  3094         {
       
  3095         iNumberOfAttachments = 0;
       
  3096         return 0;
       
  3097         }
       
  3098 
       
  3099     if ( byte >= KMms0x80 )
       
  3100         {
       
  3101         byte &= KMms0x7F; // remove the short integer identifier bit
       
  3102         // Test if it is a multipart type.
       
  3103         if ( ( byte >= KMmsAssignedApplicationVndWapMultipart &&
       
  3104             byte <= KMmsAssignedApplicationVndWapMultipartAlternative ) ||
       
  3105             ( byte == KMmsAssignedApplicationVndWapMultipartRelated ) )
       
  3106             {
       
  3107             iPosition++; // skip the content type byte
       
  3108             }
       
  3109         else
       
  3110             {
       
  3111             // Not a multipart we can handle
       
  3112             byte = 0;
       
  3113             iNumberOfAttachments = 1;
       
  3114             // point back to start of header
       
  3115             // parameters will belong to the attachment
       
  3116             iPosition = oldPosition;
       
  3117             return byte;
       
  3118             }
       
  3119         }
       
  3120     else
       
  3121         {
       
  3122         // text string, we don't even try to analyze it.
       
  3123         // Nobody should send a well-known media type as a text string,
       
  3124         // and if it is not a well-known type, we don't know what
       
  3125         // to do with it, it will be treated as a monoblock
       
  3126         TPtrC8 mediatype = GetByteString();
       
  3127         if ( mediatype.CompareF( KMmsWapMultipartReport ) == 0 )
       
  3128             {
       
  3129             byte = KMmsAssignedApplicationVndWapMultipartReport;
       
  3130             }
       
  3131         else
       
  3132             {
       
  3133             byte = 0;
       
  3134             iNumberOfAttachments = 1;
       
  3135             // point back to start of header
       
  3136             // parameters will belong to the attachment
       
  3137             iPosition = oldPosition;
       
  3138             return byte;
       
  3139             }
       
  3140         }
       
  3141 
       
  3142     // If we get here we have a WSP type multipart.
       
  3143     // We must still extract the parameters of the content type
       
  3144     // If we have multipart/related, we have start parameter.
       
  3145     // We must also try to extract Application-Id and Reply-To-Application-ID
       
  3146     //     in case Java has added them.
       
  3147     // We don't care about the others now.
       
  3148 
       
  3149     TInt header;
       
  3150     TPtrC8 contentHeader; // parameter name in case it is a string
       
  3151    
       
  3152     while ( iPosition < start + mediaLength && iPosition < iLength )
       
  3153         {
       
  3154         header = GetContentHeaderName( contentHeader );
       
  3155         if ( header == KWspStart )
       
  3156             {
       
  3157             // Now we must get the content-id of the root part
       
  3158             // and save it temporarily. We can get the actual
       
  3159             // TMsvId for the attachment only by comparing the
       
  3160             // Content-Id parameters of the attachments to the
       
  3161             // saved root-id.
       
  3162             TPtrC8 pointer = GetByteString();
       
  3163             if ( pointer.Find( KMmsLeftAngle ) == 0 &&
       
  3164                 pointer.Find( KMmsRightAngle ) == pointer.Length() - 1 )
       
  3165                 {
       
  3166                 // remove angle brackets from cid, 2 characters removed
       
  3167                 pointer.Set( pointer.Mid( 1, pointer.Length() - KMms2 ) );
       
  3168                 }
       
  3169             delete iRootContentIdBuffer;
       
  3170             iRootContentIdBuffer = NULL;
       
  3171             iRootContentIdBuffer = HBufC8::NewL( pointer.Length() );
       
  3172             iRootContentIdBuffer->Des().Copy( pointer );
       
  3173             iRootContentId.Set( iRootContentIdBuffer->Des() );
       
  3174             }
       
  3175         else if ( header == KWspQValue )
       
  3176             {
       
  3177             // value encoded as Uintvar, must skip differently than others.
       
  3178             GetUintvar();
       
  3179             }
       
  3180         else if ( header == KWspRelatedType )
       
  3181             {
       
  3182             // get content type
       
  3183             iMultipartRootType.Set( GetContentTypeL() ); 
       
  3184             }
       
  3185         else if ( header == KMmsTextHeader )
       
  3186             {
       
  3187             // see if this is Java application id
       
  3188             if ( contentHeader.CompareF( KMmsJavaApplicationId ) == 0 )
       
  3189                 {
       
  3190                 DecodeApplicationIdL();
       
  3191                 }
       
  3192             else if ( contentHeader.CompareF( KMmsJavaReplyApplicationId ) == 0 )
       
  3193                 {
       
  3194                 DecodeReplyApplicationIdL();
       
  3195                 }
       
  3196             else
       
  3197                 {
       
  3198                 // something we don't handle
       
  3199 #ifndef _NO_MMSS_LOGGING_
       
  3200                 HBufC16* buffer = NULL;
       
  3201                 buffer = HBufC16::NewLC( contentHeader.Length() );
       
  3202                 buffer->Des().Copy( contentHeader );
       
  3203                 // we cannot log indefinitely long strings.
       
  3204                 // We get this long strings only if the message is corrupted.
       
  3205                 dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3206                 TMmsLogger::Log( _L("- Text header: %S"), &dummy );
       
  3207                 CleanupStack::PopAndDestroy( buffer );
       
  3208                 buffer = NULL;
       
  3209 #endif
       
  3210                 SkipFieldValue();
       
  3211                 }
       
  3212             }
       
  3213         else
       
  3214             {
       
  3215             // skip
       
  3216             // If the caller has messed things up and sent "start"
       
  3217             // as a text string, we will miss it...
       
  3218             // GetContentHeaderName always skips the header name.
       
  3219             // if header < 0, the field has already been skipped
       
  3220             if ( header >= 0 )
       
  3221                 {
       
  3222                 SkipFieldValue();
       
  3223                 }
       
  3224             }
       
  3225         }
       
  3226         
       
  3227     iPosition = start + mediaLength;
       
  3228     iNumberOfAttachments = GetUintvar();
       
  3229 
       
  3230     return byte;
       
  3231     }
       
  3232 
       
  3233 // ---------------------------------------------------------
       
  3234 //
       
  3235 // ---------------------------------------------------------
       
  3236 //
       
  3237 void CMmsDecode::GetAttachmentContentTypeL()
       
  3238     {
       
  3239     TPtrC8 byteString;
       
  3240 #ifndef _NO_MMSS_LOGGING_
       
  3241     HBufC16* buffer = NULL;
       
  3242     TPtrC dummy;
       
  3243 #endif
       
  3244 
       
  3245     // get content type
       
  3246     byteString.Set( GetContentTypeL() );
       
  3247     TInt semicolonPosition = 0;
       
  3248     TInt position = 0;
       
  3249     semicolonPosition = byteString.FindF( KSemicolon8 );
       
  3250     // check if this content type has been sent to us as a string containing
       
  3251     // parameters
       
  3252     if ( semicolonPosition != KErrNotFound && semicolonPosition != 0 )
       
  3253         {
       
  3254         TInt endString = ( byteString.Left( semicolonPosition ).FindF( KSpace8 ) );
       
  3255         if ( endString == KErrNotFound )
       
  3256             {
       
  3257             endString = semicolonPosition;
       
  3258             }
       
  3259         // First part of string is actual content-type header,
       
  3260         // trailing blanks removed.
       
  3261         // If the string was total garbage like "type huh;hei=hui",
       
  3262         // the result will be wrong, but that cannot be helped if the input
       
  3263         // is not legal.
       
  3264         // The following should be OK
       
  3265         // "application/type ;param1=value1
       
  3266         TPtrC8 contentType = byteString.Left( endString );
       
  3267         position = contentType.Find( KMmsSlash8 );
       
  3268         if ( position <= 0 || position == contentType.Length() )
       
  3269             {
       
  3270             // weird string - no subtype, keep as is
       
  3271             iMimeHeaders->SetContentTypeL( contentType );
       
  3272             }
       
  3273         else
       
  3274             {
       
  3275             iMimeHeaders->SetContentTypeL( contentType.Left( position ) );
       
  3276             iMimeHeaders->SetContentSubTypeL( contentType.Mid( position + 1 ) );
       
  3277             }
       
  3278         // get the rest of the stuff as parameters
       
  3279         ExtractContentTypeParametersL( byteString.Mid( semicolonPosition + 1 ) );
       
  3280         }
       
  3281     else
       
  3282         {
       
  3283         // If first character is semicolon, the content type is garbage anyway,
       
  3284         // and we keep it "as is"
       
  3285         position = byteString.Find( KMmsSlash8 );
       
  3286         if ( position <= 0 || position == byteString.Length() )
       
  3287             {
       
  3288             // weird string - no subtype, keep as is
       
  3289             iMimeHeaders->SetContentTypeL( byteString );
       
  3290             }
       
  3291         else
       
  3292             {
       
  3293             iMimeHeaders->SetContentTypeL( byteString.Left( position ) );
       
  3294             iMimeHeaders->SetContentSubTypeL( byteString.Mid( position + 1 ) );
       
  3295             }
       
  3296         }
       
  3297         
       
  3298 // if attachment subtype is "smil" or "amr", increase respective counter.
       
  3299 
       
  3300 
       
  3301     if ( iMimeHeaders->ContentSubType().CompareF( KMmsSmilSubtype ) == 0 )
       
  3302         {
       
  3303         iSmilCount++;
       
  3304         }
       
  3305     else if ( iMimeHeaders->ContentType().CompareF( KMmsAudioType ) == 0 )
       
  3306         {
       
  3307         if ( iMimeHeaders->ContentSubType().CompareF( KMmsAudioSubtype ) == 0 )
       
  3308             {
       
  3309             iAudioCount++;
       
  3310             }
       
  3311         else if ( iMimeHeaders->ContentSubType().CompareF( KMmsAudioSubtype2 ) == 0 )
       
  3312             {
       
  3313             // Change the subtype because the x-amr is not supported
       
  3314             iMimeHeaders->SetContentSubTypeL( KMmsAudioSubtype );
       
  3315             iAudioCount++;
       
  3316             }
       
  3317         else
       
  3318             {
       
  3319             // do nothing - keep LINT happy
       
  3320             }
       
  3321         }
       
  3322     else
       
  3323         {
       
  3324         // do nothing - keep LINT happy
       
  3325         }
       
  3326             
       
  3327 #ifndef _NO_MMSS_LOGGING_
       
  3328     if ( semicolonPosition > 0 )
       
  3329         {
       
  3330         byteString.Set( byteString.Left( semicolonPosition ) );
       
  3331         }
       
  3332     buffer = HBufC16::NewLC( byteString.Length() );
       
  3333     buffer->Des().Copy( byteString );
       
  3334     // we cannot log indefinitely long strings.
       
  3335     // We get this long strings only if the message is corrupted.
       
  3336     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3337     TMmsLogger::Log( _L("- Content Type: %S"), &dummy );
       
  3338     CleanupStack::PopAndDestroy( buffer );
       
  3339     if ( iMimeHeaders->MimeCharset() != 0 )
       
  3340         {
       
  3341         TMmsLogger::Log( _L("- Character set: %d"), iMimeHeaders->MimeCharset() );
       
  3342         }
       
  3343     if ( iMimeHeaders->ContentTypeParams().MdcaCount() > 0 )
       
  3344         {
       
  3345         TInt i;
       
  3346         // we increment by 2 because every other value is parameter name
       
  3347         // and every othe one the value
       
  3348         for ( i = 0; i < iMimeHeaders->ContentTypeParams().MdcaCount(); i += KMms2 )
       
  3349             {
       
  3350             HBufC16* buffer2 = NULL;
       
  3351             buffer = HBufC16::NewLC(
       
  3352                 iMimeHeaders->ContentTypeParams().MdcaPoint( i ).Length() );
       
  3353             buffer->Des().Copy( iMimeHeaders->ContentTypeParams().MdcaPoint( i ) );
       
  3354             // we cannot log indefinitely long strings.
       
  3355             // We get this long strings only if the message is corrupted.
       
  3356             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3357             if ( i + 1 < iMimeHeaders->ContentTypeParams().MdcaCount() )
       
  3358                 {
       
  3359                 buffer2 = HBufC16::NewLC(
       
  3360                     iMimeHeaders->ContentTypeParams().MdcaPoint( i + 1 ).Length() );
       
  3361                 TPtrC dummy2;
       
  3362                 buffer2->Des().Copy( iMimeHeaders->ContentTypeParams().MdcaPoint( i + 1 ) );
       
  3363                 dummy2.Set( buffer2->Des().Left( KMmsMaxLogStringLength ) );
       
  3364                 TMmsLogger::Log( _L("- %S: %S"), &dummy, &dummy2 );
       
  3365                 CleanupStack::PopAndDestroy( buffer2 );
       
  3366                 }
       
  3367             else
       
  3368                 {
       
  3369                 TMmsLogger::Log( _L("- %S"), &dummy );
       
  3370                 }
       
  3371             CleanupStack::PopAndDestroy( buffer );
       
  3372             }
       
  3373         }
       
  3374 #endif
       
  3375 
       
  3376     }
       
  3377 
       
  3378 // ---------------------------------------------------------
       
  3379 //
       
  3380 // ---------------------------------------------------------
       
  3381 //
       
  3382 void CMmsDecode::DecodeOneContentHeaderL()
       
  3383     {
       
  3384 
       
  3385     TInt header;
       
  3386     HBufC16* buffer = NULL;
       
  3387     TUint8 byte = 0;
       
  3388     TPtrC8 contentHeader; // content header in case it is a string
       
  3389 #ifndef _NO_MMSS_LOGGING_
       
  3390     TPtrC dummy;
       
  3391 #endif
       
  3392     header = GetContentHeaderName( contentHeader );
       
  3393 
       
  3394     if ( header < 0 )
       
  3395         {
       
  3396         return; // skip unknown
       
  3397         }
       
  3398 
       
  3399     // Get the corresponding value
       
  3400     
       
  3401     switch ( header )
       
  3402         {
       
  3403         case KWspContentLocation:
       
  3404             {
       
  3405             // I hope this is a simple text string. we cannot handle
       
  3406             // different character sets in this context.
       
  3407 
       
  3408             buffer = GetSimpleTextStringL(); // we might try to convert from utf8 to unicode
       
  3409             CleanupStack::PushL( buffer );
       
  3410             iMimeHeaders->SetContentLocationL( buffer->Des() );
       
  3411             CleanupStack::PopAndDestroy( buffer );
       
  3412             buffer = NULL;
       
  3413             
       
  3414 #ifndef _NO_MMSS_LOGGING_
       
  3415             buffer = HBufC16::NewLC( iMimeHeaders->ContentLocation().Length() );
       
  3416             buffer->Des().Copy( iMimeHeaders->ContentLocation() );
       
  3417             // we cannot log indefinitely long strings.
       
  3418             // We get this long strings only if the message is corrupted.
       
  3419             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3420             TMmsLogger::Log( _L("- Content location: %S"), &dummy );
       
  3421             CleanupStack::PopAndDestroy( buffer );
       
  3422 #endif
       
  3423             break;
       
  3424             }
       
  3425         case KWspContentId:
       
  3426             {
       
  3427                 TPtrC8 pointer = GetByteString();
       
  3428                 if ( pointer.Find( KMmsLeftAngle ) == 0 &&
       
  3429                     pointer.Find( KMmsRightAngle ) == pointer.Length() - 1 )
       
  3430                     {
       
  3431                     // remove angle brackets from cid, 2 characters removed
       
  3432                     pointer.Set( pointer.Mid( 1, pointer.Length() - KMms2 ) );
       
  3433                     }
       
  3434                 iMimeHeaders->SetContentIdL( pointer );
       
  3435                 if ( iAttaNumber == 1 &&
       
  3436                     iMultipartType == KMmsAssignedApplicationVndWapMultipartRelated &&
       
  3437                     iRootContentId.Length() == 0 )
       
  3438                     {
       
  3439                     iRootContentId.Set( pointer );
       
  3440                     }
       
  3441 #ifndef _NO_MMSS_LOGGING_
       
  3442                 buffer = HBufC16::NewLC( iMimeHeaders->ContentId().Length() );
       
  3443                 buffer->Des().Copy( iMimeHeaders->ContentId() );
       
  3444                 // we cannot log indefinitely long strings.
       
  3445                 // We get this long strings only if the message is corrupted.
       
  3446                 dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3447                 TMmsLogger::Log( _L("- Content Id: %S"), &dummy );
       
  3448                 CleanupStack::PopAndDestroy( buffer );
       
  3449 #endif
       
  3450             break;
       
  3451             }
       
  3452         case KWspContentDisposition:
       
  3453             {
       
  3454             TUint length;
       
  3455             length = GetValueLength();
       
  3456             TUint currentPosition = iPosition;
       
  3457 
       
  3458             if ( iPosition < iLength )
       
  3459                 {
       
  3460                 iDecodeBuffer->Read(iPosition, &byte, 1);
       
  3461                 }
       
  3462             if ( byte >= KMms0x80 )
       
  3463                 {
       
  3464                 // well known header
       
  3465                 iPosition++;
       
  3466                 byte &= KMms0x7F;
       
  3467                 if ( byte == KWspAttachment )
       
  3468                     {
       
  3469                     iMimeHeaders->SetContentDispositionL( KWspAttachmentString );
       
  3470                     }
       
  3471                 else if ( byte == KWspInline )
       
  3472                     {
       
  3473                     iMimeHeaders->SetContentDispositionL( KWspInlineString );
       
  3474                     }
       
  3475                 // never mind others - might be form-data or something unknown
       
  3476                 else
       
  3477                     {
       
  3478                     // do nothing - keep LINT happy
       
  3479                     }
       
  3480                 }
       
  3481             else
       
  3482                 {
       
  3483                 // string - use as is
       
  3484                 TPtrC8 pointer = GetByteString();
       
  3485                 iMimeHeaders->SetContentDispositionL( pointer );
       
  3486                 }
       
  3487 #ifndef _NO_MMSS_LOGGING_
       
  3488             buffer = HBufC16::NewLC( iMimeHeaders->ContentDisposition().Length() );
       
  3489             buffer->Des().Copy( iMimeHeaders->ContentDisposition() );
       
  3490             // we cannot log indefinitely long strings.
       
  3491             // We get this long strings only if the message is corrupted.
       
  3492             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3493             TMmsLogger::Log( _L("- Content Disposition: %S"), &dummy );
       
  3494             CleanupStack::PopAndDestroy( buffer );
       
  3495 #endif
       
  3496             // now try to see if we have filename parameter
       
  3497             while ( iPosition < ( currentPosition + length ) && iPosition < iLength )
       
  3498                 {
       
  3499                 byte = 0; // clean out old data
       
  3500                 iDecodeBuffer->Read(iPosition, &byte, 1);
       
  3501 
       
  3502                 if ( byte >= KMms0x80 )
       
  3503                     {
       
  3504                     // well known parameter
       
  3505                     iPosition++;
       
  3506                     byte &= KMms0x7F;
       
  3507                     if ( byte == KWspFileName )
       
  3508                         {
       
  3509                         // this might contain some strange encodings (against specs.)
       
  3510                         // should be checked
       
  3511                         TPtrC8 pointer = GetByteString();
       
  3512                         iMimeHeaders->ContentDispositionParams().AppendL( KWspFilenameString );
       
  3513                         iMimeHeaders->ContentDispositionParams().AppendL( pointer );
       
  3514 #ifndef _NO_MMSS_LOGGING_
       
  3515                         buffer = HBufC16::NewLC( pointer.Length() );
       
  3516                         buffer->Des().Copy( pointer );
       
  3517                         // we cannot log indefinitely long strings.
       
  3518                         // We get this long strings only if the message is corrupted.
       
  3519                         dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3520                         TMmsLogger::Log( _L("- filename: %S"), &dummy );
       
  3521                         CleanupStack::PopAndDestroy( buffer );
       
  3522 #endif
       
  3523                         }
       
  3524                     else
       
  3525                         {
       
  3526                         SkipFieldValue();
       
  3527                         }
       
  3528                     }
       
  3529                 else
       
  3530                     {
       
  3531                     // if "filename" has been sent as string, we skip it
       
  3532                     if ( byte >= KMms0x20 && byte <= KMms0x7F )
       
  3533                         {
       
  3534                         // text string, save as content type parameter
       
  3535                         // If we don have a pair of two text strings, the message is illegal
       
  3536                         // The code will probably leave at some point
       
  3537                         iMimeHeaders->ContentDispositionParams().AppendL( GetByteString() );
       
  3538                         iMimeHeaders->ContentDispositionParams().AppendL( GetByteString() );
       
  3539                         }
       
  3540                     else
       
  3541                         {
       
  3542                         // skip
       
  3543                         SkipParameterName();
       
  3544                         SkipFieldValue();
       
  3545                         }
       
  3546                     }
       
  3547                 }
       
  3548 
       
  3549             iPosition = currentPosition + length;
       
  3550             if ( iPosition >= iLength )
       
  3551                 {
       
  3552                 iError = KErrCorrupt;
       
  3553                 }
       
  3554             break;
       
  3555             }
       
  3556         case KMmsTextHeader:
       
  3557             {
       
  3558             // contentHeader points to the textual header
       
  3559 #ifndef _NO_MMSS_LOGGING_
       
  3560             // we don't leave just for logging
       
  3561             TInt error = KErrNone;
       
  3562             TRAP( error,
       
  3563                 {
       
  3564                 buffer = NULL;
       
  3565                 buffer = HBufC16::NewLC( contentHeader.Length() );
       
  3566                 buffer->Des().Copy( contentHeader );
       
  3567                 // we cannot log indefinitely long strings.
       
  3568                 // We get this long strings only if the message is corrupted.
       
  3569                 dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3570                 TMmsLogger::Log( _L("- Textual content header: %S"), &dummy );
       
  3571                 CleanupStack::PopAndDestroy( buffer );
       
  3572                 };);
       
  3573             if ( error != KErrNone )
       
  3574                 {
       
  3575                 TMmsLogger::Log( _L("- Decode left when logging content header, error : %d"),
       
  3576                     error ); 
       
  3577                 }
       
  3578 #endif
       
  3579             if ( contentHeader.FindF( KMmsExtension ) == 0 )
       
  3580                 {
       
  3581                 // extension header, store to mime headers, get corresponding parameter
       
  3582                 // and store to MIME headers
       
  3583                 TPtrC8 pointer = GetByteString();
       
  3584                 iMimeHeaders->XTypeParams().AppendL( contentHeader ); // header name 
       
  3585                 iMimeHeaders->XTypeParams().AppendL( pointer ); // header value
       
  3586 #ifndef _NO_MMSS_LOGGING_
       
  3587                 buffer = HBufC16::NewLC( pointer.Length() );
       
  3588                 buffer->Des().Copy( pointer );
       
  3589                 // we cannot log indefinitely long strings.
       
  3590                 // We get this long strings only if the message is corrupted.
       
  3591                 dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  3592                 TMmsLogger::Log( _L("- extension header value: %S"), &dummy );
       
  3593                 CleanupStack::PopAndDestroy( buffer );
       
  3594 #endif
       
  3595                 }
       
  3596             else
       
  3597                 {
       
  3598                 SkipFieldValue();
       
  3599                 }
       
  3600                 
       
  3601             break;
       
  3602             }
       
  3603         default:
       
  3604 #ifndef _NO_MMSS_LOGGING_
       
  3605             TMmsLogger::Log( _L("- Unknown content header: 0x%02X"), header );
       
  3606 #endif
       
  3607             SkipFieldValue();
       
  3608             break;
       
  3609         }
       
  3610 
       
  3611     }
       
  3612 
       
  3613 // ---------------------------------------------------------
       
  3614 //
       
  3615 // ---------------------------------------------------------
       
  3616 //
       
  3617 TInt CMmsDecode::GetContentHeaderName( TPtrC8& aTextHeader )
       
  3618     {
       
  3619 
       
  3620     TInt header;
       
  3621     header = -1; // unknown
       
  3622     aTextHeader.Set( TPtrC8() ); // empty string
       
  3623     
       
  3624     TUint8 byte;
       
  3625 
       
  3626     if ( iPosition < iLength )
       
  3627         {
       
  3628         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  3629         }
       
  3630     else
       
  3631         {
       
  3632         return header;
       
  3633         }
       
  3634 
       
  3635     // byte cannot be bigger than 255. No need to test upper limit
       
  3636     if ( byte >= KMms0x80 )
       
  3637         {
       
  3638         // well known header, advance pointer and remove high bit
       
  3639         iPosition++;
       
  3640         header = (byte & KMms0x7F);
       
  3641         return header;
       
  3642         }
       
  3643     else
       
  3644         {
       
  3645         TPtrC8 pointer = GetByteString();
       
  3646         aTextHeader.Set( pointer );
       
  3647         header = KMmsTextHeader; // this will cover X-headers
       
  3648         if ( pointer.CompareF( KWspContentIdString ) == 0 )
       
  3649             {
       
  3650             header = KWspContentId;
       
  3651             }
       
  3652         }
       
  3653 
       
  3654     // To handle X-headers and Java apllication id parameters,
       
  3655     // the text string is offered to caller.
       
  3656     // The header has been set to KMmsTextHeader to indicate that the field value
       
  3657     // is still available.
       
  3658 
       
  3659     if ( ( header < 0 ) && ( iPosition < iLength ) )
       
  3660         {
       
  3661         SkipFieldValue();
       
  3662         }
       
  3663 
       
  3664     return header;
       
  3665     }
       
  3666 
       
  3667 // ---------------------------------------------------------
       
  3668 //
       
  3669 // ---------------------------------------------------------
       
  3670 //
       
  3671 //
       
  3672 void CMmsDecode::DecodeOneAttachmentL()
       
  3673     {
       
  3674     
       
  3675     DecodeAttachmentHeadersL();
       
  3676     
       
  3677     // We must be able to handle an empty message without panic
       
  3678     if ( iCurrentAttaLength == 0 )
       
  3679         {
       
  3680         // if attachment length == 0, do not create an attachment
       
  3681         return;
       
  3682         }
       
  3683     
       
  3684     TMsvAttachmentId attachmentId = 0;
       
  3685     TInt32 drmFlags = 0;
       
  3686     TPtrC8 attaData;
       
  3687     if ( iPosition >= iLength )
       
  3688         {
       
  3689         iCurrentAttaLength = 0;
       
  3690         }
       
  3691     attaData.Set( iDecodeBuffer->Ptr( iPosition ).Ptr(), iCurrentAttaLength );
       
  3692    
       
  3693     TInt size = 0;
       
  3694     
       
  3695 #ifndef _NO_MMSS_LOGGING_
       
  3696     TMmsLogger::Log( _L("- Attachment creation starts %S"), &iParse.FullName() );
       
  3697 #endif
       
  3698     if ( iError == KErrNone )
       
  3699         {
       
  3700         iError = iEntryWrapper->CreateFileAttachmentL(
       
  3701             *iStore,
       
  3702             iParse.NameAndExt(),
       
  3703             attaData,
       
  3704             *iMimeHeaders,
       
  3705             attachmentId,
       
  3706             size,
       
  3707             drmFlags);
       
  3708         }
       
  3709 
       
  3710 #ifndef _NO_MMSS_LOGGING_
       
  3711     if ( iError == KErrNone )
       
  3712         {
       
  3713         TRAP_IGNORE({
       
  3714             MMsvAttachmentManager& attaMan = iStore->AttachmentManagerL();
       
  3715             CMsvAttachment* attaInfo = attaMan.GetAttachmentInfoL( attachmentId );
       
  3716             TMmsLogger::Log( _L("- Attachment created %S"), &attaInfo->FilePath() );
       
  3717             delete attaInfo;
       
  3718             attaInfo = NULL;
       
  3719             });
       
  3720         }
       
  3721 #endif
       
  3722 
       
  3723     iDRMFlags |= drmFlags;
       
  3724     
       
  3725     if ( iError == KMmsErrorRemoveDRM )
       
  3726         {
       
  3727         // The attachment was not saved, but we can continue
       
  3728         iError = KErrNone;
       
  3729 #ifndef _NO_MMSS_LOGGING_
       
  3730         TMmsLogger::Log( _L("- DRM attachment removed") );
       
  3731 #endif
       
  3732         }
       
  3733     else if ( iError == KErrNone )
       
  3734         {
       
  3735         if ( ( iMultipartType == KMmsAssignedApplicationVndWapMultipartRelated ) &&
       
  3736             ( iRootContentId.Length() > 0 ) &&
       
  3737             ( iRootAttachmentId == 0 ) )
       
  3738             {
       
  3739             // check if content-id's match
       
  3740             if ( iRootContentId.Compare( iMimeHeaders->ContentId() ) == 0 )
       
  3741                 {
       
  3742                 iRootAttachmentId = attachmentId;
       
  3743                 }
       
  3744             }
       
  3745         iTotalSize += size;
       
  3746         }
       
  3747     else
       
  3748         {
       
  3749         // do nothing - keep LINT happy
       
  3750         }
       
  3751  
       
  3752     if ( iDataStart == iFakeSubject )
       
  3753         {
       
  3754         iTextPlainLength = iCurrentAttaLength;
       
  3755         }
       
  3756 
       
  3757     // if doing dumping, also dump the smil part to a file
       
  3758     // Note: this modifies iFileName, but our original file was closed already
       
  3759     
       
  3760 #ifndef _NO_MMSS_LOGGING_
       
  3761     DumpSmil( iCurrentAttaLength );
       
  3762 #endif
       
  3763  
       
  3764     iPosition = iNextStart;
       
  3765 
       
  3766     if ( iMultipartType == KMmsAssignedApplicationVndWapMultipartReport )
       
  3767         {
       
  3768         // If we have a multipart/report, we ignore the rest of attachments
       
  3769         iNumberOfAttachments = 1;
       
  3770         iPosition = iLength;
       
  3771         }
       
  3772      
       
  3773     CompleteSelf( iError );    
       
  3774         
       
  3775     }
       
  3776 
       
  3777 // ---------------------------------------------------------
       
  3778 //
       
  3779 // ---------------------------------------------------------
       
  3780 //
       
  3781 void CMmsDecode::DecodeAttachmentHeadersL()
       
  3782     {
       
  3783     TUint32 headersLength = 0;
       
  3784     iCurrentAttaLength = 0;
       
  3785     iAttaNumber++; // starts fron zero, is 1 after first increment
       
  3786     TInt error = KErrNone; // temporary error
       
  3787 #ifndef _NO_MMSS_LOGGING_
       
  3788     TPtrC dummy;
       
  3789 #endif
       
  3790 
       
  3791 #ifndef _NO_MMSS_LOGGING_
       
  3792     TMmsLogger::Log( _L("- Attachment #%d"), iAttaNumber );
       
  3793 #endif
       
  3794     // we may have a multipart structure or a single monoblock data body
       
  3795     // we handle both here.
       
  3796     // The momoblock structure probably won't work correctly in chunked mode
       
  3797     // but it is not supposed to be supported anyway.
       
  3798     
       
  3799     // Before this funtion is called in the chunked mode we have checked
       
  3800     // that we have enough data to cover all the headers (the length of the
       
  3801     // headers is given in the beginning)
       
  3802     
       
  3803     if ( iMultipartType != 0 )
       
  3804         {
       
  3805         if ( iPosition < iLength )
       
  3806             {
       
  3807             headersLength = GetUintvar();
       
  3808             }
       
  3809         else
       
  3810             {
       
  3811             iError = KErrCorrupt;
       
  3812             if ( iDecodingStage == EMmsNotApplicable )
       
  3813                 {
       
  3814                 CompleteSelf( iError );
       
  3815                 }
       
  3816             return;
       
  3817             }
       
  3818 
       
  3819         if ( iPosition < iLength )
       
  3820             {
       
  3821             iCurrentAttaLength = GetUintvar();
       
  3822             }
       
  3823         else
       
  3824             {
       
  3825             iError = KErrCorrupt;
       
  3826             if ( iDecodingStage == EMmsNotApplicable )
       
  3827                 {
       
  3828                 CompleteSelf( iError );
       
  3829                 }
       
  3830             return;
       
  3831             }
       
  3832             
       
  3833         // Data start can be calculated now.
       
  3834         // Also the start of next attachment.
       
  3835 
       
  3836         iDataStart = iPosition + headersLength;
       
  3837 
       
  3838         if ( iDataStart > iLength && iDecodingStage == EMmsNotApplicable )
       
  3839             {
       
  3840             // This is an error only if we are handling all data, not chunks
       
  3841             iError = KErrCorrupt;
       
  3842             CompleteSelf( iError );
       
  3843             return;
       
  3844             }
       
  3845 
       
  3846         if ( iDataStart + iCurrentAttaLength > iLength && iDecodingStage == EMmsNotApplicable )
       
  3847             {
       
  3848             // if we are doing chunked decoding there may not be enough data in our buffer
       
  3849             iCurrentAttaLength = iLength - iDataStart;
       
  3850             }
       
  3851         iNextStart = iDataStart + iCurrentAttaLength;
       
  3852         }
       
  3853     else
       
  3854     // monoblock - this probably won't work in chunked mode
       
  3855     // but then MMS engine is not supposed to support this kind of structure anyway
       
  3856     // The data should always be wrapped in multipart structure even if there is 
       
  3857     // only one part.
       
  3858     // If the message is so small that everything fits into the buffer at one go,
       
  3859     // then this will work in chunked mode, too.
       
  3860         {
       
  3861         // save old position
       
  3862         TUint oldPosition = iPosition;
       
  3863         headersLength = GetValueLength();
       
  3864         iDataStart = iPosition + headersLength;
       
  3865         iCurrentAttaLength = iLength - iDataStart;
       
  3866         iNextStart = iDataStart + iCurrentAttaLength;
       
  3867         // Header's length is part of content type header.
       
  3868         // we cannot remove it, or we cannot interpret the
       
  3869         // content type header correctly.
       
  3870         iPosition = oldPosition;
       
  3871         }
       
  3872 
       
  3873 #ifndef _NO_MMSS_LOGGING_
       
  3874     TMmsLogger::Log( _L("- Headers length: %d"), headersLength );
       
  3875     TMmsLogger::Log( _L("- Data length: %d"), iCurrentAttaLength );
       
  3876 #endif
       
  3877 
       
  3878     
       
  3879     // don't touch iMmsHeaders, they may still be needed.
       
  3880     // Just reset mime headers, attachments don't need anything else.
       
  3881     iMimeHeaders->Reset();
       
  3882 
       
  3883     // We must be able to handle an empty message without panic
       
  3884     if ( iCurrentAttaLength == 0 )
       
  3885         {
       
  3886         // empty attachment, don't create entry
       
  3887         iPosition = iNextStart;
       
  3888         if ( iDecodingStage == EMmsNotApplicable )
       
  3889             {
       
  3890             // chunked mode is not an active object
       
  3891             CompleteSelf( iError );
       
  3892             }
       
  3893         return;
       
  3894         }
       
  3895     
       
  3896     // attachment creation cannot be done before we have all the headers
       
  3897     
       
  3898     GetAttachmentContentTypeL();
       
  3899     
       
  3900     // Now we must analyze the content-headers
       
  3901     // We only try to find Content-Location to get the filename
       
  3902     // We should also save the Content-ID:s in case the SMIL part uses them
       
  3903     // We also need to check if the Content-ID of some part matches
       
  3904     // the content id given as the start parameter for multipart/related type
       
  3905     // Some terminals put filename as parameter of content-disposition,
       
  3906     // so that should be checked, too.
       
  3907 
       
  3908     while ( iPosition < iDataStart )
       
  3909         {
       
  3910         DecodeOneContentHeaderL();
       
  3911         }
       
  3912 
       
  3913     if ( ( iMultipartType == KMmsAssignedApplicationVndWapMultipartRelated ) &&
       
  3914         ( iRootContentId.Length() == 0 ) && iAttaNumber == 1 )
       
  3915         {
       
  3916         // First part must be root if start parameter not defined
       
  3917         if ( iMimeHeaders->ContentId().Length() == 0 )
       
  3918             {
       
  3919             TTime now;
       
  3920             now.UniversalTime();
       
  3921             TInt random;
       
  3922             TInt64 seed = now.Int64();
       
  3923             // no problem with conversions - just creating a magic number for content id
       
  3924             random = Math::Rand( seed );
       
  3925             iTempBuffer.Des().Num( random );
       
  3926             iMimeHeaders->SetContentIdL( iTempBuffer.Des() );
       
  3927             iRootContentId.Set( iTempBuffer.Des() );
       
  3928             }
       
  3929         }
       
  3930     
       
  3931     // Now we have a root content id if the message is multipart/related.
       
  3932     // we can set up the id for the root part after the attachment has been
       
  3933     // created
       
  3934     
       
  3935     iPosition = iDataStart; // binary data starts here
       
  3936     
       
  3937     // Now we must try to generate a filename for the attachment.
       
  3938     // A name must be generated before the actual attachment is saved
       
  3939     
       
  3940     TPtrC temp = TPtrC();
       
  3941     TPtrC ptr;
       
  3942 
       
  3943     TBool isContentLocationFileName = EFalse;
       
  3944     TPtrC8 dummy8;
       
  3945 
       
  3946     // Try name parameter of content location first
       
  3947     if ( !isContentLocationFileName )
       
  3948         {
       
  3949         dummy8.Set( iMimeHeaders->GetContentTypeValue( KWspNameString ) );
       
  3950         isContentLocationFileName =  MakeFilenameL( dummy8, iParse, TPtrC() );
       
  3951         }
       
  3952 
       
  3953     // Try filename parameter of content-disposition header next
       
  3954     TInt i;
       
  3955     // every other string is parameter, every other one is value
       
  3956     for ( i = 0;
       
  3957         i < iMimeHeaders->ContentDispositionParams().MdcaCount() && !isContentLocationFileName;
       
  3958         i += KMms2 )
       
  3959         {
       
  3960         // Try to generate a filename from the filename parameter
       
  3961         if ( iMimeHeaders->ContentDispositionParams().MdcaPoint( i ).CompareF(
       
  3962             KWspFilenameString ) == 0 )
       
  3963             {
       
  3964             dummy8.Set( iMimeHeaders->ContentDispositionParams().MdcaPoint( i + 1 ) );
       
  3965             isContentLocationFileName = MakeFilenameL( dummy8, iParse, TPtrC() );
       
  3966             }
       
  3967         }
       
  3968 
       
  3969     HBufC16* uri = NULL;
       
  3970     if ( !isContentLocationFileName &&
       
  3971         iMimeHeaders->ContentLocation().Length() > 0 )
       
  3972         {
       
  3973         // Try to generate a filename from the content location
       
  3974         error = KErrNone;
       
  3975         TRAP( error, ( uri = EscapeUtils::EscapeDecodeL( iMimeHeaders->ContentLocation() ) ) );
       
  3976         if ( error == KErrNone )
       
  3977             {
       
  3978             temp.Set( uri->Des().Right( KMmsMaxFileName ) );
       
  3979             }
       
  3980         else
       
  3981             {
       
  3982             temp.Set( iMimeHeaders->ContentLocation().Right( KMmsMaxFileName ) );
       
  3983             }
       
  3984         error = iParse.Set( TPtrC(), &temp, NULL );
       
  3985         if ( error == KErrNone )
       
  3986             {
       
  3987             isContentLocationFileName = iEntryWrapper->IsValidFilename( iParse.NameAndExt() );
       
  3988             }
       
  3989         }
       
  3990     CleanupStack::PushL( uri );
       
  3991 
       
  3992     // if content location not specified, use name parameter
       
  3993     // as content location. FIX for /// originated messages.
       
  3994     if ( iMimeHeaders->ContentLocation().Length() == 0 )
       
  3995         {
       
  3996         dummy8.Set( iMimeHeaders->GetContentTypeValue( KWspNameString ) );
       
  3997         // This may use some strange charset. Should be decoded.
       
  3998         // We only use it if it appears to be ascii.
       
  3999         if ( dummy8.Length() > 0 && IsStringSafe( dummy8 ) )
       
  4000             {
       
  4001             HBufC* name = HBufC::NewL( dummy8.Length() );
       
  4002             CleanupStack::PushL( name );
       
  4003             name->Des().Copy( dummy8 );
       
  4004             iMimeHeaders->SetContentLocationL( name->Des() );
       
  4005 #ifndef _NO_MMSS_LOGGING_
       
  4006             // we cannot log indefinitely long strings.
       
  4007             // We get this long strings only if the message is corrupted.
       
  4008             dummy.Set( name->Des().Left( KMmsMaxLogStringLength ) );
       
  4009             TMmsLogger::Log( _L("- Content location from name parameter: %S"), &dummy );
       
  4010 #endif
       
  4011             CleanupStack::PopAndDestroy( name );
       
  4012             name = NULL;
       
  4013             }
       
  4014         }
       
  4015 
       
  4016     TBuf<KMms14> attaName; // max 4294967295 attas.
       
  4017     _LIT( KRelated, "att");
       
  4018 
       
  4019     if ( !isContentLocationFileName )
       
  4020         {
       
  4021         // We don't have content location, we must invent a filename
       
  4022         // We should try to generate a sensible extension based on content type
       
  4023         // Now we will have no extension
       
  4024         attaName.Num( iAttaNumber, EDecimal );
       
  4025         attaName.Insert( 0, KRelated );
       
  4026 
       
  4027         i = 0;
       
  4028         TBool matchFound = EFalse;
       
  4029         TPtrC8 matchTablePointer;
       
  4030         matchTablePointer.Set( KMmsFileExtensionMatchTable[i].tag );
       
  4031         while ( matchTablePointer.Length() > 0 && !matchFound )
       
  4032             {
       
  4033             if ( iMimeHeaders->ContentSubType().FindF(
       
  4034                 TPtrC8( KMmsFileExtensionMatchTable[i].tag ) ) != KErrNotFound )
       
  4035                 {
       
  4036                 temp.Set( KMmsFileExtensionMatchTable[i].extension );
       
  4037                 matchFound = ETrue;
       
  4038                 }
       
  4039             i++;
       
  4040             matchTablePointer.Set( KMmsFileExtensionMatchTable[i].tag );
       
  4041             }
       
  4042         ptr.Set( attaName );
       
  4043         if ( !matchFound )
       
  4044             {
       
  4045             // unknown type, no extension
       
  4046             iParse.Set( TPtrC(), &ptr, NULL );
       
  4047             }
       
  4048         else
       
  4049             {
       
  4050             iParse.Set( TPtrC(), &ptr, &temp );
       
  4051             }
       
  4052         }
       
  4053         
       
  4054     // We are through with filename, and URI may go if it ever was allocated
       
  4055     CleanupStack::PopAndDestroy( uri );
       
  4056     
       
  4057 
       
  4058     // We have to use iParse.NameAndExt as a guess for filename
       
  4059     // we cannot call CApaApplication::GenerateFileName without a path
       
  4060     
       
  4061     // The next thing to do is to create an empty file ready to accept
       
  4062     // the attachment data.
       
  4063     
       
  4064     
       
  4065     
       
  4066     }
       
  4067 
       
  4068 // ---------------------------------------------------------
       
  4069 //
       
  4070 // ---------------------------------------------------------
       
  4071 //
       
  4072 void CMmsDecode::ExtractContentTypeParametersL( const TPtrC8& aBuffer )
       
  4073     {
       
  4074     // we get here the parameter part of content type in the format
       
  4075     // parameter1=value1;parameter2=value2
       
  4076     TInt start = 0;
       
  4077     TInt end = 0;
       
  4078     TInt tokenEnd = 0;
       
  4079     while ( start < aBuffer.Length() )
       
  4080         {
       
  4081         // remove leading spaces
       
  4082         while ( start < aBuffer.Length() && aBuffer.Mid( start ).FindF( KSpace8 ) == 0 )
       
  4083             {
       
  4084             start++;
       
  4085             }
       
  4086         if ( start >= aBuffer.Length() )
       
  4087             {
       
  4088             return; // done, nothing left
       
  4089             }
       
  4090         // extract token
       
  4091         end = aBuffer.Mid( start ).FindF( KEquals8 );
       
  4092         if ( end == KErrNotFound )
       
  4093             {
       
  4094             end = aBuffer.Length(); 
       
  4095             }
       
  4096         else
       
  4097             {
       
  4098             end += start; // remember the original offset
       
  4099             }
       
  4100         tokenEnd = end - 1;
       
  4101         // remove trailing spaces from token
       
  4102         while ( tokenEnd - start > start && aBuffer.Mid( start, tokenEnd - start + 1 ).FindF( KSpace8 ) == tokenEnd - start )
       
  4103             {
       
  4104             tokenEnd--;
       
  4105             }
       
  4106         if ( aBuffer.Mid( start, tokenEnd - start + 1 ).Length() == 0 )
       
  4107             {
       
  4108             return; // garbage, give up
       
  4109             }
       
  4110         else
       
  4111             {
       
  4112             iMimeHeaders->ContentTypeParams().AppendL(
       
  4113                 aBuffer.Mid( start, tokenEnd - start + 1 ) );
       
  4114             }
       
  4115         // extract value
       
  4116         start = end + 1;
       
  4117         if ( start >= aBuffer.Length() )
       
  4118             {
       
  4119             iMimeHeaders->ContentTypeParams().AppendL( TPtrC8() );
       
  4120             return;
       
  4121             }
       
  4122         // remove leading spaces
       
  4123         while ( start < aBuffer.Length() && aBuffer.Mid( start ).FindF( KSpace8 ) == 0 )
       
  4124             {
       
  4125             start++;
       
  4126             }
       
  4127         if ( start >= aBuffer.Length() )
       
  4128             {
       
  4129             // there was no value for the parameter - must add an empty value
       
  4130             iMimeHeaders->ContentTypeParams().AppendL( TPtrC8() );
       
  4131             return; // done, nothing left
       
  4132             }
       
  4133         // A string or a quoted string left.
       
  4134         // If quoted string, search for end quote.
       
  4135         // If not quoted, search for next semicolon (delimiter between parameters)
       
  4136         if ( aBuffer.Mid( start ).FindF( &KMmsStringQuote, 1 ) == 0 )
       
  4137             {
       
  4138             start++; // discard the quotes
       
  4139             end = aBuffer.Mid( start ).FindF( &KMmsStringQuote, 1 );
       
  4140             if ( end != KErrNotFound )
       
  4141                 {
       
  4142                 end += start; // remember the original offset
       
  4143                 }
       
  4144             else
       
  4145                 {
       
  4146                 end = aBuffer.Length();
       
  4147                 }
       
  4148             tokenEnd = end - 1;
       
  4149             // skip to next delimiter
       
  4150             end = aBuffer.Mid( tokenEnd + 1 ).FindF( KSemicolon8 );
       
  4151             if ( end == KErrNotFound )
       
  4152                 {
       
  4153                 end = aBuffer.Length();
       
  4154                 }
       
  4155             else
       
  4156                 {
       
  4157                 end += tokenEnd + 1; // remember the original offset
       
  4158                 }
       
  4159             }
       
  4160         else
       
  4161             {
       
  4162             end = aBuffer.Mid( start ).FindF( KSemicolon8 );
       
  4163             if ( end == KErrNotFound )
       
  4164                 {
       
  4165                 end = aBuffer.Length();
       
  4166                 }
       
  4167             else
       
  4168                 {
       
  4169                 end += start; // remember the original offset
       
  4170                 }
       
  4171             tokenEnd = end - 1;
       
  4172             // Remove trailing spaces from value.
       
  4173             // If the value was a quoted string, spaces are part of value,
       
  4174             // and must not be removed.
       
  4175             while ( aBuffer.Mid( start, tokenEnd - start + 1 ).FindF( KSpace8 ) ==
       
  4176                 tokenEnd - start )
       
  4177                 {
       
  4178                 tokenEnd--;
       
  4179                 }
       
  4180             }
       
  4181         iMimeHeaders->ContentTypeParams().AppendL( aBuffer.Mid( start, tokenEnd - start + 1 ) );
       
  4182         // keep trying 
       
  4183         start = end + 1;
       
  4184         }
       
  4185     }
       
  4186 
       
  4187 // ---------------------------------------------------------
       
  4188 //
       
  4189 // ---------------------------------------------------------
       
  4190 //
       
  4191 TBool CMmsDecode::MakeFilenameL( TPtrC8& aSource, TParse& aDestination, const TFileName& aPath )
       
  4192     {
       
  4193     if ( aSource.Length() == 0 )
       
  4194         {
       
  4195         return EFalse;
       
  4196         }
       
  4197     TBool retValue = EFalse;
       
  4198     TInt error = KErrNone;
       
  4199     HBufC* name = NULL;
       
  4200     name = HBufC::NewL( aSource.Length() );
       
  4201     CleanupStack::PushL( name );
       
  4202     TPtr pointer = name->Des();
       
  4203     pointer.Copy( aSource );
       
  4204 
       
  4205     if ( pointer.FindF( KEqualsQuestion16 ) != KErrNotFound )
       
  4206         {
       
  4207         // Try to resolve MIME encoding
       
  4208         TRAP( error, TMmsGenUtils::DecodeAndConvertMessageHeaderL( aSource, pointer, iFs ) );
       
  4209         }
       
  4210     else
       
  4211         {
       
  4212         // not MIME, error is fake, this may be just fine
       
  4213         error = KErrCorrupt;
       
  4214         }
       
  4215 
       
  4216     if ( error != KErrNone )
       
  4217         {
       
  4218         // Try to resolve plain utf8
       
  4219         error = CnvUtfConverter::ConvertToUnicodeFromUtf8( pointer, aSource );
       
  4220         }
       
  4221 
       
  4222     if ( error != KErrNone )
       
  4223         {
       
  4224         // use as is
       
  4225         name->Des().Copy( aSource );
       
  4226         }
       
  4227 
       
  4228     TPtrC ptr;
       
  4229 
       
  4230     if ( pointer.Length() > 0 )
       
  4231         {
       
  4232 #ifndef _NO_MMSS_LOGGING_
       
  4233         ptr.Set( name->Des().Left( KMmsMaxLogStringLength ) );
       
  4234         TMmsLogger::Log( _L("- decoded name: %S"), &ptr );
       
  4235 #endif
       
  4236         // We limit the length in case the filename is way too long (max is 100 characters).
       
  4237         // We take the rightmost part to get the extension.
       
  4238         // If we drop something from the beginning, it may be path or beginning of an overly
       
  4239         // long name. As the too long name does not make sense anyway, we are free to drop
       
  4240         // any part we like. No filenames should be 100 characters long.
       
  4241         ptr.Set( name->Des().Right( KMmsMaxFileName ) );
       
  4242         error = aDestination.Set( aPath, &ptr, NULL );
       
  4243         if ( error == KErrNone )
       
  4244             {
       
  4245             // If the string we are trying to set to TParse is not valid,
       
  4246             // we cannot check for filename
       
  4247             retValue = iEntryWrapper->IsValidFilename( aDestination.NameAndExt() );
       
  4248             }
       
  4249         }
       
  4250         
       
  4251     CleanupStack::PopAndDestroy( name );
       
  4252     return retValue;
       
  4253     }
       
  4254 
       
  4255 
       
  4256 // ---------------------------------------------------------
       
  4257 //
       
  4258 // ---------------------------------------------------------
       
  4259 //
       
  4260 void CMmsDecode::FinishL()
       
  4261     {
       
  4262 
       
  4263     // We don't check the critical disk space level here.
       
  4264     // If we got this far, we cannot balk now,
       
  4265     // we have to continue to the bitter end.
       
  4266 
       
  4267     // If root attachment id == 0, the root has been deleted.
       
  4268     // In that case the message structure has been messed up
       
  4269     // and we can only show separate objects
       
  4270     
       
  4271     // use iStore member
       
  4272     if ( !iStore )
       
  4273         {
       
  4274         iStore = iEntryWrapper->EditStoreL();
       
  4275         }
       
  4276     
       
  4277     iMmsHeaders->RestoreL( *iStore );
       
  4278     
       
  4279     if ( iRootContentId.Length() > 0 &&
       
  4280         iRootAttachmentId != 0 )
       
  4281         {
       
  4282         iMmsHeaders->SetRootContentIdL( iRootContentId );
       
  4283         iMmsHeaders->SetMessageRoot( iRootAttachmentId );
       
  4284         iMmsHeaders->StoreL( *iStore );
       
  4285         }
       
  4286 
       
  4287     // this also commits all the attachments
       
  4288     iStore->CommitL();
       
  4289     
       
  4290     // If we are in chunked mode we must get the possible fake subject from a file
       
  4291     // because buffer gets reused.
       
  4292     
       
  4293     // now everything should be committed, and store can go
       
  4294     delete iStore;
       
  4295     iStore = NULL;
       
  4296 
       
  4297     // calculate the total size of message
       
  4298     iTotalSize += iMmsHeaders->Size();
       
  4299 
       
  4300     TPtrC details = TPtrC();
       
  4301     TPtrC description = TPtrC();
       
  4302 
       
  4303     // Neither sender nor subject might be present.
       
  4304     // We ought to extract a few characters from the beginning of the
       
  4305     // first text/plain part for the subject, if no separate subject is available
       
  4306 
       
  4307     // if the sender is a phone number add alias.
       
  4308     // We don't add alias for email addresses here, as the comms
       
  4309     // database search for email addresses is very slow
       
  4310     // if there are lots of contacts.
       
  4311 
       
  4312     HBufC* buffer = HBufC::NewL( KMmsMaxDescription );
       
  4313     CleanupStack::PushL( buffer );
       
  4314     TPtr pBuffer = buffer->Des();
       
  4315     HBufC* descriptionBuffer = NULL; // we may or may not need this
       
  4316 
       
  4317     if ( TMmsGenUtils::GenerateDetails( iMmsHeaders->Sender(),
       
  4318         pBuffer, KMmsMaxDescription, iFs ) == KErrNone )
       
  4319         {
       
  4320         details.Set( pBuffer );
       
  4321         }
       
  4322     else
       
  4323         {
       
  4324         // We come here only if there was a fatal error in GenerateDetails.
       
  4325         // Even if we don't find the alias, we have something in the string
       
  4326         details.Set( iMmsHeaders->Sender() );
       
  4327         }
       
  4328 
       
  4329     // the buffer cannot be reused, because tEntry only contains
       
  4330     // a pointer to our data, not a copy of it.
       
  4331     if ( iMmsHeaders->Subject().Length() > 0 )
       
  4332         {
       
  4333         description.Set( iMmsHeaders->Subject() );
       
  4334         }
       
  4335     else
       
  4336         {
       
  4337         // Check if we have found a text/plain part to be used as description.
       
  4338         // Only use it if there is only one alternative, otherwise we don't
       
  4339         // know which one to use.
       
  4340         if ( iFakeSubject > 0 && iPlainTexts == 1 && iFakeSubject < iDecodeBuffer->Size() )
       
  4341             {
       
  4342             // we have a pointer to text/plain part
       
  4343             // we need a new buffer as our old buffer should not be destroyed
       
  4344 
       
  4345             descriptionBuffer = HBufC::NewL( KMmsMaxDescription );
       
  4346             CleanupStack::PushL( descriptionBuffer );
       
  4347             pBuffer.Set( descriptionBuffer->Des() );
       
  4348 
       
  4349             if ( iCharacterSet == KMmsIso10646Ucs2 ||
       
  4350                 iCharacterSet == KMmsUTF16 ||
       
  4351                 iCharacterSet == KMmsUTF16BE ||
       
  4352                 iCharacterSet == KMmsUTF16LE)
       
  4353                 {
       
  4354                 // This may be big-endian or little-endian
       
  4355                 TBool nativeEndian = EFalse; // pessimist.
       
  4356                 TInt length = iTextPlainLength;
       
  4357                 if ( length > KMmsMaxDescription * KMms2 )
       
  4358                     {
       
  4359                     length = KMmsMaxDescription * KMms2; // this should be enough
       
  4360                     }
       
  4361                 TInt i;
       
  4362                 TUint start = 0;
       
  4363                 TUint16 word = 0;
       
  4364                 iPosition = iFakeSubject;
       
  4365                 // must be able to read at least 2 bytes
       
  4366                 if ( iPosition < iLength - 1 )
       
  4367                     {
       
  4368                     iDecodeBuffer->Read( iPosition, &word, KMmsMinHeaderLength );
       
  4369                     }
       
  4370 
       
  4371                 // Check if we have a BOM (byte order mark).
       
  4372                 if ( word == KMmsByteOrderMark )
       
  4373                     {
       
  4374                     nativeEndian = ETrue;
       
  4375                     iPosition += KMms2;
       
  4376                     start += KMms2; // skip the endianness byte from the subject
       
  4377                     }
       
  4378                 else if ( word == KMmsReversedByteOrderMark )
       
  4379                     {
       
  4380                     nativeEndian = EFalse;
       
  4381                     iPosition += KMms2;
       
  4382                     start += KMms2; // skip the endianness byte from the subject
       
  4383                     }
       
  4384                 else
       
  4385                     {
       
  4386                     CBufFlat* shortBuffer = CBufFlat::NewL( KMms2 );
       
  4387                     CleanupStack::PushL( shortBuffer );
       
  4388                     shortBuffer->ResizeL( KMms2 );
       
  4389                     // no need to put it into cleanupstack... we dont't leave before we delete it
       
  4390                     TUint8 byte;
       
  4391                     // put little-endian BOM to buffer
       
  4392                     byte = 0xFF;
       
  4393                     shortBuffer->Write( 0, &byte, 1 );
       
  4394                     byte = 0xFE;
       
  4395                     shortBuffer->Write( 1, &byte, 1 );
       
  4396                     // get the result into a word, and see if it came out straight or reversed
       
  4397                     shortBuffer->Read( 0, &word, KMms2 );
       
  4398                     CleanupStack::PopAndDestroy( shortBuffer );
       
  4399                     shortBuffer = NULL;
       
  4400                     if ( iCharacterSet == KMmsUTF16LE )
       
  4401                         {
       
  4402                         // I think we are little endian, better check to be sure
       
  4403                         if ( word == KMmsByteOrderMark )
       
  4404                             {
       
  4405                             // we are little endian, charset is little endian
       
  4406                             nativeEndian = ETrue;
       
  4407                             }
       
  4408                         else
       
  4409                             {
       
  4410                             nativeEndian = EFalse;
       
  4411                             }
       
  4412                         }
       
  4413                     else if ( iCharacterSet == KMmsUTF16BE )
       
  4414                         {
       
  4415                         if ( word == KMmsByteOrderMark )
       
  4416                             {
       
  4417                             // we are little endian, charset is big endian
       
  4418                             nativeEndian = EFalse;
       
  4419                             }
       
  4420                         else
       
  4421                             {
       
  4422                             nativeEndian = ETrue;
       
  4423                             }
       
  4424                         }
       
  4425                     // if NO BOM and character set does not define byte ordering,
       
  4426                     // we don't really know.
       
  4427                     // Native endian is left as false - may not be the correct guess.
       
  4428                     else
       
  4429                         {
       
  4430                         // do nothing - keep LINT happy
       
  4431                         }
       
  4432                     }
       
  4433 
       
  4434                 if ( nativeEndian )
       
  4435                     {
       
  4436                     for ( i = start; i < length - 1; i += KMms2 )
       
  4437                         {
       
  4438                         iDecodeBuffer->Read(iPosition, &word, KMms2 );
       
  4439                         iPosition += KMms2;
       
  4440                         pBuffer.Append( word );
       
  4441                         }
       
  4442                     }
       
  4443                 else
       
  4444                     {
       
  4445                     for ( i = start; i < length - 1; i += KMms2 )
       
  4446                         {
       
  4447                         iDecodeBuffer->Read(iPosition, &word, KMms2 );
       
  4448                         iPosition += KMms2;
       
  4449                         TUint16 temp;
       
  4450                         temp = TUint16 ( word & 0xff ) ; //lower byte
       
  4451                         word >>= KMmsBitsInByte; // higher to lower
       
  4452                         word = TUint16 ( ( temp << KMmsBitsInByte ) + word ); 
       
  4453                         pBuffer.Append( word );
       
  4454                         }
       
  4455                     }
       
  4456 
       
  4457                 }
       
  4458             else if ( iCharacterSet == KMmsUsAscii )
       
  4459                 {
       
  4460                 TInt length = iTextPlainLength;
       
  4461                 if ( length > KMmsMaxDescription )
       
  4462                     {
       
  4463                     length = KMmsMaxDescription; // this should be enough
       
  4464                     }
       
  4465                 TPtrC8 attaData;
       
  4466                 attaData.Set( iDecodeBuffer->Ptr( iFakeSubject ).Ptr(), length );
       
  4467                 pBuffer.Copy( attaData );
       
  4468                 }
       
  4469             else if ( iCharacterSet == KMmsUtf8 )
       
  4470                 {
       
  4471                 TInt length = iTextPlainLength;
       
  4472                 if ( length > KMmsMaxDescription )
       
  4473                     {
       
  4474                     length = KMmsMaxDescription; // this should be enough
       
  4475                     }
       
  4476                 // just in case our message is corrupted...
       
  4477                 if ( length > (TInt) ( iDecodeBuffer->Size() - iFakeSubject ) )
       
  4478                     {
       
  4479                     length = iDecodeBuffer->Size() - iFakeSubject;
       
  4480                     }
       
  4481                 TPtrC8 attaData;
       
  4482                 attaData.Set( iDecodeBuffer->Ptr( iFakeSubject ).Ptr(), length );
       
  4483                 if ( length > 0 )
       
  4484                     {
       
  4485                     CnvUtfConverter::ConvertToUnicodeFromUtf8( pBuffer, attaData );
       
  4486                     if ( pBuffer.Length() > 0 && pBuffer.Find( &KMmsByteOrderMark, 1 ) == 0 )
       
  4487                         {
       
  4488                         // remove the BOM
       
  4489                         pBuffer.Delete( 0, 1 );
       
  4490                         }
       
  4491                     }
       
  4492                 }
       
  4493             else
       
  4494                 {
       
  4495                 // we have some unknown character set.
       
  4496                 // we should call some converter
       
  4497                 }
       
  4498             TInt position;
       
  4499             for ( position = 0; position < pBuffer.Length(); position++ )
       
  4500                 {
       
  4501                 if ( pBuffer.Mid( position, 1 ) < KSpace16 ||
       
  4502                     pBuffer.Mid( position, 1 ) == KMmsUnicodeLineSeparator ||
       
  4503                     pBuffer.Mid( position, 1 ) == KMmsUnicodeParagraphSeparator ||
       
  4504                     pBuffer.Mid( position, 1 ) == KMmsIdeographicSpace ||
       
  4505                     ((TChar)pBuffer[position]).IsControl() )
       
  4506                     {
       
  4507                     pBuffer.Replace( position, 1, KSpace16 );
       
  4508                     }
       
  4509                 }
       
  4510                 
       
  4511             
       
  4512             pBuffer.TrimAll();
       
  4513             description.Set( pBuffer );
       
  4514             }
       
  4515         }
       
  4516      
       
  4517     // don't set the response status text to description if the status is OK.
       
  4518     // In that case we have received an empty message that should have no description.
       
  4519     // In OK case the text is mostly "OK" or something equally uninformative    
       
  4520     if ( description.Length() == 0 && iMmsHeaders->ResponseText().Length() > 0 &&
       
  4521         iMmsHeaders->ResponseStatus() > KMmsResponseStatusOK )
       
  4522         {
       
  4523         description.Set( iMmsHeaders->ResponseText() );
       
  4524         }
       
  4525 
       
  4526     TUint32 messageType = 0;
       
  4527 
       
  4528     switch ( iMmsHeaders->MessageType() )
       
  4529         {
       
  4530         case KMmsMessageTypeMSendReq:
       
  4531             messageType = KMmsMessageMSendReq;
       
  4532             break;
       
  4533         case KMmsMessageTypeMNotificationInd:
       
  4534             messageType = KMmsMessageMNotificationInd;
       
  4535             break;
       
  4536         case KMmsMessageTypeMRetrieveConf:
       
  4537             messageType = KMmsMessageMRetrieveConf;
       
  4538             break;
       
  4539         case KMmsMessageTypeDeliveryInd:
       
  4540             messageType = KMmsMessageDeliveryInd;
       
  4541             break;
       
  4542         default:
       
  4543             // Unrecognized type - or one we are not interested in.
       
  4544             // Messages that should not normally be stored on disk
       
  4545             // have the type "unrecognized"
       
  4546             // The type in TMsvEntry should be used for showing icons
       
  4547             // or other special purposes only
       
  4548             messageType = KMmsMessageUnrecognized;
       
  4549             break;
       
  4550         }
       
  4551 
       
  4552     // All data to iMtmData1 is set to an empty base.
       
  4553     // If caller has more flags to set, they must be set afterwards
       
  4554     TInt32 mtmData = 0;
       
  4555     mtmData |= messageType;
       
  4556     mtmData |= iDRMFlags;
       
  4557     if ( iMmsHeaders->MessageClass() == EMmsClassAdvertisement )
       
  4558         {
       
  4559         mtmData |= KMmsMessageAdvertisement;
       
  4560         }
       
  4561     else if ( iMmsHeaders->MessageClass() == EMmsClassInformational )
       
  4562         {
       
  4563         mtmData |= KMmsMessageInformational;
       
  4564         }
       
  4565     else
       
  4566         {
       
  4567         // do nothing - keep LINT happy
       
  4568         }
       
  4569 
       
  4570     TMsvEntry entry;
       
  4571     
       
  4572     iEntryWrapper->GetIndexEntry( entry );
       
  4573     
       
  4574     entry.iDetails.Set( details );
       
  4575     entry.iDescription.Set( description );
       
  4576     entry.iMtmData1 = mtmData;
       
  4577     entry.iSize = iTotalSize;
       
  4578     // Set the date.
       
  4579     // This can in principle be either the arrival time of the message
       
  4580     // or the original time the message was received by MMSC
       
  4581     
       
  4582     entry.iDate = iMmsHeaders->ReceivingTime();
       
  4583     
       
  4584     switch ( iMmsHeaders->MessagePriority() )
       
  4585         {
       
  4586         case KMmsPriorityNormal:
       
  4587             entry.SetPriority( EMsvMediumPriority );
       
  4588             break;
       
  4589         case KMmsPriorityLow:
       
  4590             entry.SetPriority( EMsvLowPriority );
       
  4591             break;
       
  4592         case KMmsPriorityHigh:
       
  4593             entry.SetPriority( EMsvHighPriority );
       
  4594             break;
       
  4595         default:            
       
  4596             // if not defined default is normal
       
  4597             entry.SetPriority( EMsvMediumPriority );
       
  4598             break;
       
  4599         }
       
  4600         
       
  4601     // set the bio type to audio message if the message contains nothing but one
       
  4602     // amr part in addition to possible one smil
       
  4603     
       
  4604     if ( iSmilCount <= 1 && iAudioCount == 1 &&
       
  4605        ( iAttaNumber == iSmilCount + iAudioCount ) )
       
  4606         {
       
  4607          if(!CheckDRMContent())
       
  4608              {
       
  4609                 TBool audioSupported = EFalse;
       
  4610                 TRAP_IGNORE(
       
  4611                     {
       
  4612                     FeatureManager::InitializeLibL();
       
  4613                     audioSupported = FeatureManager::FeatureSupported( KFeatureIdAudioMessaging );
       
  4614                     FeatureManager::UnInitializeLib();
       
  4615                     });
       
  4616                 
       
  4617                 if ( audioSupported )
       
  4618                     {
       
  4619                     entry.iBioType = KUidMsgSubTypeMmsAudioMsg.iUid;
       
  4620                     }
       
  4621              }
       
  4622         }
       
  4623 
       
  4624     //Since the changes have been committed to the store , we should get exact attachment count from the store. 
       
  4625     //The message type check is not required as the only messagtypes decoded are retrieve-conf in global mode and send-req in local mode
       
  4626     TInt attachmentCount = 0;
       
  4627     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  4628     CleanupStack::PushL( store );
       
  4629 
       
  4630     // Only new attachment structure is supported    
       
  4631     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  4632     attachmentCount = attachMan.AttachmentCount();
       
  4633 
       
  4634     CleanupStack::PopAndDestroy( store );
       
  4635     if ( attachmentCount > 0 )
       
  4636         {
       
  4637         entry.SetAttachment(ETrue);
       
  4638         }
       
  4639        
       
  4640     iEntryWrapper->ChangeIndexEntry( entry );    
       
  4641 
       
  4642     // now that we have saved our index entry, the buffers can go
       
  4643     if ( descriptionBuffer )
       
  4644         {
       
  4645         // if we have allocated a separate buffer for the
       
  4646         // description, it sits on cleanups stack too.
       
  4647         CleanupStack::PopAndDestroy( descriptionBuffer );
       
  4648         }
       
  4649     CleanupStack::PopAndDestroy( buffer );
       
  4650 
       
  4651     }
       
  4652 
       
  4653 // ---------------------------------------------------------
       
  4654 // CMmsDecode::CheckDRMContent
       
  4655 // ---------------------------------------------------------
       
  4656 //
       
  4657 TBool CMmsDecode::CheckDRMContent()
       
  4658     {
       
  4659     CFileProtectionResolver* resolver = CFileProtectionResolver::NewLC( iFs);
       
  4660 
       
  4661     CMsvStore* store = iEntryWrapper->ReadStoreL();
       
  4662     CleanupStack::PushL( store );
       
  4663     MMsvAttachmentManager& attaManager = store->AttachmentManagerL();    
       
  4664     
       
  4665     TInt attaCount = attaManager.AttachmentCount();
       
  4666     TInt flCount = 0;
       
  4667     TInt sdCount = 0;
       
  4668 
       
  4669     for ( TInt i = 0; i < attaCount; i++ )
       
  4670         {
       
  4671         CMsvAttachment* info = attaManager.GetAttachmentInfoL( i );
       
  4672         CleanupStack::PushL( info );
       
  4673         TDataType dataType( info->MimeType() );
       
  4674         if(dataType.Des8().Match(KmmsSmilMimeType) != KErrNotFound)
       
  4675             {
       
  4676             CleanupStack::PopAndDestroy( info );
       
  4677             continue;
       
  4678             }
       
  4679         RFile file = attaManager.GetAttachmentFileL( info->Id() );
       
  4680         CleanupClosePushL( file );
       
  4681         
       
  4682         TInt status = resolver->ProtectionStatusL( file, dataType );
       
  4683         if ( status & EFileProtForwardLocked ||
       
  4684              status & EFileProtClosedContent )
       
  4685             {
       
  4686             flCount++;
       
  4687             }
       
  4688         else if ( status & EFileProtSuperDistributable )
       
  4689             {
       
  4690             sdCount++;
       
  4691             }
       
  4692 
       
  4693         CleanupStack::PopAndDestroy( 2, info ); // file, info
       
  4694         }
       
  4695 
       
  4696     CleanupStack::PopAndDestroy( 2, resolver ); //store, resolver
       
  4697 #ifndef _NO_MMSS_LOGGING_
       
  4698     TMmsLogger::Log( _L("- CheckDRMContent:Total count :%d,FlCount: %d"),attaCount, flCount );
       
  4699     TMmsLogger::Log( _L("- CheckDRMContent:SDCount: %d"), sdCount );
       
  4700 #endif
       
  4701     if(flCount ||sdCount )
       
  4702     return ETrue;
       
  4703     else
       
  4704     return EFalse;
       
  4705     }
       
  4706  
       
  4707 // ---------------------------------------------------------
       
  4708 //
       
  4709 // ---------------------------------------------------------
       
  4710 void CMmsDecode::DumpL()
       
  4711     {
       
  4712     // no dump if not logging
       
  4713 #ifndef _NO_MMSS_LOGGING_
       
  4714     TInt error = KErrNone;
       
  4715     RFile file;
       
  4716     TUint att;
       
  4717     _LIT( KRelated, "Rec.mms");
       
  4718     // if no can do, sorry.
       
  4719     TRAP( error,
       
  4720         {
       
  4721         if ( ( iDumpIncoming ) && iDecodeBuffer )
       
  4722             {
       
  4723             if ( iDecodeBuffer->Size() > 0 && iDecodingStage == EMmsNotApplicable )
       
  4724                 {
       
  4725                 // non-chunked mode. All data is in buffer, and can be dumped in one go
       
  4726                 iFileName = KMmsDefaultLogDirectory;
       
  4727                 // Check if directory exists - no directory, no dump
       
  4728                 User::LeaveIfError( iFs.Att( iFileName, att ) );
       
  4729                 iParse.Set( iFileName, &KRelated, NULL );
       
  4730                 iFileName = iParse.FullName();
       
  4731                 User::LeaveIfError( CApaApplication::GenerateFileName(
       
  4732                     iFs, iFileName ) );
       
  4733                 User::LeaveIfError( file.Create( iFs, iFileName,
       
  4734                     EFileWrite | EFileShareExclusive ) );
       
  4735                 // for message id generation
       
  4736                 iParse.Set( iFileName, NULL, NULL );
       
  4737 
       
  4738                 // the data is supposed to be in the encode buffer
       
  4739                 TPtr8 ptr = iDecodeBuffer->Ptr( 0 );
       
  4740                 file.Write( ptr );
       
  4741                 file.Flush();
       
  4742 
       
  4743                 // done - close files
       
  4744                 file.Close();
       
  4745                 }
       
  4746             // chunked mode start - no data yet, initialize file
       
  4747             else if ( iLength == 0 && iDecodingStage == EMmsHeaders )
       
  4748                 {
       
  4749                 // This is the initialization of the dump file
       
  4750                 iFileName = KMmsDefaultLogDirectory;
       
  4751                 // create an empty file
       
  4752                 // The name of the file will remain in iFilename
       
  4753                 // Later data will be appended to the same file
       
  4754                 User::LeaveIfError( iFs.Att( iFileName, att ) );
       
  4755                 iParse.Set( iFileName, &KRelated, NULL );
       
  4756                 iFileName = iParse.FullName();
       
  4757                 User::LeaveIfError( CApaApplication::GenerateFileName(
       
  4758                     iFs, iFileName ) );
       
  4759                 User::LeaveIfError( file.Create( iFs, iFileName,
       
  4760                     EFileWrite | EFileShareExclusive ) );
       
  4761                 // for message id generation
       
  4762                 iParse.Set( iFileName, NULL, NULL );
       
  4763                 file.Close();
       
  4764                 }
       
  4765             else if ( iDecodingStage != EMmsNotApplicable )
       
  4766                 {
       
  4767                 User::LeaveIfError( file.Open( iFs, iFileName,
       
  4768                     EFileWrite | EFileShareExclusive ) );
       
  4769                 TInt position = 0;    
       
  4770                 User::LeaveIfError( file.Seek( ESeekEnd, position ) );
       
  4771                 // the data is supposed to be in the encode buffer
       
  4772                 // But only write the amount of data that has been processed.
       
  4773                 // Some of the data may be pushed back to the beginning of the buffer
       
  4774                 // and we do not want to write such data twice.
       
  4775                 // iOldData tells how much data was left over from previous round
       
  4776                 // We always write as much as we have got so that we can analyze
       
  4777                 // a possible error
       
  4778                 TPtr8 ptr = iDecodeBuffer->Ptr( iOldData );
       
  4779                 // If there is any data, write it    
       
  4780                 if ( ptr.Length() > 0 )
       
  4781                     {
       
  4782                     file.Write( ptr );
       
  4783                     file.Flush();
       
  4784                     }
       
  4785 
       
  4786                 // done - close files
       
  4787                 file.Close();
       
  4788                 }
       
  4789             else
       
  4790                 {
       
  4791                 // do nothing
       
  4792                 }
       
  4793             }
       
  4794         }
       
  4795     );
       
  4796     if ( error != KErrNone )
       
  4797         {
       
  4798         TMmsLogger::Log( _L("- Dump left, error : %d"), error ); 
       
  4799         }
       
  4800 #endif
       
  4801     }
       
  4802     
       
  4803 // ---------------------------------------------------------
       
  4804 //
       
  4805 // ---------------------------------------------------------
       
  4806 void CMmsDecode::DumpSmil( TInt aDataLength )
       
  4807     {
       
  4808     // no dump if not logging
       
  4809 #ifndef _NO_MMSS_LOGGING_
       
  4810 
       
  4811     TBool lowMemory = EFalse;
       
  4812     
       
  4813     TRAP_IGNORE({
       
  4814         lowMemory = iEntryWrapper->DiskSpaceBelowCriticalLevelL( aDataLength );
       
  4815         });
       
  4816         
       
  4817     // Only dump smil part if not decoding in chunks.
       
  4818     // In chunked mode it would be too complicated.
       
  4819     if ( iDumpIncoming && iMimeHeaders->ContentType().CompareF( KMmsApplicationSmil ) == 0
       
  4820         && !lowMemory && iDecodingStage == EMmsNotApplicable)
       
  4821         {
       
  4822         RFile file;
       
  4823         iFileName = KMmsDefaultLogDirectory;
       
  4824         TUint att;
       
  4825         if ( iFs.Att( iFileName, att ) == KErrNone )
       
  4826             {
       
  4827             _LIT( KRelated2, "smil.txt");
       
  4828             iParse.Set( iFileName, &KRelated2, NULL );
       
  4829             iFileName = iParse.FullName();
       
  4830             TInt error = CApaApplication::GenerateFileName( iFs, iFileName );
       
  4831             if ( error == KErrNone )
       
  4832                 {
       
  4833                 error = file.Create( iFs, iFileName, EFileWrite | EFileShareExclusive );
       
  4834                 // for message id generation
       
  4835                 iParse.Set( iFileName, NULL, NULL );
       
  4836 
       
  4837                 if ( error == KErrNone )
       
  4838                     {
       
  4839                     // the data is supposed to be in the encode buffer
       
  4840                     TPtrC8 ptrx;
       
  4841                     ptrx.Set( iDecodeBuffer->Ptr( iPosition ).Ptr(), aDataLength );
       
  4842                     file.Write( ptrx );
       
  4843                     file.Flush();
       
  4844                     }
       
  4845 
       
  4846                 // done - close files
       
  4847                 file.Close();
       
  4848                 }
       
  4849             }
       
  4850         }
       
  4851 #endif
       
  4852     }
       
  4853     
       
  4854 
       
  4855 // ---------------------------------------------------------
       
  4856 //
       
  4857 // ---------------------------------------------------------
       
  4858 void CMmsDecode::LogYesNo( TRefByValue<const TDesC> aTitle, TInt aValue )
       
  4859     {
       
  4860 #ifndef _NO_MMSS_LOGGING_
       
  4861     TMmsLogger::Log( aTitle );
       
  4862     switch ( aValue )
       
  4863         {
       
  4864         case ( KMmsYes ):
       
  4865             TMmsLogger::Log( KLogYes );
       
  4866             break;
       
  4867         case ( KMmsNo ):
       
  4868             TMmsLogger::Log( KLogNo );
       
  4869             break;
       
  4870         default:
       
  4871             TMmsLogger::Log( KLogUnknown, aValue );
       
  4872             break;
       
  4873         }
       
  4874 #endif
       
  4875     }
       
  4876 
       
  4877 // ---------------------------------------------------------
       
  4878 //
       
  4879 // ---------------------------------------------------------
       
  4880 void CMmsDecode::GetKeywordL()
       
  4881     {
       
  4882     GetValueLength(); // must be read just to get it out of way
       
  4883     TUint8 byte;            // for simple reads
       
  4884     byte = GetWellKnownFieldValueOrSkip();
       
  4885     TUint temp;
       
  4886     temp = byte; // should be add, remove or filter
       
  4887     HBufC16* buffer = NULL;
       
  4888     buffer = GetEncodedTextStringL();
       
  4889     CleanupStack::PushL( buffer ); // keyword
       
  4890     TPtrC dummy;
       
  4891     dummy.Set( buffer->Des() );
       
  4892 
       
  4893     iMmsHeaders->MMBoxMessageHeadersL().AppendKeywordItemL( temp, dummy );
       
  4894 #ifndef _NO_MMSS_LOGGING_
       
  4895     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  4896     TMmsLogger::Log( _L("- Keyword: %S"), &dummy );
       
  4897     switch ( temp )
       
  4898         {
       
  4899         case KMmsAddToken:
       
  4900             TMmsLogger::Log( _L("-- Add") );
       
  4901             break;
       
  4902         case KMmsRemoveToken:
       
  4903             TMmsLogger::Log( _L("-- Remove") );
       
  4904             break;
       
  4905         case KMmsFilterToken:
       
  4906             TMmsLogger::Log( _L("-- Filter") );
       
  4907             break;
       
  4908         default:
       
  4909             TMmsLogger::Log( KLogUnknown, temp );
       
  4910             break;
       
  4911         }
       
  4912 #endif
       
  4913     CleanupStack::PopAndDestroy( buffer );
       
  4914     }
       
  4915     
       
  4916 // ---------------------------------------------------------
       
  4917 //
       
  4918 // ---------------------------------------------------------
       
  4919 void CMmsDecode::CompleteSelf( TInt aError )
       
  4920     {
       
  4921     // completed own status to get back to the RunL
       
  4922     iStatus = KRequestPending;
       
  4923     SetActive();
       
  4924     TRequestStatus* status = &iStatus;
       
  4925     User::RequestComplete( status, aError );
       
  4926     }
       
  4927 
       
  4928 // ---------------------------------------------------------
       
  4929 //
       
  4930 // ---------------------------------------------------------
       
  4931 //
       
  4932 TBool CMmsDecode::IsStringSafe( const TDesC8& aString )
       
  4933     {
       
  4934 
       
  4935     // Very simple check to see if string is "safe" ASCII
       
  4936     // Used for headers, which are short strings
       
  4937 
       
  4938     TInt i;
       
  4939     TBool safe = ETrue;
       
  4940     for ( i = 0; i < aString.Length() && safe; i++ )
       
  4941         {
       
  4942         if ( aString[i] < KMmsLowestAscii || aString[i] >= KMmsHighestAscii )
       
  4943             {
       
  4944             safe = EFalse;
       
  4945             }
       
  4946         }
       
  4947     return safe;
       
  4948     }
       
  4949     
       
  4950 // ---------------------------------------------------------
       
  4951 //
       
  4952 // ---------------------------------------------------------
       
  4953 void CMmsDecode::DecodeFromHeaderL()
       
  4954     {
       
  4955     HBufC16* buffer = NULL;
       
  4956     buffer = DecodeFromL();
       
  4957     CleanupStack::PushL( buffer );
       
  4958     iMmsHeaders->SetSenderL( buffer->Des() );
       
  4959 #ifndef _NO_MMSS_LOGGING_
       
  4960     // we cannot log indefinitely long strings.
       
  4961     // We get this long strings only if the message is corrupted.
       
  4962     TPtrC dummy;
       
  4963     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  4964     TMmsLogger::Log( _L("- From: %S"), &dummy );
       
  4965 #endif
       
  4966     CleanupStack::PopAndDestroy( buffer );
       
  4967     }
       
  4968     
       
  4969 // ---------------------------------------------------------
       
  4970 //
       
  4971 // ---------------------------------------------------------
       
  4972 void CMmsDecode::DecodeToL()
       
  4973     {
       
  4974     HBufC16* buffer = NULL;
       
  4975     buffer = DecodeAddressL();
       
  4976     CleanupStack::PushL( buffer );
       
  4977     iMmsHeaders->AddTypedAddresseeL( buffer->Des(), EMmsTo );
       
  4978 #ifndef _NO_MMSS_LOGGING_
       
  4979     // we cannot log indefinitely long strings.
       
  4980     // We get this long strings only if the message is corrupted.
       
  4981     TPtrC dummy;
       
  4982     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  4983     TMmsLogger::Log( _L("- To: %S"), &dummy );
       
  4984 #endif
       
  4985     CleanupStack::PopAndDestroy( buffer );
       
  4986     }
       
  4987 
       
  4988 // ---------------------------------------------------------
       
  4989 //
       
  4990 // ---------------------------------------------------------
       
  4991 void CMmsDecode::DecodeCcL()
       
  4992     {
       
  4993     HBufC16* buffer = NULL;
       
  4994     buffer = DecodeAddressL();
       
  4995     CleanupStack::PushL( buffer );
       
  4996     iMmsHeaders->AddTypedAddresseeL( buffer->Des(), EMmsCc );
       
  4997 #ifndef _NO_MMSS_LOGGING_
       
  4998     // we cannot log indefinitely long strings.
       
  4999     // We get this long strings only if the message is corrupted.
       
  5000     TPtrC dummy;
       
  5001     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5002     TMmsLogger::Log( _L("- Cc: %S"), &dummy );
       
  5003 #endif
       
  5004     CleanupStack::PopAndDestroy( buffer );
       
  5005     }
       
  5006         
       
  5007 // ---------------------------------------------------------
       
  5008 //
       
  5009 // ---------------------------------------------------------
       
  5010 void CMmsDecode::DecodeBccL()
       
  5011     {
       
  5012     HBufC16* buffer = NULL;
       
  5013     buffer = DecodeAddressL();
       
  5014     CleanupStack::PushL( buffer );
       
  5015     iMmsHeaders->AddTypedAddresseeL( buffer->Des(), EMmsBcc );
       
  5016 #ifndef _NO_MMSS_LOGGING_
       
  5017     // we cannot log indefinitely long strings.
       
  5018     // We get this long strings only if the message is corrupted.
       
  5019     TPtrC dummy;
       
  5020     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5021     TMmsLogger::Log( _L("- Bcc: %S"), &dummy );
       
  5022 #endif
       
  5023     CleanupStack::PopAndDestroy( buffer );
       
  5024     }
       
  5025     
       
  5026 // ---------------------------------------------------------
       
  5027 //
       
  5028 // ---------------------------------------------------------
       
  5029 void CMmsDecode::DecodeContentLocationHeaderL()
       
  5030     {
       
  5031     TPtrC8 byteString;
       
  5032     TUint32 size = 0;
       
  5033     // Request headers are handled for testing purposes only
       
  5034     // Only PDUs that we should decode are the confirmation types
       
  5035     if ( iMmsHeaders->MessageType() != KMmsMessageTypeMBoxDeleteConf &&
       
  5036         iMmsHeaders->MessageType() != KMmsMessageTypeDeleteConf )
       
  5037         {
       
  5038         byteString.Set( GetByteString() );
       
  5039         // for the MMBox view type PDUs the content locations go into the array
       
  5040         if ( iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewConf ||
       
  5041              iMmsHeaders->MessageType() == KMmsMessageTypeMboxViewReq ||
       
  5042              iMmsHeaders->MessageType() == KMmsMessageTypeMBoxDeleteReq ||
       
  5043              iMmsHeaders->MessageType() == KMmsMessageTypeDeleteReq )
       
  5044             {
       
  5045             iMmsHeaders->MMBoxMessageHeadersL().ContentLocationList().AppendL(
       
  5046                 byteString );
       
  5047             }
       
  5048         else if ( iMmsHeaders->ContentLocation().Length() == 0 )
       
  5049             {
       
  5050             iMmsHeaders->SetContentLocationL( byteString );
       
  5051             }
       
  5052         else
       
  5053             {
       
  5054             // This is some message type that allows more than one content location
       
  5055             // The only one should be M-Mbox-Delete.req.
       
  5056             if ( iMmsHeaders->MMBoxMessageHeadersL().ContentLocationList().MdcaCount()
       
  5057                  == 0 )
       
  5058                 {
       
  5059                 // nothing in the list, append the old one, too
       
  5060                 iMmsHeaders->MMBoxMessageHeadersL().ContentLocationList().AppendL(
       
  5061                     iMmsHeaders->ContentLocation() );
       
  5062                 }
       
  5063             iMmsHeaders->MMBoxMessageHeadersL().ContentLocationList().AppendL(
       
  5064                 byteString );
       
  5065             }
       
  5066         }
       
  5067     else // KMmsMessageTypeMBoxDeleteConf has different format
       
  5068         {
       
  5069         GetValueLength();
       
  5070         size = GetLongOrShortInteger(); // this is actually index
       
  5071         byteString.Set( GetByteString() );
       
  5072         iMmsHeaders->InsertDeleteContentLocationL( size, byteString );
       
  5073 #ifndef _NO_MMSS_LOGGING_
       
  5074         TMmsLogger::Log( _L("- Content Location index: %d"), size );
       
  5075 #endif
       
  5076         }
       
  5077 #ifndef _NO_MMSS_LOGGING_
       
  5078     HBufC16* buffer = NULL;
       
  5079     buffer = HBufC16::NewLC( byteString.Length() );
       
  5080     buffer->Des().Copy( byteString );
       
  5081     // we cannot log indefinitely long strings.
       
  5082     // We get this long strings only if the message is corrupted.
       
  5083     TPtrC dummy;
       
  5084     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5085     TMmsLogger::Log( _L("- Content Location: %S"), &dummy );
       
  5086     CleanupStack::PopAndDestroy( buffer );
       
  5087 #endif
       
  5088     }
       
  5089     
       
  5090 // ---------------------------------------------------------
       
  5091 //
       
  5092 // ---------------------------------------------------------
       
  5093 void CMmsDecode::DecodeDateHeaderL()
       
  5094     {
       
  5095     TInt64 date;
       
  5096     TUint8 byte;
       
  5097     date = GetVeryLongInteger();
       
  5098     if ( iError == KErrTooBig )
       
  5099         {
       
  5100         // we get here only if we have at least one byte to read
       
  5101         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  5102         iPosition++;
       
  5103         // skip rest of field if too long
       
  5104         iPosition += byte;
       
  5105         }
       
  5106     if ( iPosition >= iLength )
       
  5107         {
       
  5108         iError = KErrCorrupt;
       
  5109         return;
       
  5110         }
       
  5111     iMmsHeaders->SetDate( date );
       
  5112 #ifndef _NO_MMSS_LOGGING_
       
  5113     TMmsLogger::Log( _L("- Date:") );
       
  5114     LogDateL( date );
       
  5115 #endif
       
  5116     }
       
  5117     
       
  5118 // ---------------------------------------------------------
       
  5119 //
       
  5120 // ---------------------------------------------------------
       
  5121 void CMmsDecode::DecodeDeliveryReportHeader()
       
  5122     {
       
  5123     TUint8 byte;
       
  5124     TUint temp;
       
  5125     byte = GetWellKnownFieldValueOrSkip();
       
  5126     temp = byte;
       
  5127     iMmsHeaders->SetDeliveryReport( temp );
       
  5128 #ifndef _NO_MMSS_LOGGING_
       
  5129     LogYesNo( _L("- DeliveryReport:"), temp );
       
  5130 #endif
       
  5131     }
       
  5132     
       
  5133 // ---------------------------------------------------------
       
  5134 //
       
  5135 // ---------------------------------------------------------
       
  5136 void CMmsDecode::DecodeDeliveryTimeL()
       
  5137     {
       
  5138     TUint8 byte;
       
  5139     TInt64 date;
       
  5140     byte = GetRelativeOrAbsoluteTime( date );
       
  5141     if ( byte == KMmsRelativeToken )
       
  5142         {
       
  5143         iMmsHeaders->SetDeliveryTimeInterval( I64LOW( date ) );
       
  5144 #ifndef _NO_MMSS_LOGGING_
       
  5145         TMmsLogger::Log( _L("- Delivery Time, interval %d s"), I64LOW( date ) );
       
  5146 #endif
       
  5147         }
       
  5148     if ( byte == KMmsAbsoluteToken )
       
  5149         {
       
  5150         // keep as universal time, don't convert to local time
       
  5151         iMmsHeaders->SetDeliveryDate( date );
       
  5152 #ifndef _NO_MMSS_LOGGING_
       
  5153         TMmsLogger::Log( _L("- Delivery Time, absolute ") );
       
  5154         LogDateL( date );
       
  5155 #endif
       
  5156         }
       
  5157     // If could not interpret field, don't set anything.
       
  5158     }
       
  5159     
       
  5160 // ---------------------------------------------------------
       
  5161 //
       
  5162 // ---------------------------------------------------------
       
  5163 void CMmsDecode::DecodeExpiryL()
       
  5164     {
       
  5165     TUint8 byte;
       
  5166     TInt64 date;
       
  5167     byte = GetRelativeOrAbsoluteTime( date );
       
  5168     if ( byte == KMmsRelativeToken )
       
  5169         {
       
  5170         iMmsHeaders->SetExpiryInterval( I64LOW( date ) );
       
  5171 #ifndef _NO_MMSS_LOGGING_
       
  5172         TMmsLogger::Log( _L("- Expiry interval: %d s"), I64LOW( date ) );
       
  5173 #endif
       
  5174         }
       
  5175     if ( byte == KMmsAbsoluteToken )
       
  5176         {
       
  5177         // keep as universal time, don't convert to local time
       
  5178         iMmsHeaders->SetExpiryDate( date );
       
  5179 #ifndef _NO_MMSS_LOGGING_
       
  5180         TMmsLogger::Log( _L("- Expiry, absolute:") );
       
  5181         LogDateL( date );
       
  5182 #endif
       
  5183         }
       
  5184     // If could not interpret field, don't set anything.
       
  5185     }
       
  5186     
       
  5187 // ---------------------------------------------------------
       
  5188 //
       
  5189 // ---------------------------------------------------------
       
  5190 void CMmsDecode::DecodeMessageClass()
       
  5191     {
       
  5192     TUint8 byte = 0;
       
  5193     TUint temp;
       
  5194 
       
  5195     iDecodeBuffer->Read(iPosition, &byte, 1);
       
  5196         
       
  5197     if ( byte >= KMms0x80 )
       
  5198         {
       
  5199         iPosition++;
       
  5200         temp = byte;
       
  5201         iMmsHeaders->SetMessageClass( temp );
       
  5202 #ifndef _NO_MMSS_LOGGING_
       
  5203         TMmsLogger::Log( _L("-- MessageCalss encoded as Class-identifier") );
       
  5204 #endif
       
  5205         }
       
  5206     else    
       
  5207         {
       
  5208         TPtrC8 byteString = GetByteString();
       
  5209 #ifndef _NO_MMSS_LOGGING_
       
  5210         TMmsLogger::Log( _L("-- MessageCalss encoded as Token-text") );
       
  5211         // we don't leave because of logging
       
  5212         TInt error = KErrNone;
       
  5213         TRAP( error, 
       
  5214             {
       
  5215             HBufC16* buffer = NULL;
       
  5216             buffer = HBufC16::NewLC( byteString.Length() );
       
  5217             buffer->Des().Copy( byteString );
       
  5218             TPtrC dummy;
       
  5219             // we cannot log indefinitely long strings.
       
  5220             // We get this long strings only if the message is corrupted.
       
  5221             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5222             TMmsLogger::Log( _L("- Message class : %S"), &dummy ); 
       
  5223             CleanupStack::PopAndDestroy( buffer );
       
  5224             });
       
  5225         if ( error != KErrNone )
       
  5226             {
       
  5227             TMmsLogger::Log( _L("- Decode left when logging Message class, error : %d"),
       
  5228                 error );
       
  5229             }
       
  5230 #endif   
       
  5231          temp = KMmsTestIllegalValue;
       
  5232          if ( byteString.CompareF( KMessageClassPersonal ) == 0 )
       
  5233              {
       
  5234              temp = KMmsMessageClassPersonal;
       
  5235              }
       
  5236          else if ( byteString.CompareF( KMessageClassAdvertisement ) == 0 )
       
  5237              {
       
  5238              temp = KMmsMessageClassAdvertisement;
       
  5239              }  
       
  5240          else if ( byteString.CompareF( KMessageClassInformational ) == 0 )
       
  5241              {
       
  5242              temp = KMmsMessageClassInformational;
       
  5243              }
       
  5244          else if ( byteString.CompareF( KMessageClassAuto ) == 0 )
       
  5245              {
       
  5246              temp = KMmsMessageClassAuto;
       
  5247              }
       
  5248              iMmsHeaders->SetMessageClass( temp );
       
  5249          }
       
  5250 #ifndef _NO_MMSS_LOGGING_
       
  5251     TMmsLogger::Log( _L("- Message Class:") );
       
  5252     switch ( temp )
       
  5253         {
       
  5254         case KMmsMessageClassPersonal:
       
  5255             TMmsLogger::Log( _L("-- Personal") );
       
  5256             break;
       
  5257         case KMmsMessageClassAdvertisement:
       
  5258             TMmsLogger::Log( _L("-- Advertisement") );
       
  5259             break;
       
  5260         case KMmsMessageClassInformational:
       
  5261             TMmsLogger::Log( _L("-- Informational") );
       
  5262             break;
       
  5263         case KMmsMessageClassAuto:
       
  5264             TMmsLogger::Log( _L("-- Auto") );
       
  5265             break;
       
  5266         default:
       
  5267             TMmsLogger::Log( KLogUnknown, temp );
       
  5268             break;
       
  5269         }
       
  5270 #endif
       
  5271     }
       
  5272     
       
  5273 // ---------------------------------------------------------
       
  5274 //
       
  5275 // ---------------------------------------------------------
       
  5276 void CMmsDecode::DecodeMessageIdL()
       
  5277     {
       
  5278     TPtrC8 byteString;
       
  5279     byteString.Set( GetByteString() );
       
  5280     iMmsHeaders->SetMessageIdL( byteString );
       
  5281 #ifndef _NO_MMSS_LOGGING_
       
  5282     HBufC16* buffer = NULL;
       
  5283     buffer = HBufC16::NewLC( byteString.Length() );
       
  5284     buffer->Des().Copy( byteString );
       
  5285     // we cannot log indefinitely long strings.
       
  5286     // We get this long strings only if the message is corrupted.
       
  5287     TPtrC dummy;
       
  5288     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5289     TMmsLogger::Log( _L("- Message Id: %S"), &dummy );
       
  5290     CleanupStack::PopAndDestroy( buffer );
       
  5291 #endif
       
  5292     }
       
  5293     
       
  5294 // ---------------------------------------------------------
       
  5295 //
       
  5296 // ---------------------------------------------------------
       
  5297 void CMmsDecode::DecodeMessageType()
       
  5298     {
       
  5299     TUint8 byte;
       
  5300     TUint temp;
       
  5301     byte = GetWellKnownFieldValueOrSkip();
       
  5302     temp = byte;
       
  5303     iMmsHeaders->SetMessageType( temp );
       
  5304 #ifndef _NO_MMSS_LOGGING_
       
  5305     TMmsLogger::Log( _L("- MessageType:") );
       
  5306     switch ( temp )
       
  5307         {
       
  5308         case KMmsMessageTypeMSendReq:
       
  5309             TMmsLogger::Log( _L("-- send-req") );
       
  5310             break;
       
  5311         case KMmsMessageTypeMSendConf:
       
  5312             TMmsLogger::Log( _L("-- send-conf") );
       
  5313             break;
       
  5314         case KMmsMessageTypeMNotificationInd:
       
  5315             TMmsLogger::Log( _L("-- notification-ind") );
       
  5316             break;
       
  5317         case KMmsMessageTypeMNotifyRespInd:
       
  5318             TMmsLogger::Log( _L("-- notifyresp-ind") );
       
  5319             break;
       
  5320         case KMmsMessageTypeMRetrieveConf:
       
  5321             TMmsLogger::Log( _L("-- retrieve-conf") );
       
  5322             break;
       
  5323         case KMmsMessageTypeAcknowledgeInd:
       
  5324             TMmsLogger::Log( _L("-- acknowledge-ind") );
       
  5325             break;
       
  5326         case KMmsMessageTypeDeliveryInd:
       
  5327             TMmsLogger::Log( _L("-- delivery-ind") );
       
  5328             break;
       
  5329         case KMmsMessageTypeReadRecInd:
       
  5330             TMmsLogger::Log( _L("-- read-rec-ind") );
       
  5331             break;
       
  5332         case KMmsMessageTypeReadOrigInd:
       
  5333             TMmsLogger::Log( _L("-- read-orig-ind") );
       
  5334             break;
       
  5335         case KMmsMessageTypeForwardReq:
       
  5336             TMmsLogger::Log( _L("-- forward-req") );
       
  5337             break;
       
  5338         case KMmsMessageTypeForwardConf:
       
  5339             TMmsLogger::Log( _L("-- forward-conf") );
       
  5340             break;
       
  5341         case KMmsMessageTypeMboxStoreReq:
       
  5342             TMmsLogger::Log( _L("-- m-mbox-store-req") );
       
  5343             break;
       
  5344         case KMmsMessageTypeMboxStoreConf:
       
  5345             TMmsLogger::Log( _L("-- m-mbox-store-conf") );
       
  5346             break;
       
  5347         case KMmsMessageTypeMboxViewReq:
       
  5348             TMmsLogger::Log( _L("-- m-mbox-view-req") );
       
  5349             break;
       
  5350         case KMmsMessageTypeMboxViewConf:
       
  5351             TMmsLogger::Log( _L("-- m-mbox-view-conf") );
       
  5352             break;
       
  5353         case KMmsMessageTypeMBoxUploadReq:
       
  5354             TMmsLogger::Log( _L("-- m-mbox-upload-req") );
       
  5355             break;
       
  5356         case KMmsMessageTypeMBoxUploadConf:
       
  5357             TMmsLogger::Log( _L("-- m-mbox-upload-conf") );
       
  5358             break;
       
  5359         case KMmsMessageTypeMBoxDeleteReq:
       
  5360             TMmsLogger::Log( _L("-- m-mbox-delete-req") );
       
  5361             break;
       
  5362         case KMmsMessageTypeMBoxDeleteConf:
       
  5363             TMmsLogger::Log( _L("-- m-mbox-delete-conf") );
       
  5364             break;
       
  5365         case KMmsMessageTypeMBoxDescr:
       
  5366             TMmsLogger::Log( _L("-- m-mbox-descr") );
       
  5367             break;
       
  5368         case KMmsMessageTypeDeleteReq:
       
  5369             TMmsLogger::Log( _L("-- m-delete-req") );
       
  5370             break;
       
  5371         case KMmsMessageTypeDeleteConf:
       
  5372             TMmsLogger::Log( _L("-- m-delete-conf") );
       
  5373             break;
       
  5374         case KMmsMessageTypeCancelReq:
       
  5375             TMmsLogger::Log( _L("-- m-cancel-req") );
       
  5376             break;
       
  5377         case KMmsMessageTypeCancelConf:
       
  5378             TMmsLogger::Log( _L("-- m-cancel-conf") );
       
  5379             break;
       
  5380         default:
       
  5381             TMmsLogger::Log( KLogUnknown, temp );
       
  5382             break;
       
  5383         }
       
  5384 #endif
       
  5385     }
       
  5386     
       
  5387 // ---------------------------------------------------------
       
  5388 //
       
  5389 // ---------------------------------------------------------
       
  5390 void CMmsDecode::DecodeMmsVersion()
       
  5391     {
       
  5392     TUint8 byte;
       
  5393     byte = GetWellKnownFieldValueOrSkip();
       
  5394     byte &= KMms0x7F;
       
  5395     // if version major number is greater than 1,
       
  5396     // we may not be compatible any more.
       
  5397     // We save the version number, and check later
       
  5398     // what we should do about it.
       
  5399     iMmsHeaders->SetMmsVersion( byte );
       
  5400 #ifndef _NO_MMSS_LOGGING_
       
  5401     // log version number always - even when decode logging is off
       
  5402     TUint high = ( byte & KMms0x7F ) >> KMmsHalfByteShift;
       
  5403     TUint low = byte & KMms0x0F;
       
  5404     TMmsLogger::Log( _L("- MMS version: %d.%d"), high, low );
       
  5405 #endif
       
  5406     }
       
  5407     
       
  5408 // ---------------------------------------------------------
       
  5409 //
       
  5410 // ---------------------------------------------------------
       
  5411 void CMmsDecode::DecodeMessageSize()
       
  5412     {
       
  5413     TUint32 size = 0;
       
  5414     size = GetLongOrShortInteger();
       
  5415     iMmsHeaders->SetMessageSize( size );
       
  5416 #ifndef _NO_MMSS_LOGGING_
       
  5417     if ( iError != KErrTooBig )
       
  5418         {
       
  5419         TMmsLogger::Log( _L("- Message Size: %d"), size );
       
  5420         }
       
  5421     else
       
  5422         {
       
  5423         TMmsLogger::Log( _L("- Message Size bigger than maxint") );
       
  5424         }
       
  5425 #endif
       
  5426     }
       
  5427     
       
  5428 // ---------------------------------------------------------
       
  5429 //
       
  5430 // ---------------------------------------------------------
       
  5431 void CMmsDecode::DecodePriority()
       
  5432     {
       
  5433     TUint8 byte;
       
  5434     byte = GetWellKnownFieldValueOrSkip();
       
  5435     TUint temp;
       
  5436     temp = byte;
       
  5437     iMmsHeaders->SetMessagePriority( temp );
       
  5438 #ifndef _NO_MMSS_LOGGING_
       
  5439     TMmsLogger::Log( _L("- Priority:") );
       
  5440     switch ( temp )
       
  5441         {
       
  5442         case KMmsPriorityLow:
       
  5443             TMmsLogger::Log( _L("-- Low") );
       
  5444             break;
       
  5445         case KMmsPriorityNormal:
       
  5446             TMmsLogger::Log( _L("-- Normal") );
       
  5447             break;
       
  5448         case KMmsPriorityHigh:
       
  5449             TMmsLogger::Log( _L("-- High") );
       
  5450             break;
       
  5451         default:
       
  5452             TMmsLogger::Log( KLogUnknown, temp );
       
  5453             break;
       
  5454         }
       
  5455 #endif
       
  5456     }
       
  5457 
       
  5458 // ---------------------------------------------------------
       
  5459 //
       
  5460 // ---------------------------------------------------------
       
  5461 void CMmsDecode::DecodeReadReply()
       
  5462     {
       
  5463     TUint8 byte;
       
  5464     byte = GetWellKnownFieldValueOrSkip();
       
  5465     TUint temp;
       
  5466     temp = byte;
       
  5467     iMmsHeaders->SetReadReply( temp );
       
  5468 #ifndef _NO_MMSS_LOGGING_
       
  5469     LogYesNo( _L("- Read Reply:"), temp );
       
  5470 #endif
       
  5471     }
       
  5472     
       
  5473 // ---------------------------------------------------------
       
  5474 //
       
  5475 // ---------------------------------------------------------
       
  5476 void CMmsDecode::DecodeReportAllowed()
       
  5477     {
       
  5478     TUint8 byte;
       
  5479     byte = GetWellKnownFieldValueOrSkip();
       
  5480     TUint temp;
       
  5481     temp = byte;
       
  5482     iMmsHeaders->SetReportAllowed( temp );
       
  5483 #ifndef _NO_MMSS_LOGGING_
       
  5484     LogYesNo( _L("- Report Allowed:"), temp );
       
  5485 #endif
       
  5486     }
       
  5487     
       
  5488 // ---------------------------------------------------------
       
  5489 //
       
  5490 // ---------------------------------------------------------
       
  5491 #ifndef _NO_MMSS_LOGGING_
       
  5492 void CMmsDecode::DecodeResponseStatusL( TInt aHeader )
       
  5493 #else
       
  5494 void CMmsDecode::DecodeResponseStatusL( TInt /*aHeader*/ )
       
  5495 #endif
       
  5496     {
       
  5497     TUint8 byte;
       
  5498     TUint temp;
       
  5499     if ( iMmsHeaders->MessageType() != KMmsMessageTypeMBoxDeleteConf )
       
  5500         {
       
  5501         byte = GetWellKnownFieldValueOrSkip();
       
  5502         temp = byte;
       
  5503         iMmsHeaders->SetResponseStatus( temp );
       
  5504         }
       
  5505     else  // KMmsMessageTypeMBoxDeleteConf has different format
       
  5506         {
       
  5507         TUint32 size = 0;
       
  5508         GetValueLength();
       
  5509         size = GetLongOrShortInteger(); // this is actually index
       
  5510         byte = GetWellKnownFieldValueOrSkip();
       
  5511         temp = byte;
       
  5512         iMmsHeaders->InsertDeleteStatusL( size, temp );
       
  5513 #ifndef _NO_MMSS_LOGGING_
       
  5514         TMmsLogger::Log( _L("- Response Status Index: %d"), size );
       
  5515 #endif
       
  5516         }
       
  5517 #ifndef _NO_MMSS_LOGGING_
       
  5518     if ( aHeader == KMmsAssignedResponseStatus )
       
  5519         {
       
  5520         TMmsLogger::Log( _L("- Response Status:") );
       
  5521         }
       
  5522     else
       
  5523         {
       
  5524         TMmsLogger::Log( _L("- Retrieve Status:") );
       
  5525         }
       
  5526     switch ( temp )
       
  5527         {
       
  5528         case KMmsStatusOk:
       
  5529             TMmsLogger::Log( _L("-- Ok") );
       
  5530             break;
       
  5531         case KMmsErrorUnspecified:
       
  5532             TMmsLogger::Log( _L("-- ErrUnspecified") );
       
  5533             break;
       
  5534         case KMmsErrorServiceDenied:
       
  5535             TMmsLogger::Log( _L("-- ErrServiceDenied") );
       
  5536             break;
       
  5537         case KMmsErrorMessageFormatCorrupt:
       
  5538             TMmsLogger::Log( _L("-- ErrMessageFormatCorrupt") );
       
  5539             break;
       
  5540         case KMmsErrorSendingAddressUnresolved:
       
  5541             TMmsLogger::Log( _L("-- ErrSendingAddressUnresolved") );
       
  5542             break;
       
  5543         case KMmsErrorMessageNotFound:
       
  5544             TMmsLogger::Log( _L("-- ErrMessageNotFound") );
       
  5545             break;
       
  5546         case KMmsErrorNetworkProblem:
       
  5547             TMmsLogger::Log( _L("-- ErrNetworkProblem") );
       
  5548             break;
       
  5549         case KMmsErrorNoContentAccepted:
       
  5550             TMmsLogger::Log( _L("-- ErrNoContentAccepted") );
       
  5551             break;
       
  5552         case KMmsErrorUnsupportedMessage:
       
  5553             TMmsLogger::Log( _L("-- ErrUnsupportedMessage") );
       
  5554             break;
       
  5555         default:
       
  5556             if ( ( temp & KMmsErrorRangeMask ) == KMmsErrorTransient )
       
  5557                 {
       
  5558                 TMmsLogger::Log( _L("-- Transient error %d"), temp );
       
  5559                 }
       
  5560             else if ( ( temp & KMmsErrorRangeMask ) == KMmsErrorPermanent )
       
  5561                 {
       
  5562                 TMmsLogger::Log( _L("-- Permanent error %d"), temp );
       
  5563                 }
       
  5564             else
       
  5565                 {
       
  5566                 TMmsLogger::Log( KLogUnknown, temp );
       
  5567                 }
       
  5568             break;
       
  5569          }   
       
  5570 #endif
       
  5571     }
       
  5572     
       
  5573 // ---------------------------------------------------------
       
  5574 //
       
  5575 // ---------------------------------------------------------
       
  5576 void CMmsDecode::DecodeResponseTextL( TInt aHeader )
       
  5577     {
       
  5578     // The text may be response status text, retrieve status text
       
  5579     // or status text depending on which PDU we are decoding.
       
  5580     // Only one text string appears in each case, so we reuse the header
       
  5581     HBufC16* buffer = NULL;
       
  5582     if ( iMmsHeaders->MessageType() != KMmsMessageTypeMBoxDeleteConf )
       
  5583         {
       
  5584         // both notes go to the same variable, as both can never be present
       
  5585         buffer = GetEncodedTextStringL();
       
  5586         CleanupStack::PushL( buffer );
       
  5587         iMmsHeaders->SetResponseTextL( buffer->Des() );
       
  5588         }
       
  5589     else // KMmsMessageTypeMBoxDeleteConf has different format
       
  5590         {
       
  5591         GetValueLength();
       
  5592         TUint32 index = 0;
       
  5593         index = GetLongOrShortInteger();
       
  5594         buffer = GetEncodedTextStringL();
       
  5595         CleanupStack::PushL( buffer );
       
  5596         iMmsHeaders->InsertDeleteResponseTextL( index, buffer->Des() );
       
  5597 #ifndef _NO_MMSS_LOGGING_
       
  5598         TMmsLogger::Log( _L("- Response Text Index: %d"), index );
       
  5599 #endif
       
  5600         }
       
  5601 #ifndef _NO_MMSS_LOGGING_
       
  5602     switch ( aHeader )
       
  5603         {
       
  5604         case KMmsAssignedResponseText:
       
  5605             TMmsLogger::Log( _L("- Response text:") );
       
  5606             break;           
       
  5607         case KMmsAssignedRetrieveText:
       
  5608             TMmsLogger::Log( _L("- Retrieve text:") );
       
  5609             break;           
       
  5610         case KMmsAssignedStatusText:
       
  5611             TMmsLogger::Log( _L("- Status text:") );
       
  5612             break;           
       
  5613         }
       
  5614     // we cannot log indefinitely long strings.
       
  5615     // We get this long strings only if the message is corrupted.
       
  5616     TPtrC dummy;
       
  5617     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5618     TMmsLogger::Log( _L("%S"), &dummy );
       
  5619 #endif
       
  5620     CleanupStack::PopAndDestroy( buffer );
       
  5621     }
       
  5622     
       
  5623 // ---------------------------------------------------------
       
  5624 //
       
  5625 // ---------------------------------------------------------
       
  5626 void CMmsDecode::DecodeSenderVisibility()
       
  5627     {
       
  5628     TUint8 byte;
       
  5629     byte = GetWellKnownFieldValueOrSkip();
       
  5630     TUint temp;
       
  5631     temp = byte;
       
  5632     iMmsHeaders->SetSenderVisibility( temp );
       
  5633 #ifndef _NO_MMSS_LOGGING_
       
  5634     TMmsLogger::Log( _L("- Sender Visibility:") );
       
  5635     switch ( temp )
       
  5636         {
       
  5637         case KMmsSenderHide:
       
  5638             TMmsLogger::Log( _L("-- Hide") );
       
  5639             break;
       
  5640         case KMmsSenderShow:
       
  5641             TMmsLogger::Log( _L("-- Show") );
       
  5642             break;
       
  5643         default:
       
  5644             TMmsLogger::Log( KLogUnknown, temp );
       
  5645             break;
       
  5646         }
       
  5647 #endif
       
  5648     }
       
  5649     
       
  5650 // ---------------------------------------------------------
       
  5651 //
       
  5652 // ---------------------------------------------------------
       
  5653 void CMmsDecode::DecodeStatus()
       
  5654     {
       
  5655     TUint8 byte;
       
  5656     byte = GetWellKnownFieldValueOrSkip();
       
  5657     TUint temp;
       
  5658     temp = byte;
       
  5659     iMmsHeaders->SetStatus( temp );
       
  5660 #ifndef _NO_MMSS_LOGGING_
       
  5661     TMmsLogger::Log( _L("- Status:") );
       
  5662     switch ( temp )
       
  5663         {
       
  5664         case KMmsMessageStatusExpired:
       
  5665             TMmsLogger::Log( _L("-- Expired") );
       
  5666             break;
       
  5667         case KMmsMessageStatusRetrieved:
       
  5668             TMmsLogger::Log( _L("-- Retrieved") );
       
  5669             break;
       
  5670         case KMmsMessageStatusRejected:
       
  5671             TMmsLogger::Log( _L("-- Rejected") );
       
  5672             break;
       
  5673         case KMmsMessageStatusDeferred:
       
  5674             TMmsLogger::Log( _L("-- Deferred") );
       
  5675             break;
       
  5676         case KMmsMessageStatusUnrecognized:
       
  5677             TMmsLogger::Log( _L("-- Unrecognized") );
       
  5678             break;
       
  5679         case KMmsMessageStatusIndeterminate:
       
  5680             TMmsLogger::Log( _L("-- Indeterminate") );
       
  5681             break;
       
  5682         case KMmsMessageStatusForwarded:
       
  5683             TMmsLogger::Log( _L("-- Forwarded") );
       
  5684             break;
       
  5685         case KMmsMessageStatusUnreachable:
       
  5686             TMmsLogger::Log( _L("-- Unreachable") );
       
  5687             break;
       
  5688         default:
       
  5689             TMmsLogger::Log( KLogUnknown, temp );
       
  5690             break;
       
  5691         }
       
  5692 #endif
       
  5693     }
       
  5694 
       
  5695 // ---------------------------------------------------------
       
  5696 //
       
  5697 // ---------------------------------------------------------
       
  5698 void CMmsDecode::DecodeSubjectL()
       
  5699     {
       
  5700     HBufC16* buffer = NULL;
       
  5701     buffer = GetEncodedTextStringL();
       
  5702     CleanupStack::PushL( buffer );
       
  5703     // TMsvEntry.iDescription will be updated separately.
       
  5704     iMmsHeaders->SetSubjectL( buffer->Des());
       
  5705 #ifndef _NO_MMSS_LOGGING_
       
  5706     // we cannot log indefinitely long strings.
       
  5707     // We get this long strings only if the message is corrupted.
       
  5708     TPtrC dummy;
       
  5709     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5710     TMmsLogger::Log( _L("- Subject: %S"), &dummy );
       
  5711 #endif
       
  5712     CleanupStack::PopAndDestroy( buffer );
       
  5713     }
       
  5714     
       
  5715 // ---------------------------------------------------------
       
  5716 //
       
  5717 // ---------------------------------------------------------
       
  5718 void CMmsDecode::DecodeTidL()
       
  5719     {
       
  5720     TPtrC8 byteString;
       
  5721     byteString.Set( GetByteString() );
       
  5722     iMmsHeaders->SetTidL( byteString );
       
  5723 #ifndef _NO_MMSS_LOGGING_
       
  5724     HBufC16* buffer = NULL;
       
  5725     buffer = HBufC16::NewLC( byteString.Length() );
       
  5726     buffer->Des().Copy( byteString );
       
  5727     TPtrC dummy;
       
  5728     dummy.Set( buffer->Des() );
       
  5729     // we cannot log indefinitely long strings.
       
  5730     // We get this long strings only if the message is corrupted.
       
  5731     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5732     TMmsLogger::Log( _L("- Transaction Id: %S"), &dummy );
       
  5733     CleanupStack::PopAndDestroy( buffer );
       
  5734 #endif
       
  5735     }
       
  5736     
       
  5737 // ---------------------------------------------------------
       
  5738 //
       
  5739 // ---------------------------------------------------------
       
  5740 void CMmsDecode::DecodeContentTypeL()
       
  5741     {
       
  5742     // Now we must analyze the content type in order to
       
  5743     // handle the body correctly.
       
  5744     // The body may be a multipart, or a single part.
       
  5745     // The subroutine will set the number of Attachments.
       
  5746     // For a monoblock body the number of attachments will be 1.
       
  5747     iMultipartType = GetMultipartContentTypeL();
       
  5748     // save the multipart type in case we must later make decisions
       
  5749     // about the multipart/alternative type
       
  5750     iMmsHeaders->SetMultipartType( iMultipartType );
       
  5751     iLastHeader = ETrue; // Content type is always the last header
       
  5752 #ifndef _NO_MMSS_LOGGING_
       
  5753     TPtrC8 byteString;
       
  5754     HBufC16* buffer = NULL;
       
  5755     TPtrC dummy;
       
  5756     if ( iMultipartType != 0 )
       
  5757         {
       
  5758         if ( iMultipartType <= KNumberContentTypes )
       
  5759             {
       
  5760             byteString.Set( KContentTypeTable[ iMultipartType ] );
       
  5761             }
       
  5762         else if ( iMultipartType == KMmsAssignedApplicationVndWapMultipartReport )
       
  5763             {
       
  5764             byteString.Set( KMmsWapMultipartReport );
       
  5765             }
       
  5766         else
       
  5767             {
       
  5768             byteString.Set( KContentTypeTable[ KNumberContentTypes ] ); 
       
  5769             }
       
  5770         buffer = HBufC16::NewLC( byteString.Length() );
       
  5771         // we cannot log indefinitely long strings.
       
  5772         // We get this long strings only if the message is corrupted.
       
  5773         buffer->Des().Copy( byteString );
       
  5774         // no entries from our table are more than 200 bytes long.
       
  5775         dummy.Set( buffer->Des() );
       
  5776         TMmsLogger::Log( _L("- Content Type: %S"), &dummy );
       
  5777         CleanupStack::PopAndDestroy( buffer );
       
  5778         if ( iMultipartRootType.Length() > 0 )
       
  5779             {
       
  5780             buffer = HBufC16::NewLC( iMultipartRootType.Length() );
       
  5781             buffer->Des().Copy( iMultipartRootType );
       
  5782             // we cannot log indefinitely long strings.
       
  5783             // We get this long strings only if the message is corrupted.
       
  5784             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5785             TMmsLogger::Log( _L("- Root content type: %S"), &dummy );
       
  5786             CleanupStack::PopAndDestroy( buffer );
       
  5787             }
       
  5788         if ( iRootContentId.Length() > 0 )
       
  5789             {
       
  5790             buffer = HBufC16::NewLC( iRootContentId.Length() );
       
  5791             buffer->Des().Copy( iRootContentId );
       
  5792             // we cannot log indefinitely long strings.
       
  5793             // We get this long strings only if the message is corrupted.
       
  5794             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5795             TMmsLogger::Log( _L("- Root content id: %S"), &dummy );
       
  5796             CleanupStack::PopAndDestroy( buffer );
       
  5797             }
       
  5798         }
       
  5799     TMmsLogger::Log( _L("- Number of attachments: %d"), iNumberOfAttachments );
       
  5800 #endif
       
  5801     }
       
  5802     
       
  5803 // ---------------------------------------------------------
       
  5804 //
       
  5805 // ---------------------------------------------------------
       
  5806 void CMmsDecode::DecodeReadStatus()
       
  5807     {
       
  5808     TUint8 byte;
       
  5809     byte = GetWellKnownFieldValueOrSkip();
       
  5810     TUint temp;
       
  5811     temp = byte;
       
  5812     iMmsHeaders->SetReadStatus( temp );
       
  5813 #ifndef _NO_MMSS_LOGGING_
       
  5814     TMmsLogger::Log( _L("- ReadStatus:") );
       
  5815     switch ( temp )
       
  5816         {
       
  5817         case KMmsReadStatusRead:
       
  5818             TMmsLogger::Log( _L("-- Read") );
       
  5819             break;
       
  5820         case KMmsReadStatusDeletedWithoutBeingRead:
       
  5821             TMmsLogger::Log( _L("-- Deleted unread") );
       
  5822             break;
       
  5823         default:
       
  5824             TMmsLogger::Log( KLogUnknown, temp );
       
  5825             break;
       
  5826         }
       
  5827 #endif
       
  5828     }
       
  5829 
       
  5830 // ---------------------------------------------------------
       
  5831 //
       
  5832 // ---------------------------------------------------------
       
  5833 void CMmsDecode::DecodeReplyCharging()
       
  5834     {
       
  5835     TUint8 byte;
       
  5836     byte = GetWellKnownFieldValueOrSkip();
       
  5837     TUint temp;
       
  5838     temp = byte;
       
  5839     iMmsHeaders->SetReplyCharging( temp );
       
  5840 #ifndef _NO_MMSS_LOGGING_
       
  5841     TMmsLogger::Log( _L("- ReplyCharging:") );
       
  5842     switch ( temp )
       
  5843         {
       
  5844         case KMmsReplyChargingRequested:
       
  5845             TMmsLogger::Log( _L("-- Requested") );
       
  5846             break;
       
  5847         case KMmsReplyChargingRequestedTextOnly:
       
  5848             TMmsLogger::Log( _L("-- Requested text only") );
       
  5849             break;
       
  5850         case KMmsReplyChargingAccepted:
       
  5851             TMmsLogger::Log( _L("-- Accepted") );
       
  5852             break;
       
  5853         case KMmsReplyChargingAcceptedTextOnly:
       
  5854             TMmsLogger::Log( _L("-- Accepted text only") );
       
  5855             break;
       
  5856         default:
       
  5857             TMmsLogger::Log( KLogUnknown, temp );
       
  5858             break;
       
  5859         }
       
  5860 #endif
       
  5861     }
       
  5862     
       
  5863 // ---------------------------------------------------------
       
  5864 //
       
  5865 // ---------------------------------------------------------
       
  5866 void CMmsDecode::DecodeReplyChargingDeadlineL()
       
  5867     {
       
  5868     TUint8 byte;
       
  5869     TInt64 date;
       
  5870     byte = GetRelativeOrAbsoluteTime( date );
       
  5871     if ( byte == KMmsRelativeToken )
       
  5872         {
       
  5873         iMmsHeaders->SetReplyChargingInterval( I64LOW( date ) );
       
  5874 #ifndef _NO_MMSS_LOGGING_
       
  5875         TMmsLogger::Log( _L("- Reply charging interval: %d s"), I64LOW( date ) );
       
  5876 #endif
       
  5877         }
       
  5878     if ( byte == KMmsAbsoluteToken )
       
  5879         {
       
  5880         // keep as universal time, don't convert to local time
       
  5881         iMmsHeaders->SetReplyChargingDate( date );
       
  5882 #ifndef _NO_MMSS_LOGGING_
       
  5883         TMmsLogger::Log( _L("- Reply charging date, absolute:") );
       
  5884         LogDateL( date );
       
  5885 #endif
       
  5886         }
       
  5887     }
       
  5888     
       
  5889 // ---------------------------------------------------------
       
  5890 //
       
  5891 // ---------------------------------------------------------
       
  5892 void CMmsDecode::DecodeReplyChargingIdL()
       
  5893     {
       
  5894     TPtrC8 byteString;
       
  5895     byteString.Set( GetByteString() );
       
  5896     iMmsHeaders->SetReplyChargingIdL( byteString );
       
  5897 #ifndef _NO_MMSS_LOGGING_
       
  5898     HBufC16* buffer = NULL;
       
  5899     buffer = HBufC16::NewLC( byteString.Length() );
       
  5900     buffer->Des().Copy( byteString );
       
  5901     // we cannot log indefinitely long strings.
       
  5902     // We get this long strings only if the message is corrupted.
       
  5903     TPtrC dummy;
       
  5904     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5905     TMmsLogger::Log( _L("- Reply Charging Id: %S"), &dummy );
       
  5906     CleanupStack::PopAndDestroy( buffer );
       
  5907 #endif
       
  5908     }
       
  5909     
       
  5910 // ---------------------------------------------------------
       
  5911 //
       
  5912 // ---------------------------------------------------------
       
  5913 void CMmsDecode::DecodeReplyChargingSize()
       
  5914     {
       
  5915     TUint32 size = 0;
       
  5916     size = GetLongOrShortInteger();
       
  5917     iMmsHeaders->SetReplyChargingSize( size );
       
  5918 #ifndef _NO_MMSS_LOGGING_
       
  5919     if ( iError != KErrTooBig )
       
  5920         {
       
  5921         TMmsLogger::Log( _L("- Reply charging Size: %d"), size );
       
  5922         }
       
  5923     else
       
  5924         {
       
  5925         TMmsLogger::Log( _L("- Reply charging Size bigger than: %d"),
       
  5926             TInt64 (0xffffffff) );
       
  5927         }
       
  5928 #endif
       
  5929     }
       
  5930 
       
  5931 // ---------------------------------------------------------
       
  5932 //
       
  5933 // ---------------------------------------------------------
       
  5934 void CMmsDecode::DecodePreviousSenderL()
       
  5935     {
       
  5936     GetValueLength(); // we don't need this
       
  5937     TUint32 size = 0;
       
  5938     size = GetLongOrShortInteger(); // This is actually index
       
  5939     HBufC16* buffer = NULL;
       
  5940     buffer = DecodeAddressL();
       
  5941     CleanupStack::PushL( buffer );
       
  5942     // If message is corrupted, the result may be garbage, but we do our best
       
  5943     iMmsHeaders->InsertPreviouslySentByL( size, buffer->Des() );
       
  5944 #ifndef _NO_MMSS_LOGGING_
       
  5945     // we cannot log indefinitely long strings.
       
  5946     // We get this long strings only if the message is corrupted.
       
  5947     TPtrC dummy;
       
  5948     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  5949     TMmsLogger::Log( _L("- Prevously sent by: %S, order # %d"), &dummy, size );
       
  5950 #endif
       
  5951     CleanupStack::PopAndDestroy( buffer );
       
  5952     }
       
  5953     
       
  5954 // ---------------------------------------------------------
       
  5955 //
       
  5956 // ---------------------------------------------------------
       
  5957 void CMmsDecode::DecodePreviouslySentDateL()
       
  5958     {
       
  5959     GetValueLength(); // we don't need this
       
  5960     TUint32 size = 0;
       
  5961     size = GetLongOrShortInteger();
       
  5962     TInt64 date;
       
  5963     date = GetVeryLongInteger();
       
  5964     TUint8 byte;
       
  5965     if ( iError == KErrTooBig )
       
  5966         {
       
  5967         // we get here only if we have at least one byte to read
       
  5968         iDecodeBuffer->Read(iPosition, &byte, 1);
       
  5969         iPosition++;
       
  5970         // skip rest of field if too long
       
  5971         iPosition += byte;
       
  5972         // If this is too big, we just ignore it. It is no legal date.
       
  5973         date = 0;
       
  5974         iError = KErrNone;
       
  5975         }
       
  5976     // We insert the result no matter what
       
  5977     iMmsHeaders->InsertPreviouslySentDateL( size, date );
       
  5978 #ifndef _NO_MMSS_LOGGING_
       
  5979     TMmsLogger::Log( _L("- Previously sent date: (order # %d)"), size );
       
  5980     LogDateL( date );
       
  5981 #endif
       
  5982     }
       
  5983     
       
  5984 // ---------------------------------------------------------
       
  5985 //
       
  5986 // ---------------------------------------------------------
       
  5987 void CMmsDecode::DecodeStoreHeaderL()
       
  5988     {
       
  5989     TUint8 byte;
       
  5990     byte = GetWellKnownFieldValueOrSkip();
       
  5991     TUint temp;
       
  5992     temp = byte;
       
  5993     iMmsHeaders->MMBoxMessageHeadersL().SetMmsStore( temp );
       
  5994 #ifndef _NO_MMSS_LOGGING_
       
  5995     LogYesNo( _L("- Store to MMBox:"), temp );
       
  5996 #endif
       
  5997     }
       
  5998     
       
  5999 // ---------------------------------------------------------
       
  6000 //
       
  6001 // ---------------------------------------------------------
       
  6002 void CMmsDecode::DecodeMMBoxStateL()
       
  6003     {
       
  6004     TUint8 byte;
       
  6005     byte = GetWellKnownFieldValueOrSkip();
       
  6006     TUint temp;
       
  6007     temp = byte;
       
  6008     if ( iMmsHeaders->MessageType() != KMmsMessageTypeMboxViewReq &&
       
  6009         iMmsHeaders->MessageType() != KMmsMessageTypeMboxViewConf )
       
  6010         {
       
  6011         iMmsHeaders->MMBoxMessageHeadersL().SetMMState( temp );
       
  6012         }
       
  6013     else
       
  6014         {
       
  6015         // For the MMBox view PDU types we must put the states into
       
  6016         // an array as they are used for filtering, and there may be
       
  6017         // more than one state headers
       
  6018         iMmsHeaders->MMBoxViewHeadersL().MMStateArray().InsertInOrder( temp );
       
  6019         }
       
  6020 #ifndef _NO_MMSS_LOGGING_
       
  6021     TMmsLogger::Log( _L("- State in MMBox:") );
       
  6022     switch ( temp )
       
  6023         {
       
  6024         case KMmsDraft:
       
  6025             TMmsLogger::Log( _L("-- Draft") );
       
  6026             break;
       
  6027         case KMmsSent:
       
  6028             TMmsLogger::Log( _L("-- Sent") );
       
  6029             break;
       
  6030         case KMmsNew:
       
  6031             TMmsLogger::Log( _L("-- New") );
       
  6032             break;
       
  6033         case KMmsRetrieved:
       
  6034             TMmsLogger::Log( _L("-- Retrieved") );
       
  6035             break;
       
  6036         case KMmsForwarded:
       
  6037             TMmsLogger::Log( _L("-- Forwarded") );
       
  6038             break;
       
  6039         default:
       
  6040             TMmsLogger::Log( KLogUnknown, temp );
       
  6041             break;
       
  6042         }
       
  6043 #endif
       
  6044     }
       
  6045 
       
  6046 // ---------------------------------------------------------
       
  6047 //
       
  6048 // ---------------------------------------------------------
       
  6049 void CMmsDecode::DecodeMMBoxStoreStatusL()
       
  6050     {
       
  6051     TUint8 byte;
       
  6052     byte = GetWellKnownFieldValueOrSkip();
       
  6053     TUint temp;
       
  6054     temp = byte;
       
  6055     iMmsHeaders->MMBoxMessageHeadersL().SetMmsStoreStatus( temp );
       
  6056 #ifndef _NO_MMSS_LOGGING_
       
  6057     TMmsLogger::Log( _L("- MMBox Store Status:") );
       
  6058     switch ( temp )
       
  6059         {
       
  6060         case KMmsStatusOk:
       
  6061             TMmsLogger::Log( _L("-- Ok") );
       
  6062             break;
       
  6063         default:
       
  6064             if ( ( temp & KMmsErrorRangeMask ) == KMmsErrorTransient )
       
  6065                 {
       
  6066                 TMmsLogger::Log( _L("-- Transient error %d"), temp );
       
  6067                 }
       
  6068             else if ( ( temp & KMmsErrorRangeMask ) == KMmsErrorPermanent )
       
  6069                 {
       
  6070                 TMmsLogger::Log( _L("-- Permanent error %d"), temp );
       
  6071                 }
       
  6072             else
       
  6073                 {
       
  6074                 TMmsLogger::Log( KLogUnknown, temp );
       
  6075                 }
       
  6076             break;
       
  6077         }
       
  6078 #endif
       
  6079     }
       
  6080     
       
  6081 // ---------------------------------------------------------
       
  6082 //
       
  6083 // ---------------------------------------------------------
       
  6084 void CMmsDecode::DecodeMMBoxStoreStatusTextL()
       
  6085     {
       
  6086     HBufC16* buffer = NULL;
       
  6087     buffer = GetEncodedTextStringL();
       
  6088     CleanupStack::PushL( buffer );
       
  6089     iMmsHeaders->MMBoxMessageHeadersL().SetMmsStoreStatusTextL( buffer->Des() );
       
  6090 #ifndef _NO_MMSS_LOGGING_
       
  6091     // we cannot log indefinitely long strings.
       
  6092     // We get this long strings only if the message is corrupted.
       
  6093     TPtrC dummy;
       
  6094     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6095     TMmsLogger::Log( _L("- MMBox Store Status Text: %S"), &dummy );
       
  6096 #endif
       
  6097     CleanupStack::PopAndDestroy( buffer );
       
  6098     }
       
  6099     
       
  6100 // ---------------------------------------------------------
       
  6101 //
       
  6102 // ---------------------------------------------------------
       
  6103 void CMmsDecode::DecodeStoredInMMBoxHeaderL()
       
  6104     {
       
  6105     TUint8 byte;
       
  6106     byte = GetWellKnownFieldValueOrSkip();
       
  6107     TUint temp;
       
  6108     temp = byte;
       
  6109     iMmsHeaders->MMBoxMessageHeadersL().SetMmsStored( temp );
       
  6110 #ifndef _NO_MMSS_LOGGING_
       
  6111     LogYesNo( _L("- Stored to MMBox:"), temp );
       
  6112 #endif
       
  6113     }
       
  6114     
       
  6115 // ---------------------------------------------------------
       
  6116 //
       
  6117 // ---------------------------------------------------------
       
  6118 void CMmsDecode::DecodeAttributesHeaderL()
       
  6119     {
       
  6120     TUint8 byte;
       
  6121     byte = GetWellKnownFieldValueOrSkip();
       
  6122     TUint temp;
       
  6123     temp = byte;
       
  6124     User::LeaveIfError(iMmsHeaders->MMBoxViewHeadersL().AttributeArray().Append( temp ));
       
  6125 #ifndef _NO_MMSS_LOGGING_
       
  6126     TMmsLogger::Log( _L("- MMBox Attribute: %d"), temp );
       
  6127 #endif
       
  6128     }
       
  6129     
       
  6130 // ---------------------------------------------------------
       
  6131 //
       
  6132 // ---------------------------------------------------------
       
  6133 void CMmsDecode::DecodeTotalsL()
       
  6134     {
       
  6135     TUint8 byte;
       
  6136     byte = GetWellKnownFieldValueOrSkip();
       
  6137     TUint temp;
       
  6138     temp = byte;
       
  6139     iMmsHeaders->MMBoxViewHeadersL().SetMmsTotals( temp );
       
  6140 #ifndef _NO_MMSS_LOGGING_
       
  6141     LogYesNo( _L("- MMBox Totals requested:"), temp );
       
  6142 #endif
       
  6143     }
       
  6144     
       
  6145 // ---------------------------------------------------------
       
  6146 //
       
  6147 // ---------------------------------------------------------
       
  6148 void CMmsDecode::DecodeMboxTotalsL()
       
  6149     {
       
  6150     GetValueLength(); // we don't need this
       
  6151     // get message quota or size quota
       
  6152     TUint8 byte;
       
  6153     byte = GetWellKnownFieldValueOrSkip();
       
  6154     // actual value of the quota
       
  6155     // We only get normal integer (not a 64 bit integer) as a 32 bit integer 
       
  6156     // will give quota 4294967295 bytes or messages (which should be plenty)
       
  6157     TUint32 size = 0;
       
  6158     size = GetLongOrShortInteger();
       
  6159     // save message quota
       
  6160     if ( byte == KMmsMessageCountToken )
       
  6161         {
       
  6162         iMmsHeaders->MMBoxViewHeadersL().SetMMBoxTotalNumber( size );
       
  6163 #ifndef _NO_MMSS_LOGGING_
       
  6164         TMmsLogger::Log( _L("- MMBox total: %d messages"), size );
       
  6165 #endif
       
  6166         }
       
  6167     else if ( byte == KMmsMessageSizeToken )
       
  6168         {
       
  6169         iMmsHeaders->MMBoxViewHeadersL().SetMMBoxTotalSize( size );
       
  6170 #ifndef _NO_MMSS_LOGGING_
       
  6171         TMmsLogger::Log( _L("- MMBox total: %d bytes"), size );
       
  6172 #endif
       
  6173         }
       
  6174     // illegal token value is ignored.
       
  6175     else
       
  6176         {
       
  6177 #ifndef _NO_MMSS_LOGGING_
       
  6178         TUint temp;
       
  6179         temp = byte;
       
  6180         TMmsLogger::Log( _L("- MMBox total: illegal token %d"), temp );
       
  6181 #endif
       
  6182         }
       
  6183     }
       
  6184           
       
  6185 // ---------------------------------------------------------
       
  6186 //
       
  6187 // ---------------------------------------------------------
       
  6188 void CMmsDecode::DecodeQuotaHeaderL()
       
  6189     {
       
  6190     TUint8 byte;
       
  6191     byte = GetWellKnownFieldValueOrSkip();
       
  6192     TUint temp;
       
  6193     temp = byte;
       
  6194     iMmsHeaders->MMBoxViewHeadersL().SetMmsQuotas( temp );
       
  6195 #ifndef _NO_MMSS_LOGGING_
       
  6196         LogYesNo( _L("- MMBox Quotas requested:"), temp );
       
  6197 #endif
       
  6198     }
       
  6199     
       
  6200 // ---------------------------------------------------------
       
  6201 //
       
  6202 // ---------------------------------------------------------
       
  6203 void CMmsDecode::DecodeMBoxQuotasL()
       
  6204     {
       
  6205     TUint8 byte;
       
  6206     GetValueLength(); // we don't need this
       
  6207     // get message quota or size quota
       
  6208     byte = GetWellKnownFieldValueOrSkip();
       
  6209     // actual value of the quota
       
  6210     // We only get normal integer (not a 64 bit integer) as a 32 bit integer 
       
  6211     // will give quota 4294967295 bytes or messages (which should be plenty)
       
  6212     TUint32 size = 0;
       
  6213     size = GetLongOrShortInteger();
       
  6214     // save message quota
       
  6215     if ( byte == KMmsMessageCountToken )
       
  6216         {
       
  6217         iMmsHeaders->MMBoxViewHeadersL().SetMMBoxQuotaNumber( size );
       
  6218 #ifndef _NO_MMSS_LOGGING_
       
  6219         TMmsLogger::Log( _L("- MMBox quota: %d messages"), size );
       
  6220 #endif
       
  6221         }
       
  6222     else if ( byte == KMmsMessageSizeToken )
       
  6223         {
       
  6224         iMmsHeaders->MMBoxViewHeadersL().SetMMBoxQuotaSize( size );
       
  6225 #ifndef _NO_MMSS_LOGGING_
       
  6226         TMmsLogger::Log( _L("- MMBox quota: %d bytes"), size );
       
  6227 #endif
       
  6228         }
       
  6229     // illegal token value is ignored.
       
  6230     else
       
  6231         {
       
  6232 #ifndef _NO_MMSS_LOGGING_
       
  6233         TUint temp;
       
  6234         temp = byte;
       
  6235         TMmsLogger::Log( _L("- MMBox quota: illegal token %d"), temp );
       
  6236 #endif
       
  6237         }
       
  6238     }
       
  6239     
       
  6240 // ---------------------------------------------------------
       
  6241 //
       
  6242 // ---------------------------------------------------------
       
  6243 void CMmsDecode::DecodeMessageCountL()
       
  6244     {
       
  6245     TUint32 size = 0;
       
  6246     size = GetLongOrShortInteger();
       
  6247     iMmsHeaders->MMBoxViewHeadersL().SetMmsMessageCount( size );
       
  6248 #ifndef _NO_MMSS_LOGGING_
       
  6249     TMmsLogger::Log( _L("- Message count: %d"), size );
       
  6250 #endif
       
  6251     }
       
  6252     
       
  6253 // ---------------------------------------------------------
       
  6254 //
       
  6255 // ---------------------------------------------------------
       
  6256 void CMmsDecode::DecodeStartInMMBoxViewL()
       
  6257     {
       
  6258     TUint32 size = 0;
       
  6259     size = GetLongOrShortInteger();
       
  6260     iMmsHeaders->MMBoxViewHeadersL().SetMmsStart( size );
       
  6261 #ifndef _NO_MMSS_LOGGING_
       
  6262     TMmsLogger::Log( _L("- Start of messages: %d"), size );
       
  6263 #endif
       
  6264     }
       
  6265 
       
  6266 
       
  6267 // ---------------------------------------------------------
       
  6268 //
       
  6269 // ---------------------------------------------------------
       
  6270 void CMmsDecode::DecodeDistributionIndicator()
       
  6271     {
       
  6272     TUint8 byte;
       
  6273     byte = GetWellKnownFieldValueOrSkip();
       
  6274     TUint temp;
       
  6275     temp = byte;
       
  6276     iMmsHeaders->SetDistributionIndicator( temp );
       
  6277 #ifndef _NO_MMSS_LOGGING_
       
  6278     LogYesNo( _L("- May be distributed further:"), temp );
       
  6279 #endif
       
  6280     }
       
  6281     
       
  6282 // ---------------------------------------------------------
       
  6283 //
       
  6284 // ---------------------------------------------------------
       
  6285 void CMmsDecode::DecodeElementDescriptorL()
       
  6286     {
       
  6287 #ifndef _NO_MMSS_LOGGING_
       
  6288     TPtrC dummy;
       
  6289 #endif
       
  6290     TUint32 size = 0;
       
  6291     // remember where we are
       
  6292     size = GetValueLength();
       
  6293     if ( size > iLength - iPosition )
       
  6294         {
       
  6295         // If the message is corrupted and indicates incorrect length,
       
  6296         // make sure we don't read beyond the buffer
       
  6297         // We don't declare that the message is corrupted because of this.
       
  6298         // We just read what we can, we don't use this header anyway.
       
  6299         // If there is data following a corrupted header, it will be lost.
       
  6300         size = iLength - iPosition;
       
  6301         }
       
  6302     TUint endPosition = iPosition + size;
       
  6303     HBufC16* buffer = NULL;
       
  6304     buffer = GetSimpleTextStringL(); // I hope this is correct.
       
  6305     CleanupStack::PushL( buffer );
       
  6306     iMmsHeaders->ElementDescriptorL().SetContentReferenceL( buffer->Des() );
       
  6307 #ifndef _NO_MMSS_LOGGING_
       
  6308     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6309     TMmsLogger::Log( _L("- Content reference: %S"), &dummy );
       
  6310 #endif
       
  6311     CleanupStack::PopAndDestroy( buffer );
       
  6312     buffer = NULL;
       
  6313     TUint8 byte;
       
  6314     while ( iPosition < endPosition )
       
  6315         {
       
  6316         byte = GetWellKnownFieldValueOrSkip();
       
  6317         if ( byte != KMmsAssignedTopLevelContentType )
       
  6318             {
       
  6319             // Unknown parameter, ignore
       
  6320             SkipFieldValue();
       
  6321             }
       
  6322         else
       
  6323             {
       
  6324             // the value of the parameter is content-type of the top-level message content
       
  6325             TPtrC8 contType = GetContentTypeL();
       
  6326             iMmsHeaders->ElementDescriptorL().SetContentTypeL( contType );
       
  6327 #ifndef _NO_MMSS_LOGGING_
       
  6328             buffer = HBufC16::NewL( contType.Length() );
       
  6329             CleanupStack::PushL( buffer );
       
  6330             buffer->Des().Copy( contType );
       
  6331             dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6332             TMmsLogger::Log( _L("-- Top level content type : %S"), &dummy );
       
  6333             CleanupStack::PopAndDestroy( buffer );
       
  6334             buffer = NULL;
       
  6335 #endif
       
  6336             }
       
  6337         }
       
  6338     iPosition = endPosition;
       
  6339     }
       
  6340     
       
  6341 // ---------------------------------------------------------
       
  6342 //
       
  6343 // ---------------------------------------------------------
       
  6344 void CMmsDecode::DecodeMessageLimitL()
       
  6345     {
       
  6346     TUint32 size = 0;
       
  6347     size = GetLongOrShortInteger();
       
  6348     iMmsHeaders->MMBoxViewHeadersL().SetMmsLimit( size );
       
  6349 #ifndef _NO_MMSS_LOGGING_
       
  6350     TMmsLogger::Log( _L("- Max number of messages to list: %d"), size );
       
  6351 #endif
       
  6352     }
       
  6353    
       
  6354 // ---------------------------------------------------------
       
  6355 //
       
  6356 // ---------------------------------------------------------
       
  6357 void CMmsDecode::DecodeExtNotifTextL()
       
  6358     {
       
  6359     TPtrC8 byteString;
       
  6360     HBufC16* buffer = NULL;
       
  6361     byteString.Set( GetUtf8String() );
       
  6362     // There will be at most one unicode character per one utf-8 character
       
  6363     buffer = HBufC16::NewL( byteString.Length() * KMms2 );
       
  6364     TPtr16 pointer16 = buffer->Des();
       
  6365     CleanupStack::PushL( buffer );
       
  6366     // We convert what we can and forget the rest.
       
  6367     CnvUtfConverter::ConvertToUnicodeFromUtf8( pointer16, byteString );
       
  6368     iMmsHeaders->SetExtendedNotificationL( pointer16 );
       
  6369 #ifndef _NO_MMSS_LOGGING_
       
  6370     // we cannot log indefinitely long strings.
       
  6371     // We get this long strings only if the message is corrupted.
       
  6372     TPtrC dummy;
       
  6373     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6374     TMmsLogger::Log( _L("- Extend. notif. txt: %S"), &dummy );
       
  6375 #endif
       
  6376     CleanupStack::PopAndDestroy( buffer );
       
  6377     }
       
  6378    
       
  6379 // ---------------------------------------------------------
       
  6380 //
       
  6381 // ---------------------------------------------------------
       
  6382 void CMmsDecode::DecodeExtNotifEolL()
       
  6383     {
       
  6384     HBufC16* buffer = NULL;
       
  6385     buffer = GetSimpleTextStringL();
       
  6386     CleanupStack::PushL( buffer );
       
  6387     iMmsHeaders->SetMessageComplete( ( buffer->Des() )[0] );
       
  6388 #ifndef _NO_MMSS_LOGGING_
       
  6389     TUint temp;
       
  6390     temp = ( buffer->Des() )[0];
       
  6391     TMmsLogger::Log( _L("- End of ext. notif: 0x%02X"), temp );
       
  6392 #endif
       
  6393     CleanupStack::PopAndDestroy( buffer );
       
  6394     
       
  6395     }
       
  6396     
       
  6397 // ---------------------------------------------------------
       
  6398 //
       
  6399 // ---------------------------------------------------------
       
  6400 void CMmsDecode::DecodeContentClass()
       
  6401     {
       
  6402     TUint8 byte;            // for simple reads
       
  6403     TUint temp;
       
  6404     byte = GetWellKnownFieldValueOrSkip();
       
  6405     temp = byte;
       
  6406     iMmsHeaders->SetContentClass( temp );
       
  6407 #ifndef _NO_MMSS_LOGGING_
       
  6408     TMmsLogger::Log( _L("- Content Class:") );
       
  6409     switch ( temp )
       
  6410         {
       
  6411         case KMmsContentClassText:
       
  6412             TMmsLogger::Log( _L("-- Text") );
       
  6413             break;
       
  6414         case KMmsContentClassImageBasic:
       
  6415             TMmsLogger::Log( _L("-- Image Basic") );
       
  6416             break;
       
  6417         case KMmsContentClassImageRich:
       
  6418             TMmsLogger::Log( _L("-- Image Rich") );
       
  6419             break;
       
  6420         case KMmsContentClassVideoBasic:
       
  6421             TMmsLogger::Log( _L("-- Video Basic") );
       
  6422             break;
       
  6423         case KMmsContentClassVideoRich:
       
  6424             TMmsLogger::Log( _L("-- Video Rich") );
       
  6425             break;
       
  6426         case KMmsContentClassMegaPixel:
       
  6427             TMmsLogger::Log( _L("-- Megapixel") );
       
  6428             break;
       
  6429         case KMmsContentClassContentBasic:
       
  6430             TMmsLogger::Log( _L("-- Content Basic") );
       
  6431             break;
       
  6432         case KMmsContentClassContentRich:
       
  6433             TMmsLogger::Log( _L("-- Content Rich") );
       
  6434             break;
       
  6435         default:
       
  6436             TMmsLogger::Log( _L("-- Unknown %d"), temp );
       
  6437             break;
       
  6438         }
       
  6439 #endif
       
  6440     }
       
  6441 
       
  6442 // ---------------------------------------------------------
       
  6443 //
       
  6444 // ---------------------------------------------------------
       
  6445 //
       
  6446 void CMmsDecode::DecodeDrmContentHeader()
       
  6447     {
       
  6448     TUint8 byte;            // for simple reads
       
  6449     TUint temp;
       
  6450     byte = GetWellKnownFieldValueOrSkip();
       
  6451     temp = byte;
       
  6452     iMmsHeaders->SetDrmContent( temp );
       
  6453 #ifndef _NO_MMSS_LOGGING_
       
  6454     LogYesNo( _L("- DRM Content:"), temp );
       
  6455 #endif
       
  6456     }
       
  6457     
       
  6458 // ---------------------------------------------------------
       
  6459 //
       
  6460 // ---------------------------------------------------------
       
  6461 //
       
  6462 void CMmsDecode::DecodeAdaptationAllowed()
       
  6463     {
       
  6464     TUint8 byte;            // for simple reads
       
  6465     TUint temp;
       
  6466     byte = GetWellKnownFieldValueOrSkip();
       
  6467     temp = byte;
       
  6468     iMmsHeaders->SetAdaptationAllowed( temp );
       
  6469 #ifndef _NO_MMSS_LOGGING_
       
  6470     LogYesNo( _L("- Adaptation allowed:"), temp );
       
  6471 #endif
       
  6472     }
       
  6473     
       
  6474 // ---------------------------------------------------------
       
  6475 //
       
  6476 // ---------------------------------------------------------
       
  6477 //
       
  6478 void CMmsDecode::DecodeApplicationIdL()
       
  6479     {
       
  6480     HBufC16* buffer = NULL;
       
  6481     buffer = GetSimpleTextStringL();
       
  6482     CleanupStack::PushL( buffer );
       
  6483     iMmsHeaders->SetApplicIdL( buffer->Des() );
       
  6484 #ifndef _NO_MMSS_LOGGING_
       
  6485     TPtrC dummy;
       
  6486     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6487     TMmsLogger::Log( _L("- Application-ID: %S"), &dummy );
       
  6488 #endif
       
  6489     CleanupStack::PopAndDestroy( buffer );
       
  6490     }
       
  6491     
       
  6492 // ---------------------------------------------------------
       
  6493 //
       
  6494 // ---------------------------------------------------------
       
  6495 //
       
  6496 void CMmsDecode::DecodeReplyApplicationIdL()
       
  6497     {
       
  6498     HBufC16* buffer = NULL;
       
  6499     buffer = GetSimpleTextStringL();
       
  6500     CleanupStack::PushL( buffer );
       
  6501     iMmsHeaders->SetReplyApplicIdL( buffer->Des() );
       
  6502 #ifndef _NO_MMSS_LOGGING_
       
  6503     TPtrC dummy;
       
  6504     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6505     TMmsLogger::Log( _L("- Reply-To-Application-ID: %S"), &dummy );
       
  6506 #endif
       
  6507     CleanupStack::PopAndDestroy( buffer );
       
  6508     }
       
  6509 
       
  6510 // ---------------------------------------------------------
       
  6511 //
       
  6512 // ---------------------------------------------------------
       
  6513 //
       
  6514 void CMmsDecode::DecodeApplicationInfoL()
       
  6515     {
       
  6516     TPtrC8 byteString;
       
  6517     byteString.Set( GetByteString() );
       
  6518     iMmsHeaders->SetAuxApplicInfoL( byteString );
       
  6519 #ifndef _NO_MMSS_LOGGING_
       
  6520     TPtrC dummy;
       
  6521     HBufC16* buffer = NULL;
       
  6522     buffer = HBufC16::NewLC( byteString.Length() );
       
  6523     buffer->Des().Copy( byteString );
       
  6524     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6525     TMmsLogger::Log( _L("- Aux-Applic-Info: %S"), &dummy );
       
  6526     CleanupStack::PopAndDestroy( buffer );
       
  6527 #endif
       
  6528     }
       
  6529     
       
  6530 // ---------------------------------------------------------
       
  6531 //
       
  6532 // ---------------------------------------------------------
       
  6533 //
       
  6534 void CMmsDecode::DecodeRecommendedRetrievalMode()
       
  6535     {
       
  6536     TUint8 byte;
       
  6537     TUint temp;
       
  6538     byte = GetWellKnownFieldValueOrSkip();
       
  6539     temp = byte;
       
  6540     iMmsHeaders->SetRecommendedRetrievalMode( temp );
       
  6541 #ifndef _NO_MMSS_LOGGING_
       
  6542     if ( temp == KMmsRecommendedRetrievalModeManual )
       
  6543         {
       
  6544         TMmsLogger::Log( _L("- Recommended retrieval mode: Manual") );
       
  6545         }
       
  6546     else
       
  6547         {
       
  6548         TMmsLogger::Log( _L("- Recommended retrieval mode unknown %d"), temp );
       
  6549         }
       
  6550 #endif
       
  6551     }
       
  6552     
       
  6553 // ---------------------------------------------------------
       
  6554 //
       
  6555 // ---------------------------------------------------------
       
  6556 //
       
  6557 void CMmsDecode::DecodeRecommendedRetrievalModeTextL()
       
  6558     {
       
  6559     HBufC16* buffer = NULL;
       
  6560     buffer = GetEncodedTextStringL();
       
  6561     CleanupStack::PushL( buffer );
       
  6562     iMmsHeaders->SetRecommendedRetrievalModeTextL( buffer->Des() );
       
  6563 #ifndef _NO_MMSS_LOGGING_
       
  6564     // we cannot log indefinitely long strings.
       
  6565     // We get this long strings only if the message is corrupted.
       
  6566     TPtrC dummy;
       
  6567     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6568     TMmsLogger::Log( _L("- Response text: %S"), &dummy );
       
  6569 #endif
       
  6570     CleanupStack::PopAndDestroy( buffer );
       
  6571     }
       
  6572     
       
  6573 // ---------------------------------------------------------
       
  6574 //
       
  6575 // ---------------------------------------------------------
       
  6576 //
       
  6577 void CMmsDecode::DecodeCancelReplaceIdL( TInt aHeader )
       
  6578     {
       
  6579     TPtrC8 byteString;
       
  6580     byteString.Set( GetByteString() );
       
  6581     iMmsHeaders->SetReplaceCancelIdL( byteString );
       
  6582 #ifndef _NO_MMSS_LOGGING_
       
  6583     HBufC16* buffer = NULL;
       
  6584     buffer = HBufC16::NewLC( byteString.Length() );
       
  6585     buffer->Des().Copy( byteString );
       
  6586     // we cannot log indefinitely long strings.
       
  6587     // We get this long strings only if the message is corrupted.
       
  6588     TPtrC dummy;
       
  6589     dummy.Set( buffer->Des().Left( KMmsMaxLogStringLength ) );
       
  6590     if ( aHeader == KMmsAssignedReplaceId )
       
  6591         {
       
  6592         TMmsLogger::Log( _L("- Replace Id: %S"), &dummy );
       
  6593         }
       
  6594     if ( aHeader == KMmsAssignedCancelId )
       
  6595         {
       
  6596         TMmsLogger::Log( _L("- Cancel Id: %S"), &dummy );
       
  6597         }
       
  6598     CleanupStack::PopAndDestroy( buffer );
       
  6599 #endif
       
  6600     }
       
  6601     
       
  6602 // ---------------------------------------------------------
       
  6603 //
       
  6604 // ---------------------------------------------------------
       
  6605 void CMmsDecode::DecodeCancelStatus()
       
  6606     {
       
  6607     TUint8 byte;
       
  6608     byte = GetWellKnownFieldValueOrSkip();
       
  6609     TUint temp;
       
  6610     temp = byte;
       
  6611     iMmsHeaders->SetCancelStatus( temp );
       
  6612 #ifndef _NO_MMSS_LOGGING_
       
  6613     TMmsLogger::Log( _L("- Cancel Status:") );
       
  6614     switch ( temp )
       
  6615         {
       
  6616         case KMmsCancelRequestSuccessfullyReceived:
       
  6617             TMmsLogger::Log( _L("-- successful") );
       
  6618             break;
       
  6619         case KMmsCancelRequestCorrupted:
       
  6620             TMmsLogger::Log( _L("-- corrupted") );
       
  6621             break;
       
  6622         default:
       
  6623             TMmsLogger::Log( KLogUnknown, temp );
       
  6624             break;
       
  6625         }
       
  6626 #endif
       
  6627     }
       
  6628     
       
  6629 #ifndef _NO_MMSS_LOGGING_
       
  6630 // ---------------------------------------------------------
       
  6631 //
       
  6632 // ---------------------------------------------------------
       
  6633 void CMmsDecode::LogDateL( const TInt64& aDate )
       
  6634     {
       
  6635     TBuf<KMmsDateFormatLength> dateString;
       
  6636 
       
  6637     TMmsLogger::Log( _L("%d seconds from 1.1.1970 (UTC)"), aDate );
       
  6638     TTime time = TTime( KMmsYear1970String ) +
       
  6639         TTimeIntervalMicroSeconds( aDate * KMmsMicroToSeconds ); 
       
  6640     time.FormatL(dateString,(_L("%*E%*D%X%*N%Y %1 %2 '%3")));
       
  6641     TMmsLogger::Log( _L("date %S"), &dateString );
       
  6642     time.FormatL(dateString,(_L("%-B%:0%J%:1%T%:2%S%:3%+B")));
       
  6643     TMmsLogger::Log( _L("time %S"), &dateString );
       
  6644     }
       
  6645 #endif
       
  6646 
       
  6647 
       
  6648 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  6649 
       
  6650 //  End of File  
       
  6651