GEOS SDK TechDocs
|
|
3.1 Sending and the Mailbox Library
|
4 Receiving an SMS Message
mailbox.goh
To send an SMS message to the outside world, an application will need to perform the following steps:
GeoworksMailboxDataFormatID
), but a VM file is the easiest to manipulate. This VM file will be accessed by a Mailbox data driver. (See Storing the Text Within a VM File
.)
SMSendingOptions
parameters in a DB item. These will be used by the SMS transport driver when the message is delivered. (See Setting Up the SMSending Options
.)
MailboxRegisterMessageArgs
structure. (See Setting Up the MailboxRegisterMessageArgs
.)
MailboxRegisterMessage()
. (See Registering the Message
.)These steps are detailed in the sections following.
foam.goh
The Short Message Service protocol is able to handle a "short message" of up to 160 characters. The Foam library defines this character limit:
#define FOAM_MAX_SMS_TEXT_SIZE 160
The Nokia 9000i Communicator also allows you to further specify a particular application within the Nokia 9000i Communicator by adding a prefix to the SMS message (thus reducing the amount of useful text).
This prefix consists of two backslashes ("//"),
a 4-byte GEOS application token ( TokenChars),
a 5-byte GEOS ManufacturerID,
and a carriage return ("/r", ASCII 13, or 0x0D hex).
The Mailbox library will correctly read all characters up to the carriage return.
For example:
//SKAA11\r
is a valid prefix.
The application
TokenChars
and
ManufacturerID
should match those of the intended
receiving
application. If you define your own application, and only wish to communicate with its counterpart running on another device, you will define this string in the application's
.gp
file. The string is constructed from the
tokenchars
and
tokenid
lines of the
.gp
file.
You may also send a message to a different application, as long as you know its
TokenChars
and
ManufacturerID
.
This prefix should leave at least 148 characters to store the alpha-numeric text message. When concatenating two strings, be sure that you do not overflow the bounds of the array.
Code Display 3-1 Setting Up an SMS Text Message
/* * Declare the buffer to store the text message and write the prefix to the buffer. */ TCHAR smsMessage[FOAM_MAX_SMS_TEXT_SIZE + 1] = "//SKAA11\r"; TCHAR smsText[] = "Here's my test message. I better make sure it fits.";
/*
* Add the body of the text to the buffer but first check the bounds.
*/
if ( strlen( smsMessage ) + strlen( smsText ) <= FOAM_MAX_SMS_TEXT_SIZE )
{
strcat( smsMessage, smsText );
}
MailboxGetVMFile(), Mailbox\vmtree.goh
Text within an SMS message needs to be stored by the Mailbox until it connects with a cellular service provider. When you register a message with the Mailbox library, you indicate what storage format you have selected. The Mailbox uses a data driver to store and retrieve messages. There are a number of data drivers available, but we only need to know a few.
SMS messages may either be stored as VM (Virtual Memory) trees or as GEOS files, within the Mailbox itself. VM trees offer a lower overhead, and are simpler to use, so that is the format we have documented. (It is possible that future data drivers will become available as well.) If you are unfamiliar with GEOS VM trees, consult the Virtual Memory chapter of the Concepts book.
The mailbox data driver stores its data in what is called a VM tree. This tree is referenced by a
VMTreeAppRef
structure.
typedef struct {
VMChain VMTAR_vmChain;
VMFileHandle VMTAR_vmFile;
} VMTreeAppRef;
VMTAR_vmChain
stores the
VMChain
to pass to the data driver. For SMS messages, simply use the VMCHAIN_MAKE_FROM_VM_BLOCK macro to construct a
VMChain
from a single
VMBlockHandle
.
vmFile
stores the
VMFileHandle
which contains the VM block.The Mailbox stores these VM trees locally within an administation file that it maintains. To store the text within a Mailbox-compatible VM file, perform the following steps:
MailboxGetVMFile()
to retrieve a VM file handle within the Mailbox. This routine expects an argument indicating the expected number of blocks to be added to the file; because the SMS message can be contained in a single block, pass 1. Also pass a buffer to store the returned
VMStatus.
VMFileHandle.
VMAlloc().
VMLock(). This routine returns the segment address of the locked block. You will also receive a temporary memory handle that you can use to manipulate the block.
VMChainLink
that begins the block.)
VMDirty().
VMUnlock().
VMTreeAppRef
structure. This format is understood by the mailbox data driver.Code Display 3-2 Storing the Text In a VM File
VMFileHandle vmFile; VMBlockHandle vmBlock; TCHAR *textPtr; MemHandle mh; word vmStatus; VMTreeAppRef vmRef;
/* * Obtain the handle of a writable VM file from the Mailbox library. We pass one * since we do not plan to add additional blocks to this file (because SMS messages * are so short). */ vmFile = MailboxGetVMFile(1, &vmStatus);
/* * Allocate a VM block and store the text within this block. The block will need * to fit a header (VMChainLink), the SMS message itself, and a null terminator. */ vmBlock = VMAlloc(vmFile, (sizeof(VMChainLink) + strlen(smsMessage) +1), 0); charPtr = VMLock(vmFile, vmBlock, &mh);
/* * We advance past the VMChainLink contained at the beginning of the VM * block and copy the text to that location. */ strcpy(textPtr + sizeof(VMChainLink), smsMessage);
/* * Dirty the block and unlock it. */ VMDirty(mh); VMUnlock(mh);
/* * Store the VM file and VM block within a VMTreeAppRef structure. This is the * format that the mailbox library understands. Essentially, it ia a VM "chain" * of a single VM file. */ vmRef.VMTAR_vmChain = VMCHAIN_MAKE_FROM_VM_BLOCK(vmBlock); vmRef.VMTAR_vmFile = vmFile;
MailboxGetAdminFile(), smdefine.goh, SMSendingOptions, ReadCSNumberFromIniFile()
When registering a mailbox message, the application must specify a data driver to use when storing the message. It will also need to specify which transport driver to use when the message is to be delivered. The GEOS SMS transport driver expects a number of parameters indicating how the SMS message should be sent. These parameters are passed as a
SMSendingOptions
structure within a GEOS
DBItem.
To store these parameters within a compatible DB item, perform the following steps:
MailboxGetAdminFile()
to retrieve the
VMFileHandle
of the Mailbox administration file. This is where you will copy your SMS parameters.
DBAllocUngrouped().
DBLockUngrouped().
SMSendingOptions
parameters into this DB item.
InitFileReadStringBuffer(). Copy that number into the DB item.
DBDirty().
DBUnlock().
The
SMSendingOptions
structure is defined within
smdefine.goh
and is shown below:
typedef struct {
SMReplyPath SMSO_replyPath;
SMValidityPeriod SMSO_validityPeriod;
SMMessageConversion SMSO_messageConversion;
TCHAR SMSO_scAddress[MAX_ADDRESS_SIZE];
} SMSendingOptions;
#define MAX_ADDRESS_SIZE 22
replyPath
contains an
SMReplyPath
value which indicates whether the recipient may reply to the message through the sender's service provider. Possible values are:
_validityPeriod
contains an
SMValidityPeriod
value which indicates the length of time that the message is considered valid for delivery. The cellular provider should interpret this value and if it is unable to connect with the recipient, drop the message and inform the sender that the message was not delivered. Possible values are:
messageConversion
contains an
SMMessageConversion
value, indicating that you wish to have the SMS message delivered to the recipient in a different format than that of an SMS message (provided that the cellular provider offers this service). Possible values are:
scAddress
stores the address of the service center (cellular provider). This number is stored as an ASCII text string and is limited to 22 characters. This number should be retrieved from the Nokia 9000i Communicator's .INI file; the number is stored under the
scNumber
field within the
SMS
category. This "address" in this case is really just a numerical phone number.initfile.h, InitFileReadStringBuffer()
To read a string from the .INI file, call
InitFileReadStringBuffer()
. Pass "SMS" as the category and "scNumber" as the key. The routine will read the entry into a buffer passed to the routine. It will also read the size of the string into another buffer.
Code Display 3-3 Setting the SMSendingOptions Parameters
SMSendingOptions *ptrSendingOptions VMFileHandle adminFile; DBGroupAndItem smsParams; word sizeOfBuffer;
adminFile = MailboxGetAdminFile();
smsParams = DBAllocUngrouped(adminFile, sizeof(SMSendingOptions));
ptrSendingOptions = (SMSendingOptions *) DBLockUngrouped(adminFile, smsParams);
/* set desired sending options */ ptrSendingOptions->SMSO_replyPath = SMRP_NO; ptrSendingOptions->SMSO_validityPeriod = SMVP_24_HOURS; ptrSendingOptions->SMSO_messageConversion = SMMC_NORMAL;
/* be sure to initialize these fields as well, otherwise the app will crash! */ ptrSendingOptions->SMSO_dataCodingScheme = 0; ptrSendingOptions->SMSO_userDataLength = 0; ptrSendingOptions->SMSO_userDataLength = 0;
InitFileReadStringBuffer("SMS",
"scNumber",
ptrSendingOptions->SMSO_scAddress,
0,
&sizeOfBuffer);
DBDirty(ptrSendingOptions); DBNUnlock(ptrSendingOptions);
MailboxRegisterMessageArgs, MailboxTransAddr
By now, you have created a reference to the SMS message itself (within a
VMTreeAppRef
structure); you have also placed the SMS sending parameters within the mailbox administration file. You are now ready to load the
MailboxRegisterMessageArgs
structure with parameters. (Two of these parameters will be the location of the SMS message and its sending parameters.)
SMSendingOptions
are located.
All of these steps are accomplished by simply filling in a
MailboxRegisterMessageArgs
structure. This structure is large, but it is not altogether complicated. Each field is described in the following sections, though only SMS relevant information is shown. It is shown below:
typedef struct {
MailboxStorage MRA_bodyStorage;
MailboxDataFormat MRA_bodyFormat;
const void *MRA_bodyRef;
word MRA_bodyRefLen;
MailboxTransport MRA_transport;
MailboxTransportOption MRA_transOption;
MailboxTransAddr *MRA_transAddrs;
word MRA_numTransAddrs;
dword MRA_transData;
MailboxMessageFlags MRA_flags;
const char *MRA_summary;
GeodeToken MRA_destApp;
FileDateAndTime MRA_startBound;
FileDateAndTime MRA_endBound;
} MailboxRegisterMessageArgs;
As we mentioned, the Mailbox will need to store a message in a format that it can understand. Rather than have the Mailbox understand every data format that is (or will ever be) developed, it is easier to "package" the message in a small number of standard formats. You specify in what format the message will be wrapped in the MRA
_bodyStorage
field.
bodyStorage
indicates under what format (of type
MailboxStorage
) the message will be stored in the internal Mailbox administration file.
MailboxStorage
is defined as follows:typedef struct {
word MS_id;
ManufacturerID MS_manuf;
} MailboxStorage;
MS_id
GeoworksMailboxStorageID. The following types are valid:GMSID_FILE GMSID_VM_TREE
MS_manuf
ManufacturerID
of the data driver being used. Since we will be using Geoworks VM trees, we will store MANUFACTURER_ID_GEOWORKS in this location.MRA_bodyFormat
MailboxDataFormat
. This is defined below:typedef struct {
word MDF_id;
ManufacturerID MDF_manuf;
} MailboxDataFormat;
MDF_id
GeoworksMailboxDataFormatID. Pass GMDFID_SHORT_MESSAGE in this field
to indicate that the message is a Geoworks SMS message.MDF_manuf
ManufacturerID
of the format. Since we will be using Geoworks SMS , we will
store MANUFACTURER_ID_GEOWORKS in this location.
_bodyRef
stores a pointer to the reference of the SMS message. Since we will be storing the message in a VM tree, we will reference that message with a
VMAppTreeRef
.
bodyRefLen
stores the length of the reference indicated in MRA_
bodyRef
. In this case, we will store the size of the
VMAppTreeRef
structure.
transport
field.
_transport
takes an argument of type
MailboxTransport
. This is defined below:typedef struct {
word MT_id;
ManufacturerID MT_manuf;
} MailboxTransport;
MT_id
GeoworksMailboxTransportID. MT_manuf
ManufacturerID
of the transport driver being used. Since we will be using Geoworks SM transport driver, we will store MANUFACTURER_ID_GEOWORKS in this location.MRA_transOption
MRA_transAddrs
MailboxTransAddr
structure; it is only important that the transport driver understand the format for this address.
MailboxTransAddr
structures. This structure is defined below:typedef struct {
const void *MTA_transAddr;
unsigned MTA_transAddrLen;
const char *MTA_userTransAddr;
} MailboxTransAddr;
MTA_transAddrMTA_transAddrLenMTA_transAddr.MTA_userTransAddrMTA_transAddr.MRA_numTransAddrsMRA_transAddrs.MRA_transData
DBItem
containing a structure of type
SMSendingOptions
.MRA_flags
MailboxMessageFlags. MRA_summaryMRA_destApp
GeodeToken
of the destination application.MRA_startBound
FileDateAndTime
) to begin transmission of the message. You may also pass the value MAILBOX_NOW (0) for immediate delivery.MRA_endBound
FileDateAndTime
) to end attempts to transmit the message to the service provider. You may also pass the value MAILBOX_ETERNITY (-1) to indicate attempt until successful.Code Display 3-4 Setting Up the Mailbox Registration Arguments
MailboxRegisterMessageArgs registerArgs; MailboxTransAddr addressList; TCHAR number[MAX_ADDRESS_SIZE]
/* * We tell the mailbox that the data is stored within a VMTreeAppRef. */ registerArgs.MRA_bodyStorage.MS_id = GMSID_VM_TREE; registerArgs.MRA_bodyStorage.MS_manuf = MANUFACTURER_ID_GEOWORKS;
/* * We tell the mailbox that this is an SMS message. */ registerArgs.MRA_bodyFormat.MDF_id = GMDFID_SHORT_MESSAGE; registerArgs.MRA_bodyFormat.MDF_manuf = MANUFACTURER_ID_GEOWORKS;
/* * We tell the mailbox where the body text is stored. */ MRA_bodyRef = &vmRef; registerArgs.MRA_bodyRefLen = sizeof(VMTreeAppRef);
/* * We tell the mailbox to use the SM transport driver when sending the message. */ registerArgs.MRA_transport.MT_id = GMTID_SM; registerArgs.MRA_transport.MT_manuf = MANUFACTURER_ID_GEOWORKS;
registerArgs.MRA_transOption = 0;
/* * Normally, we would retrieve the phone number from an outside source (such as * the contact database). Here, we just set it to a specific value. */
number = "13125551212";
/* * We need to stuff each address (in this case, a phone number) into a * MailboxTransAddr structure. */
addressList.MTA_transAddr = &number; addressList.MTA_transAddrLen = strlen(number); addressList.MTA_userTransAddr = &number;
registerArgs.MRA_transAddrs = &addressList; registerArgs.MRA_numTransAddr = 1;
/* * We pass the previously set up SMSendingOptions in the DBGroupItem to the * transport driver. */ registerArgs.MRA_transData = smsParams;
registerArgs.MRA_flags = MMF_DELETE_BODY_AFTER_TRANSMISSION;
registerArgs.MRA_summary = "Chess Move";
strcpy(registerArgs.MRA_destApp.GT_chars, "SKAA"); registerArgs.MRA_destApp.GT_manufID = MANUFACTURER_ID_NOKIA;
registerArgs.MRA_startBound = MAILBOX_NOW; registerArgs.MRA_endBound = MAILBOX_ETERNITY;
MailboxRegisterMessage(), MailboxDoneWithVMFile()
Finally, you have everything set up. To send the message, all you need to do is register the message with the mailbox library.
MailboxRegisterMessage()
takes an address (of type
MailboxMessage
) as a second parameter. The routine will write a token value into this address so that future mailbox routines can refer to this message by its token.
Do not confuse this token with the actual message (which is sent through the
MailboxRegisterMessageArgs
).
After you have successfully registered the message, call
MailboxDoneWithVMFile()
to tell the mailbox to get rid of the temporary VM file it had created.
Code Display 3-5 Using MailboxRegisterMessage
MailboxRegisterMessageArgs registerArgs; MailboxMessage msgToken; MailboxError mailboxError; VMFileHandle vmFile;
mailboxError = MailboxRegisterMessage(®isterArgs, &msgToken);
if (mailboxError == ME_SUCCESS) {
/* If we want to do anything special upon success, here it would reside ... */
};
MailboxDoneWithVMFile(vmFile);
There is a possibility that
MailboxRegisterMessage()
may return an error (of type
MailboxError
) if something is not working correctly (or if the message was not set up correctly). The routine returns ME_SUCCESS if the registration was successful.
The following are valid mailbox error codes:
ME_SUCCESS = 0 ME_NOT_ENOUGH_MEMORY ME_CANNOT_LOAD_DATA_DRIVER ME_CANNOT_LOAD_TRANSPORT_DRIVER ME_UNABLE_TO_CREATE_TRANSMIT_THREAD ME_CANNOT_ENQUEUE_MESSAGE ME_USER_CANCELED ME_LOST_CONNECTION ME_CANNOT_CREATE_MESSAGE_FILE ME_CANNOT_RESIZE_MBOX_REF ME_CANNOT_SAVE_MESSAGE_FILE ME_CANCELLED_BY_RECEIVER ME_MESSAGE_BLOCKS_ARE_MISATCHED ME_DATA_DRIVER_CANNOT_STORE_MESSAGE_BODY ME_INSUFFICIENT_DISK_SPACE ME_CANNOT_CONNECT
The following are unrecoverable
MailboxError
error codes. (The high bit is set if this is the case.)
#define ME_UNRECOVERABLE 0x8000
ME_ADDRESS_INVALID ME_DATA_DRIVER_CANNOT_ACCESS_MESSAGE_BODY ME_UNSUPPORTED_BODY_FORMAT ME_MESSAGE_BODY_INVALID ME_INVALID_MESSAGE ME_REPLY_ADDRESS_NOT_AVAILABLE ME_DESTINATION_APPLICATION_UNKNOWN ME_UNKNOWN_DISK_ERROR ME_APP_REF_BUF_TOO_SMALL ME_CANNOT_OPEN_MESSAGE_FILE ME_CANNOT_READ_MESSAGE_FILE ME_CAN_NEVER_CONNECT
GEOS SDK TechDocs
|
|
3.1 Sending and the Mailbox Library
|
4 Receiving an SMS Message