PIM Access and Control

Our PIM API module is still in the early stage of development, but we have already implemented many vital elements of PIM management, including low-level functions for accessing contact lists. Here we take a quick look at this new interface.

PIM (personal information management) is about accessing the information about the user. PIM data is organized into lists of items, and each item has fields. The device's address book is a typical PIM list, as well as its appointments lists, todo lists, and so on.

Currently we only have functions for working with contact lists. Event lists will be added soon.

We also have a working example application, PIMExample, that demonstrates many aspects of working with the PIM module.

Lists, items, fields, values, and attributes

Each PIM list holds multiple items; for example, the contact list holds multiple contacts.  Each item in the list can have multiple fields of different types, and each field can have multiple values of the same type identified by an index.

Some field values have attributes attached. That makes it possible to define their purpose (home, mobile, work, husband, custom) and to set them as "primary" or "default" in case of multiple-value fields. The PIM structure currently supported by our PIM module looks like this:

Contact List

  • Contact Item
    • Field address
    • Field birthday
    • Field class
    • Field email
    • Field formatted address
    • Field formatted name
    • Field name
    • Field nickname
    • Field note
    • Field organization
    • Field photo
    • Field photo url
    • Field public key
    • Field public key string
    • Field revision
    • Field phone
    • Field title
    • Field UID
    • Field URL
    • Field IM
    • Field relation
    • Field organization info

It is important to note that not all fields are available on all platforms. If a field is not supported on running platform and you try to access it, you will get an error. For details of each field, its type and value, the operations it supports, the possible attributes that can be set on its values, and the platforms on which field is available, see the MoSync API Reference online or in the IDE.

Using the MoSync PIM module

For a list of all functions (syscalls) in the PIM module, see the MoSync API Reference.

Working with lists and items

To open a PIM list, use the function maPimListOpen. If a list of the selected type is available, you will get back a handle to it that you can use in subsequent calls.

MAHandle mContactsListHandle = maPimListOpen(MA_PIM_CONTACTS);

To open the items on the list, use maPimListNext. You will get back a handle to the next item on the list or 0 if there are no more items.

MAHandle pimItemHandle = maPimListNext(mContactsListHandle);

You can create new item in a list using maPimItemCreate.

MAHandle newContactHandle = maPimItemCreate(mContactsListHandle);

The newly created item is empty. The function maPimItemRemove removes an item from the list.

int resultCode = maPimItemRemove(mContactsListHandle, newContactHandle);
if (resultCode < 0)
{
    printf("Remove Item Error: %d", resultCode);
}

Important! To prevent memory leaks, always call maPimItemClose to close the item as soon as you are finished with it before opening the next item. This function also commits changes made by maPimItemAddValue, maPimItemRemoveValue, and maPimItemSetValue to permanent storage. It should also be used after maPimItemCreate.

int resultCode = maPimItemClose(pimItemHandle);
if (resultCode < 0)
{
    printf("Close Item Error: %d", resultCode);
}

