mmsengine/mmshttptransport/src/mmstransaction.cpp
changeset 0 72b543305e3a
child 26 ebe688cedc25
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     1 /*
       
     2 * Copyright (c) 2002-2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 *     Class implementing transaction within WAP session
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #include    <uriutils.h>
       
    23 #include    <httpstringconstants.h>
       
    24 #include    <uaproffilter_interface.h>
       
    25 
       
    26 #include    "mmstransaction.h"
       
    27 #include    "mmsservercommon.h"
       
    28 #include    "mmsconst.h"
       
    29 #include    "mmssession.h"
       
    30 #include    "mmserrors.h"
       
    31 #include    "MmsServerDebugLogging.h"
       
    32 #include    "mmscodecdatasupplier.h"
       
    33 #include    "mmscodecdatasink.h"
       
    34 
       
    35 
       
    36 // EXTERNAL FUNCTION PROTOTYPES  
       
    37 extern void gPanic(TMmsPanic aPanic);
       
    38 
       
    39 // CONSTANTS
       
    40 const TInt KMmsMaxRetryCount = 4;
       
    41 // HTTP error ranges
       
    42 const TInt KMmsHTTP100 = 100; // 1xx informative
       
    43 const TInt KMmsHTTP200 = 200; //
       
    44 const TInt KMmsHTTP300 = 300; //
       
    45 const TInt KMmsHTTP400 = 400; //
       
    46 const TInt KMmsHTTP500 = 500; //
       
    47 const TInt KMmsHTTP404 = 404; // Not Found
       
    48 const TInt KMmsHTTP413 = 413; // Request entity too large
       
    49 
       
    50 const TInt KMmsReserve = 10000; // extra for buffer
       
    51     
       
    52 // MACROS
       
    53 // LOCAL CONSTANTS AND MACROS
       
    54 // MODULE DATA STRUCTURES
       
    55 // LOCAL FUNCTION PROTOTYPES
       
    56 // ==================== LOCAL FUNCTIONS ====================
       
    57 // ================= MEMBER FUNCTIONS =======================
       
    58 
       
    59 // ---------------------------------------------------------
       
    60 // CMmsTransaction
       
    61 // ---------------------------------------------------------
       
    62 //
       
    63 CMmsTransaction::CMmsTransaction()
       
    64     : CMsgActive ( KMmsActiveObjectPriority ),
       
    65     iState ( EMmsIdle ),
       
    66     iUri ( NULL ),
       
    67     iHTTPSession( NULL ),
       
    68     iTimer( NULL ),
       
    69     iTransferControl( NULL ),
       
    70     iTransactionOpened( EFalse )
       
    71     {
       
    72     }
       
    73 
       
    74 // ---------------------------------------------------------
       
    75 // ConstructL
       
    76 // ---------------------------------------------------------
       
    77 //
       
    78 void CMmsTransaction::ConstructL()
       
    79     {
       
    80     iTimer = CMmsOperationTimer::NewL();
       
    81     CActiveScheduler::Add( this );    
       
    82     }
       
    83 
       
    84 // ---------------------------------------------------------
       
    85 // NewL
       
    86 // ---------------------------------------------------------
       
    87 //
       
    88 CMmsTransaction* CMmsTransaction::NewL()
       
    89     {
       
    90     CMmsTransaction* self = new (ELeave) CMmsTransaction();
       
    91     CleanupStack::PushL( self );
       
    92     self->ConstructL();
       
    93     CleanupStack::Pop( self );
       
    94     return self;
       
    95     }
       
    96 
       
    97     
       
    98 // ---------------------------------------------------------
       
    99 // ~CMmsTransaction
       
   100 // ---------------------------------------------------------
       
   101 //
       
   102 CMmsTransaction::~CMmsTransaction()
       
   103     {
       
   104     Cancel();
       
   105     if ( iTransactionOpened )
       
   106         {
       
   107         RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
       
   108         hdr.RemoveAllFields(); // clean up
       
   109         iTransaction.Close();
       
   110         }
       
   111     delete iUri;
       
   112     delete iTimer; 
       
   113     }
       
   114 
       
   115 // ---------------------------------------------------------
       
   116 // ExecuteL
       
   117 // ---------------------------------------------------------
       
   118 //
       
   119 void CMmsTransaction::ExecuteL( 
       
   120     RHTTPSession& aSession,    
       
   121     CMmsBearerStatus& aTransferControl,
       
   122     const TDesC& aUri,
       
   123     const TInt aMethod,
       
   124     CBufFlat& aMessageBuffer,
       
   125     const TInt aTransactionTimer,
       
   126     TInt32 aMaxReceiveSize,
       
   127     TInt32 aExpectedReceiveSize,
       
   128     MMmsCodecDataSupplier& aDataSupplier,
       
   129     MMmsCodecDataSink& aDataSink,
       
   130     TRequestStatus& aStatus )
       
   131     {
       
   132     LOG( _L("CMmsTransaction::ExecuteL") );
       
   133     __ASSERT_DEBUG( iState == EMmsIdle, gPanic( EMmsAlreadyBusy ) );
       
   134     
       
   135     iError = KErrNone;
       
   136   
       
   137     iHTTPSession = &aSession;
       
   138     iDataSupplier = &aDataSupplier;
       
   139     iDataSink = &aDataSink;
       
   140 
       
   141     iMaxReceiveSize = aMaxReceiveSize;
       
   142     if( aMethod == HTTP::EGET )
       
   143         {
       
   144         //
       
   145         // Setting adequate receivebuffer size for receive transactions
       
   146         //
       
   147         TInt32 reserve = KMmsReserve; // fixed reserve for unexpected surplus data
       
   148         if ( aExpectedReceiveSize == KMmsChunkedBufferSize )
       
   149             {
       
   150             // we don't need extra when receiving in chunked mode
       
   151             reserve = 0;
       
   152             }
       
   153         if( ( aExpectedReceiveSize + reserve ) > aMaxReceiveSize )
       
   154             {
       
   155             iExpectedReceiveSize = aMaxReceiveSize;
       
   156             }
       
   157         else
       
   158             {
       
   159             iExpectedReceiveSize = aExpectedReceiveSize + reserve;
       
   160             }
       
   161         }
       
   162     iTransactionOpened = EFalse;
       
   163 
       
   164     delete iUri;
       
   165     iUri = NULL;
       
   166     HBufC* newUri = aUri.AllocL();
       
   167     iUri = newUri;    
       
   168     
       
   169     iBuffer = &aMessageBuffer;
       
   170     iMethod = aMethod;
       
   171     
       
   172     iTransactionTimeout = aTransactionTimer;
       
   173     iTransferControl = &aTransferControl;
       
   174 
       
   175     // clear the flags, because we are reusing the class,
       
   176     // we don't create a new instance every time
       
   177     iRetryCount = 0;
       
   178     iRequestOngoing = EFalse;
       
   179     iSuspendOccurred = EFalse;
       
   180     iGotBodyData = EFalse;
       
   181     iDataChunkNumber = 0; // no data obtained yet
       
   182     iCumulativeSize = 0; // received size or sent size, cumulative
       
   183     iChunkSize = 0;
       
   184     iEvent = THTTPEvent::ESubmit;
       
   185 
       
   186     Queue( aStatus );   // aStatus = iStatus = KRequestPending
       
   187 
       
   188     //
       
   189     // Start transaction timer
       
   190     //
       
   191     if ( iTimer->IsActive() )
       
   192         {
       
   193         iTimer->Cancel();
       
   194         }
       
   195     iTimer->Start( (MMmsTransportObserver*) this, iTransactionTimeout );
       
   196 
       
   197     //
       
   198     // If bearer is already blocked when starting, execution enters a wait
       
   199     //
       
   200     if( iTransferControl->IsSuspended() )
       
   201         {
       
   202         LOG( _L(" - GPRS is Suspended -> waiting for resume before sending") );
       
   203 
       
   204         // Transfer cancellation
       
   205         iTransferControl->SubscribeNotification( (MMmsTransportObserver*) this );
       
   206         // Start needed operations in suspend
       
   207         GprsSuspended();
       
   208 
       
   209         // someone must set our status to KRequestPending
       
   210         iStatus = KRequestPending;
       
   211 
       
   212 #ifndef _NO_MMSS_LOGGING_
       
   213         if ( IsActive() )
       
   214             {
       
   215             LOG( _L(" - already active") );
       
   216             }
       
   217 #endif  //_NO_MMSS_LOGGING_
       
   218         SetActive();
       
   219         }
       
   220     else // Bearer not blocked, continuing directly
       
   221         {
       
   222         iStatus = KRequestPending;
       
   223         SetActive();    
       
   224         TRequestStatus* status = &iStatus;
       
   225         User::RequestComplete( status, KErrNone );
       
   226         }
       
   227     }
       
   228         
       
   229 
       
   230 // ---------------------------------------------------------
       
   231 // RunL
       
   232 // ---------------------------------------------------------
       
   233 //
       
   234 void CMmsTransaction::RunL()
       
   235     {
       
   236     // DoRunL() takes the AO through the states, queuing another
       
   237     // asynch step as required.
       
   238     // if DoRunL() detects the end of the cycle it returns
       
   239     // without queuing another cycle.
       
   240 
       
   241     // If Run() would exit without queuing another cycle it reports
       
   242     // completion to the client.
       
   243     // In CMsgActive this is true if the asynch step or DoRunL fails,
       
   244     // or the state cycle is complete
       
   245     // However, we must keep our cycle going in spite of error(s).
       
   246    
       
   247     // The CMmsOperationTimer reports the exceed situation with error
       
   248     // This must be handled in CMmsTransaction's DoRunL before returning to
       
   249     // client
       
   250 
       
   251     // Also the bearer suspend/resume status is informed via error
       
   252     // Also handled in CMmsTransaction. 
       
   253 
       
   254     // If we have completed ourselves, the error is already in iError.
       
   255     // However, if an asynchronous operation completed us, the error
       
   256     // comes back to us in iStatus.
       
   257     // As we always complete ourselves by returning iError as the
       
   258     // status, we get back either our original iError, or a new
       
   259     // error value set by an asynchronous operation.
       
   260     
       
   261     TInt status = iStatus.Int();
       
   262     
       
   263     if ( iError == KErrNone )
       
   264         {
       
   265         iError = status;
       
   266         }
       
   267 
       
   268     // Only cancel can exit.
       
   269     if ( status != KErrCancel || iError != KErrNone )
       
   270         {
       
   271         // iError contains the possible error from previous step.
       
   272      
       
   273         TRAPD( error, DoRunL() );    // continue operations, may re-queue
       
   274         // must not requeue in error situations
       
   275         // If we want to continue the loop in spite of error (yes, sir),
       
   276         // we must not leave, but return the error in iError.
       
   277         // Symbian code may leave, so we must trap the leaves here,
       
   278         // as we want to keep the loop going unless something
       
   279         // is really fatally wrong (we are completely out of memory,
       
   280         // or the system has crashed)
       
   281         __ASSERT_DEBUG( error == KErrNone || !IsActive(), User::Invariant() );
       
   282         // active means AO has been requeued, just return
       
   283         if ( IsActive() )             
       
   284             {
       
   285             return;
       
   286             }
       
   287 
       
   288         status = error;
       
   289         if ( error == KErrNone )
       
   290             {
       
   291             // If DoRunL did not leave, possible error is in iError
       
   292             status = iError;
       
   293             }
       
   294         }
       
   295     LOG2( _L("CMmsTransaction::RunL: Complete with %d"), status );
       
   296     Complete( status );
       
   297     }
       
   298 
       
   299 // ---------------------------------------------------------
       
   300 // DoRunL
       
   301 // ---------------------------------------------------------
       
   302 //
       
   303 void CMmsTransaction::DoRunL()
       
   304     {
       
   305     //
       
   306     // This routine takes the state machine through the states
       
   307     // until an error is encountered or the cycle completes.
       
   308     //
       
   309     LOG3( _L("CMmsTransaction::DoRunL status %d, iError %d"), iStatus.Int(), iError );
       
   310     // If we got last chunk already, do not cancel, let HTTP complete
       
   311     if ( iError != KErrNone && iError != KMmsErrorBearerSuspended )
       
   312         {
       
   313         if ( iRequestOngoing )
       
   314             {
       
   315             iTransaction.Cancel();
       
   316             iRequestOngoing = EFalse;
       
   317             }
       
   318         // Error code copied to status code
       
   319         iStatus = iError;
       
   320         }
       
   321 
       
   322     // We continue to next state to finish properly
       
   323     SelectNextState();
       
   324     // If appropriate, ChangeState makes us active again
       
   325     ChangeStateL();
       
   326     }
       
   327 
       
   328 // ---------------------------------------------------------
       
   329 // SelectNextState
       
   330 // ---------------------------------------------------------
       
   331 //
       
   332 void CMmsTransaction::SelectNextState()
       
   333     {
       
   334     //
       
   335     // The purpose of the switch statements is to cycle through
       
   336     // states. These states handle certain task(s) and after
       
   337     // completed CMmsTransaction is finished.
       
   338     //
       
   339     switch ( iState )
       
   340         {
       
   341         case EMmsIdle:
       
   342             // start the loop
       
   343             iState = EMmsSendingTransactionRequest;
       
   344             break;
       
   345         case EMmsSendingTransactionRequest:
       
   346             iState = EMmsFinished;            
       
   347             break;
       
   348         case EMmsFinished:
       
   349             // No more states
       
   350             iError = KErrUnknown;           
       
   351             break;
       
   352         default:
       
   353             // Illegal state, we should never get here
       
   354             iError = KErrUnknown;
       
   355             break;
       
   356         }  
       
   357     }
       
   358     
       
   359 // ---------------------------------------------------------
       
   360 // ChangeStateL
       
   361 // ---------------------------------------------------------
       
   362 //
       
   363 void CMmsTransaction::ChangeStateL()
       
   364     {
       
   365     switch ( iState )
       
   366         {
       
   367         case EMmsSendingTransactionRequest:
       
   368             MakeTransactionL();
       
   369             break;
       
   370         
       
   371         case EMmsFinished:
       
   372             FinishL();
       
   373             break;
       
   374  
       
   375         default:
       
   376             // All other states are illegal
       
   377             LOG( _L("CMmsTransaction::ChangeStateL(): ERROR: Illegal state") );
       
   378             iError = KErrUnknown;
       
   379             break;
       
   380         }    
       
   381     }
       
   382 
       
   383 // ---------------------------------------------------------
       
   384 // MakeTransactionL
       
   385 // ---------------------------------------------------------
       
   386 //
       
   387 void CMmsTransaction::MakeTransactionL()
       
   388     {
       
   389     LOG( _L("CMmsTransaction::MakeTransactionL") );
       
   390 
       
   391     // Useragent has been added to session headers:
       
   392     // It should always be present
       
   393     HBufC8* uri = HBufC8::NewL( iUri->Length() );
       
   394     CleanupStack::PushL( uri );
       
   395     uri->Des().Copy( iUri->Des() );
       
   396     TUriParser8 uri2;
       
   397     uri2.Parse( uri->Des() );
       
   398 
       
   399     RStringPool stringPool = iHTTPSession->StringPool();
       
   400 
       
   401     iTransaction = iHTTPSession->OpenTransactionL( uri2,
       
   402         *this,
       
   403         stringPool.StringF( iMethod, RHTTPSession::GetTable() ) );
       
   404 
       
   405     iTransactionOpened = ETrue;
       
   406     CleanupStack::PopAndDestroy( uri );
       
   407 
       
   408     // Set headers. If GET, no content type needed as no content present
       
   409     // common accept headers are set as session headers
       
   410     // these are done only on the first time. In retry cases, they already exist.
       
   411     RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
       
   412 
       
   413     // Adding accept headers has been moved to transaction,
       
   414     // as automatic filters seemed to override session headers
       
   415     // (session headers are not added if transaction headers already exist)
       
   416 
       
   417     // NOTE: Currently Accept header contains the following line on purpose:
       
   418     // "Accept: */*, application/vnd.wap.mms-message, application/vnd.wap.sic"
       
   419     // in order to be compliant with some server vendors.
       
   420 
       
   421     // Accept: "*/*"
       
   422     SetHeaderL( hdr, HTTP::EAccept, KMmsAny );
       
   423     // Accept: "application/vnd.wap.mms-message"
       
   424     SetHeaderL( hdr, HTTP::EAccept, KMmsMessageContentType );
       
   425     // Accept: "application/vnd.wap.sic"
       
   426     SetHeaderL( hdr, HTTP::EAccept, KMmsWapSicContentType );
       
   427 
       
   428     // Accept-Language: en
       
   429     SetHeaderL( hdr, HTTP::EAcceptLanguage, KHTTPEnglish );
       
   430 
       
   431     // Accept-Charset: utf-8
       
   432     SetHeaderL( hdr, HTTP::EAcceptCharset, KHTTPUtf8 );
       
   433     // end of headers moved from session to transaction
       
   434 
       
   435     if( iMethod == HTTP::EPOST )
       
   436         {
       
   437         // Add contenttype header 
       
   438         SetHeaderL( hdr, HTTP::EContentType, KMmsMessageContentType );
       
   439 
       
   440         // Give payload supplier for stack in case of http post
       
   441         iTransaction.Request().SetBody( *this );
       
   442         }
       
   443 
       
   444     // Set the 'Host:' header
       
   445     SetHostHeaderL( hdr );
       
   446 
       
   447     // Set UA headers
       
   448     RStringF uaClient = iHTTPSession->StringPool().OpenFStringL( KUserAgentClientId );
       
   449     CleanupClosePushL<RStringF>( uaClient );
       
   450     iTransaction.PropertySet().SetPropertyL( uaClient, THTTPHdrVal( KUserAgentCliMMS ) );
       
   451     CleanupStack::PopAndDestroy( &uaClient );
       
   452     
       
   453     // no response headers yet
       
   454     iGotResponseHeaders = EFalse; 
       
   455 
       
   456     // Perform the actual sending
       
   457     iTransaction.SubmitL();
       
   458     
       
   459     // Start observer to monitor notifications
       
   460     iTransferControl->SubscribeNotification( (MMmsTransportObserver*) this );
       
   461     
       
   462     iRequestOngoing = ETrue;
       
   463 
       
   464     iStatus = KRequestPending;
       
   465     SetActive();
       
   466     }
       
   467 
       
   468 // ---------------------------------------------------------
       
   469 // FinishL
       
   470 // ---------------------------------------------------------
       
   471 //
       
   472 void CMmsTransaction::FinishL()
       
   473     {
       
   474     LOG( _L("CMmsTransaction::FinishL") );
       
   475 
       
   476     //
       
   477     // Cancel timer and observer
       
   478     //
       
   479     iTransferControl->Cancel();
       
   480 
       
   481     //
       
   482     // Completion came from own timers
       
   483     //
       
   484     if( iStatus == KMmsErrorTimeout || iStatus == KMmsErrorSuspendTimeout )
       
   485         {
       
   486         LOG( _L(" - MmsEngine's timer expired") );
       
   487         if( iRequestOngoing )
       
   488             {
       
   489             iTransaction.Cancel();
       
   490             }
       
   491 
       
   492         if( iGotBodyData && iLastChunk )
       
   493             {
       
   494             LOG( _L(" - Data has been received, returning OK") );
       
   495             iError = KErrNone;
       
   496             }
       
   497         else // no body data, emptying 
       
   498             {
       
   499             iBuffer->Reset();
       
   500             }
       
   501         return;
       
   502         }
       
   503 
       
   504     //
       
   505     // Pause the timer (later it will be put back on, or cancelled)
       
   506     //
       
   507     iTimer->Pause();
       
   508 
       
   509     //
       
   510     // Completion came from HTTP stack
       
   511     // go through switch based on event status
       
   512     //
       
   513     switch ( iEvent.iStatus )
       
   514         {
       
   515         // Successfull case
       
   516         case THTTPEvent::ESucceeded:
       
   517             {
       
   518             iRetryCount = 0;
       
   519             iSuspendOccurred = EFalse;
       
   520             iError = KErrNone; // successful.
       
   521             LOG( _L(" - HTTP status OK") );
       
   522             // If there was response data, we've already got it
       
   523             break;
       
   524             }
       
   525 
       
   526         // Failure cases
       
   527         case THTTPEvent::EFailed:
       
   528             {
       
   529             LOG2( _L(" - HTTP failed with eventcode %d"), iEvent.iStatus );
       
   530 
       
   531             //
       
   532             // Check for suspend cases:
       
   533             // Errors due to GPRS suspend are handled either with immediate retry
       
   534             // or immediatedly after suspend has resumed. Anyway, attempt is not given up.
       
   535             //
       
   536             if( ( iTransferControl->IsSuspended() || iSuspendOccurred ) &&
       
   537                 !iGotResponseHeaders && iRetryCount < KMmsMaxRetryCount )
       
   538                 {
       
   539                 // If we haven't got any response headers yet, no need to reset the
       
   540                 // data sink as it has not been given any data yet
       
   541                 iRetryCount++;
       
   542                 iTransaction.Close();
       
   543                 iTransactionOpened = EFalse; // closed already
       
   544                 iRequestOngoing = EFalse;
       
   545                 iState = EMmsIdle;
       
   546                 iError = KErrNone;
       
   547                 iSuspendOccurred = EFalse;
       
   548                 
       
   549                 if( !iTransferControl->IsSuspended() ) // i.e. iSuspendOccurred
       
   550                     {
       
   551                     LOG( _L(" - Suspend has occurred, but has resumed -> trying again immediatedly!") );
       
   552                     TRequestStatus* status = &iStatus; 
       
   553                     User::RequestComplete( status, KErrNone );
       
   554                     iTimer->Continue();
       
   555                     SetActive();
       
   556                     return;
       
   557                     }
       
   558                 else // GPRS is now suspended
       
   559                     {
       
   560                     LOG( _L(" - GPRS is now Suspended -> waiting for resume before retry.") );
       
   561                     // Subscribe notifications from transferControl watcher
       
   562                     // Also starting timer
       
   563                     iTransferControl->SubscribeNotification( (MMmsTransportObserver*) this );
       
   564                     iTimer->Continue();
       
   565 
       
   566                     // Not completing here.. it will be done by the observer or the timer
       
   567                     iStatus = KRequestPending;
       
   568                     SetActive();
       
   569                     return;
       
   570                     }
       
   571                 }
       
   572 
       
   573             //
       
   574             // For some reason connection to network has been cut off after the first transaction.
       
   575             // The following code tries immediate resend for the transaction if this has been the case.
       
   576             // 
       
   577             if( iStatus == KErrDisconnected     // IF connection has been cut off
       
   578                 && iRetryCount < 1 )            // AND no retries have been tried yet
       
   579                 {
       
   580                 LOG( _L(" - Connection has been disconnected, re-submitting.") );
       
   581 
       
   582                 iRetryCount++;
       
   583                 iState = EMmsSendingTransactionRequest;
       
   584 
       
   585                 iCumulativeSize = 0;
       
   586                 // reset data sink in case we got partial data.
       
   587                 // If the data sink is not in chunked mode, this does nothing
       
   588                 iDataSink->ResetDataSink();
       
   589                 // Just re-submitting the transaction
       
   590                 iTransaction.SubmitL();
       
   591 
       
   592                 iRequestOngoing = ETrue;
       
   593                 iError = KErrNone;
       
   594                 
       
   595                 // Start timer running
       
   596                 iTimer->Continue();
       
   597                 // start bearer observer
       
   598                 iTransferControl->SubscribeNotification( (MMmsTransportObserver*) this );
       
   599 
       
   600                 iStatus = KRequestPending;
       
   601                 SetActive();
       
   602                 return;
       
   603                 }
       
   604                 
       
   605             //
       
   606             // Timer can now be cancelled
       
   607             //
       
   608             iTimer->Cancel();
       
   609 
       
   610             RHTTPResponse resp = iTransaction.Response();
       
   611             LOG2( _L(" - HTTP status code %d "), resp.StatusCode() );
       
   612 
       
   613             TInt error = KErrNone;
       
   614             // crude mapping only based on first number
       
   615             const TInt KMms100 = 100;
       
   616             switch ( ( resp.StatusCode() / KMms100 ) * KMms100 )
       
   617                 {
       
   618                 case KMmsHTTP100: // 1xx Informative
       
   619                     // We map "informative" to KErrNone.
       
   620                     // Further analysis is needed to tell if there was a real error or not
       
   621                     // Decoding of response from MMSC will determine the final error.
       
   622                     error = KErrNone;
       
   623                     break;
       
   624                 case KMmsHTTP200: // 2xx OK
       
   625                     error = KErrNone;
       
   626                     break;
       
   627                 case KMmsHTTP300: // 3xx Multiple choices
       
   628                     error = KMmsErrorHTTPConfiguration;
       
   629                     break;
       
   630                 case KMmsHTTP400: // 4xx Client error
       
   631 	                if( resp.StatusCode() == KMmsHTTP404 )
       
   632                         {
       
   633             	        error = KMmsErrorHTTPNotFound;
       
   634                         }
       
   635                     else if ( resp.StatusCode() == KMmsHTTP413 )
       
   636                         {
       
   637                         error = KMmsErrorEMRUExceeded;
       
   638                         }
       
   639                     else
       
   640                         {
       
   641                         error = KMmsErrorHTTPClientError;
       
   642                         }
       
   643                     break;
       
   644                 case KMmsHTTP500: // 5xx Server error
       
   645                     error = KMmsErrorHTTPServerDown;
       
   646                     break;
       
   647                 default:
       
   648                     error = KErrUnknown;
       
   649                     break;
       
   650                 }
       
   651             
       
   652             // If we get clear HTTP error code, we use it.
       
   653             // Usually iError is KErrUnknown at this point if we have got an error event.
       
   654             if ( error != KErrNone )
       
   655                 {
       
   656                 // If we have some previous error, KErrUnknown does not override
       
   657                 if ( error != KErrUnknown || iError == KErrNone )
       
   658                     {
       
   659                     iError = error;
       
   660                     }
       
   661                 }
       
   662 
       
   663             TBool mmsMessage = EFalse; // check if response data is of correct type
       
   664             if( iGotResponseHeaders )
       
   665                 {
       
   666                 RHTTPHeaders hdr = resp.GetHeaderCollection();
       
   667                 RStringPool stringPool = iHTTPSession->StringPool();
       
   668                 RStringF contentType = stringPool.StringF(
       
   669                     HTTP::EContentType, RHTTPSession::GetTable() );
       
   670                 THTTPHdrVal fieldVal;
       
   671                 if( hdr.GetField( contentType, 0, fieldVal ) == KErrNone )
       
   672                     {
       
   673                     // content type must match with KMmsMessageContentType
       
   674                     RStringF valStr = stringPool.OpenFStringL( KMmsMessageContentType );
       
   675                     CleanupClosePushL( valStr );
       
   676                     if ( valStr == fieldVal.StrF() )
       
   677                         {
       
   678                         mmsMessage = ETrue;
       
   679                         }
       
   680                     CleanupStack::PopAndDestroy( &valStr );
       
   681                     }
       
   682                 }
       
   683 
       
   684             // If we got body data, we clear error in order to make
       
   685             // mms server mtm to decode what we got.
       
   686             // - But only if the content type really was "application/vnd.wap.mms-message"
       
   687             // It is possible that the message is incomplete, but in some cases
       
   688             // HTTP stack is not sure if it got all the data or not, so we must check
       
   689             // if what we got can be decoded without problems.
       
   690             // Because chunked decoding would cause problems otherwise,
       
   691             // We can declare "no error" only if we got the last chunk
       
   692             if( iGotBodyData && mmsMessage && iLastChunk )
       
   693                 {
       
   694                 iError = KErrNone;
       
   695                 }
       
   696             break;
       
   697             }
       
   698 
       
   699         default:
       
   700             LOG( _L("CMmsTransaction::FinishL(): Unknown response") );
       
   701             // Other event = error
       
   702             // - but don't override the error if we already got something.
       
   703             if ( iError == KErrNone )
       
   704                 {
       
   705                 iError = KMmsErrorUnknownRespFromGw;
       
   706                 }
       
   707             break;
       
   708          }
       
   709     
       
   710     iSuspendOccurred = EFalse;
       
   711     iRequestOngoing = EFalse;
       
   712     iStatus = iError;
       
   713     iState = EMmsIdle;
       
   714     }
       
   715 
       
   716 // ---------------------------------------------------------
       
   717 // DoCancel
       
   718 // ---------------------------------------------------------
       
   719 //
       
   720 void CMmsTransaction::DoCancel()
       
   721     {
       
   722     LOG( _L("CMmsTransaction::DoCancel") );
       
   723     if ( iRequestOngoing )
       
   724         {
       
   725         iTransaction.Cancel();
       
   726         iRequestOngoing = EFalse;
       
   727         }
       
   728     iTimer->Cancel();
       
   729     iTransferControl->Cancel();
       
   730     iState = EMmsIdle;
       
   731     
       
   732     // Complete ourselves as no-one else is going to do it
       
   733     TRequestStatus* status = &iStatus;
       
   734     User::RequestComplete( status, KErrCancel );
       
   735 
       
   736     // This completes the caller (session)
       
   737     CMsgActive::DoCancel();
       
   738     }
       
   739 
       
   740 // ---------------------------------------------------------
       
   741 // DoComplete
       
   742 // ---------------------------------------------------------
       
   743 //
       
   744 void CMmsTransaction::DoComplete( TInt& )
       
   745     {
       
   746     // just to be sure that nothing is left active, cancel
       
   747     // all operations that may still be pending.
       
   748     LOG( _L("CMmsTransaction::DoComplete") );
       
   749 
       
   750     iTimer->Cancel();
       
   751     iTransferControl->Cancel();
       
   752 
       
   753     // transaction is automatically cancelled during close
       
   754     if ( iTransactionOpened )
       
   755         {
       
   756         RHTTPHeaders hdr = iTransaction.Request().GetHeaderCollection();
       
   757         hdr.RemoveAllFields(); // clean up
       
   758         iTransaction.Close();
       
   759         iTransactionOpened = EFalse; // closed already
       
   760         }
       
   761     if ( iDataSink )
       
   762         {
       
   763         // release data sink does nothing if there is nothing to release
       
   764         // it is safe to call it.
       
   765         iDataSink->RelaseDataSink();
       
   766         iDataSink = NULL;
       
   767         }
       
   768         
       
   769     // in case we have run out of memory or code leaves for some other
       
   770     // fatal reason, we make sure we are idle for the next loop.
       
   771     iState = EMmsIdle;
       
   772     }
       
   773     
       
   774 // ---------------------------------------------------------
       
   775 // TimerExpired
       
   776 // ---------------------------------------------------------
       
   777 //
       
   778 void CMmsTransaction::TimerExpired()
       
   779     {
       
   780     LOG( _L("CMmsTransaction::TimerExpired") );
       
   781     // No transfer cancellation any more
       
   782     iTransferControl->Cancel();
       
   783 
       
   784     if( !IsActive() )
       
   785         {
       
   786         iStatus = KRequestPending;
       
   787         SetActive();
       
   788         }
       
   789 
       
   790     // Setting the state so that we end up to FinishL() method
       
   791     iState = EMmsSendingTransactionRequest;
       
   792 
       
   793     // We complete with MMS Engine's own Timeout value in order 
       
   794     // to avoid confusion with timeouts coming from lower layers
       
   795     TRequestStatus* status = &iStatus; 
       
   796     User::RequestComplete( status, KMmsErrorTimeout );
       
   797         
       
   798     iRetryCount = 0;
       
   799     }
       
   800 
       
   801 // ---------------------------------------------------------
       
   802 // GprsSuspended
       
   803 // ---------------------------------------------------------
       
   804 //
       
   805 void CMmsTransaction::GprsSuspended()
       
   806     {
       
   807     LOG( _L("CMmsTransaction::GprsSuspended") );
       
   808     }
       
   809     
       
   810 // ---------------------------------------------------------
       
   811 // GprsResumed
       
   812 // ---------------------------------------------------------
       
   813 //
       
   814 void CMmsTransaction::GprsResumed()
       
   815     {
       
   816     //
       
   817     // GPRS context has resumed
       
   818     //
       
   819     LOG( _L("CMmsTransaction::GprsResumed") );
       
   820     if( iRequestOngoing )
       
   821         {
       
   822         // Set flag indicating that gprs was suspended at some stage
       
   823         iSuspendOccurred = ETrue;
       
   824         iTransferControl->SubscribeNotification( (MMmsTransportObserver*) this );
       
   825         }
       
   826     else
       
   827         {
       
   828         // No request ongoing yet, start state machine by completing ourselves
       
   829         iTransferControl->Cancel();
       
   830         TRequestStatus* status = &iStatus; 
       
   831         User::RequestComplete( status, KErrNone );
       
   832         }
       
   833     }
       
   834 
       
   835 // ---------------------------------------------------------
       
   836 // TransferCancelled
       
   837 // ---------------------------------------------------------
       
   838 //
       
   839 void CMmsTransaction::TransferCancelled()
       
   840     {
       
   841     LOG( _L("CMmsTransaction::TransferCancelled") );
       
   842     iTimer->Cancel();
       
   843     
       
   844     // It is possible that this method is called when there is no
       
   845     // transaction going i.e. object is not active.
       
   846     // It means that in that case we have complete ourselves 
       
   847     if( !IsActive() )
       
   848         {
       
   849         iStatus = KRequestPending;
       
   850         SetActive();
       
   851         TRequestStatus* status = &iStatus; 
       
   852         User::RequestComplete( status, KMmsErrorTransferCancelled );
       
   853         }
       
   854     else
       
   855         {
       
   856         // cancel getting events from the stack
       
   857         if ( iRequestOngoing )
       
   858             {
       
   859             iTransaction.Cancel();
       
   860             iRequestOngoing = EFalse;
       
   861             }
       
   862         iError = KMmsErrorTransferCancelled;
       
   863         TRequestStatus* status = &iStatus; 
       
   864         User::RequestComplete( status, KMmsErrorTransferCancelled );
       
   865         }    
       
   866     }
       
   867 
       
   868 // ---------------------------------------------------------
       
   869 // SetHeaderL
       
   870 // ---------------------------------------------------------
       
   871 //
       
   872 void CMmsTransaction::SetHeaderL( RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue )
       
   873     {
       
   874     RStringF valStr = iHTTPSession->StringPool().OpenFStringL( aHdrValue );
       
   875     THTTPHdrVal val( valStr );
       
   876     CleanupClosePushL( valStr );
       
   877     aHeaders.SetFieldL(
       
   878         iHTTPSession->StringPool().StringF( aHdrField, RHTTPSession::GetTable() ), val );
       
   879     CleanupStack::PopAndDestroy( &valStr );
       
   880     }
       
   881 
       
   882 // ---------------------------------------------------------
       
   883 // SetHostHeaderL
       
   884 // ---------------------------------------------------------
       
   885 //
       
   886 void CMmsTransaction::SetHostHeaderL( RHTTPHeaders aHeaders )
       
   887     {
       
   888     LOG( _L("CMmsTransaction::SetHostHeaderL()") );
       
   889     //
       
   890     // Get needed URI parts
       
   891     //
       
   892     TUriC8 uri3 = iTransaction.Request().URI();
       
   893     TPtrC8 hostPtr = uri3.Extract(EUriHost); 
       
   894     TPtrC8 portPtr = uri3.Extract(EUriPort); 
       
   895 
       
   896     // If empty, nothing can be done
       
   897     if( hostPtr.Length() == 0 )
       
   898         {
       
   899         return;
       
   900         }
       
   901 
       
   902     //
       
   903     // If host-type == IPv6 -> include '[' and ']' characters to URI
       
   904     //
       
   905     UriUtils::TUriHostType hosttype = UriUtils::HostType( hostPtr );
       
   906     if( hosttype == UriUtils::EIPv6Host )
       
   907         {
       
   908         LOG( _L(" - host type == IPv6") );
       
   909         const TInt KMmsRoomForBrackets = 2;
       
   910         hostPtr.Set( hostPtr.Ptr()-1, hostPtr.Length() + KMmsRoomForBrackets );
       
   911         }
       
   912 
       
   913     //
       
   914     // If port not equal to 80 -> include it
       
   915     //
       
   916     _LIT8( KMmsPort, "80" );
       
   917     if ( portPtr.Length() > 0 && portPtr.Compare( KMmsPort ) )
       
   918         {
       
   919         hostPtr.Set( hostPtr.Ptr(), hostPtr.Length() + 1 + portPtr.Length() );
       
   920         }
       
   921 
       
   922     //
       
   923     // Remove possible old host-header and set new one
       
   924     //
       
   925     aHeaders.RemoveField( iHTTPSession->StringPool()
       
   926         .StringF( HTTP::EHost, RHTTPSession::GetTable() ) );
       
   927     SetHeaderL( aHeaders, HTTP::EHost, hostPtr );
       
   928     }
       
   929 
       
   930 // ---------------------------------------------------------
       
   931 // MHFRunL
       
   932 // ---------------------------------------------------------
       
   933 //
       
   934 void CMmsTransaction::MHFRunL( RHTTPTransaction aTransaction, const THTTPEvent& aEvent )
       
   935     {
       
   936     TRequestStatus* status = &iStatus;
       
   937     iEvent = aEvent;
       
   938 
       
   939     // Switch through the events
       
   940     switch (aEvent.iStatus)
       
   941         {
       
   942         case THTTPEvent::EGotResponseHeaders:
       
   943             LOG( _L("CMmsTransaction::MHFRunL: Got response headers") );
       
   944             {
       
   945             // Clear buffer but do not compress
       
   946             // We get the data in small chunks, and reallocating all the time
       
   947             // may make us to run out of memory too soon.
       
   948             iBuffer->Delete( 0, iBuffer->Size() );
       
   949             iBuffer->ResizeL( 0 );
       
   950             iGotResponseHeaders = ETrue; // Got response headers, can check content type
       
   951             iDataChunkNumber = 0; // reset in case of retry
       
   952             } 
       
   953             break;
       
   954 
       
   955         case THTTPEvent::EGotResponseBodyData:
       
   956             {
       
   957             LOG( _L("CMmsTransaction::MHFRunL: Got response body data") );
       
   958             // Get the data
       
   959             TPtrC8 bodyData;
       
   960             MHTTPDataSupplier* dataSupplier = aTransaction.Response().Body();
       
   961             iLastChunk = EFalse;
       
   962             iLastChunk = dataSupplier->GetNextDataPart( bodyData );
       
   963             
       
   964             // We must remove CR and LF characters from the beginning of
       
   965             // the first data chunk representing message body because some
       
   966             // network proxies seem to add an extra CR-LF between headers and body.
       
   967             // (A well formed MMS PDU always begins with 0x8C, so that we 
       
   968             // never lose anything from a well formed PDU, and if the PDU
       
   969             // is not well formed, it is a mess anyway.)
       
   970             if ( iDataChunkNumber == 0 )
       
   971                 {
       
   972                 iPosition = 0;
       
   973                 iCumulativeSize = 0; // first data chunk, start counting from here
       
   974                 TInt overallDataSize = dataSupplier->OverallDataSize();
       
   975 #ifndef _NO_MMSS_LOGGING_
       
   976                 if ( iMethod == HTTP::EGET && iMaxReceiveSize != 0)
       
   977                     {
       
   978                     LOG2( _L("- can accept only %d bytes"), iMaxReceiveSize );
       
   979                     }
       
   980                 if ( overallDataSize != KErrNotFound )
       
   981                     {
       
   982                     LOG2( _L("- going to get at least %d bytes"), overallDataSize );
       
   983                     }
       
   984                 else
       
   985                     {
       
   986                     LOG( _L("- chunked transfer encoding used") );
       
   987                     }
       
   988 #endif  //_NO_MMSS_LOGGING_
       
   989                 TInt removedChars = 0;
       
   990                 while ( bodyData.Find( KCr8 ) == 0 || bodyData.Find( KLf8 ) == 0 )
       
   991                     {
       
   992 #ifndef _NO_MMSS_LOGGING_
       
   993                     if ( bodyData.Find( KCr8 ) == 0 )
       
   994                         {
       
   995                         LOG( _L("- removed CR") );
       
   996                         }
       
   997                     else
       
   998                         {
       
   999                         LOG( _L("- removed LF") );
       
  1000                         }
       
  1001 #endif  //_NO_MMSS_LOGGING_
       
  1002                     // remove first character
       
  1003                     bodyData.Set( bodyData.Mid( 1 ) );
       
  1004                     removedChars++;
       
  1005                     }
       
  1006 
       
  1007                 //
       
  1008                 // Check if we are about to receive too much data
       
  1009                 //
       
  1010                 if ( iMethod == HTTP::EGET &&
       
  1011                     iMaxReceiveSize != 0 &&
       
  1012                     overallDataSize != KErrNotFound &&
       
  1013                     overallDataSize - removedChars > iMaxReceiveSize )
       
  1014                     {
       
  1015                     // The overall data size is more than what we want
       
  1016                     iError = KMmsErrorEMRUExceeded;
       
  1017                     }
       
  1018 
       
  1019                 //
       
  1020                 // Size buffer to max message size
       
  1021                 //
       
  1022                 if ( iMethod == HTTP::EGET && iError != KMmsErrorEMRUExceeded )
       
  1023                     {
       
  1024                     LOG2( _L("- reserving %d bytes for receiving."), iExpectedReceiveSize );
       
  1025                     iBuffer->ResizeL( iExpectedReceiveSize );
       
  1026                     iBuffer->ResizeL( 0 );
       
  1027                     }
       
  1028                 } // (iDataChunkNumber == 0) block
       
  1029 
       
  1030             //
       
  1031             // Add the chunk number counter every time body data is received
       
  1032             //
       
  1033             iDataChunkNumber++;
       
  1034 
       
  1035             // When sending MMS, message size is not checked
       
  1036             // When receiving MMS, size is checked against iMaxReceiveSize
       
  1037             // If iMaxReceiveSize == 0 -> no check
       
  1038             // If size > iMaxReceiveSize: "KMmsErrorEMRUExceeded"
       
  1039             iCumulativeSize += bodyData.Length();
       
  1040             if( iMethod == HTTP::EGET && 
       
  1041                 iMaxReceiveSize > 0 && 
       
  1042                 iCumulativeSize > iMaxReceiveSize )
       
  1043                 {
       
  1044                 iError = KMmsErrorEMRUExceeded;
       
  1045                 }
       
  1046 
       
  1047             //
       
  1048             // Check if we are getting too much data (compared to iMaxReceiveSize)
       
  1049             //
       
  1050             if ( iError == KMmsErrorEMRUExceeded )
       
  1051                 {
       
  1052                 // Release data and cancel transaction
       
  1053                 // The following two statements have to be executed in this order
       
  1054                 dataSupplier->ReleaseData();
       
  1055                 aTransaction.Cancel();
       
  1056 
       
  1057                 // we say we did not get anything even if we might have fetched
       
  1058                 // part of the data
       
  1059                 iGotBodyData = EFalse;
       
  1060                 iDataSink->RelaseDataSink();
       
  1061 
       
  1062                 // transaction was cancelled -> not getting any more events:
       
  1063                 User::RequestComplete( status, iError ); 
       
  1064                 }
       
  1065             else // (iError not equal to KMmsErrorEMRUExceeded)
       
  1066                 {
       
  1067                 iBuffer->ResizeL( bodyData.Length() + iPosition );
       
  1068                 TInt currentData = bodyData.Length();
       
  1069                 iBuffer->Write( iPosition, bodyData, currentData );
       
  1070                 // release the databuffer
       
  1071                 dataSupplier->ReleaseData();
       
  1072 #ifndef _NO_MMSS_LOGGING_
       
  1073                 LOG3( _L("- chunk size %d (cumulative %d)"), currentData, iCumulativeSize );
       
  1074                 if ( iLastChunk )
       
  1075                     {
       
  1076                     LOG( _L("- last data chunk received!") );
       
  1077                     }
       
  1078 #endif  //_NO_MMSS_LOGGING_
       
  1079 
       
  1080                 iPosition = 0;
       
  1081 /////                
       
  1082                 iError = iDataSink->NextDataPart( *iBuffer, iPosition, iLastChunk );
       
  1083 ////                
       
  1084                 // if something goes wrong when saving the data, the transaction should be
       
  1085                 // cancelled
       
  1086                 // But if we got last chunk already, let the HTTP complete normally
       
  1087                 if ( iError != KErrNone && !iLastChunk )
       
  1088                     {
       
  1089                     // We can only get an error here if we are in chunked mode
       
  1090                     // cancel transaction
       
  1091                     aTransaction.Cancel();
       
  1092                     iDataSink->RelaseDataSink();
       
  1093 
       
  1094                     // transaction was cancelled -> not getting any more events:
       
  1095                     User::RequestComplete( status, iError );
       
  1096                     return; 
       
  1097                     }
       
  1098                 
       
  1099                 TInt amount = iBuffer->Size() - iPosition;
       
  1100                 if ( iPosition != 0 )
       
  1101                     {
       
  1102                     // some data handled
       
  1103                     iBuffer->Delete( 0, iPosition );
       
  1104                     }
       
  1105                 iBuffer->ResizeL( amount );
       
  1106                 iPosition = amount; // continue writing from here
       
  1107 
       
  1108                 if ( iLastChunk )
       
  1109                     {
       
  1110                     iDataSink->RelaseDataSink();
       
  1111                     }
       
  1112 
       
  1113                 // If we get at least some body data, we continue to decode it even if 
       
  1114                 // it might not be complete.
       
  1115                 // The HTTP session may disconnect too soon, and HTTP stack may report error
       
  1116                 // even if we already got all our body data.
       
  1117                 iGotBodyData = ETrue;
       
  1118                 }
       
  1119             } 
       
  1120             break;
       
  1121         case THTTPEvent::EResponseComplete:
       
  1122             {
       
  1123             LOG( _L("CMmsTransaction::MHFRunL: response complete") );
       
  1124             // never mind, ESucceeded or EFailed will follow
       
  1125             break;
       
  1126             }
       
  1127 
       
  1128         case THTTPEvent::ESucceeded:
       
  1129             {
       
  1130             LOG( _L("CMmsTransaction::MHFRunL: Succeeded") );
       
  1131             LOG2( _L("- Got %d data chunks"), iDataChunkNumber );
       
  1132             User::RequestComplete( status, KErrNone );
       
  1133             break;
       
  1134             }
       
  1135 
       
  1136         case THTTPEvent::EFailed:
       
  1137             {
       
  1138             LOG( _L("CMmsTransaction::MHFRunL: Failed") );
       
  1139             LOG2( _L("- Got %d data chunks"), iDataChunkNumber );
       
  1140             if ( iError == KErrNone )
       
  1141                 {
       
  1142                 iError = KErrUnknown;
       
  1143                 }
       
  1144             User::RequestComplete( status, iError ); 
       
  1145             break;
       
  1146             }
       
  1147 
       
  1148         default:
       
  1149             {
       
  1150             LOG2( _L("CMmsTransaction::MHFRunL: unknown event %d"), aEvent.iStatus );
       
  1151             // save the error, but don't override a possible earlier error
       
  1152             if ( aEvent.iStatus < 0 && iError == KErrNone )
       
  1153                 {
       
  1154                 iError = aEvent.iStatus;
       
  1155                 }
       
  1156             break;
       
  1157             }
       
  1158         }
       
  1159     }
       
  1160 
       
  1161 // ---------------------------------------------------------
       
  1162 // MHFRunError
       
  1163 // ---------------------------------------------------------
       
  1164 //
       
  1165 TInt CMmsTransaction::MHFRunError(
       
  1166     TInt aError,
       
  1167     RHTTPTransaction aTransaction, 
       
  1168     const THTTPEvent& aEvent )
       
  1169     {
       
  1170     LOG2( _L("CMmsTransaction::MHFRunError: %d"), aError );
       
  1171     iEvent = aEvent;
       
  1172     iError = aError;
       
  1173     aTransaction.Close();
       
  1174     iTransactionOpened = EFalse;
       
  1175     iDataSink->RelaseDataSink();
       
  1176     TRequestStatus* status = &iStatus;
       
  1177     User::RequestComplete( status, aEvent.iStatus ); 
       
  1178     return KErrNone;
       
  1179     }
       
  1180 
       
  1181 // ---------------------------------------------------------
       
  1182 // GetNextDataPart
       
  1183 // ---------------------------------------------------------
       
  1184 //
       
  1185 TBool CMmsTransaction::GetNextDataPart( TPtrC8& aDataPart )
       
  1186     {
       
  1187     iLastChunk = EFalse;
       
  1188     iError = iDataSupplier->GetNextDataPart( aDataPart, iLastChunk );
       
  1189     iChunkSize = aDataPart.Size();
       
  1190     LOG2( _L("CMmsTransaction::GetNextDataPart, Chunk size %d"), iChunkSize );
       
  1191 #ifndef _NO_MMSS_LOGGING_
       
  1192     if ( iLastChunk )
       
  1193         {
       
  1194         LOG( _L("CMmsTransaction:: last chunk") );
       
  1195         }
       
  1196 #endif  //_NO_MMSS_LOGGING_
       
  1197     
       
  1198     
       
  1199     if ( iError != KErrNone )
       
  1200         {
       
  1201         // could not get data - cancel the transaction
       
  1202         iTransaction.Cancel();
       
  1203         }
       
  1204 
       
  1205     return iLastChunk;
       
  1206     }
       
  1207 
       
  1208 // ---------------------------------------------------------
       
  1209 // ReleaseData
       
  1210 // ---------------------------------------------------------
       
  1211 //
       
  1212 void CMmsTransaction::ReleaseData()
       
  1213     {
       
  1214     iCumulativeSize += iChunkSize;
       
  1215     iChunkSize = 0;
       
  1216     LOG2( _L("CMmsTransaction::ReleaseData, cumulative %d"), iCumulativeSize );
       
  1217     
       
  1218     TInt error = iDataSupplier->ReleaseData();
       
  1219     if ( iError != KErrNone )
       
  1220         {
       
  1221         iError = error;
       
  1222         }
       
  1223     
       
  1224     if ( iError != KErrNone )
       
  1225         {
       
  1226         // could not get more data - cancel the transaction
       
  1227         iTransaction.Cancel();
       
  1228         }
       
  1229     else if ( !iLastChunk )
       
  1230         {
       
  1231         // If we have sent last chunk already, there is no more body data
       
  1232         // If the function leaves, there is nothing we can do about it.
       
  1233         // ReleaseData() must not leave.
       
  1234         TRAP_IGNORE( iTransaction.NotifyNewRequestBodyPartL() );
       
  1235         }
       
  1236     // else nont needed - no operation    
       
  1237     }
       
  1238 
       
  1239 // ---------------------------------------------------------
       
  1240 // OverallDataSize
       
  1241 // ---------------------------------------------------------
       
  1242 //
       
  1243 TInt CMmsTransaction::OverallDataSize()
       
  1244     {
       
  1245     TInt dataSize = iDataSupplier->OverallDataSize();
       
  1246     LOG2( _L("CMmsTransaction::OverallDataSize %d"), dataSize );
       
  1247     
       
  1248     return dataSize;
       
  1249     }
       
  1250 
       
  1251 // ---------------------------------------------------------
       
  1252 // Reset
       
  1253 // ---------------------------------------------------------
       
  1254 //
       
  1255 TInt CMmsTransaction::Reset()
       
  1256     {
       
  1257     LOG( _L("CMmsTransaction::Reset") );
       
  1258     // We always point to the start of data
       
  1259 //    return KErrNone;
       
  1260     return iDataSupplier->ResetSupplier();
       
  1261 
       
  1262     }
       
  1263 
       
  1264 //  End of File