mmsengine/mmsserver/src/mmsreceivemessage.cpp
changeset 0 72b543305e3a
child 26 ebe688cedc25
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmsengine/mmsserver/src/mmsreceivemessage.cpp	Thu Dec 17 08:44:11 2009 +0200
@@ -0,0 +1,3028 @@
+/*
+* Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+*     State machine for message receiving
+*
+*/
+
+
+
+// INCLUDE FILES
+#include    <apparc.h>
+#include    <msventry.h>
+#include    <msvids.h>
+#include    <charconv.h>
+#include    <badesca.h>
+#include    <cmsvmimeheaders.h>
+#include    <mmsvattachmentmanager.h>
+#include    <mmsvattachmentmanagersync.h>
+
+#include    <centralrepository.h>
+
+// mms private headers
+#include    "mmsconst.h"
+#include    "mmsreceivemessage.h"
+#include    "mmssession.h"
+#include    "mmssettings.h"
+#include    "mmsservercommon.h"
+#include    "mmsheaders.h"
+#include    "mmsdecode.h"
+#include    "mmsencode.h"
+#include    "mmsscheduledentry.h"
+#include    "mmserrors.h"
+#include    "mmsserverentry.h"
+#include    "mmsconninit.h"
+#include    "MmsEnginePrivateCRKeys.h"
+#include    "MmsPhoneClient.H"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES  
+extern void gPanic(TMmsPanic aPanic);
+
+// CONSTANTS
+// return codes for handling of messages addressed to an application
+const TInt KMmsMessageForUnregisteredApplication = 1;
+const TInt KMmsMessageMovedToApplicationFolder = 2;
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// ==================== LOCAL FUNCTIONS ====================
+
+
+// ================= MEMBER FUNCTIONS =======================
+
+// C++ default constructor can NOT contain any code, that
+// might leave.
+//
+CMmsReceiveMessage::CMmsReceiveMessage( RFs& aFs )
+    :CMmsBaseOperation( aFs )
+    {
+    }
+
+// Symbian OS default constructor can leave.
+void CMmsReceiveMessage::ConstructL( CMmsSettings* aMmsSettings )
+    {
+    iFileOpen = EFalse;
+    CMmsBaseOperation::ConstructL( aMmsSettings );
+    iMmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    iNotification = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    iBad = new( ELeave ) CMsvEntrySelection;
+    TRAPD ( error, {iMessageDrive = MessageServer::CurrentDriveL( iFs );});
+    if ( error != KErrNone )
+        {
+        // if cannot ask, use default
+        iMessageDrive = EDriveC;
+        }
+
+    CActiveScheduler::Add( this );
+    }
+
+// Two-phased constructor.
+CMmsReceiveMessage* CMmsReceiveMessage::NewL( RFs& aFs, CMmsSettings* aMmsSettings )
+    {
+    CMmsReceiveMessage* self = new ( ELeave ) CMmsReceiveMessage( aFs );
+    
+    CleanupStack::PushL( self );
+    self->ConstructL( aMmsSettings );
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+    
+// Destructor
+CMmsReceiveMessage::~CMmsReceiveMessage()
+    {
+    
+    Cancel();
+
+    delete iMmsHeaders;
+    delete iNotification;
+    delete iBad;
+    // This is the message for local mode testing
+    // It is closed here only to make sure that it is
+    // always closed even if we encounter a serious error.
+    // otherwise it should already be closed by now.
+    if ( iFileOpen )
+        {
+        iFile.Close();
+        }
+    }
+
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::StartL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::StartL(
+    CMsvEntrySelection& aSelection,
+    CMsvServerEntry& aServerEntry,
+    TMsvId aService,
+    TRequestStatus& aStatus )
+    {
+    __ASSERT_DEBUG( iState == EMmsOperationIdle, gPanic( EMmsAlreadyBusy ) );
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("ReceiveMsg StartL") );
+#endif
+    // just initialize common member variables
+    CMmsBaseOperation::InitializeL( aSelection, aServerEntry, aService );
+    
+    iReceivingMode = iMmsSettings->ReceivingModeHome();
+
+    iNotificationParent = KMsvNullIndexEntryId;
+    iBad->Reset();
+    iNotification->Reset();
+    iResponse->Reset(); // This sets the correct version
+    iMmsHeaders->Reset();
+    iEntryUnderConstruction = KMsvNullIndexEntryId;
+    iAlreadyDeferred = EFalse;
+    iFileOpen = EFalse;
+    
+    // selection is supposed to point to a bunch of notifications
+    // containing the URIs the messages are to be fetched from
+    TInt count = iCurrentMessageNo;
+    iError = KErrNone;
+
+    while ( count > 0 && ( iNotificationParent == KMsvNullIndexEntryId ) )
+        {
+        // Load the notification
+        // iCurrentMessageNo (and therefore also count) has originally been
+        // set to iSelection->Count() so the index is always valid.
+        count--; // indexes are zero based
+        if ( count < iSelection->Count() )
+            {
+            iError = iServerEntry->SetEntry( iSelection->At( count ) );
+            }
+        else
+            {
+            iError = KErrNotFound;
+            }
+        if ( iError == KErrNone )
+            {
+            TMsvEntry entry = iServerEntry->Entry();
+            iNotificationParent = entry.Parent();
+            }
+        }
+    
+    // release the last notification
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    if (  iNotificationParent == KMsvNullIndexEntryId )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- could not access any entry to get parent") );
+#endif
+        // nothing to receive. Give up immediately
+        aStatus = KRequestPending;
+        TRequestStatus* status = &aStatus;
+        User::RequestComplete( status, iError );
+        return;
+        }
+
+    // Initialize everything into the failed list.
+    // Very pessimistic indeed.
+    
+    iBad->SetReserveL( iCurrentMessageNo );
+
+    Queue( aStatus );
+    
+    // We complete ourselves to get into the state machine loop.
+    // The first thing to do is to check the roaming state.
+    FallThrough();
+
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::DoComplete
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::DoComplete(TInt& aError )
+    {
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg DoComplete"));
+#endif
+    // We should get here if we are cancelled, or if
+    // the cycle has completed (with or without error)
+    // Make sure the store is released
+    iDecoder->RelaseDataSink();
+
+    // If we have an error, we must delete the entry
+    // under construction.
+    // If we have successfully created the entry, we have set
+    // iEntryUnderConstruction to KMsvNullIndexEntryId.
+    // If iEntryUnderConstruction still points to an entry, it means
+    // that the cycle has been aborted, and the incomplete entry
+    // must be deleted.
+    if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
+        {
+        if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ) == KErrNone )
+            {
+            iServerEntry->DeleteEntry ( iEntryUnderConstruction );
+            }
+        iEntryUnderConstruction = KMsvNullIndexEntryId;
+        }
+
+    // Set error to entries that are still left
+    // If some of the entries already have an error set,
+    // it is not overridden.
+    UnSetSendMask( *iFailed, aError );
+    
+    // If we are supporting MMBox, we must also clear the duplicates
+    // if we have notifications in bad list
+    
+    if ( iMmsSettings->MMBoxFolder() != KMsvNullIndexEntryId )
+        {
+        TInt i = 0;
+#ifndef _NO_MMSS_LOGGING_
+        if ( iBad->Count() > 0 )
+            {
+            TMmsLogger::Log( _L("- %d notifications on bad list "), iBad->Count() );
+            }
+#endif
+
+        for ( i = 0; i < iBad->Count(); i++ )
+            {
+            if ( iServerEntry->SetEntry( iBad->At( i )) == KErrNone )
+                {
+                // we don't want to leave here, we do our best
+                TRAP_IGNORE( ClearDuplicateEntryOperationL() ); 
+                }
+            }
+        }
+    }
+
+// start of ROAMING CHECK handling
+// ---------------------------------------------------------
+// CMmsReceiveMessage::RoamingCheck
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::RoamingCheck()
+    {
+    
+    TInt error = KErrNone;
+    
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg roaming check start"));
+#endif
+
+    if ( !iMmsSettings->LocalMode() && !iMmsSettings->FetchOverride() &&
+         ( ( iMmsSettings->ReceivingModeHome() != iMmsSettings->ReceivingModeForeign() ) ||
+         ( iMmsSettings->ReceivingModeForeign() == EMmsReceivingManual ) ||
+         ( iMmsSettings->ReceivingModeForeign() == EMmsReceivingPostpone ) ) )
+        {
+        // In offline mode we cannot ask if we are roaming - just give up
+        if ( !NetworkOperationsAllowed() )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- Offline mode - cannot check network status"));
+#endif
+            error = KMmsErrorOfflineMode;
+            iError = error;
+            }
+        else
+            {
+            // if we get an error we have not been able to connect to phone module
+            // and we cannot ask if we are roaming
+            TRAP( error, iPhone = CMmsPhoneClient::NewL() )
+            }
+
+        if ( error == KErrNone )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- Receivemsg getting network status"));
+#endif
+            iPhone->Roaming( iStatus );
+            }
+        }
+    else
+        {
+        // no roaming check needed
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- Roaming check not needed"));
+#endif
+        TRequestStatus* status = &iStatus;
+        iStatus = KRequestPending;
+        // 0 = home network. If we don't care, we behave as at home
+        User::RequestComplete( status, 0 );
+        }
+        
+    if ( error != KErrNone )
+        {
+        // we got an error - iPhone is not going to complete us
+        TRequestStatus* status = &iStatus;
+        iStatus = KRequestPending;
+        User::RequestComplete( status, error );
+        }
+    SetActive();
+        
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::GetRoamingState
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::GetRoamingState()
+    {
+    
+    // if current receiving modes are valid, we have to set the message fetch state
+    // according to the receiving mode of the current (home or foreign ) network 
+    
+    // Set the message fetch state according to current network value
+    if( iRegistrationStatus != 0 )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("roaming") );
+#endif
+        iReceivingMode = iMmsSettings->ReceivingModeForeign();
+        }
+    else
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("in home network") );
+#endif
+        iReceivingMode = iMmsSettings->ReceivingModeHome();        
+        }
+        
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- message receiving mode is %d"), iReceivingMode );
+#endif
+    
+    // if something is wrong, entries are marked failed.
+    if ( iError != KErrNone )
+        {
+        // Set error to all entries
+        // If some of the entries already have an error set,
+        // it is not overridden.
+        UnSetSendMask( *iFailed, iError );
+
+        }
+    // if we have something in iError, we shall not continue
+    // to open IAP, and RunL will complete. 
+    // All entries will be rescheduled
+
+    }
+// end of ROAMING CHECK handling
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::DecodeResponseL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::DecodeResponseL()
+    {
+    FallThrough();
+    return;
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::ConnectToIapL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::ConnectToIAPL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg open IAP") );
+#endif
+    if ( !iMmsSettings->LocalMode() )
+        {
+        iError = iMmsSettings->ValidateSettings();
+        }
+    CMmsBaseOperation::ConnectToIAPL();
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::InitializeSessionL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::InitializeSessionL()
+    {
+
+    // Here we should connect to MMSC
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg Connecting") );
+#endif
+
+    // for testing purposes our messages are in files in the folder
+    // defined in iMmsSettings->iRootFolder.
+    if ( iMmsSettings->LocalMode() )
+        {
+        HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
+        CleanupStack::PushL( filename );
+        TPtr fileNamePtr = filename->Des();
+        fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
+        iFs.SetSessionPath( fileNamePtr );
+        CleanupStack::PopAndDestroy( filename );
+        }
+
+    CMmsBaseOperation::InitializeSessionL();
+
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::SubmitTransactionL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::SubmitTransactionL()
+    {
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg Receiving") );
+#endif
+    iEntryUnderConstruction = KMsvNullIndexEntryId;
+    iResponse->Reset(); // Reset sets the correct version
+    iAlreadyDeferred = EFalse;
+    iMmsHeaders->Reset();
+    iEncodeBuffer->Reset();
+
+    // We don't totally give up in case of an error.
+    // We may have a long list of entries to handle.
+    // One entry may be garbage while others will be ok.
+    
+    // Call to IsConnected() clears error for a new entry or
+    // sets the error if we are not connected. If we are not
+    // connected, we must terminate the state machine loop
+    if ( !IsConnected() )
+        {
+        return;
+        }
+
+    TMsvEntry entry;
+
+    // Load the notification. If an error occurs, we cannot continue
+    // with this notification.
+    if ( !LoadNotificationL( entry ) )
+        {
+        // LoadNotificationL sets the state machine active if we can continue
+        // to next entry.
+        // If the situation is hopeless, the state machine is not active, and
+        // the loop terminates
+        return;
+        }
+
+
+    TInt size = iNotification->MessageSize();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- message size %d"), size);
+#endif
+    // If the size in notification is bigger than the maximum size we can receive
+    // use the maximum size instead for the memory checks (we are not receiving
+    // more than that anyway)
+    if ( size > iMmsSettings->MaximumReceiveSize() )
+        {
+        // reduce the size to maximum allowed
+        size = iMmsSettings->MaximumReceiveSize();
+        }
+
+    // Now we must check if the message should be rejected or deferred
+    // The function IsNotificationInsaneL() checks if the notification
+    // has incorrect message type or incorrect major version number.
+    // If the message is unrecognized, the response will be "unrecognized"
+    // The funtion sets the status, and later the response will be sent
+    // but there is no need to check for expiration or disk space in
+    // case the message will be rejected anyway.
+    
+    if ( !IsNotificationInsaneL() )
+        {
+        // Check if message has expired.
+        // If it has, and we are in automatic mode, there is no need
+        // to send a response.
+        if ( !CheckExpirationL() )
+            {
+            return;
+            }
+
+        // Check disk space.    
+        // we must add the safety margin here...
+        size += KMmsDiskSafetyMargin;
+
+        // Query about disk space.
+        if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
+            &iFs, size, iMessageDrive ) )
+            {
+            iNotification->SetStatus( KMmsMessageStatusDeferred );
+            iError = KErrDiskFull;
+            }
+        }
+
+    // if we have got an error for this message (KErrNoMemory or
+    // KErrDiskFull) we must store the information in the notification
+    // entry to discern these situations from cases where there
+    // is something wrong with the actual transaction.
+    if ( iError != KErrNone )
+        {
+        TInt error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+        // If we cannot update our entry - that's too bad
+        if ( error == KErrNone )
+            {
+            TMsvEntry tEntry;
+            tEntry = iServerEntry->Entry();
+            tEntry.iError = iError;
+            iServerEntry->ChangeEntry( tEntry );
+            }
+        // we clear the error now. The rest of the branching
+        // is not based on iError but on the notification status
+        iError = KErrNone;
+        // Release the entry
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        }
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- notification status %d"), iNotification->Status() );
+    switch ( iNotification->Status() )
+        {
+        case KMmsMessageStatusRejected:
+            TMmsLogger::Log( _L("- rejected") );
+            break;
+        case KMmsMessageStatusDeferred:
+            TMmsLogger::Log( _L("- deferred") );
+            break;
+        case KMmsMessageStatusRetrieved:
+            TMmsLogger::Log( _L("- retrieved") );
+            break;
+        case KMmsMessageStatusUnrecognized:
+            TMmsLogger::Log( _L("- unrecognized") );
+            break;
+        default :
+            TMmsLogger::Log( _L("- whatever") );
+            break;
+        }
+#endif
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- receiving mode: %d"), iReceivingMode );
+#endif
+
+    // Sending the response tells the MMSC that the 
+    // notification has been received and understood.
+    // If we do not want to fetch the message the
+    // WantToFetchThisL() subroutine will change the state
+    // so that after return the response will be sent to MMSC
+    
+    if ( !WantToFetchThisL( entry ) )
+        {
+        return;
+        }
+
+    // Now it seems that we are supposed to fetch something
+    // The notification has cleared all our tests and fetching is on
+
+    // Now we should start a GET transaction with the
+    // URI we obtain from the headers
+           
+    // If we fail to get anything because the message has expired,
+    // we set iEntryUnderConstruction to KMsvNullIndexEntryId
+    // Otherwise we must reschedule the receive
+
+    // At this point we will invoke the transaction that sends
+    // our get request to MMSC and when the transaction completes,
+    // the data has been stored in our encode buffer, if the status
+    // is KErrNone. Otherwise the completion status will contain the
+    // error code.
+
+    if ( iMmsSettings->LocalMode() )
+        {
+        LocalModeFetchL();
+        // if only local mode, we complete ourselves
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- local mode, completing fetch with status %d"), iError );
+#endif
+        if ( !IsActive() )
+            {
+            // If Local mode fetch fails it already calls ChangeStateL() and becomes active
+            // we cannot set us active a second time
+            FallThrough();
+            }
+        }
+    else // global mode
+        {
+        // Chunked mode in global mode, too
+        // chunked mode is turned on here - other changes are generic
+        DoCreateEntryL();
+        iDecoder->InitializeChunkedMode( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer );
+        // end of chunked preparation
+        
+        // we get this far only if we are connected
+        HBufC* uri = HBufC::NewL( iNotification->ContentLocation().Length() + KMMSBufferExtra );
+        CleanupStack::PushL( uri );
+        uri->Des().Copy( iNotification->ContentLocation() );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("...Fetching from URI: %S"), uri );
+#endif
+        iMmsSession->FetchMessageL(
+            *uri, 
+            *iEncodeBuffer,
+// Use this buffer size when in chunked mode             
+            KMmsChunkedBufferSize, // tell that only this buffer size is needed
+            *iEncoder,
+            *iDecoder,
+            iStatus );
+        CleanupStack::PopAndDestroy( uri );
+        SetActive();
+        }
+
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+TBool CMmsReceiveMessage::IsConnected()
+    {
+    if ( iConnected )
+        {
+        // We clear the error at this point to tell that this message
+        // is all right so far. Notifications for failed messages
+        // remain in the selection, and they are rescheduled later
+        // The error is saved in the schedule data for the notification.
+        iError = KErrNone;
+        }
+    else
+        {
+        // We are in a totally hopeless mess.
+        // We don't have a connection. iError should contain the reason
+        // all we can do is give up
+        // If we return from RunL without becoming active again
+        // RunL completes.
+        // That's all we can do here...
+        // The selection arrays have information about
+        // which messages have succeeded and which not.
+
+        // DoComplete sets an error code to those entries in the
+        // failed list that do not already have their error set.
+        // If we don't know what went wrong, we just say "disconnected"
+        if ( iError == KErrNone )
+            {
+            iError = KErrDisconnected;
+            }
+        }
+    return iConnected;    
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsReceiveMessage::LoadNotificationL( TMsvEntry& aEntry )
+    {
+    // set entry to next notification in list
+    iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+    if ( iError != KErrNone )
+        {
+        // The code called by SkipEntryL will make us active again
+        // We may now try the next entry.
+        SkipEntryL();
+        return EFalse;
+        }
+
+    aEntry = iServerEntry->Entry();
+    if ( aEntry.iMtmData2 & KMmsNotifyResponseSent )
+        {
+        iAlreadyDeferred = ETrue;
+        }
+
+    CMsvStore* store = NULL;
+
+    TRAP (iError, {store = iServerEntry->ReadStoreL();});
+    // We have managed to generate some mysterious notifications
+    // where the ReadStoreL fails.
+    // These must be deleted, as they are garbage.
+    // I assume they are used by someone else.
+    // This means we just delete them from our list and forget them
+    // If we cannot get a read store, we cannot do anything with the
+    // schedule either.
+    if ( iError == KErrNoMemory )
+        {
+        // Out of memory - hopeless.
+        // We return without becoming active again and the 
+        // whole loop completes.
+        // We should try to disconnect, but if there is a serious
+        // memory problem I doubt that anything will work.
+
+        // Release the entry
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        return EFalse;
+        }
+        
+    if ( iError != KErrNone )
+        {
+        // don't discard the entry completely now
+        delete store;
+        store = NULL;
+        // The code called by SkipEntryL will make us active again
+        SkipEntryL();
+        return EFalse;
+        }
+        
+    // We have access to the notification
+    CleanupStack::PushL( store );
+    iNotification->RestoreL( *store );
+    CleanupStack::PopAndDestroy( store );
+    
+    // We must clear deferred status always:
+    // If we did not have enough memory the first time,
+    // the message was deferred. If we now have enough 
+    // memory the old status must be cleared
+
+    iNotification->SetResponseStatus( 0 ); // clear possible old status
+    iNotification->SetResponseTextL( TPtrC() ); // clear possible old text
+
+    if ( iNotification->Status() == KMmsMessageStatusDeferred )
+        {
+        iNotification->SetStatus( 0 );
+        }
+
+    // We must check if message fetching is deferred or totally off.
+    // if iReceivingMode == EMmsReceivingReject, notification has been deleted already.
+    if ( !iMmsSettings->FetchOverride() &&
+        iNotification->Status() == 0 &&
+        ( iReceivingMode == EMmsReceivingManual || iReceivingMode == EMmsReceivingPostpone ) )
+        {
+        iNotification->SetStatus( KMmsMessageStatusDeferred );
+        }
+    
+    // We get this far only if we are connected
+    aEntry.SetConnected( ETrue );
+    aEntry.SetSendingState( KMsvSendStateSending );
+    aEntry.iError = KErrNone; // optimistic...
+    iServerEntry->ChangeEntry( aEntry );
+
+    // Release the entry
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    // Continue with this notification
+    return ETrue;
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsReceiveMessage::CheckExpirationL()
+    {
+    
+    // If the message has expired, it can be rejected without further ado
+    // We allow a little slack here, if it expired just a few seconds ago,
+    // we still have hope...
+    // use universal time in case user changes location
+    TTime now;
+    TMsvEntry entry;
+    TBool canContinue = ETrue; // optimistic
+
+    now.UniversalTime();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MMS terminal universal datetime: ") );
+    CMmsBaseOperation::LogDateL( now );
+    TMmsLogger::Log( _L("MMS message expiry datetime:") );
+    CMmsBaseOperation::LogNetworkFormatDateL( iNotification->ExpiryDate() );
+#endif
+    if ( ( ( iNotification->ExpiryDate() + iMmsSettings->ExpiryOvershoot() ) * KMmsMillion ) <
+        now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("message has expired by %d seconds"),
+            ( now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64())/KMmsMillion -
+            iNotification->ExpiryDate() - iMmsSettings->ExpiryOvershoot() );
+#endif
+        // If the notification is in inbox or in MMBox folder, fetch will continue.
+        if( entry.Parent() == KMsvGlobalInBoxIndexEntryId  ||
+            entry.Parent() == iMmsSettings->MMBoxFolder() )
+            {
+            // Mark the notification expired
+            iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+            if ( iError == KErrNone )
+                {
+                entry = iServerEntry->Entry();
+                entry.iMtmData2 |= KMmsMessageExpired;
+                iServerEntry->ChangeEntry( entry );
+                }
+            // Release the entry
+            iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("Expired notification. Fetch continues") ); 
+#endif
+            }
+        else
+            {
+            // iError == KErrNone, the last stage will just remove our entry from the list
+            // There is no need to send any reply to an expired message.
+            // The MMSC will not be interested in getting a "reject"
+            // response to an expired message.
+            iResponse->SetStatus( KMmsMessageStatusRejected );
+            iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+            // return to the beginning of the state machine loop
+            iState = EMmsOperationUpdatingEntryStatus;
+            // The code called by ChangeStateL will make us active again
+            ChangeStateL();
+            canContinue = EFalse; // loop to next state
+            }
+        }
+    return canContinue; // can continue
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsReceiveMessage::IsNotificationInsaneL()
+    {
+    TBool isInsane = EFalse; // optimistic
+    // If the message is unrecognized, the response will be "unrecognized"
+    // Either the message type is unknown, or the major version number differs
+    if  ( ( iNotification->MmsVersion() & KMmsMajorVersionMask ) !=
+        ( iMmsSettings->MmsVersion() & KMmsMajorVersionMask ) )
+        {
+        // major versions differ, send back 1.0 version response
+        iResponse->SetMmsVersion( KMmsVersion1 );
+        iNotification->SetStatus( KMmsMessageStatusUnrecognized );
+        iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+        isInsane = ETrue;
+        }
+    else if ( iNotification->MessageType() != KMmsMessageTypeMNotificationInd && 
+        iNotification->MessageType() != KMmsMessageTypeMBoxDescr )
+        { 
+        // We have been pushed something we cannot handle.
+        // delivery reports have been picked out earlier, so they cause
+        // no problems here.
+        iNotification->SetStatus( KMmsMessageStatusUnrecognized );
+        iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+        isInsane = ETrue;
+        }
+    return isInsane;
+    }
+       
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsReceiveMessage::WantToFetchThisL( TMsvEntry& aEntry )
+    {
+    if ( ( iReceivingMode != EMmsReceivingAutomatic && !iMmsSettings->FetchOverride() ) ||
+        iNotification->Status() == KMmsMessageStatusRejected ||
+        iNotification->Status() == KMmsMessageStatusDeferred ||
+        iNotification->Status() == KMmsMessageStatusRetrieved ||
+        iNotification->Status() == KMmsMessageStatusUnrecognized )
+        {
+        // We don't want this message for one reason or another
+        // We shall send reject message or deferred message and
+        // remove this notification from the scheduling.
+        // If the fetching is deferred, the notification should remain
+        // in the machine waiting for better times.
+        // If the message is rejected, the notification is deleted.
+        // In both cases the schedule must be removed. A deferred
+        // notification is not rescheduled before the message fetching
+        // is turned on again.
+
+        // If the whole message is in the extended notification,
+        // the status is "retrieved"
+
+        // However, if the "deferred" response has already been sent,
+        // we should not send it again
+
+        iResponse->SetStatus( iNotification->Status() );
+
+        if ( iResponse->Status() != KMmsMessageStatusRejected &&
+            iResponse->Status() != KMmsMessageStatusDeferred &&
+            iResponse->Status() != KMmsMessageStatusRetrieved &&
+            iResponse->Status() != KMmsMessageStatusUnrecognized )
+            {
+            // We have an unlucky message. The notification arrived
+            // while we were supposed to fetch it, but before it was
+            // actually fetched, receiving was turned off.
+            // We try to defer it hoping it can be fetched before it
+            // expires.
+            // A message should be scheduled for fetching only a few
+            // seconds after the notification arrives, so that if the 
+            // user manages to turn the fetching off before we fetch 
+            // the message we can assume that he does not want this one either
+            // (at least not now). We are a bit conservative, though,
+            // we don't reject this one as it was supposed to be fetched
+            // before it fell into the time trap.
+            iResponse->SetStatus( KMmsMessageStatusDeferred );
+            }
+
+        if ( aEntry.iMtmData2 & KMmsNotifyResponseSent )
+            {
+            // if the notify response has already been sent for this message,
+            // we don't send it again.
+            // When the message fetch state is switched back on,
+            // server Mtm must check the pending notifications and
+            // reschedule them for fetching.
+            // An already deferred notification should not be in our
+            // list, but I'm paranoid and check in case some notification
+            // has fallen into a time trap.
+            iAlreadyDeferred = ETrue;
+            iState = EMmsOperationStoringResponseData;
+            }
+        else
+            {
+            // The function called by ChangeStateL will make us active again
+            iState = EMmsOperationStoringResponseData;
+            }
+        // We are not fetching this message.
+        // Either we send a response to MMSC or we just move to next notification.
+        ChangeStateL();
+        return EFalse;
+        }
+    return ETrue;
+    }
+        
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::DoCreateEntryL()
+    {
+    
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg DoCreateEntryL") );
+#endif
+
+    // We create a message entry into the inbox
+    // it is invisible and in preparation until
+    // we decide that we have successfully fetched the message
+    // The entry must exist before the message is fetched, because
+    // decode puts data into an existing entry, and
+    // creates children to the entry for attachments.
+
+    // If we have failed in storing data to the entry, it may be non-zero
+    // We try to delete it before creating a new one
+
+    if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
+        {
+        if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId ) == KErrNone )
+            {
+            iServerEntry->DeleteEntry ( iEntryUnderConstruction );
+            }
+        iEntryUnderConstruction = KMsvNullIndexEntryId;
+        }
+
+    // If the creation of the entry is successful, we
+    // set our entry to point to the newly created entry
+    // to get data content to it.
+    if ( iError == KErrNone )
+        {
+        TMsvId targetId = KMsvGlobalInBoxIndexEntryId;
+
+        TMsvEntry tEntry;
+
+        // set all relevant flags in tMsvEntry
+        tEntry.iType = KUidMsvMessageEntry;
+        tEntry.iMtm = KUidMsgTypeMultimedia;
+        tEntry.iServiceId = iService;
+        tEntry.SetUnread( ETrue );
+        tEntry.SetNew( ETrue );
+        tEntry.SetVisible( EFalse );
+        tEntry.SetComplete( EFalse );
+        tEntry.SetInPreparation( ETrue );
+        tEntry.SetReadOnly( EFalse );
+
+        // Query about disk space.
+        if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
+            &iFs, KMmsIndexEntryExtra, iMessageDrive ) )
+            {
+            // we use standard error code here
+            iError = KErrDiskFull;
+            }
+        if ( iError == KErrNone )
+            {
+            iError = iServerEntry->SetEntry( targetId );
+            }
+
+        if ( iError == KErrNone )
+            {
+            iError = iServerEntry->CreateEntry( tEntry );
+            }
+        iEntryUnderConstruction = tEntry.Id();
+        if ( iError == KErrNone )
+            {
+            iError = iEntryWrapper->SetCurrentEntry( iEntryUnderConstruction );
+            }
+        }
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::StoreResponseL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::StoreResponseL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg Store Response") );
+#endif
+    TInt error;
+    TInt fatal = EFalse; // fatal error, no use to retry
+
+    // If we have got this far, we don't return to CreateEntry anymore
+    // even if we encounter backup/restore problems later.
+
+    if ( iError == KErrNone )
+        {
+        // if we have no error, me must retry to make the entry visible
+        iCriticalState = EMmsOperationStoringResponseData;
+        }
+    else
+        {
+        iCriticalState = EMmsOperationSendingAck;
+        }
+
+    // At the moment we should not receive any extra message types,
+    // so that the only error of this type would
+    // be wrong type of message either from WAP stack or from MMSC.
+    // Send request is all right in local mode, as we get back
+    // the messages we send ourselves.
+    // We accept the send requests as retrieve confirmations,
+    // as they are importand during testing phase:
+    // We can put any message someone has sent into the folder
+    // representing the simulated MMSC and try to fetch it as
+    // if it were a real message.
+    // We can't check the message type if we have encountered an error.
+    // In that case the headers may not have been correctly decoded
+    if ( iError == KErrNone &&
+        iResponse->Status() != KMmsMessageStatusRejected &&
+        iResponse->Status() != KMmsMessageStatusDeferred &&
+        iResponse->Status() != KMmsMessageStatusRetrieved &&
+        iMmsHeaders->MessageType() != KMmsMessageTypeMRetrieveConf &&
+        iMmsHeaders->MessageType() != KMmsMessageTypeMSendReq )
+        {
+        iResponse->SetStatus( KMmsMessageStatusUnrecognized );
+        iError = KMmsErrorStatusUnsupportedMessage;
+        }
+
+    // If we have managed to decode the response, it may contain a status
+    // that must be mapped to an error. The error may be permanent or temporary
+
+    if ( iError == KErrNone )
+        {
+        // we have got a response from MMSC, and decoded it, but in version 1.1
+        // or later the response may still contain an error code.
+        // if response text length was 0, it was deleted
+
+        // - if error is permanent, notification will be deleted.
+        // - if error is transient, response text is copied to notification
+        // and UI components may show it to the user if needed.
+        
+        // iError is set to the correct value depending on response status
+        // "fatal" indicates if the error is permanent or temporary
+        fatal = MapErrorStatus( iMmsHeaders->ResponseStatus() );
+        }
+
+    // If we get a transient failure from MMSC, we store the possible text and status code
+    // into our notification. UI may show the text to the user in case there is something
+    // the user might do about the failure. Permament failures are stored in the message
+    // entry.
+    // The application id is also copied to the notification in case application id is present
+    // in the message but not in the notification.
+    // If the application has not been registered or memory runs out, the user may be
+    // informed that the notification refers to a message that belongs to an application.
+        
+    CopyDataFromMessageToNotificationL();
+
+    // If there has been an error and logging is allowed, dump the buffer into a file
+    // to support error analysis later
+    DumpIfNeededL();
+    
+    // We must try to finalize even if we have encountered an error.
+    // If the decode has failed, iError contains something like "KErrCorrupt".
+    // If the operation has been successful, we make the entry visible
+    // and remove the in preparation flag. The user should then be able
+    // to see the new message entry.
+
+    // free the memory we don't need anymore
+    if ( iEncodeBuffer )
+        {
+        iEncodeBuffer->Reset();
+        }
+    TMsvEntry tEntry;
+    
+    // Check if the message is going to an unregistered application.
+    // If it is, it's going to be rejected
+    iRegistered = EFalse;
+    
+    if ( iMmsHeaders->ApplicId().Length() > 0 )
+        {
+        iRegistered = RegisteredL( iMmsHeaders->ApplicId() );
+        if ( !iRegistered )
+            {
+            // not registered - reject it
+            iResponse->SetStatus( KMmsMessageStatusRejected );
+            // we clear whatever error we may have because we are
+            // going to reject the message anyway.
+            iError = KErrNone;
+            }
+        }
+        
+    // If the message is going to an application we must check if we can free disk
+    // space by deleting older messages addressed to the same application.
+    
+    if ( iError == KErrDiskFull && iRegistered )
+        {
+        // Check if we can free disk space and reschedule the fetch.
+        // In manual mode the fetch will not be rescheduled.
+        // If we can free memory we will change the error code to KMmsErrorApplicationDiskFull
+        // If we cannot free memory, the error code is left as is and the user must
+        // delete something else in order to be able to receive the message.
+        DeleteApplicationMessagesL();
+        }
+
+    // If we have tried to fetch a message, and got 
+    // EMRUExceeded, we'll reject the message. If it
+    // was already deferred, no new response is sent.
+    // The notification will be deleted, it is hopeless.
+
+    if ( iError == KMmsErrorEMRUExceeded )
+        {
+        iResponse->SetStatus( KMmsMessageStatusRejected );
+        iFailed->Delete( iCurrentMessageNo - 1 );
+        iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+        }
+
+    if ( iError != KErrNone ||
+        iResponse->Status() == KMmsMessageStatusRejected ||
+        iResponse->Status() == KMmsMessageStatusDeferred ||
+        iResponse->Status() == KMmsMessageStatusRetrieved ||
+        iResponse->Status() == KMmsMessageStatusUnrecognized )
+        {
+        // If the failure was fatal (permanent error from MMSC)
+        // we don't send any response back. If the failure was
+        // not fatal, we send "deferred" hoping we can retry later
+        if ( fatal )
+            {
+            // The notification is deleted, as we have got an MMS message.
+            iFailed->Delete( iCurrentMessageNo - 1 );
+            iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+            // we don't send back a response if failing was fatal.
+            iResponse->Reset();
+            }
+        else if ( iError == KMmsErrorHTTPConfiguration ||
+            iError == KMmsErrorHTTPNotFound ||
+            iError == KMmsErrorHTTPServerDown ||
+            iError == KMmsErrorHTTPClientError )
+            {
+            // if we have got a HTTP error, there is no sense to send ack back
+            iResponse->Reset();
+            }
+        else if ( !iAlreadyDeferred &&
+            iResponse->Status() != KMmsMessageStatusRejected &&
+            iResponse->Status() != KMmsMessageStatusRetrieved &&
+            iResponse->Status() != KMmsMessageStatusUnrecognized)
+            {
+            iResponse->SetStatus( KMmsMessageStatusDeferred );
+            EncodeNotifyResponseL();
+            }
+        else if ( iResponse->Status() == KMmsMessageStatusUnrecognized || 
+            iResponse->Status() == KMmsMessageStatusRejected)
+            {
+            EncodeNotifyResponseL();
+            }
+        else if ( iResponse->Status() == KMmsMessageStatusRetrieved )
+            {
+            EncodeNotifyResponseL();
+            iFailed->Delete( iCurrentMessageNo - 1 );
+            iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+            }
+        else
+            {
+            // We have nothing to send, we hope we can try
+            // again later.
+            iResponse->Reset();
+            }
+        }
+
+#ifndef _NO_MMSS_LOGGING_
+    // log the response status we are about to send
+    TMmsLogger::Log( _L("- Response status to be: %d"), iResponse->Status() );
+#endif
+
+    // If we have no entry, the fetching has failed. If the failing was fatal,
+    // the notification has been appended to the iBad list.
+    // It will be deleted from the iFailed list later.
+    // Those entries that end in the iBad list are just
+    // deleted, not rescheduled.
+    
+    TInt applicationMessageStatus = 0;
+    
+    // If we got an error, we delete the entry under construction.
+    // But if the error is "fatal" it means MMSC returned some error message,
+    // and the error message entry must be kept and shown to the user
+    // The corresponding notification remains in the failed list
+    // in order to be rescheduled.
+    // If the notification was bad, the corresponding notification
+    // has already been appended to bad list to be removed from 
+    // task scheduler.
+    if ( iEntryUnderConstruction != KMsvNullIndexEntryId && iError != KErrNone && !fatal )
+        {
+        if ( iMmsSettings->LocalMode() )
+            {
+            CloseLocalFileL( EFalse );
+            }
+        // if setting server entry to inbox fails, deletion of entry will fail,
+        // but there is nothing we can do about it.    
+        iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId );
+        iServerEntry->DeleteEntry ( iEntryUnderConstruction );
+        iEntryUnderConstruction = KMsvNullIndexEntryId;
+        }
+        
+    if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
+        {
+        // We don't care if this leaves. We just do our best.
+        // If this function fails, our message will have some extra parts
+        TRAP( error, HandleMultipartAlternativeL() );
+        }
+    
+    // If we have an entry we have either successfully fetched a message
+    // or received an error message about a fatal (permanent) error from MMSC
+    // The entry must now be made visible to the user.    
+    if ( iEntryUnderConstruction != KMsvNullIndexEntryId )
+        {
+        error = iServerEntry->SetEntry( iEntryUnderConstruction );
+
+        if ( error == KErrNone )
+            {
+            // we don't check disk space here, as this
+            // is local mode only: We just save the message id
+            // for testing purposes. The message id is about 5 bytes
+            // And we clear possible TID, that makes message shorter than before.
+            CMsvStore* store = NULL;
+            TRAP ( error, store = iServerEntry->EditStoreL() )
+            if ( store )
+                {
+                CleanupStack::PushL( store );
+                }
+            if ( iMmsSettings->LocalMode() &&
+                iMmsHeaders->MessageId().Length() == 0 )
+                {
+                iMmsHeaders->SetMessageIdL(
+                    iNotification->ContentLocation().Mid(
+                    iMmsSettings->LocalModeIn().Length() ) );
+                }
+            if ( iAlreadyDeferred )
+                {
+                // we need to save the TID from the message to the response
+                iResponse->SetTidL( iMmsHeaders->Tid() );
+                }
+            // clear TID from the message to prevent the same TID from being used later
+            // in case the message is copied around.
+            iMmsHeaders->SetTidL( TPtrC8() );
+            // Data is copied in case the message does not contain sender or subject
+            // Data is copied only if disk space is not below critical level
+            CopyDataFromNotificationToMessageL();
+            if ( store )
+                {
+                TRAP ( error, 
+                    {
+                    iMmsHeaders->StoreL(*store);
+                    store->CommitL();
+                    });
+                // If we managed to create the store without leaving, it is on cleanup stack
+                CleanupStack::PopAndDestroy( store );
+                store = NULL;
+                }
+            if ( iAlreadyDeferred )
+                {
+                // restore the TID
+                iMmsHeaders->SetTidL( iResponse->Tid() );
+                }
+
+            tEntry = iServerEntry->Entry();
+            
+            // If message contains application id, check, 
+            // if a folder, the name of which is application id is found
+            // and move the message to this folder.
+            // If the application is not registered, the message is deleted
+            applicationMessageStatus = MoveToApplicationFolderIfNeededL( tEntry );
+            
+            if ( applicationMessageStatus != KMmsMessageForUnregisteredApplication )
+                {
+                // reload the entry in case the message was moved
+                tEntry = iServerEntry->Entry();
+                            
+                SetIndexEntryBitsForReceivedMessage( tEntry );
+
+                // if we cannot make our entry visible because of backup/restore, we must retry.
+                error = iServerEntry->ChangeEntry( tEntry );
+
+                // This is the critical point.
+                // We must return before iEntryUnderConstruction is set to KMsvNullIndexEntryId
+                // and the notification list is edited
+
+                if ( error <= (TInt) KMsvMediaUnavailable &&
+                    error >= (TInt) KMsvIndexRestore &&
+                    !iDoNotWaitForBackupEnd )
+                    {
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- must wait for backup end ") );
+#endif
+                    iState = EMmsOperationWaitingForBackupEnd;
+                    // This will take us back to RunL
+                    WaitForBackupEnd();
+                    return;
+                    }
+                }
+
+            if ( iMmsSettings->LocalMode() )
+                {
+                CloseLocalFileL( ETrue );
+                }
+
+            // done with this entry
+            iEntryUnderConstruction = KMsvNullIndexEntryId;
+            }
+
+        // The task manager seems to handle deletion of entries
+        // gracefully nowadays. We can just delete handled entries
+        // We delete the notification as soon as possible
+        // as we don't want it hanging around after the message
+        // has been successfully fetched
+
+        if ( !fatal )
+            {
+            // Check duplicate before deleting notification entry
+            if ( iNotificationParent == KMsvGlobalInBoxIndexEntryIdValue ||
+                ( iNotificationParent == iMmsSettings->MMBoxFolder() ))
+                {
+                // For the time being Java wants these notifications to be deleted
+                // and applicationMessageStatus is always 0.
+                // This may change for other type of applications.
+                ClearOperationL( applicationMessageStatus );
+                }
+            else
+                {
+                // If the notification is not visible to the user,
+                // we don't need to save the application routing status.
+                // The rest of the handling can proceed normally - 
+                // the notification will be deleted
+                applicationMessageStatus = 0;
+                }
+
+            // If the notification does not need to be left around to inform user,
+            // it can be deleted now                    
+            if ( applicationMessageStatus == 0 )
+                {
+                error = iServerEntry->SetEntry( iNotificationParent );
+                if ( error == KErrNone )
+                    {
+                    iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+                    }
+                else
+                    {
+                    // we use this list as backup:
+                    // if we cannot delete now, we try again later.
+                    iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+                    }
+                }
+            // Even if the notification was left in the inbox,
+            // it is deleted from the failed list because it needs no more handling    
+            iFailed->Delete( iCurrentMessageNo - 1 );
+            
+            // All went well. We can acknowledge the delivery.
+            // If the MMSC is not interested in the acknowledgement,
+            // it has sent us no TID.
+            // If there is no TID, the response won't be sent.
+            // If Retrieve confirmation has not been sent, it must be
+            // sent instead of acknowledge indication
+            
+            // We don't send an ack back if we have received a response
+            // from MMSC that indicates a fatal failure.
+            // Most likely the message was expired or has disappeared
+            // for some other reason (or did not exist in the first place)
+            
+            iResponse->SetStatus( KMmsMessageStatusRetrieved );
+            if ( !iAlreadyDeferred )
+                {
+                EncodeNotifyResponseL();
+                }
+            else
+                {
+                EncodeAcknowledgeIndicationL();
+                }
+            }
+        }
+
+    if ( iFileOpen )
+        {
+        iFile.Close(); // just in case...
+        iFileOpen = EFalse;
+        }
+        
+    // release entry in case we were holding the service entry
+    // We should not leave our entry pointing to the serive entry 
+    // when we become active, others may want to use it.
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    iStatus = KRequestPending;
+    SetActive();
+    TRequestStatus* status = &iStatus;
+    // We propagate the original error no matter what has happened here
+    User::RequestComplete( status, iError );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::SendAckL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::SendAckL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg Sending response to receive request") );
+#endif
+
+    // Send response to MMSC.
+    // response is in iResponse.
+    // If no reply should actually be sent, length of TID is 0.
+
+    // We may try to send response even if we have encountered an error.
+    // We try to send "deferred" if we couldn't fetch the message.
+    // We hope the MMSC will try to keep the message in that case.
+
+    // iResponse has Tid, if it contains something reasonable.
+
+    if ( iResponse->Tid().Length() > 0 )
+        {
+        if ( !iMmsSettings->LocalMode() )
+            {
+            // send the response
+            iMmsSession->SendMessageL(
+                iUri->Des(),
+                *iEncodeBuffer,
+                *iEncoder,
+                *iDecoder,
+                iStatus );
+            SetActive();
+            }
+        else
+            {
+            iStatus = KRequestPending;
+            SetActive();
+            TRequestStatus* status = &iStatus;
+            // We propagate the original error no matter what has happened here
+            User::RequestComplete( status, iError );
+            }
+        }
+    else
+        {
+        // No response to send.
+        // Just continue to next state.
+        iStatus = KRequestPending;
+        SetActive();
+        TRequestStatus* status = &iStatus;
+        // We propagate the original error no matter what has happened here
+        User::RequestComplete( status, iError );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::UpdateEntryStatusL()
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::UpdateEntryStatusL()
+    {
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Receivemsg Checking response success") );
+#endif
+    
+    TInt error;
+    TMsvEntry tEntry;
+    TInt count = iBad->Count() - 1;
+
+    // update scheduling info for this notification
+    error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+    if ( error == KErrNone )
+        {
+        tEntry = iServerEntry->Entry();
+        error = tEntry.iError;
+        if ( error == KErrNone )
+            {
+            error = iError;
+            }
+        // In some rare cases accessing the store for the notification may fail
+        // in that case the schedule is not updated.
+        TRAP( error,
+            {
+            CMsvStore* store = iServerEntry->EditStoreL();
+            CleanupStack::PushL( store );
+            CMmsScheduledEntry* mmsScheduledEntry =
+                CMmsScheduledEntry::NewL( iServerEntry->Entry() );
+            CleanupStack::PushL( mmsScheduledEntry );
+            mmsScheduledEntry->RestoreL( *store );
+            UpdateRecipient( iError, *mmsScheduledEntry );
+            mmsScheduledEntry->StoreL( *store );
+            store->CommitL();
+            CleanupStack::PopAndDestroy( mmsScheduledEntry );
+            CleanupStack::PopAndDestroy( store );
+            });
+        }
+
+    // If the current notification has entered the "bad" list,
+    // it should not be rescheduled.
+    // For example, the message may be "deferred" because it is too
+    // big to ever fit in our phone. It must be deleted from the "failed"
+    // list, because it should not be rescheduled.
+
+    TInt count2 = iFailed->Count() - 1;
+    if ( count >= 0 &&
+        count2 >= ( iCurrentMessageNo - 1 ) &&
+        iBad->At( count ) == iFailed->At( iCurrentMessageNo - 1 ) )
+        {
+        // should not be rescheduled.
+        iFailed->Delete( iCurrentMessageNo - 1 );
+        }
+    else if ( iError == KErrNone )
+        {
+
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("Receivemsg all is well") );
+#endif
+        // All is well.
+        // If message was rejected the notification can be thrown away
+        
+        if ( iResponse->Status() == KMmsMessageStatusRejected ||
+             iResponse->Status() == KMmsMessageStatusUnrecognized )
+            {
+            // The notifications in the received list will be deleted.
+            // If the message was rejected, the notification will be
+            // deleted.
+            error = iServerEntry->SetEntry( iNotificationParent );
+            if ( error == KErrNone )
+                {
+                iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+                }
+            else
+                {
+                // we use this list as backup:
+                // if we cannot delete now, we try again later.
+                iSuccessful->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+                }
+            iFailed->Delete( iCurrentMessageNo - 1 );
+            }
+
+        if ( iResponse->Status() == KMmsMessageStatusDeferred )
+            {
+
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("Receivemsg responsestatus is deferred.") );
+#endif
+            // we have sent a "deferred" response.
+            // We should keep the notification, but not reschedule it.
+            // If we delete it from failed list, it wont get rescheduled.
+            // If we don't add it into received list, it will not be deleted.
+            // We must mark, that the "deferred" response was successfully sent
+            // so that we will not send it again later.
+
+            error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+            // If we cannot update our entry - that's too bad
+            // it just means that the response may be sent a second time...
+            // The system must not get mad about that.
+            // The system may be unreliable anyway, and some response may get lost.
+            // We just do our best.
+            if ( error == KErrNone )
+                {
+                iNotification->SetStatus( KMmsMessageStatusDeferred );
+                CMsvStore * store = iServerEntry->EditStoreL();
+                CleanupStack::PushL( store );
+                iNotification->StoreL( *store );
+                store->CommitL();
+                CleanupStack::PopAndDestroy( store );
+                tEntry = iServerEntry->Entry();
+                tEntry.iMtmData2 |= KMmsNotifyResponseSent;
+                tEntry.iMtmData2 &= ~KMmsDeferredButResponseNotSent;
+                tEntry.SetConnected( EFalse );
+                tEntry.SetFailed( EFalse );
+                tEntry.SetSendingState( KMsvSendStateUnknown );
+
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("Receivemsg notify response sent") );
+#endif
+
+                // change the iMtm type to notification 
+                // and move the notification to the inbox
+                TBool moveToInbox = EFalse;
+                
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- message receiving mode %d"), iReceivingMode );
+#endif
+                if( iReceivingMode == EMmsReceivingManual && !iMmsSettings->FetchOverride() )
+                    {          
+                    // Change the iMtm from KUidMsgTypeMultimedia to 
+                    // KUidMsgMMSNotification   
+                    tEntry.iMtm = KUidMsgMMSNotification;
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("marking as a notification") );
+#endif
+
+#ifndef _NO_MMSS_LOGGING_
+TMmsLogger::Log( _L("tentry.iMtm is %d"), tEntry.iMtm.iUid );
+#endif
+                    tEntry.SetVisible( ETrue );
+                    tEntry.SetComplete( ETrue );
+                    tEntry.SetInPreparation( EFalse );
+                    tEntry.SetReadOnly( ETrue );
+                    // This is a notification, therefore there is no sending time available.
+                    // We can only display the arrival time
+                    tEntry.iDate.UniversalTime(); // this is arrival time
+                    
+                    tEntry.iMtmData1 |= KMmsMessageMobileTerminated;
+            
+                    // Subject, sender and size are set in CMmsDecode.
+                    // Notification cannot contain multiple recipients
+                    // no need to check or set the multiple recipient bit
+                    
+                    moveToInbox = ETrue;
+                    }
+                iServerEntry->ChangeEntry( tEntry );
+
+                           
+                // if manual mode is on and the fetchoverride is not on.
+                // we have received a notification and sent a notifyresponse to the MMSC
+                // the notification should be moved to the inbox
+                if ( moveToInbox )
+                    {
+
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("Receivemsg notification entry to Inbox") );
+#endif
+                   
+                    if ( iServerEntry->SetEntry( tEntry.Parent() ) == KErrNone )
+                        {
+                        iServerEntry->MoveEntryWithinService( tEntry.Id(),
+                            KMsvGlobalInBoxIndexEntryIdValue );
+                        }
+                    }
+                }
+            
+            if ( iReceivingMode != EMmsReceivingAutomatic && !iMmsSettings->FetchOverride() )
+                {
+                // If fetching is on, the message was deferred because of an error.
+                // In that case we let it remain in the failed list for retries.
+                // If fetching is deferred, manual or off, we don't keep the failed list,
+                // The receiving mode must be changed before we retry the operation.
+
+                // Should we remove the schedule...
+                iFailed->Delete( iCurrentMessageNo - 1 );
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("Receivemsg deleting from the iFailedList") );
+#endif
+                }
+            }
+        }
+    else
+        {
+        // keep LINT happy
+        }
+
+    // release entry in case we were holding the service entry
+    // We should not leave our entry pointing to the serive entry 
+    // when we become active, others may want to use it.
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    // just return back to the start of the loop
+    // to handle next message
+    iStatus = KRequestPending;
+    SetActive();
+    TRequestStatus* status = &iStatus;
+    // We propagate the original error no matter what has happened here
+    User::RequestComplete( status, iError );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::EncodeNotifyResponseL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::EncodeNotifyResponseL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- encoding m-notifyresp-ind") );
+#endif
+    iResponse->SetMessageType( KMmsMessageTypeMNotifyRespInd );
+    iResponse->SetTidL( iNotification->Tid() );
+    // message status has been set before we are called.
+    iResponse->SetReportAllowed( iMmsSettings->DeliveryReportSendingAllowed() );
+    iEncoder->EncodeHeadersL( *iResponse, *iEncodeBuffer );
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::EncodeAcknowledgeIndicationL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::EncodeAcknowledgeIndicationL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- encoding m-acknowledge-ind") );
+#endif
+    iResponse->SetMessageType( KMmsMessageTypeAcknowledgeInd );
+    
+    // The TID has already been set to iResponse earlier, do not override it here
+    
+    // version value is set by the encoder.
+    // This response has no status. It is only sent when the status is "Retrieved"
+    iResponse->SetReportAllowed( iMmsSettings->DeliveryReportSendingAllowed() );
+    iEncoder->EncodeHeadersL( *iResponse, *iEncodeBuffer );
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::HandleMultipartAlternativeL()
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::HandleMultipartAlternativeL()
+    {
+    // This is just "best effort"
+    // If we cannot properly clear the extra attachments, they are just left "as is"
+    
+    if ( iMmsHeaders->MultipartType() != KMmsAssignedApplicationVndWapMultipartAlternative )
+        {
+        return; // nothing to do
+        }
+
+    User::LeaveIfError( iEntryWrapper->SetCurrentEntry( iEntryUnderConstruction ) );
+    CMsvStore* store = iEntryWrapper->EditStoreL();
+    CleanupStack::PushL( store );
+    
+    MMsvAttachmentManager& attachMan = store->AttachmentManagerL();
+    MMsvAttachmentManagerSync& attachManSync = store->AttachmentManagerExtensionsL();
+    
+    TInt count = attachMan.AttachmentCount();
+
+    if ( count <= 1 )
+        {
+        CleanupStack::PopAndDestroy( store );
+        return; // only one part, keep it
+        }
+
+    TInt i;
+    CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
+    CleanupStack::PushL( mimeHeaders );
+
+    for ( i = count; i > 0; i-- )
+        {
+        CMsvAttachment* attachInfo = attachMan.GetAttachmentInfoL( i - 1 );
+        CleanupStack::PushL( attachInfo );
+        TPtrC8 pointer;
+        pointer.Set( attachInfo->MimeType() );
+        HBufC8* temp = NULL;
+        if ( pointer.Length() == 0 )
+            {
+            // mime type not set. Try mime headers
+            mimeHeaders->RestoreL( *attachInfo );
+            temp = HBufC8::NewL( mimeHeaders->ContentType().Length() +
+                mimeHeaders->ContentSubType().Length() + 1 );
+            temp->Des().Copy( mimeHeaders->ContentType() );
+            temp->Des().Append( KMmsSlash8 );
+            temp->Des().Append( mimeHeaders->ContentSubType() );
+            pointer.Set( temp->Des() );
+            }
+        CleanupStack::PushL( temp );                
+        if ( pointer.CompareF( KMmsTextPlain ) != 0 )
+            {
+            attachManSync.RemoveAttachmentL( i - 1 );
+            count--;
+            }
+        CleanupStack::PopAndDestroy( temp );
+        CleanupStack::PopAndDestroy( attachInfo );
+        temp = NULL; 
+        attachInfo = NULL;
+        }
+
+    if ( count > 0 )
+        {
+        // we have something left in the selection
+        // When we commit the store, deleted attachments should disappear
+        store->CommitL();
+        }
+
+    CleanupStack::PopAndDestroy( mimeHeaders );
+    CleanupStack::PopAndDestroy( store );
+    iEntryWrapper->SetCurrentEntry( KMsvNullIndexEntryId );
+    }
+
+// ---------------------------------------------------------
+// CMmsReceiveMessage::::EncodePDUL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::EncodePDUL()
+    {
+    // This state is used to check what must be done to the notification
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsReceiveMessage EncodePDUL - Finalize of continue"));
+#endif
+
+    iError = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+    
+    if ( iError != KErrNone )
+        {
+        // The code called by SkipEntryL will make us active again
+        SkipEntryL();
+        return;
+        }
+        
+    TMsvEntry tEntry;
+    tEntry = iServerEntry->Entry();
+        
+    if ( iReceivingMode == EMmsReceivingAutomatic || iMmsSettings->FetchOverride() )
+        {
+        // if notification is in Inbox, set the fetch flags on
+        if ( tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )
+            {
+            // mark the flags to reserve the notification for fetch
+            MarkNotificationOperationReserved( tEntry, KMmsOperationFetch );
+            
+            iServerEntry->ChangeEntry( tEntry );
+            #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("mark notification that is being fetched") );
+            #endif
+            }
+        // continue fetching
+        FallThrough();
+        return;  
+        }
+
+    // mode is deferred of reject
+    
+    // entry is in inbox - clear flags and leave it
+    if ( tEntry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )
+        {
+        tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
+        tEntry.SetReadOnly( ETrue );
+        iServerEntry->ChangeEntry( tEntry );
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("notification in inbox. Let it be") );
+        #endif
+        LoopToNextEntryL();
+        return;
+        }
+    
+    // entry is in mms folder or mmbox folder
+
+    // already deferred - leave it and loop to next entry
+    if ( tEntry.iMtmData2 & KMmsNotifyResponseSent )
+        {
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("notification already deferred. Let it be") );
+        #endif
+        tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
+        iServerEntry->ChangeEntry( tEntry );
+        LoopToNextEntryL();
+        return;
+        }  
+        
+    // reject mode is on 
+    if ( iReceivingMode == EMmsReceivingReject )
+        {
+        // Let the notification be, if we have received this notification 
+        // earlier in the manual or postpone mode when we have roamed.
+        // In that case KMmsDeferredButResponseNotSent flag is set.
+        // Delete it, if it is a new one that has arrives while we are in reject mode 
+        tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
+        iServerEntry->ChangeEntry( tEntry );
+        if ( !( tEntry.iMtmData2 & KMmsDeferredButResponseNotSent ) )
+            {
+            #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("deleting the notification") );
+            #endif
+            // we ignore the error. If setting entry to parent fails, deletion will fail
+            iServerEntry->SetEntry( tEntry.Parent() );
+            iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+            }               
+        LoopToNextEntryL();
+        return;
+        }
+ 
+    // deferred and response not yet sent
+    
+    if ( iRegistrationStatus == 0 ) // home network - continue
+        {
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("in homenw and deferred mode") );
+        #endif
+        // continue fetching - will send "deferred" response
+        FallThrough();
+        return;  
+        }
+        
+    // state is deferred, and we are roaming    
+    
+    // if the status of the notification is retrieved, this
+    // notification will be deleted.
+    // This happens if the notification was extended notification 
+    // and the whole message arrived in the notification.
+    // When roaming, no response is sent. The extended notification
+    // is already in the inbox. This notification is deleted.
+
+    CMsvStore* store = iServerEntry->ReadStoreL();
+    CleanupStack::PushL( store );
+    iNotification->RestoreL( *store );
+    CleanupStack::PopAndDestroy( store );
+    store = NULL;
+    
+    if ( iNotification->Status() == KMmsMessageStatusRetrieved )
+        {
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L(" the whole extended notification received") );
+        TMmsLogger::Log( _L("deleting the notification") );
+        #endif
+        // ignore error, if setting parent fails, deletion will fail
+        iServerEntry->SetEntry( tEntry.Parent() );
+        iServerEntry->DeleteEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+        LoopToNextEntryL();
+        return;
+        }
+        
+    // The notification is not completely fetched, finalize flags    
+    
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Finalizing the notification") );
+    #endif
+    iNotification->SetStatus( KMmsMessageStatusDeferred );
+    store = iServerEntry->EditStoreL();
+    CleanupStack::PushL( store );
+    iNotification->StoreL( *store );
+    store->CommitL();
+    CleanupStack::PopAndDestroy( store );
+    store = NULL;
+
+    tEntry.SetConnected( EFalse );
+    tEntry.SetFailed( EFalse );
+    tEntry.SetSendingState( KMsvSendStateUnknown );
+
+    tEntry.iMtmData1 |= KMmsMessageMobileTerminated;
+
+    // When roaming it is not allowed to send a notify response
+    // to MMSC.
+    tEntry.iMtmData2 |= KMmsDeferredButResponseNotSent;
+
+    // The receiving mode is either manual or postpone, when roaming. 
+    // If the manual mode is on, the mtm type is changed to notification
+    // and the notification is moved to Inbox.
+    // 
+    if ( iMmsSettings->ReceivingModeForeign() != EMmsReceivingManual )
+        {
+        // this is all we need
+        iServerEntry->ChangeEntry( tEntry );
+        }
+    else
+        {
+        // Change the iMtm from KUidMsgTypeMultimedia to 
+        // KUidMsgMMSNotification   
+        tEntry.iMtm = KUidMsgMMSNotification; 
+        tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("marking as a notification") );
+        #endif                  
+        // Readonly flag has to be set on in inbox.
+        // Not in mms folder
+        tEntry.SetReadOnly( ETrue );
+        iServerEntry->ChangeEntry( tEntry );
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("moving to inbox") );
+        #endif
+        // Ignore error from set entry. If it fails, move will fail (not panic)
+        // Setting service entry to a folder should not fail.
+        iServerEntry->SetEntry( tEntry.Parent() );
+        iServerEntry->MoveEntryWithinService( tEntry.Id(), KMsvGlobalInBoxIndexEntryIdValue );
+        }
+        
+    LoopToNextEntryL();
+
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::::SkipEntryL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::SkipEntryL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("receivemsg - can't access notification") );
+#endif
+    // If the notification cannot be accessed, we must try the next one
+    // If the notification was not found, or was used by someone else,
+    // then nothing can be done. Nothing can be done to the scheduling data.
+
+    // We completely discard only entries that cannot be found
+    if ( iError == KErrNotFound )
+        {
+        iFailed->Delete( iCurrentMessageNo - 1 );
+        }
+    // we must return to the beginning of the loop without doing anything
+    iState = EMmsOperationUpdatingEntryStatus;
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    // The code called by ChangeStateL will make us active again
+    ChangeStateL();
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::::LoopToNextEntryL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::LoopToNextEntryL()
+    {
+    // release entry
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    // loop to next entry
+    iFailed->Delete( iCurrentMessageNo - 1 );
+    iState = EMmsOperationUpdatingEntryStatus;
+    SelectNextState();
+    // The code called by ChangeStateL will make us active again
+    ChangeStateL();
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::FolderEntryL
+//
+// ---------------------------------------------------------
+//
+TInt CMmsReceiveMessage::FolderEntryL(
+    TMsvId aParent, const TDesC& aFolderName, TMsvId& aFolderId )
+    {
+    aFolderId = KMsvNullIndexEntryId;
+
+    TInt error = KErrNone;
+    
+    // get a new entry, don't mess up with the original entry.
+    CMsvServerEntry* workingEntry = NULL;
+    TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent ) );
+    CleanupStack::PushL( workingEntry );
+    
+    if ( error != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( workingEntry ); // workingEntry
+        return error;
+        }
+   
+    // Show invisible entries
+    TMsvSelectionOrdering ordering =
+        TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByIdReverse, ETrue );
+    workingEntry->SetSort( ordering );
+    
+    CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
+    error = workingEntry->GetChildrenWithType( KUidMsvFolderEntry, *selection );
+    if ( error == KErrNone )
+        {           
+        // If selection contains folders, check if the folder is found.
+        TInt count = selection->Count();
+        for ( TInt i = 0; i < count && aFolderId == KMsvNullIndexEntryId; i++ )
+            {
+            error = workingEntry->SetEntry( selection->At( i ) );
+            if ( error == KErrNone )
+                {
+                // must be exact match
+                if ( workingEntry->Entry().iDetails.Compare( aFolderName ) == 0 )
+                    {
+                    aFolderId = selection->At( i );
+                    }                    
+                }                           
+            }
+        }
+    delete selection; 
+    selection = NULL;
+    CleanupStack::PopAndDestroy( workingEntry );
+    workingEntry = NULL;
+    
+    return error; 
+        
+    }
+ 
+ // -----------------------------------------------------------------------------
+// CMmsReceiveMessage::CreateFolderEntryL
+//
+// -----------------------------------------------------------------------------
+//
+TInt CMmsReceiveMessage::CreateFolderEntryL(
+    TMsvId aParentFolder, const TDesC& aFolderName, TMsvId& aFolderId )
+    {
+    
+    // Check if the folder already exists under parent folder.
+    TInt error = FolderEntryL( aParentFolder, aFolderName, aFolderId );    
+    if ( aFolderId != KMsvNullIndexEntryId || error != KErrNone )
+        {
+        // if error == KErrNone and aFolderId not equal to KMsvNullIndexEntryId
+        // the folder already exists, and we don't need to create anything
+        return error;   
+        }
+     
+    CMsvServerEntry* serverEntry = NULL;
+    TRAP( error, serverEntry = iServerEntry->NewEntryL( aParentFolder ) );
+    CleanupStack::PushL( serverEntry );
+    
+    if ( error != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( serverEntry );
+        return error;
+        }
+          
+    // Create a new folder.
+    error = serverEntry->SetEntry( aParentFolder );
+    
+    if ( error == KErrNone )
+	    {
+        TMsvEntry entry;
+	    entry.iType = KUidMsvFolderEntry;
+	    entry.iMtm = KUidMsvLocalServiceMtm;
+	    entry.iDetails.Set( aFolderName );
+	    entry.SetVisible( EFalse );
+	    entry.SetInPreparation( EFalse );
+	    entry.iServiceId = KMsvLocalServiceIndexEntryId;
+	    error = serverEntry->CreateEntry( entry );    
+	    aFolderId = entry.Id();    
+	    }
+	CleanupStack::PopAndDestroy( serverEntry );
+    serverEntry = NULL;    
+	return error;   
+       
+    }
+
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::FindDuplicateNotificationL
+// 
+// ---------------------------------------------------------
+//
+TInt CMmsReceiveMessage::FindDuplicateNotificationL(
+    TMsvId aParent, CMmsHeaders& aHeaders, TMsvId& aDuplicate )
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsReceiveMessage::FindDuplicateNotificationL") );
+#endif
+    
+    aDuplicate = KMsvNullIndexEntryId;
+ 
+    if ( aParent == KMsvNullIndexEntryId )
+        {
+        return KErrNotSupported;
+        }
+
+    // Get a new entry, dont mess up with our original entry
+    TInt error = KErrNone;
+
+    CMsvServerEntry* workingEntry = NULL;
+    TRAP( error, workingEntry = iServerEntry->NewEntryL( aParent ));
+    CleanupStack::PushL( workingEntry );
+    
+    if ( error != KErrNone )
+        {
+        CleanupStack::PopAndDestroy( workingEntry );
+        return error;
+        }
+
+    CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; 
+    CleanupStack::PushL( selection );
+
+    error = workingEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
+
+    TInt count = selection->Count();
+    if ( count == 0 )
+        {
+        error = KErrNotSupported;
+        }
+
+    if ( error != KErrNone  )
+        {
+        CleanupStack::PopAndDestroy( selection );
+        CleanupStack::PopAndDestroy( workingEntry );
+        return error;
+        }
+
+    CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    CleanupStack::PushL( mmsHeaders );
+     
+    for ( TInt i = count; i > 0 && ( aDuplicate == KMsvNullIndexEntryId ); i-- )
+        {
+        error = workingEntry->SetEntry( selection->At( i - 1 ) );
+        if ( error == KErrNone )
+            {            
+            CMsvStore* store = workingEntry->ReadStoreL();
+            CleanupStack::PushL( store );
+            mmsHeaders->RestoreL( *store );
+            CleanupStack::PopAndDestroy( store );
+
+            // content location must match 
+            if ( mmsHeaders->ContentLocation().Compare( aHeaders.ContentLocation() ) == 0 )
+                {
+                // Identical. This probably means that we have not sent a response yet,
+                // and MMSC has sent us a new notification.
+
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- content locations match") );
+#endif
+                TMsvEntry entry = workingEntry->Entry();
+                aDuplicate = entry.Id();
+                }
+            }
+        }
+
+    CleanupStack::PopAndDestroy( mmsHeaders );
+    CleanupStack::PopAndDestroy( selection );
+    CleanupStack::PopAndDestroy( workingEntry );
+
+    return error;
+    }    
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::LocalModeFetchL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::LocalModeFetchL()
+    {
+    
+    HBufC* buffer = HBufC::NewL( KMaxFileName );
+    CleanupStack::PushL( buffer );
+    if ( iNotification->ContentLocation().Length() <= KMaxPath && 
+        iMmsSettings->LocalMode() )
+        {
+        buffer->Des().Copy( iNotification->ContentLocation() );
+        }
+    TPtr temp = buffer->Des();
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("...Fetching from : %S"), &temp );
+    #endif
+
+    HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
+    CleanupStack::PushL( filename );
+    TPtr fileNamePtr = filename->Des();
+    fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
+            
+    if ( iNotification->ContentLocation().Length() <= KMaxPath &&
+        buffer->Des().FindF( fileNamePtr ) == 0 )
+        {
+        // The file reading code is for local mode (simulated MMSC)
+        // Only one can try to get the file at a time
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("opening file") );
+        #endif
+        iError = iFile.Open( iFs, temp, EFileShareExclusive );
+
+        if ( iError == KErrNone )
+            {
+            #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("file opened") );
+            #endif
+            iFileOpen = ETrue;
+            TInt size = 0;
+            iError = iFile.Size( size );
+            
+            // Here we try to use chunked buffer.
+            // Read the message in chunks and keep calling decode
+            // Before we can do that, we must create the message entry
+            // Because it must be ready to receive data
+            // If receiving fails, the entry must be removed
+            
+            DoCreateEntryL();
+            iDecoder->InitializeChunkedMode( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer );
+            TInt chunkSize = KMmsChunkedBufferSize;
+            if ( iError == KErrNone )
+                {
+                TRAP( iError, iEncodeBuffer->ResizeL( chunkSize ) );
+                }
+            if ( iError != KErrNone )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("Receivemsg can't resize buffer, error %d"), iError );
+                TMmsLogger::Log( _L("- message size %d"), chunkSize );
+#endif
+                iFile.Close();
+                iFileOpen = EFalse;
+                iDecoder->RelaseDataSink();
+                CleanupStack::PopAndDestroy( filename );
+                CleanupStack::PopAndDestroy( buffer );
+                return;
+                }
+                
+            // We now have an open file.
+            // We read it in chunks and feed it to decoder piecewise
+            TPtr8 pos = iEncodeBuffer->Ptr( 0 );
+            
+            TInt position = 0;
+            TInt readData = 0;
+            TInt amount = 0;
+            TBool lastChunk = EFalse;
+            TInt error = KErrNone;
+            
+            while ( readData < size && error == KErrNone )
+                {
+                chunkSize = KMmsChunkedBufferSize;
+                const TInt KMmsTwo = 2;
+                if ( chunkSize - amount < KMmsChunkedBufferSize / KMmsTwo )
+                    {
+                    // if almost all data has been left to buffer, increase buffer size
+                    chunkSize = amount + KMmsChunkedBufferSize / KMmsTwo;
+                    }
+                iEncodeBuffer->ResizeL( chunkSize );
+                pos.Set( iEncodeBuffer->Ptr( amount ) );
+                pos.SetLength( chunkSize - amount );
+                error = iFile.Read( pos, chunkSize - amount );
+                amount += pos.Length();
+                readData += pos.Length();
+                if ( readData >= size )
+                    {
+                    lastChunk = ETrue;
+                    }
+                if ( error == KErrNone )
+                    {
+                    // this is how much data we have
+                    iEncodeBuffer->ResizeL( amount ); 
+                    error = iDecoder->NextDataPart( *iEncodeBuffer, position, lastChunk );
+                    }
+                if ( position > iEncodeBuffer->Size() )
+                    {
+                    position = iEncodeBuffer->Size();
+                    }
+                // Check if we can continue and shift the buffer if needed
+                if ( error == KErrNone )
+                    {
+                    // now position points to the beginning of unhandled data
+                    // it must be shifted to the beginning
+                    amount -= position; // this much left unhandled
+                    if ( amount < 0 )
+                        {
+                        amount = 0;
+                        }
+                    iEncodeBuffer->Delete( 0, position );
+                    // start from the beginning the next time
+                    position = 0;
+                    }
+                }
+            if ( error != KErrNone )
+                {
+                iError = error;
+                }
+            // when the loop ends, all data should be handled and all attachments should be created
+            // Decode has also saved message headers.
+            // The changed state indicates what is complete
+            iDecoder->RelaseDataSink();
+            iState = EMmsOperationDecodingResponse; 
+            }
+        else
+            {
+            // This corresponds to the situation, where the message
+            // has expired or for some other reason is no longer available.
+            // We lie to RunL that we have already decoded the message
+            iFile.Close();
+            iFileOpen = EFalse;
+            iState = EMmsOperationDecodingResponse;
+            if ( iError != KErrInUse )
+                {
+                iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+                }
+            }
+        // We don't close the file yet.
+        // We want to keep it exclusively to ourselves until we are done with it
+        }
+    else
+        {
+        // No directory found in notification
+        // this notification cannot be handled.
+        // It will be marked bad and deleted.
+        iError = KErrNotFound;
+        iState = EMmsOperationDecodingResponse;
+        iBad->AppendL( iSelection->At( iCurrentMessageNo - 1 ) );
+        }
+    CleanupStack::PopAndDestroy( filename );
+    CleanupStack::PopAndDestroy( buffer );
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::DumpIfNeededL
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::DumpIfNeededL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TInt error = KErrNone;
+    TBool dumpIncoming = EFalse;
+    //
+    // Reading binary dumping from CenRep
+    //
+    CRepository* repository = NULL;
+    TInt retval = KErrNone;
+    TRAP( retval, repository = CRepository::NewL( KUidMmsServerMtm ) ); // ***
+    if( retval == KErrNone )
+        {
+        CleanupStack::PushL( repository );
+        TInt temp = 0;
+        retval = repository->Get( KMmsEngineBinaryDump, temp );
+        if( retval == KErrNone )
+            {
+            dumpIncoming = (TBool)temp;
+            }
+        CleanupStack::PopAndDestroy( repository );
+        }    
+
+    TMmsLogger::Log( _L("Receivemsg Dumping Entry") );
+    // If the result was bad, we dump the binary data into file
+    // - unless decode already did it.
+    if ( ( ( !dumpIncoming ) && iError != KErrNone ) &&
+        iEncodeBuffer &&
+        iEncodeBuffer->Size() > 0 )
+        {
+        TParse parse;
+        TFileName fileName;
+        fileName.Copy( KMmsDefaultLogDirectory );
+        TUint att;
+        if ( iFs.Att( fileName, att ) == KErrNone )
+            {
+            _LIT( KRelated, "Rec.mms");
+            parse.Set( fileName, &KRelated, NULL );
+            fileName = parse.FullName();
+            error = CApaApplication::GenerateFileName( iFs, fileName );
+            if ( error == KErrNone )
+                {
+                RFile file;
+                error = file.Create( iFs, fileName, EFileWrite | EFileShareExclusive );
+                // for message id generation
+                parse.Set( fileName, NULL, NULL );
+
+                if ( error == KErrNone )
+                    {
+                    // the data is supposed to be in the encode buffer
+                    TPtr8 ptr = iEncodeBuffer->Ptr( 0 );
+                    file.Write( ptr );
+                    file.Flush();
+                    }
+
+                // done - close files
+                file.Close();
+                }
+            }
+        }
+#endif
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::CloseLocalFile
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::CloseLocalFileL( TBool aDeleteFile )
+    {
+    HBufC* buffer = HBufC::NewL( KMaxFileName );
+    CleanupStack::PushL( buffer );
+    buffer->Des().Copy( iNotification->ContentLocation() );
+    HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
+    CleanupStack::PushL( filename );
+    TPtr fileNamePtr = filename->Des();
+    fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
+    if ( buffer->Des().FindF( fileNamePtr ) == 0 )
+        {
+        // this was our local message file
+        iFile.Close();
+        iFileOpen = EFalse;
+        if ( aDeleteFile )
+            {
+            iFs.Delete( *buffer );
+            }
+        }
+    CleanupStack::PopAndDestroy( filename );
+    CleanupStack::PopAndDestroy( buffer );
+    }
+    
+// ---------------------------------------------------------
+// CMmsReceiveMessage::MoveToApplicationFolderIfNeededL
+//
+// ---------------------------------------------------------
+//
+TInt CMmsReceiveMessage::MoveToApplicationFolderIfNeededL( TMsvEntry& aEntry )
+    {
+    TInt error = KErrNone;
+    TInt returnCode = 0;
+    
+    if ( iMmsHeaders->ApplicId().Length() > 0 )
+        {
+        // check if application id is registered
+        if ( iRegistered )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- message to registered application") );
+#endif
+            TMsvId targetFolder = KMsvNullIndexEntryId;
+            // target folder's parent is application folder
+            TMsvId applicationFolder = iMmsSettings->ApplicationFolder();
+            // code scanner gives false positive from the next line
+            error = CreateFolderEntryL( applicationFolder, iMmsHeaders->ApplicId(), targetFolder );
+            if ( targetFolder != KMsvNullIndexEntryId && error == KErrNone )
+                {
+                error = iServerEntry->SetEntry( aEntry.Parent() );
+                if ( error == KErrNone )
+	                {
+	                error = iServerEntry->MoveEntryWithinService( aEntry.Id(), targetFolder );     	
+	                }
+	            if ( error == KErrNone )
+	                {
+	                // Message was successfully moved to application folder
+	                // If we want to keep the notification in inbox we return 
+                    // KMmsMessageMovedToApplicationFolder.
+                    // As long as we serve only Java applications, the notifications
+                    // will disappear from inbox if the message was moved to application folder.
+                    // Java will start the applet if it is not running, and that should
+                    // be sufficient information for the user.
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- moved to application folder") );
+#endif
+	                returnCode = 0;
+	                }
+	            // If we cannot set our entry back to the one we are handling,
+	            // we are in deep trouble    
+	            User::LeaveIfError( iServerEntry->SetEntry( iEntryUnderConstruction ));
+                }                      
+            }
+        else
+            {
+            // There was an application id, but the application was not registered
+            // Message will be deleted
+            // If deletion fails, the message remains invisible and under construction
+            // and will be deleted by message server at next boot.
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- message to unregistered application - deleted") );
+#endif
+            error = iServerEntry->SetEntry( aEntry.Parent() );
+            if ( error == KErrNone )
+                {
+                iServerEntry->DeleteEntry( aEntry.Id() );
+                }
+            returnCode = KMmsMessageForUnregisteredApplication;
+            }
+        }
+    // If no application id, the message is normal    
+    return returnCode;
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::ClearDuplicateEntryOperationL()
+    {
+    CMsvStore* store = iServerEntry->ReadStoreL();
+    CleanupStack::PushL( store );
+    iMmsHeaders->RestoreL( *store );
+    CleanupStack::PopAndDestroy( store );
+    TMsvId duplicate = KMsvNullIndexEntryId;
+    TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
+    TMsvEntry dupEntry;
+
+    if ( iNotificationParent == KMsvGlobalInBoxIndexEntryIdValue )
+        {
+        // if duplicate is found from mmbox folder, 
+        // mark it as "deleted from mmbox server"
+        if ( mmboxFolder != KMsvNullIndexEntryId )
+            {
+            FindDuplicateNotificationL( mmboxFolder, *iMmsHeaders, duplicate );
+            }
+        if ( duplicate != KMsvNullIndexEntryId )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- duplicate found ") );
+#endif
+            if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
+                {
+                // Mark duplicate as deleted from mmbox server.
+                // If it was successfully fetched it is no longer in MMBox.
+                // This is not exactly correct for full MMBox support but as long as
+                // we don't have full MMBox support this works correctly
+                dupEntry = iServerEntry->Entry();
+                MarkNotificationDeletedFromMmbox( dupEntry );
+                iServerEntry->ChangeEntry( dupEntry );
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- duplicate marked as deleted from mmbox ") );
+#endif
+                }                                         
+            }    
+        }
+    else if ( iNotificationParent == mmboxFolder )
+        {
+        duplicate = iMmsHeaders->RelatedEntry();                                
+        if ( duplicate != KMsvNullIndexEntryId )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- duplicate found ") );
+#endif
+            if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
+                {
+                // Mark it deleted just in case the actual deletion fails.
+                // This is not exactly correct for full MMBox support but as long as
+                // we don't have full MMBox support this works correctly
+                dupEntry = iServerEntry->Entry();
+                MarkNotificationDeletedFromMmbox( dupEntry );
+                iServerEntry->ChangeEntry( dupEntry );
+                // delete the duplicate notification from inbox 
+                if ( iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryIdValue )
+                    == KErrNone )
+                    {
+                    TInt err = iServerEntry->DeleteEntry( duplicate );
+#ifndef _NO_MMSS_LOGGING_
+                    if ( err == KErrNone )
+                        {
+                        TMmsLogger::Log( _L("- duplicate deleted from inbox ") );
+                        }
+#endif
+                    }
+                }
+            }
+        }
+    else
+        {
+        // nothing to do - just keep compiler and code analyzer tools happy
+        }
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::ClearOperationL( TInt aApplicationMessageStatus )
+    {
+    if ( iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) ) == KErrNone )
+        {
+        if ( aApplicationMessageStatus != 0 )
+            {
+            // The entry is not deleted if it is in inbox or MMBox
+            // and has been routed to application.
+            // We save the error code or routing status to the entry.
+            TMsvEntry tEntry = iServerEntry->Entry();
+            MarkNotificationDeletedFromMmbox( tEntry );
+            tEntry.SetConnected( EFalse );
+            tEntry.SetReadOnly( ETrue );
+
+            if ( aApplicationMessageStatus == KMmsMessageMovedToApplicationFolder )
+                {
+                // This is a successful case
+                tEntry.iMtmData2 |= KMmsMessageRoutedToApplication;
+                }
+            if ( aApplicationMessageStatus ==
+                KMmsMessageForUnregisteredApplication )
+                {
+                // This will be marked as failed operation
+                // even if the message was actually successfully fetched
+                // but it was discarded because it does not belong to anybody
+                tEntry.iError = KMmsErrorUnregisteredApplication;
+                // The earlier operation cleared the possible MMBox bit
+                // This operation marks the result as failed.
+                MarkNotificationOperationFailed( tEntry );
+                }
+                
+            // error status not checked here - we just do our best    
+            iServerEntry->ChangeEntry( tEntry );    
+            }
+        ClearDuplicateEntryOperationL();
+        }
+    }
+
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::CopyDataFromNotificationToMessageL()
+    {
+    // Only subject and sender take up space when headers are added
+    TInt size = iNotification->Sender().Length() +
+                iNotification->Subject().Length();
+    if ( size > 0 &&
+        TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &iFs, size, iMessageDrive ) )
+        {
+        size = 0;
+        }
+     
+    // We copy data from notification to message if the values are missing
+    // But if the message is already complete (status == OK)
+    // we do not copy anything.
+    if ( iMmsHeaders->ResponseStatus() > KMmsResponseStatusOK )
+        {
+        // The critical disk space is checked only when adding the subject.
+        // The sender number is important and only takes a small amount of space
+        // The other fields take the same amount of space regardless of the value.
+        // As the headers have been saved already, only subject may consume
+        // significantly more disk space.
+        if ( size > 0 )
+            {
+            if ( iMmsHeaders->Subject().Length() == 0 )
+                {
+                iMmsHeaders->SetSubjectL( iNotification->Subject() );
+                }
+            }
+        if ( iMmsHeaders->Sender().Length() == 0 )
+            {
+            iMmsHeaders->SetSenderL( iNotification->Sender() );
+            }
+        if ( iMmsHeaders->MessageClass() == 0 )
+            {
+            iMmsHeaders->SetMessageClass( iNotification->MessageClass() );
+            }
+        if ( iMmsHeaders->MessagePriority() == 0 )
+            {
+            iMmsHeaders->SetMessagePriority( iNotification->MessagePriority() );
+            }
+        // Copy the expiry, too
+        if ( iMmsHeaders->ExpiryDate() == 0 && iMmsHeaders->ExpiryInterval() == 0 )
+            {
+            // No expiration data in the message - use what is in the notification
+            iMmsHeaders->SetExpiryDate( iNotification->ExpiryDate() );
+            }
+        }
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::CopyDataFromMessageToNotificationL()
+    {
+    TBool saveNotification = EFalse;
+    TInt error = KErrNone;
+    
+    iNotification->SetResponseTextL( iMmsHeaders->ResponseText() );
+    iNotification->SetResponseStatus( iMmsHeaders->ResponseStatus() );
+
+    // Notifications do not originally contain any response texts.
+    // If the length is not 0, we have added something
+    if ( iNotification->ResponseText().Length() > 0 || iNotification->ResponseStatus() != 0 )
+        {
+        saveNotification = ETrue;
+        }
+        
+    if ( iNotification->ApplicId().Length() == 0 )
+        {
+        iNotification->SetApplicIdL( iMmsHeaders->ApplicId() );
+        if ( iNotification->ApplicId().Length() > 0 )
+            {
+            // If we copied the application id, we must save it.
+            saveNotification = ETrue;
+            }
+        }
+       
+    // update the notification
+    if ( saveNotification )
+        {
+        //  We update the notification if we added something
+        error = iServerEntry->SetEntry( iSelection->At( iCurrentMessageNo - 1 ) );
+        if ( error == KErrNone )
+            {
+            TRAP( error,
+                {
+                CMsvStore* store = iServerEntry->EditStoreL();
+                CleanupStack::PushL( store );
+                iNotification->StoreL( *store );
+                store->CommitL();
+                CleanupStack::PopAndDestroy( store );
+                })
+            }
+        // If we cannot update the entry, the user does not see the error text, but that's not fatal
+        }
+    // Release the entry
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    
+    }
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+TBool CMmsReceiveMessage::MapErrorStatus( const TInt32 aErrorStatus )
+    {
+    TBool fatal = EFalse;
+    
+    switch ( aErrorStatus )
+        {
+        case 0: // if the header is not present, it is 0
+        case KMmsStatusOk:
+            // No error, don't change iError
+            break;
+        case KMmsErrorPermanentFailure:
+            fatal = ETrue;
+            iError = KMmsErrorStatusPermanentFailure;
+            break;
+        case KMmsErrorTransientFailure:
+            iError = KMmsErrorStatusTransientFailure;
+            break;
+        case KMmsErrorReceivePermanentMessageNotFound:
+            fatal = ETrue;
+            iError = KMmsErrorStatusMessageNotFound;
+            break;
+        case KMmsErrorReceiveTransientMessageNotFound:
+            iError = KMmsErrorStatusTransientMessageNotFound;
+            break;
+        case KMmsErrorReceiveTransientNetworkProblem:
+            iError = KMmsErrorStatusNetworkProblem;
+            break;
+        case KMmsErrorPermanentServiceDenied:
+            fatal = ETrue;
+            iError = KMmsErrorStatusServiceDenied;
+            break;
+        case KMmsErrorReceivePermanentContentUnsupported:
+            fatal = ETrue;
+            iError = KMmsErrorStatusContentUnsupported;
+            break;
+        default:
+            // Unknown error, if not transient, it is fatal
+            if ( ( aErrorStatus & KMmsErrorRangeMask ) == KMmsErrorTransient )
+                {
+                iError = KMmsErrorStatusTransientFailure;
+                }
+            else
+                {
+                iError = KMmsErrorPermanentFailure;
+                fatal = ETrue;
+                }
+            break;
+        }
+            
+    return fatal;
+    }
+
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::SetIndexEntryBitsForReceivedMessage( TMsvEntry& aEntry )
+    {
+    aEntry.iMtmData1 &= ~KMmsMessageTypeMask;
+    // We override message type for now.
+    // We get send requests instead of retrieve confirmations if in local mode
+    aEntry.iMtmData1 |= KMmsMessageMRetrieveConf | KMmsMessageMobileTerminated;
+
+    aEntry.SetVisible( ETrue );
+    aEntry.SetComplete( ETrue );
+    aEntry.SetInPreparation( EFalse );
+    aEntry.SetReadOnly( ETrue );
+    aEntry.iDate.UniversalTime(); // this is arrival time
+    
+    if ( iMmsSettings->ShowSentTime() )
+        {
+        // show the time the message was received by MMSC instead of 
+        // the time the message was received by the terminal
+        if ( iMmsHeaders->Date() > 0 )
+            {
+            // date is given as seconds from 1.1.1970, UTC time
+            TTime time = TTime( KMmsYear1970String ) +
+                TTimeIntervalMicroSeconds( iMmsHeaders->Date() * KMmsMillion );
+            aEntry.iDate = time.Int64();
+            }
+        }
+    // subject, sender and size are set in CMmsDecode
+    // - except if we get an empty error message.
+    // In that case the fields were copied from the notification,
+    // and we set sender and subject here.
+    if ( aEntry.iDetails.Length() == 0 )
+        {
+        aEntry.iDetails.Set( iMmsHeaders->Sender() );
+        }
+    if ( aEntry.iDescription.Length() == 0 )  
+        {
+        aEntry.iDescription.Set( iMmsHeaders->Subject() );
+        }
+
+    // Set multiple recipients
+    if ( iMmsHeaders->ToRecipients().MdcaCount() +
+        iMmsHeaders->CcRecipients().MdcaCount() +
+        iMmsHeaders->BccRecipients().MdcaCount() > 1 )
+        {
+        aEntry.SetMultipleRecipients( ETrue );
+        }
+    }
+    
+    
+// ---------------------------------------------------------
+//
+// ---------------------------------------------------------
+//
+void CMmsReceiveMessage::DeleteApplicationMessagesL()
+    {
+    // target folder's parent is application folder
+    TMsvId messageFolder = KMsvNullIndexEntryId;
+    TMsvId applicationFolder = iMmsSettings->ApplicationFolder();
+    // code scanner gives false positive from the next line
+    TInt error = KErrNone;
+    error = FolderEntryL( applicationFolder, iMmsHeaders->ApplicId(), messageFolder );
+   
+    if ( messageFolder == KMsvNullIndexEntryId || error != KErrNone )
+        {
+        // We could not find the folder - we cannot free space
+        return;
+        }
+        
+    // List all messages in the folder and try to see if we can free enough room.
+    TInt size = iNotification->MessageSize();
+    if ( size > iMmsSettings->MaximumReceiveSize() )
+        {
+        // We cannot fetch more than this anyway
+        size = iMmsSettings->MaximumReceiveSize();
+        }
+    // The safety margin must be added to the indicated size as the size in the
+    // notification only specifies the payload, not all headers and space taken
+    // by message entry and folder entry needed.
+    size += KMmsDiskSafetyMargin;
+    
+    error = iServerEntry->SetEntry( messageFolder );
+    if ( error != KErrNone )
+        {
+        // no can do
+        return;
+        }
+    
+    // sort entries by date
+    TMsvSelectionOrdering ordering =
+        TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByDate, EFalse );
+    iServerEntry->SetSort( ordering );
+    
+    CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
+    CleanupStack::PushL( selection );
+    error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *selection );
+    if ( error != KErrNone )
+        {
+        // no can do
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        CleanupStack::PopAndDestroy( selection );
+        }
+   
+    TInt i;
+    TInt deleteCount = 0; // entries to be deleted to free space
+    TInt oldSize = 0;
+    for ( i = 0; i < selection->Count() && deleteCount == 0; i++ )
+        {
+        error = iServerEntry->SetEntry( selection->At( i ) );
+        if ( error == KErrNone )
+            {
+            // If we could not access some entry, it will end up in the 
+            // delete list anyway. It may or may not be deleted.
+            oldSize += iServerEntry->Entry().iSize;
+            }
+        if ( oldSize >= size )
+            {
+            deleteCount = i + 1;
+            }
+        }
+        
+    // Check if we fond enough old messages to free space.
+    if ( deleteCount > 0 )
+        {
+        for ( i = selection->Count(); i > deleteCount; i-- )
+            {
+            // We may be able to leave some entries
+            selection->Delete( i - 1 );
+            }
+        
+        error = iServerEntry->SetEntry( messageFolder );
+        if ( error == KErrNone )
+            {
+            error = iServerEntry->DeleteEntries( *selection );
+            }
+        // If we get an error because some entry is locked or open
+        // the original KErrNoDisk remains and no entries are deleted
+        // The situation will follow normal low disk space handling
+        // If the entries are being accessed by the application, the
+        // space may be freed soon by the application.
+        if ( error == KErrNone )
+            {
+            // We have successfully deleted enough entries
+            // The new message should now fit.
+            // It can be rescheduled or fetch can be manually restarted
+            iError = KMmsErrorApplicationDiskFull;
+            }
+        }
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    CleanupStack::PopAndDestroy( selection );    
+    }
+    
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+//  End of File  
+