mmsengine/mmsserver/src/mmsserver.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 72 6f657153cbc5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmsengine/mmsserver/src/mmsserver.cpp	Fri Jun 04 10:25:39 2010 +0100
@@ -0,0 +1,5557 @@
+/*
+* 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:  
+*     Server Mtm
+*
+*/
+
+
+
+// INCLUDE FILES
+#include    <apparc.h>
+#include    <msventry.h>
+#include    <msvschedulepackage.h>
+#include    <msvschedulesettings.h>
+#include    <msvsenderroraction.h>
+#include    <bautils.h>
+#include    <e32math.h> // for notification generation
+#include    <logcli.h>
+#include    <logview.h>
+#include    <flogger.h>
+#include    <e32svr.h>
+#include    <centralrepository.h>
+#include    <utf.h>
+#include    <cmsvmimeheaders.h>
+#include    "LogsApiConsts.h"
+#include    <logengdurations.h>
+
+// MMS specific
+#include    "mmsconst.h"
+#include    "mmserrors.h"
+#include    "mmsmmboxmessageheaders.h"
+#include    "mmsservercommon.h"
+#include    "mmscmds.h"
+#include    "mmssettings.h"
+#include    "mmsaccount.h"
+#include    "mmsserver.h"
+#include    "mmssendoperation.h"
+#include    "mmsreceivemessage.h"
+#include    "mmsforwardoperation.h"
+#include    "mmsdeleteoperation.h"
+#include    "mmsmmboxlist.h"
+#include    "mmsdecode.h"
+#include    "mmsencode.h"
+#include    "mmsheaders.h"
+#include    "mmsschedulesend.h"
+#include    "mmsscheduledentry.h"
+#include    "mmslog.h"
+#include    "mmsgenutils.h"
+#include    "mmsserverentry.h"
+#include    "MmsEnginePrivateCRKeys.h"
+#include    "mmsreadreport.h"
+
+// LOCAL CONSTANTS AND MACROS
+const TInt KMmsGarbageCollectionDelay = 30; // 30s delay
+const TInt KMmsSanityInterval = 96;  // 96 hours, 4 days
+const TInt KMmsScheduleAllowance = 10;
+const TInt KMmsScheduleDelay = 5;
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ---------------------------------------------------------
+//
+CMmsServerMtm::CMmsServerMtm(
+    CRegisteredMtmDll& aRegisteredMtmDll,
+    CMsvServerEntry* aInitialEntry )
+    : CScheduleBaseServerMtm( aRegisteredMtmDll, aInitialEntry ),
+    iNotification ( KMsvNullIndexEntryId ),
+    iOOMState ( EFalse ),
+    iDeliveryStatus (EFalse)
+    {
+    // Everything not mentioned gets initialized to NULL
+    // Save our initial entry id
+    // It is either default service or service specified in Entry Selection
+    iServiceEntryId = aInitialEntry->Entry().Id();
+    // We use the file session offered by initial entry.
+    // Documentation says that it is expensive to open new file sessions
+    // We offer the same session to all classes we create so that everybody
+    // is using the same session.
+    // In the final version file session is needed for attachment access
+    // only, in the preliminary version we have a fake MMSC set up in a
+    // directory on disk, and we need the file session to access that.
+    iFs = aInitialEntry->FileSession();
+    CActiveScheduler::Add( this );
+    }
+
+// ---------------------------------------------------------
+// Symbian OS default constructor can leave.
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::ConstructL()
+    {
+
+    CScheduleBaseServerMtm::ConstructL();
+    iScheduleSend = CMmsScheduleSend::NewL( *iServerEntry );
+    iMsvSelection = new( ELeave ) CMsvEntrySelection;
+    iMmsSettings = CMmsSettings::NewL();
+    // don't load settings yet in case someone else is trying
+    // to change the settings.
+    iMmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    iMessageDrive = EDriveC;
+    // see if message server knows better
+    iMessageDrive = MessageServer::CurrentDriveL( iFs );
+    }
+
+// ---------------------------------------------------------
+// Factory function
+// 
+// ---------------------------------------------------------
+//
+EXPORT_C CMmsServerMtm* CMmsServerMtm::NewL(
+    CRegisteredMtmDll& aRegisteredMtmDll,
+    CMsvServerEntry* aInitialEntry )
+    {
+    
+    CleanupStack::PushL( aInitialEntry ); // Take ownership of aInitialEntry
+    CMmsServerMtm* self = new( ELeave ) CMmsServerMtm(
+        aRegisteredMtmDll, aInitialEntry );
+    CleanupStack::Pop( aInitialEntry ); // Entry now safely stored in member
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+    
+// ---------------------------------------------------------
+// Destructor
+// 
+// ---------------------------------------------------------
+//
+CMmsServerMtm::~CMmsServerMtm()
+    {
+    // We don't close the file session anymore, as we
+    // obtained if from the initial entry, and it is not ours to close...
+    Cancel(); // cancel anything that may be pending...
+    if ( iRemoteParties )
+        {
+        iRemoteParties->Reset();
+        }
+    delete iEntryWrapper;
+    delete iRemoteParties;
+    delete iReadReport;
+    delete iSendOperation;
+    delete iReceiveMessage;
+    delete iForwardOperation;
+    delete iDeleteOperation;
+    delete iUpdateMmboxList;
+    delete iMsvSelection;
+    delete iMmsSettings;
+    delete iScheduleSend;
+    delete iDecoder;
+    delete iMmsHeaders;
+    delete iEncodeBuffer;
+    delete iMmsLog;
+    delete iLogEvent;
+    delete iLogViewEvent;
+    delete iLogClient;
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MMSServer destructor, done") );
+#endif
+    }
+
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CopyToLocalL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CopyToLocalL(
+    const CMsvEntrySelection& /*aSelection*/,
+    TMsvId /*aDestination*/,
+    TRequestStatus& aStatus )
+    {
+    
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNotSupported );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CopyFromLocalL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CopyFromLocalL(
+    const CMsvEntrySelection& aSelection,
+    TMsvId /*aDestination*/,
+    TRequestStatus& aStatus )
+    {
+
+    // test code: copy from local means send.
+    // sent folder is handled separately
+    TCommandParameters parameters;
+    parameters.iInitialDelay = 0;
+    TCommandParametersBuf paramPack( parameters );
+
+    CMsvEntrySelection* selection = new (ELeave) CMsvEntrySelection;
+    CleanupStack::PushL(selection);
+    if ( aSelection.Count() > 0 )
+        {
+        selection->AppendL( aSelection.Back( 0 ), aSelection.Count() );
+        }
+    StartCommandL( *selection, EMmsScheduledSend, paramPack, aStatus );
+    CleanupStack::PopAndDestroy( selection );
+  
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CopyWithinServiceL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CopyWithinServiceL(
+    const CMsvEntrySelection& /*aSelection*/,
+    TMsvId /*aDestination*/,
+    TRequestStatus& aStatus )
+    {
+
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNotSupported );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::MoveToLocalL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::MoveToLocalL(
+    const CMsvEntrySelection& /*aSelection*/,
+    TMsvId /*aDestination*/,
+    TRequestStatus& aStatus )
+    {
+
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNotSupported );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::MoveFromLocalL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::MoveFromLocalL(
+    const CMsvEntrySelection& /*aSelection*/,
+    TMsvId /*aDestination*/,
+    TRequestStatus& aStatus )
+    {
+
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNotSupported );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::MoveWithinServiceL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::MoveWithinServiceL(
+    const CMsvEntrySelection& /*aSelection*/,
+    TMsvId /*aDestination*/,
+    TRequestStatus& aStatus )
+    {
+
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNotSupported );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::DeleteAllL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::DeleteAllL(
+    const CMsvEntrySelection& aSelection,
+    TRequestStatus& aStatus )
+    {
+
+    // this is implemented for scheduled send
+    // It needs to change entry asynchronously,
+    // and needs help on server mtm
+    TInt error;
+    // we are always called with a selection that has at least one member.
+    // we cannot be called with an empty selection (because then the server
+    // does not know whom to call)
+    if ( aSelection.Count() == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }
+    User::LeaveIfError( iServerEntry->SetEntry( aSelection[0] ) );
+    User::LeaveIfError( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) );
+    CMsvEntrySelection* sel = aSelection.CopyL();
+    error = iServerEntry->DeleteEntries( *sel );
+    if ( error == KErrNotFound )
+        {
+        error = KErrNone; // if not found, deleted already.
+        }
+    delete sel;
+
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, error );
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CreateL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CreateL(
+    TMsvEntry /*aNewEntry*/,
+    TRequestStatus& aStatus )
+    {
+
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNotSupported );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::ChangeL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::ChangeL(
+    TMsvEntry aNewEntry,
+    TRequestStatus& aStatus )
+    {
+
+    // this is implemented for scheduled send
+    // It needs to change entry asynchronously,
+    // and needs help on server mtm
+    User::LeaveIfError( iServerEntry->SetEntry( aNewEntry.Id() ));
+    User::LeaveIfError( iServerEntry->ChangeEntry( aNewEntry ) );
+    TRequestStatus* status = &aStatus;
+    aStatus = KRequestPending;
+    User::RequestComplete( status, KErrNone );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::StartCommandL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::StartCommandL(
+    CMsvEntrySelection& aSelection,
+    TInt aCommand,
+    const TDesC8& aParameter,
+    TRequestStatus& aStatus )
+    {
+    
+    TInt error = KErrNone;
+    TMsvEntry entry; // This will be used a lot later to access the index data
+    
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MMSServer Start Command %d"), aCommand );
+#endif // _NO_MMSS_LOGGING_
+    // log the code for debugging
+    LogCommandCode( aCommand );
+    
+    // The content of the parameter depends on command.
+    // For EMmsDecodePushedMessage it will be TWatcherParametersBuf structure,
+    // but the content is currently ignored because it has become impossible
+    // to copy the data between processes in the protected environment.
+    // For EMmsScheduledSend, EMmsScheduledReceive, and EMmsScheduledReceiveForced
+    // it will be TCommandParametersBuf.
+    // For EMmsGarbageCollection it will be TMMSGarbageCollectionParametersBuf
+    // containing the reason for the garbage collection.
+    // For others the parameter will be ignored.
+    // The parameter should be unpackaged only when the contents are known.
+
+    // The default service entry is always used.
+
+    // Because of the restriction that only one mtm
+    // per service can be open at any time, the scheduling calls
+    // cheat and offer the stuff here using local service instead
+    // of mms service. As we would like to load our settings
+    // anyway, we try to find out the real service.
+
+    if ( iServiceEntryId == KMsvLocalServiceIndexEntryId )
+        {
+        // we have been cheated
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- local service id") );
+#endif
+        // Get the actual service id from a message entry
+        GetRealServiceId( aSelection );
+        }
+        
+    // free whatever entry we are holding
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    //
+    // Load the service settings.
+    // In case call fails, loading will be retried
+    //
+    TInt loadServiceError = KErrNone;
+    TRAP( loadServiceError, LoadSettingsL( aCommand ) );
+
+#ifndef _NO_MMSS_LOGGING_
+    if ( loadServiceError != KErrNone ) 
+        {
+        TMmsLogger::Log( _L("-ERROR loading settings: %d"), loadServiceError );
+        }
+    else
+        {
+        TMmsLogger::Log( _L("- settings loaded successfully") );        
+        }
+#endif
+
+    iCurrentCommand = aCommand;
+    if ( aCommand != EMmsRetryServiceLoading )
+        {
+        iCommand = aCommand;
+        iParameter = aParameter;
+        iRequestStatus = &aStatus;
+
+        // We remove the service entry from the selection, as we don't need it anymore
+        iMsvSelection->Reset();
+        if ( aSelection.Count() > 0 )
+            {
+            iMsvSelection->AppendL( aSelection.Back( 0 ), aSelection.Count() );
+            }
+        }
+    else
+        {
+        // iRequestStatus was set on an earlier round.
+        // EMmsRetryServiceLoading is never the first command
+        iCurrentCommand = iCommand; // orginal command was stored here
+        }
+
+    // If service loading has failed, we loop through RunL to retry.
+    // Actually only EMmsScheduledReceive and EMmsScheduledReceiveForced
+    // need this service.
+    // Other callers can handle error situations gracefully.
+    // We have saved all our parameters.
+    // All we have to do now is to change iCurrent command and complete ourselves
+    // In order to get to our RunL.
+    // RunL will route us to DoRunL where we can continue
+
+    if ( loadServiceError != KErrNone )
+        {
+        // Actually we should no longer get load service error as the settings
+        // are now in central repository, no longer saved into the service entry
+        HandleLoadServiceError( loadServiceError );
+        // we cannot continue. HandleLoadServiceError has set completion status
+        // as required.
+        return;
+        }
+
+    // If we have loaded the service, we can discard the service entry
+    // if it still is in our selection
+    if ( iMsvSelection->Count() > 0 && iMsvSelection->At( 0 ) == iServiceEntryId )
+        {
+        iMsvSelection->Delete( 0 ); 
+        }
+
+#ifndef _NO_MMSS_LOGGING_
+    // log the parent folder of the selection (needed for debugging)
+    LogEntryParent();
+#endif
+
+    // we do not move the entries anywhere.
+    // it is the client's responsibility to move them to the right place
+    // we just make them visible because some applications left invisible
+    // entries to outbox.
+    if ( iCurrentCommand == EMmsSend ||
+        iCurrentCommand == EMmsScheduledSend ||
+        iCurrentCommand == EMmsDeleteSchedule )
+        {
+        RestoreVisibilityAndService();
+        }
+
+    //
+    // Following switch handles all the different requests
+    //
+    switch( iCurrentCommand )
+        {
+        // scheduled operations can only use default service.
+        case EMmsScheduledSend:
+            if ( iMsvSelection->Count() > 0 )
+                {
+                iCommand = EMmsSend;
+                // This will complete our caller.
+                // If no error, task scheduler will complete the caller.
+                // If error, the subroutine will complete
+                error = ScheduleSelectionL();
+#ifndef _NO_MMSS_LOGGING_
+                if ( error != KErrNone )
+                    {
+                    TMmsLogger::Log( _L("MmsServer Schedule send status %d"), error );
+                    }
+#endif
+                }
+            else
+                {
+                // nothing to send - successfully sent nothing
+                // ("You must have keen eyes to see nobody coming")
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            break;
+        //
+        // Handle push message (i.e. notification or delivery report)
+        //
+        case EMmsDecodePushedMessage:
+            {
+            // 
+            // First read pushed data from dummy entries stream store,
+            // and then delete it.
+            // If there is no entry, HandleDummyEntryL() leaves
+            // 
+            HandleDummyEntryL();
+            //
+            // Decode received databuffer into message
+            //
+            TInt err = KErrNone;
+            TRAP( err, DecodePushedMessageL() );
+            // DecodePushedMessageL might set iError, don't override it
+            if ( iError == KErrNone )
+                {
+                iError = err;
+                }
+
+            delete iEncodeBuffer;
+            iEncodeBuffer = NULL;
+            // The resulting id is now in iNotification
+
+            if ( iNotification != KMsvNullIndexEntryId )
+                {
+                iMsvSelection->AppendL( iNotification );
+                if ( iServerEntry->SetEntry( iNotification ) == KErrNone )
+                    {
+                    entry = iServerEntry->Entry();
+                    }
+                // Unrecognized PDUs are handled as notifications.
+                // we send a response back to MMSC
+                if ( ( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageDeliveryInd ) ||
+                    ( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageReadOrigInd ) )
+                    {
+                    // Delivery report or PDU read report
+                    HandleDeliveryReportL();
+                    }
+                else
+                    {
+                    // Everything else. Handle as notification.
+                    // If not a notification, send back response "unrecognized"
+                    // Any PDU with wrong type will fall here besides the actual notifications.
+                    HandleNotificationL();
+                    }
+                }
+            else
+                {
+                // something has gone wrong...
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, iError );
+                }
+            break;
+            }
+        case EMmsScheduledReceiveForced:
+            iCommand = EMmsReceiveForced;
+            iMmsSettings->SetFetchOverride( ETrue );
+            // if we do forced fetch, we clean up old schedules first
+            if ( iMsvSelection->Count() > 0 )
+                {
+                CleanSchedulesL( *iMsvSelection );
+                }
+            // fall through on purpose
+        case EMmsScheduledReceive:
+            if ( iCurrentCommand != EMmsScheduledReceiveForced )
+                {
+                iCommand = EMmsReceive;
+                }
+            if ( iMsvSelection->Count() < 1 )
+                {
+                TRAP( iError, CreateNotificationsL() );
+                }
+            else // iMsvSelection->Count() > 0 
+                {
+                // notifications are not checked if the fetch is forced
+                if ( iCurrentCommand == EMmsScheduledReceive )
+                    {
+                    CheckNotificationsL( *iMsvSelection );
+                    }
+                }
+
+            if ( iMsvSelection->Count() > 0 )
+                {
+                // This will complete our caller.
+                // If no error, task scheduler will complete the caller.
+                // If error, the subroutine will complete
+                error = ScheduleSelectionL();
+#ifndef _NO_MMSS_LOGGING_
+                if ( error != KErrNone )
+                    {
+                    TMmsLogger::Log( _L("MmsServer Schedule receive status %d"), error );
+                    }
+#endif
+                }
+            else
+                {
+                // Nothing to be done, complete.
+                if ( iError != KErrNoMemory && iError != KErrDiskFull )
+                    {
+                    iError = KErrNone;
+                    }
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, iError );
+                }
+            break;
+        case EMmsSend:
+            // send messages in current selection
+            // we cannot do this, if we don't have settings.
+            // Our access point is defined in settings.
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("Number of entries to send %d"), iMsvSelection->Count() );
+#endif
+            if ( iMsvSelection->Count() == 0 )
+                {
+                // nothing in the selection...
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            else
+                {
+                iCommand = EMmsSend;
+                SendToMmscL();
+                }
+            break;
+        case EMmsReceive:
+            // fetch message to inbox
+            // This is a troublesome case.
+            // we cannot fetch if we did not manage to load
+            // our settings.
+            // And we cannot leave, because schsend has an assert
+            // that forbids rescheduling entries that are not children
+            // of local service. And our notifications are children of
+            // the MMS service itself.
+            iCommand = EMmsReceive;
+            FetchFromMmscL();
+            break;
+        case EMmsReceiveForced:
+            iCommand = EMmsReceiveForced;
+            iMmsSettings->SetFetchOverride( ETrue );
+            FetchFromMmscL();
+            break;
+        case EMmsLogDeliveryReport:
+            iCommand = EMmsLogDeliveryReport;
+            // delivery reports should appear one by one for handling
+            LogDeliveryReportL();
+            break;
+        case EMmsDeleteSchedule:
+            iScheduleSend->DeleteScheduleL( aSelection );
+            *iRequestStatus = KRequestPending;
+            User::RequestComplete( iRequestStatus, KErrNone );
+            break;
+        case EMmsDeleteEntries:
+            if ( iMsvSelection->Count() > 0 )
+                {
+                error = iServerEntry->SetEntry( iMsvSelection->At(0) );
+                if ( error == KErrNone )
+                    {
+                    error = iServerEntry->SetEntry( iServerEntry->Entry().Parent() );
+                    if ( error == KErrNone )
+                        {
+                        error = iServerEntry->DeleteEntries( *iMsvSelection );
+                        }
+                    }
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, error );
+                }
+            else
+                {
+                // if nothing to delete, then done already
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            break;
+        case EMmsGarbageCollection:
+            TRAP(error, GarbageCollectionL());
+            // This returns at least KMmsErrorOfflineMode
+            *iRequestStatus = KRequestPending;
+            User::RequestComplete( iRequestStatus, error );
+            break;
+        case EMmsMessageGeneration:
+            iCommand = EMmsReceiveForced;
+            iMmsSettings->SetLocalModeIn( KMmsMessageVariationDirectory() );
+            iMmsSettings->SetFetchOverride( ETrue );
+            // set local mode on the fly - not stored anywhere.
+            iMmsSettings->SetLocalMode( ETrue );
+            iMmsSettings->SetAcceptAnonymousMessages( ETrue ); // variated messages are anonymous
+            FetchFromMmscL();
+            break;
+        case EMmsDeleteExpiredNotifications:
+            // not implemented
+            *iRequestStatus = KRequestPending;
+            User::RequestComplete( iRequestStatus, KErrNotSupported );
+            break;
+
+        case EMmsScheduledForward:
+            // Make sure there is something to schedule
+            if ( iMsvSelection->Count() > 0 )
+                {
+                iCommand = EMmsForward;
+                // ScheduleSelectionL completes the caller.
+                // If no error, task scheduler will complete the caller.
+                // If error, the subroutine will complete
+                error = ScheduleSelectionL();
+#ifndef _NO_MMSS_LOGGING_
+                if ( error != KErrNone )
+                    {
+                    TMmsLogger::Log( _L("MmsServer EMmsScheduledForward status %d"), error );
+                    }
+#endif
+                }
+            else
+                {
+                // Nothing to send
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            break;
+
+        case EMmsForward:
+            // Sends the current selection (containing forward requests)
+            // we cannot do this, if we don't have settings.
+            // Our access point is defined in settings.
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("Number of forward requests to send %d"), iMsvSelection->Count() );
+#endif
+            if ( iMsvSelection->Count() == 0 )
+                {
+                // Nothing in the selection
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            else
+                {
+                iCommand = EMmsForward;
+                SendForwardRequestsToMmscL();
+                }
+            break;
+
+        //
+        // Handles scheduling of notification deletion
+        // 
+        case EMmsScheduledNotificationDelete:
+            // Make sure there is something to schedule
+            if ( iMsvSelection->Count() > 0 )
+                {
+                iCommand = EMmsNotificationDelete;
+                // ScheduleSelectionL completes the caller.
+                // If no error, task scheduler will complete the caller.
+                // If error, the subroutine will complete
+                error = ScheduleSelectionL();
+#ifndef _NO_MMSS_LOGGING_
+                if ( error != KErrNone )
+                    {
+                    TMmsLogger::Log( _L("MmsServer EMmsScheduledNotificationDelete status %d"), error );
+                    }
+#endif
+                }
+            else
+                {
+                // Nothing to schedule
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            break;
+
+        //
+        // Deletes selection of notifications
+        //
+        case EMmsNotificationDelete:
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("Number of notifications to delete %d"), iMsvSelection->Count() );
+#endif
+            if ( iMsvSelection->Count() == 0 )
+                {
+                // Nothing in the selection
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            else
+                {
+                iCommand = EMmsNotificationDelete;
+
+                // Dig out delete type
+                TCommandParameters param;
+                TPckgC<TCommandParameters> paramPack( param );
+                paramPack.Set( iParameter );
+
+                //
+                // Create a CMmsDeleteOperation instance and start it
+                // 
+                delete iDeleteOperation;
+                iDeleteOperation = NULL;
+                iDeleteOperation = CMmsDeleteOperation::NewL( iFs, iMmsSettings  );
+                iDeleteOperation->StartL(
+                    (TMmsDeleteOperationType)paramPack().iError,
+                    *iMsvSelection,
+                    *iServerEntry,
+                    iServiceEntryId,
+                    iStatus );
+                *iRequestStatus = KRequestPending;
+                SetActive();        
+                }
+            break;
+            // update mmbox list
+        case EMmsUpdateMmboxList:
+            iCommand = EMmsUpdateMmboxList;
+            delete iUpdateMmboxList;
+            iUpdateMmboxList = NULL;
+            iUpdateMmboxList = CMmsMmboxList::NewL( iFs, iMmsSettings );
+            iUpdateMmboxList->StartL(
+                *iMsvSelection,
+                *iServerEntry,
+                iServiceEntryId, 
+                iStatus );
+            *iRequestStatus = KRequestPending;
+            SetActive();
+            break;
+        case EMmsSendReadReport:
+            SendReadReportL();
+            break;
+        case EMmsScheduledReadReport:
+            if ( iMsvSelection->Count() > 0 )
+                {
+                iCommand = EMmsSendReadReport;
+                // ScheduleSelectionL completes the caller.
+                // If no error, task scheduler will complete the caller.
+                // If error, the subroutine will complete
+                error = ScheduleSelectionL();
+#ifndef _NO_MMSS_LOGGING_
+                if ( error != KErrNone )
+                    {
+                    TMmsLogger::Log( _L("MmsServer EMmsScheduledReadReport status %d"), error );
+                    }
+#endif
+                }
+            else
+                {
+                // Nothing to schedule
+                *iRequestStatus = KRequestPending;
+                User::RequestComplete( iRequestStatus, KErrNone );
+                }
+            break;
+        default:
+            *iRequestStatus = KRequestPending;
+            User::RequestComplete( iRequestStatus, KErrNotSupported );
+            break;
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CommandExpected
+// 
+// ---------------------------------------------------------
+//
+TBool CMmsServerMtm::CommandExpected()
+    {
+    // so far we don't expect anything
+
+    return EFalse;
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::Progress
+// 
+// ---------------------------------------------------------
+//
+const TDesC8& CMmsServerMtm::Progress()
+    {
+    // should load in latest progress, if something is going on
+
+    return iProgressBuffer;
+
+    }        
+
+// ---------------------------------------------------------
+// CMmsServerMtm::LoadResourceFile
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::LoadResourceFileL()
+    {
+    // THIS IS NO LONGER NEEDED, BECAUSE THERE IS NO RESOURCE FILE ANY MORE.
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::PopulateSchedulePackage
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::PopulateSchedulePackage( const TDesC8& aParameter,
+    const TBool /*aMove*/, TMsvSchedulePackage& aPackage ) const
+    {
+    aPackage.iParameter = aParameter;
+    // We have a member telling what we are supposed to do.
+    // We can schedule both sending and receiving.
+    aPackage.iCommandId =  iCommand;
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::RestoreScheduleSettingsL
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::RestoreScheduleSettingsL( 
+    TBool /*aRestoreErrorsFromResource*/, 
+    TInt /*aErrorsResourceId*/ )
+    {
+    // EMPTY IMPLEMENTATION
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::DoCancel
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::DoCancel()
+    {
+
+    // first cancel whatever operation is active
+    if ( iSendOperation )
+        {
+        iSendOperation->Cancel();
+        }
+
+    if ( iReceiveMessage )
+        {
+        iReceiveMessage->Cancel();
+        }
+
+    if ( iMmsLog )
+        {
+        iMmsLog->Cancel();
+        }
+
+    if( iDeleteOperation )
+        {
+        iDeleteOperation->Cancel();
+        }
+
+    if( iForwardOperation )
+        {
+        iForwardOperation->Cancel();
+        }
+
+    if ( iUpdateMmboxList )
+        {
+        iUpdateMmboxList->Cancel();
+        }
+
+    if ( iReadReport )
+        {
+        iReadReport->Cancel();
+        }
+
+    DoComplete( KErrCancel );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::DoRunL
+// Active object completion
+// Run is used in this object to clean up after operations have finished.
+//
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::DoRunL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L(" MmsServer DoRunL status %d"), iStatus.Int() );
+#endif
+
+    if ( iCurrentCommand == EMmsRetryServiceLoading )
+        {
+        StartCommandL(
+            *iMsvSelection,
+            iCurrentCommand,
+            iParameter,
+            *iRequestStatus);
+        return;
+        }
+
+    TInt error = KErrNone;
+
+    if ( iOOMState ) // out of memory.
+        {
+        error = KErrNoMemory;
+        }
+        
+    if ( iCurrentCommand == EMmsUpdateMmboxList )
+        {
+        error = iStatus.Int();
+        }
+
+    // When we come here, we must see, if everything
+    // was sent - or received, or if some items need resceduling
+    DoComplete( error );
+        
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::DoComplete
+// 
+// Active object complete
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::DoComplete( TInt aError )
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L(" MmsServer DoComplete with status %d"), aError );
+#endif
+
+    // free whatever entry we were holding
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    // iSendOperation and iReceiveMessage tell us if
+    // we were sending or receiving. The one that is non-null
+    // has done all the work
+
+    // Now we must check if all went fine, or do some entries
+    // need rescheduling.
+
+    // In the case of sending iMsvSelection holds Ids of the
+    // messages to be sent. In the case of receiving iMsvSelection
+    // holds Ids of the notifications corresponding to messages
+    // to be fetched.
+
+    TRAPD( error, UpdateEntriesL() );
+
+#ifdef __WINS__
+    if ( iSendOperation )
+        {
+        User::InfoPrint(_L("MMS sending complete"));
+        }
+    if ( iReceiveMessage )
+        {
+        User::InfoPrint(_L("MMS receiving complete"));
+        }
+#endif
+
+    // restore original entry
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    if ( iError == KErrNone )
+        {
+        // The error may be changed in UpdateEntriesL
+        iError = aError;
+        }
+      
+    if ( iError == KMmsErrorApplicationDiskFull )
+        {
+        // this was handled by restarting the fetch if possible
+        iError = KErrNone;
+        }
+        
+    if ( iError == KErrNone )
+        {
+        // Pass on the error from UpDateEntriesL if it is relevant
+        // to the caller.
+        // First all errors caused by simultaneous backup/restore
+        // are passed on.
+        // If the entries were successfully reschedules we should
+        // have no error here.
+        if ( error >= KMsvMediaUnavailable && error <= KMsvIndexRestore )
+            {
+            iError = error;
+            }
+        }
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MmsServer returns error: %d to caller" ), iError );
+#endif
+    if ( !( IsActive() && iStatus.Int() == KRequestPending ) )
+        {
+        // If CMmsServer has become active again it means that it has restarted
+        // the fetch after deleting some application messages
+        // The restarted fetch will complete caller when finished
+        
+        // However, if any ongoing operation is cancelled prematurely,
+        // we may still be in active state but our own status is "cancelled"
+        
+        User::RequestComplete( iRequestStatus, iError );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::LoadSettingsL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::LoadSettingsL( TInt aCommand )
+    {
+    // Load settings
+    iMmsSettings->LoadSettingsL();
+
+    // Save service entry id
+    iServiceEntryId = iMmsSettings->Service();
+    
+    // Make sure localmode related paths exist
+    if( iMmsSettings->LocalMode() )
+        {
+        iFs.MkDirAll( iMmsSettings->LocalModeIn() );
+        iFs.MkDirAll( iMmsSettings->LocalModeOut() );
+        }
+
+    // Load schedule settings    
+    ((CMmsScheduleSend*)iScheduleSend)->LoadSettingsL( aCommand );
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::SendToMmscL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::SendToMmscL()
+    {
+    // We call our new excellent state machine
+    delete iSendOperation;
+    iSendOperation = NULL;
+    iSendOperation = CMmsSendOperation::NewL( iFs, iMmsSettings );
+    iSendOperation->StartL( *iMsvSelection, *iServerEntry, 
+        iServiceEntryId, iStatus );
+    *iRequestStatus = KRequestPending;
+    SetActive();
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::SendForwardRequestsToMmscL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::SendForwardRequestsToMmscL()
+    {
+    //
+    // Create a CMmsForwardOperation instance and start it
+    // 
+    delete iForwardOperation;
+    iForwardOperation = NULL;
+    iForwardOperation = CMmsForwardOperation::NewL( iFs, iMmsSettings );
+    iForwardOperation->StartL( 
+        *iMsvSelection, 
+        *iServerEntry, 
+        iServiceEntryId, 
+        iStatus );
+    *iRequestStatus = KRequestPending;
+    SetActive();        
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::FetchFromMmscL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::FetchFromMmscL()
+    {
+    // We must put notifications into the selection.
+    // The notifications will be have the same format
+    // as message entries, but they will contain only
+    // MMS headers.
+
+    // The test version will use only the URI (Content-Location)
+    // from the notification.
+    // The Content-Location will contain the path and filename - 
+    // as the first approximation.
+
+    // For test purposes we create a fake selection by scanning
+    // the directory specified in the settings, and storing the
+    // filenames as messages under current service.
+
+    // If we have rescheduled entries, we don't create a new notification
+    // list, as we have one already
+    if ( iMsvSelection->Count() < 1 )
+        {
+        CreateNotificationsL();
+        }
+
+    // If anything was left, we fetch them
+    if ( iMsvSelection->Count() > 0 )
+        {
+        // We call our new excellent state machine
+        delete iReceiveMessage;
+        iReceiveMessage = NULL;
+        iReceiveMessage = CMmsReceiveMessage::NewL( iFs, iMmsSettings  );
+
+        iReceiveMessage->StartL( *iMsvSelection, *iServerEntry,
+            iServiceEntryId, iStatus );
+        if ( iRequestStatus->Int() != KRequestPending )
+            {
+            *iRequestStatus = KRequestPending;
+            }
+        SetActive();    
+        }
+    else
+        {
+        // We say we are done without error, if we pruned everything.
+        // The original notifications that caused the pruning should
+        // still be hanging around.
+        // There is a danger of fetching failing so often that
+        // we cannot even manage to send a response to MMSC, and
+        // it sends us a duplicate notification because it thinks
+        // the original one has got lost.
+        // We must carefully test the failure conditions and try to 
+        // determine reasonable amount of retries that should be done
+        // to avoid such situation.
+        // The other possibility would be to always remove the old
+        // notification if a new one arrives with identical TID and
+        // Content location, but then we would be in danger of
+        // deleting an entry that is currently being used to fetch
+        // a message.
+        // The actual fetching code in CMmsReceiveMessage class
+        // tries to test that the notifications are accessible,
+        // and it tries not to trap, if the notifications have
+        // disappeared from its lists,
+        if ( iError != KErrNoMemory &&
+            iError != KErrDiskFull && iError != KMmsErrorApplicationDiskFull )
+            {
+            iError = KErrNone;
+            }
+        if ( iRequestStatus->Int() != KRequestPending )
+            {
+            *iRequestStatus = KRequestPending;
+            }
+        if ( iError == KMmsErrorApplicationDiskFull )
+            {
+            // DoComplete will complete caller
+            iError = KErrNone; 
+            }
+        else
+            {
+            User::RequestComplete( iRequestStatus, iError );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::UpdateEntriesL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::UpdateEntriesL()
+    {
+    // if something goes fatally wrong, this error will be
+    // returned to the caller in hope the caller may be able
+    // to do something to fix the problem
+    TInt fatalError = KErrNone; 
+    TMsvEntry entry;
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("UpdateEntriesL" ));
+#endif
+
+    // Tell scheduler about entries that were successfully sent
+    // or received
+
+    // Rescedule failed entries
+    // We have a member that tells which command to use
+    // (Send or receive)
+
+    // The central repository file contains a list of hopeless cases.
+    // These are not rescheduled
+
+    TMsvSchedulePackage* schedulePackage = new( ELeave ) TMsvSchedulePackage;
+    CleanupStack::PushL( schedulePackage );
+    PopulateSchedulePackage( iParameter, ETrue, *schedulePackage );
+
+    // Failed forward entries
+    if( iForwardOperation && iForwardOperation->Failed().Count() > 0 )
+        {
+        HandleFailedForwardsL( *schedulePackage );
+        }
+
+    // Successfully sent entries
+    if( iSendOperation && iSendOperation->Sent().Count() > 0 )
+        {
+        HandleSuccessfulSendsL();
+        }
+
+    // Entries that failed to be sent
+    if ( iSendOperation && iSendOperation->Failed().Count() > 0 )
+        {
+        HandleFailedSendsL( *schedulePackage );
+        }
+
+    // Message generation (branding messages)
+    if ( iReceiveMessage && iCurrentCommand == EMmsMessageGeneration )
+        {
+        CleanupAfterMessageGenerationL();
+        }
+
+    // Mark entries that failed to be fetched
+    // If there is some error connected to this, it must be returned to caller
+    // as fetching is automatic.
+    TBool restartFetch = EFalse;
+    if ( iReceiveMessage && iReceiveMessage->Failed().Count() > 0 )
+        {
+        restartFetch = HandleFailedReceivesL( *schedulePackage, fatalError );
+        }
+
+    // Successfully received entries
+    if ( iReceiveMessage && iReceiveMessage->Received().Count() > 0 )
+        {
+        HandleSuccessfulReceivesL();
+        }
+
+    // Remove bad notifications from task scheduler
+    if ( iReceiveMessage && iReceiveMessage->BadNotifications().Count() > 0 )
+        {
+        HandleBadNotificationsL();
+        }
+        
+    if ( restartFetch )
+        {
+        // We did find some failed notifications that were in inbox or MMBox folder
+        // These are not normally rescheduled
+        // But if the error was due to lack of disk space and we have been able to
+        // free the disk space by deleting some older messages belonging to a 
+        // lazy application, we can retry the fetch immediately
+        
+        // We must clear the receiver class to start with a clean slate.
+        delete iReceiveMessage;
+        iReceiveMessage = NULL;
+        FetchFromMmscL();
+        iError = KMmsErrorApplicationDiskFull;
+        }
+
+    // update delivery status counts and reschedule possible extra delivcery reports
+    if ( iCommand == EMmsLogDeliveryReport )
+        {
+        UpdateDeliveryReportsL( *schedulePackage );
+        }
+     
+    // handle failed read report entries    
+    if ( iReadReport && iReadReport->Failed().Count() > 0 )
+        {
+        HandleFailedReadReports();
+        }
+        
+    CleanupStack::PopAndDestroy( schedulePackage );
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("UpdateEntriesL done, error: %d" ), iError );
+#endif
+    if ( fatalError != KErrNone )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("UpdateEntriesL, fatal error: %d" ), fatalError );
+#endif
+        // we catch this
+        User::Leave( fatalError );
+        // return not needed as User::Leave returns
+        }
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleFailedForwardsL( TMsvSchedulePackage& aPackage )
+    {
+    TInt count = 0;
+    TMsvEntry entry;
+    TInt error = KErrNone;
+
+    count = iForwardOperation->Failed().Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- %d failed (not sent) forward entries"), count );
+    TInt rescheduled = count; // rescheduled needed only for logging
+#endif
+    // Loop selection and make them reschedulable (readonly == false)
+    while ( count-- )
+        {
+        if ( iServerEntry->SetEntry( iForwardOperation->Failed().At( count ) ) == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            entry.SetReadOnly( EFalse );
+            iServerEntry->ChangeEntry( entry ); // ignore error
+            }
+        }
+
+    //
+    //  Now reschedule.
+    //
+    iScheduleSend->ReScheduleL( iForwardOperation->Failed(), aPackage );
+
+    // Mark entries that failed to be rescheduled
+    count = iForwardOperation->Failed().Count();
+    while ( count-- )
+        {
+        if ( iServerEntry->SetEntry( iForwardOperation->Failed().At( count ) ) == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            if ( entry.SendingState() != KMsvSendStateResend )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- forward entry failed to reschedule, setting state to failed") );
+#endif
+                entry.SetSendingState( KMsvSendStateFailed );
+                error = iServerEntry->ChangeEntry( entry ); // ignore error
+#ifndef _NO_MMSS_LOGGING_
+                if( error != KErrNone )
+                    {
+                    TMmsLogger::Log( _L("- ERROR: changing entry failed") );
+                    }
+#endif
+                // Clear related notification from Inbox:
+                // Get the related notification id
+                CMsvStore* store = NULL;
+                store = iServerEntry->EditStoreL();
+                CleanupStack::PushL( store ); // ***
+                iMmsHeaders->RestoreL( *store );
+                CleanupStack::PopAndDestroy( store );
+                TMsvId relatedEntryId = iMmsHeaders->RelatedEntry();
+                iMmsHeaders->Reset(); // headers not needed any more
+
+                if( relatedEntryId != KMsvNullIndexEntryId )
+                    {
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- related notification-entry exists, clearing it") );
+#endif
+                    // Set context (iServerEntry and entry) to notification and clear it
+                    error = iServerEntry->SetEntry( relatedEntryId );
+#ifndef _NO_MMSS_LOGGING_
+                    if( error != KErrNone )
+                        {
+                        TMmsLogger::Log( _L("- ERROR: Could not set entry") );
+                        }
+#endif
+                    entry = iServerEntry->Entry();
+                    entry.iMtmData2 &= ~KMmsNewOperationForbidden; // not forbidden
+                    entry.iMtmData2 &= ~KMmsOperationOngoing;      // not ongoing
+                    entry.iMtmData2 |= KMmsOperationFinished;      // finished
+                    entry.iMtmData2 |= KMmsOperationResult;        // NOK
+                    entry.SetReadOnly( ETrue );
+                    error = iServerEntry->ChangeEntry( entry );
+#ifndef _NO_MMSS_LOGGING_
+                    if( error != KErrNone )
+                        {
+                        TMmsLogger::Log( _L("- ERROR: Could not change related entry") );
+                        }
+                    TMmsLogger::Log( _L("- Clear the related-entry link itself") );
+#endif
+
+                    // Clear related-id link from forward entry
+                    if ( iMsvSelection->Count() > count )
+                        {
+                        error = iServerEntry->SetEntry( iMsvSelection->At( count ) );
+                        }
+                    else
+                        {
+                        // We should never get this,
+                        // we check count only to keep CodeScanner happy
+                        error = KErrNotFound; 
+                        }
+                    if ( error == KErrNone )
+                        {
+                        store = iServerEntry->EditStoreL();
+                        CleanupStack::PushL( store ); // ***
+                        iMmsHeaders->RestoreL( *store );
+                        iMmsHeaders->SetRelatedEntry( KMsvNullIndexEntryId );
+                        iMmsHeaders->StoreL( *store );
+                        store->CommitL();
+                        CleanupStack::PopAndDestroy( store );
+                        iMmsHeaders->Reset(); // headers not needed any more
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- Related-entry and the link cleared") );
+#endif
+                        }
+                    }
+
+                // let go of the entry
+                iServerEntry->SetEntry( KMsvNullIndexEntryId );
+                }
+            else
+                {
+                //
+                // Delete successfully rescheduled entries
+                //
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- notification is in resend, as it should") );
+#endif
+                iForwardOperation->Failed().Delete( count );
+                }
+            }
+#ifndef _NO_MMSS_LOGGING_
+        else
+            {
+            TMmsLogger::Log( _L("- ERROR: could not access entry %d"), count );
+            }
+#endif
+        }
+
+#ifndef _NO_MMSS_LOGGING_
+    count = iForwardOperation->Failed().Count();
+    rescheduled = rescheduled - count;
+    if ( rescheduled > 0 )
+        {
+        TMmsLogger::Log( _L("- %d rescheduled forward entries"), rescheduled );
+        }
+    if ( count > 0 )
+        {
+        TMmsLogger::Log( _L("- %d not rescheduled forward entries"), count );
+        }
+#endif
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleSuccessfulSendsL()
+    {
+    TInt count = 0;
+    TMsvEntry entry;
+    
+    // Delete schedule should not be needed in the case of successfully
+    // sent entries.
+    count = iSendOperation->Sent().Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- %d Sent entries"), count );
+#endif
+    iScheduleSend->DeleteScheduleL( iSendOperation->Sent() );
+    while ( count-- )
+        {
+        if ( iServerEntry->SetEntry( iSendOperation->Sent().At( count ) ) == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            entry.SetSendingState( KMsvSendStateSent );
+            if ( entry.Parent() == KMsvSentEntryIdValue )
+                {
+                // if we have not managed to move this entry away from outbox,
+                // it must not be set to read only state
+                entry.SetReadOnly( ETrue );
+                }
+            // We don't want to leave here, we want to continue.
+            // The next message may succeed.
+            // We don't consider this fatal: If the message
+            // has been successfully sent, it should already
+            // be moved to sent folder.
+            // If the user tries to send messages during backup/restore,
+            // it is his own fault if the messages are sent more than once.
+            iServerEntry->ChangeEntry( entry );
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleFailedSendsL( TMsvSchedulePackage& aPackage )
+    {
+    TInt count = 0;
+    TMsvEntry entry;
+    
+    count = iSendOperation->Failed().Count();
+#ifndef _NO_MMSS_LOGGING_
+    TInt rescheduled = count;
+    TMmsLogger::Log( _L("- %d failed (not sent) entries"), count );
+#endif
+    while ( count-- )
+        {
+        if ( iServerEntry->SetEntry( iSendOperation->Failed().At( count ) ) == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            // we set the entry into failed state after we have
+            // checked if it still can be rescheduled.
+            entry.SetReadOnly( EFalse );
+            iServerEntry->ChangeEntry( entry ); // ignore error
+            if ( entry.SendingState() == KMsvSendStateSuspended &&
+                entry.iError != KMmsErrorOfflineMode )
+                {
+                // suspended by user, not offline mode
+                // We remove this just in case.
+                // If everything has gone well, the error is "KErrNotFound"
+                // and the entry would not be rescheduled, but this is an
+                // extra precaution.
+                iSendOperation->Failed().Delete( count );    
+                }
+            }
+        }
+        
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    count = iSendOperation->Failed().Count();
+
+    if ( count > 0 )
+        {
+        // Check needed to avoid a stupid ASSERT_DEBUG
+        iScheduleSend->ReScheduleL( iSendOperation->Failed(), aPackage );
+        }
+
+    // Mark entries that failed to be rescheduled
+    count = iSendOperation->Failed().Count();
+
+    while ( count-- )
+        {
+        if ( iServerEntry->SetEntry( iSendOperation->Failed().At( count ) ) == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            if ( entry.SendingState() != KMsvSendStateResend )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- setting state to failed") );
+#endif
+                entry.SetSendingState( KMsvSendStateFailed );
+                iServerEntry->ChangeEntry( entry ); // ignore error
+                // let go of the entry
+                iServerEntry->SetEntry( KMsvNullIndexEntryId );
+                }
+            else
+                {
+                iSendOperation->Failed().Delete( count );
+                }
+            }
+#ifndef _NO_MMSS_LOGGING_
+        else
+            {
+            TMmsLogger::Log( _L("- could not access entry %d"), count );
+            }
+#endif
+        }
+
+    count = iSendOperation->Failed().Count();
+#ifndef _NO_MMSS_LOGGING_
+    rescheduled = rescheduled - count;
+    if ( rescheduled > 0 )
+        {
+        TMmsLogger::Log( _L("- %d rescheduled for sending"), rescheduled );
+        }
+    if ( count > 0 )
+        {
+        TMmsLogger::Log( _L("- %d hopeless, not rescheduled for sending"), count );
+        }
+#endif
+
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CleanupAfterMessageGenerationL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- Finished message generation") );
+#endif
+    // we try only once.
+    // The whole selection must be in the same place.
+    CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
+    CleanupStack::PushL( selection );
+    
+    // everything must go.
+    if ( iReceiveMessage->BadNotifications().Count() > 0 )
+        {
+        selection->AppendL( iReceiveMessage->BadNotifications().Back( 0 ),
+            iReceiveMessage->BadNotifications().Count() );
+        iReceiveMessage->BadNotifications().Reset();
+        }
+    
+    if ( iReceiveMessage->Failed().Count() > 0 )
+        {
+        selection->AppendL( iReceiveMessage->Failed().Back( 0 ),
+            iReceiveMessage->Failed().Count() );
+        iReceiveMessage->Failed().Reset();
+        }
+        
+    if ( iReceiveMessage->Received().Count() > 0 )
+        {
+        selection->AppendL( iReceiveMessage->Received().Back( 0 ),
+            iReceiveMessage->Received().Count() );
+        iReceiveMessage->Received().Reset();
+        }
+    
+    // If the next loop fails, we don't care:
+    // The files will be deleted ayway, and the notifications will be orphaned
+    // If there is something weird going on during the boot,
+    // the phone won't probably work after this anyway.
+    if ( selection->Count() > 0 )
+        {
+        if ( iServerEntry->SetEntry( selection->At( 0 ) ) == KErrNone )
+            {
+            if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
+                {
+                iServerEntry->DeleteEntries( *selection );
+                }
+            }
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        }
+    CleanupStack::PopAndDestroy( selection );
+
+    // Then we delete the files in the directory
+    // (if anything left)
+    CFileMan* fileMan = CFileMan::NewL( iFs );
+    CleanupStack::PushL( fileMan );
+    // Best effort - ignore error
+    fileMan->RmDir( KMmsMessageVariationDirectory );
+    CleanupStack::PopAndDestroy( fileMan );
+    
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+TBool CMmsServerMtm::HandleFailedReceivesL( TMsvSchedulePackage& aPackage, TInt& aFatalError )
+    {
+    TInt count = 0;
+    TMsvEntry entry;
+    TInt error = KErrNone;
+    TBool restartFetch = EFalse;
+    
+    iMsvSelection->Reset();
+    count = iReceiveMessage->Failed().Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- %d failed (not received) entries"), count );
+#endif
+    // Check if the current receive mode is manual
+    TBool manual = EFalse;
+    if( iReceiveMessage->InForeignNetwork() )
+        {
+        if( iMmsSettings->ReceivingModeForeign() == EMmsReceivingManual )
+            {
+            manual = ETrue;
+            }
+        }
+    else
+        {
+        if( iMmsSettings->ReceivingModeHome() == EMmsReceivingManual )
+            {
+            manual = ETrue;
+            }
+        }
+
+    TBool inInbox = EFalse;
+    TBool inMmsFolder = EFalse;
+    TBool inMmboxFolder = EFalse;
+
+    while ( count-- )
+        {
+        error = iServerEntry->SetEntry( iReceiveMessage->Failed().At( count ) );
+        if ( error == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+
+            if ( entry.iMtmData2 & KMmsDoNotMoveToInbox )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- do not move entry to inbox "));
+#endif
+                // We do not reschedule this. It will potentially cause problems at mode change
+                // if it has not been handled by then.
+                iReceiveMessage->Failed().Delete( count );
+                // it is put into bad list and deleted later
+                iReceiveMessage->BadNotifications().AppendL( entry.Id() );
+                }
+            else
+                {
+                if ( entry.Parent() == FindMMSFolderL() )
+                    {
+                    inMmsFolder = ETrue;
+                    }
+                else if ( entry.Parent() == KMsvGlobalInBoxIndexEntryIdValue )        
+                    {
+                    inInbox = ETrue;
+                    // inbox entries will not be rescheduled
+                    if ( entry.iError == KMmsErrorApplicationDiskFull )
+                        {
+                        // This is best effort only - error ignored
+                        iMsvSelection->AppendL( iReceiveMessage->Failed().At( count ) );
+                        restartFetch = ETrue;
+                        }
+                    iReceiveMessage->Failed().Delete( count );
+                    }
+                else
+                    {
+                    inMmboxFolder = ETrue;
+                    if ( entry.iError == KMmsErrorApplicationDiskFull )
+                        {
+                        // This is best effort only - error ignored
+                        iMsvSelection->AppendL( iReceiveMessage->Failed().At( count ) );
+                        restartFetch = ETrue;
+                        }
+                    // mmbox entries will not be rescheduled
+                    iReceiveMessage->Failed().Delete( count );
+                    manual = EFalse; // manual mode must not affect the mmbox notification
+                    }
+                // We don't have a separate receiving state.
+                // We just use sending state instead.
+                // We are the only one that uses scheduled receiving.
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- marking sending state as failed "));
+#endif
+                entry.SetSendingState( KMsvSendStateFailed );
+
+                if ( manual && inMmsFolder )
+                    {
+                    // Change the iMtm from KUidMsgTypeMultimedia to 
+                    // KUidMsgMMSNotification   
+                    entry.iMtm.iUid = KUidMsgMMSNotification.iUid; // this is a notification
+
+                    entry.iMtmData2 &= ~KMmsOperationFinished; // clear flag just in case
+                    entry.iMtmData2 &= ~KMmsOperationResult; // clear flag just in case
+                    entry.iMtmData2 &= ~KMmsOperationOngoing; // Fetch operation is not active anymore
+                    entry.iMtmData2 &= ~KMmsNewOperationForbidden; // New operation can be started
+                    entry.iMtmData1 |= KMmsMessageMobileTerminated;
+                    entry.SetReadOnly( ETrue );
+                    entry.iError = KErrNone;
+                    entry.SetSendingState( KMsvSendStateUnknown );                    
+                    }
+                else if ( inInbox  )
+                    {
+                    // Mark original notification
+                    CMmsBaseOperation::MarkNotificationOperationFailed( entry ); 
+                    if ( entry.iError != KMmsErrorApplicationDiskFull )
+                        {
+                        entry.SetReadOnly( ETrue );
+                        }
+                    }
+                else if ( inMmboxFolder )
+                    {
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- in mmbox folder"));
+#endif
+                    TRAP( error, CMmsBaseOperation::MarkDuplicateL(
+                        CMmsBaseOperation::EMmsNotificationOperationFailed,
+                        *iServerEntry ) );
+                    error = KErrNone; // ignore error from trap    
+                    entry = iServerEntry->Entry();
+                    CMmsBaseOperation::MarkNotificationOperationFailed( entry );
+                    if ( entry.iError != KMmsErrorApplicationDiskFull )
+                        {
+                        entry.SetReadOnly( ETrue );
+                        }
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- marking original notif failed"));
+#endif                    
+                    }
+                else
+                    {
+                    // keep LINT happy
+                    }
+                error = iServerEntry->ChangeEntry( entry );
+                
+                // move the entry from mms folder to the inbox in manual mode.
+                if ( manual && inMmsFolder )
+                    {
+                    iError = iServerEntry->SetEntry( entry.Parent() );
+                    if ( iError == KErrNone )
+                        {
+                        error = iServerEntry->MoveEntryWithinService(
+                            entry.Id(), KMsvGlobalInBoxIndexEntryIdValue );
+                        }
+                    else
+                        {
+                        error = iError;
+                        }
+                    if ( error == KErrNone )
+                        {
+                        inInbox = ETrue;
+                        // This should not be rescheduled as it has moved to inbox
+                        iReceiveMessage->Failed().Delete( count );
+                        }
+                    }
+                }
+            if ( aFatalError == KErrNone )
+                {
+                // if we canot access the entry, tell the caller
+                aFatalError = error;
+                }
+            // let go of the entry
+            iServerEntry->SetEntry( KMsvNullIndexEntryId );
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("UpdateEntriesL: entry #%d, sending state = failed"), count );
+            TMmsLogger::Log( _L("UpdateEntriesL: entry #%d, error = %d"), count, entry.iError );
+            if ( error != KErrNone )
+                {
+                TMmsLogger::Log( _L("UpdateEntriesL: ChangeEntry failed, error %d"), error );
+                }
+#endif
+            }
+#ifndef _NO_MMSS_LOGGING_
+        else
+            {
+            // Not found is not fatal. What is gone is gone.
+            if ( error != KErrNotFound )
+                {
+                if ( aFatalError == KErrNone )
+                    {
+                    aFatalError = error;
+                    }
+                }
+            TMmsLogger::Log( _L("UpdateEntriesL: could not access entry #%d"), count );
+            }
+#endif
+        }
+
+    // only if the notification is in mmsfolder, reschedule the notification
+    // if the notification is in Inbox or in mmbox folder, do not rescedule.
+    // We have removed each notification from failed list if it was originally
+    // in inbox or in MMBox folder or if it was successfully moved to inbox
+    if( iReceiveMessage->Failed().Count() > 0 )
+        {
+        iScheduleSend->ReScheduleL( iReceiveMessage->Failed(), aPackage );
+        }
+    // The messages that could not be rescheduled anymore, are either deleted, or moved
+    // to Inbox to be handled manually
+    count = iReceiveMessage->Failed().Count();
+    // we do not delete hopeless entries:
+    // There is a separate error watcher that decides
+    // what to do with them.
+    // For example: If there is no access point, receiving
+    // fails. The error watcher gives notice to user, and
+    // when the user has entered the access point, the 
+    // fetch is restarted by the error watcher.
+#ifndef _NO_MMSS_LOGGING_
+    TInt hopeless = count;
+#endif
+    while ( count-- )
+        {
+        TMsvId failedEntry = iReceiveMessage->Failed().At( count );
+        if ( iServerEntry->SetEntry( failedEntry ) == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            // update retry count
+            TRAP( error, 
+                {
+                CMsvStore* store = NULL;
+                store = iServerEntry->ReadStoreL();
+                CleanupStack::PushL( store );
+                CMmsScheduledEntry* mmsScheduledEntry =
+                    CMmsScheduledEntry::NewL( iServerEntry->Entry() );
+                CleanupStack::PushL( mmsScheduledEntry );
+                mmsScheduledEntry->RestoreL( *store );
+                entry.iMtmData3 &= ~KMmsRetryCountMask;
+                entry.iMtmData3 |= mmsScheduledEntry->MmsRecipient().Retries();
+                iServerEntry->ChangeEntry( entry );
+                CleanupStack::PopAndDestroy( mmsScheduledEntry );
+                CleanupStack::PopAndDestroy( store );
+                }
+            );
+
+            if ( entry.SendingState() == KMsvSendStateFailed ) 
+                {
+                // remove from list just to see what was left over
+                iReceiveMessage->Failed().Delete( count );
+                }
+            }
+        }
+#ifndef _NO_MMSS_LOGGING_
+    count = iReceiveMessage->Failed().Count();
+    hopeless = hopeless - count;
+    if ( count > 0 )
+        {
+        TMmsLogger::Log( _L("- %d rescheduled for receiving"), count );
+        }
+    if ( hopeless > 0 )
+        {
+        TMmsLogger::Log( _L("- %d hopeless, not rescheduled for receiving"), hopeless );
+        }
+#endif  
+        
+    return restartFetch;
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleSuccessfulReceivesL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- %d received entries"), iReceiveMessage->Received().Count() );
+#endif
+    TMsvId parent = KMsvNullIndexEntryId;
+    // The whole selection must be in the same place.
+    if ( iServerEntry->SetEntry( iReceiveMessage->Received().At( 0 ) ) == KErrNone  )
+        {
+        parent = iServerEntry->Entry().Parent();
+        }
+
+    CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
+    CleanupStack::PushL( selection );
+    selection->AppendL( iReceiveMessage->Received().Back( 0 ),
+        iReceiveMessage->Received().Count() );
+
+    // if entry is in inbox or in MMBoxfolder,
+    // check possible duplicate and mark it "fetched from server"
+    if ( parent == KMsvGlobalInBoxIndexEntryIdValue || parent == iMmsSettings->MMBoxFolder() )
+        {
+        for ( TInt i = selection->Count(); i > 0; i-- )
+            {
+            if ( iServerEntry->SetEntry( selection->At( i - 1 )) == KErrNone )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- check possible duplicate" ));
+#endif
+                CMsvStore* store = iServerEntry->ReadStoreL();
+                CleanupStack::PushL( store );
+                iMmsHeaders->RestoreL( *store );
+                CleanupStack::PopAndDestroy( store );
+                store = NULL;
+                TMsvId duplicate = KMsvNullIndexEntryId;
+
+                if ( parent == KMsvGlobalInBoxIndexEntryIdValue )
+                    {
+                    TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
+                    if ( mmboxFolder != KMsvNullIndexEntryId )
+                        {
+                        FindDuplicateNotificationL( mmboxFolder, *iMmsHeaders, duplicate );
+                        }
+                    }
+                else // parent is mmbox folder
+                    {
+                    duplicate = iMmsHeaders->RelatedEntry();
+                    }
+                if ( duplicate != KMsvNullIndexEntryId )
+                    {
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- duplicate found"));
+#endif
+                    if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
+                        {
+                        // Mark duplicate
+                        TMsvEntry dupEntry = iServerEntry->Entry();
+                        CMmsBaseOperation::MarkNotificationDeletedFromMmbox( dupEntry );
+                        iServerEntry->ChangeEntry( dupEntry );
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- duplicate marked as fetched from mmbox"));
+#endif
+                        }
+                    } 
+                }
+            }
+        }
+    if ( parent != KMsvNullIndexEntryId && iServerEntry->SetEntry( parent ) == KErrNone )
+        {
+        iServerEntry->DeleteEntries( *selection );
+        }
+    CleanupStack::PopAndDestroy( selection );
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleBadNotificationsL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- %d bad notification entries"), iReceiveMessage->BadNotifications().Count() );
+#endif
+    // The whole selection must be in the same place.
+    if ( iServerEntry->SetEntry( iReceiveMessage->BadNotifications().At( 0 ) ) == KErrNone )
+        {
+        if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
+            {
+            CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
+            CleanupStack::PushL( selection );
+            selection->AppendL( iReceiveMessage->BadNotifications().Back( 0 ),
+                iReceiveMessage->BadNotifications().Count() );
+            iServerEntry->DeleteEntries( *selection );
+            CleanupStack::PopAndDestroy( selection );
+            }
+        }
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::UpdateDeliveryReportsL( TMsvSchedulePackage& aPackage )
+    {
+    TInt error = KErrNone;
+    TMsvEntry entry;
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- logged delivery report" ));
+#endif
+    if ( iError == KErrNone )
+        {
+        // first entry in selection was handled
+        CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
+        CleanupStack::PushL( selection );
+        selection->AppendL( iMsvSelection->At( 0 ), 1 );
+        if ( selection->Count() > 0 )
+            {
+            error = iServerEntry->SetEntry( selection->At( 0 ) );
+            }
+        else
+            {
+            // this will never happen - we are just keeping codescanner happy
+            error = KErrNotFound;
+            }
+        if ( error == KErrNone )
+            {
+            if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
+                {
+                iServerEntry->DeleteEntries( *selection );
+                }
+            }
+        CleanupStack::PopAndDestroy( selection );
+        iMsvSelection->Delete( 0 );
+        }
+    
+    //Now let's set delivery report bits in MtmData
+    TMsvId link = 0;
+    if ( iMmsLog )
+        {
+        link = iMmsLog->GetLink();
+        }
+    if (link != 0)
+        {
+        error = iServerEntry->SetEntry(link);
+        if ( error == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            }
+        }
+
+    // Even if the link exists, the original message may have disappeared already
+    // (if only 20 messages are saved in outbox, they may start disappearing quite fast)
+    if ( link != 0 && error == KErrNone && ( entry.iMtmData2 & KMmsDeliveryStatusMask ) !=
+        KMmsDeliveryStatusNotRequested )
+        {
+        TUint temp(0);
+        TUint total(0);
+        if (iDeliveryStatus) //successfully delivered
+            {
+            total = ( entry.iMtmData3 & KMmsSentItemTotalRecipientsMask ) >>
+                KMmsSentItemTotalRecipientsShift;
+            
+            temp = ( entry.iMtmData3 & KMmsSentItemSuccessfullyDeliveredMask )
+                >> KMmsSentItemSuccessfullyDeliveredShift;
+            temp++;
+            entry.iMtmData3 &= ~KMmsSentItemSuccessfullyDeliveredMask;
+            entry.iMtmData3 |= temp << KMmsSentItemSuccessfullyDeliveredShift;
+            
+            // must make sure that if even one send has been failed the delivery status
+            // is always failed
+            if ( temp == total  && ( entry.iMtmData2 & KMmsDeliveryStatusMask )
+                != KMmsDeliveryStatysFailed )
+                {
+                entry.iMtmData2 &= ~KMmsDeliveryStatusMask;
+                entry.iMtmData2 |= KMmsDeliveryStatysDelivered;
+                }
+            else if (temp < total && ( entry.iMtmData2 & KMmsDeliveryStatusMask )
+                != KMmsDeliveryStatysFailed  )
+                {
+                entry.iMtmData2 &= ~KMmsDeliveryStatusMask;
+                entry.iMtmData2 |= KMmsDeliveryStatusPartial;
+                }
+            else
+                {
+                // keep LINT happy
+                }
+
+            }
+        else 
+            {
+            temp = (entry.iMtmData3 & KMmsSentItemFailedDeliveryMask) >>
+                KMmsSentItemFailedDeliveryShift;
+            temp++;
+            entry.iMtmData3 &= ~KMmsSentItemFailedDeliveryMask;
+            entry.iMtmData3 |= temp << KMmsSentItemFailedDeliveryShift;
+            entry.iMtmData2 &= ~KMmsDeliveryStatusMask;
+            entry.iMtmData2 |= KMmsDeliveryStatysFailed;
+                            
+            
+            }
+        // If we successfully accessed the entry, iServerEntry must still be pointing to the link.
+        iServerEntry->ChangeEntry(entry);    
+        }
+        
+    iError = KErrNone; // we don't care about the error.
+    // We should normally never be here, delivery reports come
+    // one at a time...
+    if ( iMsvSelection->Count() > 0 )
+        {
+        iScheduleSend->ReScheduleL( *iMsvSelection, aPackage );
+        }
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleFailedReadReports()
+    {
+    TInt error = KErrNone;
+    if ( iReadReport->Failed().Count() > 0 )
+        {
+        error = iServerEntry->SetEntry( iReadReport->Failed().At( 0 ) );
+        }
+    else
+        {
+        error = KErrNotFound;
+        }
+    if ( error == KErrNone )
+        {
+        error = iServerEntry->SetEntry( iServerEntry->Entry().Parent() );
+        }
+    if ( error == KErrNone )
+        {
+        TInt i;
+        for ( i = iReadReport->Failed().Count() - 1; i >= 0; i-- )
+            {
+            iServerEntry->DeleteEntry( iReadReport->Failed().At( i ) );
+            }
+        }
+    }
+   
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::MakeDatesIdenticalL(
+    CMsvEntrySelection& aSelection,
+    TTimeIntervalSeconds aInterval,
+    TBool aClearError /* = EFalse */ )
+    {
+
+    TInt count = aSelection.Count();
+    TTime curTime;
+    curTime.UniversalTime();
+    if ( aInterval > TTimeIntervalSeconds( KMmsDelayInSeconds ) )
+        {
+        curTime += aInterval;
+        }
+    else
+        {
+        curTime += TTimeIntervalSeconds( KMmsDelayInSeconds );
+        }
+
+    while ( count-- )
+        {
+        if ( iServerEntry->SetEntry( aSelection.At( count ) ) == KErrNone )
+            {
+            TMsvEntry entry = iServerEntry->Entry();
+            if ( entry.Id() != aSelection.At( count ) || entry.Id() == KMsvNullIndexEntryId )
+                {
+                // The entry is garbage
+                aSelection.Delete( count, 1 );
+                }
+            else
+                {
+                entry.iDate = curTime;
+                if ( aClearError )
+                    {
+                    entry.iError = KErrNone;
+                    }
+                iServerEntry->ChangeEntry( entry );
+                }
+            }
+        }
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::DecodePushedMessageL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::DecodePushedMessageL()
+    {
+
+    // Decode the pushed content to see, if it was
+    // a notification or a delivery report
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MmsServer decoding pushed message") );
+#endif
+    iNotification = KMsvNullIndexEntryId;
+    iMmsHeaders->Reset();
+    // the possible error from this is not important as the settings are
+    // now stored in central repository
+    iServerEntry->SetEntry( iServiceEntryId );
+
+    // We decode first, and create the entry afterwards.
+    if ( !iDecoder )
+        {
+        iDecoder = CMmsDecode::NewL( iFs );
+        }
+
+    if ( !iEntryWrapper )
+        {
+        iEntryWrapper = CMmsServerEntry::NewL(
+            iFs,
+            *iServerEntry,
+            iServiceEntryId );
+        }
+
+    TRAP ( iError, iDecoder->DecodeHeadersL( *iEntryWrapper, *iMmsHeaders, *iEncodeBuffer ) );
+
+    // If we could not allocate memory to decode, we must try again later.
+    if ( iError == KErrNoMemory )
+        {
+        return;
+        }
+
+    if ( iError == KErrCorrupt ||
+        iError == KErrTooBig )
+        {
+        // if the notification has illegal content,
+        // it is just discarded, we must not tell the
+        // mmswatcher to resend it.
+        iError = KErrNone;
+        return;
+        }
+    
+    // Even if we encounter an error when decoding, we must save
+    // the message for handling, because we must be able to send
+    // "unrecognized" status back, if we get an unknown PDU
+    // If we get a message with different major version number, it
+    // may be so incompatible that we get an error while decoding.
+
+    // If we get a notification, we make some sanity checks so that 
+    // we can reject malicious notifications right away.
+
+    // mark if this is a notification of a delivery report
+    // send requests or retrieve confirmations are not pushed
+    // They are equivalent to unrecognized type
+
+    TUint32 messageType = 0;
+    switch ( iMmsHeaders->MessageType() )
+        {
+        case KMmsMessageTypeMNotificationInd:
+            messageType = KMmsMessageMNotificationInd;
+            break;
+        case KMmsMessageTypeDeliveryInd:
+            messageType = KMmsMessageDeliveryInd;
+            break;
+        case KMmsMessageTypeReadOrigInd:
+            messageType = KMmsMessageReadOrigInd;
+            break;
+        default:
+            // unrecognized type.
+            // We must send response to MMSC
+            // This includes types that should never be pushed to us.
+            messageType = KMmsMessageUnrecognized;
+            break;
+        }
+
+    // If this is an extended notification, it may already contain the whole message
+    TBool completeMessage = ( iMmsHeaders->MessageComplete() == KMmsExtendedMessageComplete );
+
+    TBool passedChecks = ETrue; // we are optimistic
+
+    // If we have a notification, we must do a couple of special tricks.
+
+    if ( messageType == KMmsMessageMNotificationInd )
+        {
+        // Some handling has been moved here from CMmsDecode,
+        // because it is better to have all notification logic in on place.
+
+        // Expiry interval must be changed to absolute time,
+        // otherwise it makes no sense.
+        if ( iMmsHeaders->ExpiryDate() == 0 )
+            {
+            TTime time;
+            // handle expiry in universal time in case user changes location
+            time.UniversalTime();
+            time += TTimeIntervalSeconds( iMmsHeaders->ExpiryInterval() );
+            // we can't use "seconds from" as it only returns a
+            // 32 bit signed integer. If fails in 2038.
+            // "microseconds from" returns a 64 bit signed integer
+            // expiry date in iMmsHeaders in in seconds from 1.1.1970.
+            // interval must be changed back to seconds
+            // This way the result may still be a 64bit integer ->
+            // no overflow in 2038
+            iMmsHeaders->SetExpiryDate(
+                ( time.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() ) / KMmsMillion );
+            }
+
+        // Then we must check if the message type is acceptable.
+        // Rejection based on message type overrides the status
+        // set above. For example, if fetching is deferred, but
+        // we get an advertisement, and we don't accept advertisements
+        // we change the message status from deferred to rejected.
+        
+        switch ( iMmsHeaders->MessageClass() )
+            {
+            case EMmsClassPersonal:
+                if ( iMmsSettings->AcceptPersonalMessages() == EFalse )
+                    {
+                    iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
+                    }
+                break;
+            case EMmsClassAdvertisement:
+                if ( iMmsSettings->AcceptAdvertisementMessages() == EFalse ) 
+                    {
+                    iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
+                    }
+                break;
+            case EMmsClassInformational:
+                if ( iMmsSettings->AcceptInformationalMessages() == EFalse )
+                    {
+                    iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
+                    }
+                break;
+            case EMmsClassAuto:
+                // We accept automatic messages. The only automatic message we
+                // know about is a text mode read report.
+                // As we now handle read reports, we must accept automatic messages
+                // in case some server has converted a read report into a text message
+                // (possible if the server does not recognize the phone and know its
+                // capabilities).
+                break;
+            default:
+                // if we cannot determine the message type,
+                // we reject it.
+                // Message class header is mandatory in notification
+                //iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
+                break;
+            }
+        // check if we accept anonymous messages
+        if ( iMmsSettings->AcceptAnonymousMessages() == EFalse &&
+            iMmsHeaders->Sender().Length() == 0 )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- Anonymous message rejected") );
+#endif
+            iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
+            }
+            
+        // If the encapsulation version is 1.3, the notification may already
+        // contain the application id header.
+        // If the application has not been registered, we reject the message
+        // (at least until more complex support for the applicatiom message
+        // handling has been implemented)
+        if ( iMmsHeaders->ApplicId().Length() > 0 )
+            {
+            if ( !CMmsBaseOperation::RegisteredL( iMmsHeaders->ApplicId() ) )
+                {
+                iMmsHeaders->SetStatus( KMmsMessageStatusRejected );
+                }
+            }
+
+        // if the extended notification contains the whole message
+        // we must mark it as "retrieved"
+        // If there is an extended message addressed to an application,
+        // it is something that cannot be reasonably handled.
+        // I hope that is an illegal case anyway.
+
+        if ( completeMessage )
+            {
+            iMmsHeaders->SetStatus( 0 ); // not applicable
+            }
+
+        // legality checks:
+        // TID is mandatory
+        if ( iMmsHeaders->Tid().Length() == 0 )
+            {
+            passedChecks = EFalse;
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- invalid TID: length = %d"), iMmsHeaders->Tid().Length() );
+#endif
+            }
+        // message class is mandatory
+        if ( iMmsHeaders->MessageClass() == 0 )
+            {
+            passedChecks = EFalse;
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- message class not defined") );
+#endif
+            }
+
+        // Messages with zero length must be accepted if message size may be
+        // just the size of payload and subject (both may have zero length)
+        // If headers are not included in calculation, zero length is acceptable here.
+
+        // expiry is mandatory - but it cannot be 0 because we just set it.
+        // If expiry is not given, the notification expires NOW
+        
+        // content location is mandatory
+        if ( iMmsHeaders->ContentLocation().Length() == 0 )
+            {
+            passedChecks = EFalse;
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- no content location") );
+#endif
+            }
+        }
+
+    // if we have notification that does not fill our
+    // criteria, we just throw it away. The purpose of this
+    // is to discard possible malignant notifications that
+    // would cause us to contact some unknown server and
+    // do strange damage - or at least cause unncessary
+    // network traffic.
+
+    // If the message is complete, we keep it anyway
+
+    if ( passedChecks == EFalse && !completeMessage )
+        {
+        iError = KErrNone;
+        return;
+        }
+
+    TMsvEntry tEntry;
+    tEntry.iType = KUidMsvMessageEntry;
+    // This may be different for notifications in manual modes
+    // This is ok, as all notifications are stored first to the internal MMS folder
+    tEntry.iMtm = KUidMsgTypeMultimedia;
+
+    // use the iRelatedId to bypass queue.
+    tEntry.iServiceId = KMsvLocalServiceIndexEntryId;
+    tEntry.iRelatedId = iServiceEntryId;
+    tEntry.SetUnread( ETrue );
+    tEntry.SetNew( ETrue );
+    tEntry.SetVisible( EFalse );
+    tEntry.SetComplete( EFalse );
+    tEntry.SetInPreparation( ETrue );
+    tEntry.SetReadOnly( EFalse );
+    tEntry.iSize = iMmsHeaders->Size();
+    
+    //
+    // Setting StoredInMMBox flag correctly
+    //
+    HandleMMBoxFlagL( tEntry );
+
+    // Notifications are always originally children of MMS Folder
+    // We have decoded our headers already.
+    // We know if this is a notification or a delivery report,
+    // and we can decide what to do.
+
+    TMsvId parent = KMsvNullIndexEntryId;
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    TMsvId mmsFolder = FindMMSFolderL();
+    if ( mmsFolder == KMsvNullIndexEntryId )
+        {
+        // If the id for our notification folder is 0, we are really in a mess
+        // and cannot continue
+        iError = KErrNotFound;
+        return;
+        }
+    parent = mmsFolder;
+
+    if ( messageType != KMmsMessageDeliveryInd &&
+         messageType != KMmsMessageReadOrigInd &&
+         messageType != KMmsMessageReadRecInd ) 
+        { 
+        // Check duplicates from parent folder, from Inbox and from mmbox folder 
+        // no mater which receiving mode is on.
+        TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
+        if ( PruneDuplicateNotificationsL( parent, *iMmsHeaders ) ||
+            PruneDuplicateNotificationsL( KMsvGlobalInBoxIndexEntryIdValue, *iMmsHeaders ) ||
+            PruneDuplicateNotificationsL( mmboxFolder, *iMmsHeaders ))
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- duplicate - not stored") );
+#endif
+            iError = KErrNone;
+            return;
+            }
+        }
+
+    // If this is an extended notification that contains the whole message
+    // the entry goes to inbox as a message, not a notification.
+    // The fetching must not be scheduled in this case as we already have the
+    // message.
+    // However, if we are in home network, we must send acknowledge back to MMSC
+    // Besides storing the notification as message entry, we must create another
+    // entry to serve as base for sending the acknowledgement. Therefore we have
+    // marked our status as "KMmsMessageStatusRetrieved"
+
+    // this is the size of the attachment if we have an extended notification
+    TInt attaSize = 0;
+
+    if ( completeMessage )
+        {
+        parent = KMsvGlobalInBoxIndexEntryIdValue;
+        tEntry.iMtm = KUidMsgTypeMultimedia;
+        // indicate complete message
+        iMmsHeaders->SetMessageType( KMmsMessageTypeMRetrieveConf );
+        }
+
+    // If we can't access the parent where the notification is to be stored,
+    // we can do nothing
+    iError = iServerEntry->SetEntry( parent );
+    if ( iError != KErrNone )
+        {
+        return; // cannot continue
+        }
+
+    // Query about disk space. KMmsIndexEntryExtra is extra for TMsvEntry
+    // Make one query, we assume no one takes away the disk space this fast.
+    if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
+        &iFs, iMmsHeaders->Size() + KMmsIndexEntryExtra + iMmsHeaders->Size(), iMessageDrive ) )
+        {
+        // we use standard error code here
+        iError = KErrDiskFull;
+        return; // cannot continue
+        }
+
+    iError = iServerEntry->CreateEntry( tEntry );
+
+    if ( iError == KErrNone )
+        {
+        iError = iServerEntry->SetEntry( tEntry.Id() );
+        iNotification = tEntry.Id();
+        }
+
+    CMsvStore* store = NULL;
+    HBufC* buffer = NULL; // we need this to generate a description for the entry
+    TBool attachmentAdded = EFalse; // to track if the extended notification text has been added to the message store or not.   
+
+    if ( iError == KErrNone )
+        {
+        // if this is a whole message, create an attachment from the text
+        if ( completeMessage && iNotification != KMsvNullIndexEntryId )
+            {
+            tEntry = iServerEntry->Entry(); // save the settings we have so far
+            if ( iMmsHeaders->Subject().Length() > 0 )
+                {
+                tEntry.iDescription.Set( iMmsHeaders->Subject() );
+                }
+            else
+                {
+                // Save text as description if we have no subject
+                TPtrC temp = iMmsHeaders->ExtendedNotification().Left( KMmsMaxDescription );
+                buffer = HBufC::NewL( temp.Length() );
+                // no need to put buffer onto cleanup stack - we don't leave before we are done
+                buffer->Des().Copy( temp );
+                TPtr pDescription = buffer->Des();
+                TMmsGenUtils::ReplaceCRLFAndTrim( pDescription );
+                tEntry.iDescription.Set( pDescription );
+                }
+            iServerEntry->ChangeEntry( tEntry );
+            // If we have not allocated the buffer, it is NULL, and it is safe to delete.
+            delete buffer;
+            buffer = NULL;
+
+            if ( iMmsHeaders->ExtendedNotification().Length() > 0 )
+                {
+                TMsvAttachmentId attachmentId = 0;
+                CMsvMimeHeaders* mimeHeaders = CMsvMimeHeaders::NewL();
+                CleanupStack::PushL( mimeHeaders );
+                TPtrC8 temp;
+                temp.Set( KMmsTextPlain );
+                mimeHeaders->SetContentTypeL( temp.Left( temp.Find( KMmsSlash8 ) ) );
+                mimeHeaders->SetContentSubTypeL( temp.Mid( temp.Find( KMmsSlash8 ) + 1 ) );
+                mimeHeaders->SetMimeCharset( KMmsUtf8 ); // text saved as utf-8
+                _LIT( KRelated, "att1.txt");
+                mimeHeaders->SetSuggestedFilenameL( KRelated );
+                // attaData must point to the text
+                // buffer long enough for conversion
+                const TInt KMmsConversionMultiplier = 5;
+                HBufC8* dataContent = HBufC8::NewL(
+                    iMmsHeaders->ExtendedNotification().Length() * KMmsConversionMultiplier );
+                CleanupStack::PushL( dataContent );
+                TPtr8 attaData = dataContent->Des();
+                CnvUtfConverter::ConvertFromUnicodeToUtf8(
+                    attaData, iMmsHeaders->ExtendedNotification() );
+                // set parent
+                iError = iEntryWrapper->SetCurrentEntry( iNotification );
+                
+                if ( iError == KErrNone )
+                    {
+                    store = iEntryWrapper->EditStoreL();
+                    CleanupStack::PushL( store );
+                    TInt32 drmFlags = 0; //ignored
+                    iError = iEntryWrapper->CreateFileAttachmentL(
+                        *store,
+                        KRelated,
+                        attaData,
+                        *mimeHeaders,
+                        attachmentId,
+                        attaSize,
+                        drmFlags);
+			        //If attachment is added to Message store successfully then attachmentAdded is set
+			        if ( iError == KErrNone )
+			            {
+                        attachmentAdded = ETrue;
+			            }    
+                    store->CommitL();
+                    CleanupStack::PopAndDestroy( store );
+                    store = NULL;
+                    }
+                iMmsHeaders->SetExtendedNotificationL( TPtrC() );
+                
+                CleanupStack::PopAndDestroy( dataContent );
+                CleanupStack::PopAndDestroy( mimeHeaders );
+                }
+            }
+        if ( iServerEntry->SetEntry( iNotification ) == KErrNone &&
+            iNotification != KMsvNullIndexEntryId )
+            {
+            store = iServerEntry->EditStoreL();
+            CleanupStack::PushL(store);
+            iMmsHeaders->StoreL(*store);
+            store->CommitL();
+            CleanupStack::PopAndDestroy( store );
+            store = NULL;
+            }
+        }
+
+
+    if ( ( iError == KErrNone || iMmsHeaders->MessageType() != 0 )
+        && iNotification != KMsvNullIndexEntryId )
+        {
+        iError = iServerEntry->SetEntry( iNotification );
+        if ( iError != KErrNone )
+            {
+            // If we have an error here, there is something
+            // seriously wrong with the system
+            if ( iServerEntry->SetEntry( parent ) == KErrNone )
+                {
+                iServerEntry->DeleteEntry( iNotification );
+                }
+            iNotification = KMsvNullIndexEntryId;
+            iServerEntry->SetEntry( KMsvNullIndexEntryId );
+            return; // cannot continue
+            }
+        }
+    else
+        {
+        if ( iServerEntry->SetEntry( parent ) == KErrNone &&
+            iNotification != KMsvNullIndexEntryId )
+            {
+            // We managed to create an entry, but not to decode
+            // the buffer contents into the entry
+            iServerEntry->DeleteEntry( iNotification );
+            }
+        iNotification = KMsvNullIndexEntryId;
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        return;
+        }
+
+    // finish the details, and the notification entry is ready to be used
+    tEntry = iServerEntry->Entry();
+    
+    if ( messageType == KMmsMessageMNotificationInd )
+        {
+        // If the sender is a phone number, add alias.
+        // We don't add alias for email addresses here, as the contact
+        // database search for email addresses is very slow
+        // if there are lots of contacts.
+        buffer = HBufC::NewL( KMmsMaxDescription );
+        CleanupStack::PushL( buffer );
+        
+        TPtr pBuffer = buffer->Des();
+
+        if ( TMmsGenUtils::GenerateDetails( iMmsHeaders->Sender(),
+            pBuffer, KMmsMaxDescription, iFs ) == KErrNone )
+            {
+            tEntry.iDetails.Set( pBuffer );
+            }
+        else
+            {
+            // We come here only if there was an fatal error in GenerateDetails.
+            // Even if we don't find the alias, we have something in the string
+            tEntry.iDetails.Set( iMmsHeaders->Sender() );
+            }
+
+        // set subject if available
+        if ( iMmsHeaders->Subject().Length() > 0 )
+            {
+            tEntry.iDescription.Set( iMmsHeaders->Subject() );
+            }
+        CleanupStack::Pop( buffer );
+
+        }
+    else if ( messageType == KMmsMessageDeliveryInd &&
+        iMmsHeaders->ToRecipients().MdcaCount() > 0 )
+        {
+        tEntry.iDetails.Set( iMmsHeaders->ToRecipients().MdcaPoint( 0 ) );
+        }
+    else
+        {
+        // keep LINT happy
+        }
+
+    tEntry.iMtmData1 &= ~KMmsMessageTypeMask;
+    tEntry.iMtmData1 |= messageType;
+    if ( iMmsHeaders->MessageClass() == EMmsClassAdvertisement )
+        {
+        tEntry.iMtmData1 |= KMmsMessageAdvertisement;
+        }
+    else if ( iMmsHeaders->MessageClass() == EMmsClassInformational )
+        {
+        tEntry.iMtmData1 |= KMmsMessageInformational;
+        }
+    else
+        {
+        // keep LINT happy
+        }
+        
+    switch ( iMmsHeaders->MessagePriority() )
+        {
+        case KMmsPriorityNormal:
+            tEntry.SetPriority( EMsvMediumPriority );
+            break;
+        case KMmsPriorityLow:
+            tEntry.SetPriority( EMsvLowPriority );
+            break;
+        case KMmsPriorityHigh:
+            tEntry.SetPriority( EMsvHighPriority );
+            break;
+        default:            
+            // if not defined default is normal
+            tEntry.SetPriority( EMsvMediumPriority );
+            break;
+        }
+        
+    tEntry.SetVisible( ETrue );
+    tEntry.SetComplete( ETrue );
+    tEntry.SetInPreparation( EFalse );
+    tEntry.SetReadOnly( EFalse );
+    tEntry.iDate.UniversalTime(); // This is arrival time
+    tEntry.iSize = iMmsHeaders->Size() + attaSize; // add attachment data + mime headers
+
+    // Set values to correspond to a new message if this was an extended notification
+    // containing full text.
+
+    if ( completeMessage )
+        {
+        tEntry.iMtmData1 &= ~KMmsMessageTypeMask;
+        // We override message type.
+        tEntry.iMtmData1 |= KMmsMessageMRetrieveConf | KMmsMessageMobileTerminated;
+        tEntry.SetReadOnly( ETrue );
+        tEntry.SetSendingState( KMsvSendStateSent );
+        tEntry.iServiceId = iServiceEntryId;
+        if ( attachmentAdded )
+            {
+        	tEntry.SetAttachment(ETrue);
+            }
+        }
+
+    // we mark delivery reports as already sent so that
+    // we get rid of them at next garbage collection, if the phone
+    // boots or crashes before they are handled.
+    // Delivery reports are lost if phone crashes.
+    if ( messageType == KMmsMessageDeliveryInd ||
+         messageType == KMmsMessageReadOrigInd )
+        {
+        tEntry.SetSendingState( KMsvSendStateSent );
+        }
+
+    iServerEntry->ChangeEntry( tEntry ); // ignore any error
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    delete buffer;
+    buffer = NULL;
+
+    // If the message was complete, we have put our notification to inbox, and it is ready to be used.
+    // However, we still need an entry for sending back an acknowledgement to the server.
+    // We must create a new new notification entry for that purpose.
+
+    if ( completeMessage )
+        {
+        // don't schedule the entry that went into inbox
+        iNotification = KMsvNullIndexEntryId;
+        TInt error = KErrNone;
+        tEntry.iType = KUidMsvMessageEntry; // This will never go to inbox
+        tEntry.iMtm = KUidMsgTypeMultimedia;
+        tEntry.iServiceId = iServiceEntryId;
+        tEntry.iRelatedId = iServiceEntryId;
+        tEntry.SetUnread( ETrue );
+        tEntry.SetNew( ETrue );
+        tEntry.SetVisible( EFalse );
+        tEntry.SetComplete( EFalse );
+        tEntry.SetInPreparation( ETrue );
+        tEntry.SetReadOnly( EFalse );
+        tEntry.iSize = iMmsHeaders->Size();
+        tEntry.SetSendingState( KMsvSendStateUnknown );
+        tEntry.iDescription.Set( iMmsHeaders->Subject() );
+        tEntry.iMtmData1 &= ~KMmsMessageTypeMask;
+        tEntry.iMtmData1 |= KMmsMessageMNotificationInd;
+        // even if sending ack fails, this must not be moved to inbox
+        // because the corresponding message already is there.
+        tEntry.iMtmData2 |= KMmsDoNotMoveToInbox; 
+        parent = mmsFolder;
+        error = iServerEntry->SetEntry( parent );
+        if ( error == KErrNone )
+            {
+            error = iServerEntry->CreateEntry( tEntry );
+            }
+        if ( error == KErrNone )
+            {
+            iError = iServerEntry->SetEntry( tEntry.Id() );
+            if ( iError == KErrNone )
+                {
+                // Now we have a new entry that will be scheduled for sending the acknowledgement
+                iNotification = tEntry.Id();
+                iMmsHeaders->SetStatus( KMmsMessageStatusRetrieved );
+                iMmsHeaders->SetMessageType( KMmsMessageTypeMNotificationInd );
+                store = iServerEntry->EditStoreL();
+                CleanupStack::PushL( store );
+                iMmsHeaders->StoreL( *store );
+                store->CommitL();
+                CleanupStack::PopAndDestroy( store );
+                store = NULL;
+                tEntry.SetVisible( ETrue );
+                tEntry.SetComplete( ETrue );
+                tEntry.SetInPreparation( EFalse );
+                iServerEntry->ChangeEntry( tEntry ); // ignore any error
+                }
+            }
+        }
+
+#ifndef _NO_MMSS_LOGGING_
+    // log a little bit of something
+    if ( messageType == KMmsMessageDeliveryInd )
+        {
+        TMmsLogger::Log( _L("- delivery report received") );
+        }
+    else if ( messageType == KMmsMessageMNotificationInd )
+        {
+        TMmsLogger::Log( _L("- notification received") );
+        }
+    else
+        {
+        TMmsLogger::Log( _L("- pushed message of type %d received"), messageType );
+        }
+#endif
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::HandleNotificationL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleNotificationL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MmsServer HandleNotification, %d items"), iMsvSelection->Count() );
+#endif
+    if ( iMsvSelection->Count() < 1 )
+        {
+        // nothing to do, give up
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, iError );
+        return;
+        }
+
+    // If both receiving modes in home and foreign network are "reject".
+    // The notification is deleted.
+    if( iMmsSettings->ReceivingModeHome() == EMmsReceivingReject &&
+        iMmsSettings->ReceivingModeForeign() == EMmsReceivingReject )
+        {
+        // we play possum and delete the notification without
+        // sending any response to MMSC.
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- playing possum, deleting notifications") );
+#endif
+        TInt count = iMsvSelection->Count();
+        TMsvEntry entry;
+        TMsvId parent = KMsvNullIndexEntryId;
+        if ( iServerEntry->SetEntry( iMsvSelection->At( count - 1 ) ) == KErrNone ) 
+            {
+            entry = iServerEntry->Entry();
+            parent = entry.Parent();
+            }
+        while ( count-- && parent != KMsvNullIndexEntryId )
+            {
+            if ( iServerEntry->SetEntry( iMsvSelection->At( count ) ) == KErrNone )
+                {
+                entry = iServerEntry->Entry();
+                parent = entry.Parent();
+                }
+            
+            if ( iServerEntry->SetEntry( parent ) == KErrNone )
+                {
+                iServerEntry->DeleteEntry( iMsvSelection->At( count ) );
+                }
+            }
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, iError );
+        return;
+        }
+        
+    // When the notificatio arrived, it was checked, and if it was
+    // a duplicate of an earlier one, it was not saved on disk.
+
+    iCommand = EMmsReceive;
+           
+    // ScheduleL completes our caller
+    // we want to get back to out RunL to check the error
+    // Query about disk space.
+    // Subroutine knows how much must be checked for task scheduler
+    TInt error = KErrNone;
+    if ( DiskSpaceBelowCriticalForSchedulingL( &iFs, 0, iMessageDrive ) )
+        {
+		// we use standard error code here
+		#ifndef _NO_MMSS_LOGGING_
+		TMmsLogger::Log( _L("HandleNotificationL.. Disk Full") );
+		#endif
+		error = KErrDiskFull;
+		TInt count = iMsvSelection->Count();
+		TMsvEntry entry;
+		if ( iServerEntry->SetEntry( iMsvSelection->At( count - 1 ) ) == KErrNone ) 
+		    {
+			entry = iServerEntry->Entry();
+			entry.iError = error;
+			iServerEntry->ChangeEntry( entry );
+			#ifndef _NO_MMSS_LOGGING_
+			TMmsLogger::Log( _L("HandleNotificationL.. Setting ierror to Entry") );
+			#endif
+		    }
+        
+        }
+    else
+        {
+        // We must set the caller's status to KRequest Pending because
+        // CScheduleBaseServerMtm::ScheduleL does not do it.
+        *iRequestStatus = KRequestPending;
+        TRAP( error, ScheduleL( *iMsvSelection, EFalse, KNullDesC8, *iRequestStatus ) );
+        // ScheduleL would complete our caller, but if it leaves,
+        // we must complete. We don't want to leave...
+        }
+    if ( error != KErrNone )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("MmsServer HandleNotification status %d"), error );
+#endif
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, error );
+        }
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::HandleDeliveryReportL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleDeliveryReportL()
+    {
+
+    if ( iMsvSelection->Count() < 1 )
+        {
+        // nothing to do, give up
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, iError );
+        return;
+        }
+    
+    iCommand = EMmsLogDeliveryReport;
+           
+    // Query about disk space.
+    // Subroutine knows how much must be checked for task scheduler
+    TInt error = KErrNone;
+    if ( DiskSpaceBelowCriticalForSchedulingL( &iFs, 0, iMessageDrive ) )
+        {
+        // we use standard error code here
+        error = KErrDiskFull;
+        }
+    else
+        {
+        // ScheduleL completes our caller
+        // We must set the caller's status to KRequest Pending because
+        // CScheduleBaseServerMtm::ScheduleL does not do it.
+        *iRequestStatus = KRequestPending;
+        TRAP( error, ScheduleL( *iMsvSelection, EFalse, KNullDesC8, *iRequestStatus ) );
+        // ScheduleL would complete our caller, but if it leaves,
+        // we must complete. We don't want to leave...
+        }
+    if ( error != KErrNone )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("MmsServer HandleDeliveryReport status %d"), error );
+#endif
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, error );
+        }
+    }
+
+
+// ---------------------------------------------------------
+// CMmsServerMtm::LogDeliveryReportL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::LogDeliveryReportL()
+    {
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MmsServer Logging delivery report") );
+#endif
+    // this subroutine does not do critical disk space level check
+    // normally we just update an existing entry changing only status
+    // which does not change disk space usage.
+    // Only if our previous entry has been deleted, we add something.
+    // We don't check that. The amount of disk space needed should
+    // be less than 100 bytes anyway. Large messages are more critical
+    // than small log entries.
+
+    if ( iMsvSelection->Count() < 1 )
+        {
+        // nothing to do, give up
+        // we complete our caller
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, iError );
+        return;
+        }
+    
+    iCommand = EMmsLogDeliveryReport;
+    TRequestStatus* status = &iStatus;
+    TBool readReport = EFalse; // first guess - delivery report
+
+    iError = iServerEntry->SetEntry( iMsvSelection->At( 0 ) );
+    if ( iError == KErrNotFound )
+        {
+        // The entry we are supposed to handle has disappeared.
+        // We complete the active object.
+        // RunL will call UpdateEntriesL, and that function
+        // will delete the entry from the list, and try the next
+        // one, if it exists.
+        // We must set the error to "none" to delete the entry
+        // instead of retrying.
+        iError = KErrNone;
+        // get back to our own RunL, it will complete caller
+        *iRequestStatus = KRequestPending;
+        iStatus = KRequestPending;
+        SetActive();
+        User::RequestComplete( status, iError );
+        return;
+        }
+
+    TMsvEntry entry;
+    if ( iError == KErrNone )
+        {
+        entry = iServerEntry->Entry();
+        }
+    else
+        {
+        // cannot access entry.
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("MmsServer could not access delivery report") );
+#endif
+        // Retry later.
+        // now our error is not KErrNone, so we will reschedule
+        // in UpdateEntriesL
+        *iRequestStatus = KRequestPending;
+        iStatus = KRequestPending;
+        SetActive();
+        User::RequestComplete( status, iError );
+        }
+        
+    if ( ( entry.iMtmData1 & KMmsMessageTypeMask ) == KMmsMessageReadOrigInd )
+        {
+        // The remote party is in "From" field because that's the recipient
+        // that is sending the read report
+        readReport = ETrue;
+        }
+    else if ( ( entry.iMtmData1 & KMmsMessageTypeMask ) != KMmsMessageDeliveryInd )
+        {
+        iError = KErrNone;
+        // get back to our own RunL
+        *iRequestStatus = KRequestPending;
+        iStatus = KRequestPending;
+        SetActive();
+        User::RequestComplete( status, iError );
+        return;
+        }
+    
+    if ( !iMmsLog )
+        {
+        iLogClient = CLogClient::NewL( iFs );
+        iLogViewEvent = CLogViewEvent::NewL( *iLogClient );
+        iMmsLog = CMmsLog::NewL( *iLogClient, *iLogViewEvent, iFs );
+        }
+
+    if ( !iLogEvent )
+        {
+        iLogEvent = CLogEvent::NewL();
+        }
+
+    if ( !iRemoteParties )
+        {
+        // We only handle one delivery report at a time
+        iRemoteParties = new ( ELeave )CDesCArrayFlat( 1 );
+        }
+    else
+        {
+        iRemoteParties->Reset();
+        }
+
+    // save the items that are the same for all our events
+    iLogEvent->SetEventType( KLogMmsEventTypeUid );
+    iLogClient->GetString( iLogString, R_LOG_DIR_OUT );
+    iLogEvent->SetDirection( iLogString );
+    iLogEvent->SetDurationType( KLogDurationNone );
+    // This should never stay
+    iLogClient->GetString( iLogString, R_LOG_DEL_SENT );
+    iLogEvent->SetStatus( iLogString );
+
+    CMsvStore* store = NULL;
+
+    TRAP( iError, store = iServerEntry->ReadStoreL(); )
+
+    if ( iError == KErrNone )
+        {
+        CleanupStack::PushL( store );
+        iMmsHeaders->RestoreL( *store );
+        CleanupStack::PopAndDestroy( store );
+        iLogEvent->SetDataL( iMmsHeaders->MessageId() );
+        // Use delivery time from delivery report
+        iLogEvent->SetTime( TTime( KMmsYear1970String ) +
+            TTimeIntervalMicroSeconds( iMmsHeaders->Date() * KMmsMillion ) );
+        
+        switch ( iMmsHeaders->Status() )
+            {
+            case KMmsMessageStatusRetrieved:
+            case KMmsMessageStatusForwarded: // forwarded is delivered from our point of view
+                iDeliveryStatus = ETrue;
+                iLogClient->GetString( iLogString, R_LOG_DEL_DONE );
+                break;
+            case KMmsMessageStatusExpired:
+            case KMmsMessageStatusRejected:
+            case KMmsMessageStatusUnreachable:
+                iDeliveryStatus = EFalse;
+                iLogClient->GetString( iLogString, R_LOG_DEL_FAILED );
+                break;
+            default:
+                if ( !readReport )
+                    {
+                    // if status cannot be mapped, it is just "pending"
+                    // KMmsMessageStatusDeferred, KMmsMessageStatusUnrecognized, and KMmsMessageStatusIndeterminate
+                    // map to "pending" state
+                    iLogClient->GetString( iLogString, R_LOG_DEL_PENDING );
+                    }
+                else
+                    {
+                    // read report can only have status "read" or 
+                    // "deleted without being read"
+                    // We need some string mapping for those...
+                    if ( iMmsHeaders->ReadStatus() == KMmsReadStatusRead )
+                        {
+                        // read
+                         iLogString.Copy( KLogsMsgReadText );
+                        }
+                    else
+                        {
+                        // deleted without being read
+                        // This does not change "delivered" status
+                        // But in case the delivery report has not arrived,
+                        // This ensures that the information of delivery gets stored.
+                        // If the user deleted the message without reading it,
+                        // it must have been delivered first.
+                        iLogClient->GetString( iLogString, R_LOG_DEL_DONE );
+                        }
+                    }
+                break;
+            }
+            
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("MmsServer delivery status code %d"), iMmsHeaders->Status() );
+        TMmsLogger::Log( _L(" - delivery status %S"), &iLogString );
+        TMmsLogger::Log( _L(" - delivery datetime:") );
+        CMmsBaseOperation::LogDateL( iLogEvent->Time() );
+#endif
+        iLogEvent->SetStatus( iLogString );
+        if ( iMmsHeaders->ToRecipients().MdcaCount() == 0 &&
+            iMmsHeaders->Sender().Length() == 0 )
+            {
+            // No recipient, cannot log
+            // no use retrying either
+            *iRequestStatus = KRequestPending;
+            iStatus = KRequestPending;
+            SetActive();
+            User::RequestComplete( status, KErrNone );
+            return;
+            }
+        if ( !readReport )
+            {
+            iRemoteParties->AppendL( TMmsGenUtils::PureAddress(
+                iMmsHeaders->ToRecipients().MdcaPoint( 0 ) ) );
+            }
+        else
+            {
+            // If we have a read report, the remote party is the sender
+            iRemoteParties->AppendL( TMmsGenUtils::PureAddress(
+                iMmsHeaders->Sender() ) );
+            }
+
+// CMmsLog is responsible for setting our status to "KRequestPending"
+// If the status or the entry is already "read" it must not be changed
+// back to "delivered"
+// CMmsLog must take care of that because it is the component that
+// finds the corresponding entry from the log database
+        iMmsLog->StartL( *iLogEvent, *iRemoteParties, iStatus);
+        *iRequestStatus = KRequestPending;
+        SetActive();
+        }
+    else
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("MmsServer could not access delivery report") );
+#endif
+        // Retry later.
+        // now our error is not KErrNone, so we will reschedule
+        // in UpdateEntriesL
+        *iRequestStatus = KRequestPending;
+        iStatus = KRequestPending;
+        SetActive();
+        User::RequestComplete( status, iError );
+        }
+
+    }
+    
+// ---------------------------------------------------------
+// CMmsServerMtm::PruneDuplicateNotificationsL
+// 
+// ---------------------------------------------------------
+//
+TBool CMmsServerMtm::PruneDuplicateNotificationsL( TMsvId aParent, CMmsHeaders& aNotification )
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MmsServer Pruning duplicate notifications") );
+#endif
+    TInt error = KErrNone;
+    TBool pruned = EFalse;
+    TMsvId mmsFolder = FindMMSFolderL();
+    
+    if ( aParent == KMsvNullIndexEntryId )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- no proper parent") );
+#endif
+        return EFalse;
+        }
+
+    error = iServerEntry->SetEntry( aParent );
+    if ( error != KErrNone )
+        {
+        // cannot access parent, cannot prune.
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- cannot access notification parent, error %d "), error );
+#endif
+        return EFalse;
+        }
+
+    // show invisible entries
+    TMsvSelectionOrdering ordering =
+        TMsvSelectionOrdering( KMsvNoGrouping, EMsvSortByNone, ETrue );
+    iServerEntry->SetSort( ordering );
+
+    CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection; 
+    CleanupStack::PushL( selection );
+    if ( aParent == mmsFolder )
+        {
+        error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *selection );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- from MMS Folder") );
+#endif
+        }
+    else
+        {
+        error = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
+#ifndef _NO_MMSS_LOGGING_
+        if ( aParent == KMsvGlobalInBoxIndexEntryIdValue )
+            {
+            TMmsLogger::Log( _L("- from Inbox") );
+            }
+        else
+            {
+            TMmsLogger::Log( _L("- from mmbox folder") );
+            }
+#endif
+        }
+
+    TInt count = selection->Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- %d notifications on disk"), count );
+#endif
+    if ( error != KErrNone || count == 0 )
+        {
+        // cannot check or no old notifications found, anything goes
+        CleanupStack::PopAndDestroy( selection ); // selection
+        return EFalse;
+        }
+
+    TInt i;
+    CMmsHeaders* notification = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    CleanupStack::PushL( notification );
+    CMsvStore* store = NULL;
+    for ( i = count; i > 0 && !pruned; i-- )
+        {
+        error = iServerEntry->SetEntry( selection->At( i - 1 ) );
+        if ( error != KErrNone )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- cannot access notification") );
+#endif
+            // cannot handle this entry.
+            continue;
+            }
+        if ( ( ( iServerEntry->Entry().iMtmData1 != 0 ) &&
+            ( ( iServerEntry->Entry().iMtmData1 & KMmsMessageTypeMask ) !=
+            KMmsMessageMNotificationInd ) ) ||
+            ( iServerEntry->Entry().iMtmData2 & KMmsNotificationBinary ) ) 
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- not a notification") );
+#endif
+            continue;
+            }
+
+        // binary notifications (empty entries) were already handled, so we can delete the rest
+        if ( iServerEntry->Entry().iMtmData1 == 0 )
+            {
+            // remove garbage.
+            error = iServerEntry->SetEntry( aParent );
+            if ( error == KErrNone )
+                {
+                // never mind the error - we are just doing our best
+                iServerEntry->DeleteEntry( selection->At( i - 1 ) );
+                }
+            continue;
+            }
+
+        error = KErrNone;
+        TRAP( error, 
+            {
+            store = iServerEntry->ReadStoreL();
+            CleanupStack::PushL( store );
+            notification->RestoreL( *store );
+            CleanupStack::PopAndDestroy( store ); // store
+            })
+        store = NULL;
+
+        if ( error != KErrNone )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- cannot access notification") );
+#endif
+            // cannot handle this entry.
+            continue;
+            }
+
+        // content location is used to identify notifications
+        // referring to the same message.
+        // Content location is the only information given back to
+        // MMSC when fetching a message, therefore it must be unique
+        if ( notification->ContentLocation().Compare( aNotification.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
+            pruned = ETrue;
+            }
+        }
+
+    CleanupStack::PopAndDestroy( notification );
+    CleanupStack::PopAndDestroy( selection );
+    error = iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    return pruned;
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CheckNotificationsL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CheckNotificationsL( CMsvEntrySelection& aSelection )
+    {
+    TInt error = KErrNone;
+    TMsvId parent = KMsvNullIndexEntryId;
+    TMsvId mmsFolder = FindMMSFolderL();
+    if ( mmsFolder == KMsvNullIndexEntryId )
+        {
+        // no folder...
+        return;
+        }
+    
+    TInt i;
+    
+    // Don't mix notifications from mms folder and inbox,
+    // in debug mode Symbian scheduler panics.
+    if ( aSelection.Count() > 0 )
+        {
+        i = aSelection.Count() - 1;
+        while ( i >= 0 && parent == KMsvNullIndexEntryId )
+            {
+            error = iServerEntry->SetEntry( aSelection.At( 0 ) );
+            if ( error == KErrNone )
+                {
+                parent = iServerEntry->Entry().Parent();
+                }
+            else if ( error == KErrNotFound )
+                {
+                // The entry has disappeared already.
+                aSelection.Delete( i );
+                }
+            else
+                {
+                // keep LINT happy
+                }
+            i--;    
+            }
+        }
+    
+    if ( parent == KMsvNullIndexEntryId ) 
+        {
+        parent = mmsFolder;
+        }
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CheckNotificationsL, got %d entries"), aSelection.Count() );
+#endif
+
+    error = iServerEntry->SetEntry( parent );
+    User::LeaveIfError( error );
+    
+    // If no notifications input find notifications from mms folder
+    if ( parent == mmsFolder && aSelection.Count() == 0 )
+        {
+        error = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, aSelection );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("Notifications found in mms folder %d "), aSelection.Count() );
+#endif
+        if ( error != KErrNone )
+            {
+            aSelection.Reset(); // make sure we return no garbage
+            User::Leave( error );
+            }
+        }
+    
+    // notifications in inbox
+    // If we have a selection, we don't generate new ones,
+    // An empty selection only lists notifications from MMS folder, we cannot
+    // touch inbox stuff otherwise.
+    // MMS Client MTM lists notifications from inbox when mode is changed
+    // from manual to automatic.
+    
+    if ( parent == KMsvGlobalInBoxIndexEntryId )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("Notifications found in inbox %d "), aSelection.Count() );
+#endif
+        TInt j;
+        for ( j = aSelection.Count() - 1; j >= 0; j-- )
+            {
+            error = iServerEntry->SetEntry( aSelection.At( j ) );
+            TMsvEntry entry;
+            if ( error == KErrNone )
+                {
+                entry = iServerEntry->Entry();
+                }
+
+            // Drop notification, if operationForbidden flag is on OR
+            // if messageexpired flag is on OR
+            // if notification is not stored in mmbox and forward operation has been succussfull OR
+            // if notification is deleted succuessfully from mmbox OR 
+            // if notification is fetched successfully from mmbox.
+            // Or if notification cannot be accessed (used by someone else)
+            if ( error != KErrNone ||
+                entry.iMtmData2 & KMmsNewOperationForbidden ||
+                entry.iMtmData2 & KMmsMessageExpired ||
+                ( entry.iMtmData2 & KMmsOperationFinished &&
+                !( entry.iMtmData2 & KMmsOperationResult) &&
+                !(entry.iMtmData2 & KMmsStoredInMMBox) ) )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L(" Dropped " ));
+                aSelection.Delete( j );
+#endif
+                }
+            else
+                {
+                // mark this that others can't start do an operation
+                entry.iMtmData2 |= KMmsNewOperationForbidden; 
+            
+                // readonly is needed to set EFalse for scheduling
+                entry.SetReadOnly( EFalse ); 
+                iServerEntry->ChangeEntry( entry );
+                // We keep this entry in our selection
+                }
+            }
+        aSelection.Compress();
+        }
+        
+    error = iServerEntry->SetEntry( parent );
+
+    // Check the list and see what we got.
+    // The list may contain both notifications and delivery reports
+    
+    TInt count = aSelection.Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("Found %d entries altogether"), count );
+#endif
+    TMsvEntry tEntry;
+    CMsvEntrySelection* thisNotification = NULL;
+    TTime now;
+    TTime entryTime;
+    
+    for ( i = count; i > 0; i-- )
+        {
+        error = iServerEntry->SetEntry( aSelection.At( i - 1 ) );
+        if ( error == KErrNoMemory )
+            {
+            User::Leave( error );
+            }
+        else if ( error != KErrNone )
+            {
+            continue;
+            }
+        else
+            {
+            // keep LINT happy
+            }
+        tEntry = iServerEntry->Entry();
+        parent = tEntry.Parent();
+        // We keep only notifications - the rest are removed from the list.
+        // If we are doing garbage collection, all non-notifications are
+        // deleted from the disk (because they will never expire).
+        // See if a notification or dummy entry
+        if ( iServerEntry->Entry().iMtmData2 & KMmsNotificationBinary &&
+            iCurrentCommand == EMmsGarbageCollection )
+            {
+            // get rid of these as these are empty
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- dummy entry - deleting"));
+#endif
+            error = iServerEntry->SetEntry( parent );
+            if ( error == KErrNone )
+                {
+                iServerEntry->DeleteEntry( aSelection.At( i - 1 ) );
+                }
+            aSelection.Delete( i - 1 );
+            }
+        else if ( ( tEntry.iMtmData1 & KMmsMessageTypeMask ) != KMmsMessageMNotificationInd )
+            {
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- not a notification"));
+#endif
+            if ( iCurrentCommand == EMmsGarbageCollection )
+                {
+                // If we are doing garbage collection, these are deleted, too
+                // If any delivery reports or other non-notification stuff
+                // is around at garbage collection time, it has become garbage.
+                
+                // Garbage collection is called with MMS Service, not with
+                // local service, so it means that garbage collection cannot
+                // be called when some other operation is ongoing.
+                // It should not be possible to delete an entry that is being
+                // handled already because access to MMS Server MTM is sequential
+                
+                // However, a delivery report or read report might just have been
+                // scheduled for handling. Check that they won't get deleted too soon
+                
+                thisNotification = new( ELeave ) CMsvEntrySelection;
+                CleanupStack::PushL( thisNotification );
+                thisNotification->AppendL( aSelection.At( i - 1 ) );
+                iScheduleSend->CheckScheduleL( *thisNotification );
+                CleanupStack::PopAndDestroy( thisNotification );
+                thisNotification = NULL;
+
+                TBool alreadyScheduled = EFalse;
+                
+                if ( iServerEntry->Entry().Scheduled() )
+                    {
+                    // Already scheduled - check, if schedule is valid
+                    // Leave the schedule, if it is in the future - but not too much
+                    now.UniversalTime();
+                    now += TTimeIntervalSeconds( KMmsScheduleDelay );
+                    entryTime = iServerEntry->Entry().iDate;
+                    if ( ( ( entryTime - TTimeIntervalHours( KMmsSanityInterval ) ) <= now ) &&
+                        ( entryTime > now ) )
+                        {
+                        // scheduled in the future, we don't touch it
+                        alreadyScheduled = ETrue;
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- already scheduled"));
+#endif
+                        }
+                    }
+                
+                error = iServerEntry->SetEntry( parent );
+                if ( error == KErrNone && !alreadyScheduled )
+                    {
+                    // we delete extra entries - but if they seem to have
+                    // legal schedule we leave them, the scheduling will
+                    // handle them in due time
+                    iServerEntry->DeleteEntry( aSelection.At( i - 1 ) );
+                    }
+                }
+            // We always clear the non-notifications from our list
+            // Either they were already legally scheduled and were left alone
+            // or they were gagbage and were deleted
+            aSelection.Delete( i - 1 );
+            }
+        else
+            {
+            // Check if scheduled
+
+            thisNotification = new( ELeave ) CMsvEntrySelection;
+            CleanupStack::PushL( thisNotification );
+            thisNotification->AppendL( aSelection.At( i - 1 ) );
+            if ( iCommand != EMmsReceiveForced )
+                {
+                iScheduleSend->CheckScheduleL( *thisNotification );
+                }
+            else
+                // if we do forced fetch, we clean up old schedules first
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- cleaning schedules"));
+#endif
+                CleanSchedulesL( *thisNotification );
+                tEntry = iServerEntry->Entry();
+                }
+
+            if ( iServerEntry->Entry().Scheduled() )
+                {
+                // Already scheduled - check, if schedule is valid
+                // Reschedule this, if it was scheduled in the past
+                // The entry is left into the selection list.
+                // If the list is rescheduled, this entry will
+                // be rescheduled to a later time.
+                // Leave the schedule, if it is in the future - but not too much
+                now.UniversalTime();
+                now += TTimeIntervalSeconds( KMmsScheduleDelay );
+                entryTime = iServerEntry->Entry().iDate;
+                if ( ( ( entryTime - TTimeIntervalHours( KMmsSanityInterval ) ) <= now ) &&
+                                ( entryTime > now ) )
+                    {
+                    // scheduled in the future, we don't touch it
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- already scheduled"));
+#endif
+                    aSelection.Delete( i - 1 );
+                    }
+                }
+            else
+                {
+                // Check expiration
+                CMsvStore * store = NULL;
+                store = iServerEntry->ReadStoreL();
+                CleanupStack::PushL( store );
+                iMmsHeaders->RestoreL( *store );
+                CleanupStack::PopAndDestroy( store );
+                TTime now;
+                now.UniversalTime();
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("MMSserver checking notifications") );
+                TMmsLogger::Log( _L("MMS terminal universal datetime: ") );
+                CMmsBaseOperation::LogDateL( now );
+                TMmsLogger::Log( _L("MMS message expiry datetime:") );
+                CMmsBaseOperation::LogNetworkFormatDateL( iMmsHeaders->ExpiryDate() );
+#endif
+                if ( ( ( iMmsHeaders->ExpiryDate() + iMmsSettings->ExpiryOvershoot() ) *
+                    KMmsMillion ) < now.MicroSecondsFrom( TTime( KMmsYear1970String ) ).Int64() )
+                    {
+                    // expired
+                    // remove schedule, 
+                    iScheduleSend->DeleteScheduleL( *thisNotification );
+
+                    // if the entry is in inbox or in mmbox folder, let it go                   
+                    if ( parent == KMsvGlobalInBoxIndexEntryIdValue  ||
+                         parent == iMmsSettings->MMBoxFolder() )
+                        {
+                        tEntry.SetReadOnly( ETrue );
+                        // not forbidden for a new operation
+                        tEntry.iMtmData2 &= ~KMmsNewOperationForbidden;
+                        iServerEntry->ChangeEntry( tEntry );
+
+                        }
+                    else // delete the whole entry if it is in mms folder
+                        {
+                        error = iServerEntry->SetEntry( parent );
+                        if ( error == KErrNone )
+                            {
+                            iServerEntry->DeleteEntry( aSelection.At( i - 1 ) );
+#ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L("- whole entry deleted"));
+#endif
+                            }
+                        }
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- already expired"));
+#endif
+                    aSelection.Delete( i - 1 );
+                    }
+                }
+            CleanupStack::PopAndDestroy( thisNotification );
+            thisNotification = NULL;
+            }
+        }
+    aSelection.Compress();
+    
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CheckNotificationsL, %d entries left"), aSelection.Count() );
+#endif
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CreateNotificationsL()
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CreateNotificationsL()
+    {
+    // This function is for testing and message variation
+
+    TInt err = KErrNone;
+    TInt i;
+    TInt count = 0;
+    TUint size = 0;
+    // Include old notifications into the selection
+    // Except when doing message generation at boot time -
+    // Then only new notifications are handled
+    if ( iCurrentCommand != EMmsMessageGeneration )
+        {
+        CheckNotificationsL( *iMsvSelection );
+        }
+    count = iMsvSelection->Count();
+
+    // If there are notifications to be handled, we don't
+    // create new ones, because new notification creation
+    // should be used for testing only
+    if ( !iMmsSettings->LocalMode() && count > 0 )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CreateNotificationsL - Global mode") );
+        TMmsLogger::Log( _L("- %d old notifications, not generating new ones"), count );
+#endif
+        return;
+        }
+        
+    RFs fs; // We need a separate session to be able to set the session path
+    err = fs.Connect();
+    if ( err != KErrNone )
+        {
+        return;
+        }
+    CleanupClosePushL( fs );
+
+    HBufC8* bufferPointer = HBufC8::NewL( KMaxFileName );
+    CleanupStack::PushL( bufferPointer );
+    TPtr8 buffer = bufferPointer->Des();
+
+    CDir* fileList = NULL;
+
+    // create notifications for local messages:
+    if ( iMmsSettings->LocalMode() )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("CreateNotificationsL - Local mode"));
+#endif
+        TEntry* entry = new( ELeave ) TEntry; // allocated from heap to save stack space
+        CleanupStack::PushL( entry );
+        HBufC* filename = HBufC::NewL( iMmsSettings->LocalModeIn().Length() );
+        CleanupStack::PushL( filename );
+        TPtr fileNamePtr = filename->Des();
+        fileNamePtr.Copy( iMmsSettings->LocalModeIn() );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("local mode dir %S "), &fileNamePtr );
+#endif
+        err = fs.SetSessionPath( fileNamePtr );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("set session path returned: %d"), err );
+        HBufC* temp = HBufC::NewL( KMaxPath );
+        CleanupStack::PushL( temp );
+        TPtr tempPtr = temp->Des();
+        fs.SessionPath( tempPtr );
+        TMmsLogger::Log( _L("Session path: %S"), &tempPtr );
+        CleanupStack::PopAndDestroy( temp );
+        temp = NULL;
+#endif
+        err = fs.Entry( fileNamePtr, *entry );
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("get path properties returned: %d"), err );
+#endif
+        if ( err == KErrNone )
+            {
+            TFindFile* finder = new( ELeave ) TFindFile( fs ); // allocated from heap to save stack space
+            CleanupStack::PushL( finder );
+            _LIT( KWild, "*" );
+
+            err = finder->FindWildByPath( KWild, &fileNamePtr, fileList );
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("find files returned: %d"), err );
+#endif
+            CleanupStack::PopAndDestroy( finder );
+            
+            if ( fileList )
+                {
+                CleanupStack::PushL( fileList );
+                }
+
+            if ( err == KErrNone )
+                {
+                count = fileList->Count();
+                }
+            else
+                {
+                count = 0;
+                }
+            }
+
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("found %d files in %S"), count, &fileNamePtr );
+#endif
+        for (i = 0; i < count; i++ )
+            {
+            iParse.Set( ( ( *fileList )[i] ).iName, &fileNamePtr, NULL );
+            buffer.Copy( iParse.FullName() );
+
+            size = fs.Entry( iParse.FullName(), *entry );
+            size = entry->iSize;
+
+            iNotification = KMsvNullIndexEntryId;
+
+#ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("notification size %d"), size );
+#endif
+            if ( size > 0 )
+                {
+                if ( !iEncodeBuffer )
+                    {
+                    iEncodeBuffer = CBufFlat::NewL( 0x400 );
+                    }
+                else
+                    {
+                    iEncodeBuffer->Reset();
+                    }
+
+                CreateNotificationL( buffer, size );
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("notification created") );
+#endif
+
+                DecodePushedMessageL();
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("notification decoded") );
+#endif
+                delete iEncodeBuffer;
+                iEncodeBuffer = NULL;
+                }
+            else
+                {
+                fs.Delete( iParse.FullName() );
+                }
+        
+            if ( iNotification != KMsvNullIndexEntryId )
+                {
+                iMsvSelection->AppendL( iNotification );
+                }
+
+            }
+        if ( fileList )
+            {
+            CleanupStack::PopAndDestroy( fileList );
+            }
+            
+        CleanupStack::PopAndDestroy( filename );
+        CleanupStack::PopAndDestroy( entry );
+        }
+
+    CleanupStack::PopAndDestroy( bufferPointer );
+    CleanupStack::PopAndDestroy( &fs ); // close fs
+    iServerEntry->SetEntry( iServiceEntryId );
+
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CreateNotificationsL - %d notifications"), iMsvSelection->Count() );
+#endif
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CreateNotificationL()
+//
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CreateNotificationL( TDesC8& aUrl, TInt aSize )
+    {
+    // for test purposes aUrl will contain the filename.
+
+    // Reset sets the default encapsulation version
+    // The default version has been set from MmsSettings in NewL
+    iMmsHeaders->Reset();
+
+    // construct the notification into iMmsHeaders, and call encode
+
+    iMmsHeaders->SetMessageType( KMmsMessageTypeMNotificationInd );
+
+    TTime currentTime;
+    currentTime.UniversalTime();
+    currentTime.Int64();
+
+    TBufC8<KMMSMAXTIDLENGTH> tid;
+    tid.Des().NumUC( currentTime.Int64(), EHex );
+    iMmsHeaders->SetTidL( tid );
+
+    iMmsHeaders->SetMessageClass( EMmsClassPersonal );
+    iMmsHeaders->SetMessageSize( aSize );
+    const TInt KTenHours = 10 * 60 * 60; // 10 hours relative expiry
+    iMmsHeaders->SetExpiryInterval( KTenHours );
+    iMmsHeaders->SetContentLocationL( aUrl );
+ 
+    CMmsEncode* encoder = CMmsEncode::NewL( iFs );
+    CleanupStack::PushL( encoder );
+    encoder->EncodeHeadersL( *iMmsHeaders, *iEncodeBuffer );
+    CleanupStack::PopAndDestroy( encoder ); // encoder
+    
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::GarbageCollectionL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GarbageCollectionL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("MMSServer doing garbage collection") );
+#endif
+
+    // are we in offline mode...
+    // We use CMmsSendOperation to allow change in the name of the
+    // base opeation class. The function is in the base class anyway.
+    if ( !CMmsSendOperation::NetworkOperationsAllowed() )
+        {
+        // not allowed to send or receive anything
+        User::Leave( KMmsErrorOfflineMode );
+        }
+        
+    // MMS watcher sends us reason codes with garbage collection parameters.
+    // paramPack().iReasonFlags will contain the reason flags.
+    // paramPack().iMediaUnavailableTime tells when the memory card was removed
+    TMMSGarbageCollectionParameters param;
+    TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
+    paramPack.Set( iParameter );
+    
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- reason code:") );
+    if ( paramPack().iReasonFlags & KMmsReasonBoot )
+        {
+        TMmsLogger::Log( _L(" -- Boot") );
+        }
+    if ( paramPack().iReasonFlags & KMmsReasonMessageStoreChanged )
+        {
+        TMmsLogger::Log( _L(" -- MessageStoreChanged") );
+        }
+    if ( paramPack().iReasonFlags & KMmsReasonNetworkAllowed )
+        {
+        TMmsLogger::Log( _L(" -- Network operations allowed") );
+        }
+    if ( paramPack().iReasonFlags & KMmsReasonBackupEnded )
+        {
+        TMmsLogger::Log( _L(" -- Backup ended") );
+        }
+    if ( paramPack().iReasonFlags & KMmsReasonHotswap )
+        {
+        TMmsLogger::Log( _L(" -- Hotswap") );
+        }
+    if ( paramPack().iReasonFlags & KMmsReasonEnvironmentTimeChanged )
+        {
+        TMmsLogger::Log( _L(" -- Environment time change") );
+        }
+#endif
+
+    //
+    // Forward entries left in outbox
+    //
+    GcOutBoxNotificationsL();
+    
+    //
+    // Message entries left in outbox
+    //
+    GcOutBoxMessagesL();
+    
+    //
+    // Notifications in MMSFolder (automatic fetch)
+    //
+    GcMmsFolderNotificationsL();
+    
+    //
+    // Notifications from inbox
+    //
+    GcInboxNotifications();
+
+    //
+    // Notifications in mmbox folder    
+    //
+    GcMmboxFolderNotifications();
+        
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::CleanSchedulesL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::CleanSchedulesL( CMsvEntrySelection& aSelection )
+    {
+    // delete old schedules and reset scheduled entry.
+    // we trap each entry separately, so that we can clean as
+    // many as possible even if there are errors
+
+    TMsvId oldEntry = iServerEntry->Entry().Id();
+    TInt i;
+    CMsvEntrySelection* thisNotification = new( ELeave ) CMsvEntrySelection;
+    CleanupStack::PushL( thisNotification );
+    TInt error = KErrNone;
+
+    for ( i = 0; i < aSelection.Count(); i++ )
+        {
+        TRAP ( error,
+            {
+            error = iServerEntry->SetEntry( aSelection.At( i ) );
+            if ( error == KErrNone )
+                {
+                CMmsScheduledEntry* mmsScheduledEntry =
+                    CMmsScheduledEntry::NewL( iServerEntry->Entry() );
+                CleanupStack::PushL( mmsScheduledEntry );
+                thisNotification->Reset();
+                thisNotification->AppendL( aSelection.At( i ) );
+                iScheduleSend->DeleteScheduleL( *thisNotification );
+
+                CMsvStore* store = NULL;
+                store = iServerEntry->EditStoreL();
+                CleanupStack::PushL( store );
+                // We clean up the old scheduled entry data
+                // by storing a new clean scheduled entry
+                mmsScheduledEntry->StoreL( *store );
+                store->CommitL();
+
+                CleanupStack::PopAndDestroy( store );
+                CleanupStack::PopAndDestroy( mmsScheduledEntry );
+                }
+            }
+            );
+        }
+    CleanupStack::PopAndDestroy( thisNotification );
+    // restore the entry we were pointing at
+    // if this fails, something is seriously wrong. We did not delete anything.
+    iServerEntry->SetEntry( oldEntry );
+
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::FindMMSFolderL
+// 
+// ---------------------------------------------------------
+//
+TMsvId CMmsServerMtm::FindMMSFolderL()
+    {
+    // Actually the value in iMmsSettings should be correct
+    // but we try to really search for the folder in case
+    // the message store has been moved or something
+    TMsvId mmsFolderId = iMmsSettings->NotificationFolder();
+    TInt error;
+    
+    // get a new entry, don't mess up with the original entry.
+    CMsvServerEntry* workingEntry = NULL;
+    TRAP( error, workingEntry = iServerEntry->NewEntryL( KMsvLocalServiceIndexEntryId ) );
+    CleanupStack::PushL( workingEntry );
+    
+    if ( error == KErrNoMemory )
+        {
+        CleanupStack::PopAndDestroy( workingEntry );
+        User::Leave( error );
+        }
+
+    if ( error != KErrNone )
+        {
+        // no can do
+        CleanupStack::PopAndDestroy( workingEntry );
+        return mmsFolderId;
+        }
+
+    // Get List of services
+    // 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 )
+        {
+        // no can do
+        delete selection;
+        if ( error == KErrNoMemory )
+            {
+            CleanupStack::PopAndDestroy( workingEntry );
+            User::Leave( error );
+            }
+        else
+            {
+            CleanupStack::PopAndDestroy( workingEntry );
+            return mmsFolderId;
+            }
+        }
+    CleanupStack::PushL( selection );
+
+    // Now we should have a list of all local folders.
+    // prune away the standard folders.
+    // They should be at the end of the list
+
+    TInt count = selection->Count();
+    TInt i;
+
+    for ( i = count - 1; i >= 0; i-- )
+        {
+        if ( selection->At( i ) <= KMsvDeletedEntryFolderEntryId )
+            {
+            // Anything below this should not be ours
+            selection->Delete( i );
+            }
+        }
+
+    // anything left...
+    count = selection->Count();
+
+    for ( i = 0; i < count && mmsFolderId == KMsvNullIndexEntryId ; i++ )
+        {
+        error = workingEntry->SetEntry( selection->At( i ) );
+        if ( error == KErrNoMemory )
+            {
+            CleanupStack::PopAndDestroy( selection );
+            CleanupStack::PopAndDestroy( workingEntry );
+            User::Leave( error );
+            }
+        // must be exact match
+        if ( error == KErrNone &&
+            workingEntry->Entry().iDetails.Compare( KMMSNotificationFolder ) == 0 )
+            {
+            mmsFolderId = selection->At( i );
+            }
+        }
+    CleanupStack::PopAndDestroy( selection );
+    CleanupStack::PopAndDestroy( workingEntry );
+
+    return mmsFolderId;
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::DiskSpaceBelowCriticalForScheduling
+// 
+// ---------------------------------------------------------
+//
+TBool CMmsServerMtm::DiskSpaceBelowCriticalForSchedulingL( RFs* aFs,
+            TInt aBytesToWrite, TInt aMessageDrive)
+    {
+    TBool belowCritical = EFalse; // optimistic
+    // The amount of memory needed depends on the number of messages to handle
+    belowCritical = TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
+        aFs, KMmsTaskSpace * iMsvSelection->Count(), EDriveC );
+    if ( !belowCritical )
+        {
+        belowCritical = TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
+            aFs, aBytesToWrite, aMessageDrive );
+        }
+    return belowCritical;
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::ScheduleSelectionL
+// 
+// ---------------------------------------------------------
+//
+TInt CMmsServerMtm::ScheduleSelectionL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::ScheduleSelectionL") );
+#endif
+    
+    TInt error = KErrNone;
+    TInt i;
+    if ( iMsvSelection->Count() > 0 )
+        {
+        TCommandParameters param;
+        TPckgC<TCommandParameters> paramPack( param );
+        paramPack.Set( iParameter );
+
+        MakeDatesIdenticalL( *iMsvSelection, paramPack().iInitialDelay, ETrue );
+        // Query about disk space.
+        // Subroutine knows how much must be checked for task scheduler
+        if ( DiskSpaceBelowCriticalForSchedulingL( &iFs, 0, iMessageDrive ) )
+            {
+            // we use standard error code here
+            error = KErrDiskFull;
+            }
+        else
+            {
+            // We must set the caller's status to KRequest Pending because
+            // CScheduleBaseServerMtm::ScheduleL does not do it.
+            *iRequestStatus = KRequestPending;
+            TRAP( error, ScheduleL( *iMsvSelection, EFalse, iParameter, *iRequestStatus ) );
+            // ScheduleL would complete our caller, but if it leaves,
+            // we must complete. We don't want to leave without cleaning up first.
+    #ifndef _NO_MMSS_LOGGING_
+            if ( error != KErrNone )
+                {
+                TMmsLogger::Log( _L("- ScheduleL left with error %d"), error );
+                }
+    #endif
+            }
+        if ( error != KErrNone )
+            {
+            // Put the entries into failed state because we could not schedule them.
+            for ( i = 0; i < iMsvSelection->Count(); i++ )
+                {
+                if ( iServerEntry->SetEntry( iMsvSelection->At( i ) ) == KErrNone )
+                    {
+                    TMsvEntry entry = iServerEntry->Entry();
+                    TMsvId parent = entry.Parent();
+
+                    TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
+                    
+                    if ( entry.iMtm == KUidMsgMMSNotification && 
+                        ( parent == KMsvGlobalInBoxIndexEntryIdValue ||
+                        parent == mmboxFolder ) )
+                        {
+                        // if the notification is in mmbox folder and duplicate exists, 
+                        // the duplicate has to be marked too.
+                        if ( parent == mmboxFolder )
+                            {
+    #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L("- parent is mmbox folder") );
+    #endif
+                            TRAP_IGNORE( CMmsBaseOperation::MarkDuplicateL(
+                                CMmsBaseOperation::EMmsNotificationOperationFailed,
+                                *iServerEntry ) );
+                            }
+
+                        // Mark original notification
+                        entry = iServerEntry->Entry();
+                        CMmsBaseOperation::MarkNotificationOperationFailed( entry );
+                        entry.SetSendingState( KMsvSendStateFailed );
+                        entry.iError = error;
+                        entry.SetReadOnly( ETrue );
+    #ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- marked original notification as failed") );
+    #endif
+                        }
+                    iServerEntry->ChangeEntry( entry );
+                    }
+                }
+            *iRequestStatus = KRequestPending;
+            User::RequestComplete( iRequestStatus, error );
+            }
+        }
+    return error;
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::HandleDummyEntryL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleDummyEntryL()
+    {
+    //
+    // Get access to the streamstore of the entry
+    //
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("HandleDummyEntryL()") );
+#endif
+    if ( iMsvSelection->Count() == 0 )
+        {
+        User::Leave( KErrNotFound );
+        }
+        
+    User::LeaveIfError( iServerEntry->SetEntry( iMsvSelection->At( 0 ) ) );
+    CMsvStore* store = iServerEntry->ReadStoreL();
+    CleanupStack::PushL( store ); // ***
+    RMsvReadStream ins;
+    ins.OpenLC( *store, KUidBinaryNotificationStream ); // ***
+
+    //
+    // Read first 32 bits into integer. It will tell the length of the data
+    //
+    TInt datalength = ins.ReadUint32L();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L(" - Streamed %d bytes from dummy-entry's store"), datalength );
+#endif
+
+    //
+    // Reserve correct size buffer
+    //
+    if ( !iEncodeBuffer )
+        {
+        iEncodeBuffer = CBufFlat::NewL( datalength );
+        iEncodeBuffer->ResizeL( datalength );
+        }
+    else
+        {
+        // Throw away old stuff and resize
+        iEncodeBuffer->Reset();
+        iEncodeBuffer->ResizeL( datalength );
+        }
+    TPtr8 pBuf = iEncodeBuffer->Ptr( 0 );
+
+    //
+    // Read the data into buffer
+    //
+    ins.ReadL( pBuf );
+    CleanupStack::PopAndDestroy( &ins ); // close in
+    CleanupStack::PopAndDestroy( store );
+
+    //
+    // Clean up: the dummy entry is deleted
+    //
+    if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
+        {
+        iServerEntry->DeleteEntry( iMsvSelection->At( 0 ) );
+        }
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    iMsvSelection->Reset();
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::HandleMMBoxFlagL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleMMBoxFlagL( TMsvEntry& aEntry )
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("HandleMMBoxFlagL()") );
+#endif
+    // Is there an mmbox field in the notification PDU...
+    if( iMmsHeaders->MMBoxMessageHeadersL().MmsStored() == 0 )
+        {
+        TInt value = 0;
+        TInt error = KErrNone;
+        CRepository* repository = NULL;
+        TRAPD( error2,        
+            // Notification does not contain explicit field, so checking cenrep
+            repository = CRepository::NewL( KUidMmsServerMtm ) ); // ***
+        if ( error2 == KErrNone )
+            {
+            CleanupStack::PushL( repository );
+            #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L("- repository created") );
+            #endif
+            error = repository->Get( KMmsEnginePseudoMMBox, value );
+            if( error == KErrNone && value == 1 )
+                {
+                // Assuming MMBox storage in this case
+                aEntry.iMtmData2 |= KMmsStoredInMMBox;
+                #ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- Setting MMBox flag based on cenrep data!") );
+                #endif
+                }
+            else
+                {
+                #ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- Key not found from cenrep data, or value != 1") );
+                #endif
+                }
+            CleanupStack::PopAndDestroy( repository );
+            }
+        }
+    else if( iMmsHeaders->MMBoxMessageHeadersL().MmsStored() == KMmsYes )
+        {
+        // Notification specifies the flag as 'yes'
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- Notification contains stored in mmbox flag!") );
+        #endif
+        aEntry.iMtmData2 |= KMmsStoredInMMBox;
+        }
+    else
+        {
+        // Keep LINT happy
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::GcOutBoxMessagesL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GcOutBoxMessagesL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::GcOutBoxMessagesL") );
+#endif
+    //
+    // MMS watcher sends us reason codes with garbage collection parameters.
+    // paramPack().iReasonFlags will contain the reason flags.
+    // paramPack().iMediaUnavailableTime tells when the memory card was removed
+    //
+    TMMSGarbageCollectionParameters param;
+    TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
+    paramPack.Set( iParameter );
+    
+    TMsvEntry entry;
+    
+    iMsvSelection->Reset();
+    TInt err = iServerEntry->SetEntry( KMsvGlobalOutBoxIndexEntryId );
+    // Get entries of type MMS Message
+    if ( err == KErrNone )
+        {
+        err = iServerEntry->GetChildrenWithMtm( KUidMsgTypeMultimedia, *iMsvSelection );
+        }
+    TInt count = iMsvSelection->Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- found %d message entries from outbox"), count );
+#endif
+
+    if ( err == KErrNone && count > 0 )
+        {
+        // iSendOperation should not be around in this context.
+        // To avoid possible memory leaks, we clean it away anyway
+        delete iSendOperation; 
+        iSendOperation = NULL;
+        iSendOperation = CMmsSendOperation::NewL( iFs, iMmsSettings );
+                
+        iSendOperation->Failed().AppendL( iMsvSelection->Back( 0 ), count );
+        iSendOperation->Sent().SetReserveL( count );
+
+        CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
+        CleanupStack::PushL( selection );
+        while ( count-- )
+            {
+            // The detailed handling depends both on the state of the entry
+            // and the event that triggered the garbage collection.
+            // Some states are handled differently depending on the event,
+            // some states are always hanldled the same way.
+            if ( iServerEntry->SetEntry( iMsvSelection->At( count ) ) == KErrNone )
+                {
+                entry = iServerEntry->Entry();
+                selection->Reset();
+                selection->AppendL( iMsvSelection->At( count ) );
+                switch ( entry.SendingState() )
+                    {
+                    case KMsvSendStateSent:
+                        {
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- already sent"));
+#endif
+                        // Sent entries are always moved to sent folder (or deleted)
+                        // regardless of trigger event
+                        // A sent message should not be in outbox. It should have already been
+                        // moved to sent folder. However, as it is not moved, we must do it.
+                        if ( iServerEntry->SetEntry( KMsvGlobalOutBoxIndexEntryId ) == KErrNone )
+                            {
+                            if ( iMmsSettings->MoveToSent() )
+                                {
+                                // Move entry from Outbox to Sent Folder
+                                // count has originally been set to iMsvSelection->Count().
+                                iServerEntry->MoveEntryWithinService(
+                                    iMsvSelection->At( count ), KMsvSentEntryIdValue );
+                                // This will not fail
+                                if ( iSendOperation->Failed().Count() > count )
+                                    {
+                                    iSendOperation->Sent().AppendL(
+                                        iSendOperation->Failed().At( count ) );
+                                    }
+                                }
+                            else    
+                                {
+                                // Move entry to Message Heaven
+                                iServerEntry->DeleteEntry( iMsvSelection->At( count ) );
+                                }
+                            }
+                        iSendOperation->Failed().Delete( count );
+                        break;
+                        }
+                    case KMsvSendStateWaiting:
+                    case KMsvSendStateSending:
+#ifndef _NO_MMSS_LOGGING_
+                        if ( entry.SendingState() == KMsvSendStateWaiting )
+                            {
+                            TMmsLogger::Log( _L("- waiting"));
+                            }
+                        else
+                            {
+                            TMmsLogger::Log( _L("- sending"));
+                            }
+#endif
+                        if ( paramPack().iReasonFlags &
+                            ( KMmsReasonHotswap | KMmsReasonBackupEnded ) )
+                            {
+                            // reschedule if last time accessed earlier that media unavailable time stamp
+                            if ( iServerEntry->Entry().iDate > paramPack().iMediaUnavailableTime )
+                                {
+                                // Access time is after media unavailable,
+                                // It means that something has been done to this entry already.
+                                // Better leave it as is.
+#ifndef _NO_MMSS_LOGGING_
+                                TMmsLogger::Log( _L(" -- accessed after media unavailable - leave as is"));
+#endif
+                                iSendOperation->Failed().Delete( count );
+                                }
+                            }
+                        else
+                            {
+                            iSendOperation->Failed().Delete( count );
+                            }
+                        break;
+                    case KMsvSendStateUponRequest:
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- upon request"));
+#endif
+                        // Entries in "upon request" state are not rescheduled
+                        iSendOperation->Failed().Delete( count );
+                        break;
+                    case KMsvSendStateSuspended:
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- suspended"));
+#endif
+                        // entries in "upon request" or "suspended" state are not rescheduled
+                        // unless we have switched from offline mode back to online mode
+                        if ( !( ( paramPack().iReasonFlags & KMmsReasonNetworkAllowed ) &&
+                            ( entry.SendingState() == KMmsOffLineState ) &&
+                            ( entry.iError == KMmsErrorOfflineMode ) ) )
+                            {
+                            iSendOperation->Failed().Delete( count );
+                            }
+                        break;
+                    case KMsvSendStateScheduled:
+                    case KMsvSendStateResend:
+                        {
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- already scheduled"));
+#endif
+                        // These are either rescheduled or scheduled for the first time
+                        // reschedule if the schedule is in the past
+                        // If the scedule is in the past, CheckSchedule moves it forward.
+                        // However, if it is too much in the past, it is moved forward by a year.
+                        // We must do some sanity chaecking about the amount of change
+                        
+                        // we set flag to indicate that our shedule had passed
+                        TInt oldSchedule = EFalse;
+                        TTime now;
+                        now.UniversalTime();
+                        
+                        if ( iServerEntry->Entry().iDate < now )
+                            {
+                            oldSchedule = ETrue;
+                            }
+                        
+                        iScheduleSend->CheckScheduleL( *selection );
+                        if ( iServerEntry->Entry().Scheduled() )
+                            {
+                            // already scheduled - check, if schedule is valid
+                            TTime scheduleTime = iServerEntry->Entry().iDate;
+                            now += TTimeIntervalSeconds( 1 );
+#ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L("MMS terminal universal datetime: ") );
+                            CMmsBaseOperation::LogDateL( now );
+                            TMmsLogger::Log( _L("Scheduled datetime:") );
+                            CMmsBaseOperation::LogDateL( scheduleTime );
+#endif
+                            // leave the schedule, if it is in the future - but not too much
+                            TTimeIntervalMinutes allowance = 
+                                TTimeIntervalMinutes( KMmsScheduleAllowance );
+                            if ( ( ( ( scheduleTime - allowance ) <= now ) && ( scheduleTime > now ) )
+                                || !oldSchedule )
+                                {
+                                // scheduled in the future, we don't touch it
+                                // or the schedule has been originally set into the future,
+                                // and we don't want to change it
+                                iSendOperation->Failed().Delete( count );
+                                }
+#ifndef _NO_MMSS_LOGGING_
+                            else
+                                {
+                                TMmsLogger::Log( _L("- bad schedule"));
+                                }
+#endif
+                            }
+                        break;
+                        }
+                    case KMsvSendStateNotApplicable:
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- not applicable"));
+#endif
+                        break;
+                    case KMsvSendStateUnknown:
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- unknown"));
+#endif
+                        break;
+                    case KMsvSendStateFailed:
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- failed"));
+#endif
+                        break;
+                    default:
+                        // all entries that are left in the array, are rescheduled in the end
+                        break;
+                    }
+                }
+            }
+        CleanupStack::PopAndDestroy( selection );
+        iCommand = EMmsSend;
+        // whatever was left gets rescheduled
+        MakeDatesIdenticalL( iSendOperation->Failed(), KMmsGarbageCollectionDelay );
+        TRAP( err, UpdateEntriesL() );
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::GcMmsFolderNotificationsL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GcMmsFolderNotificationsL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::GcMmsFolderNotificationsL") );
+#endif
+    //
+    // MMS watcher sends us reason codes with garbage collection parameters.
+    // paramPack().iReasonFlags will contain the reason flags.
+    // paramPack().iMediaUnavailableTime tells when the memory card was removed
+    //
+    TMMSGarbageCollectionParameters param;
+    TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
+    paramPack.Set( iParameter );
+    
+    TMsvEntry entry;
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    TMsvId parent = FindMMSFolderL();
+
+    TInt err = iServerEntry->SetEntry( parent );
+    iMsvSelection->Reset(); 
+    // All entries in MMSFolder have the same Uid as messages
+    // There may be notifications, delivery reports and read reports.
+    // If the whole notification folder has disappeared we cannot have messages either...
+    if ( err == KErrNone && parent != KMsvNullIndexEntryId )
+        {
+        err = iServerEntry->GetChildrenWithType( KUidMsvMessageEntry, *iMsvSelection );
+        }
+    TInt count = iMsvSelection->Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L(" - found %d notification entries"), iMsvSelection->Count() );
+#endif
+
+    if ( err == KErrNone && count > 0 )
+        {
+        // iReceiveMessage should not be around in this context.
+        // To avoid possible memory leaks, we clean it away anyway
+        delete iReceiveMessage; 
+        iReceiveMessage = NULL;
+        iReceiveMessage = CMmsReceiveMessage::NewL( iFs, iMmsSettings  );
+                
+        iReceiveMessage->Failed().AppendL( iMsvSelection->Back( 0 ), count );
+        iReceiveMessage->Received().SetReserveL( count );
+
+        while ( count-- )
+            {
+            if ( iServerEntry->SetEntry( iMsvSelection->At( count ) ) == KErrNone )
+                {
+                entry = iServerEntry->Entry();
+                if ( entry.SendingState() == KMsvSendStateSent )
+                    {
+                    // successful entry, delete it
+                    // This will not fail
+                    // Read reports are never marked as "sent" so they should not
+                    // disturb the logic here
+                    if ( iReceiveMessage->Failed().Count() > count )
+                        {
+                        iReceiveMessage->Received().AppendL(
+                            iReceiveMessage->Failed().At( count ) );
+                        iReceiveMessage->Failed().Delete( count );
+                        }
+                    }
+                else if ( ( ( entry.SendingState() == KMsvSendStateWaiting ) || 
+                    ( entry.SendingState() == KMsvSendStateSending ) ) )
+                    {
+                    if ( paramPack().iReasonFlags & ( KMmsReasonHotswap | KMmsReasonBackupEnded ) )
+                        {
+                        // These will be rescheduled only if they were accessed the last time
+                        // before the media unavailable event.
+                        // Otherwise they might be a new operation.
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- hotswap or backup trigger"));
+#endif
+                        if ( entry.iDate > paramPack().iMediaUnavailableTime )
+                            {
+                            iReceiveMessage->Failed().Delete( count );
+                            }
+                        }
+                    }
+                else if ( entry.iError == KErrNone && entry.iMtmData2 & KMmsNotifyResponseSent )
+                    {
+                    // If this is legally deferred, it will not be rescheduled
+                    CMsvStore* store = iServerEntry->ReadStoreL();
+                    CleanupStack::PushL( store );
+                    iMmsHeaders->RestoreL( *store );
+                    CleanupStack::PopAndDestroy( store );
+                    if ( iMmsHeaders->Status() == KMmsMessageStatusDeferred )
+                        {
+                        // this has been deferred legally - do not reschedule
+                        iReceiveMessage->Failed().Delete( count );
+                        }
+                    }
+                else
+                    {
+                    // Keep LINT happy
+                    }
+                }
+            // Here could be a branch that prevents automatic sending of
+            // messages that have been suspended by user. However, user can suspend
+            // fetching only in manual mode, and then the notifications are in inbox
+            }
+        // Check notifications will remove expired notifications
+        if ( iReceiveMessage->Failed().Count() > 0 )
+            {
+            // only check if there was anything left
+            CheckNotificationsL( iReceiveMessage->Failed() );
+            }
+        iCommand = EMmsReceive;
+        MakeDatesIdenticalL( iReceiveMessage->Failed(), KMmsGarbageCollectionDelay );
+        TRAP( err, UpdateEntriesL() );
+        err = KErrNone; // we don't care about the error, we just do our best
+        }
+    }
+    
+// ---------------------------------------------------------
+// CMmsServerMtm::GcMmsFolderNotificationsL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GcInboxNotifications()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::GcInboxNotifications") );
+#endif
+    //
+    // MMS watcher sends us reason codes with garbage collection parameters.
+    // paramPack().iReasonFlags will contain the reason flags.
+    // paramPack().iMediaUnavailableTime tells when the memory card was removed
+    //
+    TMMSGarbageCollectionParameters param;
+    TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
+    paramPack.Set( iParameter );
+    
+    TMsvEntry entry;
+    
+    TInt err = iServerEntry->SetEntry( KMsvGlobalInBoxIndexEntryId );
+    iMsvSelection->Reset(); 
+    if ( err == KErrNone )
+        {
+        err = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *iMsvSelection );
+        }
+    TInt count = iMsvSelection->Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L(" - found %d notifications in inbox"), iMsvSelection->Count() );
+#endif
+    TInt i;
+    if ( err == KErrNone && count > 0 )
+        {
+        for ( i = 0; i < count; i++ )
+            {
+            if ( iServerEntry->SetEntry( iMsvSelection->At( i ) ) == KErrNone )
+                {
+                entry = iServerEntry->Entry();
+                
+                //
+                // If booting and notif is not allowed to start a new operation -> something wrong
+                //
+                if( ( paramPack().iReasonFlags & ( KMmsReasonBoot ) ) &&
+                    ( entry.iMtmData2 & KMmsNewOperationForbidden ) )
+                    {
+                    entry.iError = KMmsGeneralError;
+                    CMmsBaseOperation::MarkNotificationOperationFailed( entry );
+                    entry.SetReadOnly( ETrue );
+                    entry.iMtmData2 &= ~KMmsOperationIdentifier;
+                    iServerEntry->ChangeEntry( entry );                 
+                    }
+                }
+                        
+            }
+        }
+    }
+    
+// ---------------------------------------------------------
+// CMmsServerMtm::GcOutBoxNotificationsL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GcOutBoxNotificationsL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::GcOutBoxNotificationsL") );
+#endif
+    //
+    // MMS watcher sends us reason codes with garbage collection parameters.
+    // paramPack().iReasonFlags will contain the reason flags.
+    // paramPack().iMediaUnavailableTime tells when the memory card was removed
+    //
+    TMMSGarbageCollectionParameters param;
+    TPckgC<TMMSGarbageCollectionParameters> paramPack( param );
+    paramPack.Set( iParameter );
+
+    //
+    // Get selection of notifications from Outbox
+    //
+    TInt err = iServerEntry->SetEntry( KMsvGlobalOutBoxIndexEntryId );
+    iMsvSelection->Reset();
+    if ( err == KErrNone )
+        {
+        err = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *iMsvSelection );
+        }
+    TInt count = iMsvSelection->Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("- found %d notification entries from Outbox"), count );
+#endif
+    if( err != KErrNone || count <= 0 )
+        {
+#ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L("- no entries to clean up"), count );
+#endif
+        return;
+        }
+
+    //
+    // Creating iForwardOperation  that will handle resends
+    //
+    delete iForwardOperation;
+    iForwardOperation = NULL;
+    iForwardOperation = CMmsForwardOperation::NewL( iFs, iMmsSettings );                
+    iForwardOperation->Failed().AppendL( iMsvSelection->Back( 0 ), count );
+
+    CMsvEntrySelection* selection = new( ELeave ) CMsvEntrySelection;
+    CleanupStack::PushL( selection );
+
+    //
+    // Loop through the found notifications (forward entries)
+    //
+    while( count-- )
+        {
+        //
+        // The detailed handling depends both on the state of the entry
+        // and the event that triggered the garbage collection.
+        //
+        TMsvEntry tEntry;
+        err = iServerEntry->SetEntry( iMsvSelection->At( count ) );
+        if( err != KErrNone )
+            {
+            // If entry not accessible, start a new round
+            continue;
+            }
+        tEntry = iServerEntry->Entry();
+        selection->Reset();
+        selection->AppendL( iMsvSelection->At( count ) );
+
+        //
+        // Switch through based on notification entry's state
+        //
+        switch ( tEntry.SendingState() )
+            {
+            case KMsvSendStateSuspended:
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- KMsvSendStateSuspended"));
+#endif
+                if( tEntry.iError == KMmsErrorOfflineMode )
+                    {
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- entry error == offline"));
+#endif
+                    if( paramPack().iReasonFlags & KMmsReasonNetworkAllowed )
+                        {
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- GCreason == back-from-offline: rescheduling entry"));
+#endif
+                        // Reschedule entry
+                        // i.e. nothing done here
+                        }
+                    else // GC reason is not "back from offline"
+                        {
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- GCreason != back-from-offline: leaving entry suspended"));
+#endif
+                        // Leave entry suspended (applies to both entry types)
+                        // i.e. take entryId out from to-be-scheduled list
+                        iForwardOperation->Failed().Delete( count );
+                        }
+                    }
+                else // entry.iError not equal to KMmsErrorOfflineMode
+                    {
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- entry error != offline, set forward entry as Failed") );
+#endif
+                    // Set forward entry's send-state to failed
+                    tEntry.SetFailed( ETrue );
+
+                    // Clear related notification from Inbox:
+                    // Get the related notification id
+                    CMsvStore* store = NULL;
+                    store = iServerEntry->EditStoreL();
+                    CleanupStack::PushL( store ); // ***
+                    iMmsHeaders->RestoreL( *store );
+                    CleanupStack::PopAndDestroy( store );
+                    TMsvId relatedEntryId = iMmsHeaders->RelatedEntry();
+                    iMmsHeaders->Reset(); // headers not needed any more
+
+                    if( relatedEntryId != KMsvNullIndexEntryId )
+                        {
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- related notification-entry exists, clearing it") );
+#endif
+                        // Set context (iServerEntry and entry) to notification and clear it
+                        err = iServerEntry->SetEntry( relatedEntryId );
+#ifndef _NO_MMSS_LOGGING_
+                        if( err != KErrNone )
+                            {
+                            TMmsLogger::Log( _L("- ERROR: Could not set entry") );
+                            }
+#endif
+                        if ( err == KErrNone )
+                            {
+                            tEntry = iServerEntry->Entry();
+                            tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; // not forbidden
+                            tEntry.iMtmData2 &= ~KMmsOperationOngoing;      // not ongoing
+                            tEntry.iMtmData2 |= KMmsOperationFinished;      // finished
+                            tEntry.iMtmData2 |= KMmsOperationResult;        // NOK
+                            tEntry.SetReadOnly( ETrue );
+                            err = iServerEntry->ChangeEntry( tEntry );
+                            }
+#ifndef _NO_MMSS_LOGGING_
+                        if( err != KErrNone )
+                            {
+                            TMmsLogger::Log( _L("- ERROR: Could not change related entry") );
+                            }
+                        TMmsLogger::Log( _L("- Clear the related-entry link itself") );
+#endif
+
+                        // Clear related-id link from forward entry
+                        err = iServerEntry->SetEntry( iMsvSelection->At( count ) );
+                        if ( err == KErrNone )
+                            {
+                            store = iServerEntry->EditStoreL();
+                            CleanupStack::PushL( store ); // ***
+                            iMmsHeaders->RestoreL( *store );
+                            iMmsHeaders->SetRelatedEntry( KMsvNullIndexEntryId );
+                            iMmsHeaders->StoreL( *store );
+                            store->CommitL();
+                            CleanupStack::PopAndDestroy( store );
+                            }
+                        iMmsHeaders->Reset(); // headers not needed any more
+#ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L("- Related-entry and the link cleared") );
+#endif
+                        }
+
+                    // Clean up. 
+                    // iServerEntry will be needed and set next time
+                    // at the start of this loop.
+                    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+                    // Leave entry suspended (applies to both entry types)
+                    // i.e. take entryId out from to-be-scheduled list
+#ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L("- not scheduling entry") );
+#endif
+                    iForwardOperation->Failed().Delete( count );
+                    }
+                break;
+            default:
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("- Forward entry's sendState == %d, not scheduling"), tEntry.SendingState() );
+#endif
+                    iForwardOperation->Failed().Delete( count );
+                break;
+            }
+        } // while loop
+
+    CleanupStack::PopAndDestroy( selection );
+    iCommand = EMmsForward;
+    // whatever was left gets rescheduled
+    MakeDatesIdenticalL( iForwardOperation->Failed(), KMmsGarbageCollectionDelay );
+    TRAP( err, UpdateEntriesL() );
+#ifndef _NO_MMSS_LOGGING_
+    if( err != KErrNone )
+        {
+        TMmsLogger::Log( _L("- UpdateEntriesL failed with code %d"), err );
+        }
+#endif
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::GcMmboxFolderNotifications
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GcMmboxFolderNotifications()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::GcMmboxFolderNotifications") );
+#endif
+
+    TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
+    // if mmbox folder is not found, no need to check notifications from there. 
+    if ( mmboxFolder == KMsvNullIndexEntryId )
+        {
+        return;
+        }
+
+    TInt error = iServerEntry->SetEntry( mmboxFolder );
+    iMsvSelection->Reset(); 
+    if ( error == KErrNone )
+        {
+        error = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *iMsvSelection );
+        }
+    TInt count = iMsvSelection->Count();
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L(" - mmbox folder contains %d notifications"), count );
+#endif
+    if ( error == KErrNone && count > 0 )
+        {
+
+        for ( TInt i=0; i < count; i++ )
+            {
+            if ( iServerEntry->SetEntry( iMsvSelection->At( i ) ) == KErrNone )
+                {
+                TMsvEntry entry = iServerEntry->Entry();
+
+                // If forbidden flag is on, mark as failed. 
+                if( entry.iMtmData2 & KMmsNewOperationForbidden )
+                    {             
+                    entry.iError = KMmsGeneralError;
+                    entry.SetSendingState( KMsvSendStateSuspended );
+                    CMmsBaseOperation::MarkNotificationOperationFailed( entry );
+                    entry.SetReadOnly( ETrue );
+                    entry.iMtmData2 &= ~KMmsOperationIdentifier;
+                    iServerEntry->ChangeEntry( entry );
+                    }           
+                }
+            }
+        }
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    }
+
+// ---------------------------------------------------------
+// CMmsServerMtm::FindDuplicateNotificationL
+// 
+// ---------------------------------------------------------
+//
+TInt CMmsServerMtm::FindDuplicateNotificationL(
+    TMsvId aParent, CMmsHeaders& aHeaders, TMsvId& aDuplicate )
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsServerMtm::FindDuplicateNotificationL") );
+#endif
+    
+    aDuplicate = KMsvNullIndexEntryId;
+ 
+    if ( aParent == KMsvNullIndexEntryId )
+        {
+        return KErrNotSupported;
+        }
+
+    TInt error = iServerEntry->SetEntry( aParent );
+    if ( error != KErrNone )
+        {
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        return error;
+        }
+
+    CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; 
+    CleanupStack::PushL( selection );
+
+    error = iServerEntry->GetChildrenWithMtm( KUidMsgMMSNotification, *selection );
+
+    TInt count = selection->Count();
+    if ( count == 0 )
+        {
+        error = KErrNotSupported;
+        }
+
+    if ( error != KErrNone  )
+        {
+        CleanupStack::PopAndDestroy( selection );
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+        return error;
+        }
+
+    CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    CleanupStack::PushL( mmsHeaders );
+     
+    for ( TInt i = count; i > 0 && ( aDuplicate == KMsvNullIndexEntryId ); i-- )
+        {
+        error = iServerEntry->SetEntry( selection->At( i - 1 ) );
+        if ( error == KErrNone )
+            {            
+            CMsvStore* store = iServerEntry->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 = iServerEntry->Entry();
+                aDuplicate = entry.Id();
+                }
+
+            }
+        
+        }
+
+    CleanupStack::PopAndDestroy( mmsHeaders );
+    CleanupStack::PopAndDestroy( selection );
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    return error;
+    }    
+    
+// ---------------------------------------------------------
+// CMmsServerMtm::SendReadReportL
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::SendReadReportL()
+    {
+    if ( iMsvSelection->Count() > 0 )
+        {
+        delete iReadReport;
+        iReadReport = NULL;
+        iReadReport = CMmsReadReport::NewL( iFs, iMmsSettings );
+
+        iReadReport->StartL( *iMsvSelection, *iServerEntry,
+            iServiceEntryId, iStatus );
+        *iRequestStatus = KRequestPending;
+        SetActive();    
+        }
+    else
+        {
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, KErrNotFound );
+        }
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::LogCommandCode( TInt aCommand )
+    {
+#ifndef _NO_MMSS_LOGGING_
+    switch ( aCommand )
+        {
+        case EMmsSend:
+            TMmsLogger::Log( _L(" - Send") );
+            break;
+        case EMmsReceive:
+            TMmsLogger::Log( _L(" - Receive") );
+            break;
+        case EMmsScheduledSend:
+            TMmsLogger::Log( _L(" - Scheduled send") );
+            break;
+        case EMmsScheduledReceive:
+            TMmsLogger::Log( _L(" - Scheduled fetch") );
+            break;
+        case EMmsDeleteSchedule:
+            TMmsLogger::Log( _L(" - Delete schedule") );
+            break;
+        case EMmsDecodePushedMessage:
+            TMmsLogger::Log( _L(" - Decode pushed message") );
+            break;
+        case EMmsLogDeliveryReport:
+            TMmsLogger::Log( _L(" - Log delivery report") );
+            break;
+        case EMmsDeleteEntries:
+            TMmsLogger::Log( _L(" - Delete entries") );
+            break;
+        case EMmsReceiveForced:
+            TMmsLogger::Log( _L(" - Receive forced") );
+            break;
+        case EMmsScheduledReceiveForced:
+            TMmsLogger::Log( _L(" - Scheduled receive forced") );
+            break;
+        case EMmsGarbageCollection:
+            TMmsLogger::Log( _L(" - Garbage collection") );
+            break;
+        case EMmsDeleteExpiredNotifications:
+            TMmsLogger::Log( _L(" - Delete expired notifications") );
+            break;
+        case EMmsRetryServiceLoading:
+            TMmsLogger::Log( _L(" - Retry because service loading failed!") );
+            break;
+        case EMmsMessageGeneration:
+            TMmsLogger::Log( _L(" - Message generation") );
+            break;
+        case EMmsForward:
+            TMmsLogger::Log( _L(" - EMmsForward") );
+            break;
+        case EMmsScheduledForward:
+            TMmsLogger::Log( _L(" - EMmsScheduledForward") );
+            break;
+        case EMmsNotificationDelete:
+            TMmsLogger::Log( _L(" - EMmsNotificationDelete") );
+            break;
+        case EMmsScheduledNotificationDelete:
+            TMmsLogger::Log( _L(" - EMmsScheduledNotificationDelete") );
+            break;
+        case EMmsUpdateMmboxList:
+            TMmsLogger::Log( _L(" - EMmsUpdateMmboxList") );
+            break;
+        case EMmsSendReadReport:
+            TMmsLogger::Log( _L(" - EMmsSendReadReport") );
+            break;
+        case EMmsScheduledReadReport:
+            TMmsLogger::Log( _L(" - EMmsScheduledReadReport") );
+            break;
+        default:
+            TMmsLogger::Log( _L(" - Unknown command") );
+            break;
+        }
+    TMemoryInfoV1Buf memory;
+    UserHal::MemoryInfo( memory );
+    TInt available = memory().iFreeRamInBytes;
+    TMmsLogger::Log(_L("Free memory %d"), available );
+#endif // _NO_MMSS_LOGGING_
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::GetRealServiceId( CMsvEntrySelection& aSelection )
+    {
+    TInt error = KErrNone;
+    TMsvId messageEntryId = KMsvNullIndexEntryId;
+    // the function cannot be called without a selection so the selection
+    // array always has at least one item.
+    if ( aSelection.Count() > 0 && aSelection.At( 0 ) != KMsvLocalServiceIndexEntryId )
+        {
+        messageEntryId = aSelection.At( 0 );
+        }
+    else if ( aSelection.Count() > 1 )
+        {
+        messageEntryId = aSelection.At( 1 );
+        }
+    else
+        {
+        // We never get here. This is just a safety valve.
+        error = KErrNotFound;
+        }
+
+    // if only a service entry in selection list,
+    // nothing can be done. If we have only service entry,
+    // and that is not ours, we won't get here anyway.
+
+    if ( messageEntryId != KMsvNullIndexEntryId )
+        {
+        error = iServerEntry->SetEntry( messageEntryId );
+        }
+    if ( error == KErrNone )
+        {
+        if ( iServerEntry->Entry().iServiceId == KMsvLocalServiceIndexEntryId &&
+            iServerEntry->Entry().iRelatedId != KMsvNullIndexEntryId )
+            // This is our actual service.
+            {
+            iServiceEntryId = iServerEntry->Entry().iRelatedId;
+            }
+        }
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::HandleLoadServiceError( TInt aError )
+    {
+    if ( iCommand == EMmsDecodePushedMessage )
+        {
+        // We must delete the dummy entry given to us,
+        // otherwise nobody will delete it.
+
+        if ( iMsvSelection->Count() > 0 && iMsvSelection->At( 0 ) == iServiceEntryId )
+            {
+            iMsvSelection->Delete( 0 ); 
+            }
+        if ( iMsvSelection->Count() > 0 )
+            {
+            if ( iServerEntry->SetEntry( iMsvSelection->At( 0 ) ) == KErrNone )
+                {
+                if ( iServerEntry->SetEntry( iServerEntry->Entry().Parent() ) == KErrNone )
+                    {
+                    iServerEntry->DeleteEntries( *iMsvSelection );
+                    }
+                }
+            }
+        iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+        // If we are trying to decode a notification from WAP stack
+        // return error to caller, not to ourselves
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, aError );
+        return;
+        }
+        
+    if ( aError == KErrNotFound || aError == KErrNoMemory )
+        {
+        // This is a hopeless case.
+        // It could lead to endless loop.
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, aError );
+        return;
+        }
+
+    // We only have to help client mtm when it is trying to start automatic
+    // fetch after changing fetch mode from "deferred" to "on"
+    if ( iCurrentCommand == EMmsScheduledReceive ||
+        iCurrentCommand == EMmsScheduledReceiveForced )
+        {
+        iCurrentCommand = EMmsRetryServiceLoading;
+        TRequestStatus* status = &iStatus;
+        // caller should be in pending state, too.
+        *iRequestStatus = KRequestPending;
+        iStatus = KRequestPending;
+        SetActive();
+        User::RequestComplete( status, aError );
+        return;
+        }
+    else
+        {
+        *iRequestStatus = KRequestPending;
+        User::RequestComplete( iRequestStatus, aError );
+        return;
+        }
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::LogEntryParent()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMsvId msgEntryId = KMsvNullIndexEntryId;
+    TInt error = KErrNone;
+    if ( iMsvSelection->Count() > 0 )
+        {
+        msgEntryId = iMsvSelection->At( 0 );
+        error = iServerEntry->SetEntry( msgEntryId );
+        if ( error == KErrNone )
+            {
+            if ( iServerEntry->Entry().Parent() == KMsvGlobalOutBoxIndexEntryId )
+                {
+                TMmsLogger::Log( _L("- EntryParent: Outbox") );
+                }
+            else
+                {
+                TMmsLogger::Log( _L("- EntryParent: 0x%08X"), iServerEntry->Entry().Parent() );
+                }
+            }
+        }
+    // free whatever entry we are holding
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+#endif
+    }
+    
+// ---------------------------------------------------------
+// 
+// ---------------------------------------------------------
+//
+void CMmsServerMtm::RestoreVisibilityAndService()
+    {
+    TInt error = KErrNone;
+    TInt i = 0;
+    TMsvEntry entry;
+
+    // Make sure that the entries are visible.
+    // If they are "in preparation" that's the caller's problem
+
+    for ( i = 0; i < iMsvSelection->Count(); i++ )
+        {
+        error = iServerEntry->SetEntry( iMsvSelection->At( 0 ) );
+        if ( error == KErrNone )
+            {
+            entry = iServerEntry->Entry();
+            if ( entry.Visible() == EFalse && iCurrentCommand != EMmsDeleteSchedule )
+                {
+                entry.SetVisible( ETrue );
+                // if this fails we cannot help...
+                iServerEntry->ChangeEntry( entry );
+                }
+            if ( iCurrentCommand == EMmsDeleteSchedule &&
+                entry.iServiceId == KMsvLocalServiceIndexEntryId &&
+                entry.iRelatedId != KMsvNullIndexEntryId)
+                {
+                // restore the correct service id
+                entry.iServiceId = entry.iRelatedId;
+                entry.iRelatedId = KMsvNullIndexEntryId;
+                // if this fails we cannot help...
+                iServerEntry->ChangeEntry( entry );
+                }
+            }
+        }
+
+    // free the entry we are holding
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    }
+          
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+#ifndef _NO_MMSS_LOGGING_
+const TInt KLogBufferLength = 256;
+_LIT(KLogDir, "mmss");
+_LIT(KLogFile, "mmss.txt");
+
+void TMmsLogger::Log(TRefByValue<const TDesC> aFmt,...)
+    {
+    VA_LIST list;
+    VA_START(list, aFmt);
+
+    // Print to log file
+    TBuf<KLogBufferLength> buf;
+    buf.FormatList(aFmt, list);
+
+    // Write to log file
+    RFileLogger::Write(KLogDir, KLogFile, EFileLoggingModeAppend, buf);
+    }
+#endif
+
+//
+// ---------------------------------------------------------
+// gPanic implements
+// panic function, should be used by debug version only
+//
+GLDEF_C void gPanic(
+    TMmsPanic aPanic ) // error number enumerations
+    {
+    _LIT( KMmsPanic,"MMS" );
+    User::Panic( KMmsPanic, aPanic );
+    }
+
+//  End of File