Short Message Service (SMS)

The Short Message Service (SMS) enables a Pocket PC Phone Edition device (or any other mobile device, for that matter) to instantly send and receive small messages through a Short Message Service Center (SMSC) to another mobile device on the network. Each message can be up to 160 alphanumeric characters long (140 bytes), and may be separated into multipart messages if necessary. SMS, with the introduction of the Enhanced Messaging Service (EMS) and the Multimedia Messaging Service (MMS), also has support for small binary nontext messages.

Once a message is sent to the SMSC for delivery, it is the messaging center's responsibility to forward the message to the appropriate destination mobile device. If the destination address of the device is not immediately available, the SMSC will usually store the message and continue to attempt to send it until it receives a notification that the target device has successfully received the message. SMS Messaging is based on the GSM 3.40 specification ("Technical Realization of the Short Messaging Service"), which can be downloaded from http://www.etsi.org.

One of the main differences between SMS Messaging and sending regular e-mail is that you can send SMS messages instantaneously, similar in fashion to a pager (however, SMS does not guarantee a delivery time or a confirmation) and without connecting to the Internet and a mail server. While the Pocket PC Phone Edition has seamlessly integrated SMS messaging functionality into the Inbox (see Figure 8.5), using the SMS APIs will enable you to send and receive SMS messages from within your own applications.

Figure 8.5. SMS and the Pocket PC Inbox

graphics/08fig05.gif

In order to create applications that can send and receive messages over SMS, you should include the sms.h header file, and link with the sms.lib library.

SMS Addresses

All of the SMS API functions use the SMS_ADDRESS structure to define the device address to which messages can be sent, and from which messages are received. The structure defines both the type of address and the actual phone number used in conjunction with the message. The SMS_ADDRESS structure is defined as follows:

 typedef struct sms_address_tag{    SMS_ADDRESS_TYPE smsatAddressType;    TCHAR ptsAddress[SMS_MAX_ADDRESS_LENGTH]; } SMS_ADDRESS, *LPSMS_ADDRESS; 

The smsatAddressType field is used to define the type of address, and can be one of the values listed in Table 8.11.

Table 8.11. SMS Message Address Types

Value

Address Type

SMSAT_UNKNOWN

Unknown phone number type

SMSAT_INTERNATIONAL

An international phone number

SMSAT_NATIONAL

A national phone number

SMSAT_NETWORKSPECIFIC

A network-specific phone number

SMSAT_SUBSCRIBER

A subscriber phone number

SMSAT_ALPHANUMERIC

An alphanumeric phone number

SMSAT_ABBREVIATED

An abbreviated phone number

The ptsAddress field contains a null-terminated string that contains the address, which can be up to 255 characters long.

SMS Service Center (SMSC)

An SMS Service Center (or SMSC) is the server that performs the delivery of an SMS message. When a new message is sent from a device, the SMSC is responsible for the storing, forwarding, and relaying of the message to its appropriate destination address.

The process for delivering an SMS message from one device to another works as follows:

  1. A device sends the new SMS message to the SMSC.

  2. When the SMSC receives a new message, it sends an SMS request to the home location register (HLR). This is used to find out the routing information for the destination address.

  3. The HLR sends a notification back to the SMSC with the status of the subscriber address. The notification indicates whether the address is inactive or active, and whether or not the address is roaming.

  4. If the HLR response indicates that the subscriber is inactive, then the SMSC will hold the message for a period of time. Once the device address comes online on the network, the HLR sends a notification to the SMSC that the device is active.

  5. If the HLR response is active (or the SMSC receives an active notification), the SMSC will then transfer the message to the target device address using the Short Message Delivery Point to Point (SMPP) protocol. In essence, the SMSC pages the device with the message contents.

  6. Once the SMSC receives a notification from the destination device that the message has been delivered and verified, the SMSC marks the message as sent, and does not attempt to continue delivery.

NOTE:

Every device must be configured with an SMSC phone number (or address) before it can send or receive text messages.


To get the SMS address for the current SMSC for the device, you can use the SmsGetSMSC() function, which is defined as follows:

 HRESULT SmsGetSMSC(SMS_ADDRESS* const psmsaSMSCAddress); 

As you might expect, the only parameter that the function needs is a pointer to an SMS_ADDRESS structure that will be filled in with the current SMSC information.

For example, if you wanted to get the address information for the current SMSC, your call to SmsGetSMSC() would look like the following:

 // Get the current SMS Service Center HRESULT hr = S_OK; SMS_ADDRESS smscAddress; TCHAR tchSMSC[1024] = TEXT("\0"); memset(&smscAddress, 0, sizeof(SMS_ADDRESS)); hr = SmsGetSMSC(&smscAddress); if(FAILED(hr)) {    OutputDebugString(TEXT("Could not get service center        address."));    return FALSE; } wsprintf(tchSMSC, TEXT("Current SMSC: %s"),   smscAddress.ptsAddress); MessageBox(NULL, tchSMSC, TEXT("SMSC"),   MB_OK|MB_ICONINFORMATION); 

To change the SMSC, you can pass an SMS_ADDRESS structure containing the new service center address to the following function:

 HRESULT SmsSetSMSC(const SMS_ADDRESS* const   psmsaSMSCAddress); 

The following code fragment shows how to set a new SMSC address:

 // Set a new SMS Service Center SMS_ADDRESS smscNewAddress; memset(&smscNewAddress, 0, sizeof(SMS_ADDRESS)); smscNewAddress.smsatAddressType = SMSAT_INTERNATIONAL; wsprintf(smscNewAddress.ptsAddress,TEXT("18005555555")); hr = SmsSetSMSC(&smscNewAddress); if(FAILED(hr)) {    OutputDebugString(TEXT("Could not set service center        address."));    return FALSE; } 

Opening the SMS Service

