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;
}
Aggregations