FileDocCategorySizeDatePackage
PIMProxy.javaAPI DocphoneME MR2 API (J2ME)33564Wed May 02 18:00:28 BST 2007com.sun.kvem.midp.pim

PIMProxy.java

/*
 *   
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

package com.sun.kvem.midp.pim;

import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

import javax.microedition.pim.PIMException;
import javax.microedition.pim.PIM;

import com.sun.midp.main.Configuration;
import com.sun.kvem.midp.pim.formats.FormatSupport;

/**
 * Porting layer implementation for PIM functionality.
 */
public class PIMProxy extends PIMHandler {

    /**
     * Table of fields for any list.
     */
    private Hashtable listFields = new Hashtable();

    /**
     * Table of attributes for any list.
     */
    private Hashtable listAttributes = new Hashtable();

    /**
     * List handle for which fields have been already initialized.
     */
    private Object initialized = null;

    /**
     * Field for storing data handler between native calls
     */
    private int dataHandler;

    /**
     * Field for storing items counter between native calls
     */
    private int itemCounter;

    /**
     * Constant representing a Contact List.
     * List handle for which fields have been already initialized.
     */
    public static final int CONTACT_LIST = 1;

    /**
     * Constant representing an Event List.
     */
    public static final int EVENT_LIST = 2;

    /**
     * Constant representing a ToDo List.
     */
    public static final int TODO_LIST = 3;

    /**
     * This class holds information about a single list.
     */
    private class List {
        /** Native handle of the list */
        int handle;

        /** Type of the list: CONTACT_LIST, EVENT_LIST or TODO_LIST */
        int type;

        /**
         * The only constructor for this list descriptor.
         *
         * @param listHandle low-level (native) handle of the list
         * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
         */
        List(int listHandle, int listType) {
            handle = listHandle;
            type = listType;
        }
    }

    /**
     * This class holds information about a single list item.
     */
    private class Item {
        /** Native handle of the item */
        int handle;

        /** Binary data of the item */
        byte[] rawData;

        /** Descriptor of the list containing this item */
        List list;

        /** Array of categories the item belongs to */
        String[] categories;

        /**
         * Simple constructor for this item descriptor.
         *
         * @param list descriptor of the list where the item belongs
         * @param handle low-level (native) handle of the item
         * @param dataLength size of item's data (in bytes)
         */
        Item(List list, int handle, int dataLength) {
            this.handle = handle;
            rawData = new byte[dataLength];
            this.list = list;
            categories = null;
        }

        /**
         * Constructor that allows to specify categories of the item.
         *
         * @param list descriptor of the list where the item belongs
         * @param handle low-level (native) handle of the item
         * @param dataLength size of item's data (in bytes)
         * @param cats array of categories the item belongs to
         */
        Item(List list, int handle, int dataLength, String[] cats) {
            this(list, handle, dataLength);
            setCategories(cats);
        }

        /**
         * Sets categories for the item.
         *
         * @param cats array of categories the item belongs to
         */
        void setCategories(String[] cats) {
            categories = cats;
        }

        /**
         * Returns item's categories.
         *
         * @return array of categories the item belongs to
         */
        String[] getCategories() {
            String[] cats =
                new String[categories == null ? 0 : categories.length];
            if (cats.length > 0) {
                System.arraycopy(categories, 0, cats, 0, categories.length);
            }
            return cats;
        }
    }

    /**
     * Set up field and attribute descriptions.
     *
     * @param listHandle descriptor of the list which fields and
     *        attributes will be retrieved
     */
    synchronized private void initialize(Object listHandle) {
        if (initialized != listHandle) {
            listFields.clear();
            listAttributes.clear();
            int list = ((List)listHandle).handle;

            int [] tmpArray = new int [1];
            int numFields = getFieldsCount0(list, tmpArray);
            if (numFields <= 0) {
                return;
            }
            PIMFieldDescriptor[] desc = new PIMFieldDescriptor[numFields];
            for (int i = 0; i < numFields; i++) {
                int numLabels = getFieldLabelsCount0(list, i, tmpArray[0]);
                desc[i] = new PIMFieldDescriptor(0, 0, false, null, " ",
                        new String[numLabels], 0L, 0);
            }
            getFields0(list, desc, tmpArray[0]);
            for (int i = 0; i < numFields; i++) {
                listFields.put(new Integer(desc[i].getField()), desc[i]);
            }

            tmpArray[0] = 0;
            int numAttributes = getAttributesCount0(list, tmpArray);
            PIMAttribute[] attr = new PIMAttribute[numAttributes];
            for (int i = 0; i < numAttributes; i++) {
                attr[i] = new PIMAttribute();
            }
            getAttributes0(list, attr, tmpArray[0]);
            for (int i = 0; i < numAttributes; i++) {
                listAttributes.put(new Integer(attr[i].getAttr()), attr[i]);
            }

            initialized = listHandle;
        }
    }

