mmsengine/mmsserver/src/mmsreceivemessage.cpp
changeset 0 72b543305e3a
child 26 ebe688cedc25
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:  
       
    15 *     State machine for message receiving
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #include    <apparc.h>
       
    23 #include    <msventry.h>
       
    24 #include    <msvids.h>
       
    25 #include    <charconv.h>
       
    26 #include    <badesca.h>
       
    27 #include    <cmsvmimeheaders.h>
       
    28 #include    <mmsvattachmentmanager.h>
       
    29 #include    <mmsvattachmentmanagersync.h>
       
    30 
       
    31 #include    <centralrepository.h>
       
    32 
       
    33 // mms private headers
       
    34 #include    "mmsconst.h"
       
    35 #include    "mmsreceivemessage.h"
       
    36 #include    "mmssession.h"
       
    37 #include    "mmssettings.h"
       
    38 #include    "mmsservercommon.h"
       
    39 #include    "mmsheaders.h"
       
    40 #include    "mmsdecode.h"
       
    41 #include    "mmsencode.h"
       
    42 #include    "mmsscheduledentry.h"
       
    43 #include    "mmserrors.h"
       
    44 #include    "mmsserverentry.h"
       
    45 #include    "mmsconninit.h"
       
    46 #include    "MmsEnginePrivateCRKeys.h"
       
    47 #include    "MmsPhoneClient.H"
       
    48 
       
    49 // EXTERNAL DATA STRUCTURES
       
    50 
       
    51 // EXTERNAL FUNCTION PROTOTYPES  
       
    52 extern void gPanic(TMmsPanic aPanic);
       
    53 
       
    54 // CONSTANTS
       
    55 // return codes for handling of messages addressed to an application
       
    56 const TInt KMmsMessageForUnregisteredApplication = 1;
       
    57 const TInt KMmsMessageMovedToApplicationFolder = 2;
       
    58 
       
    59 // MACROS
       
    60 
       
    61 // LOCAL CONSTANTS AND MACROS
       
    62 
       
    63 // MODULE DATA STRUCTURES
       
    64 
       
    65 // LOCAL FUNCTION PROTOTYPES
       
    66 
       
    67 // ==================== LOCAL FUNCTIONS ====================
       
    68 
       
    69 
       
    70 // ================= MEMBER FUNCTIONS =======================
       
    71 
       
    72 // C++ default constructor can NOT contain any code, that
       
    73 // might leave.
       
    74 //
       
    75 CMmsReceiveMessage::CMmsReceiveMessage( RFs& aFs )
       
    76     :CMmsBaseOperation( aFs )
       
    77     {
       
    78     }
       
    79 
       
    80 // Symbian OS default constructor can leave.
       
    81 void CMmsReceiveMessage::ConstructL( CMmsSettings* aMmsSettings )
       
    82     {
       
    83     iFileOpen = EFalse;
       
    84     CMmsBaseOperation::ConstructL( aMmsSettings );
       
    85     iMmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
    86     iNotification = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
    87     iBad = new( ELeave ) CMsvEntrySelection;
       
    88     TRAPD ( error, {iMessageDrive = MessageServer::CurrentDriveL( iFs );});
       
    89     if ( error != KErrNone )
       
    90         {
       
    91         // if cannot ask, use default
       
    92         iMessageDrive = EDriveC;
       
    93         }
       
    94 
       
    95     CActiveScheduler::Add( this );
       
    96     }
       
    97 
       
    98 // Two-phased constructor.
       
    99 CMmsReceiveMessage* CMmsReceiveMessage::NewL( RFs& aFs, CMmsSettings* aMmsSettings )
       
   100     {
       
   101     CMmsReceiveMessage* self = new ( ELeave ) CMmsReceiveMessage( aFs );
       
   102     
       
   103     CleanupStack::PushL( self );
       
   104     self->ConstructL( aMmsSettings );
       
   105     CleanupStack::Pop( self );
       
   106 
       
   107     return self;
       
   108     }
       
   109 
       
   110     
       
   111 // Destructor
       
   112 CMmsReceiveMessage::~CMmsReceiveMessage()
       
   113     {
       
   114     
       
   115     Cancel();
       
   116 
       
   117     delete iMmsHeaders;
       
   118     delete iNotification;
       
   119     delete iBad;
       
   120     // This is the message for local mode testing
       
   121     // It is closed here only to make sure that it is
       
   122     // always closed even if we encounter a serious error.
       
   123     // otherwise it should already be closed by now.
       
   124     if ( iFileOpen )
       
   125         {
       
   126         iFile.Close();
       
   127         }
       
   128     }
       
   129 
       
   130 
       
   131 // ---------------------------------------------------------
       
   132 // CMmsReceiveMessage::StartL
       
   133 //
       
   134 // ---------------------------------------------------------
       
   135 //
       
   136 void CMmsReceiveMessage::StartL(
       
   137     CMsvEntrySelection& aSelection,
       
   138     CMsvServerEntry& aServerEntry,
       
   139     TMsvId aService,
       
   140     TRequestStatus& aStatus )
       
   141     {
       
   142     __ASSERT_DEBUG( iState == EMmsOperationIdle, gPanic( EMmsAlreadyBusy ) );
       
   143 
       
   144 #ifndef _NO_MMSS_LOGGING_
       
   145     TMmsLogger::Log( _L("ReceiveMsg StartL") );
       
   146 #endif
       
   147     // just initialize common member variables
       
   148     CMmsBaseOperation::InitializeL( aSelection, aServerEntry, aService );
       
   149     
       
   150     iReceivingMode = iMmsSettings->ReceivingModeHome();
       
   151 
       
   152     iNotificationParent = KMsvNullIndexEntryId;
       
   153     iBad->Reset();
       
   154     iNotification->Reset();
       
   155     iResponse->Reset(); // This sets the correct version
       
   156     iMmsHeaders->Reset();
       
   157     iEntryUnderConstruction = KMsvNullIndexEntryId;
       
   158     iAlreadyDeferred = EFalse;
       
   159     iFileOpen = EFalse;
       
   160     
       
   161     // selection is supposed to point to a bunch of notifications
       
   162     // containing the URIs the messages are to be fetched from
       
   163     TInt count = iCurrentMessageNo;
       
   164     iError = KErrNone;
       
   165 
       
   166     while ( count > 0 && ( iNotificationParent == KMsvNullIndexEntryId ) )
       
   167         {
       
   168         // Load the notification
       
   169         // iCurrentMessageNo (and therefore also count) has originally been
       
   170         // set to iSelection->Count() so the index is always valid.
       
   171         count--; // indexes are zero based
       
   172         if ( count < iSelection->Count() )
       
   173             {
       
   174             iError = iServerEntry->SetEntry( iSelection->At( count ) );
       
   175             }
       
   176         else
       
   177             {
       
   178             iError = KErrNotFound;
       
   179             }
       
   180         if ( iError == KErrNone )
       
   181             {
       
   182             TMsvEntry entry = iServerEntry->Entry();
       
   183             iNotificationParent = entry.Parent();
       
   184             }
       
   185         }
       
   186     
       
   187     // release the last notification
       
   188     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
   189 
       
   190     if (  iNotificationParent == KMsvNullIndexEntryId )
       
   191         {
       
   192 #ifndef _NO_MMSS_LOGGING_
       
   193         TMmsLogger::Log( _L("- could not access any entry to get parent") );
       
   194 #endif
       
   195         // nothing to receive. Give up immediately
       
   196         aStatus = KRequestPending;
       
   197         TRequestStatus* status = &aStatus;
       
   198         User::RequestComplete( status, iError );
       
   199         return;
       
   200         }
       
   201 
       
   202     // Initialize everything into the failed list.
       
   203     // Very pessimistic indeed.
       
   204     
       
   205     iBad->SetReserveL( iCurrentMessageNo );
       
   206 
       
   207     Queue( aStatus );
       
   208     
       
   209     // We complete ourselves to get into the state machine loop.
       
   210     // The first thing to do is to check the roaming state.
       
   211     FallThrough();
       
   212 
       
   213     }
       
   214 
       
   215 // ---------------------------------------------------------
       
   216 // CMmsReceiveMessage::DoComplete
       
   217 //
       
   218 // ---------------------------------------------------------
       
   219 //
       
   220 void CMmsReceiveMessage::DoComplete(TInt& aError )
       
   221     {
       
   222 
       
   223 #ifndef _NO_MMSS_LOGGING_
       
   224     TMmsLogger::Log( _L("Receivemsg DoComplete"));
       
   225 #endif
       
   226     // We should get here if we are cancelled, or if
       
   227     // the cycle has completed (with or without error)
       
   228     // Make sure the store is released
       
   229     iDecoder->RelaseDataSink();
       
   230 
       
   231     // If we have an error, we must delete the entry
       
   232     // under construction.
       
   233     // If we have successfully created the entry, we have set
       
   234     // iEntryUnderConstruction to KMsvNullIndexEntryId.
       
   235     // If iEntryUnderConstruction still points to an entry, it means
       
   236     // that the cycle has been aborted, and the incomplete entry
       
   237     // must be deleted.
       
   238     if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
       
   239         {
       
   240         if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ) == KErrNone )
       
   241             {
       
   242             iServerEntry->DeleteEntry ( iEntryUnderConstruction );
       
   243             }
       
   244         iEntryUnderConstruction = KMsvNullIndexEntryId;
       
   245         }
       
   246 
       
   247     // Set error to entries that are still left
       
   248     // If some of the entries already have an error set,
       
   249     // it is not overridden.
       
   250     UnSetSendMask( *iFailed, aError );
       
   251     
       
   252     // If we are supporting MMBox, we must also clear the duplicates
       
   253     // if we have notifications in bad list
       
   254     
       
   255     if ( iMmsSettings->MMBoxFolder() != KMsvNullIndexEntryId )
       
   256         {
       
   257         TInt i = 0;
       
   258 #ifndef _NO_MMSS_LOGGING_
       
   259         if ( iBad->Count() > 0 )
       
   260             {
       
   261             TMmsLogger::Log( _L("- %d notifications on bad list "), iBad->Count() );
       
   262             }
       
   263 #endif
       
   264 
       
   265         for ( i = 0; i < iBad->Count(); i++ )
       
   266             {
       
   267             if ( iServerEntry->SetEntry( iBad->At( i )) == KErrNone )
       
   268                 {
       
   269                 // we don't want to leave here, we do our best
       
   270                 TRAP_IGNORE( ClearDuplicateEntryOperationL() ); 
       
   271                 }
       
   272             }
       
   273         }
       
   274     }
       
   275 
       
   276 // start of ROAMING CHECK handling
       
   277 // ---------------------------------------------------------
       
   278 // CMmsReceiveMessage::RoamingCheck
       
   279 //
       
   280 // ---------------------------------------------------------
       
   281 //
       
   282 void CMmsReceiveMessage::RoamingCheck()
       
   283     {
       
   284     
       
   285     TInt error = KErrNone;
       
   286     
       
   287 #ifndef _NO_MMSS_LOGGING_
       
   288     TMmsLogger::Log( _L("Receivemsg roaming check start"));
       
   289 #endif
       
   290 
       
   291     if ( !iMmsSettings->LocalMode() && !iMmsSettings->FetchOverride() &&
       
   292          ( ( iMmsSettings->ReceivingModeHome() != iMmsSettings->ReceivingModeForeign() ) ||
       
   293          ( iMmsSettings->ReceivingModeForeign() == EMmsReceivingManual ) ||
       
   294          ( iMmsSettings->ReceivingModeForeign() == EMmsReceivingPostpone ) ) )
       
   295         {
       
   296         // In offline mode we cannot ask if we are roaming - just give up
       
   297         if ( !NetworkOperationsAllowed() )
       
   298             {
       
   299 #ifndef _NO_MMSS_LOGGING_
       
   300             TMmsLogger::Log( _L("- Offline mode - cannot check network status"));
       
   301 #endif
       
   302             error = KMmsErrorOfflineMode;
       
   303             iError = error;
       
   304             }
       
   305         else
       
   306             {
       
   307             // if we get an error we have not been able to connect to phone module
       
   308             // and we cannot ask if we are roaming
       
   309             TRAP( error, iPhone = CMmsPhoneClient::NewL() )
       
   310             }
       
   311 
       
   312         if ( error == KErrNone )
       
   313             {
       
   314 #ifndef _NO_MMSS_LOGGING_
       
   315             TMmsLogger::Log( _L("- Receivemsg getting network status"));
       
   316 #endif
       
   317             iPhone->Roaming( iStatus );
       
   318             }
       
   319         }
       
   320     else
       
   321         {
       
   322         // no roaming check needed
       
   323 #ifndef _NO_MMSS_LOGGING_
       
   324         TMmsLogger::Log( _L("- Roaming check not needed"));
       
   325 #endif
       
   326         TRequestStatus* status = &iStatus;
       
   327         iStatus = KRequestPending;
       
   328         // 0 = home network. If we don't care, we behave as at home
       
   329         User::RequestComplete( status, 0 );
       
   330         }
       
   331         
       
   332     if ( error != KErrNone )
       
   333         {
       
   334         // we got an error - iPhone is not going to complete us
       
   335         TRequestStatus* status = &iStatus;
       
   336         iStatus = KRequestPending;
       
   337         User::RequestComplete( status, error );
       
   338         }
       
   339     SetActive();
       
   340         
       
   341     }
       
   342 
       
   343 // ---------------------------------------------------------
       
   344 // CMmsReceiveMessage::GetRoamingState
       
   345 //
       
   346 // ---------------------------------------------------------
       
   347 //
       
   348 void CMmsReceiveMessage::GetRoamingState()
       
   349     {
       
   350     
       
   351     // if current receiving modes are valid, we have to set the message fetch state
       
   352     // according to the receiving mode of the current (home or foreign ) network 
       
   353     
       
   354     // Set the message fetch state according to current network value
       
   355     if( iRegistrationStatus != 0 )
       
   356         {
       
   357 #ifndef _NO_MMSS_LOGGING_
       
   358         TMmsLogger::Log( _L("roaming") );
       
   359 #endif
       
   360         iReceivingMode = iMmsSettings->ReceivingModeForeign();
       
   361         }
       
   362     else
       
   363         {
       
   364 #ifndef _NO_MMSS_LOGGING_
       
   365         TMmsLogger::Log( _L("in home network") );
       
   366 #endif
       
   367         iReceivingMode = iMmsSettings->ReceivingModeHome();        
       
   368         }
       
   369         
       
   370 #ifndef _NO_MMSS_LOGGING_
       
   371     TMmsLogger::Log( _L("- message receiving mode is %d"), iReceivingMode );
       
   372 #endif
       
   373     
       
   374     // if something is wrong, entries are marked failed.
       
   375     if ( iError != KErrNone )
       
   376         {
       
   377         // Set error to all entries
       
   378         // If some of the entries already have an error set,
       
   379         // it is not overridden.
       
   380         UnSetSendMask( *iFailed, iError );
       
   381 
       
   382         }
       
   383     // if we have something in iError, we shall not continue
       
   384     // to open IAP, and RunL will complete. 
       
   385     // All entries will be rescheduled
       
   386 
       
   387     }
       
   388 // end of ROAMING CHECK handling
       
   389 
       
   390 // ---------------------------------------------------------
       
   391 // CMmsReceiveMessage::DecodeResponseL
       
   392 //
       
   393 // ---------------------------------------------------------
       
   394 //
       
   395 void CMmsReceiveMessage::DecodeResponseL()
       
   396     {
       
   397     FallThrough();
       
   398     return;
       
   399     }
       
   400 
       
   401 // ---------------------------------------------------------
       
   402 // CMmsReceiveMessage::ConnectToIapL
       
   403 //
       
   404 // ---------------------------------------------------------
       
   405 //
       
   406 void CMmsReceiveMessage::ConnectToIAPL()
       
   407     {
       
   408 #ifndef _NO_MMSS_LOGGING_
       
   409     TMmsLogger::Log( _L("Receivemsg open IAP") );
       
   410 #endif
       
   411     if ( !iMmsSettings->LocalMode() )
       
   412         {
       
   413         iError = iMmsSettings->ValidateSettings();
       
   414         }
       
   415     CMmsBaseOperation::ConnectToIAPL();
       
   416     }
       
   417 
       
   418 // ---------------------------------------------------------
       
   419 // CMmsReceiveMessage::InitializeSessionL
       
   420 //
       
   421 // ---------------------------------------------------------
       
   422 //
       
   423 void CMmsReceiveMessage::InitializeSessionL()
       
   424     {
       
   425 
       
   426     // Here we should connect to MMSC
       
   427 
       
   428 #ifndef _NO_MMSS_LOGGING_
       
   429     TMmsLogger::Log( _L("Receivemsg Connecting") );
       
   430 #endif
       
   431 
       
   432     // for testing purposes our messages are in files in the folder
       
   433     // defined in iMmsSettings->iRootFolder.
       
   434     if ( iMmsSettings->LocalMode() )
       
   435         {
       
   436         HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
       
   437         CleanupStack::PushL( filename );
       
   438         TPtr fileNamePtr = filename->Des();
       
   439         fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
       
   440         iFs.SetSessionPath( fileNamePtr );
       
   441         CleanupStack::PopAndDestroy( filename );
       
   442         }
       
   443 
       
   444     CMmsBaseOperation::InitializeSessionL();
       
   445 
       
   446     }
       
   447 
       
   448 // ---------------------------------------------------------
       
   449 // CMmsReceiveMessage::SubmitTransactionL
       
   450 //
       
   451 // ---------------------------------------------------------
       
   452 //
       
   453 void CMmsReceiveMessage::SubmitTransactionL()
       
   454     {
       
   455 
       
   456 #ifndef _NO_MMSS_LOGGING_
       
   457     TMmsLogger::Log( _L("Receivemsg Receiving") );
       
   458 #endif
       
   459     iEntryUnderConstruction = KMsvNullIndexEntryId;
       
   460     iResponse->Reset(); // Reset sets the correct version
       
   461     iAlreadyDeferred = EFalse;
       
   462     iMmsHeaders->Reset();
       
   463     iEncodeBuffer->Reset();
       
   464 
       
   465     // We don't totally give up in case of an error.
       
   466     // We may have a long list of entries to handle.
       
   467     // One entry may be garbage while others will be ok.
       
   468     
       
   469     // Call to IsConnected() clears error for a new entry or
       
   470     // sets the error if we are not connected. If we are not
       
   471     // connected, we must terminate the state machine loop
       
   472     if ( !IsConnected() )
       
   473         {
       
   474         return;
       
   475         }
       
   476 
       
   477     TMsvEntry entry;
       
   478 
       
   479     // Load the notification. If an error occurs, we cannot continue
       
   480     // with this notification.
       
   481     if ( !LoadNotificationL( entry ) )
       
   482         {
       
   483         // LoadNotificationL sets the state machine active if we can continue
       
   484         // to next entry.
       
   485         // If the situation is hopeless, the state machine is not active, and
       
   486         // the loop terminates
       
   487         return;
       
   488         }
       
   489 
       
   490 
       
   491     TInt size = iNotification->MessageSize();
       
   492 #ifndef _NO_MMSS_LOGGING_
       
   493     TMmsLogger::Log( _L("- message size %d"), size);
       
   494 #endif
       
   495     // If the size in notification is bigger than the maximum size we can receive
       
   496     // use the maximum size instead for the memory checks (we are not receiving
       
   497     // more than that anyway)
       
   498     if ( size > iMmsSettings->MaximumReceiveSize() )
       
   499         {
       
   500         // reduce the size to maximum allowed
       
   501         size = iMmsSettings->MaximumReceiveSize();
       
   502         }
       
   503 
       
   504     // Now we must check if the message should be rejected or deferred
       
   505     // The function IsNotificationInsaneL() checks if the notification
       
   506     // has incorrect message type or incorrect major version number.
       
   507     // If the message is unrecognized, the response will be "unrecognized"
       
   508     // The funtion sets the status, and later the response will be sent
       
   509     // but there is no need to check for expiration or disk space in
       
   510     // case the message will be rejected anyway.
       
   511     
       
   512     if ( !IsNotificationInsaneL() )
       
   513         {
       
   514         // Check if message has expired.
       
   515         // If it has, and we are in automatic mode, there is no need
       
   516         // to send a response.
       
   517         if ( !CheckExpirationL() )
       
   518             {
       
   519             return;
       
   520             }
       
   521 
       
   522         // Check disk space.    
       
   523         // we must add the safety margin here...
       
   524         size += KMmsDiskSafetyMargin;
       
   525 
       
   526         // Query about disk space.
       
   527         if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
       
   528             &iFs, size, iMessageDrive ) )
       
   529             {
       
   530             iNotification->SetStatus( KMmsMessageStatusDeferred );
       
   531             iError = KErrDiskFull;
       
   532             }
       
   533         }
       
   534 
       
   535     // if we have got an error for this message (KErrNoMemory or
       
   536     // KErrDiskFull) we must store the information in the notification
       
   537     // entry to discern these situations from cases where there
       
   538     // is something wrong with the actual transaction.
       
   539     if ( iError != KErrNone )
       
   540         {
       
   541         TInt error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
   542         // If we cannot update our entry - that's too bad
       
   543         if ( error == KErrNone )
       
   544             {
       
   545             TMsvEntry tEntry;
       
   546             tEntry = iServerEntry->Entry();
       
   547             tEntry.iError = iError;
       
   548             iServerEntry->ChangeEntry( tEntry );
       
   549             }
       
   550         // we clear the error now. The rest of the branching
       
   551         // is not based on iError but on the notification status
       
   552         iError = KErrNone;
       
   553         // Release the entry
       
   554         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
   555         }
       
   556 
       
   557 #ifndef _NO_MMSS_LOGGING_
       
   558     TMmsLogger::Log( _L("- notification status %d"), iNotification->Status() );
       
   559     switch ( iNotification->Status() )
       
   560         {
       
   561         case KMmsMessageStatusRejected:
       
   562             TMmsLogger::Log( _L("- rejected") );
       
   563             break;
       
   564         case KMmsMessageStatusDeferred:
       
   565             TMmsLogger::Log( _L("- deferred") );
       
   566             break;
       
   567         case KMmsMessageStatusRetrieved:
       
   568             TMmsLogger::Log( _L("- retrieved") );
       
   569             break;
       
   570         case KMmsMessageStatusUnrecognized:
       
   571             TMmsLogger::Log( _L("- unrecognized") );
       
   572             break;
       
   573         default :
       
   574             TMmsLogger::Log( _L("- whatever") );
       
   575             break;
       
   576         }
       
   577 #endif
       
   578 
       
   579 #ifndef _NO_MMSS_LOGGING_
       
   580     TMmsLogger::Log( _L("- receiving mode: %d"), iReceivingMode );
       
   581 #endif
       
   582 
       
   583     // Sending the response tells the MMSC that the 
       
   584     // notification has been received and understood.
       
   585     // If we do not want to fetch the message the
       
   586     // WantToFetchThisL() subroutine will change the state
       
   587     // so that after return the response will be sent to MMSC
       
   588     
       
   589     if ( !WantToFetchThisL( entry ) )
       
   590         {
       
   591         return;
       
   592         }
       
   593 
       
   594     // Now it seems that we are supposed to fetch something
       
   595     // The notification has cleared all our tests and fetching is on
       
   596 
       
   597     // Now we should start a GET transaction with the
       
   598     // URI we obtain from the headers
       
   599            
       
   600     // If we fail to get anything because the message has expired,
       
   601     // we set iEntryUnderConstruction to KMsvNullIndexEntryId
       
   602     // Otherwise we must reschedule the receive
       
   603 
       
   604     // At this point we will invoke the transaction that sends
       
   605     // our get request to MMSC and when the transaction completes,
       
   606     // the data has been stored in our encode buffer, if the status
       
   607     // is KErrNone. Otherwise the completion status will contain the
       
   608     // error code.
       
   609 
       
   610     if ( iMmsSettings->LocalMode() )
       
   611         {
       
   612         LocalModeFetchL();
       
   613         // if only local mode, we complete ourselves
       
   614 #ifndef _NO_MMSS_LOGGING_
       
   615         TMmsLogger::Log( _L("- local mode, completing fetch with status %d"), iError );
       
   616 #endif
       
   617         if ( !IsActive() )
       
   618             {
       
   619             // If Local mode fetch fails it already calls ChangeStateL() and becomes active
       
   620             // we cannot set us active a second time
       
   621             FallThrough();
       
   622             }
       
   623         }
       
   624     else // global mode
       
   625         {
       
   626         // Chunked mode in global mode, too
       
   627         // chunked mode is turned on here - other changes are generic
       
   628         DoCreateEntryL();
       
   629         iDecoder->InitializeChunkedMode( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer );
       
   630         // end of chunked preparation
       
   631         
       
   632         // we get this far only if we are connected
       
   633         HBufC* uri = HBufC::NewL( iNotification->ContentLocation().Length() + KMMSBufferExtra );
       
   634         CleanupStack::PushL( uri );
       
   635         uri->Des().Copy( iNotification->ContentLocation() );
       
   636 #ifndef _NO_MMSS_LOGGING_
       
   637         TMmsLogger::Log( _L("...Fetching from URI: %S"), uri );
       
   638 #endif
       
   639         iMmsSession->FetchMessageL(
       
   640             *uri, 
       
   641             *iEncodeBuffer,
       
   642 // Use this buffer size when in chunked mode             
       
   643             KMmsChunkedBufferSize, // tell that only this buffer size is needed
       
   644             *iEncoder,
       
   645             *iDecoder,
       
   646             iStatus );
       
   647         CleanupStack::PopAndDestroy( uri );
       
   648         SetActive();
       
   649         }
       
   650 
       
   651     }
       
   652     
       
   653 // ---------------------------------------------------------
       
   654 //
       
   655 // ---------------------------------------------------------
       
   656 TBool CMmsReceiveMessage::IsConnected()
       
   657     {
       
   658     if ( iConnected )
       
   659         {
       
   660         // We clear the error at this point to tell that this message
       
   661         // is all right so far. Notifications for failed messages
       
   662         // remain in the selection, and they are rescheduled later
       
   663         // The error is saved in the schedule data for the notification.
       
   664         iError = KErrNone;
       
   665         }
       
   666     else
       
   667         {
       
   668         // We are in a totally hopeless mess.
       
   669         // We don't have a connection. iError should contain the reason
       
   670         // all we can do is give up
       
   671         // If we return from RunL without becoming active again
       
   672         // RunL completes.
       
   673         // That's all we can do here...
       
   674         // The selection arrays have information about
       
   675         // which messages have succeeded and which not.
       
   676 
       
   677         // DoComplete sets an error code to those entries in the
       
   678         // failed list that do not already have their error set.
       
   679         // If we don't know what went wrong, we just say "disconnected"
       
   680         if ( iError == KErrNone )
       
   681             {
       
   682             iError = KErrDisconnected;
       
   683             }
       
   684         }
       
   685     return iConnected;    
       
   686     }
       
   687     
       
   688 // ---------------------------------------------------------
       
   689 //
       
   690 // ---------------------------------------------------------
       
   691 //
       
   692 TBool CMmsReceiveMessage::LoadNotificationL( TMsvEntry& aEntry )
       
   693     {
       
   694     // set entry to next notification in list
       
   695     iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
   696     if ( iError != KErrNone )
       
   697         {
       
   698         // The code called by SkipEntryL will make us active again
       
   699         // We may now try the next entry.
       
   700         SkipEntryL();
       
   701         return EFalse;
       
   702         }
       
   703 
       
   704     aEntry = iServerEntry->Entry();
       
   705     if ( aEntry.iMtmData2 & KMmsNotifyResponseSent )
       
   706         {
       
   707         iAlreadyDeferred = ETrue;
       
   708         }
       
   709 
       
   710     CMsvStore* store = NULL;
       
   711 
       
   712     TRAP (iError, {store = iServerEntry->ReadStoreL();});
       
   713     // We have managed to generate some mysterious notifications
       
   714     // where the ReadStoreL fails.
       
   715     // These must be deleted, as they are garbage.
       
   716     // I assume they are used by someone else.
       
   717     // This means we just delete them from our list and forget them
       
   718     // If we cannot get a read store, we cannot do anything with the
       
   719     // schedule either.
       
   720     if ( iError == KErrNoMemory )
       
   721         {
       
   722         // Out of memory - hopeless.
       
   723         // We return without becoming active again and the 
       
   724         // whole loop completes.
       
   725         // We should try to disconnect, but if there is a serious
       
   726         // memory problem I doubt that anything will work.
       
   727 
       
   728         // Release the entry
       
   729         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
   730         return EFalse;
       
   731         }
       
   732         
       
   733     if ( iError != KErrNone )
       
   734         {
       
   735         // don't discard the entry completely now
       
   736         delete store;
       
   737         store = NULL;
       
   738         // The code called by SkipEntryL will make us active again
       
   739         SkipEntryL();
       
   740         return EFalse;
       
   741         }
       
   742         
       
   743     // We have access to the notification
       
   744     CleanupStack::PushL( store );
       
   745     iNotification->RestoreL( *store );
       
   746     CleanupStack::PopAndDestroy( store );
       
   747     
       
   748     // We must clear deferred status always:
       
   749     // If we did not have enough memory the first time,
       
   750     // the message was deferred. If we now have enough 
       
   751     // memory the old status must be cleared
       
   752 
       
   753     iNotification->SetResponseStatus( 0 ); // clear possible old status
       
   754     iNotification->SetResponseTextL( TPtrC() ); // clear possible old text
       
   755 
       
   756     if ( iNotification->Status() == KMmsMessageStatusDeferred )
       
   757         {
       
   758         iNotification->SetStatus( 0 );
       
   759         }
       
   760 
       
   761     // We must check if message fetching is deferred or totally off.
       
   762     // if iReceivingMode == EMmsReceivingReject, notification has been deleted already.
       
   763     if ( !iMmsSettings->FetchOverride() &&
       
   764         iNotification->Status() == 0 &&
       
   765         ( iReceivingMode == EMmsReceivingManual || iReceivingMode == EMmsReceivingPostpone ) )
       
   766         {
       
   767         iNotification->SetStatus( KMmsMessageStatusDeferred );
       
   768         }
       
   769     
       
   770     // We get this far only if we are connected
       
   771     aEntry.SetConnected( ETrue );
       
   772     aEntry.SetSendingState( KMsvSendStateSending );
       
   773     aEntry.iError = KErrNone; // optimistic...
       
   774     iServerEntry->ChangeEntry( aEntry );
       
   775 
       
   776     // Release the entry
       
   777     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
   778 
       
   779     // Continue with this notification
       
   780     return ETrue;
       
   781     }
       
   782     
       
   783 // ---------------------------------------------------------
       
   784 //
       
   785 // ---------------------------------------------------------
       
   786 //
       
   787 TBool CMmsReceiveMessage::CheckExpirationL()
       
   788     {
       
   789     
       
   790     // If the message has expired, it can be rejected without further ado
       
   791     // We allow a little slack here, if it expired just a few seconds ago,
       
   792     // we still have hope...
       
   793     // use universal time in case user changes location
       
   794     TTime now;
       
   795     TMsvEntry entry;
       
   796     TBool canContinue = ETrue; // optimistic
       
   797 
       
   798     now.UniversalTime();
       
   799 #ifndef _NO_MMSS_LOGGING_
       
   800     TMmsLogger::Log( _L("MMS terminal universal datetime: ") );
       
   801     CMmsBaseOperation::LogDateL( now );
       
   802     TMmsLogger::Log( _L("MMS message expiry datetime:") );
       
   803     CMmsBaseOperation::LogNetworkFormatDateL( iNotification->ExpiryDate() );
       
   804 #endif
       
   805     if ( ( ( iNotification->ExpiryDate() + iMmsSettings->ExpiryOvershoot() ) * KMmsMillion ) <
       
   806         now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() )
       
   807         {
       
   808 #ifndef _NO_MMSS_LOGGING_
       
   809         TMmsLogger::Log( _L("message has expired by %d seconds"),
       
   810             ( now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64())/KMmsMillion -
       
   811             iNotification->ExpiryDate() - iMmsSettings->ExpiryOvershoot() );
       
   812 #endif
       
   813         // If the notification is in inbox or in MMBox folder, fetch will continue.
       
   814         if( entry.Parent() == KMsvGlobalInBoxIndexEntryId  ||
       
   815             entry.Parent() == iMmsSettings->MMBoxFolder() )
       
   816             {
       
   817             // Mark the notification expired
       
   818             iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
   819             if ( iError == KErrNone )
       
   820                 {
       
   821                 entry = iServerEntry->Entry();
       
   822                 entry.iMtmData2 |= KMmsMessageExpired;
       
   823                 iServerEntry->ChangeEntry( entry );
       
   824                 }
       
   825             // Release the entry
       
   826             iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
   827 
       
   828 #ifndef _NO_MMSS_LOGGING_
       
   829             TMmsLogger::Log( _L("Expired notification. Fetch continues") ); 
       
   830 #endif
       
   831             }
       
   832         else
       
   833             {
       
   834             // iError == KErrNone, the last stage will just remove our entry from the list
       
   835             // There is no need to send any reply to an expired message.
       
   836             // The MMSC will not be interested in getting a "reject"
       
   837             // response to an expired message.
       
   838             iResponse->SetStatus( KMmsMessageStatusRejected );
       
   839             iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
   840             // return to the beginning of the state machine loop
       
   841             iState = EMmsOperationUpdatingEntryStatus;
       
   842             // The code called by ChangeStateL will make us active again
       
   843             ChangeStateL();
       
   844             canContinue = EFalse; // loop to next state
       
   845             }
       
   846         }
       
   847     return canContinue; // can continue
       
   848     }
       
   849     
       
   850 // ---------------------------------------------------------
       
   851 //
       
   852 // ---------------------------------------------------------
       
   853 //
       
   854 TBool CMmsReceiveMessage::IsNotificationInsaneL()
       
   855     {
       
   856     TBool isInsane = EFalse; // optimistic
       
   857     // If the message is unrecognized, the response will be "unrecognized"
       
   858     // Either the message type is unknown, or the major version number differs
       
   859     if  ( ( iNotification->MmsVersion() & KMmsMajorVersionMask ) !=
       
   860         ( iMmsSettings->MmsVersion() & KMmsMajorVersionMask ) )
       
   861         {
       
   862         // major versions differ, send back 1.0 version response
       
   863         iResponse->SetMmsVersion( KMmsVersion1 );
       
   864         iNotification->SetStatus( KMmsMessageStatusUnrecognized );
       
   865         iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
   866         isInsane = ETrue;
       
   867         }
       
   868     else if ( iNotification->MessageType() != KMmsMessageTypeMNotificationInd && 
       
   869         iNotification->MessageType() != KMmsMessageTypeMBoxDescr )
       
   870         { 
       
   871         // We have been pushed something we cannot handle.
       
   872         // delivery reports have been picked out earlier, so they cause
       
   873         // no problems here.
       
   874         iNotification->SetStatus( KMmsMessageStatusUnrecognized );
       
   875         iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
   876         isInsane = ETrue;
       
   877         }
       
   878     return isInsane;
       
   879     }
       
   880        
       
   881 // ---------------------------------------------------------
       
   882 //
       
   883 // ---------------------------------------------------------
       
   884 //
       
   885 TBool CMmsReceiveMessage::WantToFetchThisL( TMsvEntry& aEntry )
       
   886     {
       
   887     if ( ( iReceivingMode != EMmsReceivingAutomatic && !iMmsSettings->FetchOverride() ) ||
       
   888         iNotification->Status() == KMmsMessageStatusRejected ||
       
   889         iNotification->Status() == KMmsMessageStatusDeferred ||
       
   890         iNotification->Status() == KMmsMessageStatusRetrieved ||
       
   891         iNotification->Status() == KMmsMessageStatusUnrecognized )
       
   892         {
       
   893         // We don't want this message for one reason or another
       
   894         // We shall send reject message or deferred message and
       
   895         // remove this notification from the scheduling.
       
   896         // If the fetching is deferred, the notification should remain
       
   897         // in the machine waiting for better times.
       
   898         // If the message is rejected, the notification is deleted.
       
   899         // In both cases the schedule must be removed. A deferred
       
   900         // notification is not rescheduled before the message fetching
       
   901         // is turned on again.
       
   902 
       
   903         // If the whole message is in the extended notification,
       
   904         // the status is "retrieved"
       
   905 
       
   906         // However, if the "deferred" response has already been sent,
       
   907         // we should not send it again
       
   908 
       
   909         iResponse->SetStatus( iNotification->Status() );
       
   910 
       
   911         if ( iResponse->Status() != KMmsMessageStatusRejected &&
       
   912             iResponse->Status() != KMmsMessageStatusDeferred &&
       
   913             iResponse->Status() != KMmsMessageStatusRetrieved &&
       
   914             iResponse->Status() != KMmsMessageStatusUnrecognized )
       
   915             {
       
   916             // We have an unlucky message. The notification arrived
       
   917             // while we were supposed to fetch it, but before it was
       
   918             // actually fetched, receiving was turned off.
       
   919             // We try to defer it hoping it can be fetched before it
       
   920             // expires.
       
   921             // A message should be scheduled for fetching only a few
       
   922             // seconds after the notification arrives, so that if the 
       
   923             // user manages to turn the fetching off before we fetch 
       
   924             // the message we can assume that he does not want this one either
       
   925             // (at least not now). We are a bit conservative, though,
       
   926             // we don't reject this one as it was supposed to be fetched
       
   927             // before it fell into the time trap.
       
   928             iResponse->SetStatus( KMmsMessageStatusDeferred );
       
   929             }
       
   930 
       
   931         if ( aEntry.iMtmData2 & KMmsNotifyResponseSent )
       
   932             {
       
   933             // if the notify response has already been sent for this message,
       
   934             // we don't send it again.
       
   935             // When the message fetch state is switched back on,
       
   936             // server Mtm must check the pending notifications and
       
   937             // reschedule them for fetching.
       
   938             // An already deferred notification should not be in our
       
   939             // list, but I'm paranoid and check in case some notification
       
   940             // has fallen into a time trap.
       
   941             iAlreadyDeferred = ETrue;
       
   942             iState = EMmsOperationStoringResponseData;
       
   943             }
       
   944         else
       
   945             {
       
   946             // The function called by ChangeStateL will make us active again
       
   947             iState = EMmsOperationStoringResponseData;
       
   948             }
       
   949         // We are not fetching this message.
       
   950         // Either we send a response to MMSC or we just move to next notification.
       
   951         ChangeStateL();
       
   952         return EFalse;
       
   953         }
       
   954     return ETrue;
       
   955     }
       
   956         
       
   957 // ---------------------------------------------------------
       
   958 //
       
   959 // ---------------------------------------------------------
       
   960 //
       
   961 void CMmsReceiveMessage::DoCreateEntryL()
       
   962     {
       
   963     
       
   964 #ifndef _NO_MMSS_LOGGING_
       
   965     TMmsLogger::Log( _L("Receivemsg DoCreateEntryL") );
       
   966 #endif
       
   967 
       
   968     // We create a message entry into the inbox
       
   969     // it is invisible and in preparation until
       
   970     // we decide that we have successfully fetched the message
       
   971     // The entry must exist before the message is fetched, because
       
   972     // decode puts data into an existing entry, and
       
   973     // creates children to the entry for attachments.
       
   974 
       
   975     // If we have failed in storing data to the entry, it may be non-zero
       
   976     // We try to delete it before creating a new one
       
   977 
       
   978     if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
       
   979         {
       
   980         if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ) == KErrNone )
       
   981             {
       
   982             iServerEntry->DeleteEntry ( iEntryUnderConstruction );
       
   983             }
       
   984         iEntryUnderConstruction = KMsvNullIndexEntryId;
       
   985         }
       
   986 
       
   987     // If the creation of the entry is successful, we
       
   988     // set our entry to point to the newly created entry
       
   989     // to get data content to it.
       
   990     if ( iError == KErrNone )
       
   991         {
       
   992         TMsvId targetId = KMsvGlobalInBoxIndexEntryId;
       
   993 
       
   994         TMsvEntry tEntry;
       
   995 
       
   996         // set all relevant flags in tMsvEntry
       
   997         tEntry.iType = KUidMsvMessageEntry;
       
   998         tEntry.iMtm = KUidMsgTypeMultimedia;
       
   999         tEntry.iServiceId = iService;
       
  1000         tEntry.SetUnread( ETrue );
       
  1001         tEntry.SetNew( ETrue );
       
  1002         tEntry.SetVisible( EFalse );
       
  1003         tEntry.SetComplete( EFalse );
       
  1004         tEntry.SetInPreparation( ETrue );
       
  1005         tEntry.SetReadOnly( EFalse );
       
  1006 
       
  1007         // Query about disk space.
       
  1008         if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
       
  1009             &iFs, KMmsIndexEntryExtra, iMessageDrive ) )
       
  1010             {
       
  1011             // we use standard error code here
       
  1012             iError = KErrDiskFull;
       
  1013             }
       
  1014         if ( iError == KErrNone )
       
  1015             {
       
  1016             iError = iServerEntry->SetEntry( targetId );
       
  1017             }
       
  1018 
       
  1019         if ( iError == KErrNone )
       
  1020             {
       
  1021             iError = iServerEntry->CreateEntry( tEntry );
       
  1022             }
       
  1023         iEntryUnderConstruction = tEntry.Id();
       
  1024         if ( iError == KErrNone )
       
  1025             {
       
  1026             iError = iEntryWrapper->SetCurrentEntry( iEntryUnderConstruction );
       
  1027             }
       
  1028         }
       
  1029     }
       
  1030     
       
  1031 // ---------------------------------------------------------
       
  1032 // CMmsReceiveMessage::StoreResponseL
       
  1033 //
       
  1034 // ---------------------------------------------------------
       
  1035 //
       
  1036 void CMmsReceiveMessage::StoreResponseL()
       
  1037     {
       
  1038 #ifndef _NO_MMSS_LOGGING_
       
  1039     TMmsLogger::Log( _L("Receivemsg Store Response") );
       
  1040 #endif
       
  1041     TInt error;
       
  1042     TInt fatal = EFalse; // fatal error, no use to retry
       
  1043 
       
  1044     // If we have got this far, we don't return to CreateEntry anymore
       
  1045     // even if we encounter backup/restore problems later.
       
  1046 
       
  1047     if ( iError == KErrNone )
       
  1048         {
       
  1049         // if we have no error, me must retry to make the entry visible
       
  1050         iCriticalState = EMmsOperationStoringResponseData;
       
  1051         }
       
  1052     else
       
  1053         {
       
  1054         iCriticalState = EMmsOperationSendingAck;
       
  1055         }
       
  1056 
       
  1057     // At the moment we should not receive any extra message types,
       
  1058     // so that the only error of this type would
       
  1059     // be wrong type of message either from WAP stack or from MMSC.
       
  1060     // Send request is all right in local mode, as we get back
       
  1061     // the messages we send ourselves.
       
  1062     // We accept the send requests as retrieve confirmations,
       
  1063     // as they are importand during testing phase:
       
  1064     // We can put any message someone has sent into the folder
       
  1065     // representing the simulated MMSC and try to fetch it as
       
  1066     // if it were a real message.
       
  1067     // We can't check the message type if we have encountered an error.
       
  1068     // In that case the headers may not have been correctly decoded
       
  1069     if ( iError == KErrNone &&
       
  1070         iResponse->Status() != KMmsMessageStatusRejected &&
       
  1071         iResponse->Status() != KMmsMessageStatusDeferred &&
       
  1072         iResponse->Status() != KMmsMessageStatusRetrieved &&
       
  1073         iMmsHeaders->MessageType() != KMmsMessageTypeMRetrieveConf &&
       
  1074         iMmsHeaders->MessageType() != KMmsMessageTypeMSendReq )
       
  1075         {
       
  1076         iResponse->SetStatus( KMmsMessageStatusUnrecognized );
       
  1077         iError = KMmsErrorStatusUnsupportedMessage;
       
  1078         }
       
  1079 
       
  1080     // If we have managed to decode the response, it may contain a status
       
  1081     // that must be mapped to an error. The error may be permanent or temporary
       
  1082 
       
  1083     if ( iError == KErrNone )
       
  1084         {
       
  1085         // we have got a response from MMSC, and decoded it, but in version 1.1
       
  1086         // or later the response may still contain an error code.
       
  1087         // if response text length was 0, it was deleted
       
  1088 
       
  1089         // - if error is permanent, notification will be deleted.
       
  1090         // - if error is transient, response text is copied to notification
       
  1091         // and UI components may show it to the user if needed.
       
  1092         
       
  1093         // iError is set to the correct value depending on response status
       
  1094         // "fatal" indicates if the error is permanent or temporary
       
  1095         fatal = MapErrorStatus( iMmsHeaders->ResponseStatus() );
       
  1096         }
       
  1097 
       
  1098     // If we get a transient failure from MMSC, we store the possible text and status code
       
  1099     // into our notification. UI may show the text to the user in case there is something
       
  1100     // the user might do about the failure. Permament failures are stored in the message
       
  1101     // entry.
       
  1102     // The application id is also copied to the notification in case application id is present
       
  1103     // in the message but not in the notification.
       
  1104     // If the application has not been registered or memory runs out, the user may be
       
  1105     // informed that the notification refers to a message that belongs to an application.
       
  1106         
       
  1107     CopyDataFromMessageToNotificationL();
       
  1108 
       
  1109     // If there has been an error and logging is allowed, dump the buffer into a file
       
  1110     // to support error analysis later
       
  1111     DumpIfNeededL();
       
  1112     
       
  1113     // We must try to finalize even if we have encountered an error.
       
  1114     // If the decode has failed, iError contains something like "KErrCorrupt".
       
  1115     // If the operation has been successful, we make the entry visible
       
  1116     // and remove the in preparation flag. The user should then be able
       
  1117     // to see the new message entry.
       
  1118 
       
  1119     // free the memory we don't need anymore
       
  1120     if ( iEncodeBuffer )
       
  1121         {
       
  1122         iEncodeBuffer->Reset();
       
  1123         }
       
  1124     TMsvEntry tEntry;
       
  1125     
       
  1126     // Check if the message is going to an unregistered application.
       
  1127     // If it is, it's going to be rejected
       
  1128     iRegistered = EFalse;
       
  1129     
       
  1130     if ( iMmsHeaders->ApplicId().Length() > 0 )
       
  1131         {
       
  1132         iRegistered = RegisteredL( iMmsHeaders->ApplicId() );
       
  1133         if ( !iRegistered )
       
  1134             {
       
  1135             // not registered - reject it
       
  1136             iResponse->SetStatus( KMmsMessageStatusRejected );
       
  1137             // we clear whatever error we may have because we are
       
  1138             // going to reject the message anyway.
       
  1139             iError = KErrNone;
       
  1140             }
       
  1141         }
       
  1142         
       
  1143     // If the message is going to an application we must check if we can free disk
       
  1144     // space by deleting older messages addressed to the same application.
       
  1145     
       
  1146     if ( iError == KErrDiskFull && iRegistered )
       
  1147         {
       
  1148         // Check if we can free disk space and reschedule the fetch.
       
  1149         // In manual mode the fetch will not be rescheduled.
       
  1150         // If we can free memory we will change the error code to KMmsErrorApplicationDiskFull
       
  1151         // If we cannot free memory, the error code is left as is and the user must
       
  1152         // delete something else in order to be able to receive the message.
       
  1153         DeleteApplicationMessagesL();
       
  1154         }
       
  1155 
       
  1156     // If we have tried to fetch a message, and got 
       
  1157     // EMRUExceeded, we'll reject the message. If it
       
  1158     // was already deferred, no new response is sent.
       
  1159     // The notification will be deleted, it is hopeless.
       
  1160 
       
  1161     if ( iError == KMmsErrorEMRUExceeded )
       
  1162         {
       
  1163         iResponse->SetStatus( KMmsMessageStatusRejected );
       
  1164         iFailed->Delete( iCurrentMessageNo - 1 );
       
  1165         iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1166         }
       
  1167 
       
  1168     if ( iError != KErrNone ||
       
  1169         iResponse->Status() == KMmsMessageStatusRejected ||
       
  1170         iResponse->Status() == KMmsMessageStatusDeferred ||
       
  1171         iResponse->Status() == KMmsMessageStatusRetrieved ||
       
  1172         iResponse->Status() == KMmsMessageStatusUnrecognized )
       
  1173         {
       
  1174         // If the failure was fatal (permanent error from MMSC)
       
  1175         // we don't send any response back. If the failure was
       
  1176         // not fatal, we send "deferred" hoping we can retry later
       
  1177         if ( fatal )
       
  1178             {
       
  1179             // The notification is deleted, as we have got an MMS message.
       
  1180             iFailed->Delete( iCurrentMessageNo - 1 );
       
  1181             iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1182             // we don't send back a response if failing was fatal.
       
  1183             iResponse->Reset();
       
  1184             }
       
  1185         else if ( iError == KMmsErrorHTTPConfiguration ||
       
  1186             iError == KMmsErrorHTTPNotFound ||
       
  1187             iError == KMmsErrorHTTPServerDown ||
       
  1188             iError == KMmsErrorHTTPClientError )
       
  1189             {
       
  1190             // if we have got a HTTP error, there is no sense to send ack back
       
  1191             iResponse->Reset();
       
  1192             }
       
  1193         else if ( !iAlreadyDeferred &&
       
  1194             iResponse->Status() != KMmsMessageStatusRejected &&
       
  1195             iResponse->Status() != KMmsMessageStatusRetrieved &&
       
  1196             iResponse->Status() != KMmsMessageStatusUnrecognized)
       
  1197             {
       
  1198             iResponse->SetStatus( KMmsMessageStatusDeferred );
       
  1199             EncodeNotifyResponseL();
       
  1200             }
       
  1201         else if ( iResponse->Status() == KMmsMessageStatusUnrecognized || 
       
  1202             iResponse->Status() == KMmsMessageStatusRejected)
       
  1203             {
       
  1204             EncodeNotifyResponseL();
       
  1205             }
       
  1206         else if ( iResponse->Status() == KMmsMessageStatusRetrieved )
       
  1207             {
       
  1208             EncodeNotifyResponseL();
       
  1209             iFailed->Delete( iCurrentMessageNo - 1 );
       
  1210             iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1211             }
       
  1212         else
       
  1213             {
       
  1214             // We have nothing to send, we hope we can try
       
  1215             // again later.
       
  1216             iResponse->Reset();
       
  1217             }
       
  1218         }
       
  1219 
       
  1220 #ifndef _NO_MMSS_LOGGING_
       
  1221     // log the response status we are about to send
       
  1222     TMmsLogger::Log( _L("- Response status to be: %d"), iResponse->Status() );
       
  1223 #endif
       
  1224 
       
  1225     // If we have no entry, the fetching has failed. If the failing was fatal,
       
  1226     // the notification has been appended to the iBad list.
       
  1227     // It will be deleted from the iFailed list later.
       
  1228     // Those entries that end in the iBad list are just
       
  1229     // deleted, not rescheduled.
       
  1230     
       
  1231     TInt applicationMessageStatus = 0;
       
  1232     
       
  1233     // If we got an error, we delete the entry under construction.
       
  1234     // But if the error is "fatal" it means MMSC returned some error message,
       
  1235     // and the error message entry must be kept and shown to the user
       
  1236     // The corresponding notification remains in the failed list
       
  1237     // in order to be rescheduled.
       
  1238     // If the notification was bad, the corresponding notification
       
  1239     // has already been appended to bad list to be removed from 
       
  1240     // task scheduler.
       
  1241     if ( iEntryUnderConstruction != KMsvNullIndexEntryId && iError != KErrNone && !fatal )
       
  1242         {
       
  1243         if ( iMmsSettings->LocalMode() )
       
  1244             {
       
  1245             CloseLocalFileL( EFalse );
       
  1246             }
       
  1247         // if setting server entry to inbox fails, deletion of entry will fail,
       
  1248         // but there is nothing we can do about it.    
       
  1249         iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId );
       
  1250         iServerEntry->DeleteEntry ( iEntryUnderConstruction );
       
  1251         iEntryUnderConstruction = KMsvNullIndexEntryId;
       
  1252         }
       
  1253         
       
  1254     if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
       
  1255         {
       
  1256         // We don't care if this leaves. We just do our best.
       
  1257         // If this function fails, our message will have some extra parts
       
  1258         TRAP( error, HandleMultipartAlternativeL() );
       
  1259         }
       
  1260     
       
  1261     // If we have an entry we have either successfully fetched a message
       
  1262     // or received an error message about a fatal (permanent) error from MMSC
       
  1263     // The entry must now be made visible to the user.    
       
  1264     if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
       
  1265         {
       
  1266         error = iServerEntry->SetEntry( iEntryUnderConstruction );
       
  1267 
       
  1268         if ( error == KErrNone )
       
  1269             {
       
  1270             // we don't check disk space here, as this
       
  1271             // is local mode only: We just save the message id
       
  1272             // for testing purposes. The message id is about 5 bytes
       
  1273             // And we clear possible TID, that makes message shorter than before.
       
  1274             CMsvStore* store = NULL;
       
  1275             TRAP ( error, store = iServerEntry->EditStoreL() )
       
  1276             if ( store )
       
  1277                 {
       
  1278                 CleanupStack::PushL( store );
       
  1279                 }
       
  1280             if ( iMmsSettings->LocalMode() &&
       
  1281                 iMmsHeaders->MessageId().Length() == 0 )
       
  1282                 {
       
  1283                 iMmsHeaders->SetMessageIdL(
       
  1284                     iNotification->ContentLocation().Mid(
       
  1285                     iMmsSettings->LocalModeIn().Length() ) );
       
  1286                 }
       
  1287             if ( iAlreadyDeferred )
       
  1288                 {
       
  1289                 // we need to save the TID from the message to the response
       
  1290                 iResponse->SetTidL( iMmsHeaders->Tid() );
       
  1291                 }
       
  1292             // clear TID from the message to prevent the same TID from being used later
       
  1293             // in case the message is copied around.
       
  1294             iMmsHeaders->SetTidL( TPtrC8() );
       
  1295             // Data is copied in case the message does not contain sender or subject
       
  1296             // Data is copied only if disk space is not below critical level
       
  1297             CopyDataFromNotificationToMessageL();
       
  1298             if ( store )
       
  1299                 {
       
  1300                 TRAP ( error, 
       
  1301                     {
       
  1302                     iMmsHeaders->StoreL(*store);
       
  1303                     store->CommitL();
       
  1304                     });
       
  1305                 // If we managed to create the store without leaving, it is on cleanup stack
       
  1306                 CleanupStack::PopAndDestroy( store );
       
  1307                 store = NULL;
       
  1308                 }
       
  1309             if ( iAlreadyDeferred )
       
  1310                 {
       
  1311                 // restore the TID
       
  1312                 iMmsHeaders->SetTidL( iResponse->Tid() );
       
  1313                 }
       
  1314 
       
  1315             tEntry = iServerEntry->Entry();
       
  1316             
       
  1317             // If message contains application id, check, 
       
  1318             // if a folder, the name of which is application id is found
       
  1319             // and move the message to this folder.
       
  1320             // If the application is not registered, the message is deleted
       
  1321             applicationMessageStatus = MoveToApplicationFolderIfNeededL( tEntry );
       
  1322             
       
  1323             if ( applicationMessageStatus != KMmsMessageForUnregisteredApplication )
       
  1324                 {
       
  1325                 // reload the entry in case the message was moved
       
  1326                 tEntry = iServerEntry->Entry();
       
  1327                             
       
  1328                 SetIndexEntryBitsForReceivedMessage( tEntry );
       
  1329 
       
  1330                 // if we cannot make our entry visible because of backup/restore, we must retry.
       
  1331                 error = iServerEntry->ChangeEntry( tEntry );
       
  1332 
       
  1333                 // This is the critical point.
       
  1334                 // We must return before iEntryUnderConstruction is set to KMsvNullIndexEntryId
       
  1335                 // and the notification list is edited
       
  1336 
       
  1337                 if ( error <= (TInt) KMsvMediaUnavailable &&
       
  1338                     error >= (TInt) KMsvIndexRestore &&
       
  1339                     !iDoNotWaitForBackupEnd )
       
  1340                     {
       
  1341 #ifndef _NO_MMSS_LOGGING_
       
  1342                     TMmsLogger::Log( _L("- must wait for backup end ") );
       
  1343 #endif
       
  1344                     iState = EMmsOperationWaitingForBackupEnd;
       
  1345                     // This will take us back to RunL
       
  1346                     WaitForBackupEnd();
       
  1347                     return;
       
  1348                     }
       
  1349                 }
       
  1350 
       
  1351             if ( iMmsSettings->LocalMode() )
       
  1352                 {
       
  1353                 CloseLocalFileL( ETrue );
       
  1354                 }
       
  1355 
       
  1356             // done with this entry
       
  1357             iEntryUnderConstruction = KMsvNullIndexEntryId;
       
  1358             }
       
  1359 
       
  1360         // The task manager seems to handle deletion of entries
       
  1361         // gracefully nowadays. We can just delete handled entries
       
  1362         // We delete the notification as soon as possible
       
  1363         // as we don't want it hanging around after the message
       
  1364         // has been successfully fetched
       
  1365 
       
  1366         if ( !fatal )
       
  1367             {
       
  1368             // Check duplicate before deleting notification entry
       
  1369             if ( iNotificationParent == KMsvGlobalInBoxIndexEntryIdValue ||
       
  1370                 ( iNotificationParent == iMmsSettings->MMBoxFolder() ))
       
  1371                 {
       
  1372                 // For the time being Java wants these notifications to be deleted
       
  1373                 // and applicationMessageStatus is always 0.
       
  1374                 // This may change for other type of applications.
       
  1375                 ClearOperationL( applicationMessageStatus );
       
  1376                 }
       
  1377             else
       
  1378                 {
       
  1379                 // If the notification is not visible to the user,
       
  1380                 // we don't need to save the application routing status.
       
  1381                 // The rest of the handling can proceed normally - 
       
  1382                 // the notification will be deleted
       
  1383                 applicationMessageStatus = 0;
       
  1384                 }
       
  1385 
       
  1386             // If the notification does not need to be left around to inform user,
       
  1387             // it can be deleted now                    
       
  1388             if ( applicationMessageStatus == 0 )
       
  1389                 {
       
  1390                 error = iServerEntry->SetEntry( iNotificationParent );
       
  1391                 if ( error == KErrNone )
       
  1392                     {
       
  1393                     iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1394                     }
       
  1395                 else
       
  1396                     {
       
  1397                     // we use this list as backup:
       
  1398                     // if we cannot delete now, we try again later.
       
  1399                     iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1400                     }
       
  1401                 }
       
  1402             // Even if the notification was left in the inbox,
       
  1403             // it is deleted from the failed list because it needs no more handling    
       
  1404             iFailed->Delete( iCurrentMessageNo - 1 );
       
  1405             
       
  1406             // All went well. We can acknowledge the delivery.
       
  1407             // If the MMSC is not interested in the acknowledgement,
       
  1408             // it has sent us no TID.
       
  1409             // If there is no TID, the response won't be sent.
       
  1410             // If Retrieve confirmation has not been sent, it must be
       
  1411             // sent instead of acknowledge indication
       
  1412             
       
  1413             // We don't send an ack back if we have received a response
       
  1414             // from MMSC that indicates a fatal failure.
       
  1415             // Most likely the message was expired or has disappeared
       
  1416             // for some other reason (or did not exist in the first place)
       
  1417             
       
  1418             iResponse->SetStatus( KMmsMessageStatusRetrieved );
       
  1419             if ( !iAlreadyDeferred )
       
  1420                 {
       
  1421                 EncodeNotifyResponseL();
       
  1422                 }
       
  1423             else
       
  1424                 {
       
  1425                 EncodeAcknowledgeIndicationL();
       
  1426                 }
       
  1427             }
       
  1428         }
       
  1429 
       
  1430     if ( iFileOpen )
       
  1431         {
       
  1432         iFile.Close(); // just in case...
       
  1433         iFileOpen = EFalse;
       
  1434         }
       
  1435         
       
  1436     // release entry in case we were holding the service entry
       
  1437     // We should not leave our entry pointing to the serive entry 
       
  1438     // when we become active, others may want to use it.
       
  1439     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1440 
       
  1441     iStatus = KRequestPending;
       
  1442     SetActive();
       
  1443     TRequestStatus* status = &iStatus;
       
  1444     // We propagate the original error no matter what has happened here
       
  1445     User::RequestComplete( status, iError );
       
  1446 
       
  1447     }
       
  1448 
       
  1449 // ---------------------------------------------------------
       
  1450 // CMmsReceiveMessage::SendAckL
       
  1451 //
       
  1452 // ---------------------------------------------------------
       
  1453 //
       
  1454 void CMmsReceiveMessage::SendAckL()
       
  1455     {
       
  1456 #ifndef _NO_MMSS_LOGGING_
       
  1457     TMmsLogger::Log( _L("Receivemsg Sending response to receive request") );
       
  1458 #endif
       
  1459 
       
  1460     // Send response to MMSC.
       
  1461     // response is in iResponse.
       
  1462     // If no reply should actually be sent, length of TID is 0.
       
  1463 
       
  1464     // We may try to send response even if we have encountered an error.
       
  1465     // We try to send "deferred" if we couldn't fetch the message.
       
  1466     // We hope the MMSC will try to keep the message in that case.
       
  1467 
       
  1468     // iResponse has Tid, if it contains something reasonable.
       
  1469 
       
  1470     if ( iResponse->Tid().Length() > 0 )
       
  1471         {
       
  1472         if ( !iMmsSettings->LocalMode() )
       
  1473             {
       
  1474             // send the response
       
  1475             iMmsSession->SendMessageL(
       
  1476                 iUri->Des(),
       
  1477                 *iEncodeBuffer,
       
  1478                 *iEncoder,
       
  1479                 *iDecoder,
       
  1480                 iStatus );
       
  1481             SetActive();
       
  1482             }
       
  1483         else
       
  1484             {
       
  1485             iStatus = KRequestPending;
       
  1486             SetActive();
       
  1487             TRequestStatus* status = &iStatus;
       
  1488             // We propagate the original error no matter what has happened here
       
  1489             User::RequestComplete( status, iError );
       
  1490             }
       
  1491         }
       
  1492     else
       
  1493         {
       
  1494         // No response to send.
       
  1495         // Just continue to next state.
       
  1496         iStatus = KRequestPending;
       
  1497         SetActive();
       
  1498         TRequestStatus* status = &iStatus;
       
  1499         // We propagate the original error no matter what has happened here
       
  1500         User::RequestComplete( status, iError );
       
  1501         }
       
  1502     }
       
  1503 
       
  1504 // ---------------------------------------------------------
       
  1505 // CMmsReceiveMessage::UpdateEntryStatusL()
       
  1506 //
       
  1507 // ---------------------------------------------------------
       
  1508 //
       
  1509 void CMmsReceiveMessage::UpdateEntryStatusL()
       
  1510     {
       
  1511 
       
  1512 #ifndef _NO_MMSS_LOGGING_
       
  1513     TMmsLogger::Log( _L("Receivemsg Checking response success") );
       
  1514 #endif
       
  1515     
       
  1516     TInt error;
       
  1517     TMsvEntry tEntry;
       
  1518     TInt count = iBad->Count() - 1;
       
  1519 
       
  1520     // update scheduling info for this notification
       
  1521     error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1522     if ( error == KErrNone )
       
  1523         {
       
  1524         tEntry = iServerEntry->Entry();
       
  1525         error = tEntry.iError;
       
  1526         if ( error == KErrNone )
       
  1527             {
       
  1528             error = iError;
       
  1529             }
       
  1530         // In some rare cases accessing the store for the notification may fail
       
  1531         // in that case the schedule is not updated.
       
  1532         TRAP( error,
       
  1533             {
       
  1534             CMsvStore* store = iServerEntry->EditStoreL();
       
  1535             CleanupStack::PushL( store );
       
  1536             CMmsScheduledEntry* mmsScheduledEntry =
       
  1537                 CMmsScheduledEntry::NewL( iServerEntry->Entry() );
       
  1538             CleanupStack::PushL( mmsScheduledEntry );
       
  1539             mmsScheduledEntry->RestoreL( *store );
       
  1540             UpdateRecipient( iError, *mmsScheduledEntry );
       
  1541             mmsScheduledEntry->StoreL( *store );
       
  1542             store->CommitL();
       
  1543             CleanupStack::PopAndDestroy( mmsScheduledEntry );
       
  1544             CleanupStack::PopAndDestroy( store );
       
  1545             });
       
  1546         }
       
  1547 
       
  1548     // If the current notification has entered the "bad" list,
       
  1549     // it should not be rescheduled.
       
  1550     // For example, the message may be "deferred" because it is too
       
  1551     // big to ever fit in our phone. It must be deleted from the "failed"
       
  1552     // list, because it should not be rescheduled.
       
  1553 
       
  1554     TInt count2 = iFailed->Count() - 1;
       
  1555     if ( count >= 0 &&
       
  1556         count2 >= ( iCurrentMessageNo - 1 ) &&
       
  1557         iBad->At( count ) == iFailed->At( iCurrentMessageNo - 1 ) )
       
  1558         {
       
  1559         // should not be rescheduled.
       
  1560         iFailed->Delete( iCurrentMessageNo - 1 );
       
  1561         }
       
  1562     else if ( iError == KErrNone )
       
  1563         {
       
  1564 
       
  1565 #ifndef _NO_MMSS_LOGGING_
       
  1566         TMmsLogger::Log( _L("Receivemsg all is well") );
       
  1567 #endif
       
  1568         // All is well.
       
  1569         // If message was rejected the notification can be thrown away
       
  1570         
       
  1571         if ( iResponse->Status() == KMmsMessageStatusRejected ||
       
  1572              iResponse->Status() == KMmsMessageStatusUnrecognized )
       
  1573             {
       
  1574             // The notifications in the received list will be deleted.
       
  1575             // If the message was rejected, the notification will be
       
  1576             // deleted.
       
  1577             error = iServerEntry->SetEntry( iNotificationParent );
       
  1578             if ( error == KErrNone )
       
  1579                 {
       
  1580                 iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1581                 }
       
  1582             else
       
  1583                 {
       
  1584                 // we use this list as backup:
       
  1585                 // if we cannot delete now, we try again later.
       
  1586                 iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1587                 }
       
  1588             iFailed->Delete( iCurrentMessageNo - 1 );
       
  1589             }
       
  1590 
       
  1591         if ( iResponse->Status() == KMmsMessageStatusDeferred )
       
  1592             {
       
  1593 
       
  1594 #ifndef _NO_MMSS_LOGGING_
       
  1595             TMmsLogger::Log( _L("Receivemsg responsestatus is deferred.") );
       
  1596 #endif
       
  1597             // we have sent a "deferred" response.
       
  1598             // We should keep the notification, but not reschedule it.
       
  1599             // If we delete it from failed list, it wont get rescheduled.
       
  1600             // If we don't add it into received list, it will not be deleted.
       
  1601             // We must mark, that the "deferred" response was successfully sent
       
  1602             // so that we will not send it again later.
       
  1603 
       
  1604             error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1605             // If we cannot update our entry - that's too bad
       
  1606             // it just means that the response may be sent a second time...
       
  1607             // The system must not get mad about that.
       
  1608             // The system may be unreliable anyway, and some response may get lost.
       
  1609             // We just do our best.
       
  1610             if ( error == KErrNone )
       
  1611                 {
       
  1612                 iNotification->SetStatus( KMmsMessageStatusDeferred );
       
  1613                 CMsvStore * store = iServerEntry->EditStoreL();
       
  1614                 CleanupStack::PushL( store );
       
  1615                 iNotification->StoreL( *store );
       
  1616                 store->CommitL();
       
  1617                 CleanupStack::PopAndDestroy( store );
       
  1618                 tEntry = iServerEntry->Entry();
       
  1619                 tEntry.iMtmData2 |= KMmsNotifyResponseSent;
       
  1620                 tEntry.iMtmData2 &= ~KMmsDeferredButResponseNotSent;
       
  1621                 tEntry.SetConnected( EFalse );
       
  1622                 tEntry.SetFailed( EFalse );
       
  1623                 tEntry.SetSendingState( KMsvSendStateUnknown );
       
  1624 
       
  1625 #ifndef _NO_MMSS_LOGGING_
       
  1626                 TMmsLogger::Log( _L("Receivemsg notify response sent") );
       
  1627 #endif
       
  1628 
       
  1629                 // change the iMtm type to notification 
       
  1630                 // and move the notification to the inbox
       
  1631                 TBool moveToInbox = EFalse;
       
  1632                 
       
  1633 #ifndef _NO_MMSS_LOGGING_
       
  1634                 TMmsLogger::Log( _L("- message receiving mode %d"), iReceivingMode );
       
  1635 #endif
       
  1636                 if( iReceivingMode == EMmsReceivingManual && !iMmsSettings->FetchOverride() )
       
  1637                     {          
       
  1638                     // Change the iMtm from KUidMsgTypeMultimedia to 
       
  1639                     // KUidMsgMMSNotification   
       
  1640                     tEntry.iMtm = KUidMsgMMSNotification;
       
  1641 #ifndef _NO_MMSS_LOGGING_
       
  1642                     TMmsLogger::Log( _L("marking as a notification") );
       
  1643 #endif
       
  1644 
       
  1645 #ifndef _NO_MMSS_LOGGING_
       
  1646 TMmsLogger::Log( _L("tentry.iMtm is %d"), tEntry.iMtm.iUid );
       
  1647 #endif
       
  1648                     tEntry.SetVisible( ETrue );
       
  1649                     tEntry.SetComplete( ETrue );
       
  1650                     tEntry.SetInPreparation( EFalse );
       
  1651                     tEntry.SetReadOnly( ETrue );
       
  1652                     // This is a notification, therefore there is no sending time available.
       
  1653                     // We can only display the arrival time
       
  1654                     tEntry.iDate.UniversalTime(); // this is arrival time
       
  1655                     
       
  1656                     tEntry.iMtmData1 |= KMmsMessageMobileTerminated;
       
  1657             
       
  1658                     // Subject, sender and size are set in CMmsDecode.
       
  1659                     // Notification cannot contain multiple recipients
       
  1660                     // no need to check or set the multiple recipient bit
       
  1661                     
       
  1662                     moveToInbox = ETrue;
       
  1663                     }
       
  1664                 iServerEntry->ChangeEntry( tEntry );
       
  1665 
       
  1666                            
       
  1667                 // if manual mode is on and the fetchoverride is not on.
       
  1668                 // we have received a notification and sent a notifyresponse to the MMSC
       
  1669                 // the notification should be moved to the inbox
       
  1670                 if ( moveToInbox )
       
  1671                     {
       
  1672 
       
  1673 #ifndef _NO_MMSS_LOGGING_
       
  1674                     TMmsLogger::Log( _L("Receivemsg notification entry to Inbox") );
       
  1675 #endif
       
  1676                    
       
  1677                     if ( iServerEntry->SetEntry( tEntry.Parent() ) == KErrNone )
       
  1678                         {
       
  1679                         iServerEntry->MoveEntryWithinService( tEntry.Id(),
       
  1680                             KMsvGlobalInBoxIndexEntryIdValue );
       
  1681                         }
       
  1682                     }
       
  1683                 }
       
  1684             
       
  1685             if ( iReceivingMode != EMmsReceivingAutomatic && !iMmsSettings->FetchOverride() )
       
  1686                 {
       
  1687                 // If fetching is on, the message was deferred because of an error.
       
  1688                 // In that case we let it remain in the failed list for retries.
       
  1689                 // If fetching is deferred, manual or off, we don't keep the failed list,
       
  1690                 // The receiving mode must be changed before we retry the operation.
       
  1691 
       
  1692                 // Should we remove the schedule...
       
  1693                 iFailed->Delete( iCurrentMessageNo - 1 );
       
  1694 #ifndef _NO_MMSS_LOGGING_
       
  1695                 TMmsLogger::Log( _L("Receivemsg deleting from the iFailedList") );
       
  1696 #endif
       
  1697                 }
       
  1698             }
       
  1699         }
       
  1700     else
       
  1701         {
       
  1702         // keep LINT happy
       
  1703         }
       
  1704 
       
  1705     // release entry in case we were holding the service entry
       
  1706     // We should not leave our entry pointing to the serive entry 
       
  1707     // when we become active, others may want to use it.
       
  1708     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  1709     // just return back to the start of the loop
       
  1710     // to handle next message
       
  1711     iStatus = KRequestPending;
       
  1712     SetActive();
       
  1713     TRequestStatus* status = &iStatus;
       
  1714     // We propagate the original error no matter what has happened here
       
  1715     User::RequestComplete( status, iError );
       
  1716 
       
  1717     }
       
  1718 
       
  1719 // ---------------------------------------------------------
       
  1720 // CMmsReceiveMessage::EncodeNotifyResponseL
       
  1721 //
       
  1722 // ---------------------------------------------------------
       
  1723 //
       
  1724 void CMmsReceiveMessage::EncodeNotifyResponseL()
       
  1725     {
       
  1726 #ifndef _NO_MMSS_LOGGING_
       
  1727     TMmsLogger::Log( _L("- encoding m-notifyresp-ind") );
       
  1728 #endif
       
  1729     iResponse->SetMessageType( KMmsMessageTypeMNotifyRespInd );
       
  1730     iResponse->SetTidL( iNotification->Tid() );
       
  1731     // message status has been set before we are called.
       
  1732     iResponse->SetReportAllowed( iMmsSettings->DeliveryReportSendingAllowed() );
       
  1733     iEncoder->EncodeHeadersL( *iResponse, *iEncodeBuffer );
       
  1734     }
       
  1735 
       
  1736 // ---------------------------------------------------------
       
  1737 // CMmsReceiveMessage::EncodeAcknowledgeIndicationL
       
  1738 //
       
  1739 // ---------------------------------------------------------
       
  1740 //
       
  1741 void CMmsReceiveMessage::EncodeAcknowledgeIndicationL()
       
  1742     {
       
  1743 #ifndef _NO_MMSS_LOGGING_
       
  1744     TMmsLogger::Log( _L("- encoding m-acknowledge-ind") );
       
  1745 #endif
       
  1746     iResponse->SetMessageType( KMmsMessageTypeAcknowledgeInd );
       
  1747     
       
  1748     // The TID has already been set to iResponse earlier, do not override it here
       
  1749     
       
  1750     // version value is set by the encoder.
       
  1751     // This response has no status. It is only sent when the status is "Retrieved"
       
  1752     iResponse->SetReportAllowed( iMmsSettings->DeliveryReportSendingAllowed() );
       
  1753     iEncoder->EncodeHeadersL( *iResponse, *iEncodeBuffer );
       
  1754     }
       
  1755 
       
  1756 // ---------------------------------------------------------
       
  1757 // CMmsReceiveMessage::HandleMultipartAlternativeL()
       
  1758 //
       
  1759 // ---------------------------------------------------------
       
  1760 //
       
  1761 void CMmsReceiveMessage::HandleMultipartAlternativeL()
       
  1762     {
       
  1763     // This is just "best effort"
       
  1764     // If we cannot properly clear the extra attachments, they are just left "as is"
       
  1765     
       
  1766     if ( iMmsHeaders->MultipartType() != KMmsAssignedApplicationVndWapMultipartAlternative )
       
  1767         {
       
  1768         return; // nothing to do
       
  1769         }
       
  1770 
       
  1771     User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iEntryUnderConstruction ) );
       
  1772     CMsvStore* store = iEntryWrapper->EditStoreL();
       
  1773     CleanupStack::PushL( store );
       
  1774     
       
  1775     MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
       
  1776     MMsvAttachmentManagerSync& attachManSync = store->AttachmentManagerExtensionsL();
       
  1777     
       
  1778     TInt count = attachMan.AttachmentCount();
       
  1779 
       
  1780     if ( count <= 1 )
       
  1781         {
       
  1782         CleanupStack::PopAndDestroy( store );
       
  1783         return; // only one part, keep it
       
  1784         }
       
  1785 
       
  1786     TInt i;
       
  1787     CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
       
  1788     CleanupStack::PushL( mimeHeaders );
       
  1789 
       
  1790     for ( i = count; i > 0; i-- )
       
  1791         {
       
  1792         CMsvAttachment* attachInfo = attachMan.GetAttachmentInfoL( i - 1 );
       
  1793         CleanupStack::PushL( attachInfo );
       
  1794         TPtrC8 pointer;
       
  1795         pointer.Set( attachInfo->MimeType() );
       
  1796         HBufC8* temp = NULL;
       
  1797         if ( pointer.Length() == 0 )
       
  1798             {
       
  1799             // mime type not set. Try mime headers
       
  1800             mimeHeaders->RestoreL( *attachInfo );
       
  1801             temp = HBufC8::NewL( mimeHeaders->ContentType().Length() +
       
  1802                 mimeHeaders->ContentSubType().Length() + 1 );
       
  1803             temp->Des().Copy( mimeHeaders->ContentType() );
       
  1804             temp->Des().Append( KMmsSlash8 );
       
  1805             temp->Des().Append( mimeHeaders->ContentSubType() );
       
  1806             pointer.Set( temp->Des() );
       
  1807             }
       
  1808         CleanupStack::PushL( temp );                
       
  1809         if ( pointer.CompareF( KMmsTextPlain ) != 0 )
       
  1810             {
       
  1811             attachManSync.RemoveAttachmentL( i - 1 );
       
  1812             count--;
       
  1813             }
       
  1814         CleanupStack::PopAndDestroy( temp );
       
  1815         CleanupStack::PopAndDestroy( attachInfo );
       
  1816         temp = NULL; 
       
  1817         attachInfo = NULL;
       
  1818         }
       
  1819 
       
  1820     if ( count > 0 )
       
  1821         {
       
  1822         // we have something left in the selection
       
  1823         // When we commit the store, deleted attachments should disappear
       
  1824         store->CommitL();
       
  1825         }
       
  1826 
       
  1827     CleanupStack::PopAndDestroy( mimeHeaders );
       
  1828     CleanupStack::PopAndDestroy( store );
       
  1829     iEntryWrapper->SetCurrentEntry( KMsvNullIndexEntryId );
       
  1830     }
       
  1831 
       
  1832 // ---------------------------------------------------------
       
  1833 // CMmsReceiveMessage::::EncodePDUL
       
  1834 //
       
  1835 // ---------------------------------------------------------
       
  1836 //
       
  1837 void CMmsReceiveMessage::EncodePDUL()
       
  1838     {
       
  1839     // This state is used to check what must be done to the notification
       
  1840 #ifndef _NO_MMSS_LOGGING_
       
  1841     TMmsLogger::Log( _L("CMmsReceiveMessage EncodePDUL - Finalize of continue"));
       
  1842 #endif
       
  1843 
       
  1844     iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1845     
       
  1846     if ( iError != KErrNone )
       
  1847         {
       
  1848         // The code called by SkipEntryL will make us active again
       
  1849         SkipEntryL();
       
  1850         return;
       
  1851         }
       
  1852         
       
  1853     TMsvEntry tEntry;
       
  1854     tEntry = iServerEntry->Entry();
       
  1855         
       
  1856     if ( iReceivingMode == EMmsReceivingAutomatic || iMmsSettings->FetchOverride() )
       
  1857         {
       
  1858         // if notification is in Inbox, set the fetch flags on
       
  1859         if ( tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )
       
  1860             {
       
  1861             // mark the flags to reserve the notification for fetch
       
  1862             MarkNotificationOperationReserved( tEntry, KMmsOperationFetch );
       
  1863             
       
  1864             iServerEntry->ChangeEntry( tEntry );
       
  1865             #ifndef _NO_MMSS_LOGGING_
       
  1866             TMmsLogger::Log( _L("mark notification that is being fetched") );
       
  1867             #endif
       
  1868             }
       
  1869         // continue fetching
       
  1870         FallThrough();
       
  1871         return;  
       
  1872         }
       
  1873 
       
  1874     // mode is deferred of reject
       
  1875     
       
  1876     // entry is in inbox - clear flags and leave it
       
  1877     if ( tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )
       
  1878         {
       
  1879         tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
       
  1880         tEntry.SetReadOnly( ETrue );
       
  1881         iServerEntry->ChangeEntry( tEntry );
       
  1882         #ifndef _NO_MMSS_LOGGING_
       
  1883         TMmsLogger::Log( _L("notification in inbox. Let it be") );
       
  1884         #endif
       
  1885         LoopToNextEntryL();
       
  1886         return;
       
  1887         }
       
  1888     
       
  1889     // entry is in mms folder or mmbox folder
       
  1890 
       
  1891     // already deferred - leave it and loop to next entry
       
  1892     if ( tEntry.iMtmData2 & KMmsNotifyResponseSent )
       
  1893         {
       
  1894         #ifndef _NO_MMSS_LOGGING_
       
  1895         TMmsLogger::Log( _L("notification already deferred. Let it be") );
       
  1896         #endif
       
  1897         tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
       
  1898         iServerEntry->ChangeEntry( tEntry );
       
  1899         LoopToNextEntryL();
       
  1900         return;
       
  1901         }  
       
  1902         
       
  1903     // reject mode is on 
       
  1904     if ( iReceivingMode == EMmsReceivingReject )
       
  1905         {
       
  1906         // Let the notification be, if we have received this notification 
       
  1907         // earlier in the manual or postpone mode when we have roamed.
       
  1908         // In that case KMmsDeferredButResponseNotSent flag is set.
       
  1909         // Delete it, if it is a new one that has arrives while we are in reject mode 
       
  1910         tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
       
  1911         iServerEntry->ChangeEntry( tEntry );
       
  1912         if ( !( tEntry.iMtmData2 & KMmsDeferredButResponseNotSent ) )
       
  1913             {
       
  1914             #ifndef _NO_MMSS_LOGGING_
       
  1915             TMmsLogger::Log( _L("deleting the notification") );
       
  1916             #endif
       
  1917             // we ignore the error. If setting entry to parent fails, deletion will fail
       
  1918             iServerEntry->SetEntry( tEntry.Parent() );
       
  1919             iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1920             }               
       
  1921         LoopToNextEntryL();
       
  1922         return;
       
  1923         }
       
  1924  
       
  1925     // deferred and response not yet sent
       
  1926     
       
  1927     if ( iRegistrationStatus == 0 ) // home network - continue
       
  1928         {
       
  1929         #ifndef _NO_MMSS_LOGGING_
       
  1930         TMmsLogger::Log( _L("in homenw and deferred mode") );
       
  1931         #endif
       
  1932         // continue fetching - will send "deferred" response
       
  1933         FallThrough();
       
  1934         return;  
       
  1935         }
       
  1936         
       
  1937     // state is deferred, and we are roaming    
       
  1938     
       
  1939     // if the status of the notification is retrieved, this
       
  1940     // notification will be deleted.
       
  1941     // This happens if the notification was extended notification 
       
  1942     // and the whole message arrived in the notification.
       
  1943     // When roaming, no response is sent. The extended notification
       
  1944     // is already in the inbox. This notification is deleted.
       
  1945 
       
  1946     CMsvStore* store = iServerEntry->ReadStoreL();
       
  1947     CleanupStack::PushL( store );
       
  1948     iNotification->RestoreL( *store );
       
  1949     CleanupStack::PopAndDestroy( store );
       
  1950     store = NULL;
       
  1951     
       
  1952     if ( iNotification->Status() == KMmsMessageStatusRetrieved )
       
  1953         {
       
  1954         #ifndef _NO_MMSS_LOGGING_
       
  1955         TMmsLogger::Log( _L(" the whole extended notification received") );
       
  1956         TMmsLogger::Log( _L("deleting the notification") );
       
  1957         #endif
       
  1958         // ignore error, if setting parent fails, deletion will fail
       
  1959         iServerEntry->SetEntry( tEntry.Parent() );
       
  1960         iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  1961         LoopToNextEntryL();
       
  1962         return;
       
  1963         }
       
  1964         
       
  1965     // The notification is not completely fetched, finalize flags    
       
  1966     
       
  1967     #ifndef _NO_MMSS_LOGGING_
       
  1968     TMmsLogger::Log( _L("Finalizing the notification") );
       
  1969     #endif
       
  1970     iNotification->SetStatus( KMmsMessageStatusDeferred );
       
  1971     store = iServerEntry->EditStoreL();
       
  1972     CleanupStack::PushL( store );
       
  1973     iNotification->StoreL( *store );
       
  1974     store->CommitL();
       
  1975     CleanupStack::PopAndDestroy( store );
       
  1976     store = NULL;
       
  1977 
       
  1978     tEntry.SetConnected( EFalse );
       
  1979     tEntry.SetFailed( EFalse );
       
  1980     tEntry.SetSendingState( KMsvSendStateUnknown );
       
  1981 
       
  1982     tEntry.iMtmData1 |= KMmsMessageMobileTerminated;
       
  1983 
       
  1984     // When roaming it is not allowed to send a notify response
       
  1985     // to MMSC.
       
  1986     tEntry.iMtmData2 |= KMmsDeferredButResponseNotSent;
       
  1987 
       
  1988     // The receiving mode is either manual or postpone, when roaming. 
       
  1989     // If the manual mode is on, the mtm type is changed to notification
       
  1990     // and the notification is moved to Inbox.
       
  1991     // 
       
  1992     if ( iMmsSettings->ReceivingModeForeign() != EMmsReceivingManual )
       
  1993         {
       
  1994         // this is all we need
       
  1995         iServerEntry->ChangeEntry( tEntry );
       
  1996         }
       
  1997     else
       
  1998         {
       
  1999         // Change the iMtm from KUidMsgTypeMultimedia to 
       
  2000         // KUidMsgMMSNotification   
       
  2001         tEntry.iMtm = KUidMsgMMSNotification; 
       
  2002         tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
       
  2003         #ifndef _NO_MMSS_LOGGING_
       
  2004         TMmsLogger::Log( _L("marking as a notification") );
       
  2005         #endif                  
       
  2006         // Readonly flag has to be set on in inbox.
       
  2007         // Not in mms folder
       
  2008         tEntry.SetReadOnly( ETrue );
       
  2009         iServerEntry->ChangeEntry( tEntry );
       
  2010         #ifndef _NO_MMSS_LOGGING_
       
  2011         TMmsLogger::Log( _L("moving to inbox") );
       
  2012         #endif
       
  2013         // Ignore error from set entry. If it fails, move will fail (not panic)
       
  2014         // Setting service entry to a folder should not fail.
       
  2015         iServerEntry->SetEntry( tEntry.Parent() );
       
  2016         iServerEntry->MoveEntryWithinService( tEntry.Id(), KMsvGlobalInBoxIndexEntryIdValue );
       
  2017         }
       
  2018         
       
  2019     LoopToNextEntryL();
       
  2020 
       
  2021     }
       
  2022     
       
  2023 // ---------------------------------------------------------
       
  2024 // CMmsReceiveMessage::::SkipEntryL
       
  2025 //
       
  2026 // ---------------------------------------------------------
       
  2027 //
       
  2028 void CMmsReceiveMessage::SkipEntryL()
       
  2029     {
       
  2030 #ifndef _NO_MMSS_LOGGING_
       
  2031     TMmsLogger::Log( _L("receivemsg - can't access notification") );
       
  2032 #endif
       
  2033     // If the notification cannot be accessed, we must try the next one
       
  2034     // If the notification was not found, or was used by someone else,
       
  2035     // then nothing can be done. Nothing can be done to the scheduling data.
       
  2036 
       
  2037     // We completely discard only entries that cannot be found
       
  2038     if ( iError == KErrNotFound )
       
  2039         {
       
  2040         iFailed->Delete( iCurrentMessageNo - 1 );
       
  2041         }
       
  2042     // we must return to the beginning of the loop without doing anything
       
  2043     iState = EMmsOperationUpdatingEntryStatus;
       
  2044     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2045     // The code called by ChangeStateL will make us active again
       
  2046     ChangeStateL();
       
  2047     }
       
  2048     
       
  2049 // ---------------------------------------------------------
       
  2050 // CMmsReceiveMessage::::LoopToNextEntryL
       
  2051 //
       
  2052 // ---------------------------------------------------------
       
  2053 //
       
  2054 void CMmsReceiveMessage::LoopToNextEntryL()
       
  2055     {
       
  2056     // release entry
       
  2057     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2058     // loop to next entry
       
  2059     iFailed->Delete( iCurrentMessageNo - 1 );
       
  2060     iState = EMmsOperationUpdatingEntryStatus;
       
  2061     SelectNextState();
       
  2062     // The code called by ChangeStateL will make us active again
       
  2063     ChangeStateL();
       
  2064     }
       
  2065     
       
  2066 // ---------------------------------------------------------
       
  2067 // CMmsReceiveMessage::FolderEntryL
       
  2068 //
       
  2069 // ---------------------------------------------------------
       
  2070 //
       
  2071 TInt CMmsReceiveMessage::FolderEntryL(
       
  2072     TMsvId aParent, const TDesC& aFolderName, TMsvId& aFolderId )
       
  2073     {
       
  2074     aFolderId = KMsvNullIndexEntryId;
       
  2075 
       
  2076     TInt error = KErrNone;
       
  2077     
       
  2078     // get a new entry, don't mess up with the original entry.
       
  2079     CMsvServerEntry* workingEntry = NULL;
       
  2080     TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent ) );
       
  2081     CleanupStack::PushL( workingEntry );
       
  2082     
       
  2083     if ( error != KErrNone )
       
  2084         {
       
  2085         CleanupStack::PopAndDestroy( workingEntry ); // workingEntry
       
  2086         return error;
       
  2087         }
       
  2088    
       
  2089     // Show invisible entries
       
  2090     TMsvSelectionOrdering ordering =
       
  2091         TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByIdReverse, ETrue );
       
  2092     workingEntry->SetSort( ordering );
       
  2093     
       
  2094     CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
       
  2095     error = workingEntry->GetChildrenWithType( KUidMsvFolderEntry, *selection );
       
  2096     if ( error == KErrNone )
       
  2097         {           
       
  2098         // If selection contains folders, check if the folder is found.
       
  2099         TInt count = selection->Count();
       
  2100         for ( TInt i = 0; i < count && aFolderId == KMsvNullIndexEntryId; i++ )
       
  2101             {
       
  2102             error = workingEntry->SetEntry( selection->At( i ) );
       
  2103             if ( error == KErrNone )
       
  2104                 {
       
  2105                 // must be exact match
       
  2106                 if ( workingEntry->Entry().iDetails.Compare( aFolderName ) == 0 )
       
  2107                     {
       
  2108                     aFolderId = selection->At( i );
       
  2109                     }                    
       
  2110                 }                           
       
  2111             }
       
  2112         }
       
  2113     delete selection; 
       
  2114     selection = NULL;
       
  2115     CleanupStack::PopAndDestroy( workingEntry );
       
  2116     workingEntry = NULL;
       
  2117     
       
  2118     return error; 
       
  2119         
       
  2120     }
       
  2121  
       
  2122  // -----------------------------------------------------------------------------
       
  2123 // CMmsReceiveMessage::CreateFolderEntryL
       
  2124 //
       
  2125 // -----------------------------------------------------------------------------
       
  2126 //
       
  2127 TInt CMmsReceiveMessage::CreateFolderEntryL(
       
  2128     TMsvId aParentFolder, const TDesC& aFolderName, TMsvId& aFolderId )
       
  2129     {
       
  2130     
       
  2131     // Check if the folder already exists under parent folder.
       
  2132     TInt error = FolderEntryL( aParentFolder, aFolderName, aFolderId );    
       
  2133     if ( aFolderId != KMsvNullIndexEntryId || error != KErrNone )
       
  2134         {
       
  2135         // if error == KErrNone and aFolderId not equal to KMsvNullIndexEntryId
       
  2136         // the folder already exists, and we don't need to create anything
       
  2137         return error;   
       
  2138         }
       
  2139      
       
  2140     CMsvServerEntry* serverEntry = NULL;
       
  2141     TRAP( error, serverEntry = iServerEntry->NewEntryL( aParentFolder ) );
       
  2142     CleanupStack::PushL( serverEntry );
       
  2143     
       
  2144     if ( error != KErrNone )
       
  2145         {
       
  2146         CleanupStack::PopAndDestroy( serverEntry );
       
  2147         return error;
       
  2148         }
       
  2149           
       
  2150     // Create a new folder.
       
  2151     error = serverEntry->SetEntry( aParentFolder );
       
  2152     
       
  2153     if ( error == KErrNone )
       
  2154 	    {
       
  2155         TMsvEntry entry;
       
  2156 	    entry.iType = KUidMsvFolderEntry;
       
  2157 	    entry.iMtm = KUidMsvLocalServiceMtm;
       
  2158 	    entry.iDetails.Set( aFolderName );
       
  2159 	    entry.SetVisible( EFalse );
       
  2160 	    entry.SetInPreparation( EFalse );
       
  2161 	    entry.iServiceId = KMsvLocalServiceIndexEntryId;
       
  2162 	    error = serverEntry->CreateEntry( entry );    
       
  2163 	    aFolderId = entry.Id();    
       
  2164 	    }
       
  2165 	CleanupStack::PopAndDestroy( serverEntry );
       
  2166     serverEntry = NULL;    
       
  2167 	return error;   
       
  2168        
       
  2169     }
       
  2170 
       
  2171     
       
  2172 // ---------------------------------------------------------
       
  2173 // CMmsReceiveMessage::FindDuplicateNotificationL
       
  2174 // 
       
  2175 // ---------------------------------------------------------
       
  2176 //
       
  2177 TInt CMmsReceiveMessage::FindDuplicateNotificationL(
       
  2178     TMsvId aParent, CMmsHeaders& aHeaders, TMsvId& aDuplicate )
       
  2179     {
       
  2180 #ifndef _NO_MMSS_LOGGING_
       
  2181     TMmsLogger::Log( _L("CMmsReceiveMessage::FindDuplicateNotificationL") );
       
  2182 #endif
       
  2183     
       
  2184     aDuplicate = KMsvNullIndexEntryId;
       
  2185  
       
  2186     if ( aParent == KMsvNullIndexEntryId )
       
  2187         {
       
  2188         return KErrNotSupported;
       
  2189         }
       
  2190 
       
  2191     // Get a new entry, dont mess up with our original entry
       
  2192     TInt error = KErrNone;
       
  2193 
       
  2194     CMsvServerEntry* workingEntry = NULL;
       
  2195     TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent ));
       
  2196     CleanupStack::PushL( workingEntry );
       
  2197     
       
  2198     if ( error != KErrNone )
       
  2199         {
       
  2200         CleanupStack::PopAndDestroy( workingEntry );
       
  2201         return error;
       
  2202         }
       
  2203 
       
  2204     CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; 
       
  2205     CleanupStack::PushL( selection );
       
  2206 
       
  2207     error = workingEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
       
  2208 
       
  2209     TInt count = selection->Count();
       
  2210     if ( count == 0 )
       
  2211         {
       
  2212         error = KErrNotSupported;
       
  2213         }
       
  2214 
       
  2215     if ( error != KErrNone  )
       
  2216         {
       
  2217         CleanupStack::PopAndDestroy( selection );
       
  2218         CleanupStack::PopAndDestroy( workingEntry );
       
  2219         return error;
       
  2220         }
       
  2221 
       
  2222     CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
       
  2223     CleanupStack::PushL( mmsHeaders );
       
  2224      
       
  2225     for ( TInt i = count; i > 0 && ( aDuplicate == KMsvNullIndexEntryId ); i-- )
       
  2226         {
       
  2227         error = workingEntry->SetEntry( selection->At( i - 1 ) );
       
  2228         if ( error == KErrNone )
       
  2229             {            
       
  2230             CMsvStore* store = workingEntry->ReadStoreL();
       
  2231             CleanupStack::PushL( store );
       
  2232             mmsHeaders->RestoreL( *store );
       
  2233             CleanupStack::PopAndDestroy( store );
       
  2234 
       
  2235             // content location must match 
       
  2236             if ( mmsHeaders->ContentLocation().Compare( aHeaders.ContentLocation() ) == 0 )
       
  2237                 {
       
  2238                 // Identical. This probably means that we have not sent a response yet,
       
  2239                 // and MMSC has sent us a new notification.
       
  2240 
       
  2241 #ifndef _NO_MMSS_LOGGING_
       
  2242                 TMmsLogger::Log( _L("- content locations match") );
       
  2243 #endif
       
  2244                 TMsvEntry entry = workingEntry->Entry();
       
  2245                 aDuplicate = entry.Id();
       
  2246                 }
       
  2247             }
       
  2248         }
       
  2249 
       
  2250     CleanupStack::PopAndDestroy( mmsHeaders );
       
  2251     CleanupStack::PopAndDestroy( selection );
       
  2252     CleanupStack::PopAndDestroy( workingEntry );
       
  2253 
       
  2254     return error;
       
  2255     }    
       
  2256     
       
  2257 // ---------------------------------------------------------
       
  2258 // CMmsReceiveMessage::LocalModeFetchL
       
  2259 //
       
  2260 // ---------------------------------------------------------
       
  2261 //
       
  2262 void CMmsReceiveMessage::LocalModeFetchL()
       
  2263     {
       
  2264     
       
  2265     HBufC* buffer = HBufC::NewL( KMaxFileName );
       
  2266     CleanupStack::PushL( buffer );
       
  2267     if ( iNotification->ContentLocation().Length() <= KMaxPath && 
       
  2268         iMmsSettings->LocalMode() )
       
  2269         {
       
  2270         buffer->Des().Copy( iNotification->ContentLocation() );
       
  2271         }
       
  2272     TPtr temp = buffer->Des();
       
  2273     #ifndef _NO_MMSS_LOGGING_
       
  2274     TMmsLogger::Log( _L("...Fetching from : %S"), &temp );
       
  2275     #endif
       
  2276 
       
  2277     HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
       
  2278     CleanupStack::PushL( filename );
       
  2279     TPtr fileNamePtr = filename->Des();
       
  2280     fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
       
  2281             
       
  2282     if ( iNotification->ContentLocation().Length() <= KMaxPath &&
       
  2283         buffer->Des().FindF( fileNamePtr ) == 0 )
       
  2284         {
       
  2285         // The file reading code is for local mode (simulated MMSC)
       
  2286         // Only one can try to get the file at a time
       
  2287         #ifndef _NO_MMSS_LOGGING_
       
  2288         TMmsLogger::Log( _L("opening file") );
       
  2289         #endif
       
  2290         iError = iFile.Open( iFs, temp, EFileShareExclusive );
       
  2291 
       
  2292         if ( iError == KErrNone )
       
  2293             {
       
  2294             #ifndef _NO_MMSS_LOGGING_
       
  2295             TMmsLogger::Log( _L("file opened") );
       
  2296             #endif
       
  2297             iFileOpen = ETrue;
       
  2298             TInt size = 0;
       
  2299             iError = iFile.Size( size );
       
  2300             
       
  2301             // Here we try to use chunked buffer.
       
  2302             // Read the message in chunks and keep calling decode
       
  2303             // Before we can do that, we must create the message entry
       
  2304             // Because it must be ready to receive data
       
  2305             // If receiving fails, the entry must be removed
       
  2306             
       
  2307             DoCreateEntryL();
       
  2308             iDecoder->InitializeChunkedMode( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer );
       
  2309             TInt chunkSize = KMmsChunkedBufferSize;
       
  2310             if ( iError == KErrNone )
       
  2311                 {
       
  2312                 TRAP( iError, iEncodeBuffer->ResizeL( chunkSize ) );
       
  2313                 }
       
  2314             if ( iError != KErrNone )
       
  2315                 {
       
  2316 #ifndef _NO_MMSS_LOGGING_
       
  2317                 TMmsLogger::Log( _L("Receivemsg can't resize buffer, error %d"), iError );
       
  2318                 TMmsLogger::Log( _L("- message size %d"), chunkSize );
       
  2319 #endif
       
  2320                 iFile.Close();
       
  2321                 iFileOpen = EFalse;
       
  2322                 iDecoder->RelaseDataSink();
       
  2323                 CleanupStack::PopAndDestroy( filename );
       
  2324                 CleanupStack::PopAndDestroy( buffer );
       
  2325                 return;
       
  2326                 }
       
  2327                 
       
  2328             // We now have an open file.
       
  2329             // We read it in chunks and feed it to decoder piecewise
       
  2330             TPtr8 pos = iEncodeBuffer->Ptr( 0 );
       
  2331             
       
  2332             TInt position = 0;
       
  2333             TInt readData = 0;
       
  2334             TInt amount = 0;
       
  2335             TBool lastChunk = EFalse;
       
  2336             TInt error = KErrNone;
       
  2337             
       
  2338             while ( readData < size && error == KErrNone )
       
  2339                 {
       
  2340                 chunkSize = KMmsChunkedBufferSize;
       
  2341                 const TInt KMmsTwo = 2;
       
  2342                 if ( chunkSize - amount < KMmsChunkedBufferSize / KMmsTwo )
       
  2343                     {
       
  2344                     // if almost all data has been left to buffer, increase buffer size
       
  2345                     chunkSize = amount + KMmsChunkedBufferSize / KMmsTwo;
       
  2346                     }
       
  2347                 iEncodeBuffer->ResizeL( chunkSize );
       
  2348                 pos.Set( iEncodeBuffer->Ptr( amount ) );
       
  2349                 pos.SetLength( chunkSize - amount );
       
  2350                 error = iFile.Read( pos, chunkSize - amount );
       
  2351                 amount += pos.Length();
       
  2352                 readData += pos.Length();
       
  2353                 if ( readData >= size )
       
  2354                     {
       
  2355                     lastChunk = ETrue;
       
  2356                     }
       
  2357                 if ( error == KErrNone )
       
  2358                     {
       
  2359                     // this is how much data we have
       
  2360                     iEncodeBuffer->ResizeL( amount ); 
       
  2361                     error = iDecoder->NextDataPart( *iEncodeBuffer, position, lastChunk );
       
  2362                     }
       
  2363                 if ( position > iEncodeBuffer->Size() )
       
  2364                     {
       
  2365                     position = iEncodeBuffer->Size();
       
  2366                     }
       
  2367                 // Check if we can continue and shift the buffer if needed
       
  2368                 if ( error == KErrNone )
       
  2369                     {
       
  2370                     // now position points to the beginning of unhandled data
       
  2371                     // it must be shifted to the beginning
       
  2372                     amount -= position; // this much left unhandled
       
  2373                     if ( amount < 0 )
       
  2374                         {
       
  2375                         amount = 0;
       
  2376                         }
       
  2377                     iEncodeBuffer->Delete( 0, position );
       
  2378                     // start from the beginning the next time
       
  2379                     position = 0;
       
  2380                     }
       
  2381                 }
       
  2382             if ( error != KErrNone )
       
  2383                 {
       
  2384                 iError = error;
       
  2385                 }
       
  2386             // when the loop ends, all data should be handled and all attachments should be created
       
  2387             // Decode has also saved message headers.
       
  2388             // The changed state indicates what is complete
       
  2389             iDecoder->RelaseDataSink();
       
  2390             iState = EMmsOperationDecodingResponse; 
       
  2391             }
       
  2392         else
       
  2393             {
       
  2394             // This corresponds to the situation, where the message
       
  2395             // has expired or for some other reason is no longer available.
       
  2396             // We lie to RunL that we have already decoded the message
       
  2397             iFile.Close();
       
  2398             iFileOpen = EFalse;
       
  2399             iState = EMmsOperationDecodingResponse;
       
  2400             if ( iError != KErrInUse )
       
  2401                 {
       
  2402                 iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  2403                 }
       
  2404             }
       
  2405         // We don't close the file yet.
       
  2406         // We want to keep it exclusively to ourselves until we are done with it
       
  2407         }
       
  2408     else
       
  2409         {
       
  2410         // No directory found in notification
       
  2411         // this notification cannot be handled.
       
  2412         // It will be marked bad and deleted.
       
  2413         iError = KErrNotFound;
       
  2414         iState = EMmsOperationDecodingResponse;
       
  2415         iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
       
  2416         }
       
  2417     CleanupStack::PopAndDestroy( filename );
       
  2418     CleanupStack::PopAndDestroy( buffer );
       
  2419     }
       
  2420     
       
  2421 // ---------------------------------------------------------
       
  2422 // CMmsReceiveMessage::DumpIfNeededL
       
  2423 //
       
  2424 // ---------------------------------------------------------
       
  2425 //
       
  2426 void CMmsReceiveMessage::DumpIfNeededL()
       
  2427     {
       
  2428 #ifndef _NO_MMSS_LOGGING_
       
  2429     TInt error = KErrNone;
       
  2430     TBool dumpIncoming = EFalse;
       
  2431     //
       
  2432     // Reading binary dumping from CenRep
       
  2433     //
       
  2434     CRepository* repository = NULL;
       
  2435     TInt retval = KErrNone;
       
  2436     TRAP( retval, repository = CRepository::NewL( KUidMmsServerMtm ) ); // ***
       
  2437     if( retval == KErrNone )
       
  2438         {
       
  2439         CleanupStack::PushL( repository );
       
  2440         TInt temp = 0;
       
  2441         retval = repository->Get( KMmsEngineBinaryDump, temp );
       
  2442         if( retval == KErrNone )
       
  2443             {
       
  2444             dumpIncoming = (TBool)temp;
       
  2445             }
       
  2446         CleanupStack::PopAndDestroy( repository );
       
  2447         }    
       
  2448 
       
  2449     TMmsLogger::Log( _L("Receivemsg Dumping Entry") );
       
  2450     // If the result was bad, we dump the binary data into file
       
  2451     // - unless decode already did it.
       
  2452     if ( ( ( !dumpIncoming ) && iError != KErrNone ) &&
       
  2453         iEncodeBuffer &&
       
  2454         iEncodeBuffer->Size() > 0 )
       
  2455         {
       
  2456         TParse parse;
       
  2457         TFileName fileName;
       
  2458         fileName.Copy( KMmsDefaultLogDirectory );
       
  2459         TUint att;
       
  2460         if ( iFs.Att( fileName, att ) == KErrNone )
       
  2461             {
       
  2462             _LIT( KRelated, "Rec.mms");
       
  2463             parse.Set( fileName, &KRelated, NULL );
       
  2464             fileName = parse.FullName();
       
  2465             error = CApaApplication::GenerateFileName( iFs, fileName );
       
  2466             if ( error == KErrNone )
       
  2467                 {
       
  2468                 RFile file;
       
  2469                 error = file.Create( iFs, fileName, EFileWrite | EFileShareExclusive );
       
  2470                 // for message id generation
       
  2471                 parse.Set( fileName, NULL, NULL );
       
  2472 
       
  2473                 if ( error == KErrNone )
       
  2474                     {
       
  2475                     // the data is supposed to be in the encode buffer
       
  2476                     TPtr8 ptr = iEncodeBuffer->Ptr( 0 );
       
  2477                     file.Write( ptr );
       
  2478                     file.Flush();
       
  2479                     }
       
  2480 
       
  2481                 // done - close files
       
  2482                 file.Close();
       
  2483                 }
       
  2484             }
       
  2485         }
       
  2486 #endif
       
  2487     }
       
  2488     
       
  2489 // ---------------------------------------------------------
       
  2490 // CMmsReceiveMessage::CloseLocalFile
       
  2491 //
       
  2492 // ---------------------------------------------------------
       
  2493 //
       
  2494 void CMmsReceiveMessage::CloseLocalFileL( TBool aDeleteFile )
       
  2495     {
       
  2496     HBufC* buffer = HBufC::NewL( KMaxFileName );
       
  2497     CleanupStack::PushL( buffer );
       
  2498     buffer->Des().Copy( iNotification->ContentLocation() );
       
  2499     HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
       
  2500     CleanupStack::PushL( filename );
       
  2501     TPtr fileNamePtr = filename->Des();
       
  2502     fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
       
  2503     if ( buffer->Des().FindF( fileNamePtr ) == 0 )
       
  2504         {
       
  2505         // this was our local message file
       
  2506         iFile.Close();
       
  2507         iFileOpen = EFalse;
       
  2508         if ( aDeleteFile )
       
  2509             {
       
  2510             iFs.Delete( *buffer );
       
  2511             }
       
  2512         }
       
  2513     CleanupStack::PopAndDestroy( filename );
       
  2514     CleanupStack::PopAndDestroy( buffer );
       
  2515     }
       
  2516     
       
  2517 // ---------------------------------------------------------
       
  2518 // CMmsReceiveMessage::MoveToApplicationFolderIfNeededL
       
  2519 //
       
  2520 // ---------------------------------------------------------
       
  2521 //
       
  2522 TInt CMmsReceiveMessage::MoveToApplicationFolderIfNeededL( TMsvEntry& aEntry )
       
  2523     {
       
  2524     TInt error = KErrNone;
       
  2525     TInt returnCode = 0;
       
  2526     
       
  2527     if ( iMmsHeaders->ApplicId().Length() > 0 )
       
  2528         {
       
  2529         // check if application id is registered
       
  2530         if ( iRegistered )
       
  2531             {
       
  2532 #ifndef _NO_MMSS_LOGGING_
       
  2533             TMmsLogger::Log( _L("- message to registered application") );
       
  2534 #endif
       
  2535             TMsvId targetFolder = KMsvNullIndexEntryId;
       
  2536             // target folder's parent is application folder
       
  2537             TMsvId applicationFolder = iMmsSettings->ApplicationFolder();
       
  2538             // code scanner gives false positive from the next line
       
  2539             error = CreateFolderEntryL( applicationFolder, iMmsHeaders->ApplicId(), targetFolder );
       
  2540             if ( targetFolder != KMsvNullIndexEntryId && error == KErrNone )
       
  2541                 {
       
  2542                 error = iServerEntry->SetEntry( aEntry.Parent() );
       
  2543                 if ( error == KErrNone )
       
  2544 	                {
       
  2545 	                error = iServerEntry->MoveEntryWithinService( aEntry.Id(), targetFolder );     	
       
  2546 	                }
       
  2547 	            if ( error == KErrNone )
       
  2548 	                {
       
  2549 	                // Message was successfully moved to application folder
       
  2550 	                // If we want to keep the notification in inbox we return 
       
  2551                     // KMmsMessageMovedToApplicationFolder.
       
  2552                     // As long as we serve only Java applications, the notifications
       
  2553                     // will disappear from inbox if the message was moved to application folder.
       
  2554                     // Java will start the applet if it is not running, and that should
       
  2555                     // be sufficient information for the user.
       
  2556 #ifndef _NO_MMSS_LOGGING_
       
  2557                     TMmsLogger::Log( _L("- moved to application folder") );
       
  2558 #endif
       
  2559 	                returnCode = 0;
       
  2560 	                }
       
  2561 	            // If we cannot set our entry back to the one we are handling,
       
  2562 	            // we are in deep trouble    
       
  2563 	            User::LeaveIfError( iServerEntry->SetEntry( iEntryUnderConstruction ));
       
  2564                 }                      
       
  2565             }
       
  2566         else
       
  2567             {
       
  2568             // There was an application id, but the application was not registered
       
  2569             // Message will be deleted
       
  2570             // If deletion fails, the message remains invisible and under construction
       
  2571             // and will be deleted by message server at next boot.
       
  2572 #ifndef _NO_MMSS_LOGGING_
       
  2573             TMmsLogger::Log( _L("- message to unregistered application - deleted") );
       
  2574 #endif
       
  2575             error = iServerEntry->SetEntry( aEntry.Parent() );
       
  2576             if ( error == KErrNone )
       
  2577                 {
       
  2578                 iServerEntry->DeleteEntry( aEntry.Id() );
       
  2579                 }
       
  2580             returnCode = KMmsMessageForUnregisteredApplication;
       
  2581             }
       
  2582         }
       
  2583     // If no application id, the message is normal    
       
  2584     return returnCode;
       
  2585     }
       
  2586     
       
  2587 // ---------------------------------------------------------
       
  2588 //
       
  2589 // ---------------------------------------------------------
       
  2590 //
       
  2591 void CMmsReceiveMessage::ClearDuplicateEntryOperationL()
       
  2592     {
       
  2593     CMsvStore* store = iServerEntry->ReadStoreL();
       
  2594     CleanupStack::PushL( store );
       
  2595     iMmsHeaders->RestoreL( *store );
       
  2596     CleanupStack::PopAndDestroy( store );
       
  2597     TMsvId duplicate = KMsvNullIndexEntryId;
       
  2598     TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
       
  2599     TMsvEntry dupEntry;
       
  2600 
       
  2601     if ( iNotificationParent == KMsvGlobalInBoxIndexEntryIdValue )
       
  2602         {
       
  2603         // if duplicate is found from mmbox folder, 
       
  2604         // mark it as "deleted from mmbox server"
       
  2605         if ( mmboxFolder != KMsvNullIndexEntryId )
       
  2606             {
       
  2607             FindDuplicateNotificationL( mmboxFolder, *iMmsHeaders, duplicate );
       
  2608             }
       
  2609         if ( duplicate != KMsvNullIndexEntryId )
       
  2610             {
       
  2611 #ifndef _NO_MMSS_LOGGING_
       
  2612             TMmsLogger::Log( _L("- duplicate found ") );
       
  2613 #endif
       
  2614             if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
       
  2615                 {
       
  2616                 // Mark duplicate as deleted from mmbox server.
       
  2617                 // If it was successfully fetched it is no longer in MMBox.
       
  2618                 // This is not exactly correct for full MMBox support but as long as
       
  2619                 // we don't have full MMBox support this works correctly
       
  2620                 dupEntry = iServerEntry->Entry();
       
  2621                 MarkNotificationDeletedFromMmbox( dupEntry );
       
  2622                 iServerEntry->ChangeEntry( dupEntry );
       
  2623 #ifndef _NO_MMSS_LOGGING_
       
  2624                 TMmsLogger::Log( _L("- duplicate marked as deleted from mmbox ") );
       
  2625 #endif
       
  2626                 }                                         
       
  2627             }    
       
  2628         }
       
  2629     else if ( iNotificationParent == mmboxFolder )
       
  2630         {
       
  2631         duplicate = iMmsHeaders->RelatedEntry();                                
       
  2632         if ( duplicate != KMsvNullIndexEntryId )
       
  2633             {
       
  2634 #ifndef _NO_MMSS_LOGGING_
       
  2635             TMmsLogger::Log( _L("- duplicate found ") );
       
  2636 #endif
       
  2637             if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
       
  2638                 {
       
  2639                 // Mark it deleted just in case the actual deletion fails.
       
  2640                 // This is not exactly correct for full MMBox support but as long as
       
  2641                 // we don't have full MMBox support this works correctly
       
  2642                 dupEntry = iServerEntry->Entry();
       
  2643                 MarkNotificationDeletedFromMmbox( dupEntry );
       
  2644                 iServerEntry->ChangeEntry( dupEntry );
       
  2645                 // delete the duplicate notification from inbox 
       
  2646                 if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryIdValue )
       
  2647                     == KErrNone )
       
  2648                     {
       
  2649                     TInt err = iServerEntry->DeleteEntry( duplicate );
       
  2650 #ifndef _NO_MMSS_LOGGING_
       
  2651                     if ( err == KErrNone )
       
  2652                         {
       
  2653                         TMmsLogger::Log( _L("- duplicate deleted from inbox ") );
       
  2654                         }
       
  2655 #endif
       
  2656                     }
       
  2657                 }
       
  2658             }
       
  2659         }
       
  2660     else
       
  2661         {
       
  2662         // nothing to do - just keep compiler and code analyzer tools happy
       
  2663         }
       
  2664     }
       
  2665     
       
  2666 // ---------------------------------------------------------
       
  2667 //
       
  2668 // ---------------------------------------------------------
       
  2669 //
       
  2670 void CMmsReceiveMessage::ClearOperationL( TInt aApplicationMessageStatus )
       
  2671     {
       
  2672     if ( iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ) == KErrNone )
       
  2673         {
       
  2674         if ( aApplicationMessageStatus != 0 )
       
  2675             {
       
  2676             // The entry is not deleted if it is in inbox or MMBox
       
  2677             // and has been routed to application.
       
  2678             // We save the error code or routing status to the entry.
       
  2679             TMsvEntry tEntry = iServerEntry->Entry();
       
  2680             MarkNotificationDeletedFromMmbox( tEntry );
       
  2681             tEntry.SetConnected( EFalse );
       
  2682             tEntry.SetReadOnly( ETrue );
       
  2683 
       
  2684             if ( aApplicationMessageStatus == KMmsMessageMovedToApplicationFolder )
       
  2685                 {
       
  2686                 // This is a successful case
       
  2687                 tEntry.iMtmData2 |= KMmsMessageRoutedToApplication;
       
  2688                 }
       
  2689             if ( aApplicationMessageStatus ==
       
  2690                 KMmsMessageForUnregisteredApplication )
       
  2691                 {
       
  2692                 // This will be marked as failed operation
       
  2693                 // even if the message was actually successfully fetched
       
  2694                 // but it was discarded because it does not belong to anybody
       
  2695                 tEntry.iError = KMmsErrorUnregisteredApplication;
       
  2696                 // The earlier operation cleared the possible MMBox bit
       
  2697                 // This operation marks the result as failed.
       
  2698                 MarkNotificationOperationFailed( tEntry );
       
  2699                 }
       
  2700                 
       
  2701             // error status not checked here - we just do our best    
       
  2702             iServerEntry->ChangeEntry( tEntry );    
       
  2703             }
       
  2704         ClearDuplicateEntryOperationL();
       
  2705         }
       
  2706     }
       
  2707 
       
  2708 
       
  2709 // ---------------------------------------------------------
       
  2710 //
       
  2711 // ---------------------------------------------------------
       
  2712 //
       
  2713 void CMmsReceiveMessage::CopyDataFromNotificationToMessageL()
       
  2714     {
       
  2715     // Only subject and sender take up space when headers are added
       
  2716     TInt size = iNotification->Sender().Length() +
       
  2717                 iNotification->Subject().Length();
       
  2718     if ( size > 0 &&
       
  2719         TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &iFs, size, iMessageDrive ) )
       
  2720         {
       
  2721         size = 0;
       
  2722         }
       
  2723      
       
  2724     // We copy data from notification to message if the values are missing
       
  2725     // But if the message is already complete (status == OK)
       
  2726     // we do not copy anything.
       
  2727     if ( iMmsHeaders->ResponseStatus() > KMmsResponseStatusOK )
       
  2728         {
       
  2729         // The critical disk space is checked only when adding the subject.
       
  2730         // The sender number is important and only takes a small amount of space
       
  2731         // The other fields take the same amount of space regardless of the value.
       
  2732         // As the headers have been saved already, only subject may consume
       
  2733         // significantly more disk space.
       
  2734         if ( size > 0 )
       
  2735             {
       
  2736             if ( iMmsHeaders->Subject().Length() == 0 )
       
  2737                 {
       
  2738                 iMmsHeaders->SetSubjectL( iNotification->Subject() );
       
  2739                 }
       
  2740             }
       
  2741         if ( iMmsHeaders->Sender().Length() == 0 )
       
  2742             {
       
  2743             iMmsHeaders->SetSenderL( iNotification->Sender() );
       
  2744             }
       
  2745         if ( iMmsHeaders->MessageClass() == 0 )
       
  2746             {
       
  2747             iMmsHeaders->SetMessageClass( iNotification->MessageClass() );
       
  2748             }
       
  2749         if ( iMmsHeaders->MessagePriority() == 0 )
       
  2750             {
       
  2751             iMmsHeaders->SetMessagePriority( iNotification->MessagePriority() );
       
  2752             }
       
  2753         // Copy the expiry, too
       
  2754         if ( iMmsHeaders->ExpiryDate() == 0 && iMmsHeaders->ExpiryInterval() == 0 )
       
  2755             {
       
  2756             // No expiration data in the message - use what is in the notification
       
  2757             iMmsHeaders->SetExpiryDate( iNotification->ExpiryDate() );
       
  2758             }
       
  2759         }
       
  2760     }
       
  2761     
       
  2762 // ---------------------------------------------------------
       
  2763 //
       
  2764 // ---------------------------------------------------------
       
  2765 //
       
  2766 void CMmsReceiveMessage::CopyDataFromMessageToNotificationL()
       
  2767     {
       
  2768     TBool saveNotification = EFalse;
       
  2769     TInt error = KErrNone;
       
  2770     
       
  2771     iNotification->SetResponseTextL( iMmsHeaders->ResponseText() );
       
  2772     iNotification->SetResponseStatus( iMmsHeaders->ResponseStatus() );
       
  2773 
       
  2774     // Notifications do not originally contain any response texts.
       
  2775     // If the length is not 0, we have added something
       
  2776     if ( iNotification->ResponseText().Length() > 0 || iNotification->ResponseStatus() != 0 )
       
  2777         {
       
  2778         saveNotification = ETrue;
       
  2779         }
       
  2780         
       
  2781     if ( iNotification->ApplicId().Length() == 0 )
       
  2782         {
       
  2783         iNotification->SetApplicIdL( iMmsHeaders->ApplicId() );
       
  2784         if ( iNotification->ApplicId().Length() > 0 )
       
  2785             {
       
  2786             // If we copied the application id, we must save it.
       
  2787             saveNotification = ETrue;
       
  2788             }
       
  2789         }
       
  2790        
       
  2791     // update the notification
       
  2792     if ( saveNotification )
       
  2793         {
       
  2794         //  We update the notification if we added something
       
  2795         error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
       
  2796         if ( error == KErrNone )
       
  2797             {
       
  2798             TRAP( error,
       
  2799                 {
       
  2800                 CMsvStore* store = iServerEntry->EditStoreL();
       
  2801                 CleanupStack::PushL( store );
       
  2802                 iNotification->StoreL( *store );
       
  2803                 store->CommitL();
       
  2804                 CleanupStack::PopAndDestroy( store );
       
  2805                 })
       
  2806             }
       
  2807         // If we cannot update the entry, the user does not see the error text, but that's not fatal
       
  2808         }
       
  2809     // Release the entry
       
  2810     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2811     
       
  2812     }
       
  2813     
       
  2814 // ---------------------------------------------------------
       
  2815 //
       
  2816 // ---------------------------------------------------------
       
  2817 //
       
  2818 TBool CMmsReceiveMessage::MapErrorStatus( const TInt32 aErrorStatus )
       
  2819     {
       
  2820     TBool fatal = EFalse;
       
  2821     
       
  2822     switch ( aErrorStatus )
       
  2823         {
       
  2824         case 0: // if the header is not present, it is 0
       
  2825         case KMmsStatusOk:
       
  2826             // No error, don't change iError
       
  2827             break;
       
  2828         case KMmsErrorPermanentFailure:
       
  2829             fatal = ETrue;
       
  2830             iError = KMmsErrorStatusPermanentFailure;
       
  2831             break;
       
  2832         case KMmsErrorTransientFailure:
       
  2833             iError = KMmsErrorStatusTransientFailure;
       
  2834             break;
       
  2835         case KMmsErrorReceivePermanentMessageNotFound:
       
  2836             fatal = ETrue;
       
  2837             iError = KMmsErrorStatusMessageNotFound;
       
  2838             break;
       
  2839         case KMmsErrorReceiveTransientMessageNotFound:
       
  2840             iError = KMmsErrorStatusTransientMessageNotFound;
       
  2841             break;
       
  2842         case KMmsErrorReceiveTransientNetworkProblem:
       
  2843             iError = KMmsErrorStatusNetworkProblem;
       
  2844             break;
       
  2845         case KMmsErrorPermanentServiceDenied:
       
  2846             fatal = ETrue;
       
  2847             iError = KMmsErrorStatusServiceDenied;
       
  2848             break;
       
  2849         case KMmsErrorReceivePermanentContentUnsupported:
       
  2850             fatal = ETrue;
       
  2851             iError = KMmsErrorStatusContentUnsupported;
       
  2852             break;
       
  2853         default:
       
  2854             // Unknown error, if not transient, it is fatal
       
  2855             if ( ( aErrorStatus & KMmsErrorRangeMask ) == KMmsErrorTransient )
       
  2856                 {
       
  2857                 iError = KMmsErrorStatusTransientFailure;
       
  2858                 }
       
  2859             else
       
  2860                 {
       
  2861                 iError = KMmsErrorPermanentFailure;
       
  2862                 fatal = ETrue;
       
  2863                 }
       
  2864             break;
       
  2865         }
       
  2866             
       
  2867     return fatal;
       
  2868     }
       
  2869 
       
  2870 // ---------------------------------------------------------
       
  2871 //
       
  2872 // ---------------------------------------------------------
       
  2873 //
       
  2874 void CMmsReceiveMessage::SetIndexEntryBitsForReceivedMessage( TMsvEntry& aEntry )
       
  2875     {
       
  2876     aEntry.iMtmData1 &= ~KMmsMessageTypeMask;
       
  2877     // We override message type for now.
       
  2878     // We get send requests instead of retrieve confirmations if in local mode
       
  2879     aEntry.iMtmData1 |= KMmsMessageMRetrieveConf | KMmsMessageMobileTerminated;
       
  2880 
       
  2881     aEntry.SetVisible( ETrue );
       
  2882     aEntry.SetComplete( ETrue );
       
  2883     aEntry.SetInPreparation( EFalse );
       
  2884     aEntry.SetReadOnly( ETrue );
       
  2885     aEntry.iDate.UniversalTime(); // this is arrival time
       
  2886     
       
  2887     if ( iMmsSettings->ShowSentTime() )
       
  2888         {
       
  2889         // show the time the message was received by MMSC instead of 
       
  2890         // the time the message was received by the terminal
       
  2891         if ( iMmsHeaders->Date() > 0 )
       
  2892             {
       
  2893             // date is given as seconds from 1.1.1970, UTC time
       
  2894             TTime time = TTime( KMmsYear1970String ) +
       
  2895                 TTimeIntervalMicroSeconds( iMmsHeaders->Date() * KMmsMillion );
       
  2896             aEntry.iDate = time.Int64();
       
  2897             }
       
  2898         }
       
  2899     // subject, sender and size are set in CMmsDecode
       
  2900     // - except if we get an empty error message.
       
  2901     // In that case the fields were copied from the notification,
       
  2902     // and we set sender and subject here.
       
  2903     if ( aEntry.iDetails.Length() == 0 )
       
  2904         {
       
  2905         aEntry.iDetails.Set( iMmsHeaders->Sender() );
       
  2906         }
       
  2907     if ( aEntry.iDescription.Length() == 0 )  
       
  2908         {
       
  2909         aEntry.iDescription.Set( iMmsHeaders->Subject() );
       
  2910         }
       
  2911 
       
  2912     // Set multiple recipients
       
  2913     if ( iMmsHeaders->ToRecipients().MdcaCount() +
       
  2914         iMmsHeaders->CcRecipients().MdcaCount() +
       
  2915         iMmsHeaders->BccRecipients().MdcaCount() > 1 )
       
  2916         {
       
  2917         aEntry.SetMultipleRecipients( ETrue );
       
  2918         }
       
  2919     }
       
  2920     
       
  2921     
       
  2922 // ---------------------------------------------------------
       
  2923 //
       
  2924 // ---------------------------------------------------------
       
  2925 //
       
  2926 void CMmsReceiveMessage::DeleteApplicationMessagesL()
       
  2927     {
       
  2928     // target folder's parent is application folder
       
  2929     TMsvId messageFolder = KMsvNullIndexEntryId;
       
  2930     TMsvId applicationFolder = iMmsSettings->ApplicationFolder();
       
  2931     // code scanner gives false positive from the next line
       
  2932     TInt error = KErrNone;
       
  2933     error = FolderEntryL( applicationFolder, iMmsHeaders->ApplicId(), messageFolder );
       
  2934    
       
  2935     if ( messageFolder == KMsvNullIndexEntryId || error != KErrNone )
       
  2936         {
       
  2937         // We could not find the folder - we cannot free space
       
  2938         return;
       
  2939         }
       
  2940         
       
  2941     // List all messages in the folder and try to see if we can free enough room.
       
  2942     TInt size = iNotification->MessageSize();
       
  2943     if ( size > iMmsSettings->MaximumReceiveSize() )
       
  2944         {
       
  2945         // We cannot fetch more than this anyway
       
  2946         size = iMmsSettings->MaximumReceiveSize();
       
  2947         }
       
  2948     // The safety margin must be added to the indicated size as the size in the
       
  2949     // notification only specifies the payload, not all headers and space taken
       
  2950     // by message entry and folder entry needed.
       
  2951     size += KMmsDiskSafetyMargin;
       
  2952     
       
  2953     error = iServerEntry->SetEntry( messageFolder );
       
  2954     if ( error != KErrNone )
       
  2955         {
       
  2956         // no can do
       
  2957         return;
       
  2958         }
       
  2959     
       
  2960     // sort entries by date
       
  2961     TMsvSelectionOrdering ordering =
       
  2962         TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByDate, EFalse );
       
  2963     iServerEntry->SetSort( ordering );
       
  2964     
       
  2965     CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
       
  2966     CleanupStack::PushL( selection );
       
  2967     error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *selection );
       
  2968     if ( error != KErrNone )
       
  2969         {
       
  2970         // no can do
       
  2971         iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  2972         CleanupStack::PopAndDestroy( selection );
       
  2973         }
       
  2974    
       
  2975     TInt i;
       
  2976     TInt deleteCount = 0; // entries to be deleted to free space
       
  2977     TInt oldSize = 0;
       
  2978     for ( i = 0; i < selection->Count() && deleteCount == 0; i++ )
       
  2979         {
       
  2980         error = iServerEntry->SetEntry( selection->At( i ) );
       
  2981         if ( error == KErrNone )
       
  2982             {
       
  2983             // If we could not access some entry, it will end up in the 
       
  2984             // delete list anyway. It may or may not be deleted.
       
  2985             oldSize += iServerEntry->Entry().iSize;
       
  2986             }
       
  2987         if ( oldSize >= size )
       
  2988             {
       
  2989             deleteCount = i + 1;
       
  2990             }
       
  2991         }
       
  2992         
       
  2993     // Check if we fond enough old messages to free space.
       
  2994     if ( deleteCount > 0 )
       
  2995         {
       
  2996         for ( i = selection->Count(); i > deleteCount; i-- )
       
  2997             {
       
  2998             // We may be able to leave some entries
       
  2999             selection->Delete( i - 1 );
       
  3000             }
       
  3001         
       
  3002         error = iServerEntry->SetEntry( messageFolder );
       
  3003         if ( error == KErrNone )
       
  3004             {
       
  3005             error = iServerEntry->DeleteEntries( *selection );
       
  3006             }
       
  3007         // If we get an error because some entry is locked or open
       
  3008         // the original KErrNoDisk remains and no entries are deleted
       
  3009         // The situation will follow normal low disk space handling
       
  3010         // If the entries are being accessed by the application, the
       
  3011         // space may be freed soon by the application.
       
  3012         if ( error == KErrNone )
       
  3013             {
       
  3014             // We have successfully deleted enough entries
       
  3015             // The new message should now fit.
       
  3016             // It can be rescheduled or fetch can be manually restarted
       
  3017             iError = KMmsErrorApplicationDiskFull;
       
  3018             }
       
  3019         }
       
  3020     iServerEntry->SetEntry( KMsvNullIndexEntryId );
       
  3021     CleanupStack::PopAndDestroy( selection );    
       
  3022     }
       
  3023     
       
  3024 
       
  3025 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  3026 
       
  3027 //  End of File  
       
  3028