To close a list when you have finished with it, use maPimListClose. (This function does not close the list's items, but it does invalidate them, so maPimItemClose will now be the only function you can safely use on items.)

int resultCode = maPimListClose(mContactsListHandle );
if (resultCode < 0)
{
    printf("Close List Error: %d", resultCode);
}

Working with fields and attributes

To count the number of fields an item has, use the function maPimItemCount.

int countFields = maPimItemCount(pimItemHandle);
if (countFields >= 0)
{
    printf("The item has %d fields", countFields);
}
else
{
    printf("Count Item Error: %d", countFields);
}

To count the number of values that exist for the field for the item, use maPimItemFieldCount.

int countValues = maPimItemFieldCount(mItemHandle, MA_PIM_FIELD_CONTACT_ADDR);
if (countValues >= 0)
{
    printf("The field has %d values", countValues);
}
else
{
    printf("Count Item Field Error: %d", countValues);
}

Each field of the item has a type. To get the field's type (Address, Birthday, Name, etc.), use maPimItemGetField passing it the the position of the field and the item handle that was returned by maPimListNext.

for (int index = 0; index < countFields; i++)
{
    int type = maPimItemGetField(pimItemHandle, index);
    if (type > 0)
    {
        printf("Field %d type: %d", index, type);
    }
    else
    {
        printf("Get Field %d Error: %d", index, type);
    }
} 

You can use the maPimFieldType function to get the data type (integer, boolean, string, etc.) of the field. The value returned will be one of the MA_PIM_TYPE_* constants (date, boolean, string array, etc.).

int type = maPimItemGetField(pimItemHandle, 0);
if (type >0)
{ 
	int dataType = maPimFieldType(mContactsListHandle, type);
	if (dataType > 0)
	{
		printf("Field %d data type: %d", type, dataType);
	}
	else
	{
		printf("Get Field Type %d Error: %d", type, dataType);
	}
} 

To get the attribute for a value in a field use maPimItemGetAttributes.

for (int index = 0; index < countValues; i++)
{
	int attribute = maPimItemGetAttributes(pimItemHandle, MA_PIM_FIELD_CONTACT_ADDR, index);
	if (attribute > 0)
	{
		if ((attribute & MA_PIM_ATTRPREFERRED) != 0)
		{
			printf("Primary attribute");
		}
		attribute &= (MA_PIM_ATTRPREFERRED - 1);
		printf("Field %d attribute: %d", index, attribute);
	}
	else
	{
		printf("Get Field Attribute %d Error: %d", index, attribute);
	}
}

You can retrieve the label for a value in a field, if the value has a custom label, using the maPimItemGetLabel function. To set a custom label for a value in a field use the function maPimItemSetLabel. The field must of course be writable.

if (countValues > 0)
{
	int attribute = maPimItemGetAttributes(pimItemHandle, MA_PIM_FIELD_CONTACT_ADDR, 0);
	if (attribute > 0)
	{
		attribute &= (MA_PIM_ATTRPREFERRED - 1);
		if (attribute == MA_PIM_ATTR_ADDR_CUSTOM)
		{
			MA_PIM_ARGS labelArgs;
			labelArgs.item = pimItemHandle;
			labelArgs.field = MA_PIM_ATTR_ADDR_CUSTOM;
			char* buf = NULL;
			int labelSize = 512;
			do
			{
				labelArgs.bufSize = labelSize;
				if (buf != NULL)
				{
					delete[] buf;
				}
				buf = new char[labelArgs.bufSize];
				labelArgs.buf = buf;
				resultCode = maPimItemGetLabel(&labelArgs, 0);
			} while (resultCode > labelArgs.bufSize);
			if (resultCode > 0)
			{
				printf("Label: %S", (wchar*) buf);
			}
			else
			{
				printf("Get Field Label %d Error: %d", 0, resultCode);
			}
		}
	}
	else
	{
		printf("Get Field Attribute %d Error: %d", 0, attribute);
	}
}

Getting and setting values

To read the value of a field and copy it to the argument buffer (args.buf ), call maPimItemGetValue. You will need to specify the index of the value ( 0 <= index < maPimItemFieldCount() ). The argument buffer should look like this:

struct MA_PIM_ARGS {
	MAHandle item; // Opened by maPimListNext().
	int field;     // One of the MA_PIM_FIELD constants.
	MAAddress buf; // The buffer address where a value is stored.
	int bufSize;   // The size of the buffer, in bytes.
}

If the buffer created is too small, the syscall will return the miminum needed size for your buffer

MA_PIM_ARGS args;
args.field = MA_PIM_FIELD_CONTACT_NAME;

// Get value from name field at position 0.
int resultCode = maPimItemGetValue(&mArgs, 0);

if (resultCode < 0)
{
	printf("Get Field %d Value Error %d", 0, resultCode);
}

To add a new value to a field, use maPimItemAddValue; to remove a value from a field, use maPimItemRemoveValue; to change a value in a field and the attributes of the value, use maPimItemSetValue passing an args.buf.

For each of these functions the changes are not actually written to permanent storage until the item is closed with maPimItemClose -- if the program exits before then, the changes we be lost.

Panics on Android and iOS

Usually a MoSync panic will be thrown if the position is invalid, or a field/index combination doesn't exist, and so on. On Android and iOS (iPhone) you can disable panics using the function maSyscallPanicsDisable so that you'll get error codes instead.

Turn panics back on with maSyscallPanicsEnable.