    /**
     *  Gets the descriptor for given field.
     *
     * @param field the field ID
     *
     * @return field descriptor
     */
    private PIMFieldDescriptor getFieldDescriptor(int field) {
        return (PIMFieldDescriptor)listFields.get(new Integer(field));
    }

    /**
     * Gets all fields that are supported in this list.  All fields supported by
     * this list, including both standard and extended, are returned in this
     * array.
     *
     * @param listHandle handle of the list
     * @return  an int array containing all fields supported by this list.  The
     *          order of the fields returned is unspecified.  If there are no
     *          supported fields, a zero-length array is returned.
     */
    public int[] getSupportedFields(Object listHandle) {
        initialize(listHandle);
        int[] result = new int[listFields.size()];
        Enumeration fieldNumbers = listFields.keys();
        for (int i = 0; i < result.length; i++) {
	    result[i] = ((Integer)fieldNumbers.nextElement()).intValue();
        }
        return result;
    }

    /**
     * Checks if field is supported in list.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return <code>true</code> if field supported
     */
    public boolean isSupportedField(Object listHandle, int field) {
        initialize(listHandle);
        return getFieldDescriptor(field) != null;
    }

    /**
     * Checks if field has default value.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return <code>true</code> if field supported
     */
    public boolean hasDefaultValue(Object listHandle, int field) {
        initialize(listHandle);
        return getFieldDescriptor(field).hasDefaultValue();
    }

    /**
     * Gets the data type of the field.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return data type identifier
     */
    public int getFieldDataType(Object listHandle, int field) {
        initialize(listHandle);
        try {
            return getFieldDescriptor(field).getDataType();
        } catch (NullPointerException npe) {
            return -1;
        }
    }

    /**
     * Gets the label of the field.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return label of the field
     */
    public String getFieldLabel(Object listHandle, int field) {
        initialize(listHandle);
        try {
            return getFieldDescriptor(field).getLabel();
        } catch (NullPointerException npe) {
            return null;
        }
    }

    /**
     * Gets the default integer value for the given field. This will
     *  only
     * return a valid value if hasDefaultValue(listType, field) returns true.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return default value of the field
     */
    public int getDefaultIntValue(Object listHandle, int field) {
        initialize(listHandle);
        PIMFieldDescriptor descriptor = getFieldDescriptor(field);
        return ((Integer) descriptor.getDefaultValue()).intValue();
    }

    /**
     * Gets the default string value for the given field. This will
     * only
     * return a valid value if hasDefaultValue(listType, field) returns true.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return default value of the field
     */
    public String getDefaultStringValue(Object listHandle, int field) {
        initialize(listHandle);
        return null;
    }

    /**
     * Gets the default String[] value for the given field. This will
     * only
     * return a valid value if hasDefaultValue(listType, field) returns true.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return default value of the field
     */
    public String[] getDefaultStringArrayValue(Object listHandle, int field) {
        int length = getStringArraySize(listHandle, field);
        return new String[length];
    }

    /**
     * Gets the default date value for the given field. This will only
     * return a valid value if hasDefaultValue(listType, field) returns true.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return default value of the field
     */
    public long getDefaultDateValue(Object listHandle, int field) {
        initialize(listHandle);
        return 0;
    }

    /**
     * Gets the default byte[] value for the given field. This will
     * only
     * return a valid value if hasDefaultValue(listType, field) returns true.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return default value of the field
     */
    public byte[] getDefaultBinaryValue(Object listHandle, int field) {
        initialize(listHandle);
        return null;
    }

