BREW's Short Messaging Service Interfaces: Which to Use and Why
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 );
}
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.
Page 1 of 2
