Every phone or data device that operates on the GSM (Global System for Mobile) network contains a small, postage stamp?sized card that is known as the Subscriber Identity Module (SIM). The SIM is actually a smart card that contains both a processor and storage for contacts, messages, and data. Typical SIM cards have between 16KB and 64KB of storage, which provides you with plenty of room for hundreds of phone numbers, messages, or other information.
You can usually remove the SIM card from the phone, which enables you to move your phone numbers, contacts, and other data between devices. For example, if you remove the SIM card from your GSM phone and place it into a Pocket PC Phone Edition device, the Pocket PC will have access to all of the dialing information, messages, and even phone numbers that the old device had. In essence, the SIM card is the storage medium for all of your personal and subscription data.
Pocket PC Phone Edition provides a set of functions called the SIM Manager (see Figure 8.3), which enables you to interact with the SIM card currently in the device. These APIs enable you to change the status of the phone locked state, manipulate contact entries that are on the SIM card, and read messages currently stored on the card.
In order to use the SIM Manager APIs in your applications, you need to include the simmgr.h header file in your project, and link with the cellcore.lib library.
Before you can access any information on the SIM card, you first must call the SimInitialize() function. This function actually has two purposes: One, it provides a handle to the SIM, which you will use for additional calls to get information from the card. Two, SimInitialize() can be used to register a callback function that will send you notifications whenever changes occur to the SIM while you have the handle open:
HRESULT SimInitialize(DWORD dwFlags, SIMCALLBACK lpfnCallBack, DWORD dwParam, LPHSIM lphSim);
The first parameter, dwFlags, specifies whether or not you want to receive notification messages from the SIM. By setting the flag to SIM_INIT_SIMCARD_NOTIFICATIONS, notifications will be sent to the callback function that is pointed to by the lpfnCallback parameter. If you do not need to receive informational messages from the SIM, you can set dwFlags to 0, and lpfnCallBack to NULL. The dwParam parameter is a DWORD value that is sent to your callback function every time a notification is sent. The last parameter, lphSim, is a pointer to an HSIM handle that you will use for making additional calls to the SIM card.
The following example initializes the SIM card for reading data without using a callback:
HRESULT hr = S_OK; HSIM hSim = NULL; // Initialize and open the SIM w/o a callback hr = SimInitialize(0, NULL, 0, &hSim); if(FAILED(hr)) { MessageBox(NULL, TEXT("Could not open the SIM"), TEXT("Error"), MB_OK|MB_ICONERROR); return FALSE; } // Continue with app...
If you decide to receive notifications from the SIM when changes occur, then you need to pass a pointer to a callback function (identified by the lpfnCallBack parameter). Whenever the device or another application attempts to modify the contents of the SIM card, your function will then be called. The callback function you create must have the following definition:
void SIMCallbackFunction(DWORD dwNotifyCode, const void *lpData, DWORD dwDataSize, DWORD dwParam);
The first parameter that will be sent to your function specifies the notification that was received from the SIM. Next, the contents of the lpData pointer will depend on which notification message you are receiving. For example, if you are sent a SIM_NOTIFY_CARD_REMOVED, then lpData will be NULL. However, if you received a SIM_NOTIFY_PBE_DELETED notification, lpData will point to a SIMPBECHANGE structure that provides additional information about the phonebook entry that has been modified.
Table 8.1 lists both the notification messages and the structure information sent to lpData.
Notification | lpData | Description |
---|---|---|
SIM_NOTIFY_CARD_REMOVED | NULL | The SIM card has been removed. |
SIM_NOTIFY_FILE_REFRESH | SIMFILEREFRESH | Files on the SIM have been refreshed. |
SIM_NOTIFY_MSG_STORED | SIMMESSAGECHANGE | A message has been stored on the SIM. |
SIM_NOTIFY_MSG_DELETED | SIMMESSAGECHANGE | A message has been deleted from the SIM. |
SIM_NOTIFY_MSG_RECEIVED | SIMMESSAGECHANGE | A message was sent directly to the SIM. |
SIM_NOTIFY_PBE_STORED | SIMPBECHANGE | A phonebook entry has been stored on the SIM. |
SIM_NOTIFY_PBE_DELETED | SIMPBECHANGE | A phonebook entry has been deleted from the SIM. |
SIM_NOTIFY_RADIOOFF | NULL | The modem radio has been turned off. |
SIM_NOTIFY_RADIOON | NULL | The modem radio has been turned on. |
SIM_NOTIFY_RADIOPRESENT | DWORD | The modem radio has been installed. The DWORD value stored in lpData will indicate 0 if the radio is off, and 1 if it is on. |
SIM_NOTIFY_RADIOREMOVED | NULL | The modem radio has been removed. |
The dwDataSize parameter will specify, in bytes, the size of the structure returned in lpData. The final parameter, dwParam, is the DWORD value that was previously set in your original call to the SimInitialize() function.
If any changes to the files on the SIM occur (SIM_NOTIFY_FILE_REFRESH), your callback function will be passed a SIMFILEREFRESH structure that looks like the following:
typedef struct simfilerefresh_tag{ DWORD cbSize; DWORD dwParams; DWORD dwFlags; DWORD dwFileCount; DWORD rgdwAddress[MAX_FILES]; } SIMFILEREFRESH, FAR *LPSIMFILEREFRESH;
The first field, cbSize, is the size, in bytes, of the SIMFILEREFRESH structure. Next, the dwParams field specifies which of the fields in the SIMFILEREFRESH structure are valid, and can be one or more of the following values:
SIM_PARAM_FILEREFRESH_FLAGS indicates that the dwFlags field is valid.
SIM_PARAM_FILEREFRESH_FILECOUNT indicates that the dwFileCount field is valid.
SIM_PARAM_FILEREFRESH_FILEARRAY indicates that the rgdwAddress field is valid.
SIM_PARAM_FILEREFRESH_ALL indicates that all the fields are valid.
The dwFlags field contains additional details about what has changed with regard to the SIM's file system, and can be one or more of the following:
SIMFILE_FULLFILECHANGE specifies that all files have changed.
SIMFILE_FILECHANGE specifies that only a few files have changed.
SIMFILE_SIMINIT specifies that the SIM has been initialized.
SIMFILE_SIMRESET specifies that the SIM has been reset.
The dwFileCount field, as the name implies, contains a DWORD value that indicates how many files have changed, and indicates the number of rgdwAddress structures in the array of files.
For example, the following code would handle a notification that some files have changed on the SIM:
// The SIM notification callback void SimCallbackProc(DWORD dwNotifyCode, const void *lpData, DWORD dwDataSize, DWORD dwParam) { // Handle a file change if(dwNotifyCode == SIM_NOTIFY_FILE_REFRESH) { SIMFILEREFRESH *pfileRefresh = (SIMFILEREFRESH *)lpData; TCHAR tchNotifyMessage[1024] = TEXT("\0"); if(!pfileRefresh) return; // Handle the file change notification if(pfileRefresh->dwParams & SIM_PARAM_FILEREFRESH_FILECOUNT) { wsprintf(tchNotifyMessage, TEXT("%d files have changed"), pfileRefresh->dwFileCount); MessageBox(NULL, tchNotifyMessage, TEXT("SIM File Change"), MB_OK); } // Get the DWORD address of the SIM files that have changed // if(pfileRefresh->dwParams & SIM_PARAM_FILEREFRESH_FILEARRAY) { DWORD dwFiles = 0; for(dwFiles; dwFiles < pfileRefresh->dwFileCount; dwFiles++) { wsprintf(tchNotifyMessage, TEXT("File change #%d. File address: %d"), dwFiles, pfileRefresh->rgdwAddress[dwFiles]); MessageBox(NULL, tchNotifyMessage, TEXT("SIM Files Change"), MB_OK); } } } return; } // Initialize the SIM BOOL InitializeSIM(HSIM *phSim) { HRESULT hr = S_OK; // Initialize and open the SIM w/ a callback hr = SimInitialize(SIM_INIT_SIMCARD_NOTIFICATIONS, (SIMCALLBACK)SimCallbackProc, 0, phSim); if(FAILED(hr)) { MessageBox(NULL, TEXT("Could not open the SIM"), TEXT("Error"), MB_OK|MB_ICONERROR); return FALSE; } return TRUE; }
If the SIM detects any changes to a message located on the card (SIM_NOTIFY_MSG_STORED, SIM_NOTIFY_MSG_DELETED, or SIM_NOTIFY_MSG_RECIEVED), the callback function is passed a SIMMESSAGECHANGE structure, which is defined as follows:
typedef struct simmessagechange_tag{ DWORD dwEntry; DWORD dwStorage; } SIMMESSAGECHANGE, FAR *LPSIMMESSAGECHANGE;
This structure has only two fields: the index to the entry that has changed and its storage location. The dwStorage field will be set to the SIM_SMSSTORAGE_BROADCAST location if its storage location is with system broadcast messages; otherwise, it will be set to SIM_SMSSTORAGE_SIM.
Finally, the last type of notification you can receive deals with entries in SIM's phonebook (SIM_NOTIFY_PBE_STORED, SIM_NOTIFY_PBE_DELETED), and uses the SIMPBECHANGE structure:
typedef struct simpbechange_tag{ DWORD dwEntry; DWORD dwStorage; } SIMPBECHANGE, FAR *LPSIMPBECHANGE;
The first field is the index to the phonebook entry that has changed. The dwStorage field specifies the phonebook in which the entry is located, and can be one of the following values:
SIM_PBSTORAGE_EMERGENCY, if the entry is located in the Emergency dial list
SIM_PBSTORAGE_FIXEDDIALING, if the entry is in the SIM fixed dialing list SIM_PBSTORAGE_LASTDIALING, if the entry is in the SIM last dialing list
SIM_PBSTORAGE_OWNNUMBERS, if the entry is in the SIM ownnumbers list
SIM_PBSTORAGE_SIM, if the entry is in the general SIM storage
The following code shows how to handle a notification message that indicates a change to one of the phonebook entries:
// The SIM notification callback void SimCallbackProc(DWORD dwNotifyCode, const void *lpData, DWORD dwDataSize, DWORD dwParam) { // Handle a phonebook change if(dwNotifyCode == SIM_NOTIFY_PBE_STORED || dwNotifyCode == SIM_NOTIFY_PBE_DELETED) { SIMPBECHANGE *pPBNotify = (SIMPBECHANGE *)lpData; TCHAR tchNotifyMessage[1024] = TEXT("\0"); TCHAR tchPhonebook[256] = TEXT("\0"); if(!pPBNotify) return; switch(pPBNotify->dwStorage) { case SIM_PBSTORAGE_EMERGENCY: wsprintf(tchPhonebook, TEXT("Emergency Number List")); break; case SIM_PBSTORAGE_FIXEDDIALING: wsprintf(tchPhonebook, TEXT("Fixed Dialing List")); break; case SIM_PBSTORAGE_LASTDIALING: wsprintf(tchPhonebook, TEXT("Last Numbered Dialed List")); break; case SIM_PBSTORAGE_OWNNUMBERS: wsprintf(tchPhonebook, TEXT("Own Number List")); break; case SIM_PBSTORAGE_SIM: wsprintf(tchPhonebook, TEXT("General List")); break; default: wsprintf(tchPhonebook, TEXT("Unknown List")); break; } // Build a message wsprintf(tchNotifyMessage, TEXT("A phonebook entry in the %s at index %d has been "), tchPhonebook, pPBNotify->dwEntry); // Type of notification if(dwNotifyCode == SIM_NOTIFY_PBE_DELETED) _tcscat(tchNotifyMessage, TEXT("deleted.")); else if(dwNotifyCode == SIM_NOTIFY_PBE_STORED) _tcscat(tchNotifyMessage, TEXT("modified.")); } return; }
When you are finished working with information on the SIM, you can simply call the SimDeinitialize() function, which is defined as follows:
HRESULT SimDeinitialize(HSIM hSim);
The only parameter that the function needs is a handle to the SIM module that was previously returned by the original call to SimInitialize().
The following code sample shows how to properly release the handle to the SIM module:
// Close the SIM handle if(hSim) SimDeinitialize(hSim);
To get more information about what functionality the SIM supports, you can use the following function:
HRESULT SimGetDevCaps(HSIM hSim, DWORD dwCapsType, LPSIMCAPS lpSimCaps);
This function can be used to query specific capabilities of the SIM by functional area, or to return information about the phonebook or locking passwords. To use it, you need to pass the handle to the SIM that was returned from a previous call to SimInitialize() in the hSim parameter. The dwCapsType parameter can be used to set which capabilities you are interested in, and can be one or more of the following values:
SIM_CAPSTYPE_PBENTRYLENGTH, to query phonebook entry lengths
SIM_CAPSTYPE_PBSTORELOCATIONS, to query phonebook storage locations
SIM_CAPSTYPE_LOCKFACILITIES, to query the available Lock facilities
SIM_CAPSTYPE_PBINDEXRANGE, to query valid phonebook entry indexes
SIM_CAPSTYPE_LOCKINGPWDLENGTHS, to query the Locking password lengths
SIM_CAPSTYPE_MSGMEMORYLOCATIONS, to query Message memory locations
SIM_CAPSTYPE_ALL, to query all of the SIM capabilities
The last parameter, lpSimCaps, should point to a SIMCAPS structure that will receive the capabilities specified in the dwCapsType parameter. The structure is defined as follows:
typedef struct simcaps_tag{ DWORD cbSize; DWORD dwParams; DWORD dwPBStorages; DWORD dwMinPBIndex; DWORD dwMaxPBIndex; DWORD dwMaxPBEAddressLength; DWORD dwMaxPBETextLength; DWORD dwLockFacilities; DWORD dwReadMsgStorages; DWORD dwWriteMsgStorages; DWORD dwNumLockingPwdLengths; SIMLOCKINGPWDLENGTH rgLockingPwdLengths[SIM_NUMLOCKFACILITIES]; } SIMCAPS, FAR *LPSIMCAPS;
The cbSize field must be set to the size of the SIMCAPS structure before calling the SimGetDevCaps() function. The dwParams field indicates what other fields in the structure contain data, and can be set to one or more of the values described in Table 8.2.
Value | Valid Fields | |
---|---|---|
SIM_PARAM_CAPS_PBSTORAGES | dwPBStorages is valid. | |
SIM_PARAM_CAPS_PBEMAXADDRESSLENGTH | dwMaxPBEAddressLength is valid. | |
SIM_PARAM_CAPS_PBEMAXTEXTLENGTH | dwMaxPBETextLength is valid. | |
SIM_PARAM_CAPS_PBEMININDEX | dwMinPBIndex is valid. | |
SIM_PARAM_CAPS_PBEMAXINDEX | dwMaxPBIndex is valid. | |
SIM_PARAM_CAPS_LOCKFACILITIES | dwLockFacilities is valid. | |
SIM_PARAM_CAPS_LOCKINGPWDLENGTH | dwNumLockingPwdLengths and rgLockingPwdLengths are valid. | |
SIM_PARAM_CAPS_READMSGSTORAGES | dwReadMsgStorages is valid. | |
SIM_PARAM_CAPS_WRITEMSGSTORAGES | dwWriteMsgStorages is valid. | |
SIM_PARAM_CAPS_ALL | All fields are valid. |
The dwPBStorages, dwMinPBIndex, and dwMaxPBIndex fields contain the total number (as well as the minimum and maximum number) of entries that are available for the SIM card's phonebook. The maximum length of an address is stored in the dwMaxPBEAddressLength field, and dwMaxPBETextLength will contain the maximum length for any text string in an entry.
The dwReadMsgStorages and dwWriteMsgStorages fields pertain to the total number of read and write storage areas that are available on the SIM, respectively.
The last set of available fields deals with the locking capabilities of the SIM card. The dwLockFacilities field contains the total number of supported locking facilities that are available on the SIM. Each of these is described in the array of SIMLOCKINGPWDLENGTH structures specified by the rgLockingPwdLengths field. The SIMLOCKINGPWDLENGTH structure contains information about the locking facility index and its maximum password length, and has the following prototype:
typedef struct simlockingpwdlength{ DWORD dwFacility; DWORD dwPasswordLength; } SIMLOCKINGPWDLENGTH, FAR *LPSIMLOCKINGPWDLENGTH;
The following example queries the available capabilities of a SIM card:
// Get the SIM capabilities SIMCAPS simInfo; memset(&simInfo, 0, sizeof(SIMCAPS)); simInfo.cbSize = sizeof(SIMCAPS); hr = SimGetDevCaps(hSim, SIM_CAPSTYPE_ALL, &simInfo); if(FAILED(hr)) { SimDeinitialize(hSim); MessageBox(NULL, TEXT("Could not query the SIM module"), TEXT("Error"), MB_OK|MB_ICONERROR); return FALSE; }
To get the status of an SMS storage location, you can call the following function:
HRESULT SimGetSmsStorageStatus(HSIM hSim, DWORD dwStorage, LPDWORD lpdwUsed, LPDWORD lpdwTotal);
The first parameter is the previously opened handle to the SIM card, and is followed by dwStorage, which should indicate which storage location on the SIM to query. This can be set to either the SIM_SMSSTORAGE_BROADCAST location for the broadcast message location or SIM_SMSSTORAGE_SIM, for the general storage location.
The lpdwUsed parameter should point to a DWORD value that will receive the number of locations that are used, and lpdwTotal is the total number of locations available.
The following example shows how you can use SimGetSmsStorageStatus() to query the storage locations on the SIM:
// Get the SIM general storage usage DWORD dwUsed = 0, dwTotal = 0; TCHAR tchStorage[1024] = TEXT("\0"); hr = SimGetSmsStorageStatus(hSim, SIM_SMSSTORAGE_SIM, &dwUsed, &dwTotal); if(FAILED(hr)) MessageBox(NULL, TEXT("Could not get general storage information"), TEXT("Error"), MB_OK|MB_ICONERROR); else { wsprintf(tchStorage, TEXT("General SIM Storage:\r\n%d Used\r\n%d Free\r\n%d Total"), dwUsed, dwTotal-dwUsed, dwTotal); MessageBox(NULL, tchStorage, TEXT("SIM Usage"), MB_OK|MB_ICONINFORMATION); } // Get the SIM broadcast storage usage dwUsed = dwTotal = 0; hr = SimGetSmsStorageStatus(hSim, SIM_SMSSTORAGE_BROADCAST, &dwUsed, &dwTotal); if(FAILED(hr)) MessageBox(NULL, TEXT("Could not get broadcast storage information"), TEXT("Error"), MB_OK|MB_ICONERROR); else { wsprintf(tchStorage, TEXT("General SIM Storage:\r\n%d Used\r\n%d Free\r\n%d Total"), dwUsed, dwTotal-dwUsed, dwTotal); MessageBox(NULL, tchStorage, TEXT("SIM Broadcast Usage"), MB_OK|MB_ICONINFORMATION); }
Before you start reading and writing entries to the SIM phonebooks, let's first examine how to obtain the number of entries in a particular phonebook location (such as the Emergency dial list). To do so, you can call the following function:
HRESULT SimGetPhonebookStatus(HSIM hSim, DWORD dwLocation, LPDWORD lpdwUsed, LPDWORD lpdwTotal);
The first parameter is the previously opened handle to the SIM card, and is followed by dwLocation, which indicates what phonebook on the SIM to query. This should be set to one of the following: SIM_PBSTORAGE_EMERGENCY, SIM_PBSTORAGE_FIXEDDIALING, SIM_PBSTORAGE_LASTDIALING, SIM_PBSTORAGE_OWNNUMBERS, or SIM_PBSTORAGE_SIM.
The lpdwUsed parameter should point to a DWORD value that will receive the number of entries used in the specified phonebook. The last parameter, lpdwTotal, is the total number of entry "slots" that are available for the phonebook.
The following example shows how you can use SimGetPhonebookStatus() to retrieve the number of entries in the Emergency phonebook:
// Get phonebook status DWORD dwUsed = 0, dwTotal = 0; TCHAR tchPhonebook[1024] = TEXT("\0"); hr = SimGetPhonebookStatus(hSim, SIM_PBSTORAGE_EMERGENCY, &dwUsed, &dwTotal); if(FAILED(hr)) MessageBox(NULL, TEXT("Could not get Emergency Phonebook information"), TEXT("Error"), MB_OK|MB_ICONERROR); else { wsprintf(tchPhonebook, TEXT("Phonebook Usage:\r\n%d Used\r\n%d Free\r\n%d Total"), dwUsed, dwTotal-dwUsed, dwTotal); MessageBox(NULL, tchPhonebook, TEXT("SIM Emergency Phonebook"), MB_OK|MB_ICONINFORMATION); }
To read and write entries from the SIM phonebook, you use the following two functions:
HRESULT SimReadPhonebookEntry(HSIM hSim, DWORD dwLocation, DWORD dwIndex, LPSIMPHONEBOOKENTRY lpPhonebookEntry);
and
HRESULT SimWritePhonebookEntry(HSIM hSim, DWORD dwLocation, DWORD dwIndex, LPSIMPHONEBOOKENTRY lpPhonebookEntry);
Both functions take the same four parameters: the hSim parameter should be the handle to the device's SIM card, dwLocation should be set to one of the phonebook locations (such as SIM_PBSTORAGE_EMERGENCY), and the dwIndex parameter should be the index of the entry to write or read.
The lpPhonebookEntry parameter points to a SIMPHONEBOOKENTRY structure that contains information about the phonebook entry. If you are using the SimWritePhonebookEntry() function, the entry will be saved to the location specified by the dwLocation parameter. When reading an entry, the structure will be filled with the data from the SIM.
The structure used for a phonebook entry is defined as follows:
typedef struct simphonebookentry_tag{ DWORD cbSize; DWORD dwParams; TCHAR lpszAddress[MAX_LENGTH_ADDRESS]; DWORD dwAddressType; DWORD dwNumPlan; TCHAR lpszText[MAX_LENGTH_PHONEBOOKENTRYTEXT]; } SIMPHONEBOOKENTRY, *LPSIMPHONEBOOKENTRY;
The first field, cbSize, should be set to the size of the SIMPHONEBOOKENTRY structure before calling either the SimReadPhonebookEntry() or SimWritePhonebookEntry() functions. The dwParams field will indicate which of the fields in the structure contain valid data, and can be one or more of the values in Table 8.3.
Value | Valid Fields |
---|---|
SIM_PARAM_PBE_ADDRESS | The lpszAddress field is valid. |
SIM_PARAM_PBE_ADDRESS_TYPE | The dwAddressType field is valid. |
SIM_PARAM_PBE_NUMPLAN | The dwNumPlan field is valid. |
SIM_PARAM_PBE_TEXT | The lpszText field is valid. |
SIM_PARAM_PBE_ALL | All fields are valid. |
The entry's phone number is stored as a null-terminated string in the lpszAddress field. Details about what type of number the entry is will be indicated by using one of the flags in Table 8.4 in the dwAddressType field.
Value | Description |
---|---|
SIM_ADDRTYPE_UNKNOWN | Unknown address type. |
SIM_ADDRTYPE_INTERNATIONAL | International number. Note that numbers stored as international should be prefixed with a plus (+) sign before being displayed to the user. |
SIM_ADDRTYPE_NATIONAL | National number. |
SIM_ADDRTYPE_NETWKSPECIFIC | Network-specific number. |
SIM_ADDRTYPE_SUBSCRIBER | Protocol-specific subscriber number. |
SIM_ADDRTYPE_ALPHANUM | Alphanumeric number. |
SIM_ADDRTYPE_ABBREV | Abbreviated number. |
If the entry is a SIM_ADDRTYPE_UNKNOWN, SIM_ADDRTYPE_INTERNATIONAL, or SIM_ADDRTYPE_NATIONAL address type, the dwNumPlan field will provide additional information about the numbering plan (i.e., the format) used for the address. It can be one of the following:
SIM_NUMPLAN_UNKNOWN specifies that the numbering plan is unknown.
SIM_NUMPLAN_TELEPHONE specifies that a standard telephone or ISDN numbering plan (E.164/E.163) is used.
SIM_NUMPLAN_DATA specifies an X.121 data numbering plan.
SIM_NUMPLAN_TELEX specifies a Telex numbering plan.
SIM_NUMPLAN_NATIONAL specifies a national numbering plan.
SIM_NUMPLAN_PRIVATE specifies a private numbering plan.
SIM_NUMPLAN_ERMES specifies that an ERMES (ETSI DE/PS 3 01-3) numbering plan is used.
Finally, the lpszText field contains a null-terminated string that contains any text associated with this entry.
The following code reads the first phonebook entry from the general SIM phonebook:
SIMPHONEBOOKENTRY simPhoneEntry; memset(&simPhoneEntry, 0, sizeof(SIMPHONEBOOKENTRY)); simPhoneEntry.cbSize = sizeof(SIMPHONEBOOKENTRY); hr = SimReadPhonebookEntry(hSim, SIM_PBSTORAGE_SIM, 1, &simPhoneEntry); if(FAILED(hr)) { MessageBox(NULL, TEXT("Could not read phonebook entry"), TEXT("Error"), MB_OK|MB_ICONERROR); return FALSE; } // Process entry here
If you need to write an entry to the phonebook, you can use the following:
// Write a phonebook entry to the SIM SIMPHONEBOOKENTRY simPhoneEntry; memset(&simPhoneEntry, 0, sizeof(SIMPHONEBOOKENTRY)); simPhoneEntry.cbSize = sizeof(SIMPHONEBOOKENTRY); simPhoneEntry.dwParams = SIM_PARAM_PBE_ALL; simPhoneEntry.dwAddressType = SIM_ADDRTYPE_NATIONAL; simPhoneEntry.dwNumPlan = SIM_NUMPLAN_TELEPHONE; wsprintf(simPhoneEntry.lpszAddress, TEXT("5555551212")); wsprintf(simPhoneEntry.lpszText, TEXT("Jeremy")); hr = SimWritePhonebookEntry(hSim, SIM_PBSTORAGE_SIM, 3, &simPhoneEntry); if(FAILED(hr)) MessageBox(NULL, TEXT("Could not write new phonebook entry"), TEXT("Error"), MB_OK|MB_ICONERROR); else MessageBox(NULL, TEXT("New entry added successfully"), TEXT("SIM Write"), MB_OK);
Finally, to delete a phonebook entry from the SIM card, you can use the SimDeletePhonebookEntry() function, which is defined as follows:
HRESULT SimDeletePhonebookEntry(HSIM hSim, DWORD dwLocation, DWORD dwIndex);
The only parameters that the function needs are the handle to the SIM card, the phonebook location, and the index to the entry to delete.
The following short code sample shows how you can delete a SIM phonebook entry:
hr = SimDeletePhonebookEntry(hSim, SIM_PBSTORAGE_SIM, 3); if(FAILED(hr)) MessageBox(NULL, TEXT("Could not delete entry"), TEXT("Error"), MB_OK|MB_ICONERROR); else MessageBox(NULL, TEXT("Entry deleted."), TEXT("SIM Delete"), MB_OK);
To read or write a Short Message Service text message in a specific storage location on the SIM, you can call the following two functions:
HRESULT SimReadMessage(HSIM hSim, DWORD dwStorage, DWORD dwIndex, LPSIMMESSAGE lpSimMessage);
and
HRESULT SimWriteMessage(HSIM hSim, DWORD dwStorage, LPDWORD lpdwIndex, LPSIMMESSAGE lpSimMessage);
Both of these functions need an open handle to the SIM card, as well as a storage location (either SIM_SMSSTORAGE_BROADCAST or SIM_SMSSTORAGE_SIM) as the first two parameters. When you are reading a message from the SIM, the third parameter, dwIndex, should be set to the index of the message you want to read. If you are writing a message, lpdwIndex will point to a DWORD value that receives the index of the message that was written when you called SimWriteMessage().
The last parameter is a pointer to a SIMMESSAGE structure. When reading a message, this structure's fields will be filled in with the contents of the message you specify with the dwIndex parameter. If you are writing a message, you should fill in the structure with the details of the message you want to save.
The SIMMESSAGE structure is defined as follows:
typedef struct simmessage_tag{ DWORD cbSize; DWORD dwParams; TCHAR lpszAddress[MAX_LENGTH_ADDRESS]; DWORD dwAddressType; DWORD dwNumPlan; SYSTEMTIME stReceiveTime; DWORD cbHdrLength; BYTE rgbHeader[MAX_LENGTH_HEADER]; TCHAR lpszMessage[MAX_LENGTH_MESSAGE]; } SIMMESSAGE, FAR *LPSIMMESSAGE;
The first field, cbSize, should be set to the size of the SIMMESSAGE structure before calling either the SimReadMessage() or SimWriteMessage() functions. The dwParams field will indicate which of the fields in the structure contain valid data, and can be set to one or more of the values in Table 8.5.
Value | Valid Fields |
---|---|
SIM_PARAM_MSG_ADDRESS | The lpszAddress field is valid. |
SIM_PARAM_MSG_ADDRESS_TYPE | The lpszAddressType field is valid. |
SIM_PARAM_MSG_NUMPLAN | The dwNumPlan field is valid. |
SIM_PARAM_MSG_RECEIVE_TIME | The stReceiveTime field is valid. |
SIM_PARAM_MSG_HEADER | The rgbHeader field is valid. |
SIM_PARAM_MSG_HEADER_LENGTH | The cbHdrLength field is valid. |
SIM_PARAM_MSG_MESSAGE | The lpszMessage field is valid. |
SIM_PARAM_PBE_ALL | All fields are valid. |
The incoming message address and numbering plan information fields are similar to those described for SIM phonebook entries.
The stReceiveTime field will contain a SYSTEMTIME structure that contains the timestamp for the incoming message. The message header is stored in rgbHeader, and its length is specified by the cbHdrLength field.
The actual message body is stored in lpszMessage.
To delete a message from the SIM, you can use the SimDeleteMessage() function. This function needs a handle to the open a SIM card, a storage location (either SIM_SMSSTORAGE_BROADCAST or SIM_SMSSTORAGE_SIM), and the index of the message to delete. The function is defined as follows:
HRESULT SimDeleteMessage(HSIM hSim, DWORD dwStorage, DWORD dwIndex);
Recall that the Subscriber Identity Module (SIM) card not only contains your phonebook and text messages, but is actually a smart card containing a processor and a file system. The file system that a SIM card uses is based on the ISO-7816 standard for smart card devices, and is fully specified by the GSM 11.11 standard (more information about both standards can be downloaded from http://www.etsi.org).
Although the file system on the SIM card is analogous to that of a file system on the desktop or Pocket PC device (you can read, write, or delete files), there are a few subtle differences:
The root level of the file system is known as the Master file.
Directories are known as Dedicated files and are of a fixed size.
Individual records (or files) are known as Elementary files.
All files are identified as an address (a DWORD value), rather than a filename.
Before you can read from or write to a particular file in the SIM file system, you must first get information about the record.
Figure 8.4 shows the basic tree structure of the SIM file system.
The most noticeable difference between a regular file system (typically found on a PC) and the SIM file system (besides basic terminology) is that each file in the latter has a four-byte file identifier that uniquely identifies it, rather than a filename.
File identifiers are constructed in the following manner on a GSM SIM card. The first two bytes are used to identify the type of file:
3F Master file (file system root)
7F Dedicated file (a directory)
2F Elementary file underneath the Master file
6F Elementary file underneath the Dedicated file
The second two bytes are a unique identifier for the file, and are subject to the following rules:
The file ID is created at the time of file creation.
No two files can have the same identifier under the same parent.
A child and a parent shall never have the same identifier.
Table 8.6 describes the different record types that the SIM card file system can store.
File Type | Description |
---|---|
Transparent | A random access file that can contain any type of data. |
Linear Fixed File | A fixed-length record that can be navigated through by using next, first, last, and so on. The SIM phonebook is an example of records that are Linear Fixed. |
Cyclic | A fixed-length set of records that will loop to the first entry after the last entry is read; they are stored in chronological order. The "last number dialed" list is an example of records that are Cyclic. |
Variable-length records | Not supported. |
Incremental | A single-byte record that can be incremented or decremented by one. |
Every SIM card that is provisioned with a Pocket PC Phone Edition device already contains several required files that are needed in order to maintain compatibility with the GSM protocol. Although most of these records are marked as read-only by your wireless carrier, they contain a lot of useful information that can be used in your own applications.
Table 8.7 describes the files located in the GSM SIM file system (more detailed information about each file can also be found in the GSM 11.11 specification).
Name | Address (ID) | Level | Type | Description |
---|---|---|---|---|
ICC-ID | 0x2FE2 | Master | Transparent | ICC card serial number |
GSM | 0x7F20 | N/A | N/A | Directory for GSM files |
LP | 0x6F05 | Application | Transparent | Language preference |
IMSI | 0x6F07 | Application | Transparent | International Mobile Subscriber Identity (IMSI) |
KC | 0x6F20 | Application | Transparent | Ciphering key |
PLMN | 0x6F30 | Application | Transparent | PLMN Selector |
HPLMN | 0x6F31 | Application | Transparent | HPLMN search interval time |
ACMMAX | 0x6F37 | Application | Transparent | Accumulated call meter maximum |
SST | 0x6F38 | Application | Transparent | SIM service table |
ACM | 0x6F39 | Application | Cyclic | Accumulated call meter |
GID1 | 0x6F3E | Application | Transparent | Group Identifier Level 1 |
GID2 | 0x6F3F | Application | Transparent | Group Identifier Level 2 |
SPN | 0x6F46 | Application | Transparent | Service provider name |
PUCT | 0x6F41 | Application | Transparent | Price per unit and currency table |
CBMI | 0x6F45 | Application | Transparent | Cell Broadcast Message Identifier selection |
CBMID | 0x6F48 | Application | Transparent | Cell Broadcast Message Identifier for Data Download |
CBMIR | 0x6F50 | Application | Transparent | Cell Broadcast Message Identifier |
BCCH | 0x6F74 | Application | Transparent | Broadcast control channels |
ACC | 0x6F78 | Application | Transparent | Access control class |
FPLMN | 0x6F7B | Application | Transparent | Forbidden PLMNs |
LOCI | 0x6F7E | Application | Transparent | Location information |
AD | 0x6FAD | Application | Transparent | Administrative data |
PHASE | 0x6FAE | Application | Transparent | Phase identification |
VGCS | 0x6FB1 | Application | Transparent | Voice Group Call Service |
VGCSS | 0x6FB2 | Application | Transparent | Voice Group Call Service status |
VBS | 0x6FB3 | Application | Transparent | Voice Broadcast Service |
VBSS | 0x6FB4 | Application | Transparent | Voice Broadcast Service Status |
eMLPP | 0x6FB5 | Application | Transparent | Enhanced Multi-Level Preemption and Priority |
AAeM | 0x6FB6 | Application | Transparent | Automatic Answer for eMLPP Service |
ECC | 0x6FB7 | Application | Transparent | Emergency Call Codes |
Telcom | 0x7F10 | N/A | N/A | Directory for Telcom files |
ADN | 0x6F3A | Telcom | Linear Fixed | Abbreviated dialing numbers |
FDN | 0x6F3B | Telcom | Linear Fixed | Fixed dialing numbers |
SMS | 0x6F3C | Telcom | Linear Fixed | Short messages |
CCP | 0x6F3D | Telcom | Linear Fixed | Capability configuration parameters |
MSISDN | 0x6F40 | Telcom | Linear Fixed | MSISDN |
SMSP | 0x6F42 | Telcom | Linear Fixed | Short message service parameters |
SMSS | 0x6F43 | Telcom | Transparent | Short message service status |
LND | 0x6F44 | Telcom | Cyclic | Last number dialed |
SDN | 0x6F49 | Telcom | Linear Fixed | Service Dialing Numbers |
EXT1 | 0x6F4A | Telcom | Linear Fixed | Extension 1 |
EXT2 | 0x6F4B | Telcom | Linear Fixed | Extension 2 |
EXT3 | 0x6F4C | Telcom | Linear Fixed | Extension 3 |