    /**
     * Gets the default boolean value for the given field. This will
     * only
     * return a valid value if hasDefaultValue(listType, field) returns true.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return default value of the field
     */
    public boolean getDefaultBooleanValue(Object listHandle, int field) {
        initialize(listHandle);
        return false;
    }

    /**
     * Gets the supported attributes for the given field.
     * @param listHandle handle of the list
     * @param field identifier of field
     * @return array of supported attributes of the field
     */
    public int[] getSupportedAttributes(Object listHandle, int field) {
        initialize(listHandle);
        long attributes = getFieldDescriptor(field).getSupportedAttributes();
        int listType = ((List)listHandle).type;
        // ATTR_NONE is supported for all Contact fields
        int elementCount = listType == PIM.CONTACT_LIST ? 1 : 0;
        for (long a = attributes; a > 0; a >>= 1) {
            if ((a & 1) == 1) {
                elementCount++;
            }
        }
        int[] result = new int[elementCount];
        if (elementCount > 0) {
            int a = 1;
            int i;
            if (listType == PIM.CONTACT_LIST) {
                result[0] = PIMItem.ATTR_NONE;
                i = 1;
            } else {
                i = 0;
            }
            for (; i < elementCount; i++) {
                while ((attributes & a) == 0) a <<= 1;
                result[i] = a;
                a <<= 1;
            }
        }
        return result;
    }

    /**
     * Gets a mask containing all possible attributes for the given field.
     *
     * @param listHandle handle of the list
     * @param field the field number
     * @return supported attribute mask
     */
    public int getSupportedAttributesMask(Object listHandle, int field) {
        initialize(listHandle);
        return (int)getFieldDescriptor(field).getSupportedAttributes();
    }

    /**
     * Gets attribute label for the given field attribute.
     *
     * @param listHandle handle of the list
     * @param attribute identifier of attribute
     * @return attribute label
     */
    public String getAttributeLabel(Object listHandle, int attribute) {
        initialize(listHandle);
        if (attribute == PIMItem.ATTR_NONE) {
            String tag = "PIM.Attributes.None";
            return Configuration.getPropertyDefault(tag, "Label_" + tag);
        }
        try {
            return ((PIMAttribute)listAttributes.
                    get(new Integer(attribute))).getLabel();
        } catch (NullPointerException npe) {
            return null;
        }
    }

    /**
     * Checks if attribute is supported.
     *
     * @param listHandle handle of the list
     * @param field the field number
     * @param attribute identifier of attribute
     * @return <code>true</code> if attribute is supported
     */
    public boolean isSupportedAttribute(Object listHandle, int field,
        int attribute) {
        initialize(listHandle);
        if (attribute == PIMItem.ATTR_NONE) {
            return true;
        } else {
            long attributes = getFieldDescriptor(field).
                    getSupportedAttributes();
            return (attributes & attribute) != 0;
        }
    }

    /**
     * Checks if size of the string array.
     *
     * @param listHandle handle of the list
     * @param field the field number
     * @return size of the string array
     */
    public int getStringArraySize(Object listHandle, int field) {
        initialize(listHandle);
        try {
            return getFieldDescriptor(field).getStringArraySize();
        } catch (NullPointerException e) {
            // debug.exception(Debug.LIGHT, e);
            return 0;
        }
    }

    /**
     * Gets the array of supported elements.
     *
     * @param listHandle handle of the list
     * @param field the field number
     * @return array of supported elements
     */
    public int[] getSupportedArrayElements(Object listHandle, int field) {
        int size = getStringArraySize(listHandle, field);
        int[] result = new int[size];
        for (int i = 0; i < size; i++) {
            result[i] = i;
        }
        return result;
    }

    /**
     * Gets the array element label.
     *
     * @param listHandle handle of the list
     * @param field the field number
     * @param arrayElement the element identifier
     * @return label fro the array element
     */
    public String getArrayElementLabel(Object listHandle, int field,
						int arrayElement) {
        initialize(listHandle);
        return getFieldDescriptor(field).getElementlabel(arrayElement);
    }

    /**
     * Checks if the array element is supported.
     *
     * @param listHandle handle of the list
     * @param field the field number
     * @param arrayElement the element identifier
     * @return <code>true</code> if attribute element is supported
     */
    public boolean isSupportedArrayElement(Object listHandle, int field,
						    int arrayElement) {
        return arrayElement >= 0 &&
	    arrayElement < getStringArraySize(listHandle, field);
    }

