This document is a single-page version of a a multi-page document, suitable for easy printing.

Contacts

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.

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.


Contacts: 1 Setting up a Contact List

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.

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:

  1. Get the current Contact database's handle. To do this, call ContactGetDBHandle(). This routine takes no arguments, and returns the Contact database's handle.
  2. Get the handle of the record by calling 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.
  3. To extract the contact's GSM phone number, call 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.
  4. Now that you're done with the record, let the database know by calling FoamDBDiscardRecord(). This routine takes the Contact's database handle and the record's handle as arguments.
  5. Now that you're done with the database, release its handle by calling 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();
}

Contacts: 1.1 Setting up a Contact List: Multiple-Selection ContactLists

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:


Contacts: 1.2 Setting up a Contact List: Remembering the Search

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


Contacts: 1 Setting up a Contact List: 1.3 Detecting Unknown Phone Numbers

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.

 


Contacts: 1 Setting up a Contact List : 1.4 Alternate Selection Messages

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
Set this to the message which will be called when the user selects a contact from the list after holding the Select trigger for a long duration. If more than one contact was selected then this message returns the first selection. This message must follow the prototype:
@prototype void CONTACT_LIST_ALTERNATE_NOTIFY_CONTACT_SELECTED_MSG(
                                dword recordID = cx:dx,
                                word fieldID = bp);
fieldID is the ID of the field containing the selected GSM phone number of the record with the ID recordID. This is the same API as that of the normal selection message; you may use the same handler for both messages.
ATTR_CONTACT_LIST_ALTERNATE_NOTIFY_NUMBER_ENTERED_MSG
Set this to the message which should be sent when the user has entered a valid phone number in the search field which does not match any record in the contact list and the user has held the trigger for a long duration. For this message to be sent, CLF_SELECT_CONTACT_NUMBER must be set. The message must follow the prototype:
@prototype void CONTACT_LIST_ALTERNATE_NOTIFY_NUMBER_ENTERED_MSG(
                                MemHandle block = cx);
block will contain the null-terminated phone number.
ATTR_CONTACT_LIST_ALTERNATE_NOTIFY_MULTIPLE_CONTACTS_SELECTED_MSG
Set this to the message which will be sent when the user selects one or more contacts from the list and holds the Select trigger for a long duration. Note that CLF_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);
block will contain the num ContactListSelectedEntry selected items.

Contacts: 2 Choosing Contacts From a Log

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:

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


Contacts: 3 Using a Dedicated Contact

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:

  1. Which of the user's Contact databases do you wish to search? If the user has a memory card installed, there may be several databases to search. Perhaps you want to search all of them. Perhaps you want to ignore databases on the memory card, and only search the device's own database.
  2. For each database, to get the 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.
  3. If you're searching multiple databases and the current database doesn't contain the record, go on to the next database.

  4. Get the Contact database's handle. To do this, call ContactGetDBHandle(). This routine takes no arguments and returns the database's handle.
  5. Get the record's handle by calling FoamDBGetRecordFromID(). This routine takes the Contact database's handle and the record's RecordID. It returns the record's memory handle.
  6. Get the 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.
  7. 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.

  8. To extract the phone number data, call 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.
  9. Now that you're done with the record, let the database know by calling FoamDBDiscardRecord(). This routine takes the Contact's database handle and the record's handle as arguments.
  10. Now that you're done with the database, release its handle by calling 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.)


Contacts: 4 Logging Calls

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:

  1. Before making the call, set up a 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.
  2. Make the call.
  3. When the call is done, call 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.


Contacts: 5 To Get More Info about a Contact

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,

  1. The database containing the contact must be the current contact database; in the contexts described above, this will be true. You will need the record's RecordID number.
    To query a 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.
  2. Gain access to the current Contact database by calling ContactGetDBHandle(), storing the returned handle.
  3. To access the database record corresponding to the selected contact, call FoamDBGetRecordFromID(). This returns the record's handle.
  4. Get the contact information you need. Information about how you might do this is described in the paragraphs following this checklist.
  5. When you're done with the record handle, call FoamDBDiscardRecord() to free the handle.
  6. Be sure to call 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.


Contacts: 6 The User's Own Data

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.


This document is a single-page version of a a multi-page document, suitable for easy printing.