The Nokia 9110i Communicator uses Contact databases to store
"address book" information. Every time the user enters
information about how a place may be reached by phone, fax, or e-mail
that information is stored in a Contact database, accessed via
the contdb library.
Whenever you prompt the user for information about where to send
something, you'll probably use a ContactList. This will allow
the user to choose which of their contacts should be the recipient.
There are two libraries which exist to keep track of Contact databases and provide an API for the applications which share access to it.
contdb
library keeps track of the contact information, and may be used
to look up or edit contact information. It also provides a
controller which allows the user to choose a contact from a list
of existing contacts.contLog
library provides an API for logging what sorts of communication
has been made with the entities described in the Contact database.
It also provides a controller which allows the user to select a
recently contacted contact.Contact database are Foam databases, and some operations upon the database will make use of Foam database commands. We will not explore the meanings of these commands closely here, but will show how they are used in the context of Contact databases.
Before reading this chapter, you should be familiar with
controllers, Object-Oriented Programming, and the GEOS messaging
system. It helps if you try out the "Contacts" built-in
application, which demonstrates much of the functionality we'll
discuss here. The appl/SDK_9000/Contact/ sample
application gives full source for the most useful Contact database
operations.
Most programmers first encounter the contdb
and ContLog libraries when they need to intercept
a message associated with a ContactList
or perhaps a RecentContactsControl
object. These object classes provide the user with a standard
way to choose a contact.
There are other controllers which allow the user to choose
an SMS contact. SMAddressControlClass allows the
user to choose a recipient for a SMS message. This class should
cover some applications' needs when it comes to allowing the
user to choose a contact. However, if you need a custom
control, you may wish to use a ContactList
and/or a RecentContactsSMSControl.
A ContactList presents the user with a list of
known contacts. The user may choose a name from the list.
In Setting up a Contact List, we show how to set up such an object and get the phone number of
the contact the user selects.
The RecentContactsSMSControl presents the user
with a list containing names and numbers associated with contacts
that have recently had SMS transactions with the user. The user
may choose a name or number from the list. In
Choosing Contacts From a Log, we show how to set up such an object and get the phone number of
the contact the user selects.
1 Setting up a Contact List
1.1 Multiple-Selection ContactLists and Groups
1.2 Remembering the Search
1.3 Detecting Unknown Phone Numbers
1.4 Alternate Messages
2 Choosing Contacts From a Log
3 Using a Dedicated Contact
4 Logging Calls
5 To Get More Info on a Contact
6 The User's Own Data
ContactListClass, CONTACT_LIST_NOTIFY_CONTACT_SELECTED_MSG, ContactGetDBHandle(), FoamDBGetRecordFromID(), FoamDBGetFieldData(), FoamDBDiscardRecord(), ContactReleaseDBHandle()
To present the user with a list of Contacts, do the following:
Make sure that your .gp file contains lines requiring the foamdb and contdb libraries:
library contdb library foamdb
In your source code, create a ContactList
object. The following ContactList
object declaration allows the user to pick a contact. If
the contact has more than one GSM phone number, the controller
will make the user choose one of the fields.
ContactList
will send a message to an object. The ContactList's
GCI_output
and ATTR_CONTACT_LIST_NOTIFY_CONTACT_SELECTED_MSG specify the object
and message. In the example below, the application's process object
will handle a message. We will discuss the message in more detail
below.ContactList SMS-specific, set its
ATTR_CONTACT_LIST_CALL_TYPE to CCT_SMS as shown below. This
will gray out contacts which do not have SMS phone numbers.
ContactList's Search bar, set the
CLF_SEARCH feature flag in ATTR_GEN_CONTROL_REQUIRE_UI; to
exclude the Search bar, exclude the UI.ContactList a ComplexMoniker
and setting its CMI_iconBitmap field to CMB_CONTACT_LIST.Putting this together, we end up with the following:
@object ContactListClass MyContactList = {
GI_visMoniker = "I want to talk to...";
GCI_output = (TO_PROCESS);
ATTR_CONTACT_LIST_CALL_TYPE = CCT_SMS;
ATTR_GEN_CONTROL_REQUIRE_UI = CLF_SEARCH |
CLF_SELECT_CONTACT_NUMBER ;
HINT_EXPAND_HEIGHT_TO_FIT_PARENT;
ATTR_CONTACT_LIST_NOTIFY_CONTACT_SELECTED_MSG =
MSG_MYPROCESS_SEND_MESSAGE ;
}
With this configuration, the ContactList
will send a MSG_MYPROCESS_SEND_MESSAGE
message to your process object when the user chooses a contact. A sample handler for this message is shown below
(Handling the ContactList's "Selected" Message). The message will conform to the prototype:
@prototype void
CONTACT_LIST_NOTIFY_CONTACT_SELECTED_MSG(
dword recordID,
word fieldID);
The message handler should carry out the following steps:
ContactGetDBHandle(). This routine takes no arguments,
and returns the Contact database's handle.FoamDBGetRecordFromID(). This routine takes the Contact's
database handle and the record's RecordID
value. It allocates a block of memory to hold the record's data
and returns the record's handle. FoamDBGetFieldData(). Pass the database handle,
the record handle, the FieldID
associated with the GSM number field (this number is supplied by the
ContactList when it sends this message), a buffer to
write the name to, and the size of that buffer. The function fills in
the buffer with the phone number string, and returns the length of that
string. The returned string might not be null-terminated; thus you will
either need to keep track of the returned string length, or else terminate
the string.FoamDBDiscardRecord(). This routine takes the Contact's
database handle and the record's handle as arguments.ContactReleaseDBHandle().The example below shows a way of carrying out the above set of steps.
Code Display Handling the ContactList's "Selected" Message
@class MyProcessClass, GenProcessClass; @message (CONTACT_LIST_NOTIFY_CONTACT_SELECTED_MSG) MSG_MYPROCESS_SEND_MESSAGE; @endc
@method MyProcessClass, MSG_MYPROCESS_SEND_MESSAGE {
TCHAR theNumber[31];
TCHAR theName[MAX_NAME_DATA_LEN+1];
word numLen;
VMFileHandle CDBHandle;
MemHandle theRecord;
/* Get the Contact database's handle */ CDBHandle = ContactGetDBHandle();
/* Get the handle to the record we're interested in */ theRecord = FoamDBGetRecordFromID( CDBHandle, recordID );
/* Get the GSM phone number string; null-terminate it. */ FoamDBGetFieldData( CDBHandle, theRecord, fieldID, theNumber, 30); theNumber[numLen] = `\000'; /* add null terminator */
/* We'll copy the name to theName buffer. */ ContactGetName(theRecord, theName); /* If you need more information about the contact * (e.g., business name, job title), this is a good place * to retrieve it. */ /* Do what you like with theNumber and theName */
/* We're done with this record. */ FoamDBDiscardRecord(CDBHandle, theRecord );
/* We're done with the database. */ ContactReleaseDBHandle(); }
Multiple-Selection ContactLists and Groups
Detecting Unknown Phone Numbers
Recent versions of the ContDB library support ContactLists which allow the user to select more than one contact at a time, either by selecting contacts one by one or by choosing contact groups. This feature is available on devices with version numbers "Responder Build 4...." and higher. See Software Version Numberfor information about finding out the software version of the user's device.)
To create such a ContactList, give it the hint
HINT_CONTACT_LIST_NON_EXCLUSIVE_LIST.
If your application is running on a
device recent enough to support contact groups, then
ATTR_CONTACT_LIST_ALLOW_GROUP_AS_CALL_TYPE
will allow the user to select a group.
There are two ways to obtain the list of selected contacts:
CLF_SELECT_CONTACT_NUMBER in
ATTR_GEN_CONTROL_REQUIRE_UI, and set
ATTR_CONTACT_LIST_NOTIFY_MULTIPLE_CONTACTS_SELECTED_MSG to the
message which will be sent whenever one or more contacts are selected from
the contact list. This message must be of the prototype:
@prototype void
CONTACT_LIST_NOTIFY_MULTIPLE_CONTACTS_SELECTED_MSG(
MemHandle block = cx,
word num = dx);
The passed memory handle block will contain the set of
ContactListSelectedEntrys, and num will contain
the number of these entries.
Your method must free the passed memory block.
ContactList directly.
Call MSG_CONTACT_LIST_GET_IDS_OF_SELECTED_RECORDS;
the ContactList will return a
ContactListSelectedRecordsData structure containing
the number of selected entries and the handle to a memory block
containing the IDs of the selected entries stored as
ContactListSelectedEntry structures.Normally, a ContactList will lose track of the user's current search if the focus moves to another object. To force the list to remember the current search, send it a MSG_CONTACT_LIST_PRESERVE_SEARCH_ON_NEXT_LOST_FOCUS before it loses the focus. (This message is available on devices with version numbers "Responder Build 4...." and higher. See Software Version Number for information about finding out the software version of the user's device.)
If the user enters a valid phone number in the search box of a ContactList, but that number is not found, an application may request that the ContactList send out a notification using a variable data field. (This variable data field is available on devices with version numbers "Responder Build 4...." and higher. See Software Version Number for information about finding out the software version of the user's device.)
Give the ContactList a ATTR_CONTACT_LIST_NOTIFY_NUMBER_ENTERED_MSG variable data field. This field's data is a message.
The message should have parameters:
void MSG_MY_CL_NOTIFY( MemHandle phNumber = cx);
The passed block contains the phone number string. The message's recipient is responsible for freeing the passed block.
Build 4.3.7 of the Responder
(see versions for more information about software versions) supports two methods for selecting
contacts from a CCT_PHONE type of contact controller list.
If the user quickly presses the Select trigger (F1 on
the PC emulator), then, depending on the circumstances, the message
specified by ATTR_CONTACT_LIST_NOTIFY_CONTACT_SELECTED_MSG,
ATTR_CONTACT_LIST_NOTIFY_NUMBER_ENTERED_MSG, or
ATTR_CONTACT_LIST_NOTIFY_MULTIPLE_CONTACTS_SELECTED_MSG is sent.
If the user holds the Select trigger for a longer time,
an alternate type of message analogous to the normal selection message
is sent. These alternate messages include:
ATTR_CONTACT_LIST_ALTERNATE_NOTIFY_CONTACT_SELECTED_MSG
@prototype void CONTACT_LIST_ALTERNATE_NOTIFY_CONTACT_SELECTED_MSG(
dword recordID = cx:dx,
word fieldID = bp);
ATTR_CONTACT_LIST_ALTERNATE_NOTIFY_NUMBER_ENTERED_MSGCLF_SELECT_CONTACT_NUMBER must be set. The message must
follow the prototype:
@prototype void CONTACT_LIST_ALTERNATE_NOTIFY_NUMBER_ENTERED_MSG(
MemHandle block = cx);
ATTR_CONTACT_LIST_ALTERNATE_NOTIFY_MULTIPLE_CONTACTS_SELECTED_MSGCLF_SELECT_CONTACT_NUMBER and
HINT_NON_EXCLUSIVE_LIST must be present for multiple
selection contact lists. This message must follow the prototype:
@prototype void CONTACT_LIST_ALTERNATE_NOTIFY_MULTIPLE_CONTACTS_SELECTED_MSG(
MemHandle block = cx,
word num = dx);
ContactListSelectedEntry selected items.RecentContactsSMSControlClass, CONTACTS_CONTROL_NOTIFY_ENTRY_SELECTED_MSG
For a list of recent SMS contacts, use a
RecentContactsSMSController. You will need the following
line in your .gp file:
library contlog
The following setup would allow the user to pick a phone number
from a list of recently called SMS numbers, sending a
MSG_MYPROCESS_SEND_RECENT
message to the application's process object:
@object RecentContactsSMSControlClass MyLog = {
GCI_output = ( TO_PROCESS );
ATTR_RECENT_CONTACTS_CONTROL_NOTIFY_ENTRY_SELECTED_MSG =
MSG_MYPROCESS_SEND_RECENT;
}
With this setup, when the user chooses a phone number from
the log, a MSG_MYPROCESS_SEND_RECENT message will
be sent to the process object, which should handle the message.
The message should conform to the
CONTACTS_CONTROL_NOTIFY_ENTRY_SELECTED_MSG prototype.
@prototype void
CONTACTS_CONTROL_NOTIFY_ENTRY_SELECTED_MSG(
RecentContactsData *data)
typedef struct {
dword RCD_contactID;
NameOrNumber RCD_number;
} RecentContactsData;
The data argument's RCD_number field contains
the GSM phone number of the selected contact. The RCD_contactID
contains either:
ContactID of a record in the device's contact database
(not of a database on a memory card), orLECI_INVALID_CONTACT_IDThe code example below shows a handler that extract's the name associated with the selected contact. It makes use of functions described in Setting up a Contact List.
Code Display: Handling the RecentContacts "Selected" Message
@class MyProcessClass, GenProcessClass;
@message (CONTACTS_CONTROL_NOTIFY_ENTRY_SELECTED_MSG)
MSG_MYPROCESS_SEND_RECENT;
@endc
@method MyProcessClass, MSG_MYPROCESS_SEND_RECENT {
/* Note: the code in this example is only useful if you need
* the contact's name. If all you need is the GSM phone number,
* none of this code is necessary. The phone number string is in
* data->RCD_number.
*
* If you do need the following code, you will need to make sure
* that your .gp file includes the lines
library contdb
library foamdb
*/
TCHAR theName[MAX_NAME_DATA_LEN+1];
VMFileHandle CDBHandle;
MemHandle theRecord;
word oldOverride;
/* If the user chose a phone number that doesn't have a contact
* associated with it, the contact's RecordID value is
* LECI_INVALID_CONTACT_ID, signalling an invalid contact. */
if ( data->RCD_contactID != LECI_INVALID_CONTACT_ID) {
oldOverride = ContactSetOverrideDB(CONTACT_DEVICE_DB_NAME);
CDBHandle = ContactGetDBHandle();
theRecord = FoamDBGetRecordFromID( CDBHandle,
data->RCD_contactID );
ContactGetName(theRecord, theName);
/* If you need more information about the contact
* (e.g., business name, job title), this is a good place
* to retrieve it. */
FoamDBDiscardRecord(CDBHandle, theRecord);
ContactReleaseDBHandle();
ContactRestoreOverrideDB(oldOverride);
}
/* do something useful with data->RCD_number and theName */
}
Recent versions of the Nokia 9000i Communicator allow fax and SMS contact lists to support
multiple selections. Set the RCFCF_MULTIPLE_SELECTION or
RCMCF_MULTIPLE_SELECTION bit to enable multiple selection
for, respectively, a fax or SMS recent contact list and specify the
message
ATTR_RECENT_CONTACTS_CONTROL_NOTIFY_ENTRY_SELECTED_MSG
which will be sent when the user chooses an item from the list.
ContactMatchName(), ContactEnsureField()
Perhaps you're writing a special-purpose application that communicates with just one contact. Perhaps a carry-out restaurant chain has contracted you to write an application that the user can use to place an order over the phone. The program would only need to make contact with one place: the local restaurant's GSM phone number.
In this case, you wouldn't want to provide UI for choosing a contact--your program is only interested in one dedicated contact. Still, it's worthwhile to store the contact in the Contact database--if the restaurant's phone number changes, the user can enter the corrected number using the Contact Manager built-in application.
To find the Contact record for a particular contact, you will need to make sure that your .gp file contains the following lines:
library contdb library foamdb
Finding the "Stuckey's Snack Shack" Contact, below, shows how you could find a dedicated contact in a Contact database and extract the phone number associated with that contact.
To locate a dedicated contact and extract its phone number, carry out the following steps:
RecordID of the contact's
record, call ContactMatchName(). This routine takes a
search string (pass the contact's name), a ContdbFieldType
(pass CFT_NAME, since we're searching by name), a flag (pass a non-zero
value to specify that you're only interested in one matching record),
a pointer to a FieldID buffer to fill in and a pointer to
a word value to fill in. It returns the RecordID of the
contact (or -1 if the contact wasn't found). It also fills in the
FieldID buffer with the contact's name field
FieldID and fills in the word value with the number of
matches found; neither of these values is important to our purpose.If you're searching multiple databases and the current database doesn't contain the record, go on to the next database.
ContactGetDBHandle(). This routine takes no arguments
and returns the database's handle.FoamDBGetRecordFromID().
This routine takes the Contact database's handle and the record's
RecordID. It returns the record's memory handle.FieldID of the record's GSM phone number field. In
the example below, we assume that the record has only one phone number
field, and that this is the field we want. For a more rigorous approach,
we could examine each field to make sure it was named
"Tel (GSM)". For an example of how one might examine all the
fields of a record, see To Get More Info on a Contact.For our shortcut, we use the ContactEnsureField()
function. This function takes as arguments a record handle, a field
name string (in our example, we pass a null optr to specify that
we should use the default field name, and the ContdbFieldType
of the field to find ( pass CFT_PHONE). The function returns a
FieldID.
FoamDBGetFieldData().
Pass the database handle, the record handle, the FieldID, a
buffer to write the name to, and the size of that buffer. The function
fills in the buffer with the phone number string, and returns the length
of that string. The returned string might not be null-terminated; thus
you will either need to keep track of the returned string length, or
else terminate the string.FoamDBDiscardRecord(). This routine takes the Contact's
database handle and the record's handle as arguments.ContactReleaseDBHandle().If the contact is not found, there are a couple of approaches the application can take:
Code Display: Finding the "Stuckey's Snack Shack" Contact
@method ContactProcessClass, MSG_CONTACT_PROCESS_SEND_TO_STUCKEYS
{
TCHAR nameStr[] = "Stuckey's Snack Shack";
TCHAR numStr[] = "+1-800-788-2539";
VMFileHandle hCDB;
RecordID recordID;
FieldID fieldID;
word numMatches;
dword recordIndex;
word len;
MemHandle hRecord;
int dbOverride = TRUE;
FileLongName dbName;
int numDBs;
int dbNumber;
word oldOverride;
/*
* Check the database on the device and the databases in the memory card.
*/
/*
* First try the db on the device.
*/
oldOverride = ContactSetOverrideDB(CONTACT_DEVICE_DB_NAME);
hCDB = ContactGetDBHandle(); /* device DB */
recordID = ContactMatchName( nameStr, CFT_NAME, TRUE,
&fieldID, &numMatches );
ContactReleaseDBHandle(); /* device DB */
if ( recordID == LECI_INVALID_CONTACT_ID) {
/*
* Now try each db on the memory card.
*/
numDBs = ContactGetNumDBsOnMemoryCard();
for (dbNumber = 0 ; dbNumber < numDBs; dbNumber++) {
ContactGetDBName(dbNumber, dbName);
ContactSetOverrideDB(dbName);
hCDB = ContactGetDBHandle();
recordID = ContactMatchName( nameStr, CFT_NAME, TRUE,
&fieldID, &numMatches );
ContactReleaseDBHandle();
if ( recordID != LECI_INVALID_CONTACT_ID) {
break;
}
/* We didn't find it, loop up and try again. */
}
if ( recordID == LECI_INVALID_CONTACT_ID) {
ContactRestoreOverrideDB(oldOverride);
dbOverride = FALSE;
}
}
hCDB = ContactGetDBHandle();
if ( LECI_INVALID_CONTACT_ID == recordID ) {
/* No such record in contact database -- let's add it. */
dbOverride = FALSE;
hRecord = ContactCreateRecordFromTemplate();
fieldID = ContactEnsureField( hRecord, NullOptr, CFT_NAME );
FoamDBSetFieldData( hCDB, hRecord, fieldID,
nameStr, strlen( nameStr ) );
fieldID = ContactEnsureField( hRecord, @TelGSMStr, CFT_PHONE );
FoamDBSetFieldData( hCDB, hRecord, fieldID,
numStr, strlen( numStr ) );
recordIndex = ContactSaveRecord( hRecord );
hRecord = FoamDBGetVisibleRecord( hCDB, recordIndex );
}
else {
/* Contact exists: get record from ID. */
hRecord = FoamDBGetRecordFromID( hCDB, recordID );
}
/* Record was either found or created: get the GSM phone number. */
fieldID = ContactEnsureField( hRecord, @TelGSMStr, CFT_PHONE );
len = FoamDBGetFieldData( hCDB, hRecord, fieldID,
numStr, MAX_NUMBER_FIELD_DATA_LEN );
numStr[len] = '\0';
/*
* Here, the application can do something with the contact's data...
*/
ContactReleaseDBHandle();
if (dbOverride ) {
ContactRestoreOverrideDB(oldOverride);
}
} /* MSG_CONTACT_PROCESS_SEND_TO_STUCKEYS */
To allow the user to edit the contact information for this single
contact, use a ContactEdit object. To specify the
contact that the user will work with, you will need its handle.
Pass the handle as an argument to the MSG_CONTACT_EDIT_DISPLAY_RECORD
message. (Don't call ContactSaveRecord(),
FoamDBDeleteRecord(), or FoamDBDiscardRecord()
when done with this handle; the controller will do so.)
LogAddEntry()
If you wish to log incoming or outgoing messages, you will use
the LogAddEntry() function, provided by the
contlog
library. Make sure that you your.gp
file contains the line
library contlog
To log a call, carry out the following steps:
LogEntry structure and call
LogAddEntry(). The code shown in
Logging an SMS Callwould be appropriate for logging an outgoing message; to log an
incoming message, substitute LED_RECEIVED for LED_SENT.LogAddEntry() again,
passing the same LogEntry structure as before, after
writing the duration (in seconds) in the LogEntry's
LE_duration field. (The previous invokation of
LogAddEntry() will have filled in the LogEntry's
LE_flags field with correct values.)Code Display: Logging an SMS Call
LogEntry MyEntry ;
dword duration;
TimerDateAndTime tdat;
TimerGetDateAndTime(&tdat);
duration = TimerGetCount();
strcpy( MyEntry->LE_number, theNumber);
MyEntry.LE_contactID = recordID; /* This is useful only if recordID
* refers to a record in the device contact
* databse--not a database on a memory card.
* If this is not the case, then use
* LECI_INVALID_CONTACT_ID*/
MyEntry.LE_type = LET_SMS;
MyEntry.LE_direction = LED_SENT;
MyEntry.LE_duration = 1;
MyEntry.LE_dateTime.DAT_year = tdat.TDAT_year;
MyEntry.LE_datetime.DAT_month = tdat.TDAT_month;
MyEntry.LE_datetime.DAT_day = tdat.TDAT_day;
MyEntry.LE_datetime.DAT_hour = tdat.TDAT_hours;
MyEntry.LE_datetime.DAT_minute = tdat.TDAT_minutes;
LogAddEntry( &MyEntry );
/* Send the message, and when done...*/
MyEntry.LE_duration = TimerGetCount() - duration;
LogAddEntry( &MyEntry );
When using the Contact Log library to log a contact, if you don't
know the phone number, you can pass LEF_WILDCARD_NUMBER to
LogAddEntry() to specify that this call's number should
match any phone number. This is only allowed on devices with version
numbers "Responder Build 4...." and higher.
See Software Version Number for information about finding out the software version of
the user's device.
FoamDBFieldEnum(), FoamDBGetFieldType(), FoamDBGetFieldName()
In previous examples, we've shown how to get a selected contact's
name and GSM phone number. It is possible to get more information
about a contact given if you know which database it's in and its
RecordID number.
In the examples shown in Handling the ContactList's "Selected" Message, Handling the RecentContacts "Selected" Message, and Finding the "Stuckey's Snack Shack" Contact there is a comment noting a good place to get more information about a contact. If, for some reason, you need to find out information about a Contact in a context other than shown in one of those examples,
RecordID
number.ContactList
object for the RecordID
of its selected record, use the
MSG_CONTACT_LIST_GET_ID_OF_SELECTED_RECORD
message. This message takes no arguments,
and returns a RecordID.ContactGetDBHandle(), storing the returned handle.FoamDBGetRecordFromID().
This returns the record's handle.FoamDBDiscardRecord() to free the handle.ContactReleaseDBHandle() to signal
you're done with the database. You shouldn't keep the handle around
for long; doing so prevents the file from being closed.To find out any other sort of information about the contact, you'll
need to access one of the fields of the record. Fields within a Foam DB
record (the Contact DB is a Foam DB) are identified by a
FieldID number.
The FoamDBFieldEnum() function provides a way to scan all
the fields of a record. The following code snippet shows how you might
use FoamDBFieldEnum() to search for all of a contact's
voice phone numbers. FoamDBFieldEnum() calls a callback
routine for each of the record's fields. FoamDBFieldEnum()
takes as arguments a record handle, a pointer to a data buffer (this
pointer will be passed to the callback routine; it gives you a way to
pass data to the callback; in our example, we pass the record handle
in the buffer), and a pointer to a callback function. The callback
function is passed a FieldHeader structure and a pointer
to the data buffer that was passed toFoamDBFieldEnum().
From the FieldHeader, it can get the FieldID from the
FieldHeader's FH_id field. To get information
about each field, use the FoamDBGetFieldType(),
FoamDBGetFieldName(), and/or FoamDBGetFieldData()
routines. Each of these routines takes the contact database handle, a
record handle, a FieldID, and a pointer to a buffer to fill
with a return value.
Code Display: Checking All Fields of a Contact
In this example, we check all fields of a contact
and build up an array with the names and data for those fields that
correspond to voice phone numbers. We know that the database containing
the contact is the current contact database. We know the contact's
RecordID value.
void BuildNumberList( RecordID recordID ) {
/* Scan all fields of the Contact record */
/* For each one that corresponds to a voice phone number, store
* the field's name (e.g., "Phone") and data (e.g., "555-1212") in
* the global Data array. */
VMFileHandle CDBHandle;
MemHandle curRecord;
CDBHandle = ContactGetDBHandle(); curRecord = FoamDBGetRecordFromID( CDBHandle, recordID ); NumberOfNumbers = 0 /* Global variable: number of elements in Data array*/ FoamDBFieldEnum( curRecord, &curRecord, &BuildNumberListCallback ); FoamDBDiscardRecord( CDBhandle, curRecord) ; /* Done with the record */ ContactReleaseDBHandle(); /* Done with the Contact DB for now */ }
Boolean _pascal BuildNumberListCallback( FieldHeader *field, void *enumData ) {
VMFileHandle CDBHandle;
byte fieldType;
MemHandle curRecord = *((MemHandle *) enumData );
CDBandle = ContactGetDBHandle();
FoamDBGetFieldType( CDBHandle, curRecord, field->FH_id, &fieldType);
if (fieldType == CFT_PHONE ) { /* For each voice phone number */
/* To look for something other than a phone
* number, we would use a different
* ContdbFieldType value. */
/* Grab the field name */
FoamDBGetFieldName( CDBHandle, curRecord, field->FH_id,
Data[NumberOfNumbers].fName, MAX_FIELD_LABEL_LEN);
/* Grab the field data */
/* If the data has zero length, func will
* return zero. */
if (FoamDBGetFieldData( CDBHandle, curRecord, field->FH_id,
Data[NumberOfNumbers].fData, MAX_FIELD_NUMBER_DATA_LEN)) {
/* If the data was not of zero length
* (wasn't just a blank field), then
* up our NumberOfNumbers. */
NumberOfNumbers++;
}
}
ContactReleaseDBHandle(); /* We're done with the database */
/* if we return non-zero, we'll stop Enum'ing
* through the fields. Since we only have room
* for 10 fields in our array... */
return( NumberOfNumbers > 10) ;
}
As shown above, to get the field data and field name associated
with a field, use the FoamDBGetFieldData()
and FoamDBFGetFieldName() functions. Many users will
leave blank fields in their contact records; to test for a blank
field, check FoamDBGetFieldData()'s return value;
if it is zero, then the user has not filled in that field of the
contact information.
ContactGetUserDataName(), ContactGetUserDataID()
Recent versions of the ContDB library provide routines which access the user's own contact information. These routines are only available on devices with version numbers "Responder Build 4...." and higher. See Software Version Number for information about finding out the software version of the user's device.
The ContDB library provides two routines useful for accessing the contact information the user has specified for themself. The
ContactGetUserDataName()
routine returns the user's name string.
ContactGetUserDataID()
returns the record ID number of a record which contains the user's contact information.