SIM Manager

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.

Figure 8.3. Pocket PC Phone Edition SIM Manager

graphics/08fig03.gif

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.

Initialization and Notifications

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.

Table 8.1. SIM Callback Notifications

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);

SIM Details

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.

Table 8.2. SIM Device Capabilities Parameters

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);
}

The SIM Phonebook

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.

Table 8.3. SIM Phonebook Entry Flags

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.

Table 8.4. SIM Phonebook Address Types

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);

Working with SIM-Based Messages

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.

Table 8.5. SIM Message Parameters

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);

The SIM File System

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.

Figure 8.4. SIM card file system structure

graphics/08fig04.gif

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.

Table 8.6. SIM File Types

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).

Table 8.7. The GSM File System

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