ncdengine/engine/transport/src/catalogssmssender.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ncdengine/engine/transport/src/catalogssmssender.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,712 @@
+/*
+* Copyright (c) 2006 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:  
+*
+*/
+
+
+#include <smscmds.h>
+#include <txtrich.h>
+#include <smsclnt.h>
+#include <smuthdr.h>
+#include <mtclreg.h>
+
+#include "catalogssmsoperationimpl.h"
+#include "catalogssmssender.h"
+#include "catalogsdebug.h"
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Creator
+// ---------------------------------------------------------------------------
+//
+CCatalogsSmsSender* CCatalogsSmsSender::NewL( CCatalogsSmsOperation& aObserver )
+    {
+    CCatalogsSmsSender* self = new( ELeave ) CCatalogsSmsSender( aObserver );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Destructor
+// ---------------------------------------------------------------------------
+//
+CCatalogsSmsSender::~CCatalogsSmsSender()
+    {
+    DLTRACEIN(( KNullDesC() ));
+    CancelOperation();
+    Cleanup();
+    DLTRACEOUT(( KNullDesC() ));
+    }
+
+// ---------------------------------------------------------------------------
+// Starts sending the message
+// ---------------------------------------------------------------------------
+//        
+void CCatalogsSmsSender::StartL( const TDesC& aRecipient, 
+    const TDesC& aBody )
+    {  
+    DLTRACEIN(( KNullDesC() ));
+
+    if( iSmsState != ECatalogsSmsStateIdle &&
+        iSmsState != ECatalogsSmsStateSessionReady &&
+        iSmsState != ECatalogsSmsStateStarting )
+        {
+        User::Leave( KErrInUse );
+        }
+
+    delete iRecipient;
+    iRecipient = 0;
+    delete iBody;
+    iBody = 0;
+    
+    // Copy recipient and body
+    iRecipient = aRecipient.AllocL();
+    iBody = aBody.AllocL();
+    
+    // Open a session to the message server.
+    iSession = CMsvSession::OpenAsyncL( *this );
+    iSmsState = ECatalogsSmsStateStarting;    
+    }
+
+
+// ---------------------------------------------------------------------------
+// Cancel operation
+// ---------------------------------------------------------------------------
+//        
+void CCatalogsSmsSender::CancelOperation()
+    {
+    if ( !iCancelled ) 
+        {
+        
+        DLTRACEIN(( KNullDesC() ));
+        iCancelled = ETrue; 
+        // Cancel the current asynchronous operation if any
+        if( iSmsState == ECatalogsSmsStateIdle || 
+            iSmsState == ECatalogsSmsStateSessionReady ||
+            iSmsState == ECatalogsSmsStateStarting ) 
+            {
+            Cleanup();
+            iObserver.HandleSmsSenderEvent( KErrCancel );
+            }
+        
+        else if( iSmsState == ECatalogsSmsStateMoving || 
+            iSmsState == ECatalogsSmsStateSending )
+            {        
+            if ( iOp ) 
+                {
+                iOp->Cancel();
+                }
+            
+            TRAPD( err, FinishMessageL() );    
+            if ( err != KErrNone ) 
+                {
+                // Add error handling
+                }
+                
+            DLTRACE( ( _L("FinishMessageL failed: %i"), err ) );
+            }
+        Cancel();            
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// Creates the message
+// ---------------------------------------------------------------------------
+//            
+void CCatalogsSmsSender::CreateMessageL()
+    {
+    DLTRACEIN(( KNullDesC() ));
+    // We get a MtmClientRegistry from our session
+    // this registry is used to instantiate new mtms.
+    
+    // This function should be called only once during the life cycle 
+    // of an CCatalogsSmsSender object. Thus there is no need to delete
+    // member variables before assigning them values.
+    iMtmRegistry = CClientMtmRegistry::NewL( *iSession );
+    
+
+    // Create a new message entry.
+
+    DLTRACE( ( _L("Creating message entry") ) );
+    // message type is SMS
+    iMsvEntry.iMtm = KUidMsgTypeSMS;                         
+    // this defines the type of the entry: message
+    iMsvEntry.iType = KUidMsvMessageEntry;                   
+    // ID of local service ( containing the standard folders )
+    iMsvEntry.iServiceId = KMsvLocalServiceIndexEntryId;     
+    // set the date of the entry to home time
+    iMsvEntry.iDate.HomeTime();                              
+    // a flag that this message is in preparation
+    iMsvEntry.SetInPreparation( ETrue );                     
+
+    //
+    // Create the entry in the Drafts folder.
+    //
+    CMsvEntry* entry =
+        CMsvEntry::NewL( *iSession,
+                         KMsvDraftEntryIdValue,
+                         TMsvSelectionOrdering() );
+    CleanupStack::PushL( entry );
+
+    entry->CreateL( iMsvEntry );
+    CleanupStack::PopAndDestroy( entry );
+
+    DLTRACE( ( _L("Creating a new MTM handle") ) );
+    // Create a new mtm to handle this message ( 
+    // in case our own mtm is in use)
+    iSmsMtm =
+        static_cast<CSmsClientMtm*>( iMtmRegistry->NewMtmL( iMsvEntry.iMtm ) );
+    
+
+    iSmsMtm->SwitchCurrentEntryL( iMsvEntry.Id() );
+
+    
+    DLTRACE( ( _L("Set body") ) );
+    // We get the message body from Mtm and insert a bodytext
+    CRichText& mtmBody = iSmsMtm->Body();
+    mtmBody.Reset();
+
+    // Set the body text.
+    mtmBody.InsertL( 0, *iBody );
+
+    // Set description equal to the message. Without this 9210 sms browser
+    // won't show any preview text when browsing messages.
+    iMsvEntry.iDescription.Set( *iBody );
+
+
+    DLTRACE( ( _L("Set recipient") ) );        
+    // set iRecipient into the Details of the entry
+    iMsvEntry.iDetails.Set( *iRecipient );  // set recipient info in details
+    iMsvEntry.SetInPreparation( EFalse );  // set inPreparation to false
+
+    // set the sending state ( immediately )
+    iMsvEntry.SetSendingState( KMsvSendStateWaiting ); 
+    
+    // set time to Home Time  
+    iMsvEntry.iDate.HomeTime();                        
+
+    DLTRACE( ( _L("Set SMS setting") ) );
+    iSmsMtm->RestoreServiceAndSettingsL();
+
+    // CSmsHeader encapsulates data specific for sms messages,
+    // like service center number and options for sending.
+    CSmsHeader& header = iSmsMtm->SmsHeader();
+    CSmsSettings* sendOptions = CSmsSettings::NewL();
+
+    CleanupStack::PushL( sendOptions );
+    
+    // restore existing settings
+    sendOptions->CopyL( iSmsMtm->ServiceSettings() ); 
+
+    // set send options
+    
+    // set to be delivered immediately
+    sendOptions->SetDelivery( ESmsDeliveryImmediately );      
+    header.SetSmsSettingsL( *sendOptions );
+    CleanupStack::PopAndDestroy( sendOptions );
+
+    // let's check if there's sc address
+    if ( header.Message().ServiceCenterAddress().Length() == 0 )
+        {
+        DLTRACE( ( _L("No SC address") ) );
+        
+        // no, there isn't. We assume there is at least one sc number set 
+        // and use the default SC number.
+        CSmsSettings* serviceSettings = &( iSmsMtm->ServiceSettings() );
+
+        // if number of scaddresses in the list is null
+
+        if ( serviceSettings->ServiceCenterCount() == 0 )
+            {
+            // No service center address, query from the user should be here
+            // if supported
+            DLTRACE( ( _L("Definitely no SC address") ) );
+            }
+        else
+            {
+            DLTRACE( ( _L("Using default SC") ) );
+            // set sc address to default.
+            CSmsNumber* sc = CSmsNumber::NewL();
+            CleanupStack::PushL( sc );
+            sc->SetAddressL( serviceSettings->GetServiceCenter( 
+                serviceSettings->DefaultServiceCenter() ).Address() );
+                
+            header.Message().SetServiceCenterAddressL( sc->Address() );
+            CleanupStack::PopAndDestroy( sc );
+            }
+        }
+
+    DLTRACE( ( _L("Add recipient") ) );
+    // Add our recipient to the list, takes in two TDesCs, 
+    // first is real address and second is an alias
+    // works also without the alias parameter.
+    iSmsMtm->AddAddresseeL( *iRecipient, iMsvEntry.iDetails );
+
+    DLTRACE( ( _L("Save message") ) );
+    // save message
+    CMsvEntry& newEntry = iSmsMtm->Entry();
+
+    // make sure that we are handling the right entry
+    newEntry.ChangeL( iMsvEntry ); 
+    iSmsMtm->SaveMessageL();     // closes the message
+
+    DLTRACE( ( _L("Start moving the entry to outbox") ) );
+    // This moves the message entry to outbox, we'll schedule it 
+    // for sending after this.
+    TMsvSelectionOrdering sort;
+    sort.SetShowInvisibleEntries( ETrue );
+
+    // Take the current parent.
+    iParentEntry =
+        CMsvEntry::NewL( *iSession, iMsvEntry.Parent(), sort );
+
+
+    iSmsState = ECatalogsSmsStateMoving;
+
+    //if ( !iCancelled ) 
+        {
+        
+        iOp = iParentEntry->MoveL( iMsvEntry.Id(), KMsvGlobalOutBoxIndexEntryId, 
+            iStatus );
+
+        SetActive();
+        DASSERT( iStatus.Int() == KRequestPending );
+        }
+/*
+    else 
+        {
+        DLTRACE( ( _L("Synch Move") ) );
+        // Do some hideous Symbian magic.
+        CMsvOperationWait* wait = CMsvOperationWait::NewLC();
+        wait->Start();
+
+        iOp = iParentEntry->MoveL( iMsvEntry.Id(), KMsvGlobalOutBoxIndexEntryId, 
+            wait->iStatus );
+        CleanupStack::PopAndDestroy( wait );
+        }
+  */  
+    }
+
+
+// ---------------------------------------------------------------------------
+// Sends the message
+// ---------------------------------------------------------------------------
+//        
+void CCatalogsSmsSender::SendMessageL()
+    {
+    DLTRACEIN(( KNullDesC() ));
+    
+    TMsvLocalOperationProgress prog = McliUtils::GetLocalProgressL( *iOp );
+    User::LeaveIfError( prog.iError );
+
+    iMovedId = prog.iId;
+
+    // Delete unnecessary objects
+    delete iParentEntry;
+    iParentEntry = NULL;
+    
+    delete iOp;
+    iOp = NULL;
+
+
+    DLTRACE( ( _L("Start sending the SMS") ) );
+    // We must create an entry selection for message copies 
+    // (although now we only have one message in iSelection )
+    iSelection = new (ELeave) CMsvEntrySelection();
+
+    iSelection->AppendL( iMovedId ); // add our message to the iSelection
+
+    TBuf8<1> dummyParams;
+    
+    iSmsState = ECatalogsSmsStateSending;
+    //
+    // Initiate the send
+    
+    //if ( !iCancelled ) 
+        {
+        
+    
+        iOp = iSmsMtm->InvokeAsyncFunctionL( ESmsMtmCommandSendScheduledCopy,
+                                           *iSelection,
+                                           dummyParams,
+                                           iStatus );
+
+        SetActive();
+    
+        iObserver.HandleSmsSenderEvent( ECatalogsSmsSending );
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Finishes the send operation
+// ---------------------------------------------------------------------------
+//        
+void CCatalogsSmsSender::FinishMessageL()
+    {
+    
+    DLTRACEIN(( KNullDesC() ));
+    delete iOp;
+    iOp = NULL;
+    
+    // Check state of the SMS    
+    iSendState = KMsvSendStateUnknown;
+
+    // Trap here since switching the entry may fail if SMS has been removed
+    TRAPD( err,
+        {
+        // Check if SMS was successfully sent
+        iSmsMtm->SwitchCurrentEntryL( iMovedId );
+        } );
+
+    iSmsState = ECatalogsSmsStateDeletingSchedule;
+    
+    if ( err != KErrNone )
+        {
+
+        if ( err == KErrNotFound )
+            {
+            // SMS has been deleted, probably due to a setting 
+            // "Don't keep sent SMS:s"
+            // consider this case a successful send and continue
+            DLTRACE( ( _L("Couldn't find the SMS anymore") ) );
+            iSendState = KMsvSendStateSent;
+            }
+        
+        // Skip active scheduler and just execute the next state
+        
+        RunL();
+        }
+    else
+        {
+        DLTRACE( ( _L("Deleting SMS schedule") ) );
+        
+        CMsvEntry& cEntry = iSmsMtm->Entry();
+
+        iSendState = TMsvSendState( cEntry.Entry().SendingState() );
+        DLINFO(("iSendState: %d", iSendState ));
+        
+        TBuf8<1> dummyParams;
+        DLTRACE( ( _L("InvokeAsyncFunctionL") ) );
+        //
+        // Delete SMS schedule just in case SMS was not 
+        // successfully sent
+        //
+        if ( !iCancelled ) 
+            {            
+            iOp = iSmsMtm->InvokeAsyncFunctionL( ESmsMtmCommandDeleteSchedule,
+                                               *iSelection,
+                                               dummyParams,
+                                               iStatus );
+            
+            DLTRACE( ( _L("Activating schedule delete") ) );
+            SetActive();
+            }
+        else 
+            {
+            // When cancelling, use synchronous delete
+            DLTRACE( ( _L("Sync schedule delete") ) );
+            CMsvOperationWait* wait = CMsvOperationWait::NewLC();            
+            
+
+            iOp = iSmsMtm->InvokeAsyncFunctionL( ESmsMtmCommandDeleteSchedule,
+                                               *iSelection,
+                                               dummyParams,
+                                               wait->iStatus );
+                    
+            wait->Start();
+            CActiveScheduler::Start();
+    
+            TUint deleteScheduleResult = cEntry.Entry().SendingState();
+            DLTRACE( ( _L( "-> SMS schedule deleted, sendingState: %d" ), 
+                             deleteScheduleResult ) );
+    
+            CleanupStack::PopAndDestroy( wait ); // wait       
+            DeleteMessageL();     
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// Deletes the sent message
+// ---------------------------------------------------------------------------
+//                
+void CCatalogsSmsSender::DeleteMessageL()
+    {
+    DLTRACEIN(( KNullDesC() ));
+    CMsvEntry& cEntry = iSmsMtm->Entry();
+    TUint deleteScheduleResult = cEntry.Entry().SendingState();
+
+    delete iOp;
+    iOp = NULL;
+
+    //
+    // Delete the SMS
+    //
+    TMsvSelectionOrdering sort;
+    sort.SetShowInvisibleEntries( ETrue );
+    
+    DLTRACE( ( _L("Taking the current parent") ) );
+    // Take the current parent.
+    iParentEntry = CMsvEntry::NewL( *iSession, cEntry.Entry().Parent(), 
+        sort );
+    
+
+    if ( !iCancelled ) 
+        {
+        // Normally we delete asynchronously
+        DLTRACE( ( _L("Deleting the SMS") ) );
+        iOp = iParentEntry->DeleteL( iMsvEntry.Id(), iStatus );
+
+        DLTRACE( ( _L("Activating delete") ) );
+        iSmsState = ECatalogsSmsStateDeletingMessage;
+        
+        SetActive();
+        }
+    else 
+        {
+        // When cancelling, delete synchronously
+        DLTRACE( ( _L("Sync SMS delete" ) ) );
+        // Do some hideous Symbian magic.
+        CMsvOperationWait* wait = CMsvOperationWait::NewLC();
+
+
+        iOp = iParentEntry->DeleteL( iMsvEntry.Id(), wait->iStatus );
+        wait->Start();
+        CActiveScheduler::Start();
+        
+        CleanupStack::PopAndDestroy( wait );
+        
+        // cleanup
+        Cleanup();
+        
+        iSmsState = ECatalogsSmsStateDone;
+        // Notify observer about cancellation or success
+        if( iCancelled ) 
+            {
+            iObserver.HandleSmsSenderEvent( KErrCancel );
+            }
+        else
+            {                    
+            iObserver.HandleSmsSenderEvent( KErrNone );
+            }
+        DLTRACE( ( _L("Sync SMS delete end" ) ) );        
+        
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// RunL
+// ---------------------------------------------------------------------------
+//
+void CCatalogsSmsSender::RunL()
+    {
+    DLTRACEIN(( "State: %d, status: %d", iSmsState, iStatus.Int() ));
+    if ( iStatus == KErrCancel ) 
+        {
+        DLTRACE( ( _L("Cancelling" ) ) );        
+        return;
+        }
+   
+    switch( iSmsState )
+        {
+        case ECatalogsSmsStateSessionReady:
+            {
+            CreateMessageL();
+            break;
+            }
+                
+        case ECatalogsSmsStateMoving:
+            {
+            SendMessageL();
+            break;
+            }
+            
+        case ECatalogsSmsStateSending:
+            {
+            FinishMessageL();
+            break;
+            }
+            
+        case ECatalogsSmsStateDeletingSchedule:
+            {
+            DeleteMessageL();
+            break;
+            }
+            
+        case ECatalogsSmsStateDeletingMessage:
+            {
+            iSmsState = ECatalogsSmsStateDone;
+            // cleanup
+            Cleanup();
+            
+            // Notify observer about cancellation or success
+            if( iCancelled ) 
+                {
+                iObserver.HandleSmsSenderEvent( KErrCancel );
+                }
+            else if( iSendState != KMsvSendStateSent )
+                {
+                // For some reason the SMS was not sent
+                iObserver.HandleSmsSenderEvent( KErrGeneral );
+                }
+            else
+                {                
+                iObserver.HandleSmsSenderEvent( KErrNone );
+                }
+            
+            break;
+            }
+            
+        default:
+            {
+            }
+        
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// DoCancel
+// ---------------------------------------------------------------------------
+//
+void CCatalogsSmsSender::DoCancel()
+    {
+    DLTRACEIN(( KNullDesC() ));
+    //CancelOperation();
+    }
+    
+
+// ---------------------------------------------------------------------------
+// Error handler
+// ---------------------------------------------------------------------------
+//
+TInt CCatalogsSmsSender::RunError( TInt aError )
+    {
+    DLTRACEIN(( KNullDesC() ));
+    // Check
+    if( aError == KErrNotFound && ( 
+        iSmsState == ECatalogsSmsStateDeletingSchedule
+        || iSmsState == ECatalogsSmsStateDeletingMessage ) )
+        {
+        iSendState = KMsvSendStateSent;
+        }
+
+    if( iCancelled ) 
+        {
+        iObserver.HandleSmsSenderEvent( KErrCancel );
+        }
+    else if( iSendState == KMsvSendStateSent )
+    // If the message was sent but some error occurred we still notify
+    // of a successful sending    
+        {
+        iObserver.HandleSmsSenderEvent( KErrNone );
+        }
+    else 
+        {    
+        iObserver.HandleSmsSenderEvent( KErrGeneral );
+        }
+        
+    return KErrNone;
+    }
+
+
+// ---------------------------------------------------------------------------
+// 
+// ---------------------------------------------------------------------------
+//
+void CCatalogsSmsSender::HandleSessionEventL( TMsvSessionEvent aEvent, 
+    TAny* /*aArg1*/, TAny* /*aArg2*/, TAny* /*aArg3*/ )
+    {
+    DLTRACEIN( ( _L("Event: %i"), aEvent ) );
+    if( iCancelled ) 
+        {
+        return;
+        }
+        
+    switch( aEvent )
+        {
+        case EMsvServerReady:
+            {
+            // Make a fake request and complete it in order to continue
+            // in RunL
+            iSmsState = ECatalogsSmsStateSessionReady;
+            CreateMessageL();
+            break;
+            }
+        
+        default:
+            {
+            }
+        
+        }
+    DLTRACEOUT( ( _L("Event: %i"), aEvent ) );
+    }
+
+
+
+// ---------------------------------------------------------------------------
+// Constructor
+// ---------------------------------------------------------------------------
+//	
+CCatalogsSmsSender::CCatalogsSmsSender( CCatalogsSmsOperation& aObserver ) : 
+    CActive( EPriorityStandard ), iObserver( aObserver )
+    {    
+    CActiveScheduler::Add(this);
+    }
+
+
+// ---------------------------------------------------------------------------
+// Cleanup
+// ---------------------------------------------------------------------------
+//	
+void CCatalogsSmsSender::Cleanup()
+    {
+    DLTRACEIN(( KNullDesC() ));
+    
+    if( iOp && iSmsState != ECatalogsSmsStateDone ) 
+        {
+        DLTRACE( ( _L("Cancelling current operation") ));
+        iOp->Cancel();
+        }
+    delete iOp;
+    iOp = NULL;
+    
+    delete iParentEntry;
+    iParentEntry = NULL;
+    
+    delete iSelection;
+    iSelection = NULL;
+    
+    delete iSmsMtm;
+    iSmsMtm = NULL;
+    
+    delete iBody;
+    iBody = NULL;
+    
+    delete iRecipient;
+    iRecipient = NULL;
+    
+    delete iMtmRegistry;
+    iMtmRegistry = NULL;
+    
+    delete iSession;
+    iSession = NULL;
+    DLTRACEOUT(( KNullDesC() ));
+    }