Discussing the nuts and bolts of software development

Tuesday, June 17, 2008

 

Obtaining the voicemail number on Windows Mobile phones

The voicemail number, if available, may be stored in various locations on the Windows Mobile phone device depending on the type and carrier. In most cases, the number will show up somewhere in the registry. From experience I have found them in one of several locations under HKEY_CURRENT_USER:

\Software\Microsoft\Vmail\PhoneNumber1
\Software\Microsoft\Vmail\PhoneNumber2
\Software\Microsoft\Vmail\UserProvidedNumber1
\Software\Microsoft\Vmail\CarrierProviderNumber1
\System\State\Messages\vmail\VMailNumber
\Palm\State\Messages\vmail\VMailNumber

On some GSM devices however the number isn’t always updated properly in the registry. In that case you would have to fetch it direct from the SIM card. In fact it is probably safest to fetch it from the SIM card first since this ensures a more accurate number.

If you do some internet searches and dig through some of the 3GPP specifications for (U)SIM (i.e. 3GPP TS 31.102, 51.011) you will find that the voicemail number is stored in the EFMBDN (Mailbox Dialing Numbers) file located at either 6FC7 for 3G devices or 6F17 for 2G.

We can get the voicemail file from the SIM using the SIM Manager API. Note that some of these are privileged functions. You also have to make sure to add “cellcore.lib” as a dependency to your project. The code would look as follows:


// include the SIM Manager API
#include

// set the voicemail addresses
#define EF_MBDN_2G 0x6F17
#define EF_MBDN_3G 0x6FC7



std::string getVoicemailNumber()
{

std::string number;
HSIM hSim = 0;
HRESULT hr = S_OK;

// initialize
hr = SimInitialize (0, 0, 0, (LPHSIM)&hSim);

if (S_OK == hr)
{
DWORD address = EF_MBDN_2G;
SIMRECORDINFO simRecordInfo = {0};
simRecordInfo.cbSize = sizeof(SIMRECORDINFO);

// check the 2G address for the file
hr = SimGetRecordInfo(hSim, address, &simRecordInfo);

// The file may hold more than one number for devices with
// multiple lines; however we will assume only one line.
// A valid file needs to be "linear" type and at least 14 bytes.
if ( S_OK != hr ||
SIM_RECORDTYPE_LINEAR != simRecordInfo.dwRecordType ||
simRecordInfo.dwItemCount == 0 ||
simRecordInfo.dwSize < 14 )
{
// no valid 2G file, check the 3G address
address = EF_MBDN_3G;
memset(&simRecordInfo, 0, sizeof(simRecordInfo));
simRecordInfo.cbSize = sizeof(SIMRECORDINFO);
hr = SimGetRecordInfo(hSim, address, &simRecordInfo);
}

if ( S_OK == hr &&
SIM_RECORDTYPE_LINEAR == simRecordInfo.dwRecordType &&
simRecordInfo.dwItemCount > 0 &&
simRecordInfo.dwSize >= 14)
{
// allocate the specified size
LPBYTE buf = (LPBYTE)LocalAlloc(LPTR, simRecordInfo.dwSize);
DWORD bytesRead = 0;

// read the SIM file
hr = SimReadRecord(hSim, address, SIM_RECORDTYPE_LINEAR, 1,
buf, simRecordInfo.dwSize, &bytesRead);

if (S_OK == hr && bytesRead >= 14)
{
// handle the bytes received
...


Now that we have the file, we need to interpret the bytes into a useful number. The 3GPP specifications show the EFMBDN structure as follows:


Bytes Description M/O Length
----------------------------------------------------------------------
1 to X Alpha Identifier O X bytes
X+1 Length of BCD number/SSC contents M 1 byte
X+2 TON and NPI M 1 byte
X+3 to X+12 Dialling Number/SSC contents M 10 bytes
X+13 Capability/Configuration2 Record Identifier M 1 byte
X+14 Extension 6 Record Identifier M 1 byte


The first few bytes (1 to X) are the optional identifier. In most cases it will just show the words “voicemail”. The last 14 bytes describe the voicemail number with up to 10 bytes representing the number as binary coded decimals. For our purpose we can ignore Capability/Configuration2 Record Identifier and Extension 6 Record Identifier. The way to interpret the bytes is described in the 3GPP specifications 31.102 clause 4.4.2.3 for EFADN (Abbreviated dialing numbers). We can proceed to get the number from the bytes as follows:


...

// use the last 14 bytes
char data[14];
memcpy(&data, &buf[bytesRead-14], 14);

// byte 0 (X+1) is the length of dialing number
int length = data[0];

std::stringstream ss;

// TON and NPI determines the type of number
// see 3GPP specifications 31.102 clause 4.4.2.3
if (0x90 == (0xF0 & data[1]))
{
// add the + for international numbers
ss << '+';
}

// convert the BCD bytes to Ascii chars
for (int idx=2; idx < length+1; idx++)
{
// break the byte into 2 nibbles
BYTE nibble[2];
nibble[0] = data[idx] & 0xF;
nibble[1] = (data[idx] >> 4) & 0xF;

for (int i=0; i<2; i++)
{
if (nibble[i] == 0xA)
{
// 0xA represents a *
ss << '*';
}
else if (nibble[i] == 0xB)
{
// 0xB represents a #
ss << '#';
}
else if (nibble[i] < 0xA)
{
// add the number
ss << (char) ('0' + nibble[i]);
}
}
}

// set the voicemail number
ss >> number;


Now that we have the voicemail number we should free the buffer and sim handle and return the number:


// free the buffer
LocalFree( buf );
}

// deinitialize
SimDeinitialize( hSim );
}
return number;

}


There are a couple of things to note. Here I’ve handled both the 2G and 3G cases, however it is probably better to detect which type is being used beforehand. Also note that I have assumed the case of only one voicemail number. For a multi-line scenario you would have to check if there are more than one number stored in the SIM file. For a more detailed look on how the numbers are stored please refer to the 3GPP specifications.

Labels:


Comments:
Thanks, Buddy.

Jacob
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?