Categories: S60 | Symbian C++ | Messaging | SMS | Code Examples
This page was last modified 06:53, 25 June 2008.
Sending SMS in S60 3rd Edition - MTM
From Forum Nokia Wiki
SMSHandler.h
#ifndef __CSMSHANDLER_H__ #define __CSMSHANDLER_H__ // INCLUDES #include <e32base.h> #include <msvapi.h> #include <mtuireg.h> #include <txtrich.h> // CONSTANTS const TInt KBfrLength = 20; // FORWARD DECLARATIONS class CSmsAppUi; class CClientMtmRegistry; class CSmsClientMtm; // CLASS DECLARATION /** * CSmsHandler application engine class. * Takes care of sending and receiveing SMS messages using the SMS client MTM. * Interacts with the application UI class. */ class CSmsHandler : public CActive, public MMsvSessionObserver { public: // Constructors and destructor /** * NewL. * Two-phased constructor. * @param aSmsAppUi Pointer to AppUi instance. * @return Pointer to the created instance of CSmsHandler. */ static CSmsHandler* NewL( ); /** * NewLC. * Two-phased constructor. * @param aSmsAppUi Pointer to AppUi instance. * @return Pointer to the created instance of CSmsHandler. */ static CSmsHandler* NewLC(); /** * ~CSmsHandler * Destructor. */ virtual ~CSmsHandler(); public: // New functions /** * SendL. * Starts the process of creating and sending an SMS message. * @param aRecipientNumber The number of the recipent. * @param aMessageText The message text. * @return ETrue if successful, EFalse if not. */ TBool SendL( const TDesC& aRecipientNumber, const TDesC& aMessageText ); /** * ViewL. * Displays a received SMS message. */ void ViewL(); public: // Functions from base classes /** * From MMsvSessionObserver, HandleSessionEventL. * Handles notifications of events from the Message Server. * @param aEvent The event that has taken place * @param aArg1 Event type-specific argument value * @param aArg2 Event type-specific argument value * @param aArg3 Event type-specific argument value */ void HandleSessionEventL( TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* aArg3 ); protected: // Functions from base classes /** * From CActive, DoCancel. * Cancels any outstanding requests. */ void DoCancel(); /** * From CActive, RunL. * Handles an active object’s request completion event. */ void RunL(); private: // Constructors /** * CSmsHandler. * C++ default constructor. * @param aSmsAppUi Pointer to AppUi instance. */ CSmsHandler(); /** * ConstructL. * 2nd phase constructor. */ void ConstructL(); private: // New functions /** * AccessMtmL. * Access the MTM Registry and create an SMS specific Client MTM instance. */ void AccessMtmL(); /** * CreateMsgL. * Create an SMS message. * @return ETrue if successful, EFalse is unsuccessful. */ TBool CreateMsgL(); /** * ScheduleL. * Schedule an SMS message for sending. */ void ScheduleL(); /** * MessageReceivedL. * Handles a received SMS message. * @param aEntryId The message server id of the received message. */ void MessageReceivedL( TMsvId aEntryId ); /** * ValidateL. * Validate an SMS message. * @return ETrue if successful, EFalse is unsuccessful. */ TBool ValidateL(); private: // Enumeration /** * TState, enumeration for the state of the handler, used by RunL(). */ enum TState { EWaitingForMoving = 1, EWaitingForScheduling }; private: // Data /** * iState, the state of the handler. */ TState iState; /** * iSession, the contact database. * Owned by CSmsHandler object. */ CMsvSession* iSession; /** * iMtmRegistry, client MTM registry. * Owned by CSmsHandler object. */ CClientMtmRegistry* iMtmRegistry; /** * iSmsMtm, SMS specific Client MTM. * Owned by CSmsHandler object. */ CSmsClientMtm* iSmsMtm; /** * iOperation, the current message server operation. * Owned by CSmsHandler object. */ CMsvOperation* iOperation; /** * iRecipientNumber, telephone number of the recipient. */ // TBuf<EMaxTelephoneNumberLength> iRecipientNumber; TBuf<15> iRecipientNumber; /** * iMessageText, SMS message text. */ // TBuf<EMaxMessageLength> iMessageText; TBuf<160> iMessageText; /** * iSmsAppUi, application UI * Not owned by CSmsHandler object. */ CSmsAppUi* iSmsAppUi; /** * iMtmUiRegistry, User Interface MTM Registry. * Owned by CSmsHandler object. */ CMtmUiRegistry* iMtmUiRegistry; /** * iSelection, entry selection to hold received messages. * Owned by CSmsHandler object. */ CMsvEntrySelection* iSelection; /** * iNextUnread, index of the next unread message in iSelection. */ TInt iNextUnread; }; #endif // __CSMSHANDLER_H__
SMSHandler.cpp
// INCLUDE FILES #include <eikenv.h> #include <coemain.h> #include <e32std.h> #include <msvids.h> #include <msvstd.h> #include <smsclnt.h> #include <smut.h> #include <mtclreg.h> #include <txtrich.h> #include <smscmds.h> #include <mtmuibas.h> #include <mtmdef.h> #include <stringloader.h> #include "SmsHandler.h" #include "smutset.h" #include "smuthdr.h" // ============================ MEMBER FUNCTIONS =============================== // ----------------------------------------------------------------------------- // CSmsHandler::CSmsHandler() // C++ default constructor can NOT contain any code, that might leave. // ----------------------------------------------------------------------------- // CSmsHandler::CSmsHandler() : CActive( CActive::EPriorityStandard ) { CActiveScheduler::Add( this ); iNextUnread = 0; // index of next unread message in iSelection } // ----------------------------------------------------------------------------- // CSmsHandler::ConstructL() // Symbian 2nd phase constructor can leave. // ----------------------------------------------------------------------------- // void CSmsHandler::ConstructL() { // Session to message server is opened asynchronously. iSession = CMsvSession::OpenAsyncL( *this ); // Entry selection for all received messages. iSelection = new ( ELeave ) CMsvEntrySelection(); } // ----------------------------------------------------------------------------- // CSmsHandler::NewL() // Two-phased constructor. // ----------------------------------------------------------------------------- // CSmsHandler* CSmsHandler::NewL( ) { CSmsHandler* self = NewLC( ); CleanupStack::Pop( self ); return self; } // ----------------------------------------------------------------------------- // CSmsHandler::NewLC() // Two-phased constructor. // ----------------------------------------------------------------------------- // CSmsHandler* CSmsHandler::NewLC() { CSmsHandler* self = new ( ELeave ) CSmsHandler(); CleanupStack::PushL( self ); self->ConstructL(); return self; } // ---------------------------------------------------------- // CSmsHandler::~CSmsHandler() // Destructor. // ---------------------------------------------------------- // CSmsHandler::~CSmsHandler() { Cancel(); // cancel any outstanding request delete iOperation; delete iMtmUiRegistry; delete iSelection; delete iSmsMtm; delete iMtmRegistry; delete iSession; // session must be deleted last } // ----------------------------------------------------------------------------- // CSmsHandler::DoCancel() // Cancels a request. // ----------------------------------------------------------------------------- // void CSmsHandler::DoCancel() { if ( iOperation ) { iOperation->Cancel(); } } // ----------------------------------------------------------------------------- // CSmsHandler::RunL() // Handles request completion events. // ----------------------------------------------------------------------------- // void CSmsHandler::RunL() { User::LeaveIfError( iStatus != KErrNone ); // Determine the current operations progress. // ProgressL returns an 8 bit descriptor. TBufC8<KMsvProgressBufferLength> progress( iOperation->ProgressL() ); _LIT8( KCompare, "KErrNone" ); User::LeaveIfError( !progress.Compare( KCompare ) ); // The pointer to the current CMsvOperation object is no longer needed. delete iOperation; iOperation = NULL; // Determine which request has finished. switch ( iState ) { case EWaitingForMoving: // Once a message is moved to Outbox it is scheduled for sending. ScheduleL(); break; case EWaitingForScheduling: { TMsvEntry entry( iSmsMtm->Entry().Entry() ); TInt state( entry.SendingState() ); if ( state == KMsvSendStateWaiting || state == KMsvSendStateScheduled) { } break; } default: break; } } // ----------------------------------------------------------------------------- // CSmsHandler::HandleSessionEventL() // Handles notifications of events from the Message Server. // ----------------------------------------------------------------------------- // void CSmsHandler::HandleSessionEventL( TMsvSessionEvent aEvent, TAny* aArg1, TAny* aArg2, TAny* /*aArg3*/) { switch ( aEvent ) { // Session to server established case EMsvServerReady: { TMsvId serviceId( KUidMsgTypeSMS.iUid ); // SMS service id // Determine if the event was succesful. // ServiceProgress inserts TBuf8 value in progress. TBuf8<KBfrLength> progress; iSession->ServiceProgress( serviceId, progress ); _LIT8( KCompare, "KErrNone" ); if ( progress.Compare( KCompare ) ) { // Check that MtmRegistry has not already been accessed. if ( !iMtmRegistry ) { AccessMtmL(); } } break; } // A new entry has been created on the message server. case EMsvEntriesCreated: { // Entry id is obtained from the session event arguments. TMsvId* entryId = STATIC_CAST( TMsvId*, aArg2 ); // We are interested in messages that are created in Inbox. if ( *entryId != KMsvGlobalInBoxIndexEntryId ) { break; } // We take the created entries into a selection CMsvEntrySelection* newEntries = STATIC_CAST( CMsvEntrySelection*, aArg1 ); // Process each created entry. for ( TInt i( 0 ); i < newEntries->Count(); i++ ) { // We are interested in SMS messages. if ( ( iSession->GetEntryL( newEntries->At( i ) ) ) ->Entry().iMtm == KUidMsgTypeSMS ) { // Add the entry to the selection of all received messages. iSelection->AppendL( newEntries->At( i ), 1 ); // Set received messages visible. MessageReceivedL( newEntries->At( i ) ); } } break; } case EMsvCloseSession: case EMsvServerTerminated: case EMsvGeneralError: case EMsvServerFailedToStart: { // iSmsAppUi->ServerDown( aEvent ); // close application break; } // All other events are ignored. default: break; } } // ----------------------------------------------------------------------------- // CSmsHandler::AccessMtmL() // Access the MTM Registry and create a SMS specific Client MTM instance. // ----------------------------------------------------------------------------- // void CSmsHandler::AccessMtmL() { // Create an MTM Registry object. iMtmRegistry = CClientMtmRegistry::NewL( *iSession ); // Create an SMS Client MTM object. iSmsMtm = STATIC_CAST( CSmsClientMtm*, iMtmRegistry->NewMtmL( KUidMsgTypeSMS ) ); } // ----------------------------------------------------------------------------- // CSmsHandler::SendL() // Starts the process of creating and sending an SMS message. // ----------------------------------------------------------------------------- // TBool CSmsHandler::SendL( const TDesC& aRecipientNumber, const TDesC& aMessageText ) { iRecipientNumber = aRecipientNumber; iMessageText = aMessageText; if ( CreateMsgL() ) { return ETrue; } return EFalse; } // ----------------------------------------------------------------------------- // CSmsHandler::CreateMsgL() // Create an SMS message. // ----------------------------------------------------------------------------- // TBool CSmsHandler::CreateMsgL() { // Current entry is the Draft folder. iSmsMtm->SwitchCurrentEntryL( KMsvDraftEntryId ); // Create a new SMS message entry as a child of the current context. iSmsMtm->CreateMessageL( KUidMsgTypeSMS.iUid ); CMsvEntry& serverEntry = iSmsMtm->Entry(); TMsvEntry entry( serverEntry.Entry() ); CRichText& body = iSmsMtm->Body(); // the body of the message body.Reset(); // Insert the message text gotten as input from user. body.InsertL( 0, iMessageText ); // Message will be sent immediately. entry.SetSendingState( KMsvSendStateWaiting ); //Added for 3rd edition // entry.iDate.HomeTime(); // insert current time //This was causing problem:SMS stays into Outbox only. entry.iDate.UniversalTime(); // insert current time //Solution for HomeTime() //Code Ends- // Set the SMS message settings for the message. CSmsHeader& header = iSmsMtm->SmsHeader(); CSmsSettings* settings = CSmsSettings::NewL(); CleanupStack::PushL( settings ); settings->CopyL( iSmsMtm->ServiceSettings() ); // restore settings settings->SetDelivery( ESmsDeliveryImmediately ); // to be delivered immediately settings->SetDeliveryReport(ETrue); header.SetSmsSettingsL( *settings ); // new settings // Let's check if there is a service center address. if ( header.Message().ServiceCenterAddress().Length() == 0 ) { // No, there isn't. We assume there is at least one service center // number set and use the default service center number. CSmsSettings* serviceSettings = &( iSmsMtm->ServiceSettings() ); // Check if number of service center addresses in the list is null. //Changed for 3rd Edition specially // if ( !serviceSettings->NumSCAddresses() ) if ( !serviceSettings->ServiceCenterCount() ) { return EFalse; // quit creating the message } else { //Changed for 3rd Edition specially // CSmsNumber* smsCenter = &( serviceSettings->SCAddress( serviceSettings->DefaultSC() ) ); CSmsNumber* smsCenter= CSmsNumber::NewL(); CleanupStack::PushL(smsCenter); smsCenter->SetAddressL((serviceSettings->GetServiceCenter( serviceSettings->DefaultServiceCenter())).Address()); header.Message().SetServiceCenterAddressL( smsCenter->Address() ); CleanupStack::PopAndDestroy(smsCenter); } } CleanupStack::PopAndDestroy( settings ); // Recipient number is displayed also as the recipient alias. entry.iDetails.Set( iRecipientNumber ); // Add addressee. iSmsMtm->AddAddresseeL( iRecipientNumber, entry.iDetails ); // Validate message. if ( !ValidateL() ) { return EFalse; } entry.SetVisible( ETrue ); // set message as visible entry.SetInPreparation( EFalse ); // set together with the visibility flag serverEntry.ChangeL( entry ); // commit changes iSmsMtm->SaveMessageL(); // save message TMsvSelectionOrdering selection; CMsvEntry* parentEntry = CMsvEntry::NewL( iSmsMtm->Session(), KMsvDraftEntryId, selection ); CleanupStack::PushL( parentEntry ); // Move message to Outbox. iOperation =parentEntry->MoveL( entry.Id(), KMsvGlobalOutBoxIndexEntryId, iStatus ); CleanupStack::PopAndDestroy( parentEntry ); iState = EWaitingForMoving; SetActive(); return ETrue; } // ----------------------------------------------------------------------------- // CSmsHandler::ValidateL() // Validate an SMS message. // ----------------------------------------------------------------------------- // TBool CSmsHandler::ValidateL() { // Empty part list to hold the result. TMsvPartList result( KMsvMessagePartNone ); // Validate message body. result = iSmsMtm->ValidateMessage( KMsvMessagePartBody ); if ( result != KMsvMessagePartNone ) { return EFalse; } // Validate recipient. result = iSmsMtm->ValidateMessage( KMsvMessagePartRecipient ); if ( result != KMsvMessagePartNone ) { return EFalse; } return ETrue; } // ----------------------------------------------------------------------------- // CSmsHandler::ScheduleL() // Schedule an SMS message for sending. // ----------------------------------------------------------------------------- // void CSmsHandler::ScheduleL() { CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection; CleanupStack::PushL( selection ); selection->AppendL( iSmsMtm->Entry().EntryId() ); // add message to selection // Add entry to task scheduler. TBuf8<1> dummyParams; // dummy parameters needed for InvokeAsyncFunctionL iOperation = iSmsMtm->InvokeAsyncFunctionL( ESmsMtmCommandScheduleCopy, *selection, dummyParams, iStatus ); CleanupStack::PopAndDestroy( selection ); iState = EWaitingForScheduling; SetActive(); } // ----------------------------------------------------------------------------- // CSmsHandler::MessageReceivedL() // Handles a received SMS message. // ----------------------------------------------------------------------------- // void CSmsHandler::MessageReceivedL( TMsvId aEntryId ) { CMsvEntry* serverEntry = iSession->GetEntryL( aEntryId ); // current entry CleanupStack::PushL( serverEntry ); TMsvEntry entry = serverEntry->Entry(); // currently handled message entry entry.SetNew( ETrue ); entry.SetUnread( ETrue ); entry.SetVisible( ETrue ); serverEntry->ChangeL( entry ); // commit changes //iSmsAppUi->MessageReceived(); // let UI know we have received a message CleanupStack::PopAndDestroy( serverEntry ); } // ----------------------------------------------------------------------------- // CSmsHandler::ViewL() // Dispalys a received SMS message. // ----------------------------------------------------------------------------- // void CSmsHandler::ViewL() { // There is an own registry for UI MTM's. iMtmUiRegistry = CMtmUiRegistry::NewL( *iSession ); // We are interested in the next unread message. TMsvId entryId( iSelection->At( iNextUnread ) ); CMsvEntry* serverEntry = iSession->GetEntryL( entryId ); CleanupStack::PushL( serverEntry ); // Create new MTM. CBaseMtm* clientMtm = iMtmRegistry->NewMtmL( serverEntry->Entry().iMtm ); CleanupStack::PushL( clientMtm ); clientMtm->SwitchCurrentEntryL( serverEntry->EntryId() ); // Check if there are more unreads messages. iNextUnread++; if ( iNextUnread < iSelection->Count() ) { // iSmsAppUi->MessageReceived(); // still messages to read } else { // iSmsAppUi->NoMoreUnread(); // no more messages to read } TMsvEntry entry( serverEntry->Entry() ); entry.SetNew( EFalse ); // message is no longer new entry.SetUnread( EFalse ); // message is no longer unread serverEntry->ChangeL( entry ); // commit changes CBaseMtmUi* ui = iMtmUiRegistry->NewMtmUiL( *clientMtm ); // UI MTM for SMS CleanupStack::PushL( ui ); // Display the SMS using the UI MTM. iOperation = ui->ViewL( iStatus ); CleanupStack::PopAndDestroy( 3 ); // ui, clientMtm, serverEntry SetActive(); }
Now perform the following steps:
- Copy SmsHandler.h and SmsHandler.cpp in your own project.
- Give entry SOURCE SmsHandler.cpp in your .mmp file.
- Add appropriate libraries in your .mmp file. For example:
//Libraries included for SMS support LIBRARY msgs.lib smcm.lib gsmu.lib mtur.lib
- Open your CyrAppView.cpp file.
- Include SmsHandler.h in your Container class.
- Define object of CSmshandler class in your CYrAppView.h class. For example:
CSmsHandler* iSmsHandler;
- Open your CYrAppView.cpp file.
- Initialize iSmsHandler. For example:
void CYrAppView::ConstructL( const TRect& aRect ) { // Create a window for this application view CreateWindowL(); // Set the windows size SetRect( aRect ); // Activate the window, which makes it ready to be drawn ActivateL(); iSmsHandler = CSmsHandler::NewL(); }
Now implement SMS sending call like: where MySendMessage() is your own defined function - just for sending SMS
void CYrAppView::MySendMessage() { TBuf<160> SMSText,PhoneNumber; TBuf<15> PhoneNumber; SMSText.Copy(_L("Test Message")); PhoneNumber.Copy(_L("99999999999")); //Replace your desired number here iSmsHandler->SendL( PhoneNumber, SMSText) ; }
Finally call it like in one of the commands in CyrAppUi.cpp. For example:
void CYrAppUi::HandleCommandL( TInt aCommand ) { switch( aCommand ) { case EEikCmdExit: case EAknSoftkeyExit: Exit(); break; case EYrCommand1: { iAppView->MySendMessage(); } break; default: Panic( EYrUi ); break; } }
NOTE: You need ReadUserData WriteUserData NetworkServices capabilities.
Reference: smssend example from S60 2nd FP2 SDK.
A working application can be downloaded from here: Image:SMS3rd.zip
| Related Discussions | ||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Recording audio in AMR format, SDK 3rd | handle_cn | General Symbian C++ | 12 | 2007-11-03 08:16 |
| py2sis Environment Veriable | Faisal Rehman | Python | 24 | 2008-07-19 17:29 |
| Starting with programming | Genom | Symbian Tools & SDKs | 3 | 2007-02-02 08:23 |
| Background SMS Send s60 3rd Ed | jamespoh | Symbian Tools & SDKs | 9 | 2007-03-05 06:58 |
| Send SMS without put it in outbox/sent folder | cindul | Symbian Networking & Messaging | 1 | 2006-07-18 15:01 |