    /**
     * Get the maximum number of values that can be stored in the given field.
     *
     * @param listHandle handle of the list
     * @param field the field type
     * @return the maximum value
     */
    public int getMaximumValues(Object listHandle, int field) {
        initialize(listHandle);
        return getFieldDescriptor(field).getMaximumValues();
    }

    /**
     * Get the supported list names for the given list type. All list elements
     * must be unique within the list.
     *
     * @param listType the type of the list
     * @return a non-null array of supported list names. A copy of this array is
     * returned by PIM.listPIMLists()
     */
    synchronized public String[] getListNames(int listType) {
        int namesCount = getListNamesCount0(listType);
        String[] listNames = new String[namesCount];

        if (namesCount != 0) {
            getListNames0(listNames);
        }

        return listNames;
    }

    /**
     * Get the name of the default list for the given type.
     *
     * @param listType the type of the list
     * @return the name of the default list, or null if no list of this type
     * is supported.
     */
    public String getDefaultListName(int listType) {
        String propertyName;

        if (listType == PIM.CONTACT_LIST) {
            propertyName = "DefaultContactList";
        } else if (listType == PIM.EVENT_LIST) {
            propertyName = "DefaultEventList";
        } else if (listType == PIM.TODO_LIST) {
            propertyName = "DefaultTodoList";
        } else {
            return null;
        }

        return Configuration
		.getProperty(propertyName);
    }

    /**
     * Opens list.
     *
     * @param listType the type of the list
     * @param listName the name of the list
     * @param openMode open mode:
     * <ul>
     *  <li> {@link javax.microedition.pim.PIM#READ_ONLY}
     *  <li> {@link javax.microedition.pim.PIM#WRITE_ONLY}
     *  <li> {@link javax.microedition.pim.PIM#READ_WRITE}
     * </ul>
     * @return list handle that will be used to access this list
     * @throws PIMException  in case of I/O error.
     */
    public Object openList(int listType, String listName, int openMode)
        throws PIMException {
        int listHandle = listOpen0(listType, listName, openMode);
        if (listHandle == 0) {
            throw new PIMException("Unable to open list");
        }
        return new List(listHandle, listType);
    }

    /**
     * Closes list.
     *
     * @param listHandle handle of list
     * @throws PIMException  in case of I/O error.
     */
    public void closeList(Object listHandle)
        throws PIMException {
        if (!listClose0(((List)listHandle).handle)) {
            throw new PIMException();
        }
    }

    /**
     * Get list element keys.
     *
     * @param listHandle handle of the list
     * @return an array of objects representing PIM element keys. These keys
     * are to be passed to getListElement() and commitListElement().
     * @throws PIMException  in case of I/O error.
     */
    synchronized public Object[] getListKeys(Object listHandle)
        throws PIMException {
        Vector keys = new Vector();
        int[] itemDesc = new int[4];
        int handle = ((List)listHandle).handle;

        while (getNextItemDescription0(handle, itemDesc)) {
            Item nextItem = new Item((List)listHandle, itemDesc[0],
                itemDesc[1]);
            getNextItemData0(nextItem.handle, nextItem.rawData, itemDesc[3]);
            keys.addElement(nextItem);
            String catList = getItemCategories0(nextItem.handle, itemDesc[3]);
            if (catList != null) {
                nextItem.setCategories(FormatSupport.split(catList, ',', 0));
            }
        }
        Item[] items = new Item[keys.size()];
        for (int index = 0; index < items.length; index++) {
            items[index] = (Item)keys.elementAt(index);
        }
        return items;
    }

    /**
     * Get the data for a list element.
     * @param listHandle handle of the list
     * @param elementKey the key of the requested element
     * @return a byte array containing the element data in a supported format
     * @throws PIMException  in case of I/O error.
     */
    public byte[] getListElement(Object listHandle,
        Object elementKey) throws PIMException {
        return ((Item)elementKey).rawData;
    }

