Package com.funambol.syncclient.blackberry.parser

Source Code of com.funambol.syncclient.blackberry.parser.XMLContactParser

/*
* Funambol is a mobile platform developed by Funambol, Inc.
* Copyright (C) 2003 - 2007 Funambol, Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
*
* 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 for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*
* You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
* 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by Funambol" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by Funambol".
*/
package com.funambol.syncclient.blackberry.parser;

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

import net.rim.blackberry.api.pdap.BlackBerryContact;
//import javax.microedition.pim.Contact;
import net.rim.blackberry.api.pdap.BlackBerryContactList;
//import javax.microedition.pim.ContactList;
import net.rim.device.api.util.StringUtilities;

import javax.microedition.pim.PIMItem;//the corresponding RIM's PIMItem class is deprecated

import com.funambol.syncclient.common.StringTools;
import com.funambol.syncclient.util.StaticDataHelper;
import com.funambol.syncclient.spds.SyncException;

import net.rim.device.api.ui.component.Dialog;

import javax.microedition.pim.PIMList;
import javax.microedition.pim.PIMException;

/**
* This is not, despite the name, only a parser,
* but rather a formatter with added parsing
* functionalities. For more information about
* the Contact fields' values see
* {@link http://www.j2medev.com/api/pim/constant-values.html}
*/
public class XMLContactParser extends XMLParser implements ContactParser {
    /*
     * the values are the SIF-C elements' tag names
     */

    private static final String NOTE = "Body";//BlackBerryContact.NOTE
    private static final String BUSINESS_TEL2 = "Business2TelephoneNumber";
    private static final String BUSINESS_CITY = "BusinessAddressCity";
    private static final String BUSINESS_COUNTRY = "BusinessAddressCountry";
    private static final String BUSINESS_PO = "BusinessAddressPostalCode";
    private static final String BUSINESS_STATE = "BusinessAddressState";
    private static final String BUSINESS_STREET = "BusinessAddressStreet";
    private static final String BUSINESS_FAX = "BusinessFaxNumber";//BlackBerryContact.TEL + BlackBerryContact.ATTR_FAX
    private static final String BUSINESS_TEL = "BusinessTelephoneNumber";//BlackBerryContact.TEL + BlackBerryContact.ATTR_WORK
    private static final String CATEGORIES = "Categories";
    private static final String COMPANY = "CompanyName";//BlackBerryContact.ORG
    private static final String EMAIL_1 = "Email1Address";//BlackBerryContact.EMAIL
    private static final String FILE_AS = "FileAs";
    private static final String FIRST_NAME = "FirstName";//BlackBerryContact.NAME_GIVEN
    private static final String HOME_CITY = "HomeAddressCity";
    private static final String HOME_COUNTRY = "HomeAddressCountry";
    private static final String HOME_PO = "HomeAddressPostalCode";
    private static final String HOME_STATE = "HomeAddressState";
    private static final String HOME_STREET = "HomeAddressStreet";
    private static final String HOME_FAX = "HomeFaxNumber";
    private static final String HOME_TEL = "HomeTelephoneNumber";//BlackBerryContact.TEL + BlackBerryContact.ATTR_HOME
    private static final String INSTANT_MESSENGER = "IstantMessenger";
    private static final String TITLE = "JobTitle";//BlackBerryContact.TITLE
    private static final String LAST_NAME = "LastName";//BlackBerryContact.NAME_FAMILY
    private static final String MOBILE_TEL = "MobileTelephoneNumber";//BlackBerryContact.TEL + BlackBerryContact.ATTR_MOBILE
    private static final String PREFIX_TITLE = "Title";//Bug 856 BlackBerryContact.NAME_PREFIX
    private static final String OTHER = "OtherTelephoneNumber";//Bug 856 the field ist not supported by RIM
    private static final String PAGER_NUMBER = "PagerNumber";//Bug 856 BlackBerryContact.ATTR_PAGER
    private static final String WEB_PAGE = "WebPage";//BlackBerryContact.URL
    private static final String HIGHER_OS_4_0 = "4.0.2";
    private static final String HIGHER_OS_4_1 = "4.1";
    /**
     * This ordered list is used in the
     * method #buildMapFromXML(String)
     */
    private String[] tagArray = {
        BUSINESS_FAX, //<BusinessFaxNumber>       BlackBerryContact.TEL + BlackBerryContact.ATTR_FAX
        BUSINESS_TEL, //<BusinessTelephoneNumber> BlackBerryContact.TEL + BlackBerryContact.ATTR_WORK
        BUSINESS_TEL2,
        BUSINESS_CITY,
        BUSINESS_COUNTRY,
        BUSINESS_PO,
        BUSINESS_STATE,
        BUSINESS_STREET,
        CATEGORIES, //<Categories>
        COMPANY, //<CompanyName>             BlackBerryContact.ORG
        EMAIL_1, //<Email1Address>           BlackBerryContact.EMAIL
        FILE_AS, //<FileAs>
        FIRST_NAME, //<FirstName>               BlackBerryContact.NAME_GIVEN
        HOME_CITY,
        HOME_COUNTRY,
        HOME_FAX,
        HOME_PO,
        HOME_STATE,
        HOME_STREET,
        HOME_TEL, //<HomeTelephoneNumber>     BlackBerryContact.TEL + BlackBerryContact.ATTR_HOME
        INSTANT_MESSENGER,
        LAST_NAME, //<LastName>                BlackBerryContact.NAME_FAMILY
        MOBILE_TEL, //<MobileTelephoneNumber>   BlackBerryContact.TEL + BlackBerryContact.ATTR_MOBILE
        NOTE, //<Body>                    BlackBerryContact.NOTE
        OTHER, //<OtherTelephoneNumber>    NOT SUPPORTED BY RIM
        PAGER_NUMBER, //<PagerNumber>             BlackBerryContact.TEL + BlackBerryContact.ATTR_PAGER
        PREFIX_TITLE, //<Title>                   BlackBerryContact.NAME_PREFIX
        TITLE, //<JobTitle>                BlackBerryContact.TITLE
        WEB_PAGE             //<WebPage>                 BlackBerryContact.URL
    };
    private String[] telAttrs = {
        BUSINESS_FAX, //<BusinessFaxNumber>
        BUSINESS_TEL, //<BusinessTelephoneNumber>
        HOME_TEL, //<HomeTelephoneNumber>
        MOBILE_TEL, //<MobileTelephoneNumber>
        PAGER_NUMBER   //<PagerNumber>
    };
    private BlackBerryContactList list;
    private BlackBerryContact contact;
    private boolean modify;

