http://www.developer.com/

Back to article

BREW's Short Messaging Service Interfaces: Which to Use and Why


October 12, 2005

If you've downloaded the latest QUALCOMM BREW SDKs (see the resources section) and reviewed the documentation, you doubtless saw a bevy of new Short Messaging Service (SMS)-related interfaces including ISMS, ISMSMsg, ISMSNotifier, and ISMSStorage. If so, you're probably wondering: What do these classes offer that ITAPI doesn't, and why would you use them? You're not alone. In this article, I'll review how SMS sends and receives works in BREW, and explain why there are all of these new classes around the SMS protocol. Fortunately, as you will see, most applications can continue to use the existing ITAPI interfaces for managing SMS; the new interfaces are for a few very specific purposes.

The ITAPI Interface and SMS

For time immemorial (BREW time, anyway), the ITAPI interface has been your pathway to sending and receiving SMS. Sending is trivial, thanks to the ITAPI_SendSMS method, which takes the destination address, message, and an optional class ID to which the message should be delivered as well as a status callback, like this:

   ITAPI_SendSMS (pITapi, "8885551212", "Hello World",
                  0,MOSMSNotify, pThis );
void MOSMSNotify( void *p, int result )
{
   if ( result == AEEMOSMS_ERR_NO_ERR )
      DBGPRINTF("Success!");
 5  else
      DBGPRINTF("Failure &d", result );
}

It's up to your application logic to determine how best to handle errors; some error codes returned by the ITAPI interface are temporary in nature (such as the network being unavailable), while others are more grievous—such as the message not being accepted by the network at all, or an internal configuration error (likely from a handset that's not been provisioned).

While sending SMS messages is trivial—all it requires is the message text and a callback—receiving messages presents you with a number of choices in how you wish to receive a message. All handsets have always had the ability to receive BREW-directed SMS messages (also called BDSMS), those messages which begin with the string //BREW:classid: where classid is your application's class id. When the handset receives a BDSMS to your application, it posts the payload of the message to your application using the EVT_APP_MESSAGE event.

More recent versions of BREW let you receive all SMS text messages, although you need to take care when doing this that you don't inadvertently hijack the handset's text messaging application, keeping the handset user from receiving any text messages. To do this, you must only register for with the TAPI class using the NMASK_TAPI_SMS_TEXT mask in your application's Module Information File (MIF). When a message comes in, your application receives an EVT_NOTIFY, and can get the contents of the message as an AEESMSTextMsg structure like this:

// In your application's event handler
case EVT_NOTIFY:
{
   AEENotify *pNoti = (AEENotify *)dwParam;
   if ( pNoti->cls ==  AEECLSID_TAPI )
   {
      AEESMSMsg pMsg = (AEESMSTextMsg *)pNoti->pData;
      // Do something with the payload here.
   }
}

Text SMS messages are just one of a subset of messages deliverable via SMS; the SMS protocol provides for multiple addresses for SMS messages, called teleservice ids. These are analogous to the notion of a port number in the TCP/IP protocol; different teleservice ID's are used for different purposes, such as WAP push notifications or voicemail notifications. You can receive these messages with ITAPI, too, using a very similar mechanism; see the BREW documentation for details.

The ISMS Interface

New in the latest versions of BREW 3.1.2 is a suite of SMS interfaces, ISMS, ISMSNotifier, ISMSMsg, and ISMSStorage. These interfaces open up the entire suite of SMS on the phone, letting you:

  • Send SMS messages—text or binary—using ISMS and ISMSMsg
  • Receive SMS messages using ISMSNotifier, ISMS, and ISMSMsg
  • Insert and fetch messages from the handset's native message store

Looking at this list, you might surmise that these interfaces aren't for general consumption, and you'd be absolutely correct. These interfaces are provided largely for handset manufacturers, who now can write the handset's embedded messaging suite in BREW, something that couldn't easily be done before. Nonetheless, it's instructive to look at how these classes work, if only because they provide insight into how the handset's SMS functionality works under the hood.

Consider sending an SMS: Previously, as developers we've only been able to send SMS using ITAPI_SendSMS. By using ISMS and ISMSMsg, there's considerably more flexibility—at the cost of complexity, as you can imagine. Here's pseudocode to send a message:

