Search in sources :

Example 6 with VCardParamsAndValue

use of com.zimbra.cs.mailbox.VCardParamsAndValue in project zm-mailbox by Zimbra.

the class VCard method parseVCard.

public static List<VCard> parseVCard(String vcard) throws ServiceException {
    List<VCard> cards = new ArrayList<VCard>();
    Map<String, String> fields = new HashMap<String, String>();
    ListMultimap<String, VCardParamsAndValue> xprops = ArrayListMultimap.create();
    List<Attachment> attachments = new ArrayList<Attachment>();
    VCardProperty vcprop = new VCardProperty();
    int depth = 0;
    int cardstart = 0;
    String uid = null;
    StringBuilder line = new StringBuilder(256);
    for (int start, pos = 0, limit = vcard.length(); pos < limit; ) {
        // unfold the next line in the vcard
        line.setLength(0);
        String name = null;
        String value;
        int linestart = pos;
        boolean folded = true;
        do {
            start = pos;
            while (pos < limit && vcard.charAt(pos) != '\r' && vcard.charAt(pos) != '\n') {
                pos++;
            }
            line.append(vcard.substring(start, pos));
            if (pos < limit) {
                if (pos < limit && vcard.charAt(pos) == '\r')
                    pos++;
                if (pos < limit && vcard.charAt(pos) == '\n')
                    pos++;
            }
            if (pos < limit && (vcard.charAt(pos) == ' ' || vcard.charAt(pos) == '\t')) {
                pos++;
            } else {
                name = vcprop.parse(line);
                if ((vcprop.getEncoding() != Encoding.Q) || !((line.length() > 0) && ('=' == (line.charAt(line.length() - 1))))) {
                    folded = false;
                }
            }
        } while (folded);
        if (vcprop.isEmpty()) {
            continue;
        }
        if (Strings.isNullOrEmpty(name)) {
            throw ServiceException.PARSE_ERROR("missing property name in line " + shortFormForLogging(line), null);
        } else if (name.equals("VERSION") || name.equals("REV") || name.equals("PRODID")) {
            continue;
        } else if ((name.startsWith("X-") && !name.startsWith("X-ZIMBRA-")) || (!PROPERTY_NAMES.contains(name))) {
            VCardParamsAndValue ppav;
            if (Encoding.B.equals(vcprop.encoding)) {
                // Keep value encoded as don't trust binary data stored in metadata
                Set<String> params = vcprop.params;
                params.add("ENCODING=B");
                if ((vcprop.charset != null) && (!MimeConstants.P_CHARSET_UTF8.equals(vcprop.charset))) {
                    params.add(String.format("CHARSET=%s", vcprop.charset));
                }
                ppav = new VCardParamsAndValue(vcprop.value, vcprop.params);
            } else {
                ppav = new VCardParamsAndValue(vcfDecode(vcprop.getValue()), vcprop.params);
            }
            // handle multiple occurrences of xprops with the same key
            String group = vcprop.getGroup();
            String key = (group == null) ? name : group + "." + name;
            xprops.put(key, ppav);
        } else if (name.equals("BEGIN")) {
            if (++depth == 1) {
                // starting a top-level vCard; reset state
                fields = new HashMap<String, String>();
                xprops = ArrayListMultimap.create();
                attachments = new ArrayList<Attachment>();
                cardstart = linestart;
                uid = null;
            }
            continue;
        } else if (name.equals("END")) {
            if (depth > 0 && depth-- == 1) {
                if (!xprops.isEmpty()) {
                    fields.put(ContactConstants.A_vCardXProps, Contact.encodeUnknownVCardProps(xprops));
                }
                // finished a vCard; add to list if non-empty
                if (!fields.isEmpty()) {
                    Contact.normalizeFileAs(fields);
                    cards.add(new VCard(fields.get(ContactConstants.A_fullName), vcard.substring(cardstart, pos), fields, attachments, uid));
                }
            }
            continue;
        } else if (depth <= 0) {
            continue;
        } else if (name.equals("AGENT")) {
            // catch AGENT on same line as BEGIN block when rest of AGENT is not on the same line
            if (vcprop.getValue().trim().toUpperCase().matches("BEGIN\\s*:\\s*VCARD"))
                depth++;
            continue;
        }
        if (vcprop.getEncoding() == Encoding.B && !vcprop.containsParam("VALUE=URI")) {
            if (name.equals("PHOTO")) {
                String suffix = vcprop.getParamValue("TYPE").toUpperCase();
                String ctype = null;
                if (!Strings.isNullOrEmpty(suffix)) {
                    ctype = "image/" + suffix.toLowerCase();
                    suffix = '.' + suffix;
                }
                attachments.add(new Attachment(vcprop.getDecoded(), ctype, "image", "image" + suffix));
                continue;
            }
            if (name.equals("KEY")) {
                String encoded = new String(Base64.encodeBase64Chunked(vcprop.getDecoded()));
                fields.put(ContactConstants.A_userCertificate, encoded);
                continue;
            }
        }
        value = vcprop.getValue();
        // decode the property's value and assign to the appropriate contact field(s)
        if (name.equals("FN"))
            addField(ContactConstants.A_fullName, vcfDecode(value), "altFullName", 2, fields);
        else if (name.equals("N"))
            decodeStructured(value, NAME_FIELDS, fields);
        else if (// TODO: VCARD 4 NICKNAME is multi-valued (COMMA separated)
        name.equals("NICKNAME"))
            // It is treated as a single value here
            addField(ContactConstants.A_nickname, vcfDecode(value), "altNickName", 2, fields);
        else if (// Assumption: Do not want multiple photos.
        name.equals("PHOTO"))
            // Assumption: Do not want multiple photos.
            fields.put(ContactConstants.A_image, vcfDecode(value));
        else if (name.equals("BDAY"))
            addField(ContactConstants.A_birthday, vcfDecode(value), null, 2, fields);
        else if (name.equals("ADR"))
            decodeAddress(value, vcprop, fields);
        else if (name.equals("TEL"))
            decodeTelephone(value, vcprop, fields);
        else if (name.equals("URL"))
            decodeURL(value, vcprop, fields);
        else if (name.equals("ORG"))
            decodeStructured(value, ORG_FIELDS, fields);
        else if (name.equals("TITLE"))
            addField(ContactConstants.A_jobTitle, vcfDecode(value), "altJobTitle", 2, fields);
        else if (name.equals("NOTE"))
            addField(ContactConstants.A_notes, vcfDecode(value), null, 2, fields);
        else if (name.equals("EMAIL"))
            addField(ContactConstants.A_email, vcfDecode(value), null, 2, fields);
        else if (name.equals("X-ZIMBRA-MAIDENNAME"))
            fields.put(ContactConstants.A_maidenName, vcfDecode(value));
        else if (name.startsWith("X-ZIMBRA-IMADDRESS"))
            addField("imAddress", true, vcfDecode(value), null, 1, fields);
        else if (name.equals("X-ZIMBRA-ANNIVERSARY"))
            addField(ContactConstants.A_anniversary, vcfDecode(value), null, 2, fields);
        else if (name.equals("UID"))
            uid = value;
    }
    return cards;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Attachment(com.zimbra.cs.mailbox.Contact.Attachment) VCardParamsAndValue(com.zimbra.cs.mailbox.VCardParamsAndValue)

Aggregations

VCardParamsAndValue (com.zimbra.cs.mailbox.VCardParamsAndValue)6 ServiceException (com.zimbra.common.service.ServiceException)3 Contact (com.zimbra.cs.mailbox.Contact)2 Attachment (com.zimbra.cs.mailbox.Contact.Attachment)2 ContactGroup (com.zimbra.cs.mailbox.ContactGroup)2 Member (com.zimbra.cs.mailbox.ContactGroup.Member)2 ItemId (com.zimbra.cs.service.util.ItemId)2 ArrayList (java.util.ArrayList)2 Test (org.junit.Test)2 IOException (java.io.IOException)1 StringWriter (java.io.StringWriter)1 SimpleDateFormat (java.text.SimpleDateFormat)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 ContentType (javax.mail.internet.ContentType)1 ParseException (javax.mail.internet.ParseException)1 FoldingWriter (net.fortuna.ical4j.data.FoldingWriter)1