In order to either send or receive messages over the SMS service, you must first obtain a handle that you will use for subsequent messaging calls. Be aware that although you may have multiple handles open simultaneously for sending a message over a particular SMS protocol, you can open only one handle at a time for receiving messages (the Pocket PC Inbox, \Windows\tmail.exe, will typically have the receive handle already open).

To get an SMS handle, call the SmsOpen() function:

 HRESULT SmsOpen(const LPCTSTR ptsMessageProtocol,    const DWORD dwMessageModes,    SMS_HANDLE* const psmshHandle, HANDLE* const    phMessageAvailableEvent); 

The first parameter, ptsMessageProtocol, is a null-terminated string that specifies which SMS protocol to use. There are several predefined SMS provider types, each with its own set of structures that make up different types of messages. The SMS protocols that Pocket PC Phone Edition supports are listed in Table 8.12.

The dwMessageModes parameter sets the transfer mode of the open handle. This can be set to SMS_MODE_RECEIVE if you want to receive messages, and/or SMS_MODE_SEND if you want to send messages. Note that certain SMS protocols can support only receive mode, and SmsOpen() will return an error if you try to open the protocol with the send option.

The pshmshHandle should point to the address of a variable that will receive an SMS_HANDLE when the function returns. The last parameter, phMessageAvailableEvent, is a pointer to a Windows event handle that will be signaled when a new message arrives. Although you can use this handle for wait event functions such as WaitForSingleObject(), you should not use any other event APIs on the handle. Calling functions such as SetEvent() and ResetEvent() will confuse the SMS engine, and unpredictable results can occur. In addition, you do not need to call CloseHandle() on the handle returned to pshmshHandle, as the SMS engine will close it when you call SmsClose() to shut down SMS.

Table 8.12. SMS Message Protocol Types

SMS Protocol Type

Send/Receive

Description

SMS_MSGTYPE_TEXT

Both

Text SMS Protocol. Uses the TEXT_PROVIDER_SPECIFIC_DATA structure.

SMS_MSGTYPE_NOTIFICATION

Receive only

Notification SMS Protocol. Uses the NOTIFICATION_PROVIDER_SPECIFIC_DATA structure.

SMS_MSGTYPE_WDP

Both

WDP SMS Message. Uses the WDP_PROVIDER_SPECIFIC_DATA structure.

SMS_MSGTYPE_WCMP

Both

WCMP SMS Message. Uses the WCMP_PROVIDER_SPECIFIC_DATA structure.

SMS_MSGTYPE_STATUS

Receive only

Status message SMS Protocol. Uses the STATUS_PROVIDER_SPECIFIC_DATA structure.

SMS_MSGTYPE_BROADCAST

Receive only

Broadcast Message SMS Protocol. Uses the BROADCAST_PROVIDER_SPECIFIC_DATA structure.

SMS_MSGTYPE_RAW

Receive only

Raw SMS Protocol. Uses the RAW_PROVIDER_SPECIFIC_DATA structure.

Using the SmsOpen() function to initiate a SMS messaging session is fairly straightforward, as shown by the following example:

 SMS_HANDLE hSms = NULL; HANDLE hSmsEvent = NULL; HRESULT hr = S_OK; // Open up an SMS handle for the text provider // Remember, tmail.exe will typically have the receive // handle already open, and needs to be shut down before opening. hr = SmsOpen(SMS_MSGTYPE_TEXT,    SMS_MODE_RECEIVE|SMS_MODE_SEND, &hSms, &hSmsEvent); if(FAILED(hr)) {    OutputDebugString(TEXT("Could not open a handle to the       SMS text message service."));    return FALSE; } 

SMS Message Protocols

Several different SMS protocols can be used when sending a message from one device to another. Each protocol, also known as an SMS provider, has its own specific data structure, which makes up the message associated with it. The Pocket PC Phone Edition supports the short messaging protocols described in Table 8.12. Note that some of the protocols can be used only to receive messages, not to send them.