// Make a new SMS message
   nResult = ISHELL_CreateInstance(pThis->sApplet.m_pIShell,
                                   AEECLSID_SMSMSG,
                                   (void**)&(pISMSMsg));
   if(nResult != SUCCESS )
   {
      DBGPRINTF("Failed to create ISMSMsg %s", nResult);
      goto fail;
   }
   // Make a new SMS service
   nResult = ISHELL_CreateInstance(pThis->sApplet.m_pIShell,
                                   AEECLSID_SMS,
                                   (void**)&(pThis->pISMS));
   if(nResult != SUCCESS )
   {
      DBGPRINTF("Failed to create ISMS %s", nResult);
      goto fail;
   }
   // Configure our options buffer. Options will be added
   // "one at a time"
   sOpts[1].nId = MSGOPT_END;
   sOpts[1].pVal = NULL;
   // We need to instruct the ISMSMessage to copy options that
   // are passed
   sOpts[0].nId = MSGOPT_COPYOPTS;
   sOpts[0].pVal = (void *)TRUE;
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   // Set the destination address on our outbound sms message
   sOpts[0].nId = MSGOPT_TO_DEVICE_SZ;
   sOpts[0].pVal = (void *)"8885551212"
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   // priority
   sOpts[0].nId = MSGOPT_PRIORITY;
   sOpts[0].pVal = (void *)AEESMS_PRIORITY_NORMAL;
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   // sender address (from).  We get the sender's MDN from ITAPI
   nResult = ISHELL_CreateInstance(pThis->sApplet.m_pIShell,
                                   AEECLSID_TAPI,
                                   (void **)&pITapi);
   if(nResult != SUCCESS)
   {
      DBGPRINTF("Failed to create ITAPI instance %s", nResult);
      goto fail;
   }
   ITAPI_GetStatus(pITapi, &sStatus);
   ITAPI_Release(pITapi);
   sOpts[0].nId = MSGOPT_FROM_DEVICE_SZ;
   sOpts[0].pVal = (void *)&sStatus.szMobileID[5];
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   sOpts[0].nId = MSGOPT_MOSMS_ENCODING;
   sOpts[0].pVal = (void *)AEESMS_ENC_ASCII;
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   sOpts[0].nId = MSGOPT_PAYLOAD_SZ;
   sOpts[0].pVal = (void *)"Hello World";
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   sOpts[0].nId = MSGOPT_PAYLOAD_ENCODING;
   sOpts[0].pVal = (void *)AEE_ENC_ISOLATIN1;
   ISMSMSG_AddOpt(pISMSMsg, (WebOpt *)&sOpts);
   // Prepare to send the message by init'ing callback and
   // setting status
   CALLBACK_Init(&pThis->m_sSendMessageCallback, SMSSendCB, pThis);
   ISMS_SendMsg(pThis->pISMS, pISMSMsg,
                &pThis->m_sSendMessageCallback, 
                &pThis->m_dwSMSSendResult);
// And our callback
static void SMSSendCB(CApp *pThis)
{
   int  nResult = EFAILED;
   uint32  dwErrorType = 0;
   uint32  dwErrorCode = EFAILED;
   dwErrorType = AEESMS_GETERRORTYPE(pThis->m_dwSMSSendResult);
   DBGPRINTF("etype: 0x%x", dwErrorType);
   dwErrorCode = AEESMS_GETERROR(pThis->m_dwSMSSendResult);
   DBGPRINTF("ecode: 0x%x", dwErrorCode);
   switch(dwErrorType)
   {
   case 0:
      // Should be a success!
      break;
   case 1:
      // SMSC Error type 1
      break;
   case 2:
      // SMSC Error type 2
      break;
   case 3:
      // SMSC Error type 3
      break;
   default:
      DBGPRINTF("invalid error type %d", dwErrorType);
      break;
  }
}

Wow. That's a lot of code just to send a message! After creating an empty SMS message and an instance of ISMS (which will actually perform the sending operation), most of the code consists of configuring the SMS message with the options for the message, such as its destination address, sender address, encoding (ASCII, as opposed to a binary SMS message), message payload (the ubiquitous "Hello World", and how the payload is encoded (ISO-Latin character set). For users of IWeb, this interface should look familiar—under the hood, an ISMSMessage is actually a collection of WebOpts.

As with ITAPI, the process of sending an SMS message is an asynchronous one; when sending you must pass an initialized AEECallback along with a 32-bit integer in which ISMS will store the result value from the attempt to send your message. Of course, both the callback and this integer must be on the heap, not the stack, because they must remain in scope after your routine exits; it's often easiest just to allocate these as part of your application structure.

The callback is more complex, too, because it must manage both network errors and potential BREW errors that arise. It is also responsible for handling whatever retry rules are mandated by the carrier on which the application will run: Different carriers have different requirements regarding how often a handset should attempt to retry sending an SMS.

As you might imagine, receiving an SMS message is similarly complex. Without diving into the details in terms of code, the general flow is that your application receives a notification from ISMSNotifier, and then you use information in that notification to invoke ISMS_ReceiveMsg, which creates an ISMSMsg object, which you then parse by walking its list of options to determine the message sender, payload encoding, payload, and so forth. Perhaps most important to know about receiving SMS messages is that there should only be one application on the handset using ISMS to receive messages.

Which to Use and Why

By now, the choice of which to use and why should be pretty obvious: If you're writing a downloadable application, you definitely want to stick with using the relatively simple ITAPI-based interfaces to SMS sending and receiving. They're somewhat limited, to be sure (for example, there's no support for binary payloads), which may force you to be somewhat creative in how you craft a message payload (perhaps using base-64 encoding of binary data in the case where you need to send binary data). The support for SMS receipt is actually quite good, and there's a lot you can do with the ITAPI interface alone in the latest versions of BREW.

Handset manufacturers, on the other hand, are blessed with the flexibility required to write an entire messaging application in BREW using the new ISMS-based message classes. Closely reflecting the underlying implementation of an SMS message, the ISMSMsg class lets you string together the contents of an SMS message, or parse apart a received SMS message. However, these aren't things you can do as a downloadable application developer; not only would they potentially interfere with the built-in messaging application, but require privileges not available to downloadable applications as well.

Related Resources

QUALCOMM BREW: http://www.qualcomm.com/brew/

Presentation on Telephony & SMS Interfaces: http://brew.qualcomm.com/brew/en/press_room/events/brew_2005/pres_video_02.html, TT501.

Mobile Messaging Technologies and Services: SMS, EMS, and MMS. Gwenaël Le Bodic, published by John Wiley and Sons.

About the Author

Ray Rischpater is the chief architect at Rocket Mobile, Inc., specializing in the design and development of messaging and information access applications for today's wireless devices. Ray Rischpater is the author of several books on software Development including eBay Application Development and Software Development for the QUALCOMM BREW Platform, both available from Apress, and is an active Amateur Radio operator. Contact Ray at kf6gpe@lothlorien.com.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date