mmsengine/mmsserver/src/mmsdeleteoperation.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 52 12db4185673b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmsengine/mmsserver/src/mmsdeleteoperation.cpp	Fri Jun 04 10:25:39 2010 +0100
@@ -0,0 +1,920 @@
+/*
+* Copyright (c) 2004-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  
+*     State machine for sending a delete request to network
+*
+*/
+
+
+
+// INCLUDE FILES
+#include    <apparc.h>
+#include    <msventry.h>
+#include    <msvids.h>
+#include    <logcli.h>
+#include    <commdb.h>
+#include    <in_sock.h>
+#include    <commdbconnpref.h>
+#include    <AknGlobalNote.h>
+
+// the rest are local includes, needed always
+#include    "mmsconst.h"
+#include    "mmsdeleteoperation.h"
+#include    "mmssession.h"
+#include    "mmssettings.h"
+#include    "mmsservercommon.h"
+#include    "mmsheaders.h"
+#include    "mmsmmboxmessageheaders.h"
+#include    "mmsencode.h"
+#include    "mmsdecode.h"
+#include    "mmsscheduledentry.h"
+#include    "mmsgenutils.h"
+#include    "mmserrors.h"
+#include    "mmsserverentry.h"
+#include    "mmsconninit.h"
+
+// EXTERNAL DATA STRUCTURES
+
+// EXTERNAL FUNCTION PROTOTYPES  
+extern void gPanic( TMmsPanic aPanic );
+
+// CONSTANTS
+
+// MACROS
+
+// LOCAL CONSTANTS AND MACROS
+
+// MODULE DATA STRUCTURES
+
+// LOCAL FUNCTION PROTOTYPES
+
+// ==================== LOCAL FUNCTIONS ====================
+
+// ================= MEMBER FUNCTIONS =======================
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::CMmsDeleteOperation
+//
+// ---------------------------------------------------------
+//
+CMmsDeleteOperation::CMmsDeleteOperation( RFs& aFs ):
+    CMmsBaseOperation( aFs )
+    {
+    //
+    // members that get initial value 0, need not be initialized here
+    //
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::ConstructL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::ConstructL( CMmsSettings* aMmsSettings )
+    {
+    CMmsBaseOperation::ConstructL( aMmsSettings );
+    iMmsRequestHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+    CActiveScheduler::Add( this );
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::NewL
+//
+// ---------------------------------------------------------
+//
+CMmsDeleteOperation* CMmsDeleteOperation::NewL( RFs& aFs, CMmsSettings* aMmsSettings )
+    {
+    CMmsDeleteOperation* self = new ( ELeave ) CMmsDeleteOperation( aFs );
+    CleanupStack::PushL( self );
+    self->ConstructL( aMmsSettings );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+    
+// ---------------------------------------------------------
+// CMmsDeleteOperation::~CMmsDeleteOperation
+//
+// ---------------------------------------------------------
+//
+CMmsDeleteOperation::~CMmsDeleteOperation()
+    {
+    Cancel();
+    delete iMmsRequestHeaders;
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::DoCancel
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::DoCancel()
+    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsDeleteOperation::DoCancel") );
+    #endif
+    CMmsBaseOperation::DoCancel();
+
+    // Clear possible flags
+    for( TInt i = iSelection->Count()-1; i >= 0; i-- )
+        {
+        // original entry
+        if ( iServerEntry->SetEntry( iSelection->At( i ) ) == KErrNone )
+            {
+            TMsvEntry tEntry = iServerEntry->Entry();
+            TMsvId parent = tEntry.Parent();
+            // If notification in iSelection is in mmbox folder, mark the
+            // possible duplicate notification in inbox too. 
+            if ( parent == iMmsSettings->MMBoxFolder() )
+                { 
+    #ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("possible duplicates has to be checked") );
+    #endif            
+                TInt error = KErrNone;
+                TRAP ( error, MarkDuplicateL( EMmsNotificationOperationFailed, *iServerEntry ) );
+    #ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("Trap failed: error %d "), error );
+    #endif
+                }
+            
+            // reload to make sure any changes are included
+            // (there should be no changes)
+            tEntry = iServerEntry->Entry();
+            MarkNotificationOperationFailed( tEntry );
+            
+            // put to read only state after duplicates have been marked
+            // because MarkDuplicateL may want to edit link to related entry
+            tEntry.SetReadOnly( ETrue );
+            iServerEntry->ChangeEntry( tEntry );        
+
+            }
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::StartL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::StartL(
+    TMmsDeleteOperationType aDeleteType,
+    CMsvEntrySelection& aSelection,
+    CMsvServerEntry& aServerEntry,
+    TMsvId aService,
+    TRequestStatus& aStatus )
+    {
+    iDeleteType = aDeleteType;
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsDeleteOperation::StartL") );
+    if( iDeleteType == EMmsDeleteNotificationOnly ) TMmsLogger::Log( _L("- EMmsDeleteNotificationOnly") );
+    if( iDeleteType == EMmsDeleteMMBoxOnly ) TMmsLogger::Log( _L("- EMmsDeleteMMBoxOnly") );
+    if( iDeleteType == EMmsDeleteBoth ) TMmsLogger::Log( _L("- EMmsDeleteBoth") );
+    #endif
+    // Make sure the version number is correctly set
+    CMmsBaseOperation::StartL( aSelection, aServerEntry, aService, aStatus );
+    iMmsRequestHeaders->Reset();
+
+    //
+    // Delete operation does not work as regular operations:
+    //
+    // iFailed list is emptied because retries are not used for delete
+    iFailed->Reset();
+    // iCurrentMessageNo makes no sense in case of delete
+    iCurrentMessageNo = 0;
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::StartL
+// This just overrides the base class version.
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::StartL(
+    CMsvEntrySelection&,
+    CMsvServerEntry&,
+    TMsvId,
+    TRequestStatus& )
+    {
+    User::Leave( KErrNotSupported );
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::EncodePDUL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::EncodePDUL()
+    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsDeleteOperation::EncodePDU") );
+    #endif
+    TInt err = KErrNone;  // used to trap errors that are not propagated further
+   
+    // Go through iSelection and make various checks   
+    TMsvEntry tEntry;
+    for( TInt i = iSelection->Count()-1; i >= 0; i-- )
+        {
+        if ( iServerEntry->SetEntry( iSelection->At( i ) ) == KErrNone )
+            {
+            tEntry = iServerEntry->Entry();
+
+            // Check that selection contains only "idle" notifications
+            if( ( tEntry.iMtm != KUidMsgMMSNotification ) ||
+                ( tEntry.iMtm == KUidMsgMMSNotification && 
+                tEntry.iMtmData2 & KMmsNewOperationForbidden ) )
+                {
+                // Take out all non-notifications and notifications that have some operation ongoing
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- notif not idle, skipping" ) );
+    #endif
+                iSelection->Delete( i );
+                }
+            else
+                {
+                // If only local delete requested, delete the entry
+                if( iDeleteType == EMmsDeleteNotificationOnly )
+                    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- just deleting the notif entry" ) );
+    #endif
+                    TRAP( err, DeleteNotificationEntryL() );
+    #ifndef _NO_MMSS_LOGGING_
+                    if( err != KErrNone )
+                        {
+                        TMmsLogger::Log( _L( "- ERROR: DeleteNotificationEntryL left" ) );
+                        }
+    #endif
+                    iSelection->Delete( i );
+                    }
+                else // EMmsDeleteMMBoxOnly OR EMmsDeleteBoth
+                    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- mmbox deletion wanted" ) );
+    #endif
+                    // Is there a message in MMBox.
+                    if( !(tEntry.iMtmData2 & KMmsStoredInMMBox ) )
+                        {
+                        // No need to care about possible duplicate notification. 
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- accordig to mmbox flag, message is not in mmbox" ) );
+    #endif
+                        // If both requested, but no message in MMBox,
+                        // just delete the notification.
+                        if( iDeleteType == EMmsDeleteBoth )
+                            {                        
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- local deletion requested, performing it" ) );
+    #endif
+                            TRAP( err, DeleteNotificationEntryL() );
+    #ifndef _NO_MMSS_LOGGING_
+                            if( err != KErrNone )
+                                {
+                                TMmsLogger::Log( _L( "- ERROR: DeleteNotificationEntryL left" ) );
+                                }
+    #endif
+                            }
+                        else // iDeleteType == EMmsDeleteMMBoxOnly
+                            {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- can not delete from mmbox, clearing entry flags" ) );
+    #endif
+                            MarkNotificationOperationFailed( tEntry );
+                            tEntry.SetReadOnly( ETrue );
+                            iServerEntry->ChangeEntry( tEntry );
+                            }
+                        // As message not in MMBox, delete entry from selection
+                        iSelection->Delete( i );
+                        }
+                    }
+                }
+            }
+        else
+            {
+            // take out an entry that could not be accessed
+            iSelection->Delete( i );
+            }
+        }
+
+    // delete from mmbox is wanted and the notifications are stored in mmbox
+    // Check duplicates, if the parent is in mmbox folder.
+    
+    // If duplicate is found, check if the duplicate is free. 
+    // If the duplicate is free, mark the duplicate as "deleting operation going on". 
+    // If duplicate is not free, drop the original notification from iSelection.
+
+    for ( TInt j = iSelection->Count()-1; j >= 0; j-- )
+        {
+        if ( iServerEntry->SetEntry( iSelection->At( j ) ) == KErrNone ) 
+            {
+            // if original notification cannot be accessed there is no way
+            // to check the notification
+            tEntry = iServerEntry->Entry();
+
+            if ( tEntry.Parent() == iMmsSettings->MMBoxFolder() )
+                {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- check if duplicate is found" ) );
+    #endif
+                // parent is mmbox folder.
+                CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+                CleanupStack::PushL( mmsHeaders ); 
+                CMsvStore* store = iServerEntry->ReadStoreL();
+                CleanupStack::PushL( store );           
+                mmsHeaders->RestoreL( *store );
+                CleanupStack::PopAndDestroy( store );
+                store = NULL;
+
+                TMsvId duplicate = KMsvNullIndexEntryId;
+                FindDuplicateNotificationL( KMsvGlobalInBoxIndexEntryIdValue,
+                    *mmsHeaders, duplicate );
+                    
+                if ( duplicate != KMsvNullIndexEntryId )
+                    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- duplicate found" ) );
+    #endif
+                    if ( iServerEntry->SetEntry( duplicate ) == KErrNone )
+                        {
+                        // Mark duplicate, if it is free for a new operation
+                        TMsvEntry dupEntry = iServerEntry->Entry();
+
+                        if ( FreeNotification( dupEntry, KMmsOperationDelete ) )
+                            {
+    #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- Marking duplicate" ) );
+    #endif
+                            MarkNotificationOperationReserved( dupEntry, KMmsOperationDelete );
+                        
+                            iServerEntry->ChangeEntry( dupEntry );
+
+                            // Set duplicate as related entry to the original notification
+                            if ( iServerEntry->SetEntry( iSelection->At( j ) ) == KErrNone )
+                                {
+                                tEntry = iServerEntry->Entry();
+                                tEntry.SetReadOnly( EFalse );
+                                iServerEntry->ChangeEntry( tEntry );
+
+                                store = iServerEntry->EditStoreL();
+                                CleanupStack::PushL( store );
+                                mmsHeaders->RestoreL( *store );
+
+                                mmsHeaders->SetRelatedEntry( duplicate );
+                                mmsHeaders->StoreL( *store );
+                                store->CommitL();
+                                CleanupStack::PopAndDestroy( store );
+                                store = NULL;
+                                }
+                            }
+                        else
+                            {
+                            // duplicate is not free, drop the original from iSelection. 
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "- Duplicate is not free, drop the original notification from selection" ) );
+    #endif
+                            iSelection->Delete( j );
+                            }
+                        }
+                    }
+                CleanupStack::PopAndDestroy( mmsHeaders );
+                }
+            }
+        }
+    
+    // iSelection contains notifications that are deleted from mmbox
+    // Mark notifications as "deleting operation going on"
+
+    for ( TInt k = iSelection->Count()-1; k >= 0; k--  )
+        {
+        if ( iServerEntry->SetEntry( iSelection->At( k ) ) == KErrNone )
+            {
+            tEntry = iServerEntry->Entry();
+    #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L( "- reserve notif for deletion" ) );
+    #endif
+
+            // Mark all remaining notifications as operation-ongoing
+            // operation is from now on delete
+            MarkNotificationOperationReserved( tEntry, KMmsOperationDelete );
+            
+            tEntry.SetReadOnly( EFalse );   
+            iServerEntry->ChangeEntry( tEntry );
+            }
+        }
+    // 
+    // If remote delete is required, creating PDU to be sent
+    //
+    if( ( iDeleteType != EMmsDeleteNotificationOnly ) && 
+        ( iSelection->Count() > 0 ) )
+        {
+#ifndef _NO_MMSS_LOGGING_
+TMmsLogger::Log( _L( "- creating PDU" ) );
+#endif
+        //
+        // Create headers structure
+        //
+        // iMmsRequestHeaders is a member that has been created in the constructor
+        // And Reset in the StartL function
+
+        // MessageType
+        iMmsRequestHeaders->SetMessageType( KMmsMessageTypeMBoxDeleteReq );
+
+        // TransactionId
+        TBufC8<KMMSMAXTIDLENGTH> tid;
+        tid.Des().NumUC( AllocateTID(), EHex );
+        iMmsRequestHeaders->SetTidL( tid );
+
+        //
+        // Content-Location array
+        // Loop through selection and put all content locations into array
+        //
+        CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+        CleanupStack::PushL( mmsHeaders ); // ***
+        for( TInt i = iSelection->Count() - 1; i >= 0; i-- )
+            {
+            // Get entry
+            if ( iServerEntry->SetEntry( iSelection->At( i ) ) == KErrNone )
+                {
+                // Get read-only message store
+                CMsvStore* store = iServerEntry->ReadStoreL();
+                CleanupStack::PushL( store ); // ***
+                // Restore all parts of multimedia message
+                mmsHeaders->RestoreL( *store );
+
+                // Add array to headers
+                iMmsRequestHeaders->MMBoxMessageHeadersL().ContentLocationList()
+                    .AppendL( mmsHeaders->ContentLocation() );
+                CleanupStack::PopAndDestroy( store );
+                }
+            }
+        CleanupStack::PopAndDestroy( mmsHeaders );
+
+        //
+        // Encode the PDU
+        //
+        iEncoder->EncodeHeadersL( *iMmsRequestHeaders, *iEncodeBuffer );
+        }
+
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    FallThrough();
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::ConnectToIAPL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::ConnectToIAPL()
+    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsDeleteOperation::ConnectToIAPL") );
+    #endif
+
+    if( iDeleteType == EMmsDeleteNotificationOnly || iSelection->Count() == 0 )
+        {
+        FallThrough();
+        }
+    else 
+        {
+        CMmsBaseOperation::ConnectToIAPL();
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::InitializeSessionL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::InitializeSessionL()
+    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsDeleteOperation::InitializeSessionL") );
+    #endif
+
+    if( iDeleteType == EMmsDeleteNotificationOnly || iSelection->Count() == 0 )
+        {
+        FallThrough();
+        }
+    else 
+        {
+        CMmsBaseOperation::InitializeSessionL();
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::SubmitTransactionL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::SubmitTransactionL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L("CMmsDeleteOperation::SubmitTransactionL"));
+#endif
+    //
+    // Maybe networking not needed at all
+    // 
+    if( iDeleteType == EMmsDeleteNotificationOnly || iSelection->Count() == 0 )
+        {
+        FallThrough();
+        return;
+        }
+        
+    // This check is needed only when running tests in local mode
+    // if length of URI is 0, Symbian code will panic    
+    if ( !iUri )
+        {
+        iError = KMmsErrorNoURI1;
+        }
+    else if ( iUri->Des().Length() == 0 )
+        {
+        iError = KMmsErrorNoURI1;
+        }
+    else
+        {
+        // keep LINT happy
+        }
+
+    //
+    // Networking is needed. Is connection open.
+    //
+    if ( !iConnected )
+        {
+        if ( iError == KErrNone )
+            {
+            iError = KErrCouldNotConnect;
+            }
+        }
+        
+    //
+    // If something has gone wrong, just fall through
+    // 
+    if ( iError != KErrNone )
+        {
+        FallThrough();
+        return;
+        }
+
+    //
+    // Send
+    //
+    iMmsSession->SendMessageL(
+        iUri->Des(),
+        *iEncodeBuffer,
+        *iEncoder,
+        *iDecoder,
+        iStatus );
+    SetActive();
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::DecodeResponseL()
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::DecodeResponseL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "CMmsDeleteOperation::DecodeResponseL()" ) );
+#endif
+
+    if( iDeleteType != EMmsDeleteNotificationOnly && iSelection->Count() > 0 )
+        {
+        // iError is checked in base class method.
+        CMmsBaseOperation::DecodeResponseL();
+        }
+    else
+        {
+        FallThrough();
+        }
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::UpdateEntryStatusL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::UpdateEntryStatusL()
+    {
+#ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "CMmsDeleteOperation::UpdateEntryStatusL()" ) );
+    TMmsLogger::Log( _L( "- Number of ids in iSelection: %d" ), iSelection->Count() );
+#endif
+
+    if( iDeleteType == EMmsDeleteNotificationOnly || iSelection->Count() == 0 )
+        {
+        FallThrough();
+        return;
+        }
+                
+    //
+    // If error has occurred and there is nothing received from the network,
+    // just correcting the flags in the notification entries as they were before.
+    //
+    if( iError != KErrNone )
+        {
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L( "- error has occurred" ) );
+        #endif
+        MarkSelectionAsFailed();
+        FallThrough();
+        return;
+        }
+    //
+    // Following is the the default behaviour: no errors, response received
+    //
+    else
+        {
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L( "- no errors" ) );
+        #endif
+
+        //
+        // Get delete result array from response
+        //
+        const RPointerArray<CMmsDeleteResultArray>& resultArray
+            = iResponse->DeleteResultArray();
+        #ifndef _NO_MMSS_LOGGING_
+        TMmsLogger::Log( _L( "- resultarray length: %d" ), iResponse->DeleteResultArray().Count() );
+        #endif
+
+        //
+        // Make overall check for the response before checking each entry separately
+        // First, messagetype
+        //
+        if( iResponse->MessageType() != KMmsMessageTypeMBoxDeleteConf )
+            {
+            #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L( "- ERROR: Response has wrong message type!" ) );
+            #endif
+            MarkSelectionAsFailed();
+            FallThrough();
+            return;
+            }
+        // Second, if result array contains status Unsupported-Message with no
+        // related Content-Location, the transaction is interpreted as failed.
+        for( TInt j = 0; j < resultArray.Count(); j++ )
+            {
+            if( resultArray[j]->ContentLocation().Length() == 0 && 
+                resultArray[j]->ResponseStatus() == KMmsErrorStatusUnsupportedMessage )
+                {
+                // If array contains item that has no Content-Location,
+                // something is wrong
+                #ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L( "- Response contains response-status with no corresponding ContentLocation!" ) );
+                TMmsLogger::Log( _L( "  Interpreting this as delete failure." ) );
+                #endif
+                MarkSelectionAsFailed();
+                FallThrough();
+                return;
+                }
+            }
+
+        //
+        // Moving from response level checks into entry level checks...
+        //
+        // Loop through iSelection to separate failed and successful ones
+        // (contains notifications that were sent to network)
+        //
+        CMmsHeaders* mmsHeaders = CMmsHeaders::NewL( iMmsSettings->MmsVersion() );
+        CleanupStack::PushL( mmsHeaders );
+        for( TInt i = iSelection->Count(); i > 0; i-- )
+            {
+            #ifndef _NO_MMSS_LOGGING_
+            TMmsLogger::Log( _L( "- looping in iSelection[%d]" ), i-1 );
+            #endif
+            // Get Content-location of this notification
+            if ( iServerEntry->SetEntry( iSelection->At( i-1 ) ) == KErrNone )
+                {
+                CMsvStore* store = iServerEntry->ReadStoreL();
+                CleanupStack::PushL( store );
+                mmsHeaders->RestoreL( *store );
+                CleanupStack::PopAndDestroy( store );
+                store = NULL;
+                #ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L( "- store read" ) );
+                #endif            
+                TPtrC8 pContentLocation = mmsHeaders->ContentLocation();
+                TMsvId duplicate = mmsHeaders->RelatedEntry();
+
+                //
+                // Search for the same content-location from response PDU
+                // (if it is found, it's mmbox delete has failed)
+                //
+                TBool bMmboxDeleteSucceeded = ETrue;
+                for ( TInt j = 0; j < resultArray.Count(); j++ )
+                    {
+                    // Check match
+                    #ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L( "- looping in resultArray[%d]" ), j );
+                    #endif
+                    if( resultArray[j]->ContentLocation().Compare( pContentLocation ) == 0 )
+                        {
+                        // Get response status that will be investigated next
+                        TInt32 responseStatus = resultArray[j]->ResponseStatus();
+                        #ifndef _NO_MMSS_LOGGING_
+                        TMmsLogger::Log( _L( "- Match found. X-Mms-Response-Status == %d" ), responseStatus );
+                        #endif
+                        // Found a match, now check the reason
+                        if( responseStatus != KMmsStatusOk &&
+                            responseStatus != KMmsErrorMessageNotFound && // this should not be used by the server
+                            responseStatus != KMmsErrorPermanentMessageNotFound )
+                            {
+                            #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- delete did not succeed for this notif" ) );
+                            #endif
+                            // This entry failed, removing it from iSelection
+                            iSelection->Delete( i-1 );
+                            bMmboxDeleteSucceeded = EFalse;
+
+                            // Notification will not be deleted any longer regardless of iDeleteType
+                            // Correcting the notification entry
+                            // StoredInMMBox flag value not changed.
+                            #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- clearing entry flags" ) );
+                            #endif
+
+                            // if the original notification is in mmbox folder and a duplicate is found,
+                            // mark the status of the duplicate notification too. 
+
+                            if ( duplicate != KMsvNullIndexEntryId &&
+                                iServerEntry->Entry().Parent() == iMmsSettings->MMBoxFolder() )
+                                {
+                                #ifndef _NO_MMSS_LOGGING_
+                                TMmsLogger::Log( _L(
+                                    "- duplicate exists and original notification is in mmbox folder" )
+                                    );
+                                #endif
+                                // Clear related entry from the original notification
+                                // and mark the duplicate as failed
+                                TRAP_IGNORE( MarkDuplicateL(
+                                    EMmsNotificationOperationFailed, *iServerEntry ) );
+                                }
+
+                            // Mark original notification. iServerEntry still points to it
+                            TMsvEntry tEntry = iServerEntry->Entry();
+                            MarkNotificationOperationFailed( tEntry );
+                            tEntry.SetReadOnly( ETrue );
+                            iServerEntry->ChangeEntry( tEntry );
+                            #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- original marked failed" ) );
+                            #endif
+                            }
+                        }
+                    } // inner for loop (resultArray)
+
+                // Has the current entry been deleted from mmbox...
+                if( bMmboxDeleteSucceeded )
+                    {
+                    #ifndef _NO_MMSS_LOGGING_
+                    TMmsLogger::Log( _L( "- this notification was deleted from mmbox" ) );
+                    #endif
+                    
+                    if ( iServerEntry->SetEntry( iSelection->At( i-1 ) ) == KErrNone )
+                        {
+                        // if notification is in inbox, check if a duplicate exits in mmbox folder
+                        if ( iServerEntry->Entry().Parent() == KMsvGlobalInBoxIndexEntryIdValue )
+                            {
+                            TMsvId mmboxFolder = iMmsSettings->MMBoxFolder();
+                            if ( mmboxFolder != KMsvNullIndexEntryId )
+                                {
+                                #ifndef _NO_MMSS_LOGGING_
+                                TMmsLogger::Log( _L( "- original notification is in inbox" ) );
+                                TMmsLogger::Log( _L( "- finding duplicate from mmbox inbox" ) );
+                                #endif
+                                FindDuplicateNotificationL( mmboxFolder, *mmsHeaders, duplicate );
+                                }
+                            }
+                        
+                        // if duplicate exits, mark it as "deleted successfully from mmbox"
+                        if ( duplicate != KMsvNullIndexEntryId )
+                            {
+                            #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- duplicate exists" ) );
+                            #endif
+                            
+                            // iServerEntry should still be pointing to the original notification
+                            
+                            // Clear related entry from the original notification
+                            // and mark the duplicate as "deleted from mmbox"
+                            TRAP_IGNORE( MarkDuplicateL( EMmsDeletedFromMmbox, *iServerEntry ) )
+                            }
+
+                        // Should notification also be deleted...
+                        if( iDeleteType == EMmsDeleteBoth )
+                            {
+                            #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- about to delete notif entry" ) );
+                            #endif
+                            DeleteNotificationEntryL();
+                            }
+                        else // deletetype not equal to delete-both
+                            {
+                            #ifndef _NO_MMSS_LOGGING_
+                            TMmsLogger::Log( _L( "- clearing notif flags" ) );
+                            #endif
+                            TMsvEntry tEntry = iServerEntry->Entry();
+                            tEntry.iMtmData2 &= ~KMmsStoredInMMBox;         // not-stored-in-mmbox
+                            tEntry.iMtmData2 &= ~KMmsNewOperationForbidden; // operations allowed
+                            tEntry.iMtmData2 &= ~KMmsOperationOngoing;      // not ongoing
+                            tEntry.iMtmData2 |= KMmsOperationFinished;      // finished
+                            tEntry.iMtmData2 &= ~KMmsOperationResult;       // OK
+                            tEntry.SetReadOnly( ETrue );
+                            iServerEntry->ChangeEntry( tEntry );
+                            }
+                        }
+                    }
+                }
+            } // outer for loop (iSelection)
+        CleanupStack::PopAndDestroy( mmsHeaders );
+        }
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    FallThrough();    
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::DeleteNotificationEntryL
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::DeleteNotificationEntryL()
+    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "CMmsDeleteOperation::DeleteNotificationEntryL()" ) );
+    #endif
+    // Get indexentry
+    TMsvEntry tEntry = iServerEntry->Entry(); 
+    TInt error = iServerEntry->SetEntry( tEntry.Parent());
+    if ( error == KErrNone )
+        {
+        // Can delete entry only if setting entry to parent was successful
+        iServerEntry->DeleteEntry( tEntry.Id() );        
+        }
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+    }
+
+// ---------------------------------------------------------
+// CMmsDeleteOperation::MarkSelectionAsFailed
+//
+// ---------------------------------------------------------
+//
+void CMmsDeleteOperation::MarkSelectionAsFailed()
+    {
+    #ifndef _NO_MMSS_LOGGING_
+    TMmsLogger::Log( _L( "CMmsDeleteOperation::MarkSelectionAsFailed()" ) );
+    #endif
+
+    // Loop through iSelection
+    for( TInt i = iSelection->Count(); i > 0; i-- )
+        {
+        TInt error = KErrNone;
+        error = iServerEntry->SetEntry( iSelection->At( i-1 ) );
+        if ( error == KErrNone )
+            {
+            // If notification in iSelection is in mmbox folder, mark the
+            // possible duplicate notification in inbox too. 
+            if ( iServerEntry->Entry().Parent() == iMmsSettings->MMBoxFolder() )
+                {
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L( "- check possible duplicate" ) );
+#endif
+                TRAP ( error, MarkDuplicateL( EMmsNotificationOperationFailed, *iServerEntry ) );
+#ifndef _NO_MMSS_LOGGING_
+                TMmsLogger::Log( _L("Trap failed: error %d "), error );
+#endif
+                }
+
+            // Mark the original notification in selection
+            // MarkDuplicateL does not mess up the original context of iServerEntry
+            TMsvEntry tEntry = iServerEntry->Entry();
+            MarkNotificationOperationFailed( tEntry );
+            tEntry.SetReadOnly( ETrue );
+            error = iServerEntry->ChangeEntry( tEntry );
+#ifndef _NO_MMSS_LOGGING_
+            if( error != KErrNone )
+                {
+                TMmsLogger::Log( _L( "ERROR: ChangeEntry() failed" ) );
+                }
+            else
+                {
+                TMmsLogger::Log( _L( "- selection[%d] flags are cleared" ), i );
+                }
+#endif
+            }
+        }
+    iServerEntry->SetEntry( KMsvNullIndexEntryId );
+
+    }
+
+// ================= OTHER EXPORTED FUNCTIONS ==============
+
+//  End of File