    /**
     * The initialization constructor
     *
     * @param BlackBerryContactList A BlackBerry contacts list
     * @param BlackBerryContact A BlackBerry contact
     * @param boolean To modify or not to modify: that is the question...
     */
    public XMLContactParser(BlackBerryContactList list,
            BlackBerryContact contact,
            boolean modify) {
        this.list = list;
        this.contact = contact;
        this.modify = modify;
        START_MARKER = "<contact>";
        END_MARKER = "</contact>";
    }

    /**
     * <p>This method is invoked by ContactDataStore.setRecord
     * (itself invoked by SyncManagerImpl.processModifications)
     * to obtain a BlackBerryContact object from a contact String
     * in SIF-C format</p>
     *
     * <p>If the <code>modify</code> flag (passed by creating the
     * XMLContactParser within the ParserFactory) is set to true,
     * the contact is modified by invoking the {@link #modifyContact(String)}
     * method</p>
     *
     * <p>If the <code>modify</code> flag (passed by creating the
     * XMLContactParser within the ParserFactory) is set to false,
     * a contact is simply added to the BlackBerry address book by
     * invoking the {@link #addContact(String)} method</p>
     *
     * @param String String containing contact information to be
     *               parsed
     * @return The BlackBerryContact that has to be added/modified
     *         in the BlackBerry address book
     */
    public BlackBerryContact parseContact(String contactString) throws SyncException {
        if (modify) {
            return modifyContact(contactString);
        } else {
            return addContact(contactString);
        }
    }

    /**
     * Invoked to obtain a BlackBerryContact
     * object from a contact String coming from the server
     * (in SIF-C XML format), when a contact has to be added
     * to the BlackBerry address book. This method adds a new
     * contact coming from the server to the data store and
     * returns a reference to that object
     *
     * @param String String containing the contact
     *               information to be parsed in
     *               SIF-C format
     * @return The BlackBerryContact objec that has
     *         to be added
     */
    public BlackBerryContact addContact(String contactString) throws SyncException {
        Hashtable contactMap = buildMapFromXML(contactString);

        if (contactMap != null) {
            try {
                StaticDataHelper sdh = null;
                String osVersion = null;

                sdh = new StaticDataHelper();
                osVersion = sdh.getOS();

                /*
                 * This array is added here below to the contact
                 * through BlackBerryContact.NAME (so you can see
                 * BlackBerryContact.NAME as BlackBerryContact.NAME_FAMILY
                 * + BlackBerryContact.NAME_GIVEN)
                 */
                String[] arrayField = new String[5];

                //the contactMap comes from the buildMapFromXML method
                arrayField[BlackBerryContact.NAME_FAMILY] = getValue(contactMap, LAST_NAME);//LastName
                arrayField[BlackBerryContact.NAME_GIVEN] = getValue(contactMap, FIRST_NAME);//FirstName
                arrayField[BlackBerryContact.NAME_PREFIX] = getValue(contactMap, PREFIX_TITLE);//Title

                //'list' is the BlackBerryContactList passed from the ParserFactory
                if (list.isSupportedField(BlackBerryContact.NAME)) {
                    //'contact' is the BlackBerryContact passed to the constructor from the ParserFactory
                    contact.addStringArray(BlackBerryContact.NAME, PIMItem.ATTR_NONE, arrayField);//see above
                }

                String field = getValue(contactMap, EMAIL_1);//Email1Address
                if (isSupportedField(BlackBerryContact.EMAIL, field)) {
                    contact.addString(BlackBerryContact.EMAIL, BlackBerryContact.ATTR_NONE, field);
                }

                field = getValue(contactMap, NOTE);//Body
                if (isSupportedField(BlackBerryContact.NOTE, field)) {
                    contact.addString(BlackBerryContact.NOTE, BlackBerryContact.ATTR_NONE, field);
                }

                field = getValue(contactMap, TITLE);//JobTitle
                if (isSupportedField(BlackBerryContact.TITLE, field)) {
                    contact.addString(BlackBerryContact.TITLE, BlackBerryContact.ATTR_NONE, field);
                }

                field = getValue(contactMap, COMPANY);//CompanyName
                if (isSupportedField(BlackBerryContact.ORG, field)) {
                    contact.addString(BlackBerryContact.ORG, BlackBerryContact.ATTR_NONE, field);
                }

                field = getValue(contactMap, WEB_PAGE);//WebPage
                if (isSupportedField(BlackBerryContact.URL, field)) {
                    contact.addString(BlackBerryContact.URL, BlackBerryContact.ATTR_NONE, field);
                }

                field = getValue(contactMap, HOME_TEL);//HomeTelephoneNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_HOME, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_HOME, field);
                }

                field = getValue(contactMap, OTHER);//OtherTelephoneNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_OTHER, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_OTHER, field);
                }
               
                field = getValue(contactMap, MOBILE_TEL);//MobileTelephoneNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_MOBILE, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_MOBILE, field);
                }