    /**
     * Get categories for the specified list element.
     * @param listHandle handle of list
     * @param elementKey the key of the requested element
     * @return an array of categories names
     * @throws PIMException  in case of I/O error.
     */
    public String[] getListElementCategories(Object listHandle,
        Object elementKey) throws PIMException {

        return ((Item)elementKey).getCategories();
    }

    /**
     * Commit a list element.
     *
     * @param listHandle handle of the list
     * @param elementKey the key of the element to be stored, or null if this
     * is a new element.
     * @param element element data in a form that can be interpreted
     * by getListElement()
     * @param categories list of categories which the list element belongs to
     * @return a non-null key for this element, to be used in future calls
     * to commitListElement() and getListElement()
     * @throws PIMException  in case of I/O error.
     */
    synchronized public Object commitListElement(Object listHandle,
        Object elementKey,
        byte[] element,
        String[] categories) throws PIMException {
        Item item = (Item)elementKey;
        List list = (List)listHandle;

        if (elementKey == null) {
            /* Add new item */
            int itemHandle = addItem0(list.handle, element, categories == null ?
                null : FormatSupport.join(categories, ","));
            if (itemHandle == 0) {
                throw new PIMException("Unable to add new item");
            }
            item = new Item(list, itemHandle, element.length, categories);
            item.rawData = element;
        } else if (element == null) {
            /* Remove item */
            if (!removeItem0(list.handle, item.handle)) {
                throw new PIMException("Unable to delete item");
            }
        } else {
            item.rawData = element;
            if (!commitItemData0(list.handle, item.handle,
                element, categories == null ?
                null : FormatSupport.join(categories, ","))) {
                throw new PIMException("Unable to update",
                    PIMException.UPDATE_ERROR);
            }
        }
        return item;
    }

    /**
     * Gets the set of categories defined for a list.
     *
     * @param listHandle handle of the list
     * @return the set of defined categories
     * @throws PIMException  If an error occurs or
     * the list is no longer accessible or closed.
     */
    public String[] getCategories(Object listHandle)
        throws PIMException {
        String categories = getListCategories0(((List)listHandle).handle);
        return categories != null ? FormatSupport.split(categories, ',', 0) :
                                    new String[0];
    }

    /**
     * Adds a category to the categories defined for a list.
     *
     * @param listHandle handle of list
     * @param category category name
     * @throws PIMException  If an error occurs or
     * the list is no longer accessible or closed.
     * @see #getCategories
     */
    public void addCategory(Object listHandle,
        String category) throws PIMException {
        if (getCategories(listHandle).length ==
            getListMaxCategories0(((List)listHandle).handle)) {
            throw new PIMException("Maximum number of categories exceeded",
                PIMException.MAX_CATEGORIES_EXCEEDED);
        }
        if (!addListCategory0(((List)listHandle).handle, category)) {
            throw new PIMException("Unable to add category",
                PIMException.UPDATE_ERROR);
        }
    }

    /**
     * Deletes a category from the categories defined for a list.
     *
     * @param listHandle handle of list
     * @param category category name
     * @throws PIMException  If an error occurs or
     * the list is no longer accessible or closed.
     * @see #getCategories
     */
    public void deleteCategory(Object listHandle,
        String category) throws PIMException {
        if (!deleteListCategory0(((List)listHandle).handle, category)) {
            throw new PIMException("Unable to delete category",
                PIMException.UPDATE_ERROR);
        }
    }

    /**
     * Rename a category.
     *
     * @param listHandle handle of list
     * @param currentCategory current category name
     * @param newCategory new category name
     * @throws PIMException  If an error occurs or
     * the list is no longer accessible or closed.
     * @see #getCategories
     */
    public void renameCategory(Object listHandle,
        String currentCategory, String newCategory) throws PIMException {
        if (!renameListCategory0(((List)listHandle).handle, currentCategory,
            newCategory)) {
            throw new PIMException("Unable to rename category",
                PIMException.UPDATE_ERROR);
        }
    }

    /**
     * Returns number of lists of the specified type.
     *
     * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
     *
     * @return number of lists
     * @see #getListNames0
     */
    private native int getListNamesCount0(int listType);

    /**
     * Retrieves list names for the selected list type.
     *
     * @param names array where list names will be stored
     *        (must have sufficient number of elements for list names)
     * @see #getListNamesCount0
     */
    private native void getListNames0(String[] names);

