package net.sourceforge.cardme.engine; import net.sourceforge.cardme.io.CompatibilityMode; import net.sourceforge.cardme.util.Base64Wrapper; import net.sourceforge.cardme.util.ISOUtils; import net.sourceforge.cardme.util.VCardUtils; import net.sourceforge.cardme.vcard.*; import net.sourceforge.cardme.vcard.errors.ErrorSeverity; import net.sourceforge.cardme.vcard.errors.VCardBuildException; import net.sourceforge.cardme.vcard.errors.VCardError; import net.sourceforge.cardme.vcard.errors.VCardException; import net.sourceforge.cardme.vcard.features.AddressFeature; import net.sourceforge.cardme.vcard.types.*; import net.sourceforge.cardme.vcard.types.media.AudioMediaType; import net.sourceforge.cardme.vcard.types.media.ImageMediaType; import net.sourceforge.cardme.vcard.types.media.KeyTextType; import net.sourceforge.cardme.vcard.types.parameters.*; import org.apache.commons.codec.net.QuotedPrintableCodec; import java.io.*; import java.net.URI; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Calendar; import java.util.Iterator; import java.util.List; /* * Copyright 2011 George El-Haddad. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY GEORGE EL-HADDAD ''AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GEORGE EL-HADDAD OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of George El-Haddad. */ /** * * @author George El-Haddad * <br/> * May 6, 2009 - 11:29:02 AM * <p> * @author Michael Angstadt * <br/> * Jul 06, 2012 * */ public class VCardEngine { private final int BUFFER_SIZE = 8192; /** * <p>Selects from a list of application compatibility modes * to use when formatting the output of the vcard. Some applications * expect a certain type of formatting or non-standard types.</p> */ private CompatibilityMode compatMode = null; /** * <p>If set, this charset will override any charset definition * when decoding strings from any type that defines "CHARSET".</p> */ private Charset forceCharset = null; /** * <p>Create a VCard parsing engine and initialize it to * use RFC2426 compatibility mode by default.</p> */ public VCardEngine() { compatMode = CompatibilityMode.RFC2426; } /** * <p>Create a VCard parsing engine with a user * specified compatibility mode.</p> * * @param compatMode */ public VCardEngine(CompatibilityMode compatMode) { this.compatMode = compatMode; } /** * <p>Sets a specified compatibility mode.</p> * * @see CompatibilityMode * @param compatMode */ public void setCompatibilityMode(CompatibilityMode compatMode) { if(compatMode == null) { this.compatMode = CompatibilityMode.RFC2426; } else { this.compatMode = compatMode; } } /** * <p>Returns the currently set compatibility mode. * Null if not set.</p> * * @return {@link CompatibilityMode} */ public CompatibilityMode getCompatibilityMode() { return compatMode; } /** * <p>Sets the charset to always be used when the * "CHARSET" parameter is encountered.</p> * * @param charset */ public void setForcedCharset(String charset) { forceCharset = Charset.forName(charset); } /** * <p>Sets the charset to always be used when the * "CHARSET" parameter is encountered.</p> * * @param charset */ public void setForcedCharset(Charset charset) { forceCharset = charset; } /** * <p>Returns the charset that has been set * to be forced on all types, null if not set.</p> * * @return {@link Charset} */ public Charset getForcedCharset() { return forceCharset; } /** * <p>Returns true if the engine is enforcing a charset * on all types.</p> * * @return boolean */ public boolean isCharsetForced() { return forceCharset != null; } /** * <p>Convenient method to parse an array of VCard files in one go. * This returns an array of VCard objects in the same order they were * parsed.</p> * * @param vcardFiles * @return {@link VCard}[] * @throws IOException */ public VCard[] parse(File[] vcardFiles) throws IOException { VCard[] vcards = new VCard[vcardFiles.length]; for (int i = 0; i < vcardFiles.length; i++) { vcards[i] = parse(vcardFiles[i]); } return vcards; } /** * <p>Parses the specified VCard file by retrieving the contents * of the file, unfolding it and then parsing it. The returned result * is a VCard java object.</p> * * @param vcardFile * @return {@link VCard} * @throws IOException */ public VCard parse(File vcardFile) throws IOException { String vcardStr = getContentFromFile(vcardFile); String unfoldedVcardStr = VCardUtils.unfoldVCard(vcardStr); return parseVCard(unfoldedVcardStr); } /** * <p>Convenient method to parse an array of VCard strings in one go. * This returns an array of VCard objects in the same order they were * parsed.</p> * * @param vcardStrings * @return {@link VCard}[] * @throws IOException */ public VCard[] parse(String[] vcardStrings) throws IOException { VCard[] vcards = new VCard[vcardStrings.length]; for (int i = 0; i < vcards.length; i++) { vcards[i] = parse(vcardStrings[i]); } return vcards; } /** * <p>Parses the specified VCard String by retrieving the contents * of the file, unfolding it and then parsing it. The returned result * is a VCard java object.</p> * * @param vcardString * @return {@link VCard} * @throws IOException */ public VCard parse(String vcardString) throws IOException { String vcardStr = getContentFromString(vcardString); String unfoldedVcardStr = VCardUtils.unfoldVCard(vcardStr); return parseVCard(unfoldedVcardStr); } /** * <p>Returns an iterator of VCards given a path that can * contain an arbitrary number of vcards inside it.</p> * * @param vcardPath * @return {@link List}<VCard> * @throws IOException */ public List<VCard> parseMultiple(String vcardPath) throws IOException { return parseMultiple(new File(vcardPath)); } /** * <p>Returns an iterator of VCards given a file that can * contain an arbitrary number of vcards inside it.</p> * * @param vcardFile * @return {@link List}<VCard> * @throws IOException */ public List<VCard> parseMultiple(File vcardFile) throws IOException { String vcardStr = getContentFromFile(vcardFile); String unfoldedVcardStr = VCardUtils.unfoldVCard(vcardStr); return parseManyInOneVCard(unfoldedVcardStr); } /** * <p>Parses the specified VCard String and returns a VCard java object. * Should errors occur during the parsing of the VCard they will be handled * within the VCard error handling interface. These errors can be retrieved * via the <code>{@link VCardImpl}.getErrors()</code> method.<br/> * * This method assumes the following: * <ol> * <li>The String has only \n end of line markers instead of \r\n</li> * <li>All lines in the String are unfolded</li> * </ol> * </p> * * @param vcardStr * @return {@link VCard} */ private VCard parseVCard(String vcardStr) { VCardImpl vcard = new VCardImpl(); vcard.setThrowExceptions(false); String[] lines = vcardStr.split("\n"); for (int i = 0; i < lines.length; i++) { String vLine = lines[i]; VCardLine parsedLine = VCardLine.parse(vLine); if(parsedLine != null) { try { parseLine(parsedLine, vcard); } catch(VCardBuildException vbe) { if(vcard.isThrowExceptions()) { throw new VCardException(vbe.getMessage(), vbe); } else { handleError(vcard, vbe.getMessage(), vbe, ErrorSeverity.WARNING); } } } else { if(vcard.isThrowExceptions()) { throw new VCardException("Invalid data in VCard on line "+i); } else { handleError(vcard, "Invalid data in VCard on line "+i, null, ErrorSeverity.FATAL); } } } return vcard; } private List<VCard> parseManyInOneVCard(String vcardStr) { List<VCard> vcards = new ArrayList<VCard>(); List<String> enumCards = enumerateVCards(vcardStr); for (String card : enumCards) { VCard vcard = parseVCard(card); vcards.add(vcard); } return vcards; } private List<String> enumerateVCards(String vcardString) { List<String> vcardStrings = new ArrayList<String>(); StringBuilder sb = new StringBuilder(); String[] split = vcardString.split("\r?\n"); boolean begin = false; boolean end = false; for (String s : split) { if(s.matches("\\p{Blank}*((BEGIN)|(begin))\\p{Blank}*:\\p{Blank}*((VCARD)|(vcard))\\p{Blank}*")) { begin = true; } if(s.matches("\\p{Blank}*((END)|(end))\\p{Blank}*:\\p{Blank}*((VCARD)|(vcard))\\p{Blank}*")) { end = true; } if(begin && !end) { sb.append(s); sb.append('\n'); } if(end) { sb.append(s); sb.append('\n'); begin = false; end = false; vcardStrings.add(sb.toString()); sb = new StringBuilder(); } } return vcardStrings; } /** * <p>Parses a specific line of text from the VCard. This line is partitioned into * the following segments. * <ul> * <li><b>group</b> Optional grouping name for the type.</li> * <li><b>type</b> The vcard type that identifies this line.</li> * <li><b>paramTypes</b> Any parameters that follow the type.</li> * <li><b>value</b> The actual value or data of the type.</li> * <li><b>vcard</b> The vcard object to append the type to once parsed.</li> * </ul> * </p> * * @param parsedLine * @param vcard * @throws VCardBuildException */ private void parseLine(VCardLine parsedLine, VCardImpl vcard) throws VCardBuildException { String type = parsedLine.getTypeName().trim().toUpperCase(); String value = parsedLine.getValue().trim(); List<ParameterType> paramTypes = parseParamTypes(parsedLine.getParameters()); String group = parsedLine.getGroup(); VCardType vCardType = null; //Extended Types are a bit special since they only start with X- and end with anything. if(type.startsWith("X-")) { vCardType = VCardType.XTENDED; } else { try { //Enums do not like hyphens so replace it with an underscore. type = type.replaceAll("-", "_"); vCardType = VCardType.valueOf(type); } catch(IllegalArgumentException iae) { if(vcard.isThrowExceptions()) { throw new VCardException(iae.getMessage(), iae); } else { handleError(vcard, "Unrecognizable type name \""+type+"\"", iae, ErrorSeverity.WARNING); return; } } } switch (vCardType) { case BEGIN: { parseBeginType(group, value, vcard); break; } case END: { parseEndType(group, value, vcard); break; } case VERSION: { parseVersionType(group, value, vcard); break; } case FN: { parseFnType(group, value, paramTypes, vcard); break; } case N: { parseNType(group, value, paramTypes, vcard); break; } case NICKNAME: { parseNicknameType(group, value, paramTypes, vcard); break; } case PHOTO: { parsePhotoType(group, value, paramTypes, vcard); break; } case BDAY: { parseBDayType(group, value, paramTypes, vcard); break; } case ADR: { parseAdrType(group, value, paramTypes, vcard); break; } case LABEL: { parseLabelType(group, value, paramTypes, vcard); break; } case TEL: { parseTelType(group, value, paramTypes, vcard); break; } case EMAIL: { parseEmailType(group, value, paramTypes, vcard); break; } case MAILER: { parseMailerType(group, value, paramTypes, vcard); break; } case TZ: { parseTzType(group, value, paramTypes, vcard); break; } case GEO: { parseGeoType(group, value, paramTypes, vcard); break; } case TITLE: { parseTitleType(group, value, paramTypes, vcard); break; } case ROLE: { parseRoleType(group, value, paramTypes, vcard); break; } case LOGO: { parseLogoType(group, value, paramTypes, vcard); break; } case AGENT: { //TODO parseAgentType(group, value, vcard); break; } case ORG: { parseOrgType(group, value, paramTypes, vcard); break; } case CATEGORIES: { parseCategoriesType(group, value, paramTypes, vcard); break; } case NOTE: { parseNoteType(group, value, paramTypes, vcard); break; } case PRODID: { parseProdidType(group, value, paramTypes, vcard); break; } case REV: { parseRevType(group, value, paramTypes, vcard); break; } case SORT_STRING: { parseSortStringType(group, value, paramTypes, vcard); break; } case SOUND: { parseSoundType(group, value, paramTypes, vcard); break; } case UID: { parseUidType(group, value, paramTypes, vcard); break; } case URL: { parseUrlType(group, value, paramTypes, vcard); break; } case CLASS: { parseClassType(group, value, paramTypes, vcard); break; } case KEY: { parseKeyType(group, value, paramTypes, vcard); break; } case XTENDED: { parseXtendedType(group, value, type, paramTypes, vcard); break; } case NAME: { parseDisplayableNameType(group, value, paramTypes, vcard); break; } case PROFILE: { parseProfileType(group, value, paramTypes, vcard); break; } case SOURCE: { parseSourceType(group, value, paramTypes, vcard); break; } case IMPP: { parseImppType(group, value, paramTypes, vcard); break; } default: { throw new VCardBuildException("Unhandled VCard type \""+vCardType.getType()+"\""); } } } /** * <p>Parses the BEGIN type.</p> * * @param group * @param value * @param vcard * @throws VCardBuildException */ private void parseBeginType(String group, String value, VCardImpl vcard) throws VCardBuildException { try { BeginType beginFeature = new BeginType(); if(value.compareToIgnoreCase("VCARD") == 0) { if(group != null) { beginFeature.setGroup(group); } vcard.setBegin(beginFeature); } else { throw new VCardBuildException("Invalid value for \"BEGIN\" type. Must be \"VCARD\""); } } catch(Exception ex) { throw new VCardBuildException("BeginType ("+VCardType.BEGIN.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the END type.</p> * * @param group * @param value * @param vcard * @throws VCardBuildException */ private void parseEndType(String group, String value, VCardImpl vcard) throws VCardBuildException { try { EndType endFeature = new EndType(); if (value.compareToIgnoreCase("VCARD") == 0) { if(group != null) { endFeature.setGroup(group); } vcard.setEnd(endFeature); } else { throw new VCardException("Invalid value for \"END\" type. Must be \"VCARD\""); } } catch(Exception ex) { throw new VCardBuildException("EndType ("+VCardType.END.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the VERSION type.</p> * * @param group * @param value * @param vcard * @throws VCardBuildException */ private void parseVersionType(String group, String value, VCardImpl vcard) throws VCardBuildException { try { VersionType versionFeature = new VersionType(); if(value.compareTo(VCardVersion.V3_0.getVersion()) == 0) { versionFeature.setVersion(VCardVersion.V3_0); } else if(value.compareTo(VCardVersion.V2_1.getVersion()) == 0) { versionFeature.setVersion(VCardVersion.V2_1); } else { throw new VCardException("Invalid value for \"VERSION\" type. Must be [3.0, 2.1]"); } if(group != null) { versionFeature.setGroup(group); } vcard.setVersion(versionFeature); } catch(Exception ex) { throw new VCardBuildException("VersionType ("+VCardType.VERSION.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the FN type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseFnType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { FormattedNameType formattedNameFeature = new FormattedNameType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { formattedNameFeature.setCharset(pt.getValue()); value = new String(value.getBytes(), formattedNameFeature.getCharset().name()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { formattedNameFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { formattedNameFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); formattedNameFeature.addExtendedParameter(parameter); } } if(formattedNameFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(formattedNameFeature.hasCharset()) { value = q.decode(value, formattedNameFeature.getCharset().name()); } else { value = q.decode(value); } } } formattedNameFeature.setFormattedName(VCardUtils.unescapeString(value)); if(group != null) { formattedNameFeature.setGroup(group); } vcard.setFormattedName(formattedNameFeature); } catch(Exception ex) { throw new VCardBuildException("FormattedNameType ("+VCardType.FN.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the N type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseNType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { NameType nameFeature = new NameType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { nameFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { nameFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { nameFeature.setLanguage(pt.getValue()); } else { throw new VCardBuildException("Invalid parameter type: "+pt); } } if(nameFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(nameFeature.hasCharset()) { value = q.decode(value, nameFeature.getCharset().name()); } else { value = q.decode(value); } } } switch(compatMode) { case MS_OUTLOOK: { parseNTypeOutlook(nameFeature, value); break; } default: { parseNTypeRFC(nameFeature, value); break; } } if(group != null) { nameFeature.setGroup(group); } vcard.setName(nameFeature); } catch(Exception ex) { throw new VCardBuildException("NameType ("+VCardType.N.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } private NameType parseNTypeOutlook(NameType nameFeature, String value) { String[] names = VCardUtils.parseStringWithEscappedDelimiter(value, ';'); for(int i=0; i < names.length; i++) { switch(i) { case 0: { nameFeature.setFamilyName(VCardUtils.unescapeString(names[0])); break; } case 1: { nameFeature.setGivenName(VCardUtils.unescapeString(names[1])); break; } case 2: { String[] addNames = VCardUtils.parseStringWithEscappedDelimiter(names[2], ','); for(int j = 0; j < addNames.length; j++) { nameFeature.addAdditionalName(VCardUtils.unescapeString(addNames[j])); } break; } case 3: { String[] prefixes = VCardUtils.parseStringWithEscappedDelimiter(names[3], ','); for(int j = 0; j < prefixes.length; j++) { nameFeature.addHonorificPrefix(VCardUtils.unescapeString(prefixes[j])); } break; } case 4: { String[] suffixes = VCardUtils.parseStringWithEscappedDelimiter(names[4], ','); for(int j = 0; j < suffixes.length; j++) { nameFeature.addHonorificSuffix(VCardUtils.unescapeString(suffixes[j])); } break; } } } return nameFeature; } private NameType parseNTypeRFC(NameType nameFeature, String value) { String[] names = VCardUtils.parseStringWithEscappedDelimiter(value, ';'); int cur = 0; if(names.length > cur && names[cur] != null) { if(VCardUtils.needsUnEscaping(names[cur])) { nameFeature.setFamilyName(VCardUtils.unescapeString(names[cur])); } else { nameFeature.setFamilyName(names[cur]); } } cur++; if(names.length > cur && names[cur] != null) { if(VCardUtils.needsUnEscaping(names[cur])) { nameFeature.setGivenName(VCardUtils.unescapeString(names[cur])); } else { nameFeature.setGivenName(names[cur]); } } cur++; if(names.length > cur && names[cur] != null) { String[] addNames = VCardUtils.parseStringWithEscappedDelimiter(names[cur], ','); for(int i = 0; i < addNames.length; i++) { if(VCardUtils.needsUnEscaping(addNames[i])) { nameFeature.addAdditionalName(VCardUtils.unescapeString(addNames[i])); } else { nameFeature.addAdditionalName(addNames[i]); } } } cur++; if(names.length > cur && names[cur] != null) { String[] prefixes = VCardUtils.parseStringWithEscappedDelimiter(names[cur], ','); for(int i = 0; i < prefixes.length; i++) { if(VCardUtils.needsUnEscaping(prefixes[i])) { nameFeature.addHonorificPrefix(VCardUtils.unescapeString(prefixes[i])); } else { nameFeature.addHonorificPrefix(prefixes[i]); } } } cur++; if(names.length > cur && names[cur] != null) { String[] suffixes = VCardUtils.parseStringWithEscappedDelimiter(names[cur], ','); for(int i = 0; i < suffixes.length; i++) { if(VCardUtils.needsUnEscaping(suffixes[i])) { nameFeature.addHonorificSuffix(VCardUtils.unescapeString(suffixes[i])); } else { nameFeature.addHonorificSuffix(suffixes[i]); } } } return nameFeature; } /** * <p>Parses the Nickname type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseNicknameType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { NicknameType nicknameFeature = new NicknameType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { nicknameFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { nicknameFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { nicknameFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); nicknameFeature.addExtendedParameter(parameter); } } if(nicknameFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(nicknameFeature.hasCharset()) { value = q.decode(value, nicknameFeature.getCharset().name()); } else { value = q.decode(value); } } } String[] nicknames = VCardUtils.parseStringWithEscappedDelimiter(value, ','); for(int i = 0; i < nicknames.length; i++) { if(VCardUtils.needsUnEscaping(nicknames[i])) { nicknameFeature.addNickname(VCardUtils.unescapeString(nicknames[i])); } else { nicknameFeature.addNickname(nicknames[i]); } } if(group != null) { nicknameFeature.setGroup(group); } vcard.setNicknames(nicknameFeature); } catch(Exception ex) { throw new VCardBuildException("NicknameType ("+VCardType.NICKNAME.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the PHOTO type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parsePhotoType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { PhotoType photoFeature = new PhotoType(); boolean isBinary = false; for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { photoFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().compareToIgnoreCase(EncodingType.BINARY.getType()) == 0) { photoFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else if(pt.getValue().compareToIgnoreCase(EncodingType.BASE64.getType()) == 0) { photoFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else { throw new VCardBuildException("PhotoType ("+VCardType.PHOTO.getType()+") Invalid encoding type \""+pt.getValue()+"\""); } } else if(pt.getName().equals("TYPE")) { ImageMediaType mediaType = ImageMediaType.valueOf(pt.getValue()); if (mediaType == null){ mediaType = new ImageMediaType(pt.getValue(), pt.getValue(), pt.getValue()); } photoFeature.setImageMediaType(mediaType); } else if(pt.getName().equals("VALUE")) { if(pt.getValue().compareToIgnoreCase("URI") == 0) { photoFeature.setEncodingType(EncodingType.EIGHT_BIT); isBinary = false; } else { throw new VCardBuildException("PhotoType ("+VCardType.PHOTO.getType()+") Invalid value type \""+pt.getValue()+"\""); } } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); photoFeature.addExtendedParameter(parameter); } } if(isBinary) { byte[] photoBytes = Base64Wrapper.decode(value); photoFeature.setCompression(false); photoFeature.setPhoto(photoBytes); } else { URI photoUri = new URI(value); photoFeature.setPhotoURI(photoUri); } if(group != null) { photoFeature.setGroup(group); } vcard.addPhoto(photoFeature); } catch(Exception ex) { throw new VCardBuildException("PhotoType ("+VCardType.PHOTO.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the BDAY type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseBDayType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { BirthdayType birthdayFeature = new BirthdayType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { birthdayFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("VALUE")) { if(pt.getValue().equals("DATE")) { birthdayFeature.setBirthdayParameterType(BirthdayParameterType.DATE); } else if(pt.getValue().equals("DATE-TIME")) { birthdayFeature.setBirthdayParameterType(BirthdayParameterType.DATE_TIME); } else { throw new VCardBuildException("Invalid parameter type: "+pt); } } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); birthdayFeature.addExtendedParameter(parameter); } } Calendar cal = ISOUtils.parseISO8601Date(value); birthdayFeature.setBirthday(cal); if(group != null) { birthdayFeature.setGroup(group); } vcard.setBirthday(birthdayFeature); } catch(Exception ex) { throw new VCardBuildException("BirthdayType ("+VCardType.BDAY.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the ADR type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseAdrType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { AddressType addressFeature = new AddressType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { addressFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { addressFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("TYPE")) { if(pt.getValue().indexOf(',') != -1) { String[] typeValueList = pt.getValue().split(","); for(String typeValue : typeValueList) { setAdrParameterType(addressFeature, typeValue); } } else { setAdrParameterType(addressFeature, pt.getValue()); } } else if(pt.getName().equals("LANGUAGE")) { addressFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); addressFeature.addExtendedParameter(parameter); } } if(addressFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(addressFeature.hasCharset()) { value = q.decode(value, addressFeature.getCharset().name()); } else { value = q.decode(value); } } } String[] address = VCardUtils.parseStringWithEscappedDelimiter(value, ';'); int i = 0; String postOfficeBox = (address.length > i) ? address[i] : null; i++; String extendedAddress = (address.length > i) ? address[i] : null; i++; String streetAddress = (address.length > i) ? address[i] : null; i++; String locality = (address.length > i) ? address[i] : null; i++; String region = (address.length > i) ? address[i] : null; i++; String postalCode = (address.length > i) ? address[i] : null; i++; String countryName = (address.length > i) ? address[i] : null; if(postOfficeBox != null) { if(VCardUtils.needsUnEscaping(postOfficeBox)) { addressFeature.setPostOfficeBox(VCardUtils.unescapeString(postOfficeBox)); } else { addressFeature.setPostOfficeBox(postOfficeBox); } } if(extendedAddress != null) { if(VCardUtils.needsUnEscaping(extendedAddress)) { addressFeature.setExtendedAddress(VCardUtils.unescapeString(extendedAddress)); } else { addressFeature.setExtendedAddress(extendedAddress); } } if(streetAddress != null) { if(VCardUtils.needsUnEscaping(streetAddress)) { addressFeature.setStreetAddress(VCardUtils.unescapeString(streetAddress)); } else { addressFeature.setStreetAddress(streetAddress); } } if(locality != null) { if(VCardUtils.needsUnEscaping(locality)) { addressFeature.setLocality(VCardUtils.unescapeString(locality)); } else { addressFeature.setLocality(locality); } } if(region != null) { if(VCardUtils.needsUnEscaping(region)) { addressFeature.setRegion(VCardUtils.unescapeString(region)); } else { addressFeature.setRegion(region); } } if(postalCode != null) { if(VCardUtils.needsUnEscaping(postalCode)) { addressFeature.setPostalCode(VCardUtils.unescapeString(postalCode)); } else { addressFeature.setPostalCode(postalCode); } } if(countryName != null) { if(VCardUtils.needsUnEscaping(countryName)) { addressFeature.setCountryName(VCardUtils.unescapeString(countryName)); } else { addressFeature.setCountryName(countryName); } } if(group != null) { addressFeature.setGroup(group); } vcard.addAddress(addressFeature); } catch(Exception ex) { throw new VCardBuildException("AddressType ("+VCardType.ADR.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Helper method for the above.</p> * * @param adrType * @param paramValue */ private void setAdrParameterType(AddressType adrType, String paramValue) { try { String enumParamValue = paramValue.replace("-", "_").toUpperCase(); AddressParameterType adrParamType = AddressParameterType.valueOf(enumParamValue); adrType.addAddressParameterType(adrParamType); } catch(IllegalArgumentException iae) { XAddressParameterType xAdrType = null; if(paramValue.indexOf('=') != -1) { String[] pTmp = paramValue.split("="); xAdrType = new XAddressParameterType(pTmp[0], pTmp[1]); } else { xAdrType = new XAddressParameterType(paramValue); } adrType.addExtendedAddressParameterType(xAdrType); } } /** * <p>Parses the LABEL type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseLabelType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { LabelType labelFeature = new LabelType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { labelFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { labelFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("TYPE")) { if(pt.getValue().indexOf(',') != -1) { String[] typeValueList = pt.getValue().split(","); for(String typeValue : typeValueList) { setLabelParameterType(labelFeature, typeValue); } } else { setLabelParameterType(labelFeature, pt.getValue()); } } else if(pt.getName().equals("LANGUAGE")) { labelFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); labelFeature.addExtendedParameter(parameter); } } if(labelFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(labelFeature.hasCharset()) { value = q.decode(value, labelFeature.getCharset().name()); } else { value = q.decode(value); } } } labelFeature.setLabel(VCardUtils.unescapeString(value)); if(group != null) { labelFeature.setGroup(group); } boolean match = false; Iterator<AddressFeature> addrIter = vcard.getAddresses(); while(addrIter.hasNext() && !match) { //Get address and all its parameter and extended parameter types AddressFeature addr = addrIter.next(); List<AddressParameterType> aPrmList = addr.getAddressParameterTypesList(); List<XAddressParameterType> aXPrmList = addr.getExtendedAddressParameterTypesList(); Iterator<LabelParameterType> lPrmIter = labelFeature.getLabelParameterTypes(); Iterator<XLabelParameterType> lXPrmIter = labelFeature.getExtendedLabelParameterTypes(); //See how many address parameter types match each label parameter type int paramsMatched = 0; while(lPrmIter.hasNext()) { LabelParameterType labelParamType = lPrmIter.next(); for(AddressParameterType aPrm : aPrmList) { if(aPrm.getType().equals(labelParamType.getType())) { paramsMatched++; } } } //See how many extended address parameter types match each extended label parameter type int xparamsMatched = 0; while(lXPrmIter.hasNext()) { XLabelParameterType xlabelParamType = lXPrmIter.next(); for(XAddressParameterType aXPrm : aXPrmList) { if(aXPrm.getType().equals(xlabelParamType.getType())) { xparamsMatched++; } } } //If the number of matching parameter types match between the label //and the address then this label belongs to the respective address. if(paramsMatched == labelFeature.getLabelParameterSize() && xparamsMatched == labelFeature.getExtendedLabelParameterSize()) { //Only set the label on the address if it does not already have one if(!vcard.hasLabel(addr)) { vcard.setLabel(labelFeature, addr); } else { vcard.addError("Label with duplicate parameter tpyes was detected and ignored. Label -> "+labelFeature.toString(), ErrorSeverity.WARNING, new VCardBuildException("Duplicate label")); } match = true; } } } catch(Exception ex) { throw new VCardBuildException("LabelType ("+VCardType.LABEL.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Helper method for the above.</p> * * @param labelType * @param paramValue */ private void setLabelParameterType(LabelType labelType, String paramValue) { try { String enumParamValue = paramValue.replace("-", "_").toUpperCase(); LabelParameterType adrParamType = LabelParameterType.valueOf(enumParamValue); labelType.addLabelParameterType(adrParamType); } catch(IllegalArgumentException iae) { XLabelParameterType xLabelType = null; if(paramValue.indexOf('=') != -1) { String[] pTmp = paramValue.split("="); xLabelType = new XLabelParameterType(pTmp[0], pTmp[1]); } else { xLabelType = new XLabelParameterType(paramValue); } labelType.addExtendedLabelParameterType(xLabelType); } } /** * <p>Parses the TEL type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseTelType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { TelephoneType telephoneFeature = new TelephoneType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { telephoneFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { telephoneFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("TYPE")) { if(pt.getValue().indexOf(',') != -1) { String[] typeValueList = pt.getValue().split(","); for(String typeValue : typeValueList) { setTelParameterType(telephoneFeature, typeValue); } } else { setTelParameterType(telephoneFeature, pt.getValue()); } } else if(pt.getName().equals("LANGUAGE")) { telephoneFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); telephoneFeature.addExtendedParameter(parameter); } } if(telephoneFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(telephoneFeature.hasCharset()) { value = q.decode(value, telephoneFeature.getCharset().name()); } else { value = q.decode(value); } } } telephoneFeature.setTelephone(VCardUtils.unescapeString(value)); if(group != null) { telephoneFeature.setGroup(group); } vcard.addTelephoneNumber(telephoneFeature); } catch(Exception ex) { throw new VCardBuildException("TelephoneType ("+VCardType.TEL.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Helper method for the above.</p> * * @param telType * @param paramValue */ private void setTelParameterType(TelephoneType telType, String paramValue) { try { String enumParamValue = paramValue.replace("-", "_").toUpperCase(); TelephoneParameterType telParamType = TelephoneParameterType.valueOf(enumParamValue); telType.addTelephoneParameterType(telParamType); } catch(IllegalArgumentException iae) { XTelephoneParameterType xTelType = null; if(paramValue.indexOf('=') != -1) { String[] pTmp = paramValue.split("="); xTelType = new XTelephoneParameterType(pTmp[0], pTmp[1]); } else { xTelType = new XTelephoneParameterType(paramValue); } telType.addExtendedTelephoneParameterType(xTelType); } } /** * <p>Parses the EMAIL type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseEmailType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { EmailType emailFeature = new EmailType(); boolean isBinary = false; for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { emailFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("TYPE")) { if(pt.getValue().indexOf(',') != -1) { String[] typeValueList = pt.getValue().split(","); for(String typeValue : typeValueList) { setEmailParameterType(emailFeature, typeValue); } } else { setEmailParameterType(emailFeature, pt.getValue()); } } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().compareToIgnoreCase(EncodingType.BINARY.getType()) == 0) { emailFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else if(pt.getValue().compareToIgnoreCase(EncodingType.BASE64.getType()) == 0) { emailFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { emailFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } else { throw new VCardBuildException("EmailType ("+VCardType.EMAIL.getType()+") Invalid encoding type \""+pt.getValue()+"\""); } } else if(pt.getName().equals("LANGUAGE")) { emailFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); emailFeature.addExtendedParameter(parameter); } } if(isBinary) { byte[] emailBytes = Base64Wrapper.decode(value); emailFeature.setCompression(false); if(emailFeature.hasCharset()) { emailFeature.setEmail(new String(emailBytes, emailFeature.getCharset().name())); } else { emailFeature.setEmail(new String(emailBytes, Charset.defaultCharset().name())); } } else { if(emailFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); value = q.decode(value); } emailFeature.setEmail(value); } if(group != null) { emailFeature.setGroup(group); } vcard.addEmail(emailFeature); } catch(Exception ex) { throw new VCardBuildException("EmailType ("+VCardType.EMAIL.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Helper method for the above.</p> * * @param emailType * @param paramValue */ private void setEmailParameterType(EmailType emailType, String paramValue) { try { String enumParamValue = paramValue.replace("-", "_").toUpperCase(); EmailParameterType emailParamType = EmailParameterType.valueOf(enumParamValue); emailType.addEmailParameterType(emailParamType); } catch(IllegalArgumentException iae) { XEmailParameterType xEmailType = null; if(paramValue.indexOf('=') != -1) { String[] pTmp = paramValue.split("="); xEmailType = new XEmailParameterType(pTmp[0], pTmp[1]); } else { xEmailType = new XEmailParameterType(paramValue); } emailType.addExtendedEmailParameterType(xEmailType); } } /** * <p>Parses the MAILER type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseMailerType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { MailerType mailerFeature = new MailerType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { mailerFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { mailerFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { mailerFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); mailerFeature.addExtendedParameter(parameter); } } if(mailerFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(mailerFeature.hasCharset()) { value = q.decode(value, mailerFeature.getCharset().name()); } else { value = q.decode(value); } } } mailerFeature.setMailer(VCardUtils.unescapeString(value)); if(group != null) { mailerFeature.setGroup(group); } vcard.setMailer(mailerFeature); } catch(Exception ex) { throw new VCardBuildException("MailerType ("+VCardType.MAILER.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the TZ type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseTzType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { TimeZoneType timeZoneFeature = new TimeZoneType(); //VALUE=TEXT //-05:00; EST; Raleigh/North America String paramValue = null; for (ParameterType pt : paramTypeList){ if (pt.getName().equalsIgnoreCase("VALUE")){ paramValue = pt.getValue(); } } if("TEXT".equalsIgnoreCase(paramValue)) { String split[] = VCardUtils.parseStringWithEscappedDelimiter(value, ';'); int cur = 0; if (split.length > cur && split[cur].length() > 0){ timeZoneFeature.parseTimeZoneOffset(VCardUtils.unescapeString(split[cur])); } cur++; if (split.length > cur && split[cur].length() > 0){ timeZoneFeature.setShortText(VCardUtils.unescapeString(split[cur])); } cur++; if (split.length > cur && split[cur].length() > 0){ timeZoneFeature.setLongText(VCardUtils.unescapeString(split[cur])); } } else { timeZoneFeature.parseTimeZoneOffset(value); } if(group != null) { timeZoneFeature.setGroup(group); } vcard.setTimeZone(timeZoneFeature); } catch(Exception ex) { throw new VCardBuildException("TimeZoneType ("+VCardType.TZ.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the GEO type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseGeoType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { GeographicPositionType geographicPositionFeature = new GeographicPositionType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { geographicPositionFeature.setCharset(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); geographicPositionFeature.addExtendedParameter(parameter); } } if(value.matches("-?\\d{1,3}\\.\\d{1,6}\\;-?\\d{1,3}\\.\\d{1,6}")) { String[] geo = value.split(";"); String lat = geo[0]; String lon = geo[1]; geographicPositionFeature.setLatitude(Float.parseFloat(lat)); geographicPositionFeature.setLongitude(Float.parseFloat(lon)); if(group != null) { geographicPositionFeature.setGroup(group); } vcard.setGeographicPosition(geographicPositionFeature); } else { throw new VCardBuildException("GeographicPositionType ("+VCardType.GEO.getType()+") GeographicPositionType is not valid."); } } catch(Exception ex) { throw new VCardBuildException("GeographicPositionType ("+VCardType.GEO.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the TITLE type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseTitleType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { TitleType titleFeature = new TitleType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { titleFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { titleFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { titleFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); titleFeature.addExtendedParameter(parameter); } } if(titleFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(titleFeature.hasCharset()) { value = q.decode(value, titleFeature.getCharset().name()); } else { value = q.decode(value); } } } titleFeature.setTitle(VCardUtils.unescapeString(value)); if(group != null) { titleFeature.setGroup(group); } vcard.setTitle(titleFeature); } catch(Exception ex) { throw new VCardBuildException("TitleType ("+VCardType.TITLE.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the ROLE type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseRoleType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { RoleType roleFeature = new RoleType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { roleFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { roleFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { roleFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); roleFeature.addExtendedParameter(parameter); } } if(roleFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(roleFeature.hasCharset()) { value = q.decode(value, roleFeature.getCharset().name()); } else { value = q.decode(value); } } } roleFeature.setRole(VCardUtils.unescapeString(value)); if(group != null) { roleFeature.setGroup(group); } vcard.setRole(roleFeature); } catch(Exception ex) { throw new VCardBuildException("RoleType ("+VCardType.ROLE.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the LOGO type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseLogoType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { LogoType logoFeature = new LogoType(); boolean isBinary = false; for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { logoFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().compareToIgnoreCase(EncodingType.BINARY.getType()) == 0) { logoFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else if(pt.getValue().compareToIgnoreCase(EncodingType.BASE64.getType()) == 0) { logoFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else { throw new VCardBuildException("LogoType ("+VCardType.LOGO.getType()+") Invalid encoding type \""+pt.getValue()+"\""); } } else if(pt.getName().equals("TYPE")) { ImageMediaType mediaType = ImageMediaType.valueOf(pt.getValue()); if (mediaType == null){ mediaType = new ImageMediaType(pt.getValue(), pt.getValue(), pt.getValue()); } logoFeature.setImageMediaType(mediaType); } else if(pt.getName().equals("VALUE")) { if(pt.getValue().compareToIgnoreCase("URI") == 0) { logoFeature.setEncodingType(EncodingType.EIGHT_BIT); isBinary = false; } else { throw new VCardBuildException("LogoType ("+VCardType.LOGO.getType()+") Invalid value type \""+pt.getValue()+"\""); } } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); logoFeature.addExtendedParameter(parameter); } } if(isBinary) { byte[] logoBytes = Base64Wrapper.decode(value); logoFeature.setCompression(false); logoFeature.setLogo(logoBytes); } else { URI logoUri = new URI(value); logoFeature.setLogoURI(logoUri); } if(group != null) { logoFeature.setGroup(group); } vcard.addLogo(logoFeature); } catch(Exception ex) { throw new VCardBuildException("LogoType ("+VCardType.LOGO.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the ORG type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseOrgType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { OrganizationType organizationFeature = new OrganizationType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { organizationFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { organizationFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { organizationFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); organizationFeature.addExtendedParameter(parameter); } } if(organizationFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(organizationFeature.hasCharset()) { value = q.decode(value, organizationFeature.getCharset().name()); } else { value = q.decode(value); } } } String[] orgs = VCardUtils.parseStringWithEscappedDelimiter(value, ';'); for(int i = 0; i < orgs.length; i++) { if(VCardUtils.needsUnEscaping(orgs[i])) { String unesc = VCardUtils.unescapeString(orgs[i]); organizationFeature.addOrganization(unesc); } else { organizationFeature.addOrganization(orgs[i]); } } if(group != null) { organizationFeature.setGroup(group); } vcard.setOrganizations(organizationFeature); } catch(Exception ex) { throw new VCardBuildException("OrganizationType ("+VCardType.ORG.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the CATEGORIES type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseCategoriesType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { CategoriesType categoriesFeature = new CategoriesType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { categoriesFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { categoriesFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { categoriesFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); categoriesFeature.addExtendedParameter(parameter); } } if(categoriesFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(categoriesFeature.hasCharset()) { value = q.decode(value, categoriesFeature.getCharset().name()); } else { value = q.decode(value); } } } String[] categories = null; switch(compatMode) { case KDE_ADDRESS_BOOK: { categories = VCardUtils.unescapeString(value).split(","); break; } default: { categories = VCardUtils.parseStringWithEscappedDelimiter(value, ','); break; } } for(int i = 0; i < categories.length; i++) { categoriesFeature.addCategory(VCardUtils.unescapeString(categories[i])); } if(group != null) { categoriesFeature.setGroup(group); } vcard.setCategories(categoriesFeature); } catch(Exception ex) { throw new VCardBuildException("CategoriesType ("+VCardType.CATEGORIES.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the NOTE type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseNoteType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { NoteType noteFeature = new NoteType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { noteFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { noteFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { noteFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); noteFeature.addExtendedParameter(parameter); } } if(noteFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(noteFeature.hasCharset()) { value = q.decode(value, noteFeature.getCharset().name()); } else { value = q.decode(value); } } } noteFeature.setNote(VCardUtils.unescapeString(value)); if(group != null) { noteFeature.setGroup(group); } vcard.addNote(noteFeature); } catch(Exception ex) { throw new VCardBuildException("NoteType ("+VCardType.NOTE.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the PRODID type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseProdidType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { ProductIdType productIdFeature = new ProductIdType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { productIdFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { productIdFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { productIdFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); productIdFeature.addExtendedParameter(parameter); } } if(productIdFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(productIdFeature.hasCharset()) { value = q.decode(value, productIdFeature.getCharset().name()); } else { value = q.decode(value); } } } productIdFeature.setProductId(VCardUtils.unescapeString(value)); if(group != null) { productIdFeature.setGroup(group); } vcard.setProductId(productIdFeature); } catch(Exception ex) { throw new VCardBuildException("ProductIdType ("+VCardType.PRODID.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the REV type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseRevType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { RevisionType revisionFeature = new RevisionType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { revisionFeature.setCharset(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); revisionFeature.addExtendedParameter(parameter); } } Calendar cal = ISOUtils.parseISO8601Date(value); revisionFeature.setRevision(cal); if(group != null) { revisionFeature.setGroup(group); } vcard.setRevision(revisionFeature); } catch(Exception ex) { throw new VCardBuildException("RevisionType ("+VCardType.REV.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the SORT-STRING type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseSortStringType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { SortStringType sortStringFeature = new SortStringType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { sortStringFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { sortStringFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { sortStringFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); sortStringFeature.addExtendedParameter(parameter); } } if(sortStringFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(sortStringFeature.hasCharset()) { value = q.decode(value, sortStringFeature.getCharset().name()); } else { value = q.decode(value); } } } sortStringFeature.setSortString(VCardUtils.unescapeString(value)); if(group != null) { sortStringFeature.setGroup(group); } vcard.setSortString(sortStringFeature); } catch(Exception ex) { throw new VCardBuildException("SortStringType ("+VCardType.SORT_STRING.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the SOUND type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseSoundType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { SoundType soundFeature = new SoundType(); boolean isBinary = false; for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { soundFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().compareToIgnoreCase(EncodingType.BINARY.getType()) == 0) { soundFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else if(pt.getValue().compareToIgnoreCase(EncodingType.BASE64.getType()) == 0) { soundFeature.setEncodingType(EncodingType.BINARY); isBinary = true; } else { throw new VCardBuildException("SoundType ("+VCardType.SOUND.getType()+") Invalid encoding type \""+pt.getValue()+"\""); } } else if(pt.getName().equals("TYPE")) { AudioMediaType mediaType = AudioMediaType.valueOf(pt.getValue()); if (mediaType == null){ mediaType = new AudioMediaType(pt.getValue(), pt.getValue(), pt.getValue()); } soundFeature.setAudioMediaType(mediaType); } else if(pt.getName().equals("VALUE")) { if(pt.getValue().compareToIgnoreCase("URI") == 0) { soundFeature.setEncodingType(EncodingType.EIGHT_BIT); isBinary = false; } else { throw new VCardBuildException("SoundType ("+VCardType.SOUND.getType()+") Invalid value type \""+pt.getValue()+"\""); } } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); soundFeature.addExtendedParameter(parameter); } } if(isBinary) { byte[] soundBytes = Base64Wrapper.decode(value); soundFeature.setCompression(false); soundFeature.setSound(soundBytes); } else { URI soundUri = new URI(value); soundFeature.setSoundURI(soundUri); } if(group != null) { soundFeature.setGroup(group); } vcard.addSound(soundFeature); } catch(Exception ex) { throw new VCardBuildException("SoundType ("+VCardType.SOUND.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the UID type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseUidType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { UIDType uidFeature = new UIDType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { uidFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { uidFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { uidFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); uidFeature.addExtendedParameter(parameter); } } if(uidFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(uidFeature.hasCharset()) { value = q.decode(value, uidFeature.getCharset().name()); } else { value = q.decode(value); } } } uidFeature.setUID(VCardUtils.unescapeString(value)); if(group != null) { uidFeature.setGroup(group); } vcard.setUID(uidFeature); } catch(Exception ex) { throw new VCardBuildException("UIDType ("+VCardType.UID.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the URL type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseUrlType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { URLType urlFeature = new URLType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { urlFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { urlFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { urlFeature.setLanguage(pt.getValue()); } else { switch(compatMode) { case MS_OUTLOOK: case I_PHONE: case GMAIL: case MAC_ADDRESS_BOOK: case EVOLUTION: case IOS_EXPORTER: case KDE_ADDRESS_BOOK: case RFC2426: { if(pt.getName().equals("TYPE")) { if(pt.getValue().indexOf(',') != -1) { String[] typeValueList = pt.getValue().split(","); for(String typeValue : typeValueList) { setUrlParameterType(urlFeature, typeValue); } } else { setUrlParameterType(urlFeature, pt.getValue()); } } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); urlFeature.addExtendedParameter(parameter); } break; } default: { throw new VCardBuildException("Invalid parameter type: "+pt); } } } } if(urlFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(urlFeature.hasCharset()) { value = q.decode(value, urlFeature.getCharset().name()); } else { value = q.decode(value); } } } urlFeature.setRawURL(VCardUtils.unescapeString(value)); if(group != null) { urlFeature.setGroup(group); } vcard.addURL(urlFeature); } catch(Exception ex) { throw new VCardBuildException("URLType ("+VCardType.URL.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Helper method for the above.</p> * * @param urlType * @param paramValue */ private void setUrlParameterType(URLType urlType, String paramValue) { try { String enumParamValue = paramValue.replace("-", "_").toUpperCase(); URLParameterType urlParamType = URLParameterType.valueOf(enumParamValue); urlType.addURLParameterType(urlParamType); } catch(IllegalArgumentException iae) { XURLParameterType xUrlType = null; if(paramValue.indexOf('=') != -1) { String[] pTmp = paramValue.split("="); xUrlType = new XURLParameterType(pTmp[0], pTmp[1]); } else { xUrlType = new XURLParameterType(paramValue); } urlType.addExtendedURLParameterType(xUrlType); } } /** * <p>Parses the CLASS type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseClassType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { ClassType classFeature = new ClassType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { classFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { classFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { classFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); classFeature.addExtendedParameter(parameter); } } if(classFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(classFeature.hasCharset()) { value = q.decode(value, classFeature.getCharset().name()); } else { value = q.decode(value); } } } classFeature.setSecurityClass(VCardUtils.unescapeString(value)); if(group != null) { classFeature.setGroup(group); } vcard.setSecurityClass(classFeature); } catch(Exception ex) { throw new VCardBuildException("ClassType ("+VCardType.CLASS.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the KEY type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseKeyType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { KeyType keyFeature = new KeyType(); boolean quotedPrintable = false; boolean text = true; //assume that the key is encoded in text if there is no ENCODING parameter for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { keyFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().compareToIgnoreCase(EncodingType.BINARY.getType()) == 0) { keyFeature.setEncodingType(EncodingType.BINARY); text = false; } else if(pt.getValue().compareToIgnoreCase(EncodingType.BASE64.getType()) == 0) { keyFeature.setEncodingType(EncodingType.BINARY); text = false; } else if(pt.getValue().compareToIgnoreCase(EncodingType.QUOTED_PRINTABLE.getType()) == 0) { quotedPrintable = true; text = true; } else if(pt.getValue().compareToIgnoreCase(EncodingType.SEVEN_BIT.getType()) == 0 || pt.getValue().compareToIgnoreCase(EncodingType.EIGHT_BIT.getType()) == 0) { text = true; } else { throw new VCardBuildException("KeyType ("+VCardType.KEY.getType()+") Invalid encoding type \""+pt.getValue()+"\""); } } else if(pt.getName().equals("TYPE")) { KeyTextType keyTextType = KeyTextType.valueOf(pt.getValue()); if (keyTextType == null){ keyTextType = new KeyTextType(pt.getValue(), pt.getValue(), pt.getValue()); } keyFeature.setKeyTextType(keyTextType); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); keyFeature.addExtendedParameter(parameter); } } if (quotedPrintable){ QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(keyFeature.hasCharset()) { value = q.decode(value, keyFeature.getCharset().name()); } else { value = q.decode(value); } } } keyFeature.setCompression(false); if(text) { keyFeature.setKey(value); } else { byte[] keyBytes = Base64Wrapper.decode(value); keyFeature.setKey(keyBytes); } if(group != null) { keyFeature.setGroup(group); } vcard.addKey(keyFeature); } catch(Exception ex) { throw new VCardBuildException("KeyType ("+VCardType.KEY.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the EXTENDED type.</p> * * @param group * @param value * @param paramTypeList * @param typeName * @param vcard * @throws VCardBuildException */ private void parseXtendedType(String group, String value, String typeName, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { ExtendedType extendedFeature = new ExtendedType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { extendedFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { extendedFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { extendedFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); extendedFeature.addExtendedParameter(parameter); } } if(extendedFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(extendedFeature.hasCharset()) { value = q.decode(value, extendedFeature.getCharset().name()); } else { value = q.decode(value); } } } extendedFeature.setExtensionName(typeName); extendedFeature.setExtensionData(VCardUtils.unescapeString(value)); if(group != null) { extendedFeature.setGroup(group); } vcard.addExtendedType(extendedFeature); } catch(Exception ex) { throw new VCardBuildException("ExtendedType ("+VCardType.XTENDED.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the NAME type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseDisplayableNameType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { DisplayableNameType displayableNameFeature = new DisplayableNameType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { displayableNameFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { displayableNameFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { displayableNameFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); displayableNameFeature.addExtendedParameter(parameter); } } if(displayableNameFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(displayableNameFeature.hasCharset()) { value = q.decode(value, displayableNameFeature.getCharset().name()); } else { value = q.decode(value); } } } displayableNameFeature.setName(VCardUtils.unescapeString(value)); if(group != null) { displayableNameFeature.setGroup(group); } vcard.setDisplayableNameFeature(displayableNameFeature); } catch(Exception ex) { throw new VCardBuildException("DisplayableNameType ("+VCardType.NAME.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the PROFILE type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseProfileType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { ProfileType profileFeature = new ProfileType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { profileFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { profileFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { profileFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); profileFeature.addExtendedParameter(parameter); } } if(profileFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(profileFeature.hasCharset()) { value = q.decode(value, profileFeature.getCharset().name()); } else { value = q.decode(value); } } } profileFeature.setProfile(VCardUtils.unescapeString(value)); if(group != null) { profileFeature.setGroup(group); } vcard.setProfile(profileFeature); } catch(Exception ex) { throw new VCardBuildException("ProfileType ("+VCardType.PROFILE.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the SOURCE type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseSourceType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { SourceType sourceFeature = new SourceType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("CHARSET")) { sourceFeature.setCharset(pt.getValue()); } else if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.QUOTED_PRINTABLE.getType())) { sourceFeature.setEncodingType(EncodingType.QUOTED_PRINTABLE); } } else if(pt.getName().equals("LANGUAGE")) { sourceFeature.setLanguage(pt.getValue()); } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); sourceFeature.addExtendedParameter(parameter); } } if(sourceFeature.getEncodingType() == EncodingType.QUOTED_PRINTABLE) { QuotedPrintableCodec q = new QuotedPrintableCodec(); if(isCharsetForced()) { value = q.decode(value, forceCharset.name()); } else { if(sourceFeature.hasCharset()) { value = q.decode(value, sourceFeature.getCharset().name()); } else { value = q.decode(value); } } } sourceFeature.setSource(VCardUtils.unescapeString(value)); if(group != null) { sourceFeature.setGroup(group); } vcard.setSource(sourceFeature); } catch(Exception ex) { throw new VCardBuildException("SourceType ("+VCardType.SOURCE.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Parses the IMPP type.</p> * * @param group * @param value * @param paramTypeList * @param vcard * @throws VCardBuildException */ private void parseImppType(String group, String value, List<ParameterType> paramTypeList, VCardImpl vcard) throws VCardBuildException { try { IMPPType imppFeature = new IMPPType(); for (ParameterType pt : paramTypeList) { if(pt.getName().equals("ENCODING")) { if(pt.getValue().equals(EncodingType.EIGHT_BIT.getType())) { imppFeature.setEncodingType(EncodingType.EIGHT_BIT); } else { throw new VCardBuildException("IMPP's encoding must be 8bit."); } } else { if(pt.getName().equals("TYPE")) { if(pt.getValue().indexOf(',') != -1) { String[] typeValueList = pt.getValue().split(","); for(String typeValue : typeValueList) { setImppParameterType(imppFeature, typeValue); } } else { setImppParameterType(imppFeature, pt.getValue()); } } else { ExtendedParameterType parameter = new ExtendedParameterType(pt.getName(), pt.getValue()); imppFeature.addExtendedParameter(parameter); } } } imppFeature.setURI(new URI(value)); if(group != null) { imppFeature.setGroup(group); } vcard.addIMPP(imppFeature); } catch(Exception ex) { throw new VCardBuildException("IMPPType ("+VCardType.IMPP.getType()+") ["+ex.getClass().getName()+"] "+ex.getMessage(), ex); } } /** * <p>Helper method for the above.</p> * * @param imppType * @param paramValue */ private void setImppParameterType(IMPPType imppType, String paramValue) { try { String enumParamValue = paramValue.replace("-", "_").toUpperCase(); IMPPParameterType imppParamType = IMPPParameterType.valueOf(enumParamValue); imppType.addIMPPParameterType(imppParamType); } catch(IllegalArgumentException iae) { XIMPPParameterType xImppType = null; if(paramValue.indexOf('=') != -1) { String[] pTmp = paramValue.split("="); xImppType = new XIMPPParameterType(pTmp[0], pTmp[1]); } else { xImppType = new XIMPPParameterType(paramValue); } imppType.addExtendedIMPPParameterType(xImppType); } } /** * <p>Creates a VCardError object and sets the specified error information * in it and adds it to the VCard currently being parses.</p> * * @see VCardError * @see ErrorSeverity * * @param vcard * @param errorMessage * @param exception * @param severity */ private void handleError(VCardImpl vcard, String errorMessage, Throwable exception, ErrorSeverity severity) { VCardError vError = new VCardError(); vError.setErrorMessage(errorMessage); vError.setSeverity(severity); if(exception != null) { vError.setError(exception); } vcard.addError(vError); } /** * <p>Parses the raw parameter names and values and returns * a list of {@link ParameterType} objects.</p> * * @param paramTypes * @return {@link List}<ParameterType> * @throws VCardBuildException */ private List<ParameterType> parseParamTypes(List<String[]> paramTypes) throws VCardBuildException { List<ParameterType> parameterTypes = new ArrayList<ParameterType>(); for(String[] param : paramTypes) { String paramName = param[0]; String paramValue = param[1].toUpperCase().trim(); if(paramName != null) { paramName = paramName.toUpperCase().trim(); parameterTypes.add(new ParameterType(paramName, paramValue)); } else { //When the parameter types are missing we try to guess what they are. //We really should not as it breaks RFC rules but some apps do broken exports. if(paramValue.equals(EncodingType.BASE64.getType())) { parameterTypes.add(new ParameterType("ENCODING", paramValue)); } else if(paramValue.equals(EncodingType.BINARY.getType())) { parameterTypes.add(new ParameterType("ENCODING", paramValue)); } else if(paramValue.equals(EncodingType.QUOTED_PRINTABLE.getType())) { parameterTypes.add(new ParameterType("ENCODING", paramValue)); } else if(paramValue.equals("URI")) { parameterTypes.add(new ParameterType("VALUE", paramValue)); } else { boolean supported; try { supported = Charset.isSupported(paramValue); } catch (Exception ignored) { supported = false; } if(paramValue.length() > 0 && supported) { //Hell, it could even be a charset parameterTypes.add(new ParameterType("CHARSET", paramValue)); } else { /* * Type special notes: The type can include the type parameter "TYPE" to * specify the graphic image format type. The TYPE parameter values MUST * be one of the IANA registered image formats or a non-standard image format. */ parameterTypes.add(new ParameterType("TYPE", paramValue)); } } } } return parameterTypes; } /** * <p>Returns the contents of the vcard file where each line is delimited with * the standard java EOL char '\n' This is still a folded vcard String.</p> * * @param vcardFile * @return {@link String} * @throws IOException */ private String getContentFromFile(File vcardFile) throws IOException { return getContent(new FileReader(vcardFile)); } /** * <p>Returns the contents of the vcard String where each line is delimited with * the standard java EOL char '\n' This is still a folded vcard String.</p> * * @param vcardString * @return {@link String} * @throws IOException */ private String getContentFromString(String vcardString) throws IOException { return getContent(new StringReader(vcardString)); } /** * <p>Reads the contents of a Reader where each line is delimited with * the standard java EOL char '\n' This is still a folded vcard String.</p> * * @param reader * @return {@link String} * @throws IOException */ private String getContent(Reader reader) throws IOException { BufferedReader br = null; try { // Using explicit buffer size to avoid polluting logcat br = new BufferedReader(reader, BUFFER_SIZE); String line; StringBuilder sb = new StringBuilder(); while((line = br.readLine()) != null) { // skips blank lines if(!line.matches("$")) { sb.append(line); sb.append("\n"); } } return sb.toString(); } finally { if (br != null) { br.close(); } } } }