                field = getValue(contactMap, BUSINESS_TEL);//BusinessTelephoneNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_WORK, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_WORK, field);
                }

                field = getValue(contactMap, BUSINESS_FAX);//BusinessFaxNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_FAX, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_FAX, field);
                }

                field = getValue(contactMap, PAGER_NUMBER);//PagerNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_PAGER, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_PAGER, field);
                }

                field = getValue(contactMap, CATEGORIES);//Categories
                //String[] categories = StringUtilities.stringToWords(field);
                int startIndex = 0;
                String category = field;
                final String sep=";";
                do {
                    int i = category.indexOf(sep, startIndex);
                    if (i != -1) {
                        addCategory(category.substring(startIndex, i), contact);

                        category = category.substring(i + 1);
                        startIndex = i + 1;
                    }

                } while (category.indexOf(sep, startIndex) != -1);
                if (category.trim().length() > 0) {
                    addCategory(category, contact);
                }
                //for (int j = 0; j < categories.length; j++)
                //{
                //    contact.addToCategory(categories[j]);
                //}

                //if the OS version is 4.0.2 upward
                if (checkOS(osVersion)) {
                    //in case field BlackBerryContact.ADDR is supported with work (business) attributes...
                    if (list.isSupportedField(BlackBerryContact.ADDR)) {
                        arrayField = new String[7];
                        arrayField[BlackBerryContact.ADDR_COUNTRY] = getValue(contactMap, BUSINESS_COUNTRY);
                        arrayField[BlackBerryContact.ADDR_STREET] = getValue(contactMap, BUSINESS_STREET);
                        arrayField[BlackBerryContact.ADDR_REGION] = getValue(contactMap, BUSINESS_STATE);
                        arrayField[BlackBerryContact.ADDR_LOCALITY] = getValue(contactMap, BUSINESS_CITY);
                        arrayField[BlackBerryContact.ADDR_POSTALCODE] = getValue(contactMap, BUSINESS_PO);

                        StaticDataHelper.log("[DEBUG]In XMLContactParser.addContact() -> setting arrayField with BUSINESS ADDRESS: " + StringTools.dump(arrayField));
                        contact.addStringArray(BlackBerryContact.ADDR,
                                BlackBerryContact.ATTR_WORK,
                                arrayField);
                    }


                    //in case the field BlackBerryContact.ADDR supports the Home attributes too...
                    if (list.isSupportedField(BlackBerryContact.ADDR) &&
                            list.isSupportedAttribute(BlackBerryContact.ADDR, BlackBerryContact.ATTR_HOME)) {
                        arrayField = new String[7];
                        arrayField[BlackBerryContact.ADDR_COUNTRY] = getValue(contactMap, HOME_COUNTRY);
                        arrayField[BlackBerryContact.ADDR_STREET] = getValue(contactMap, HOME_STREET);
                        arrayField[BlackBerryContact.ADDR_REGION] = getValue(contactMap, HOME_STATE);
                        arrayField[BlackBerryContact.ADDR_LOCALITY] = getValue(contactMap, HOME_CITY);
                        arrayField[BlackBerryContact.ADDR_POSTALCODE] = getValue(contactMap, HOME_PO);

                        StaticDataHelper.log("[DEBUG]In XMLContactParser.addContact() -> arrayField set wit HOME ADDRESS: " + StringTools.dump(arrayField));
                        contact.addStringArray(BlackBerryContact.ADDR,
                                BlackBerryContact.ATTR_HOME,
                                arrayField);
                    }
                }

                return contact;
            } catch (Exception e) {
                StaticDataHelper.log("[CARD]Exception in XMLContactParser.addContact(): " + e.toString());
                e.printStackTrace();

                return null;
            }
        }

        /*
         * when contactMap is null (i.e.,
         * when wether <contact> nor </contact>
         * tags are found in the data section
         * of the SyncML message by the
         * buildMapFromXML() method)
         */
        return null;
    }

    private void addCategory(String category, PIMItem item) {
        try {
            PIMList list = item.getPIMList();
            if (list.isCategory(category)) {
                item.addToCategory(category);
            } else {
                if ((list.maxCategories() == -1)||(list.maxCategories() > list.getCategories().length)) {
                    list.addCategory(category);
                    item.addToCategory(category);
                }
            }
        } catch (PIMException e) {
             StaticDataHelper.log("[CARD]Exception in XMLContactParser.addCategory(): " + e.toString());
             e.printStackTrace();
        }

    }

    /**
     * Invoked to obtain a BlackBerryContact
     * object from a contact String coming from
     * the server, when a contact has to be modified
     * in the BlackBerry address book. This method
     * modifies the object and returns a reference
     * to that object
     *
     * @param String The string containing contact
     *               information to be parsed
     * @return The BlackBerryContact contact that
     *         has been modified on the server
     */
    public BlackBerryContact modifyContact(String contactString) throws SyncException {
        String[] arrayFieldWork = null;
        String[] arrayFieldHome = null;

        Hashtable contactMap = buildMapFromXML(contactString);

        StaticDataHelper sdh = new StaticDataHelper();
        String osVersion = sdh.getOS();

        if (contactMap != null) {
            try {
                String[] arrayField = new String[5];
                arrayField[BlackBerryContact.NAME_FAMILY] = getValue(contactMap, LAST_NAME);
                arrayField[BlackBerryContact.NAME_GIVEN] = getValue(contactMap, FIRST_NAME);
                arrayField[BlackBerryContact.NAME_PREFIX] = getValue(contactMap, PREFIX_TITLE);

                /*
                 * since you can't add data to a field that already contains data,
                 * invoke countValues() to determine whether the field is empty. If
                 * the field is not empty, invoke removeValue() to remove the data
                 * from the field before you add new data. But you can set an
                 * existing string array value in that field, like here
                 */
                if (contact.countValues(BlackBerryContact.NAME) > 0) {
                    contact.setStringArray(BlackBerryContact.NAME, 0, BlackBerryContact.ATTR_NONE, arrayField);
                } else {
                    contact.addStringArray(BlackBerryContact.NAME, BlackBerryContact.ATTR_NONE, arrayField);
                }

                String field = getValue(contactMap, EMAIL_1);
                if (isSupportedField(BlackBerryContact.EMAIL, field)) {
                    if (contact.countValues(BlackBerryContact.EMAIL) > 0) {
                        contact.setString(BlackBerryContact.EMAIL, 0, BlackBerryContact.ATTR_NONE, field);
                    } else {
                        contact.addString(BlackBerryContact.EMAIL, BlackBerryContact.ATTR_NONE, field);
                    }
                }

                field = getValue(contactMap, NOTE);
                if (isSupportedField(BlackBerryContact.NOTE, field)) {
                    if (contact.countValues(BlackBerryContact.NOTE) > 0) {
                        contact.removeValue(BlackBerryContact.NOTE, 0);
                        contact.addString(BlackBerryContact.NOTE, BlackBerryContact.ATTR_NONE, field);
                    } else {
                        contact.addString(BlackBerryContact.NOTE, BlackBerryContact.ATTR_NONE, field);
                    }
                }

                field = getValue(contactMap, COMPANY);
                if (isSupportedField(BlackBerryContact.ORG, field)) {
                    if (contact.countValues(BlackBerryContact.ORG) > 0) {
                        contact.setString(BlackBerryContact.ORG, 0, BlackBerryContact.ATTR_NONE, field);
                    } else {
                        contact.addString(BlackBerryContact.ORG, BlackBerryContact.ATTR_NONE, field);
                    }
                }

                field = getValue(contactMap, TITLE);//<JobTitle>
                if (isSupportedField(BlackBerryContact.TITLE, field) && contact.countValues(BlackBerryContact.TITLE) > 0) {
                    contact.setString(BlackBerryContact.TITLE, 0, BlackBerryContact.ATTR_NONE, field);
                } else {
                    contact.addString(BlackBerryContact.TITLE, BlackBerryContact.ATTR_NONE, field);
                }

                if (isSupportedField(BlackBerryContact.URL, field) && contact.countValues(BlackBerryContact.URL) > 0) {
                    contact.removeValue(BlackBerryContact.URL, 0);
                    field = getValue(contactMap, WEB_PAGE);
                    contact.addString(BlackBerryContact.URL, BlackBerryContact.ATTR_NONE, field);
                }

                int telValues = contact.countValues(BlackBerryContact.TEL);
                for (int i = 0; i < telValues; i++) {
                    contact.removeValue(BlackBerryContact.TEL, 0);
                }

                field = getValue(contactMap, HOME_TEL);
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_HOME, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_HOME, field);
                }

                field = getValue(contactMap, MOBILE_TEL);
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_MOBILE, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_MOBILE, field);
                }

                field = getValue(contactMap, OTHER);//OtherTelephoneNumber
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_OTHER, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_OTHER, field);
                }
               
                field = getValue(contactMap, BUSINESS_TEL);
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_WORK, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_WORK, field);
                }

                field = getValue(contactMap, BUSINESS_FAX);
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_FAX, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_FAX, field);
                }

                field = getValue(contactMap, PAGER_NUMBER);//<PagerNumber>
                if (isSupportedAttributedField(BlackBerryContact.TEL, BlackBerryContact.ATTR_PAGER, field)) {
                    contact.addString(BlackBerryContact.TEL, BlackBerryContact.ATTR_PAGER, field);
                }

                field = getValue(contactMap, CATEGORIES);//<Categories>
                String[] categories = StringUtilities.stringToWords(field);

                /*
                 * first wipe all categories already on the device...
                 */
                String[] alreadyOnDevicePresentCategories = contact.getCategories();
                for (int i = 0; i < alreadyOnDevicePresentCategories.length; i++) {
                    contact.removeFromCategory(alreadyOnDevicePresentCategories[i]);
                }

                /*
                 * ... and then add the new ones (they're
                 * incoming, and represent always the last
                 * will of the user)
                 */
                for (int j = 0; j < categories.length; j++) {
                    contact.addToCategory(categories[j]);
                }

                //only for OS 4.0.2 upward
                //FIXME: every OS version has at least the Business address!
                if (checkOS(osVersion)) {

                    //when the field BlackBerryContact.ADDR is supported with work (business) attributes...
                    if (list.isSupportedField(BlackBerryContact.ADDR)) {
                        arrayFieldWork = new String[7];//very important: the length must be 7
                        arrayFieldWork[BlackBerryContact.ADDR_COUNTRY] = getValue(contactMap, BUSINESS_COUNTRY);
                        arrayFieldWork[BlackBerryContact.ADDR_STREET] = getValue(contactMap, BUSINESS_STREET);
                        arrayFieldWork[BlackBerryContact.ADDR_REGION] = getValue(contactMap, BUSINESS_STATE);
                        arrayFieldWork[BlackBerryContact.ADDR_LOCALITY] = getValue(contactMap, BUSINESS_CITY);
                        arrayFieldWork[BlackBerryContact.ADDR_POSTALCODE] = getValue(contactMap, BUSINESS_PO);
                    }

                    //when the field BlackBerryContact.ADDR supports the Home attributes too...
                    if (list.isSupportedField(BlackBerryContact.ADDR) &&
                            list.isSupportedAttribute(BlackBerryContact.ADDR, BlackBerryContact.ATTR_HOME)) {

                        arrayFieldHome = new String[7];//very important: the length must be 7
                        arrayFieldHome[BlackBerryContact.ADDR_COUNTRY] = getValue(contactMap, HOME_COUNTRY);
                        arrayFieldHome[BlackBerryContact.ADDR_STREET] = getValue(contactMap, HOME_STREET);
                        arrayFieldHome[BlackBerryContact.ADDR_REGION] = getValue(contactMap, HOME_STATE);
                        arrayFieldHome[BlackBerryContact.ADDR_LOCALITY] = getValue(contactMap, HOME_CITY);
                        arrayFieldHome[BlackBerryContact.ADDR_POSTALCODE] = getValue(contactMap, HOME_PO);
                    }

                    StaticDataHelper.log("[DEBUG]>>> Count Addr Items: " + contact.countValues(BlackBerryContact.ADDR));
                    int addressFields = contact.countValues(BlackBerryContact.ADDR);

                    switch (addressFields) {

                        /*
                         * the contact hasn't both home and
                         * work address already set, we just
                         * need to add the new values with
                         * the addStringArray() method without
                         * removing old data
                         */
                        case 0:
                            StaticDataHelper.log("[DEBUG]In XMLContactParser.modifyContact() -> adding arrayField with BUSINESS ADDRESS: " + StringTools.dump(arrayFieldWork));
                            contact.addStringArray(BlackBerryContact.ADDR,
                                    BlackBerryContact.ATTR_WORK,
                                    arrayFieldWork);

                            StaticDataHelper.log("[DEBUG]In XMLContactParser.modifyContact() -> adding arrayField with HOME ADDRESS: " + StringTools.dump(arrayFieldHome));
                            contact.addStringArray(BlackBerryContact.ADDR,
                                    BlackBerryContact.ATTR_HOME,
                                    arrayFieldHome);
                            break;

                        /*
                         * only the work address or the
                         * home address is set, we need
                         * to remove the address and then
                         * to add both work and home address,
                         * even though one of them is empty
                         */
                        case 1:
                            contact.removeValue(BlackBerryContact.ADDR, 0);
                            StaticDataHelper.log("[DEBUG]In XMLContactParser.modifyContact() -> adding arrayField with BUSINESS ADDRESS: " + StringTools.dump(arrayFieldWork));
                            contact.addStringArray(BlackBerryContact.ADDR,
                                    BlackBerryContact.ATTR_WORK,
                                    arrayFieldWork);

                            StaticDataHelper.log("[DEBUG]In XMLContactParser.modifyContact() -> adding arrayField with HOME ADDRESS: " + StringTools.dump(arrayFieldHome));
                            contact.addStringArray(BlackBerryContact.ADDR,
                                    BlackBerryContact.ATTR_HOME,
                                    arrayFieldHome);
                            break;

                        /*
                         * both work and home address are
                         * set, we can modify them with the
                         * setStringArray() method
                         */
                        case 2:
                            StaticDataHelper.log("[DEBUG]In XMLContactParser.modifyContact() -> setting arrayField with BUSINESS ADDRESS: " + StringTools.dump(arrayFieldWork));
                            contact.setStringArray(BlackBerryContact.ADDR, //The field in which the value to change exists
                                    0, //The index of the value to change
                                    BlackBerryContact.ATTR_WORK, //A byte array containing information about this field as int
                                    arrayFieldWork); //The new value

                            StaticDataHelper.log("[DEBUG]In XMLContactParser.modifyContact() -> setting arrayField with HOME ADDRESS: " + StringTools.dump(arrayFieldHome));
                            contact.setStringArray(BlackBerryContact.ADDR, //The field in which the value to change exists
                                    1, //The index of the value to change
                                    BlackBerryContact.ATTR_HOME, //A byte array containing information about this field as int
                                    arrayFieldHome); //The new value
                            break;

                        default:
                            //
                            break;
                    }

                    return contact;
                }
            } catch (Exception e) {
                StaticDataHelper.log("[CARD]Exception in XMLContactParser.modifyContact(): " + e.toString());
                return null;
            }
        }
        return null;
    }

    /**
     * Transforms the contact information from the storage
     * of the device (also known as database) into a SIF-C
     * XML string to pass to the server in the \<Data\>
     * section of a SyncML message
     *
     * @param BlackBerryContact A native BlackBerry contact
     *                          wrapped in a Java BlackBerryContact
     *                          class
     * @return String All contact information in a string
     *                (XML SIF-C)
     */
    public String toString(BlackBerryContact contact) {
        StaticDataHelper.log(">>> Entering XMLContactParser.toString()...");
        StringBuffer contactBuffer = new StringBuffer();

        StaticDataHelper sdh = null;
        String osVersion = null;

        sdh = new StaticDataHelper();

        osVersion = sdh.getOS();

        contactBuffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

        contactBuffer.append("<contact>\n");

        /*
         * to let Outlook display the name
         * on the Contacts start page
         */
        //appendFileAs(contactBuffer);

        appendName(contactBuffer, contact);

        appendField(contactBuffer,
                contact,
                BlackBerryContact.ORG,//the int native code of this contact field on the device
                COMPANY);//<CompanyName></CompanyName>

        appendField(contactBuffer,
                contact,
                BlackBerryContact.NOTE,//the int native code of this contact field on the device
                NOTE);//<Body></Body>

        appendField(contactBuffer,
                contact,
                BlackBerryContact.TITLE,//the int native code of this contact field on the device
                TITLE);//<JobTitle></JobTitle>

        appendField(contactBuffer,
                contact,
                BlackBerryContact.EMAIL,//the int native code of this contact field on the device
                EMAIL_1);//<Email1Address></Email1Address>

        appendField(contactBuffer,
                contact,
                BlackBerryContact.URL,//the int native code of this contact field on the device
                WEB_PAGE);//<WebPage></WebPage>

        //bugfix 877
        appendCategories(contactBuffer);

        appendTelephoneFields(contactBuffer, contact);

        if (checkOS(osVersion)) {
            appendAddress(contactBuffer, contact);
        }

        contactBuffer.append("</contact>");

        sdh.log(">>> returned SIF-C content after fixing bug 856:\n" + contactBuffer.toString());
        return contactBuffer.toString();
    }

    /**
     * Appends the contact information
     * supported by the BlackBerry to
     * a string buffer (uses #appendToContact)
     *
     * @param StringBuffer String buffer containing contact information
     * @param BlackBerryContact A BlackBerry contact
     * @param int Type of field (native code of the device's contact field)
     * @param String An XML tag for the SIF format
     */
    private void appendField(StringBuffer contactBuffer,
            BlackBerryContact contact,
            int field,
            String tag) {
        String value = null;

        if (list.isSupportedField(field)) {
            value = "";

            try {
                value = contact.getString(field, 0);//
            } catch (Exception e) {
                StaticDataHelper.log(">>> In XMLContactParser.appendField() --> Field not set: " + tag +
                        ". --> " + e.toString());
            }

            appendToContact(contactBuffer, tag, value);
        }
    }

    /**
     * Appends the contact information
     * supported by the BlackBerry to
     * a string buffer (used by #appendField)
     *
     * @param StringBuffer String buffer representing the SIF-C content and
     *                     containing contact information
     * @param String Name of tag associated with the contact information
     * @param String Value corresponding to the XML element
     */
    private void appendToContact(StringBuffer contactBuffer, String tag, String value) {
        value = (value == null) ? "" : value;

        if (value.length() > 0) {
            value = StringTools.escapeXml(value);
        }

        contactBuffer.append("<").append(tag).append(">").append(value);
        contactBuffer.append("</").append(tag).append(">\n");

    }

    /**
     * This method appends the data corresponding
     * to the contact's name array
     *
     * @param StringBuffer String buffer to which data is appended
     * @param BlackBerryContact The BlackBerry contact object
     */
    private void appendName(StringBuffer buffer, BlackBerryContact contact) {
        if (contact.countValues(BlackBerryContact.NAME) > 0) {
            String[] name = contact.getStringArray(BlackBerryContact.NAME, 0);

            appendToContact(buffer, FIRST_NAME, name[BlackBerryContact.NAME_GIVEN]);//e.g. <FirstName>John</FirstName>
            appendToContact(buffer, LAST_NAME, name[BlackBerryContact.NAME_FAMILY]);//e.g. <LastName>Doe</LastName>
            appendToContact(buffer, PREFIX_TITLE, name[BlackBerryContact.NAME_PREFIX]);//e.g. <Title>Dr</Title>
        } else {
            appendToContact(buffer, FIRST_NAME, "");//e.g. <FirstName></FirstName>
            appendToContact(buffer, LAST_NAME, "");//e.g. <LastName></LastName>
            appendToContact(buffer, PREFIX_TITLE, "");//e.g. <Title></Title>
        }
    }

    /**
     * This method appends the data corresponding
     * to the contact's telephone numbers array
     *
     * @param StringBuffer BlackBerry contact list
     * @param BlackBerryContact BlackBerry contact
     */
    private void appendTelephoneFields(StringBuffer buffer, BlackBerryContact contact) {
        /**
         * The number of values contained in the <code>BlackBerryContact.TEL</code> field
         */
        int totalTelFields = contact.countValues(BlackBerryContact.TEL);

        Vector addedAttrs = new Vector();

        for (int i = 0; i < totalTelFields; i++) {
            String value = contact.getString(BlackBerryContact.TEL, i);
            int attr = contact.getAttributes(BlackBerryContact.TEL, i);
            String tag = "";
            switch (attr) {
                case BlackBerryContact.ATTR_MOBILE://16
                    tag = MOBILE_TEL;//<MobileTelephoneNumber>
                    break;
                case BlackBerryContact.ATTR_FAX://4
                    tag = BUSINESS_FAX;//<BusinessFaxNumber>
                    break;
                case BlackBerryContact.ATTR_WORK://512
                    tag = BUSINESS_TEL;//<BusinessTelephoneNumber>
                    break;
                case BlackBerryContact.ATTR_HOME://8
                    tag = HOME_TEL;//<HomeTelephoneNumber>
                    break;
                case BlackBerryContact.ATTR_PAGER://64
                    tag = PAGER_NUMBER;//<PagerNumber>
                    break;
                case BlackBerryContact.ATTR_OTHER:
                    tag = OTHER;//<OtherThelephonNumber>
                    break;
            }
            if (!tag.equals("")) {
                appendToContact(buffer, tag, value);
                addedAttrs.addElement(tag);
            }
        }

        //this is just to create an empty element
        //for each element that wasn't added here
        //above
        for (int i = 0; i < telAttrs.length; i++) {
            if (!addedAttrs.contains(telAttrs[i]))//telAttrs is a String array defined above
            {
                appendToContact(buffer, telAttrs[i], "");
            }
        }
    }

    /**
     * This method only appends the data corresponding to contact's address details.
     *
     * @param StringBuffer: Blackberry contact list
     * @param BlackBerryContact: Blackberry contact
     * @return void
     */
    private void appendAddress(StringBuffer buffer, BlackBerryContact contact) {

        StaticDataHelper sdh = null;
        String osVersion = null;
        boolean findHome = false;
        boolean findBusiness = false;

        sdh = new StaticDataHelper();

        osVersion = sdh.getOS();

        if (checkOS(osVersion)) {

            if (list.isSupportedField(BlackBerryContact.ADDR) && contact.countValues(BlackBerryContact.ADDR) > 0) {

                for (int i = 0; i < contact.countValues(BlackBerryContact.ADDR); i++) {
                    String[] addr = contact.getStringArray(BlackBerryContact.ADDR, i);
                    if (addr != null && addr.length > 0) {
                        int addrType = contact.getAttributes(BlackBerryContact.ADDR, i);

                        if (addrType == BlackBerryContact.ATTR_HOME) {

                            findHome = true;

                            appendToContact(buffer, HOME_STREET, addr[BlackBerryContact.ADDR_STREET]);
                            appendToContact(buffer, HOME_STATE, addr[BlackBerryContact.ADDR_REGION]);
                            appendToContact(buffer, HOME_CITY, addr[BlackBerryContact.ADDR_LOCALITY]);
                            appendToContact(buffer, HOME_PO, addr[BlackBerryContact.ADDR_POSTALCODE]);
                            appendToContact(buffer, HOME_COUNTRY, addr[BlackBerryContact.ADDR_COUNTRY]);

                        } else {

                            findBusiness = true;

                            appendToContact(buffer, BUSINESS_STREET, addr[BlackBerryContact.ADDR_STREET]);
                            appendToContact(buffer, BUSINESS_STATE, addr[BlackBerryContact.ADDR_REGION]);
                            appendToContact(buffer, BUSINESS_CITY, addr[BlackBerryContact.ADDR_LOCALITY]);
                            appendToContact(buffer, BUSINESS_PO, addr[BlackBerryContact.ADDR_POSTALCODE]);
                            appendToContact(buffer, BUSINESS_COUNTRY, addr[BlackBerryContact.ADDR_COUNTRY]);
                        }

                    }
                }
            }

            if (!findHome) {
                appendToContact(buffer, HOME_STREET, "");
                appendToContact(buffer, HOME_STATE, "");
                appendToContact(buffer, HOME_CITY, "");
                appendToContact(buffer, HOME_PO, "");
                appendToContact(buffer, HOME_COUNTRY, "");
            }

            if (!findBusiness) {
                appendToContact(buffer, BUSINESS_STREET, "");
                appendToContact(buffer, BUSINESS_STATE, "");
                appendToContact(buffer, BUSINESS_CITY, "");
                appendToContact(buffer, BUSINESS_PO, "");
                appendToContact(buffer, BUSINESS_COUNTRY, "");
            }

        }

    }

    /**
     * Returns the value associated with a key in a hashtable
     * represented by the passed contactMap. The content is
     * trimmed before to be returned. If the value associated
     * with the given key is a null object, an empty string
     * is returned
     *
     * @param Hashtable The passed contactMap
     * @param String The key to which the associated value is to be found
     * @return String The value associated with the key
     */
    private String getValue(Hashtable contactMap, String key) {
        Object val = contactMap.get(key);
        String value = val == null ? "" : val.toString();
        return value.trim();
    }

    /**
     * This method checks if the field and attibute are supported by the contact list
     * of blackberry address book
     *
     * @param int: field
     * @param int: attribute
     * @param String: value
     * @return boolean:returns true if both the field and attribute
     * associated with it r supported
     */
    private boolean isSupportedAttributedField(int field, int attribute, String value) {
        return isSupportedField(field, value) && list.isSupportedAttribute(field, attribute);
    }

    /**
     * Checks if the type of field is supported by the contact list
     * of the BlackBerry address book
     *
     * @param int type
     * @param String value
     * @return boolean returns true if the contact list supports this field
     */
    private boolean isSupportedField(int type, String value) {
        return list.isSupportedField(type);
    }


    /**
     * This method creates a hashtable with keys and values associated with
     * the BlackBerry contact list attributes (picked from the great ordered
     * list defined at the top of this class, {@code tagArray})
     *
     * @param String A SIF-C XML string representing a BlackBerryContact
     *               from the server
     * @return Hashtable
     * @throws SyncException if no correct contact element in SIF-C comes from
     *                       the server
     */
     /*
    private Hashtable buildMapFromXML(String contactString) throws SyncException {

        int startMarkerIndex = contactString.indexOf(START_MARKER);//<contact>
        int endMarkerIndex = contactString.indexOf(END_MARKER);//</contact>

        if (startMarkerIndex == -1 || endMarkerIndex == -1) {
            throw new SyncException("Improper data from the server");
        //Dialog.inform("Improper data from the server");
        //return null;
        }

        //Check if xml is got an utf-8 encoding in header. TODO: Generalize to other encodings.
        boolean is_utf8 = (contactString.substring(0, startMarkerIndex).toLowerCase().indexOf("encoding=\"utf-8\"") != -1);

        Hashtable contactMap = new Hashtable();       
        boolean readNothing = true;
        boolean readOpenTag = false;
        boolean readData = false;
        int openTagPos = 0;
        int dataPos = 0;
        String tagName = "";
        String data = "";
       
        int tagLength = START_MARKER.length();
        //TODO: Handle CDATA      
        for(int i=startMarkerIndex + tagLength; i< endMarkerIndex; i++){
            char c = contactString.charAt(i);    
            switch(c){
                case '<':
                    if(readNothing){
                        openTagPos = i+1;
                        readOpenTag = true;
                        readNothing = false;
                    }
                    else if(readData){
                        int p = contactString.indexOf("</" + tagName + '>', i);
                        if(p != -1){
                            data = contactString.substring(dataPos, i);
                            if(is_utf8){
                                try{
                                    data = new String(data.getBytes(), "UTF-8");
                                }
                                catch (java.io.UnsupportedEncodingException e){
                                    Log.debug(e.toString());
                                }
                            }
                           
                            i += tagName.length() + 2;
                            readData = false;
                            dataPos = 0;
                            readNothing = true;
                           
                            data = unEscapeXML(data);
                            //Insert into map
                           contactMap.put(tagName, data);
                        }
                        else {
                           //Tag mismatch
                            //TODO:Exception
                        }
                    }
                    else {
                        //Unexpected <
                        //TODO:Exception
                    }
                    break;
                case '/':
                    if(readOpenTag){
                        //<Tag />
                        readOpenTag = false;
                        readNothing = true;
                        openTagPos = 0;
                        i++;
                    }
                    break;
                case ' ':
                    if(readOpenTag){
                        tagName = contactString.substring(openTagPos, i);
                        int p = contactString.indexOf('>', i);
                        if(p != -1){
                            if(contactString.substring(i,p).indexOf('/') != -1){
                                //<Tag />
                                readOpenTag = false;
                                readNothing = true;
                                openTagPos = 0;
                                i = p;
                            }
                            else {
                                //Finished reading open tag
                                i = p;
                                readOpenTag = false;
                                readData = true;
                                dataPos = i+1;
                            }
                        }
                        else {
                            //Tag not closed
                            //TODO:Exception
                        }
                    }
                    break;
                case '>':
                    if(readOpenTag){
                        tagName = contactString.substring(openTagPos, i);
                        readOpenTag = false;
                        readData = true;
                        dataPos = i+1;
                    }
                    break;
                default:
                   
             }
        }
        return contactMap;
    }
*/
    /**
     * check OS version
     * @param handled OS
     * @return true if OS >= 4.0.2
     */
    private boolean checkOS(String os) {
        if (os == null || os.length() == 0) {
            StaticDataHelper sdh = new StaticDataHelper();
            sdh.setOS();
            os = sdh.getOS();
        }

        if (os == null || !(os.length() > 3)) {
            return false;
        }

        int major = Integer.valueOf(os.substring(0, 1)).intValue();
        int middle = Integer.valueOf(os.substring(2, 3)).intValue();

        int minor = 0;

        if (os.length() > 4) {
            minor = Integer.valueOf(os.substring(4, 5)).intValue();
        }

        if ((major > 4) || (major == 4 && ((middle == 0 && minor >= 2) || middle >= 1))) {
            return true;
        } else {
            return false;
        }
    }

    //bugfixing 877
    private void appendCategories(StringBuffer contactBuffer) {
        String[] categories = contact.getCategories();
        StringBuffer categoriesBuffer = new StringBuffer();
        String categoriesContents = null;

        if (categories.length >= 1) {
            for (int k = 0; k < categories.length; k++) {
                categoriesBuffer.append(categories[k]);
                if (categories.length > 1 && k < (categories.length - 1)) {
                    categoriesBuffer.append("; ");//the separator (semicolon + blank)
                }
            }

            //e.g. Business; Marketing
            categoriesContents = StringTools.escapeXml(categoriesBuffer.toString());
        } else {
            //no categories at all!
            categoriesContents = "";
        }

        //e.g. <Categories>Business; Marketing</Categories>
        contactBuffer.append("<" + CATEGORIES + ">" +
                categoriesContents +
                "</" + CATEGORIES + ">");
    }

    /*
     * FIXME: we can save the incoming FileAs to a User defined field, and put it back
     *        when it's present
     */
    private void appendFileAs(StringBuffer contactBuffer) {

        String name = contact.getStringArray(BlackBerryContact.NAME, 0)[BlackBerryContact.NAME_GIVEN];
        String surname = contact.getStringArray(BlackBerryContact.NAME, 0)[BlackBerryContact.NAME_FAMILY];
        String comma = ", ";

        if (surname == null) {
            surname = "";
            comma = "";
        }

        if (name == null) {
            name = "";
            comma = "";
        }

        String value = surname + comma + name;//"Reeve, Christopher" | "Reeve" | "Christopher"

        if (value.length() > 0) {
            value = StringTools.escapeXml(value);
        }

        contactBuffer.append("<" + FILE_AS + ">" +
                value +
                "</" + FILE_AS + ">");
    }
}
TOP

Related Classes of com.funambol.syncclient.blackberry.parser.XMLContactParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.