    /**
     * Opens the specified list.
     *
     * @param listType CONTACT_LIST, EVENT_LIST or TODO_LIST
     * @param listName name of the list to open
     * @param mode open mode:
     * <ul>
     *  <li> {@link javax.microedition.pim.PIM#READ_ONLY}
     *  <li> {@link javax.microedition.pim.PIM#WRITE_ONLY}
     *  <li> {@link javax.microedition.pim.PIM#READ_WRITE}
     * </ul>
     *
     * @return native handle of the opened list
     * @see #listClose0
     */
    private native int listOpen0(int listType, String listName, int mode);

    /**
     * Closes the specified list.
     *
     * @param listHandle native handle of the list that was previously opened
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     * @see #listOpen0
     */
    private native boolean listClose0(int listHandle);

    /**
     * Retrieves general information about the next item in the list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param description buffer to store the item description
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean getNextItemDescription0(int listHandle,
        int[] description);

    /**
     * Retrieves next item's data from the list.
     *
     * @param itemHandle native handle of the item
     * @param data buffer to store the item's data
     * @param dataHandle handle for data buffer
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean getNextItemData0(int itemHandle, byte[] data, int dataHandle);

    /**
     * Writes modified item data to persistent storage.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param itemHandle native handle of the item
     * @param data raw data of the item
     * @param categories item's categories, separated by comma
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean commitItemData0(int listHandle, int itemHandle,
        byte[] data, String categories);

    /**
     * Adds item to the list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param data raw data of the item
     * @param categories item's categories, separated by comma
     *
     * @return native handle of the item
     */
    private native int addItem0(int listHandle, byte[] data, String categories);

    /**
     * Removes specified item from the list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param itemHandle native handle of the item
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean removeItem0(int listHandle, int itemHandle);

    /**
     * Retrieves categories defined for the specified list.
     *
     * @param listHandle native handle of the list that was previously opened
     *
     * @return item's categories, separated by comma
     */
    private native String getListCategories0(int listHandle);

    /**
     * Returns maximum number of categories supported for the given list.
     *
     * @param listHandle native handle of the list that was previously opened
     *
     * @return maximum number of categories for the list
     */
    private native int getListMaxCategories0(int listHandle);

    /**
     * Adds category to the specified list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param category name of the category to add
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean addListCategory0(int listHandle, String category);

    /**
     * Removes category from the specified list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param category name of the category to delete
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean deleteListCategory0(int listHandle, String category);

    /**
     * Renames category supported by the given list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param currentCategory old category name
     * @param newCategory new category name
     *
     * @return <code>true</code> on success, <code>false</code> otherwise
     */
    private native boolean renameListCategory0(int listHandle,
        String currentCategory, String newCategory);

    /**
     * Retrieves list of categories the specified item belongs to.
     *
     * @param itemHandle native handle of the item
     * @param dataHandle handle for data buffer
     * @return item's categories, separated by comma
     */
    private native String getItemCategories0(int itemHandle, int dataHandle);

    /**
     * Returns number of fields supported by the given list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param dataHandle to save data handle in
     *
     * @return number of supported fields
     */
    private native int getFieldsCount0(int listHandle, int [] dataHandle);

    /**
     * Returns number of labels for the specified field.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param fieldIndex index of the field
     * @param dataHandle handle of data
     *
     * @return number of labels
     */
    private native int getFieldLabelsCount0(int listHandle, int fieldIndex, int dataHandle);

    /**
     * Retrieves information about all fields supported by the list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param desc array where field descriptions will be stored
     * @param dataHandle handle of data
     */
    private native void getFields0(int listHandle, PIMFieldDescriptor[] desc, int dataHandle);

    /**
     * Returns number of attributes supported by the given list.
     *
     * @param listHandle native handle of the list that was previously opened
     *
     * @param dataHandle array to store data handle in
     * @return number of supported attributes
     */
    private native int getAttributesCount0(int listHandle, int[] dataHandle);

    /**
     * Retrieves information about all attributes supported by the list.
     *
     * @param listHandle native handle of the list that was previously opened
     * @param attr array where attribute descriptions will be stored
     * @param dataHandle data handle
     */
    private native void getAttributes0(int listHandle, PIMAttribute[] attr, int dataHandle);
}