diff -r 000000000000 -r ba25891c3a9e ncdengine/engine/transport/src/catalogssmssender.cpp --- /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 +#include +#include +#include +#include + +#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( 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() )); + }