Complete details about SMS provider functionality and terminology can be found in the GSM 3.40 specification (found at http://www.etsi.org).

Text SMS Messages

The text SMS provider is the most commonly used protocol for sending and receiving messages. As the name implies, the content of a text message is just that a string up to 160 characters long. When working with text SMS messages, you use the TEXT_PROVIDER_SPECIFIC_DATA structure for any additional protocol information. The structure is defined as follows:

 typedef struct text_provider_specific_data_tag {    DWORD dwMessageOptions;    PROVIDER_SPECIFIC_MESSAGE_CLASS psMessageClass;    PROVIDER_SPECIFIC_REPLACE_OPTION psReplaceOption; } TEXT_PROVIDER_SPECIFIC_DATA; 

The dwMessageOptions field specifies any options that can be used with the provider. It can be set to one or more of the following:

  • PS_MESSAGE_OPTION_NONE indicates that no options are being used.

  • PS_MESSAGE_OPTION_REPLYPATH indicates that the TP-Reply-Path bit should be set when sending a message (GSM 3.40 specification).

  • PS_MESSAGE_OPTION_STATUSREPORT indicates that the TP-Status-Report-Request bit should be set when sending a message (GSM 3.40 specification).

  • PS_MESSAGE_OPTION_DISCARD indicates that the TP-User-Data-Header bit should set to discard when sending a message (GSM 3.40 specification).

The psMessageClass field specifies how a message should interact with the SMS Service Center when it is received by its destination. It should be set to one of the following options:

  • PS_MESSAGE_CLASS0 indicates that the message should be displayed immediately and not stored in the SIM. This is typical for an alert message, and should always send an acknowledgment back to the SMSC.

  • PS_MESSAGE_CLASS1 indicates that the message should be stored in the SIM, and an acknowledgment should be sent to the SMSC once it has been received.

  • PS_MESSAGE_CLASS2 indicates that the message should be stored in the SIM, and an acknowledgment should be sent to the SMSC once it has been stored. If the message cannot be stored in the SIM and other memory is available, then an "unspecified protocol error" will be returned. If there is no memory to store the message, a "memory capacity exceeded" error will be sent to the SMSC.

  • PS_MESSAGE_CLASS3 indicates that an acknowledgment should be sent to the SMSC when the message has reached its target address.

The psReplaceOption field specifies how a message should be replaced for a previously received notification. It can be one of the following values:

  • PSRO_NONE indicates that no earlier notifications should be replaced, and that the message should be acknowledged.

  • PSRO_REPLACE_TYPE1 indicates that Replace Short Message Type 1 notifications should be replaced if the originating address and parameter values match.

  • PSRO_REPLACE_TYPE2 indicates that Replace Short Message Type 2 notifications should be replaced if the originating address and parameter values match.

  • PSRO_REPLACE_TYPE3 indicates that Replace Short Message Type 3 notifications should be replaced if the originating address and parameter values match.

  • PSRO_REPLACE_TYPE4 indicates that Replace Short Message Type 4 notifications should be replaced if the originating address and parameter values match.

  • PSRO_REPLACE_TYPE5 indicates that Replace Short Message Type 5 notifications should be replaced if the originating address and parameter values match.

  • PSRO_REPLACE_TYPE6 indicates that Replace Short Message Type 6 notifications should be replaced if the originating address and parameter values match.

  • PSRO_REPLACE_TYPE7 indicates that Replace Short Message Type 7 notifications should be replaced if the originating address and parameter values match.

  • PSRO_RETURN_CALL indicates that the originating device address can accept a return call.

  • PSRO_DEPERSONALIZATION indicates that the message contains code to depersonalize the device, and should not be displayed to the user.

Notification SMS Messages

The notification message protocol is used only when receiving messages that are message waiting alerts, such as a new voice mail.

Notification messages use the NOTIFICATION_PROVIDER_SPECIFIC_DATA structure, which is defined as follows:

 typedef struct notification_provider_specific_data_tag {    DWORD dwMessageOptions;    PROVIDER_SPECIFIC_MESSAGE_CLASS psMessageClass;    PROVIDER_SPECIFIC_REPLACE_OPTION psReplaceOption;    NOTIFICATION_PROVIDER_SPECIFIC_MSG_WAITING_TYPE       npsMsgWaitingType;    int iNumberOfMessagesWaiting;    NOTIFICATION_PROVIDER_SPECIFIC_INDICATOR_TYPE       npsIndicatorType; } NOTIFICATION_PROVIDER_SPECIFIC_DATA; 

The dwMessageOptions, psMessageClass, and psReplaceOptions fields specify any additional information about the message, and are identical to those found in the TEXT_PROVIDER_SPECIFIC_DATA structure.

The npsMsgWaitingType field specifies the type of notification that was received. Pocket PC Phone Edition supports the following notification types:

  • NOTIFICATIONPSMWT_NONE, if no message is waiting

  • NOTIFICATIONPSMWT_GENERIC, if the waiting message is generic

  • NOTIFICATIONPSMWT_VOICEMAIL, if the waiting message is a voice mail message

  • NOTIFICATIONPSMWT_FAX, if the waiting message is a fax

  • NOTIFICATIONPSMWT_EMAIL, if the waiting message is an e-mail message

  • NOTIFICATIONPSMWT_OTHER, if the waiting message is of an unknown type

The iNumberofMessagesWaiting field contains the number of messages that are waiting. The last field, npsIndicatorType, will specify the phone line that the notification is for, and can be set to NOTIFICATIONPSIT_NONE, NOTIFICATIONPSIT_LINE1, or NOTIFICATIONPSIT_LINE2.

WDP SMS Messages

The Wireless Datagram Protocol (WDP) is used to send and receive packets of binary data (similar to UDP) from one wireless device to another over the SMS service, and is part of the Wireless Application Protocol (WAP) stack. More information on WDP can be found in the WAP-202-WCMP specification, which is downloadable from http://www.etsi.org.

WDP messages use the WDP_PROVIDER_SPECIFIC_DATA structure, which is defined as follows:

 typedef struct wdp_provider_specific_data_tag {    WDP_PROVIDER_SPECIFIC_PORT_ADDRESSING wdppsPortAddressing;    WORD wDestinationPort;    WORD wOriginatorPort; } WDP_PROVIDER_SPECIFIC_DATA; 

The first field, wdppsPortAddressing, specifies how the port numbers in the remaining fields should be addressed. This can be set to WDPPSA_8_BIT_PORT_NUMBERS for 8-bit addressing or WDPPSPA_16_BIT_PORT_NUMBERS for 16-bit values.

The wDestinationPort and wOriginatorPort fields specify which ports should be used for the delivery and reception of WDP packets, respectively.

WCMP SMS Messages

The Wireless Control Message Protocol (WCMP) is used to send status messages and report errors that occur while using the Wireless Datagram Protocol. It is similar in functionality to TCP/IP's ICMP protocol for handling echo requests and responses. In addition, WCMP messages can be used for diagnostic and informational purposes.

WCMP messages use the WCMP_PROVIDER_SPECIFIC_DATA structure, which has the following prototype:

 typedef struct wcmp_provider_specific_data_tag {    WCMP_PROVIDER_SPECIFIC_MESSAGE_TYPE wcmppsMessageType;    WORD wParam1;    WORD wParam2;    WORD wParam3;    SMS_ADDRESS smsaAddress; } WCMP_PROVIDER_SPECIFIC_DATA; 

The wcmppsMessageType field indicates the type of WCMP message that the structure represents. It can be any of the following:

  • WCMPPSMT_UNSUPPORTED, if there is no way to route the message to the destination address

  • WCMPPSMT_PORT_UNREACHABLE, if the destination port is unreachable

  • WCMPPSMT_MESSAGE_TOO_BIG, if the message is larger than the destination's buffer size

  • WCMPPSMT_ECHO_REQUEST, if the message is an echo request

  • WCMPPSMT_ECHO_REPLY, if the message is an echo response

The type of WCMP message that was sent or received (see Table 8.13) determines the value of the other fields in the structure.

Table 8.13. WCMP Message Types

Message Type

wParam1

wParam2

wParam3

smsaAddress

UNSUPPORTED

None

None

None

None

PORT_UNREACHABLE

Destination port

Source port

None

Destination address of original datagram

MESSAGE_TOO_BIG

Destination port

Source port

Maximum size

Destination address of original datagram

ECHO_REQUEST

Identifier

Sequence number

None

None

ECHO_REPLY

Identifier

Sequence number

None

None

Status SMS Messages

If an SMS message (such as a text or notification message) requested status information by setting the PS_MESSAGE_OPTION_STATUSREPORT value, then a status SMS message will be sent to the device.

When a status message is received, it uses the STATUS_PROVIDER_SPECIFIC_DATA structure to report any information. The structure is defined as follows:

 typedef struct status_provider_specific_data_tag {    SMS_STATUS_INFORMATION smssiStatusInformation; } STATUS_PROVIDER_SPECIFIC_DATA; 

The only information that the structure provides is an SMS_STATUS_INFORMATION structure. SMS_STATUS_INFORMATION will be filled in with the actual details of the status message:

 typedef struct sms_status_information_tag {    SMS_MESSAGE_ID smsmidMessageID;    DWORD dwMessageStatus0;    DWORD dwMessageStatus1;    SMS_ADDRESS smsaRecipientAddress;    SYSTEMTIME stServiceCenterTimeStamp;    SYSTEMTIME stDischargeTime; } SMS_STATUS_INFORMATION, *LPSMS_STATUS_INFORMATION; 

The smsmidMessageID field is the identifier of the message for which the status message was sent, and is the same as the identifier that you are returned from calling SmsSendMessage().

The dwMessageStatus0 and dwMessageStatus1 fields are two DWORD values that indicate the status message. Note that both fields must have the MESSAGE_STATUS_UNKNOWN flag set if the message status is truly undefined.

dwMessageStatus0 can be one of the values described in Table 8.14.

Table 8.14. SMS Message Status

SMS Message Status

Delivered?

Description

MESSAGE_STATUS_UNKNOWN

N/A

Unknown status message

MESSAGE_STATUS_0_RECEIVEDBYSME

Yes

Message was received by destination

MESSAGE_STATUS_0_FORWARDEDTOSME

Yes

Message was forwarded to destination

MESSAGE_STATUS_0_REPLACEDBYSC

Yes

Message was replaced by SMSC

MESSAGE_STATUS_0_CONGESTION_TRYING

No

Network congestion; continuing to try

MESSAGE_STATUS_0_SMEBUSY_TRYING

No

Busy signal; continuing to try

MESSAGE_STATUS_0_SMENOTRESPONDING_TRYING

No

No response from destination; continuing to try

MESSAGE_STATUS_0_SVCREJECTED_TRYING

No

Service rejected; continuing to try

MESSAGE_STATUS_0_QUALITYUNAVAIL_TRYING

No

Quality unavailable; continuing to try

MESSAGE_STATUS_0_SMEERROR_TRYING

No

Destination error

MESSAGE_STATUS_0_CONGESTION

No

Temporary network congestion

MESSAGE_STATUS_0_SMEBUSY

No

Temporary busy signal at destination

MESSAGE_STATUS_0_SMENOTRESPONDING

No

Destination is not responding temporarily

MESSAGE_STATUS_0_SVCREJECTED

No

Service has been rejected by destination temporarily

MESSAGE_STATUS_0_QUALITYUNAVAIL_TEMP

No

Quality is temporarily unavailable

MESSAGE_STATUS_0_SMEERROR

No

Temporary destination error

MESSAGE_STATUS_0_REMOTEPROCERROR

No

Permanent failure

MESSAGE_STATUS_0_INCOMPATIBLEDEST

No

Permanent failure due to destination incompatibility

MESSAGE_STATUS_0_CONNECTIONREJECTED

No

Permanent failure due to rejection of the connection

MESSAGE_STATUS_0_NOTOBTAINABLE

No

Permanent failure due to destination being unattainable

MESSAGE_STATUS_0_NOINTERNETWORKING

No

Permanent failure due to internetworking being unavailable

MESSAGE_STATUS_0_VPEXPIRED

No

Permanent failure due to validity period expiring

MESSAGE_STATUS_0_DELETEDBYORIGSME

No

Permanent failure due to message being deleted by originator

MESSAGE_STATUS_0_DELETEDBYSC

No

Permanent failure due to message being deleted by service center

MESSAGE_STATUS_0_NOLONGEREXISTS

No

Permanent failure due to the message no longer existing

MESSAGE_STATUS_0_QUALITYUNAVAIL

No

Permanent failure due to quality not existing

MESSAGE_STATUS_0_RESERVED_COMPLETED

No

Message has been successfully reserved

MESSAGE_STATUS_0_RESERVED_TRYING

No

Message has been reserved and is trying to be sent

MESSAGE_STATUS_0_RESERVED_ERROR

No

Permanent failure due to a reserve error

MESSAGE_STATUS_0_RESERVED_TMPERROR

No

Temporary error due to reserve on message

MESSAGE_STATUS_0_SCSPECIFIC_COMPLETED

Yes

Message is destined for the SMSC and has been delivered

MESSAGE_STATUS_0_SCSPECIFIC_TRYING

No

Continuing to try to send message to SMSC

MESSAGE_STATUS_0_SCSPECIFIC_ERROR

No

Permanent failure due to SMSC error

The smsaRecipientAddress field contains the destination address for the message.

The last two fields, stServiceCenterTimeStamp and stDischargeTime, are both SYSTEMTIME values that are set at different stages of the messaging delivery process. The stServiceCenterTimeStamp is set when SMSC received the message, and stDischargeTime may or may not be stamped, depending on the dwMessageStatus value.

Broadcast SMS Messages

A message received over the Cell Broadcast Service is generally sent to multiple recipients from a broadcast center over a geographical area from a service provider. A broadcast message may be up to 93 characters long, and may consist of multiple messages (or pages) that need to be concatenated to form the entire message. You can find more information about the Cell Broadcast Service in the GSM 3.41 specification, which is downloadable from http://www.etsi.org.

Broadcast SMS messages use the BROADCAST_PROVIDER_SPECIFIC_DATA structure, which has the following prototype:

 typedef struct broadcast_provider_specific_data_tag {    WORD wMessageID;    WORD wMessageCode;    BROADCAST_PROVIDER_SPECIFIC_GEOGRAPHICAL_SCOPE       bpsgsGeographicalScope;    WORD wUpdateNumber; } BROADCAST_PROVIDER_SPECIFIC_DATA; 

The wMessageID field identifies the particular type of broadcast message, and is defined by the Cell Broadcast Service center that sent the message.

The wMessageCode field enables you to differentiate between multiple broadcast messages that contain the same wMessageID. For example, if the message identifier indicated that the message was a traffic report; different codes would be used for different traffic incidents.

The bpsgsGeographicalScope field indicates the location for which the message is valid, as well as the display mode. It will be one of the following values:

  • BPSGS_UNKNOWN indicates that the message type is unknown.

  • BPSGS_CELL_DISPLAY_IMMEDIATE indicates that the message is cell-wide and should be displayed immediately.

  • BPSGS_CELL indicates that the message is valid for the current cell.

  • BPSGS_PLMN indicates that the message code must be different for additional messages with the same message ID for the cell.

  • BPSGS_LOCATION_AREA indicates that the message is location-based.

Lastly, the wUpdateNumber field indicates a change of message content. For example, if a message has the same wMessageID, wMessageCode, and bpsgsGeopgraphicalScope, the update number can be used to determine old and new messages. This value is a four-bit number, and when it is eight or less higher (mod 16) than the last received message, it should be considered more recent.

Raw SMS Messages

The raw SMS message provider is used when an SMS message is received and none of the other provider types is appropriate for it.

If you receive a raw SMS message, you should use the RAW_PROVIDER_SPECIFIC_DATA structure:

 typedef struct raw_provider_specific_data_tag {    DWORD dwHeaderDataSize;    BYTE pbHeaderData[SMS_DATAGRAM_SIZE]; } RAW_PROVIDER_SPECIFIC_DATA; 

The dwHeaderDataSize field has the number of bytes that are returned in the pbHeaderData field, and pbHeaderData stores the raw user header from the incoming message.

Sending a Message

You can send a message over a specific SMS provider by using the following function:

 HRESULT SmsSendMessage(const SMS_HANDLE smshHandle,    const SMS_ADDRESS* psmsaSMSCAddress,    const SMS_ADDRESS* psmsaDestinationAddress,    const SYSTEMTIME* pstValidityPeriod,    const BYTE* pbData, const DWORD dwDataSize,    const BYTE* pbProviderSpecificData,    const DWORD dwProviderSpecificDataSize,    const SMS_DATA_ENCODING smsdeDataEncoding,    const DWORD dwOptions, SMS_MESSAGE_ID* psmsmidMessageID); 

As you can see, numerous parameters are needed to send a message over SMS. The first one is the handle to an open SMS provider that was returned from a previous call to SmsOpen. The next parameter, psmsaSMSCAddress, points to the SMS Service Center through which you want to route your message. If you want to use the default SMSC address that was specified by the SmsSetSMSC() function, then you can set this to NULL, as it is an optional parameter. The psmsaDestinationAddress parameter should be set to the address of the device to which the message is sent.

The validity period of a message tells the SMSC how long a message is valid for. It begins when the SMSC receives the message. Once the period has expired, the message is automatically deleted. The pstValidityPeriod parameter is optional and can be set to NULL.

The next two parameters contain the SMS message body. The pbData parameter should point to the contents of the message, and the dwDataSize parameter should specify the size, in bytes, of the buffer pointed to by pbData. If there is no message, then you can set pbData to NULL, and dwDataSize to 0.

The pbProviderSpecificData and dwProviderSpecificDataSize parameters contain additional information for whichever SMS protocol you are using to send your message. For example, to send a text message (using SMS_MSGTYPE_TEXT), you would need to fill out a TEXT_PROVIDER_SPECIFIC_DATA structure. A pointer to this structure would then be passed in for the pbProviderSpecificData parameter, and its size (in bytes) would be passed in for the dwProviderSpecificDataSize parameter.

The smsdeDataEncoding parameter specifies the text encoding method for the message, and can be set to one of the following options:

  • SMSDE_OPTIMAL will use the best data encoding scheme that results in the least amount of space. This is the recommended option to use.

  • SMSDE_GSM specifies that standard GSM-7 encoding should be used.

  • SMSDE_UCS2 specifies that standard Unicode UCS2 encoding should be used.

The dwOptions flag can be set to either of the following:

  • SMS_OPTION_DELIVERY_NONE, for no special options

  • SMS_OPTION_DELIVERY_NO_RETRY, if you do not want the SMSC to retry sending a message if it is undeliverable

The last parameter, psmsmidMessageID, will receive a message ID once the function returns; it can be used for additional informational messages regarding the status of a sent message. This parameter is optional.

The following example shows how to send an SMS message:

 // Send an SMS message through default SMSC SMS_ADDRESS smsDestination; SMS_MESSAGE_ID smsMsgId = 0; // Set the destination address for the message memset(&smsDestination, 0, sizeof(SMS_ADDRESS)); smsDestination.smsatAddressType = SMSAT_INTERNATIONAL; _tcsncpy(smsDestination.ptsAddress,    TEXT("15555555555"), SMS_MAX_ADDRESS_LENGTH); // Create the message DWORD dwMessageLength = 0; TCHAR tchMessage[140] = TEXT("\0"); wsprintf(tchMessage, TEXT("This is a test text   message\r\n")); dwMessageLength = lstrlen(tchMessage)*sizeof(TCHAR); // Configure the text provider TEXT_PROVIDER_SPECIFIC_DATA txtProviderData; DWORD dwProviderLength = 0; memset(&txtProviderData, 0, sizeof(TEXT_PROVIDER_SPECIFIC_DATA)); txtProviderData.dwMessageOptions = PS_MESSAGE_OPTION_NONE; txtProviderData.psMessageClass = PS_MESSAGE_CLASS0; txtProviderData.psReplaceOption = PSRO_NONE; dwProviderLength = sizeof(TEXT_PROVIDER_SPECIFIC_DATA); // Send the message hr = SmsSendMessage(hSms, NULL, &smsDestination, NULL,    (BYTE *)tchMessage, dwMessageLength, (LPBYTE)&txtProviderData,    dwProviderLength, SMSDE_OPTIMAL, SMS_OPTION_DELIVERY_NONE,    &smsMsgId); if(FAILED(hr))    OutputDebugString(TEXT("Could not send SMS Text       Message.")); else    OutputDebugString(TEXT("Message Sent.")); 

If at any time you need to get the status information for a message that you have sent, you can call the SmsGetMessageStatus() function:

 HRESULT SmsGetMessageStatus(const SMS_HANDLE smshHandle,    SMS_MESSAGE_ID smsmidMessageID,    SMS_STATUS_INFORMATION* const psmssiStatusInformation,    const DWORD dwTimeout); 

The first parameter is an SMS handle and is followed by the message ID for which you want to get status information. The message ID was returned to you when you originally called the SmsSendMessage() function. The psmssiStatusInformation parameter should point to an SMS_STATUS_INFORMATION structure that will be filled in with the message's status when the function returns (information on the SMS_STATUS_INFORMATION structure can be found in the section "Status SMS Messages"). The last parameter, dwTimeout, specifies the time to wait (in milliseconds) for the status message to be received.

The following code fragment shows how to get the status of an SMS message (notice how you change the txtProviderData.dwMessageOptions flag from the previous sample to indicate you want a status report):

 txtProviderData.dwMessageOptions = PS_MESSAGE_OPTION_STATUSREPORT; txtProviderData.psMessageClass = PS_MESSAGE_CLASS0; txtProviderData.psReplaceOption = PSRO_NONE; dwProviderLength = sizeof(TEXT_PROVIDER_SPECIFIC_DATA); // Send the message hr = SmsSendMessage(hSms, NULL, &smsDestination, NULL,    (BYTE *)tchMessage, dwMessageLength, (LPBYTE)&txtProviderData,    dwProviderLength, SMSDE_OPTIMAL, SMS_OPTION_DELIVERY_NONE,    &smsMsgId); if(FAILED(hr))    OutputDebugString(TEXT("Could not send SMS Text       Message.")); else    OutputDebugString(TEXT("Message Sent.")); // Get message status (wait 2 seconds) SMS_STATUS_INFORMATION smsStatus; memset(&smsStatus, 0, sizeof(SMS_STATUS_INFORMATION)); hr = SmsGetMessageStatus(hSms, smsMsgId, &smsStatus, 2000); if(FAILED(hr))    OutputDebugString(TEXT("Could not get SMS message       status")); else {    if(smsStatus.dwMessageStatus0 ==       MESSAGE_STATUS_0_RECEIVEDBYSME)       OutputDebugString(TEXT("Message has been received")); } 

Reading a Message

By using the event handle that was returned when you called SmsOpen(), you can also wait for a new message to be received by your device. Once that event handle has been signaled, reading the contents of a message is a two-step process.

First, you need to find out how large the message is by calling the following function:

 HRESULT SmsGetMessageSize(const SMS_HANDLE smshHandle,    DWORD* const pdwDataSize); 

The function takes only two parameters: an open SMS handle and a pointer to a DWORD value that will receive the size, in bytes, of the message.

Once you have the size of the incoming message, you can retrieve the message contents by using the SmsReadMessage() function. It is defined as follows:

 HRESULT SmsReadMessage(const SMS_HANDLE smshHandle,    SMS_ADDRESS* const psmsaSMSCAddress,    SMS_ADDRESS* const psmsaSourceAddress,    SYSTEMTIME* const pstReceiveTime,    BYTE* const pbBuffer, DWORD dwBufferSize,    BYTE* const pbProviderSpecificBuffer,    DWORD dwProviderSpecificDataBuffer, DWORD* pdwBytesRead); 

The first parameter, smshHandle, is an open SMS handle for the provider from which you are going to receive a message.

The next two parameters, psmsaSMSCAddress and psmsaSourceAddress, point to variables that will be filled in with the SMSC that delivered the message, as well as the address from which it originated. Both of these are optional and can be set to NULL.

The pstReceiveTime parameter points to a SYSTEMTIME structure that will be filled in with the time the message was received. The pstReceiveTime parameter is also optional and can be set to NULL.

The pbBuffer and dwBufferSize parameters are used to store the message contents. The buffer that pbBuffer points to should be at least the size that was returned from the call to SmsGetMessageSize(). The dwBufferSize parameter should be set to the size of pbBuffer.

The pbProviderSpecificBuffer and dwProviderSpecificDataBuffer parameters contain a provider-specific data structure and its size. For example, if the received message was a WDP SMS message (using the SMS_MSGTYPE_WDP protocol type), the pbProviderSpecificBuffer would then point to a WDP_PROVIDER_SPECIFIC_DATA structure.

The pdwBytesRead parameter should point to a DWORD variable that will be filled in with the actual number of bytes that were put into the pbBuffer buffer when the function returns.

The following code example illustrates a function that is waiting for a new SMS text message to arrive. Once the SMS event is signaled, you get the size of the incoming message, allocate a buffer that is large enough for it, and finally retrieve the message:

 // Wait for an incoming message DWORD dwReturn = 0; dwReturn = WaitForSingleObject(hSmsEvent, INFINITE); // SMS event has become signaled if(dwReturn == WAIT_ABANDONED || dwReturn == WAIT_TIMEOUT) {    OutputDebugString(TEXT("No longer waiting for a    message"));    SmsClose(hSms);    return FALSE; } // Receive a message. First, get the size DWORD dwMessageSize = 0; hr = SmsGetMessageSize(hSms, &dwMessageSize); if(FAILED(hr)) {    OutputDebugString(TEXT("Could not get message size"));    SmsClose(hSms);    return FALSE; } // Set up to receive the message SMS_ADDRESS smscAddress; SMS_ADDRESS inAddress; SYSTEMTIME rcvTime; TEXT_PROVIDER_SPECIFIC_DATA txtProviderData; DWORD dwProviderLength = 0; dwProviderLength = sizeof(TEXT_PROVIDER_SPECIFIC_DATA); memset(&txtProviderData, 0, dwProviderLength); memset(&smscAddress, 0, sizeof(SMS_ADDRESS)); memset(&inAddress, 0, sizeof(SMS_ADDRESS)); memset(&rcvTime, 0, sizeof(SYSTEMTIME)); // Create a buffer to get the message TCHAR *tchMsgBuffer = NULL; tchMsgBuffer = (TCHAR *)LocalAlloc(LPTR,   dwMessageSize*sizeof(TCHAR)); if(!tchMsgBuffer) {    OutputDebugString(TEXT("Could not allocate a buffer for    the message"));    SmsClose(hSms);    return FALSE; } // Read the message DWORD dwBytesRead = 0; hr = SmsReadMessage(hSms, &smscAddress, &inAddress,    &rcvTime, (LPBYTE)tchMsgBuffer, dwMessageSize,    (LPBYTE)&txtProviderData, dwProviderLength, &dwBytesRead); if(FAILED(hr)) {    OutputDebugString(TEXT("There was an error reading the    message"));    LocalFree(tchMsgBuffer);    SmsClose(hSms);    return FALSE; } // Display the message to the user TCHAR tchDisplayMsg[1024] = TEXT("\0"); wsprintf(tchDisplayMsg, TEXT("New    Message!\r\nFrom:%s\r\n\r\n%s"), inAddress.ptsAddress,    tchMsgBuffer); MessageBox(NULL, tchDisplayMsg, TEXT("New SMS Message"),    MB_OK|MB_ICONEXCLAMATION); LocalFree(tchMsgBuffer); 

Closing the SMS Handle

When you have finished working with SMS, you need to close the handle to the SMS provider to ensure that the messaging component is shut down properly. You can do this by using the following function call:

 HRESULT SmsClose(const SMS_HANDLE smshHandle); 

The only parameter that the function needs is a handle to an open SMS session. When SmsClose() is called, both the handle specified by the smshHandle parameter and the Windows event handle that was returned from your call to SmsOpen() are closed.

Using the SmsClose() function is straightforward:

 // Close the SMS handle if(hSms) {    SmsClose(hSms);    hSms = NULL; } 

Broadcast Message Range

The SMS Messaging protocol specifies that GRPS devices should have the ability to receive messages from a Cell Broadcast Service. These messages are typically sent from a broadcast center and are transmitted over a geographic area, and may provide regional information such as traffic reports.

A Pocket PC Phone Edition device fully supports receiving broadcast messages, and provides you with functions to both read and set the accepted range of location IDs for incoming broadcast messages. These two functions are as follows:

 HRESULT SmsSetBroadcastMsgRanges(    const SMS_BROADCAST_RANGES* const psmsbrBroadcastRanges); 

and

 HRESULT SmsGetBroadcastMsgRanges(    SMS_BROADCAST_RANGES* const psmsbrBroadcastRanges); 

Both SmsSetBroadcastMsgRanges() and SmsGetBroadcastMsgRanges() take one parameter: a pointer to an SMS_BROADCAST_RANGES structure, which defines the specifics about the accepted broadcast ranges. The structure is defined as follows:

 typedef struct sms_broadcast_ranges_tag {    DWORD cbSize;    DWORD dwParams;    DWORD dwNumRanges;    DWORD dwBroadcastMsgLangs;    BOOL bAccept;    SMS_RANGE smsrBroadcastRanges[]; } SMS_BROADCAST_RANGES, *LPSMS_BROADCAST_RANGES; 

The first field, cbSize, needs to be set to the size of the SMS_BROADCAST_RANGES structure before calling either SmsSetBroadcastMsgRanges() or SmsGetBroadcastMsgRanges().

The dwParams field indicates which of the remaining fields of the structure contain valid data, and can be one or more of the following options:

  • SMS_PARAM_SBR_BROADCASTMSGIDS indicates that the dwNumRanges and smsrBroadcastRanges fields are valid.

  • SMS_PARAM_SBR_BROADCASTMSGLANGS indicates that the dwBroadcastMsgLangs field is valid.

  • SMS_PARAM_SBR_ACCEPTIDS indicates that the bAccept field is valid.

The dwNumRanges field specifies how many items are in the smsrBroadcastRanges array. This array is comprised of several SMS_ARRAY structures, each specifying a minimum and maximum number of mobile IDs to listen to. The SMS_ARRAY structure is defined as follows:

 typedef struct sms_range_tag {    DWORD dwMinimum;    DWORD dwMaximum; } SMS_RANGE, *LPSMS_RANGE; 

The dwBroadcastMsgLangs field specifies which languages are supported by the Pocket PC device, and can be one or more of the languages listed in Table 8.15.

Table 8.15. Broadcast Message Languages

Broadcast Languages

SMS_DCSLANG_UNKNOWN

SMS_DCSLANG_GERMAN

SMS_DCSLANG_ENGLISH

SMS_DCSLANG_ITALIAN

SMS_DCSLANG_FRENCH

SMS_DCSLANG_SPANISH

SMS_DCSLANG_DUTCH

SMS_DCSLANG_SWEDISH

SMS_DCSLANG_DANISH

SMS_DCSLANG_NORWEGIAN

SMS_DCSLANG_GREEK

SMS_DCSLANG_TURKISH

SMS_DCSLANG_HUNGARIAN

SMS_DCSLANG_POLISH

SMS_DCSLANG_CZECH

SMS_DCSLANG_PORTUGUESE

SMS_DCSLANG_FINNISH

SMS_DCSLANG_ALL

The last field, bAccept, is used to indicate whether or not the message IDs defined by dwBroadcastMsgLangs and smsrBroadcastRanges are accepted or not. If bAccept is set to TRUE, then the device will accept message from the specified identifiers.

SMS Notifications

Pocket PC Phone Edition provides your application with the capability to receive SMS messages even if it is not currently running. The function SmsSetMessageNotification() can be used to configure an application that should be started when a message from a specific SMS protocol arrives. The function is defined as follows:

 HRESULT SmsSetMessageNotification(    const SMSREGISTRATIONDATA* psmsrd); 

The only parameter that SmsSetMessageNotification() uses is a pointer to an SMSREGISTRATIONDATA structure, which looks like the following:

 typedef struct smsregistrationdata_tag {    DWORD cbSize;    TCHAR tszAppName[SMS_MAX_APPNAME_LENGTH];    TCHAR tszParams[SMS_MAX_PARAMS_LENGTH];    TCHAR tszProtocolName[SMS_MAX_PROTOCOLNAME_LENGTH]; } SMSREGISTRATIONDATA, *LPSMSREGISTRATIONDATA; 

The first field should be set to the size of the SMSREGISTRATIONDATA structure. The second field, tszAppName, specifies the application name and path that should be run when a new message arrives. When the application is run, the command-line parameters that are set in the tszParams field will be passed to it.

The last field, tszProtocolName, indicates the message provider (protocol) for which the notification is being set, and can be one of the following:

  • SMS_MSGTYPE_TEXT, for messages using the Microsoft Text SMS Protocol

  • SMS_MSGTYPE_NOTIFICATION, for messages using the Microsoft Notification SMS Protocol

  • SMS_MSGTYPE_WDP, for messages using the Microsoft WDP SMS Protocol

  • SMS_MSGTYPE_WCMP, for messages using the Microsoft WCMP SMS Protocol

  • SMS_MSGTYPE_STATUS, for messages using the Microsoft Status Message Protocol

  • SMS_MSGTYPE_RAW, for messages using the Microsoft Raw SMS Protocol

Be aware that when you set a new notification for a specific SMS protocol, you will overwrite any existing notifications for the provider.

To cancel notification messages from an SMS provider, simply call the following:

 HRESULT SmsClearMessageNotification(    const LPCTSTR tszProtocolName); 

The only parameter the function takes is the name of the protocol for which you want to remove notification messages. This should be the same as the provider name that was passed into the SMSREGISTRATIONDATA structure's tszProtocolName field when setting up the notification.

Getting Additional Information from the SIM

The SMS service on the Pocket PC Phone Edition supports two additional functions that enable you to get more information about the device from the SMS service.

To get the SMS address of the device you are using, you can use the following function:

 HRESULT SmsGetPhoneNumber(SMS_ADDRESS* const psmsaAddress); 

The only parameter that SmsGetPhoneNumber() needs is a pointer to an SMS_ADDRESS structure, which will be filled in with the device's phone number when the function returns, as shown in the following example:

 // Device phone number SMS_ADDRESS mySmsAddress; memset(&mySmsAddress, 0, sizeof(SMS_ADDRESS)); hr = SmsGetPhoneNumber(&mySmsAddress); if(FAILED(hr)) {    OutputDebugString(TEXT("Could not open a handle to the       SMS text message service.")); return FALSE; } MessageBox(NULL, mySmsAddress.ptsAddress, TEXT("Device Phone    Number"), MB_ICONINFORMATION|MB_OK); 

To get an estimate of the current time, you can call the SmsGetTime() function. This function will try to figure out the time by using the last status report message that was sent to the device from the SMS Service Center. The function is defined as follows:

 HRESULT SmsGetTime(SYSTEMTIME* const ptsCurrentTime,    DWORD* const pdwErrorMargin); 

The first parameter, ptsCurrentTime, is a pointer to a SYSTEMTIME structure that will be filled in with the estimate of the current time. The time that is returned to you will be in Universal Coordinated Time (UTC) format and should be converted to a local format before being used.

The pdwErrorMargin parameter is the maximum amount of time, in seconds, that the returned time could be off by. If SMS cannot determine the error margin, this will be set to 0xFFFFFFFF.

The following example shows how you can get the current estimated time from SMS and properly convert it:

 // Estimate current time from SMS SYSTEMTIME estTime; DWORD dwErrorMargin = 0; memset(&estTime, 0, sizeof(SYSTEMTIME)); hr = SmsGetTime(&estTime, &dwErrorMargin); if(FAILED(hr)) {    OutputDebugString(TEXT("Could not get estimated time       from SMSC."));    return FALSE; } // Since the time information is a UTC value, we will need // to convert it. FILETIME estFileTime; FILETIME localFileTime; SystemTimeToFileTime(&estTime, &estFileTime); FileTimeToLocalFileTime(&estFileTime, &localFileTime); // Convert it back SYSTEMTIME estLocalSysTime; memset(&estLocalSysTime, 0, sizeof(SYSTEMTIME)); FileTimeToSystemTime(&localFileTime, &estLocalSysTime); // Use estLocalSysTime to set clock, etc. ... 


Pocket PC Network Programming
Pocket PC Network Programming
ISBN: 0321133528
EAN: 2147483647
Year: 2005
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net