+++ /dev/null
-<HTML>
-<BODY>
-Support classes for SyncML.
-{@hide}
-</BODY>
-</HTML>
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim;
-
-import android.content.ContentValues;
-
-import org.apache.commons.codec.binary.Base64;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
-
-@Deprecated
-public class PropertyNode {
-
- public String propName;
-
- public String propValue;
-
- public List<String> propValue_vector;
-
- /** Store value as byte[],after decode.
- * Used when propValue is encoded by something like BASE64, QUOTED-PRINTABLE, etc.
- */
- public byte[] propValue_bytes;
-
- /** param store: key=paramType, value=paramValue
- * Note that currently PropertyNode class does not support multiple param-values
- * defined in vCard 3.0 (See also RFC 2426). multiple-values are stored as
- * one String value like "A,B", not ["A", "B"]...
- * TODO: fix this.
- */
- public ContentValues paramMap;
-
- /** Only for TYPE=??? param store. */
- public Set<String> paramMap_TYPE;
-
- /** Store group values. Used only in VCard. */
- public Set<String> propGroupSet;
-
- public PropertyNode() {
- propName = "";
- propValue = "";
- propValue_vector = new ArrayList<String>();
- paramMap = new ContentValues();
- paramMap_TYPE = new HashSet<String>();
- propGroupSet = new HashSet<String>();
- }
-
- public PropertyNode(
- String propName, String propValue, List<String> propValue_vector,
- byte[] propValue_bytes, ContentValues paramMap, Set<String> paramMap_TYPE,
- Set<String> propGroupSet) {
- if (propName != null) {
- this.propName = propName;
- } else {
- this.propName = "";
- }
- if (propValue != null) {
- this.propValue = propValue;
- } else {
- this.propValue = "";
- }
- if (propValue_vector != null) {
- this.propValue_vector = propValue_vector;
- } else {
- this.propValue_vector = new ArrayList<String>();
- }
- this.propValue_bytes = propValue_bytes;
- if (paramMap != null) {
- this.paramMap = paramMap;
- } else {
- this.paramMap = new ContentValues();
- }
- if (paramMap_TYPE != null) {
- this.paramMap_TYPE = paramMap_TYPE;
- } else {
- this.paramMap_TYPE = new HashSet<String>();
- }
- if (propGroupSet != null) {
- this.propGroupSet = propGroupSet;
- } else {
- this.propGroupSet = new HashSet<String>();
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof PropertyNode)) {
- return false;
- }
-
- PropertyNode node = (PropertyNode)obj;
-
- if (propName == null || !propName.equals(node.propName)) {
- return false;
- } else if (!paramMap.equals(node.paramMap)) {
- return false;
- } else if (!paramMap_TYPE.equals(node.paramMap_TYPE)) {
- return false;
- } else if (!propGroupSet.equals(node.propGroupSet)) {
- return false;
- }
-
- if (propValue_bytes != null && Arrays.equals(propValue_bytes, node.propValue_bytes)) {
- return true;
- } else {
- // Log.d("@@@", propValue + ", " + node.propValue);
- if (!propValue.equals(node.propValue)) {
- return false;
- }
-
- // The value in propValue_vector is not decoded even if it should be
- // decoded by BASE64 or QUOTED-PRINTABLE. When the size of propValue_vector
- // is 1, the encoded value is stored in propValue, so we do not have to
- // check it.
- return (propValue_vector.equals(node.propValue_vector) ||
- propValue_vector.size() == 1 ||
- node.propValue_vector.size() == 1);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("propName: ");
- builder.append(propName);
- builder.append(", paramMap: ");
- builder.append(paramMap.toString());
- builder.append(", propmMap_TYPE: ");
- builder.append(paramMap_TYPE.toString());
- builder.append(", propGroupSet: ");
- builder.append(propGroupSet.toString());
- if (propValue_vector != null && propValue_vector.size() > 1) {
- builder.append(", propValue_vector size: ");
- builder.append(propValue_vector.size());
- }
- if (propValue_bytes != null) {
- builder.append(", propValue_bytes size: ");
- builder.append(propValue_bytes.length);
- }
- builder.append(", propValue: ");
- builder.append(propValue);
- return builder.toString();
- }
-
- /**
- * Encode this object into a string which can be decoded.
- */
- public String encode() {
- // PropertyNode#toString() is for reading, not for parsing in the future.
- // We construct appropriate String here.
- StringBuilder builder = new StringBuilder();
- if (propName.length() > 0) {
- builder.append("propName:[");
- builder.append(propName);
- builder.append("],");
- }
- int size = propGroupSet.size();
- if (size > 0) {
- Set<String> set = propGroupSet;
- builder.append("propGroup:[");
- int i = 0;
- for (String group : set) {
- // We do not need to double quote groups.
- // group = 1*(ALPHA / DIGIT / "-")
- builder.append(group);
- if (i < size - 1) {
- builder.append(",");
- }
- i++;
- }
- builder.append("],");
- }
-
- if (paramMap.size() > 0 || paramMap_TYPE.size() > 0) {
- ContentValues values = paramMap;
- builder.append("paramMap:[");
- size = paramMap.size();
- int i = 0;
- for (Entry<String, Object> entry : values.valueSet()) {
- // Assuming param-key does not contain NON-ASCII nor symbols.
- //
- // According to vCard 3.0:
- // param-name = iana-token / x-name
- builder.append(entry.getKey());
-
- // param-value may contain any value including NON-ASCIIs.
- // We use the following replacing rule.
- // \ -> \\
- // , -> \,
- // In String#replaceAll(), "\\\\" means a single backslash.
- builder.append("=");
- builder.append(entry.getValue().toString()
- .replaceAll("\\\\", "\\\\\\\\")
- .replaceAll(",", "\\\\,"));
- if (i < size -1) {
- builder.append(",");
- }
- i++;
- }
-
- Set<String> set = paramMap_TYPE;
- size = paramMap_TYPE.size();
- if (i > 0 && size > 0) {
- builder.append(",");
- }
- i = 0;
- for (String type : set) {
- builder.append("TYPE=");
- builder.append(type
- .replaceAll("\\\\", "\\\\\\\\")
- .replaceAll(",", "\\\\,"));
- if (i < size - 1) {
- builder.append(",");
- }
- i++;
- }
- builder.append("],");
- }
-
- size = propValue_vector.size();
- if (size > 0) {
- builder.append("propValue:[");
- List<String> list = propValue_vector;
- for (int i = 0; i < size; i++) {
- builder.append(list.get(i)
- .replaceAll("\\\\", "\\\\\\\\")
- .replaceAll(",", "\\\\,"));
- if (i < size -1) {
- builder.append(",");
- }
- }
- builder.append("],");
- }
-
- return builder.toString();
- }
-
- public static PropertyNode decode(String encodedString) {
- PropertyNode propertyNode = new PropertyNode();
- String trimed = encodedString.trim();
- if (trimed.length() == 0) {
- return propertyNode;
- }
- String[] elems = trimed.split("],");
-
- for (String elem : elems) {
- int index = elem.indexOf('[');
- String name = elem.substring(0, index - 1);
- Pattern pattern = Pattern.compile("(?<!\\\\),");
- String[] values = pattern.split(elem.substring(index + 1), -1);
- if (name.equals("propName")) {
- propertyNode.propName = values[0];
- } else if (name.equals("propGroupSet")) {
- for (String value : values) {
- propertyNode.propGroupSet.add(value);
- }
- } else if (name.equals("paramMap")) {
- ContentValues paramMap = propertyNode.paramMap;
- Set<String> paramMap_TYPE = propertyNode.paramMap_TYPE;
- for (String value : values) {
- String[] tmp = value.split("=", 2);
- String mapKey = tmp[0];
- // \, -> ,
- // \\ -> \
- // In String#replaceAll(), "\\\\" means a single backslash.
- String mapValue =
- tmp[1].replaceAll("\\\\,", ",").replaceAll("\\\\\\\\", "\\\\");
- if (mapKey.equalsIgnoreCase("TYPE")) {
- paramMap_TYPE.add(mapValue);
- } else {
- paramMap.put(mapKey, mapValue);
- }
- }
- } else if (name.equals("propValue")) {
- StringBuilder builder = new StringBuilder();
- List<String> list = propertyNode.propValue_vector;
- int length = values.length;
- for (int i = 0; i < length; i++) {
- String normValue = values[i]
- .replaceAll("\\\\,", ",")
- .replaceAll("\\\\\\\\", "\\\\");
- list.add(normValue);
- builder.append(normValue);
- if (i < length - 1) {
- builder.append(";");
- }
- }
- propertyNode.propValue = builder.toString();
- }
- }
-
- // At this time, QUOTED-PRINTABLE is already decoded to Java String.
- // We just need to decode BASE64 String to binary.
- String encoding = propertyNode.paramMap.getAsString("ENCODING");
- if (encoding != null &&
- (encoding.equalsIgnoreCase("BASE64") ||
- encoding.equalsIgnoreCase("B"))) {
- propertyNode.propValue_bytes =
- Base64.decodeBase64(propertyNode.propValue_vector.get(0).getBytes());
- }
-
- return propertyNode;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim;
-
-import java.util.List;
-
-@Deprecated
-public interface VBuilder {
- void start();
-
- void end();
-
- /**
- * @param type
- * VXX <br>
- * BEGIN:VXX
- */
- void startRecord(String type);
-
- /** END:VXX */
- void endRecord();
-
- void startProperty();
-
- void endProperty();
-
- /**
- * @param group
- */
- void propertyGroup(String group);
-
- /**
- * @param name
- * N <br>
- * N
- */
- void propertyName(String name);
-
- /**
- * @param type
- * LANGUAGE \ ENCODING <br>
- * ;LANGUage= \ ;ENCODING=
- */
- void propertyParamType(String type);
-
- /**
- * @param value
- * FR-EN \ GBK <br>
- * FR-EN \ GBK
- */
- void propertyParamValue(String value);
-
- void propertyValues(List<String> values);
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim;
-
-import java.util.Collection;
-import java.util.List;
-
-@Deprecated
-public class VBuilderCollection implements VBuilder {
-
- private final Collection<VBuilder> mVBuilderCollection;
-
- public VBuilderCollection(Collection<VBuilder> vBuilderCollection) {
- mVBuilderCollection = vBuilderCollection;
- }
-
- public Collection<VBuilder> getVBuilderCollection() {
- return mVBuilderCollection;
- }
-
- public void start() {
- for (VBuilder builder : mVBuilderCollection) {
- builder.start();
- }
- }
-
- public void end() {
- for (VBuilder builder : mVBuilderCollection) {
- builder.end();
- }
- }
-
- public void startRecord(String type) {
- for (VBuilder builder : mVBuilderCollection) {
- builder.startRecord(type);
- }
- }
-
- public void endRecord() {
- for (VBuilder builder : mVBuilderCollection) {
- builder.endRecord();
- }
- }
-
- public void startProperty() {
- for (VBuilder builder : mVBuilderCollection) {
- builder.startProperty();
- }
- }
-
-
- public void endProperty() {
- for (VBuilder builder : mVBuilderCollection) {
- builder.endProperty();
- }
- }
-
- public void propertyGroup(String group) {
- for (VBuilder builder : mVBuilderCollection) {
- builder.propertyGroup(group);
- }
- }
-
- public void propertyName(String name) {
- for (VBuilder builder : mVBuilderCollection) {
- builder.propertyName(name);
- }
- }
-
- public void propertyParamType(String type) {
- for (VBuilder builder : mVBuilderCollection) {
- builder.propertyParamType(type);
- }
- }
-
- public void propertyParamValue(String value) {
- for (VBuilder builder : mVBuilderCollection) {
- builder.propertyParamValue(value);
- }
- }
-
- public void propertyValues(List<String> values) {
- for (VBuilder builder : mVBuilderCollection) {
- builder.propertyValues(values);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim;
-
-import android.content.ContentValues;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.net.QuotedPrintableCodec;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Store the parse result to custom datastruct: VNode, PropertyNode
- * Maybe several vcard instance, so use vNodeList to store.
- * VNode: standy by a vcard instance.
- * PropertyNode: standy by a property line of a card.
- */
-@Deprecated
-public class VDataBuilder implements VBuilder {
- static private String LOG_TAG = "VDATABuilder";
-
- /**
- * If there's no other information available, this class uses this charset for encoding
- * byte arrays.
- */
- static public String DEFAULT_CHARSET = "UTF-8";
-
- /** type=VNode */
- public List<VNode> vNodeList = new ArrayList<VNode>();
- private int mNodeListPos = 0;
- private VNode mCurrentVNode;
- private PropertyNode mCurrentPropNode;
- private String mCurrentParamType;
-
- /**
- * The charset using which VParser parses the text.
- */
- private String mSourceCharset;
-
- /**
- * The charset with which byte array is encoded to String.
- */
- private String mTargetCharset;
-
- private boolean mStrictLineBreakParsing;
-
- public VDataBuilder() {
- this(VParser.DEFAULT_CHARSET, DEFAULT_CHARSET, false);
- }
-
- public VDataBuilder(String charset, boolean strictLineBreakParsing) {
- this(null, charset, strictLineBreakParsing);
- }
-
- /**
- * @hide sourceCharset is temporal.
- */
- public VDataBuilder(String sourceCharset, String targetCharset,
- boolean strictLineBreakParsing) {
- if (sourceCharset != null) {
- mSourceCharset = sourceCharset;
- } else {
- mSourceCharset = VParser.DEFAULT_CHARSET;
- }
- if (targetCharset != null) {
- mTargetCharset = targetCharset;
- } else {
- mTargetCharset = DEFAULT_CHARSET;
- }
- mStrictLineBreakParsing = strictLineBreakParsing;
- }
-
- public void start() {
- }
-
- public void end() {
- }
-
- // Note: I guess that this code assumes the Record may nest like this:
- // START:VPOS
- // ...
- // START:VPOS2
- // ...
- // END:VPOS2
- // ...
- // END:VPOS
- //
- // However the following code has a bug.
- // When error occurs after calling startRecord(), the entry which is probably
- // the cause of the error remains to be in vNodeList, while endRecord() is not called.
- //
- // I leave this code as is since I'm not familiar with vcalendar specification.
- // But I believe we should refactor this code in the future.
- // Until this, the last entry has to be removed when some error occurs.
- public void startRecord(String type) {
-
- VNode vnode = new VNode();
- vnode.parseStatus = 1;
- vnode.VName = type;
- // I feel this should be done in endRecord(), but it cannot be done because of
- // the reason above.
- vNodeList.add(vnode);
- mNodeListPos = vNodeList.size() - 1;
- mCurrentVNode = vNodeList.get(mNodeListPos);
- }
-
- public void endRecord() {
- VNode endNode = vNodeList.get(mNodeListPos);
- endNode.parseStatus = 0;
- while(mNodeListPos > 0){
- mNodeListPos--;
- if((vNodeList.get(mNodeListPos)).parseStatus == 1)
- break;
- }
- mCurrentVNode = vNodeList.get(mNodeListPos);
- }
-
- public void startProperty() {
- mCurrentPropNode = new PropertyNode();
- }
-
- public void endProperty() {
- mCurrentVNode.propList.add(mCurrentPropNode);
- }
-
- public void propertyName(String name) {
- mCurrentPropNode.propName = name;
- }
-
- // Used only in VCard.
- public void propertyGroup(String group) {
- mCurrentPropNode.propGroupSet.add(group);
- }
-
- public void propertyParamType(String type) {
- mCurrentParamType = type;
- }
-
- public void propertyParamValue(String value) {
- if (mCurrentParamType == null ||
- mCurrentParamType.equalsIgnoreCase("TYPE")) {
- mCurrentPropNode.paramMap_TYPE.add(value);
- } else {
- mCurrentPropNode.paramMap.put(mCurrentParamType, value);
- }
-
- mCurrentParamType = null;
- }
-
- private String encodeString(String originalString, String targetCharset) {
- if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
- return originalString;
- }
- Charset charset = Charset.forName(mSourceCharset);
- ByteBuffer byteBuffer = charset.encode(originalString);
- // byteBuffer.array() "may" return byte array which is larger than
- // byteBuffer.remaining(). Here, we keep on the safe side.
- byte[] bytes = new byte[byteBuffer.remaining()];
- byteBuffer.get(bytes);
- try {
- return new String(bytes, targetCharset);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
- return new String(bytes);
- }
- }
-
- private String handleOneValue(String value, String targetCharset, String encoding) {
- if (encoding != null) {
- if (encoding.equals("BASE64") || encoding.equals("B")) {
- // Assume BASE64 is used only when the number of values is 1.
- mCurrentPropNode.propValue_bytes =
- Base64.decodeBase64(value.getBytes());
- return value;
- } else if (encoding.equals("QUOTED-PRINTABLE")) {
- String quotedPrintable = value
- .replaceAll("= ", " ").replaceAll("=\t", "\t");
- String[] lines;
- if (mStrictLineBreakParsing) {
- lines = quotedPrintable.split("\r\n");
- } else {
- StringBuilder builder = new StringBuilder();
- int length = quotedPrintable.length();
- ArrayList<String> list = new ArrayList<String>();
- for (int i = 0; i < length; i++) {
- char ch = quotedPrintable.charAt(i);
- if (ch == '\n') {
- list.add(builder.toString());
- builder = new StringBuilder();
- } else if (ch == '\r') {
- list.add(builder.toString());
- builder = new StringBuilder();
- if (i < length - 1) {
- char nextCh = quotedPrintable.charAt(i + 1);
- if (nextCh == '\n') {
- i++;
- }
- }
- } else {
- builder.append(ch);
- }
- }
- String finalLine = builder.toString();
- if (finalLine.length() > 0) {
- list.add(finalLine);
- }
- lines = list.toArray(new String[0]);
- }
- StringBuilder builder = new StringBuilder();
- for (String line : lines) {
- if (line.endsWith("=")) {
- line = line.substring(0, line.length() - 1);
- }
- builder.append(line);
- }
- byte[] bytes;
- try {
- bytes = builder.toString().getBytes(mSourceCharset);
- } catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
- bytes = builder.toString().getBytes();
- }
-
- try {
- bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
- } catch (DecoderException e) {
- Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
- return "";
- }
-
- try {
- return new String(bytes, targetCharset);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
- return new String(bytes);
- }
- }
- // Unknown encoding. Fall back to default.
- }
- return encodeString(value, targetCharset);
- }
-
- public void propertyValues(List<String> values) {
- if (values == null || values.size() == 0) {
- mCurrentPropNode.propValue_bytes = null;
- mCurrentPropNode.propValue_vector.clear();
- mCurrentPropNode.propValue_vector.add("");
- mCurrentPropNode.propValue = "";
- return;
- }
-
- ContentValues paramMap = mCurrentPropNode.paramMap;
-
- String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
- String encoding = paramMap.getAsString("ENCODING");
-
- if (targetCharset == null || targetCharset.length() == 0) {
- targetCharset = mTargetCharset;
- }
-
- for (String value : values) {
- mCurrentPropNode.propValue_vector.add(
- handleOneValue(value, targetCharset, encoding));
- }
-
- mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
- }
-
- private String listToString(List<String> list){
- int size = list.size();
- if (size > 1) {
- StringBuilder typeListB = new StringBuilder();
- for (String type : list) {
- typeListB.append(type).append(";");
- }
- int len = typeListB.length();
- if (len > 0 && typeListB.charAt(len - 1) == ';') {
- return typeListB.substring(0, len - 1);
- }
- return typeListB.toString();
- } else if (size == 1) {
- return list.get(0);
- } else {
- return "";
- }
- }
-
- public String getResult(){
- return null;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim;
-
-import java.util.ArrayList;
-
-@Deprecated
-public class VNode {
-
- public String VName;
-
- public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>();
-
- /** 0:parse over. 1:parsing. */
- public int parseStatus = 1;
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-
-/**
- * This interface is used to parse the V format files, such as VCard & VCal
- */
-@Deprecated
-abstract public class VParser {
- // Assume that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
- // decode the unicode to the original charset. If not, this setting will cause some bug.
- public static String DEFAULT_CHARSET = "iso-8859-1";
-
- /**
- * The buffer used to store input stream
- */
- protected String mBuffer = null;
-
- /** The builder to build parsed data */
- protected VBuilder mBuilder = null;
-
- /** The encoding type */
- protected String mEncoding = null;
-
- protected final int PARSE_ERROR = -1;
-
- protected final String mDefaultEncoding = "8BIT";
-
- /**
- * If offset reach '\r\n' return 2. Else return PARSE_ERROR.
- */
- protected int parseCrlf(int offset) {
- if (offset >= mBuffer.length())
- return PARSE_ERROR;
- char ch = mBuffer.charAt(offset);
- if (ch == '\r') {
- offset++;
- ch = mBuffer.charAt(offset);
- if (ch == '\n') {
- return 2;
- }
- }
- return PARSE_ERROR;
- }
-
- /**
- * Parse the given stream
- *
- * @param is
- * The source to parse.
- * @param encoding
- * The encoding type.
- * @param builder
- * The v builder which used to construct data.
- * @return Return true for success, otherwise false.
- * @throws IOException
- */
- public boolean parse(InputStream is, String encoding, VBuilder builder)
- throws IOException {
- setInputStream(is, encoding);
- mBuilder = builder;
- int ret = 0, offset = 0, sum = 0;
-
- if (mBuilder != null) {
- mBuilder.start();
- }
- for (;;) {
- ret = parseVFile(offset); // for next property length
- if (PARSE_ERROR == ret) {
- break;
- } else {
- offset += ret;
- sum += ret;
- }
- }
- if (mBuilder != null) {
- mBuilder.end();
- }
- return (mBuffer.length() == sum);
- }
-
- /**
- * Parse the given stream with the default encoding.
- *
- * @param is
- * The source to parse.
- * @param builder
- * The v builder which used to construct data.
- * @return Return true for success, otherwise false.
- * @throws IOException
- */
- public boolean parse(InputStream is, VBuilder builder) throws IOException {
- return parse(is, DEFAULT_CHARSET, builder);
- }
-
- /**
- * Copy the content of input stream and filter the "folding"
- */
- protected void setInputStream(InputStream is, String encoding)
- throws UnsupportedEncodingException {
- InputStreamReader reader = new InputStreamReader(is, encoding);
- StringBuilder b = new StringBuilder();
-
- int ch;
- try {
- while ((ch = reader.read()) != -1) {
- if (ch == '\r') {
- ch = reader.read();
- if (ch == '\n') {
- ch = reader.read();
- if (ch == ' ' || ch == '\t') {
- b.append((char) ch);
- continue;
- }
- b.append("\r\n");
- if (ch == -1) {
- break;
- }
- } else {
- b.append("\r");
- }
- }
- b.append((char) ch);
- }
- mBuffer = b.toString();
- } catch (Exception e) {
- return;
- }
- return;
- }
-
- /**
- * abstract function, waiting implement.<br>
- * analyse from offset, return the length of consumed property.
- */
- abstract protected int parseVFile(int offset);
-
- /**
- * From offset, jump ' ', '\t', '\r\n' sequence, return the length of jump.<br>
- * 1 * (SPACE / HTAB / CRLF)
- */
- protected int parseWsls(int offset) {
- int ret = 0, sum = 0;
-
- try {
- char ch = mBuffer.charAt(offset);
- if (ch == ' ' || ch == '\t') {
- sum++;
- offset++;
- } else if ((ret = parseCrlf(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- } else {
- return PARSE_ERROR;
- }
- for (;;) {
- ch = mBuffer.charAt(offset);
- if (ch == ' ' || ch == '\t') {
- sum++;
- offset++;
- } else if ((ret = parseCrlf(offset)) != PARSE_ERROR) {
- offset += ret;
- sum += ret;
- } else {
- break;
- }
- }
- } catch (IndexOutOfBoundsException e) {
- ;
- }
- if (sum > 0)
- return sum;
- return PARSE_ERROR;
- }
-
- /**
- * To determine if the given string equals to the start of the current
- * string.
- *
- * @param offset
- * The offset in buffer of current string
- * @param tar
- * The given string.
- * @param ignoreCase
- * To determine case sensitive or not.
- * @return The consumed characters, otherwise return PARSE_ERROR.
- */
- protected int parseString(int offset, final String tar, boolean ignoreCase) {
- int sum = 0;
- if (tar == null) {
- return PARSE_ERROR;
- }
-
- if (ignoreCase) {
- int len = tar.length();
- try {
- if (mBuffer.substring(offset, offset + len).equalsIgnoreCase(
- tar)) {
- sum = len;
- } else {
- return PARSE_ERROR;
- }
- } catch (IndexOutOfBoundsException e) {
- return PARSE_ERROR;
- }
-
- } else { /* case sensitive */
- if (mBuffer.startsWith(tar, offset)) {
- sum = tar.length();
- } else {
- return PARSE_ERROR;
- }
- }
- return sum;
- }
-
- /**
- * Skip the white space in string.
- */
- protected int removeWs(int offset) {
- if (offset >= mBuffer.length())
- return PARSE_ERROR;
- int sum = 0;
- char ch;
- while ((ch = mBuffer.charAt(offset)) == ' ' || ch == '\t') {
- offset++;
- sum++;
- }
- return sum;
- }
-
- /**
- * "X-" word, and its value. Return consumed length.
- */
- protected int parseXWord(int offset) {
- int ret = 0, sum = 0;
- ret = parseString(offset, "X-", true);
- if (PARSE_ERROR == ret)
- return PARSE_ERROR;
- offset += ret;
- sum += ret;
-
- ret = parseWord(offset);
- if (PARSE_ERROR == ret) {
- return PARSE_ERROR;
- }
- sum += ret;
- return sum;
- }
-
- /**
- * From offset, parse as :mEncoding ?= 7bit / 8bit / quoted-printable /
- * base64
- */
- protected int parseValue(int offset) {
- int ret = 0;
-
- if (mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
- || mEncoding.equalsIgnoreCase("8BIT")
- || mEncoding.toUpperCase().startsWith("X-")) {
- ret = parse8bit(offset);
- if (ret != PARSE_ERROR) {
- return ret;
- }
- return PARSE_ERROR;
- }
-
- if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
- ret = parseQuotedPrintable(offset);
- if (ret != PARSE_ERROR) {
- return ret;
- }
- return PARSE_ERROR;
- }
-
- if (mEncoding.equalsIgnoreCase("BASE64")) {
- ret = parseBase64(offset);
- if (ret != PARSE_ERROR) {
- return ret;
- }
- return PARSE_ERROR;
- }
- return PARSE_ERROR;
- }
-
- /**
- * Refer to RFC 1521, 8bit text
- */
- protected int parse8bit(int offset) {
- int index = 0;
-
- index = mBuffer.substring(offset).indexOf("\r\n");
-
- if (index == -1)
- return PARSE_ERROR;
- else
- return index;
-
- }
-
- /**
- * Refer to RFC 1521, quoted printable text ([*(ptext / SPACE / TAB) ptext]
- * ["="] CRLF)
- */
- protected int parseQuotedPrintable(int offset) {
- int ret = 0, sum = 0;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
-
- for (;;) {
- ret = parsePtext(offset);
- if (PARSE_ERROR == ret)
- break;
- offset += ret;
- sum += ret;
-
- ret = removeWs(offset);
- offset += ret;
- sum += ret;
- }
-
- ret = parseString(offset, "=", false);
- if (ret != PARSE_ERROR) {
- // offset += ret;
- sum += ret;
- }
-
- return sum;
- }
-
- /**
- * return 1 or 3 <any ASCII character except "=", SPACE, or TAB>
- */
- protected int parsePtext(int offset) {
- int ret = 0;
-
- try {
- char ch = mBuffer.charAt(offset);
- if (isPrintable(ch) && ch != '=' && ch != ' ' && ch != '\t') {
- return 1;
- }
- } catch (IndexOutOfBoundsException e) {
- return PARSE_ERROR;
- }
-
- ret = parseOctet(offset);
- if (ret != PARSE_ERROR) {
- return ret;
- }
- return PARSE_ERROR;
- }
-
- /**
- * start with "=" two of (DIGIT / "A" / "B" / "C" / "D" / "E" / "F") <br>
- * So maybe return 3.
- */
- protected int parseOctet(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseString(offset, "=", false);
- if (PARSE_ERROR == ret)
- return PARSE_ERROR;
- offset += ret;
- sum += ret;
-
- try {
- int ch = mBuffer.charAt(offset);
- if (ch == ' ' || ch == '\t')
- return ++sum;
- if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
- offset++;
- sum++;
- ch = mBuffer.charAt(offset);
- if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
- sum++;
- return sum;
- }
- }
- } catch (IndexOutOfBoundsException e) {
- ;
- }
- return PARSE_ERROR;
- }
-
- /**
- * Refer to RFC 1521, base64 text The end of the text is marked with two
- * CRLF sequences
- */
- protected int parseBase64(int offset) {
- int sum = 0;
- try {
- for (;;) {
- char ch;
- ch = mBuffer.charAt(offset);
-
- if (ch == '\r') {
- int ret = parseString(offset, "\r\n\r\n", false);
- sum += ret;
- break;
- } else {
- /* ignore none base64 character */
- sum++;
- offset++;
- }
- }
- } catch (IndexOutOfBoundsException e) {
- return PARSE_ERROR;
- }
- sum -= 2;/* leave one CRLF to parse the end of this property */
- return sum;
- }
-
- /**
- * Any printable ASCII sequence except [ ]=:.,;
- */
- protected int parseWord(int offset) {
- int sum = 0;
- try {
- for (;;) {
- char ch = mBuffer.charAt(offset);
- if (!isPrintable(ch))
- break;
- if (ch == ' ' || ch == '=' || ch == ':' || ch == '.'
- || ch == ',' || ch == ';')
- break;
- if (ch == '\\') {
- ch = mBuffer.charAt(offset + 1);
- if (ch == ';') {
- offset++;
- sum++;
- }
- }
- offset++;
- sum++;
- }
- } catch (IndexOutOfBoundsException e) {
- ;
- }
- if (sum == 0)
- return PARSE_ERROR;
- return sum;
- }
-
- /**
- * If it is a letter or digit.
- */
- protected boolean isLetterOrDigit(char ch) {
- if (ch >= '0' && ch <= '9')
- return true;
- if (ch >= 'a' && ch <= 'z')
- return true;
- if (ch >= 'A' && ch <= 'Z')
- return true;
- return false;
- }
-
- /**
- * If it is printable in ASCII
- */
- protected boolean isPrintable(char ch) {
- if (ch >= ' ' && ch <= '~')
- return true;
- return false;
- }
-
- /**
- * If it is a letter.
- */
- protected boolean isLetter(char ch) {
- if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
- return true;
- }
- return false;
- }
-
- /**
- * Get a word from current position.
- */
- protected String getWord(int offset) {
- StringBuilder word = new StringBuilder();
- try {
- for (;;) {
- char ch = mBuffer.charAt(offset);
- if (isLetterOrDigit(ch) || ch == '-') {
- word.append(ch);
- offset++;
- } else {
- break;
- }
- }
- } catch (IndexOutOfBoundsException e) {
- ;
- }
- return word.toString();
- }
-
- /**
- * If is: "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
- */
- protected int parsePValueVal(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseString(offset, "INLINE", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "URL", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "CONTENT-ID", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "CID", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "INLINE", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseXWord(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- return PARSE_ERROR;
- }
-
- /**
- * If is: "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word and
- * set mEncoding.
- */
- protected int parsePEncodingVal(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseString(offset, "7BIT", true);
- if (ret != PARSE_ERROR) {
- mEncoding = "7BIT";
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "8BIT", true);
- if (ret != PARSE_ERROR) {
- mEncoding = "8BIT";
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "QUOTED-PRINTABLE", true);
- if (ret != PARSE_ERROR) {
- mEncoding = "QUOTED-PRINTABLE";
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "BASE64", true);
- if (ret != PARSE_ERROR) {
- mEncoding = "BASE64";
- sum += ret;
- return sum;
- }
-
- ret = parseXWord(offset);
- if (ret != PARSE_ERROR) {
- mEncoding = mBuffer.substring(offset).substring(0, ret);
- sum += ret;
- return sum;
- }
-
- return PARSE_ERROR;
- }
-
- /**
- * Refer to RFC1521, section 7.1<br>
- * If is: "us-ascii" / "iso-8859-xxx" / "X-" word
- */
- protected int parseCharsetVal(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseString(offset, "us-ascii", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-1", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-2", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-3", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-4", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-5", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-6", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-7", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-8", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseString(offset, "iso-8859-9", true);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- ret = parseXWord(offset);
- if (ret != PARSE_ERROR) {
- sum += ret;
- return sum;
- }
-
- return PARSE_ERROR;
- }
-
- /**
- * Refer to RFC 1766<br>
- * like: XXX(sequence letters)-XXX(sequence letters)
- */
- protected int parseLangVal(int offset) {
- int ret = 0, sum = 0;
-
- ret = parseTag(offset);
- if (PARSE_ERROR == ret) {
- return PARSE_ERROR;
- }
- offset += ret;
- sum += ret;
-
- for (;;) {
- ret = parseString(offset, "-", false);
- if (PARSE_ERROR == ret) {
- break;
- }
- offset += ret;
- sum += ret;
-
- ret = parseTag(offset);
- if (PARSE_ERROR == ret) {
- break;
- }
- offset += ret;
- sum += ret;
- }
- return sum;
- }
-
- /**
- * From first 8 position, is sequence LETTER.
- */
- protected int parseTag(int offset) {
- int sum = 0, i = 0;
-
- try {
- for (i = 0; i < 8; i++) {
- char ch = mBuffer.charAt(offset);
- if (!isLetter(ch)) {
- break;
- }
- sum++;
- offset++;
- }
- } catch (IndexOutOfBoundsException e) {
- ;
- }
- if (i == 0) {
- return PARSE_ERROR;
- }
- return sum;
- }
-
-}
+++ /dev/null
-<HTML>
-<BODY>
-Support classes for SyncML.
-{@hide}
-</BODY>
-</HTML>
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import android.content.AbstractSyncableContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.provider.Contacts;
-import android.provider.CallLog.Calls;
-import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.Extensions;
-import android.provider.Contacts.GroupMembership;
-import android.provider.Contacts.Organizations;
-import android.provider.Contacts.People;
-import android.provider.Contacts.Phones;
-import android.provider.Contacts.Photos;
-import android.syncml.pim.PropertyNode;
-import android.syncml.pim.VNode;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * The parameter class of VCardComposer.
- * This class standy by the person-contact in
- * Android system, we must use this class instance as parameter to transmit to
- * VCardComposer so that create vCard string.
- *
- * @deprecated Please use the new code in android.pim.vcard
- */
-// TODO: rename the class name, next step
-@Deprecated
-public class ContactStruct {
- private static final String LOG_TAG = "ContactStruct";
-
- // Note: phonetic name probably should be "LAST FIRST MIDDLE" for European languages, and
- // space should be added between each element while it should not be in Japanese.
- // But unfortunately, we currently do not have the data and are not sure whether we should
- // support European version of name ordering.
- //
- // TODO: Implement the logic described above if we really need European version of
- // phonetic name handling. Also, adding the appropriate test case of vCard would be
- // highly appreciated.
- public static final int NAME_ORDER_TYPE_ENGLISH = 0;
- public static final int NAME_ORDER_TYPE_JAPANESE = 1;
-
- /** MUST exist */
- public String name;
- public String phoneticName;
- /** maybe folding */
- public List<String> notes = new ArrayList<String>();
- /** maybe folding */
- public String title;
- /** binary bytes of pic. */
- public byte[] photoBytes;
- /** The type of Photo (e.g. JPEG, BMP, etc.) */
- public String photoType;
- /** Only for GET. Use addPhoneList() to PUT. */
- public List<PhoneData> phoneList;
- /** Only for GET. Use addContactmethodList() to PUT. */
- public List<ContactMethod> contactmethodList;
- /** Only for GET. Use addOrgList() to PUT. */
- public List<OrganizationData> organizationList;
- /** Only for GET. Use addExtension() to PUT */
- public Map<String, List<String>> extensionMap;
-
- public String timeStamp;
-
- // Use organizationList instead when handling ORG.
- @Deprecated
- public String company;
-
- public static class PhoneData {
- public int type;
- /** maybe folding */
- public String data;
- public String label;
- public boolean isPrimary;
- }
-
- public static class ContactMethod {
- // Contacts.KIND_EMAIL, Contacts.KIND_POSTAL
- public int kind;
- // e.g. Contacts.ContactMethods.TYPE_HOME, Contacts.PhoneColumns.TYPE_HOME
- // If type == Contacts.PhoneColumns.TYPE_CUSTOM, label is used.
- public int type;
- public String data;
- // Used only when TYPE is TYPE_CUSTOM.
- public String label;
- public boolean isPrimary;
- }
-
- public static class OrganizationData {
- public int type;
- public String companyName;
- public String positionName;
- public boolean isPrimary;
- }
-
- /**
- * Add a phone info to phoneList.
- * @param data phone number
- * @param type type col of content://contacts/phones
- * @param label lable col of content://contacts/phones
- */
- public void addPhone(int type, String data, String label, boolean isPrimary){
- if (phoneList == null) {
- phoneList = new ArrayList<PhoneData>();
- }
- PhoneData phoneData = new PhoneData();
- phoneData.type = type;
-
- StringBuilder builder = new StringBuilder();
- String trimed = data.trim();
- int length = trimed.length();
- for (int i = 0; i < length; i++) {
- char ch = trimed.charAt(i);
- if (('0' <= ch && ch <= '9') || (i == 0 && ch == '+')) {
- builder.append(ch);
- }
- }
- phoneData.data = PhoneNumberUtils.formatNumber(builder.toString());
- phoneData.label = label;
- phoneData.isPrimary = isPrimary;
- phoneList.add(phoneData);
- }
-
- /**
- * Add call history time stamp and call type.
- * @param type call type
- * @param timeStamp timeStamp
- */
- public void addCallHistoryTimeStamp(int type, String date) {
- // Extension for call history as defined in
- // in the Specification for Ic Mobile Communcation - ver 1.1,
- // Oct 2000. This is used to send the details of the call
- // history - missed, incoming, outgoing along with date and time
- // to the requesting device (For example, transferring phone book
- // when connected over bluetooth)
- // X-IRMC-CALL-DATETIME;MISSED:20050320T100000
- String strCallType;
- if (type == Calls.INCOMING_TYPE) {
- strCallType = "INCOMING";
- } else if (type == Calls.OUTGOING_TYPE) {
- strCallType = "OUTGOING";
- } else if (type == Calls.MISSED_TYPE) {
- strCallType = "MISSED";
- } else {
- strCallType = "";
- }
- timeStamp = "X-IRMC-CALL-DATETIME;" + strCallType + ":" + date;
- }
-
- /**
- * Add a contactmethod info to contactmethodList.
- * @param kind integer value defined in Contacts.java
- * (e.g. Contacts.KIND_EMAIL)
- * @param type type col of content://contacts/contact_methods
- * @param data contact data
- * @param label extra string used only when kind is Contacts.KIND_CUSTOM.
- */
- public void addContactmethod(int kind, int type, String data,
- String label, boolean isPrimary){
- if (contactmethodList == null) {
- contactmethodList = new ArrayList<ContactMethod>();
- }
- ContactMethod contactMethod = new ContactMethod();
- contactMethod.kind = kind;
- contactMethod.type = type;
- contactMethod.data = data;
- contactMethod.label = label;
- contactMethod.isPrimary = isPrimary;
- contactmethodList.add(contactMethod);
- }
-
- /**
- * Add a Organization info to organizationList.
- */
- public void addOrganization(int type, String companyName, String positionName,
- boolean isPrimary) {
- if (organizationList == null) {
- organizationList = new ArrayList<OrganizationData>();
- }
- OrganizationData organizationData = new OrganizationData();
- organizationData.type = type;
- organizationData.companyName = companyName;
- organizationData.positionName = positionName;
- organizationData.isPrimary = isPrimary;
- organizationList.add(organizationData);
- }
-
- /**
- * Set "position" value to the appropriate data. If there's more than one
- * OrganizationData objects, the value is set to the last one. If there's no
- * OrganizationData object, a new OrganizationData is created, whose company name is
- * empty.
- *
- * TODO: incomplete logic. fix this:
- *
- * e.g. This assumes ORG comes earlier, but TITLE may come earlier like this, though we do not
- * know how to handle it in general cases...
- * ----
- * TITLE:Software Engineer
- * ORG:Google
- * ----
- */
- public void setPosition(String positionValue) {
- if (organizationList == null) {
- organizationList = new ArrayList<OrganizationData>();
- }
- int size = organizationList.size();
- if (size == 0) {
- addOrganization(Contacts.OrganizationColumns.TYPE_OTHER, "", null, false);
- size = 1;
- }
- OrganizationData lastData = organizationList.get(size - 1);
- lastData.positionName = positionValue;
- }
-
- public void addExtension(PropertyNode propertyNode) {
- if (propertyNode.propValue.length() == 0) {
- return;
- }
- // Now store the string into extensionMap.
- List<String> list;
- String name = propertyNode.propName;
- if (extensionMap == null) {
- extensionMap = new HashMap<String, List<String>>();
- }
- if (!extensionMap.containsKey(name)){
- list = new ArrayList<String>();
- extensionMap.put(name, list);
- } else {
- list = extensionMap.get(name);
- }
-
- list.add(propertyNode.encode());
- }
-
- private static String getNameFromNProperty(List<String> elems, int nameOrderType) {
- // Family, Given, Middle, Prefix, Suffix. (1 - 5)
- int size = elems.size();
- if (size > 1) {
- StringBuilder builder = new StringBuilder();
- boolean builderIsEmpty = true;
- // Prefix
- if (size > 3 && elems.get(3).length() > 0) {
- builder.append(elems.get(3));
- builderIsEmpty = false;
- }
- String first, second;
- if (nameOrderType == NAME_ORDER_TYPE_JAPANESE) {
- first = elems.get(0);
- second = elems.get(1);
- } else {
- first = elems.get(1);
- second = elems.get(0);
- }
- if (first.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(first);
- builderIsEmpty = false;
- }
- // Middle name
- if (size > 2 && elems.get(2).length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(elems.get(2));
- builderIsEmpty = false;
- }
- if (second.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(second);
- builderIsEmpty = false;
- }
- // Suffix
- if (size > 4 && elems.get(4).length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(elems.get(4));
- builderIsEmpty = false;
- }
- return builder.toString();
- } else if (size == 1) {
- return elems.get(0);
- } else {
- return "";
- }
- }
-
- public static ContactStruct constructContactFromVNode(VNode node,
- int nameOrderType) {
- if (!node.VName.equals("VCARD")) {
- // Impossible in current implementation. Just for safety.
- Log.e(LOG_TAG, "Non VCARD data is inserted.");
- return null;
- }
-
- // For name, there are three fields in vCard: FN, N, NAME.
- // We prefer FN, which is a required field in vCard 3.0 , but not in vCard 2.1.
- // Next, we prefer NAME, which is defined only in vCard 3.0.
- // Finally, we use N, which is a little difficult to parse.
- String fullName = null;
- String nameFromNProperty = null;
-
- // Some vCard has "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", and
- // "X-PHONETIC-LAST-NAME"
- String xPhoneticFirstName = null;
- String xPhoneticMiddleName = null;
- String xPhoneticLastName = null;
-
- ContactStruct contact = new ContactStruct();
-
- // Each Column of four properties has ISPRIMARY field
- // (See android.provider.Contacts)
- // If false even after the following loop, we choose the first
- // entry as a "primary" entry.
- boolean prefIsSetAddress = false;
- boolean prefIsSetPhone = false;
- boolean prefIsSetEmail = false;
- boolean prefIsSetOrganization = false;
-
- for (PropertyNode propertyNode: node.propList) {
- String name = propertyNode.propName;
-
- if (TextUtils.isEmpty(propertyNode.propValue)) {
- continue;
- }
-
- if (name.equals("VERSION")) {
- // vCard version. Ignore this.
- } else if (name.equals("FN")) {
- fullName = propertyNode.propValue;
- } else if (name.equals("NAME") && fullName == null) {
- // Only in vCard 3.0. Use this if FN does not exist.
- // Though, note that vCard 3.0 requires FN.
- fullName = propertyNode.propValue;
- } else if (name.equals("N")) {
- nameFromNProperty = getNameFromNProperty(propertyNode.propValue_vector,
- nameOrderType);
- } else if (name.equals("SORT-STRING")) {
- contact.phoneticName = propertyNode.propValue;
- } else if (name.equals("SOUND")) {
- if (propertyNode.paramMap_TYPE.contains("X-IRMC-N") &&
- contact.phoneticName == null) {
- // Some Japanese mobile phones use this field for phonetic name,
- // since vCard 2.1 does not have "SORT-STRING" type.
- // Also, in some cases, the field has some ';' in it.
- // We remove them.
- StringBuilder builder = new StringBuilder();
- String value = propertyNode.propValue;
- int length = value.length();
- for (int i = 0; i < length; i++) {
- char ch = value.charAt(i);
- if (ch != ';') {
- builder.append(ch);
- }
- }
- contact.phoneticName = builder.toString();
- } else {
- contact.addExtension(propertyNode);
- }
- } else if (name.equals("ADR")) {
- List<String> values = propertyNode.propValue_vector;
- boolean valuesAreAllEmpty = true;
- for (String value : values) {
- if (value.length() > 0) {
- valuesAreAllEmpty = false;
- break;
- }
- }
- if (valuesAreAllEmpty) {
- continue;
- }
-
- int kind = Contacts.KIND_POSTAL;
- int type = -1;
- String label = "";
- boolean isPrimary = false;
- for (String typeString : propertyNode.paramMap_TYPE) {
- if (typeString.equals("PREF") && !prefIsSetAddress) {
- // Only first "PREF" is considered.
- prefIsSetAddress = true;
- isPrimary = true;
- } else if (typeString.equalsIgnoreCase("HOME")) {
- type = Contacts.ContactMethodsColumns.TYPE_HOME;
- label = "";
- } else if (typeString.equalsIgnoreCase("WORK") ||
- typeString.equalsIgnoreCase("COMPANY")) {
- // "COMPANY" seems emitted by Windows Mobile, which is not
- // specifically supported by vCard 2.1. We assume this is same
- // as "WORK".
- type = Contacts.ContactMethodsColumns.TYPE_WORK;
- label = "";
- } else if (typeString.equalsIgnoreCase("POSTAL")) {
- kind = Contacts.KIND_POSTAL;
- } else if (typeString.equalsIgnoreCase("PARCEL") ||
- typeString.equalsIgnoreCase("DOM") ||
- typeString.equalsIgnoreCase("INTL")) {
- // We do not have a kind or type matching these.
- // TODO: fix this. We may need to split entries into two.
- // (e.g. entries for KIND_POSTAL and KIND_PERCEL)
- } else if (typeString.toUpperCase().startsWith("X-") &&
- type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString.substring(2);
- } else if (type < 0) {
- // vCard 3.0 allows iana-token. Also some vCard 2.1 exporters
- // emit non-standard types. We do not handle their values now.
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString;
- }
- }
- // We use "HOME" as default
- if (type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_HOME;
- }
-
- // adr-value = 0*6(text-value ";") text-value
- // ; PO Box, Extended Address, Street, Locality, Region, Postal
- // ; Code, Country Name
- String address;
- List<String> list = propertyNode.propValue_vector;
- int size = list.size();
- if (size > 1) {
- StringBuilder builder = new StringBuilder();
- boolean builderIsEmpty = true;
- if (Locale.getDefault().getCountry().equals(Locale.JAPAN.getCountry())) {
- // In Japan, the order is reversed.
- for (int i = size - 1; i >= 0; i--) {
- String addressPart = list.get(i);
- if (addressPart.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(addressPart);
- builderIsEmpty = false;
- }
- }
- } else {
- for (int i = 0; i < size; i++) {
- String addressPart = list.get(i);
- if (addressPart.length() > 0) {
- if (!builderIsEmpty) {
- builder.append(' ');
- }
- builder.append(addressPart);
- builderIsEmpty = false;
- }
- }
- }
- address = builder.toString().trim();
- } else {
- address = propertyNode.propValue;
- }
- contact.addContactmethod(kind, type, address, label, isPrimary);
- } else if (name.equals("ORG")) {
- // vCard specification does not specify other types.
- int type = Contacts.OrganizationColumns.TYPE_WORK;
- boolean isPrimary = false;
-
- for (String typeString : propertyNode.paramMap_TYPE) {
- if (typeString.equals("PREF") && !prefIsSetOrganization) {
- // vCard specification officially does not have PREF in ORG.
- // This is just for safety.
- prefIsSetOrganization = true;
- isPrimary = true;
- }
- // XXX: Should we cope with X- words?
- }
-
- List<String> list = propertyNode.propValue_vector;
- int size = list.size();
- StringBuilder builder = new StringBuilder();
- for (Iterator<String> iter = list.iterator(); iter.hasNext();) {
- builder.append(iter.next());
- if (iter.hasNext()) {
- builder.append(' ');
- }
- }
-
- contact.addOrganization(type, builder.toString(), "", isPrimary);
- } else if (name.equals("TITLE")) {
- contact.setPosition(propertyNode.propValue);
- } else if (name.equals("ROLE")) {
- contact.setPosition(propertyNode.propValue);
- } else if (name.equals("PHOTO")) {
- // We prefer PHOTO to LOGO.
- String valueType = propertyNode.paramMap.getAsString("VALUE");
- if (valueType != null && valueType.equals("URL")) {
- // TODO: do something.
- } else {
- // Assume PHOTO is stored in BASE64. In that case,
- // data is already stored in propValue_bytes in binary form.
- // It should be automatically done by VBuilder (VDataBuilder/VCardDatabuilder)
- contact.photoBytes = propertyNode.propValue_bytes;
- String type = propertyNode.paramMap.getAsString("TYPE");
- if (type != null) {
- contact.photoType = type;
- }
- }
- } else if (name.equals("LOGO")) {
- // When PHOTO is not available this is not URL,
- // we use this instead of PHOTO.
- String valueType = propertyNode.paramMap.getAsString("VALUE");
- if (valueType != null && valueType.equals("URL")) {
- // TODO: do something.
- } else if (contact.photoBytes == null) {
- contact.photoBytes = propertyNode.propValue_bytes;
- String type = propertyNode.paramMap.getAsString("TYPE");
- if (type != null) {
- contact.photoType = type;
- }
- }
- } else if (name.equals("EMAIL")) {
- int type = -1;
- String label = null;
- boolean isPrimary = false;
- for (String typeString : propertyNode.paramMap_TYPE) {
- if (typeString.equals("PREF") && !prefIsSetEmail) {
- // Only first "PREF" is considered.
- prefIsSetEmail = true;
- isPrimary = true;
- } else if (typeString.equalsIgnoreCase("HOME")) {
- type = Contacts.ContactMethodsColumns.TYPE_HOME;
- } else if (typeString.equalsIgnoreCase("WORK")) {
- type = Contacts.ContactMethodsColumns.TYPE_WORK;
- } else if (typeString.equalsIgnoreCase("CELL")) {
- // We do not have Contacts.ContactMethodsColumns.TYPE_MOBILE yet.
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME;
- } else if (typeString.toUpperCase().startsWith("X-") &&
- type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString.substring(2);
- } else if (type < 0) {
- // vCard 3.0 allows iana-token.
- // We may have INTERNET (specified in vCard spec),
- // SCHOOL, etc.
- type = Contacts.ContactMethodsColumns.TYPE_CUSTOM;
- label = typeString;
- }
- }
- // We use "OTHER" as default.
- if (type < 0) {
- type = Contacts.ContactMethodsColumns.TYPE_OTHER;
- }
- contact.addContactmethod(Contacts.KIND_EMAIL,
- type, propertyNode.propValue,label, isPrimary);
- } else if (name.equals("TEL")) {
- int type = -1;
- String label = null;
- boolean isPrimary = false;
- boolean isFax = false;
- for (String typeString : propertyNode.paramMap_TYPE) {
- if (typeString.equals("PREF") && !prefIsSetPhone) {
- // Only first "PREF" is considered.
- prefIsSetPhone = true;
- isPrimary = true;
- } else if (typeString.equalsIgnoreCase("HOME")) {
- type = Contacts.PhonesColumns.TYPE_HOME;
- } else if (typeString.equalsIgnoreCase("WORK")) {
- type = Contacts.PhonesColumns.TYPE_WORK;
- } else if (typeString.equalsIgnoreCase("CELL")) {
- type = Contacts.PhonesColumns.TYPE_MOBILE;
- } else if (typeString.equalsIgnoreCase("PAGER")) {
- type = Contacts.PhonesColumns.TYPE_PAGER;
- } else if (typeString.equalsIgnoreCase("FAX")) {
- isFax = true;
- } else if (typeString.equalsIgnoreCase("VOICE") ||
- typeString.equalsIgnoreCase("MSG")) {
- // Defined in vCard 3.0. Ignore these because they
- // conflict with "HOME", "WORK", etc.
- // XXX: do something?
- } else if (typeString.toUpperCase().startsWith("X-") &&
- type < 0) {
- type = Contacts.PhonesColumns.TYPE_CUSTOM;
- label = typeString.substring(2);
- } else if (type < 0){
- // We may have MODEM, CAR, ISDN, etc...
- type = Contacts.PhonesColumns.TYPE_CUSTOM;
- label = typeString;
- }
- }
- // We use "HOME" as default
- if (type < 0) {
- type = Contacts.PhonesColumns.TYPE_HOME;
- }
- if (isFax) {
- if (type == Contacts.PhonesColumns.TYPE_HOME) {
- type = Contacts.PhonesColumns.TYPE_FAX_HOME;
- } else if (type == Contacts.PhonesColumns.TYPE_WORK) {
- type = Contacts.PhonesColumns.TYPE_FAX_WORK;
- }
- }
-
- contact.addPhone(type, propertyNode.propValue, label, isPrimary);
- } else if (name.equals("NOTE")) {
- contact.notes.add(propertyNode.propValue);
- } else if (name.equals("BDAY")) {
- contact.addExtension(propertyNode);
- } else if (name.equals("URL")) {
- contact.addExtension(propertyNode);
- } else if (name.equals("REV")) {
- // Revision of this VCard entry. I think we can ignore this.
- contact.addExtension(propertyNode);
- } else if (name.equals("UID")) {
- contact.addExtension(propertyNode);
- } else if (name.equals("KEY")) {
- // Type is X509 or PGP? I don't know how to handle this...
- contact.addExtension(propertyNode);
- } else if (name.equals("MAILER")) {
- contact.addExtension(propertyNode);
- } else if (name.equals("TZ")) {
- contact.addExtension(propertyNode);
- } else if (name.equals("GEO")) {
- contact.addExtension(propertyNode);
- } else if (name.equals("NICKNAME")) {
- // vCard 3.0 only.
- contact.addExtension(propertyNode);
- } else if (name.equals("CLASS")) {
- // vCard 3.0 only.
- // e.g. CLASS:CONFIDENTIAL
- contact.addExtension(propertyNode);
- } else if (name.equals("PROFILE")) {
- // VCard 3.0 only. Must be "VCARD". I think we can ignore this.
- contact.addExtension(propertyNode);
- } else if (name.equals("CATEGORIES")) {
- // VCard 3.0 only.
- // e.g. CATEGORIES:INTERNET,IETF,INDUSTRY,INFORMATION TECHNOLOGY
- contact.addExtension(propertyNode);
- } else if (name.equals("SOURCE")) {
- // VCard 3.0 only.
- contact.addExtension(propertyNode);
- } else if (name.equals("PRODID")) {
- // VCard 3.0 only.
- // To specify the identifier for the product that created
- // the vCard object.
- contact.addExtension(propertyNode);
- } else if (name.equals("X-PHONETIC-FIRST-NAME")) {
- xPhoneticFirstName = propertyNode.propValue;
- } else if (name.equals("X-PHONETIC-MIDDLE-NAME")) {
- xPhoneticMiddleName = propertyNode.propValue;
- } else if (name.equals("X-PHONETIC-LAST-NAME")) {
- xPhoneticLastName = propertyNode.propValue;
- } else {
- // Unknown X- words and IANA token.
- contact.addExtension(propertyNode);
- }
- }
-
- if (fullName != null) {
- contact.name = fullName;
- } else if(nameFromNProperty != null) {
- contact.name = nameFromNProperty;
- } else {
- contact.name = "";
- }
-
- if (contact.phoneticName == null &&
- (xPhoneticFirstName != null || xPhoneticMiddleName != null ||
- xPhoneticLastName != null)) {
- // Note: In Europe, this order should be "LAST FIRST MIDDLE". See the comment around
- // NAME_ORDER_TYPE_* for more detail.
- String first;
- String second;
- if (nameOrderType == NAME_ORDER_TYPE_JAPANESE) {
- first = xPhoneticLastName;
- second = xPhoneticFirstName;
- } else {
- first = xPhoneticFirstName;
- second = xPhoneticLastName;
- }
- StringBuilder builder = new StringBuilder();
- if (first != null) {
- builder.append(first);
- }
- if (xPhoneticMiddleName != null) {
- builder.append(xPhoneticMiddleName);
- }
- if (second != null) {
- builder.append(second);
- }
- contact.phoneticName = builder.toString();
- }
-
- // Remove unnecessary white spaces.
- // It is found that some mobile phone emits phonetic name with just one white space
- // when a user does not specify one.
- // This logic is effective toward such kind of weird data.
- if (contact.phoneticName != null) {
- contact.phoneticName = contact.phoneticName.trim();
- }
-
- // If there is no "PREF", we choose the first entries as primary.
- if (!prefIsSetPhone &&
- contact.phoneList != null &&
- contact.phoneList.size() > 0) {
- contact.phoneList.get(0).isPrimary = true;
- }
-
- if (!prefIsSetAddress && contact.contactmethodList != null) {
- for (ContactMethod contactMethod : contact.contactmethodList) {
- if (contactMethod.kind == Contacts.KIND_POSTAL) {
- contactMethod.isPrimary = true;
- break;
- }
- }
- }
- if (!prefIsSetEmail && contact.contactmethodList != null) {
- for (ContactMethod contactMethod : contact.contactmethodList) {
- if (contactMethod.kind == Contacts.KIND_EMAIL) {
- contactMethod.isPrimary = true;
- break;
- }
- }
- }
- if (!prefIsSetOrganization &&
- contact.organizationList != null &&
- contact.organizationList.size() > 0) {
- contact.organizationList.get(0).isPrimary = true;
- }
-
- return contact;
- }
-
- public String displayString() {
- if (name.length() > 0) {
- return name;
- }
- if (contactmethodList != null && contactmethodList.size() > 0) {
- for (ContactMethod contactMethod : contactmethodList) {
- if (contactMethod.kind == Contacts.KIND_EMAIL && contactMethod.isPrimary) {
- return contactMethod.data;
- }
- }
- }
- if (phoneList != null && phoneList.size() > 0) {
- for (PhoneData phoneData : phoneList) {
- if (phoneData.isPrimary) {
- return phoneData.data;
- }
- }
- }
- return "";
- }
-
- private void pushIntoContentProviderOrResolver(Object contentSomething,
- long myContactsGroupId) {
- ContentResolver resolver = null;
- AbstractSyncableContentProvider provider = null;
- if (contentSomething instanceof ContentResolver) {
- resolver = (ContentResolver)contentSomething;
- } else if (contentSomething instanceof AbstractSyncableContentProvider) {
- provider = (AbstractSyncableContentProvider)contentSomething;
- } else {
- Log.e(LOG_TAG, "Unsupported object came.");
- return;
- }
-
- ContentValues contentValues = new ContentValues();
- contentValues.put(People.NAME, name);
- contentValues.put(People.PHONETIC_NAME, phoneticName);
-
- if (notes.size() > 1) {
- StringBuilder builder = new StringBuilder();
- for (String note : notes) {
- builder.append(note);
- builder.append("\n");
- }
- contentValues.put(People.NOTES, builder.toString());
- } else if (notes.size() == 1){
- contentValues.put(People.NOTES, notes.get(0));
- }
-
- Uri personUri;
- long personId = 0;
- if (resolver != null) {
- personUri = Contacts.People.createPersonInMyContactsGroup(
- resolver, contentValues);
- if (personUri != null) {
- personId = ContentUris.parseId(personUri);
- }
- } else {
- personUri = provider.insert(People.CONTENT_URI, contentValues);
- if (personUri != null) {
- personId = ContentUris.parseId(personUri);
- ContentValues values = new ContentValues();
- values.put(GroupMembership.PERSON_ID, personId);
- values.put(GroupMembership.GROUP_ID, myContactsGroupId);
- Uri resultUri = provider.insert(GroupMembership.CONTENT_URI, values);
- if (resultUri == null) {
- Log.e(LOG_TAG, "Faild to insert the person to MyContact.");
- provider.delete(personUri, null, null);
- personUri = null;
- }
- }
- }
-
- if (personUri == null) {
- Log.e(LOG_TAG, "Failed to create the contact.");
- return;
- }
-
- if (photoBytes != null) {
- if (resolver != null) {
- People.setPhotoData(resolver, personUri, photoBytes);
- } else {
- Uri photoUri = Uri.withAppendedPath(personUri, Contacts.Photos.CONTENT_DIRECTORY);
- ContentValues values = new ContentValues();
- values.put(Photos.DATA, photoBytes);
- provider.update(photoUri, values, null, null);
- }
- }
-
- long primaryPhoneId = -1;
- if (phoneList != null && phoneList.size() > 0) {
- for (PhoneData phoneData : phoneList) {
- ContentValues values = new ContentValues();
- values.put(Contacts.PhonesColumns.TYPE, phoneData.type);
- if (phoneData.type == Contacts.PhonesColumns.TYPE_CUSTOM) {
- values.put(Contacts.PhonesColumns.LABEL, phoneData.label);
- }
- // Already formatted.
- values.put(Contacts.PhonesColumns.NUMBER, phoneData.data);
-
- // Not sure about Contacts.PhonesColumns.NUMBER_KEY ...
- values.put(Contacts.PhonesColumns.ISPRIMARY, 1);
- values.put(Contacts.Phones.PERSON_ID, personId);
- Uri phoneUri;
- if (resolver != null) {
- phoneUri = resolver.insert(Phones.CONTENT_URI, values);
- } else {
- phoneUri = provider.insert(Phones.CONTENT_URI, values);
- }
- if (phoneData.isPrimary) {
- primaryPhoneId = Long.parseLong(phoneUri.getLastPathSegment());
- }
- }
- }
-
- long primaryOrganizationId = -1;
- if (organizationList != null && organizationList.size() > 0) {
- for (OrganizationData organizationData : organizationList) {
- ContentValues values = new ContentValues();
- // Currently, we do not use TYPE_CUSTOM.
- values.put(Contacts.OrganizationColumns.TYPE,
- organizationData.type);
- values.put(Contacts.OrganizationColumns.COMPANY,
- organizationData.companyName);
- values.put(Contacts.OrganizationColumns.TITLE,
- organizationData.positionName);
- values.put(Contacts.OrganizationColumns.ISPRIMARY, 1);
- values.put(Contacts.OrganizationColumns.PERSON_ID, personId);
-
- Uri organizationUri;
- if (resolver != null) {
- organizationUri = resolver.insert(Organizations.CONTENT_URI, values);
- } else {
- organizationUri = provider.insert(Organizations.CONTENT_URI, values);
- }
- if (organizationData.isPrimary) {
- primaryOrganizationId = Long.parseLong(organizationUri.getLastPathSegment());
- }
- }
- }
-
- long primaryEmailId = -1;
- if (contactmethodList != null && contactmethodList.size() > 0) {
- for (ContactMethod contactMethod : contactmethodList) {
- ContentValues values = new ContentValues();
- values.put(Contacts.ContactMethodsColumns.KIND, contactMethod.kind);
- values.put(Contacts.ContactMethodsColumns.TYPE, contactMethod.type);
- if (contactMethod.type == Contacts.ContactMethodsColumns.TYPE_CUSTOM) {
- values.put(Contacts.ContactMethodsColumns.LABEL, contactMethod.label);
- }
- values.put(Contacts.ContactMethodsColumns.DATA, contactMethod.data);
- values.put(Contacts.ContactMethodsColumns.ISPRIMARY, 1);
- values.put(Contacts.ContactMethods.PERSON_ID, personId);
-
- if (contactMethod.kind == Contacts.KIND_EMAIL) {
- Uri emailUri;
- if (resolver != null) {
- emailUri = resolver.insert(ContactMethods.CONTENT_URI, values);
- } else {
- emailUri = provider.insert(ContactMethods.CONTENT_URI, values);
- }
- if (contactMethod.isPrimary) {
- primaryEmailId = Long.parseLong(emailUri.getLastPathSegment());
- }
- } else { // probably KIND_POSTAL
- if (resolver != null) {
- resolver.insert(ContactMethods.CONTENT_URI, values);
- } else {
- provider.insert(ContactMethods.CONTENT_URI, values);
- }
- }
- }
- }
-
- if (extensionMap != null && extensionMap.size() > 0) {
- ArrayList<ContentValues> contentValuesArray;
- if (resolver != null) {
- contentValuesArray = new ArrayList<ContentValues>();
- } else {
- contentValuesArray = null;
- }
- for (Entry<String, List<String>> entry : extensionMap.entrySet()) {
- String key = entry.getKey();
- List<String> list = entry.getValue();
- for (String value : list) {
- ContentValues values = new ContentValues();
- values.put(Extensions.NAME, key);
- values.put(Extensions.VALUE, value);
- values.put(Extensions.PERSON_ID, personId);
- if (resolver != null) {
- contentValuesArray.add(values);
- } else {
- provider.insert(Extensions.CONTENT_URI, values);
- }
- }
- }
- if (resolver != null) {
- resolver.bulkInsert(Extensions.CONTENT_URI,
- contentValuesArray.toArray(new ContentValues[0]));
- }
- }
-
- if (primaryPhoneId >= 0 || primaryOrganizationId >= 0 || primaryEmailId >= 0) {
- ContentValues values = new ContentValues();
- if (primaryPhoneId >= 0) {
- values.put(People.PRIMARY_PHONE_ID, primaryPhoneId);
- }
- if (primaryOrganizationId >= 0) {
- values.put(People.PRIMARY_ORGANIZATION_ID, primaryOrganizationId);
- }
- if (primaryEmailId >= 0) {
- values.put(People.PRIMARY_EMAIL_ID, primaryEmailId);
- }
- if (resolver != null) {
- resolver.update(personUri, values, null, null);
- } else {
- provider.update(personUri, values, null, null);
- }
- }
- }
-
- /**
- * Push this object into database in the resolver.
- */
- public void pushIntoContentResolver(ContentResolver resolver) {
- pushIntoContentProviderOrResolver(resolver, 0);
- }
-
- /**
- * Push this object into AbstractSyncableContentProvider object.
- */
- public void pushIntoAbstractSyncableContentProvider(
- AbstractSyncableContentProvider provider, long myContactsGroupId) {
- boolean successful = false;
- provider.beginBatch();
- try {
- pushIntoContentProviderOrResolver(provider, myContactsGroupId);
- successful = true;
- } finally {
- provider.endBatch(successful);
- }
- }
-
- public boolean isIgnorable() {
- return TextUtils.isEmpty(name) &&
- TextUtils.isEmpty(phoneticName) &&
- (phoneList == null || phoneList.size() == 0) &&
- (contactmethodList == null || contactmethodList.size() == 0);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.codec.binary.Base64;
-
-import android.provider.Contacts;
-import android.syncml.pim.vcard.ContactStruct.PhoneData;
-
-/**
- * Compose VCard string
- */
-@Deprecated
-public class VCardComposer {
- final public static int VERSION_VCARD21_INT = 1;
-
- final public static int VERSION_VCARD30_INT = 2;
-
- /**
- * A new line
- */
- private String mNewline;
-
- /**
- * The composed string
- */
- private StringBuilder mResult;
-
- /**
- * The email's type
- */
- static final private HashSet<String> emailTypes = new HashSet<String>(
- Arrays.asList("CELL", "AOL", "APPLELINK", "ATTMAIL", "CIS",
- "EWORLD", "INTERNET", "IBMMAIL", "MCIMAIL", "POWERSHARE",
- "PRODIGY", "TLX", "X400"));
-
- static final private HashSet<String> phoneTypes = new HashSet<String>(
- Arrays.asList("PREF", "WORK", "HOME", "VOICE", "FAX", "MSG",
- "CELL", "PAGER", "BBS", "MODEM", "CAR", "ISDN", "VIDEO"));
-
- static final private String TAG = "VCardComposer";
-
- public VCardComposer() {
- }
-
- private static final HashMap<Integer, String> phoneTypeMap = new HashMap<Integer, String>();
-
- private static final HashMap<Integer, String> emailTypeMap = new HashMap<Integer, String>();
-
- static {
- phoneTypeMap.put(Contacts.Phones.TYPE_HOME, "HOME");
- phoneTypeMap.put(Contacts.Phones.TYPE_MOBILE, "CELL");
- phoneTypeMap.put(Contacts.Phones.TYPE_WORK, "WORK");
- // FAX_WORK not exist in vcard spec. The approximate is the combine of
- // WORK and FAX, here only map to FAX
- phoneTypeMap.put(Contacts.Phones.TYPE_FAX_WORK, "WORK;FAX");
- phoneTypeMap.put(Contacts.Phones.TYPE_FAX_HOME, "HOME;FAX");
- phoneTypeMap.put(Contacts.Phones.TYPE_PAGER, "PAGER");
- phoneTypeMap.put(Contacts.Phones.TYPE_OTHER, "X-OTHER");
- emailTypeMap.put(Contacts.ContactMethods.TYPE_HOME, "HOME");
- emailTypeMap.put(Contacts.ContactMethods.TYPE_WORK, "WORK");
- }
-
- /**
- * Create a vCard String.
- *
- * @param struct
- * see more from ContactStruct class
- * @param vcardversion
- * MUST be VERSION_VCARD21 /VERSION_VCARD30
- * @return vCard string
- * @throws VCardException
- * struct.name is null /vcardversion not match
- */
- public String createVCard(ContactStruct struct, int vcardversion)
- throws VCardException {
-
- mResult = new StringBuilder();
- // check exception:
- if (struct.name == null || struct.name.trim().equals("")) {
- throw new VCardException(" struct.name MUST have value.");
- }
- if (vcardversion == VERSION_VCARD21_INT) {
- mNewline = "\r\n";
- } else if (vcardversion == VERSION_VCARD30_INT) {
- mNewline = "\n";
- } else {
- throw new VCardException(
- " version not match VERSION_VCARD21 or VERSION_VCARD30.");
- }
- // build vcard:
- mResult.append("BEGIN:VCARD").append(mNewline);
-
- if (vcardversion == VERSION_VCARD21_INT) {
- mResult.append("VERSION:2.1").append(mNewline);
- } else {
- mResult.append("VERSION:3.0").append(mNewline);
- }
-
- if (!isNull(struct.name)) {
- appendNameStr(struct.name);
- }
-
- if (!isNull(struct.company)) {
- mResult.append("ORG:").append(struct.company).append(mNewline);
- }
-
- if (struct.notes.size() > 0 && !isNull(struct.notes.get(0))) {
- mResult.append("NOTE:").append(
- foldingString(struct.notes.get(0), vcardversion)).append(mNewline);
- }
-
- if (!isNull(struct.title)) {
- mResult.append("TITLE:").append(
- foldingString(struct.title, vcardversion)).append(mNewline);
- }
-
- if (struct.photoBytes != null) {
- appendPhotoStr(struct.photoBytes, struct.photoType, vcardversion);
- }
-
- if (struct.phoneList != null) {
- appendPhoneStr(struct.phoneList, vcardversion);
- }
-
- if (struct.contactmethodList != null) {
- appendContactMethodStr(struct.contactmethodList, vcardversion);
- }
-
- if (!isNull(struct.timeStamp)) {
- mResult.append(struct.timeStamp).append(mNewline);
- }
-
- mResult.append("END:VCARD").append(mNewline);
- return mResult.toString();
- }
-
- /**
- * Alter str to folding supported format.
- *
- * @param str
- * the string to be folded
- * @param version
- * the vcard version
- * @return the folded string
- */
- private String foldingString(String str, int version) {
- if (str.endsWith("\r\n")) {
- str = str.substring(0, str.length() - 2);
- } else if (str.endsWith("\n")) {
- str = str.substring(0, str.length() - 1);
- } else {
- return null;
- }
-
- str = str.replaceAll("\r\n", "\n");
- if (version == VERSION_VCARD21_INT) {
- return str.replaceAll("\n", "\r\n ");
- } else if (version == VERSION_VCARD30_INT) {
- return str.replaceAll("\n", "\n ");
- } else {
- return null;
- }
- }
-
- /**
- * Build LOGO property. format LOGO's param and encode value as base64.
- *
- * @param bytes
- * the binary string to be converted
- * @param type
- * the type of the content
- * @param version
- * the version of vcard
- */
- private void appendPhotoStr(byte[] bytes, String type, int version)
- throws VCardException {
- String value, encodingStr;
- try {
- value = foldingString(new String(Base64.encodeBase64(bytes, true)),
- version);
- } catch (Exception e) {
- throw new VCardException(e.getMessage());
- }
-
- if (isNull(type) || type.toUpperCase().indexOf("JPEG") >= 0) {
- type = "JPEG";
- } else if (type.toUpperCase().indexOf("GIF") >= 0) {
- type = "GIF";
- } else if (type.toUpperCase().indexOf("BMP") >= 0) {
- type = "BMP";
- } else {
- // Handle the string like "image/tiff".
- int indexOfSlash = type.indexOf("/");
- if (indexOfSlash >= 0) {
- type = type.substring(indexOfSlash + 1).toUpperCase();
- } else {
- type = type.toUpperCase();
- }
- }
-
- mResult.append("LOGO;TYPE=").append(type);
- if (version == VERSION_VCARD21_INT) {
- encodingStr = ";ENCODING=BASE64:";
- value = value + mNewline;
- } else if (version == VERSION_VCARD30_INT) {
- encodingStr = ";ENCODING=b:";
- } else {
- return;
- }
- mResult.append(encodingStr).append(value).append(mNewline);
- }
-
- private boolean isNull(String str) {
- if (str == null || str.trim().equals("")) {
- return true;
- }
- return false;
- }
-
- /**
- * Build FN and N property. format N's value.
- *
- * @param name
- * the name of the contact
- */
- private void appendNameStr(String name) {
- mResult.append("FN:").append(name).append(mNewline);
- mResult.append("N:").append(name).append(mNewline);
- /*
- * if(name.indexOf(";") > 0)
- * mResult.append("N:").append(name).append(mNewline); else
- * if(name.indexOf(" ") > 0) mResult.append("N:").append(name.replace(' ',
- * ';')). append(mNewline); else
- * mResult.append("N:").append(name).append("; ").append(mNewline);
- */
- }
-
- /** Loop append TEL property. */
- private void appendPhoneStr(List<ContactStruct.PhoneData> phoneList,
- int version) {
- HashMap<String, String> numMap = new HashMap<String, String>();
- String joinMark = version == VERSION_VCARD21_INT ? ";" : ",";
-
- for (ContactStruct.PhoneData phone : phoneList) {
- String type;
- if (!isNull(phone.data)) {
- type = getPhoneTypeStr(phone);
- if (version == VERSION_VCARD30_INT && type.indexOf(";") != -1) {
- type = type.replace(";", ",");
- }
- if (numMap.containsKey(phone.data)) {
- type = numMap.get(phone.data) + joinMark + type;
- }
- numMap.put(phone.data, type);
- }
- }
-
- for (Map.Entry<String, String> num : numMap.entrySet()) {
- if (version == VERSION_VCARD21_INT) {
- mResult.append("TEL;");
- } else { // vcard3.0
- mResult.append("TEL;TYPE=");
- }
- mResult.append(num.getValue()).append(":").append(num.getKey())
- .append(mNewline);
- }
- }
-
- private String getPhoneTypeStr(PhoneData phone) {
-
- int phoneType = phone.type;
- String typeStr, label;
-
- if (phoneTypeMap.containsKey(phoneType)) {
- typeStr = phoneTypeMap.get(phoneType);
- } else if (phoneType == Contacts.Phones.TYPE_CUSTOM) {
- label = phone.label.toUpperCase();
- if (phoneTypes.contains(label) || label.startsWith("X-")) {
- typeStr = label;
- } else {
- typeStr = "X-CUSTOM-" + label;
- }
- } else {
- // TODO: need be updated with the provider's future changes
- typeStr = "VOICE"; // the default type is VOICE in spec.
- }
- return typeStr;
- }
-
- /** Loop append ADR / EMAIL property. */
- private void appendContactMethodStr(
- List<ContactStruct.ContactMethod> contactMList, int version) {
-
- HashMap<String, String> emailMap = new HashMap<String, String>();
- String joinMark = version == VERSION_VCARD21_INT ? ";" : ",";
- for (ContactStruct.ContactMethod contactMethod : contactMList) {
- // same with v2.1 and v3.0
- switch (contactMethod.kind) {
- case Contacts.KIND_EMAIL:
- String mailType = "INTERNET";
- if (!isNull(contactMethod.data)) {
- int methodType = new Integer(contactMethod.type).intValue();
- if (emailTypeMap.containsKey(methodType)) {
- mailType = emailTypeMap.get(methodType);
- } else if (emailTypes.contains(contactMethod.label
- .toUpperCase())) {
- mailType = contactMethod.label.toUpperCase();
- }
- if (emailMap.containsKey(contactMethod.data)) {
- mailType = emailMap.get(contactMethod.data) + joinMark
- + mailType;
- }
- emailMap.put(contactMethod.data, mailType);
- }
- break;
- case Contacts.KIND_POSTAL:
- if (!isNull(contactMethod.data)) {
- mResult.append("ADR;TYPE=POSTAL:").append(
- foldingString(contactMethod.data, version)).append(
- mNewline);
- }
- break;
- default:
- break;
- }
- }
- for (Map.Entry<String, String> email : emailMap.entrySet()) {
- if (version == VERSION_VCARD21_INT) {
- mResult.append("EMAIL;");
- } else {
- mResult.append("EMAIL;TYPE=");
- }
- mResult.append(email.getValue()).append(":").append(email.getKey())
- .append(mNewline);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import android.app.ProgressDialog;
-import android.content.AbstractSyncableContentProvider;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.IContentProvider;
-import android.os.Handler;
-import android.provider.Contacts;
-import android.syncml.pim.PropertyNode;
-import android.syncml.pim.VBuilder;
-import android.syncml.pim.VNode;
-import android.syncml.pim.VParser;
-import android.text.TextUtils;
-import android.util.CharsetUtils;
-import android.util.Log;
-
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.net.QuotedPrintableCodec;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * VBuilder for VCard. VCard may contain big photo images encoded by BASE64,
- * If we store all VNode entries in memory like VDataBuilder.java,
- * OutOfMemoryError may be thrown. Thus, this class push each VCard entry into
- * ContentResolver immediately.
- */
-@Deprecated
-public class VCardDataBuilder implements VBuilder {
- static private String LOG_TAG = "VCardDataBuilder";
-
- /**
- * If there's no other information available, this class uses this charset for encoding
- * byte arrays.
- */
- static public String DEFAULT_CHARSET = "UTF-8";
-
- private class ProgressShower implements Runnable {
- private ContactStruct mContact;
-
- public ProgressShower(ContactStruct contact) {
- mContact = contact;
- }
-
- public void run () {
- mProgressDialog.setMessage(mProgressMessage + "\n" +
- mContact.displayString());
- }
- }
-
- /** type=VNode */
- private VNode mCurrentVNode;
- private PropertyNode mCurrentPropNode;
- private String mCurrentParamType;
-
- /**
- * The charset using which VParser parses the text.
- */
- private String mSourceCharset;
-
- /**
- * The charset with which byte array is encoded to String.
- */
- private String mTargetCharset;
- private boolean mStrictLineBreakParsing;
- private ContentResolver mContentResolver;
-
- // For letting VCardDataBuilder show the display name of VCard while handling it.
- private Handler mHandler;
- private ProgressDialog mProgressDialog;
- private String mProgressMessage;
- private Runnable mOnProgressRunnable;
- private boolean mLastNameComesBeforeFirstName;
-
- // Just for testing.
- private long mTimeCreateContactStruct;
- private long mTimePushIntoContentResolver;
-
- // Ideally, this should be ContactsProvider but it seems Class loader cannot find it,
- // even when it is subclass of ContactsProvider...
- private AbstractSyncableContentProvider mProvider;
- private long mMyContactsGroupId;
-
- public VCardDataBuilder(ContentResolver resolver) {
- mTargetCharset = DEFAULT_CHARSET;
- mContentResolver = resolver;
- }
-
- /**
- * Constructor which requires minimum requiredvariables.
- *
- * @param resolver insert each data into this ContentResolver
- * @param progressDialog
- * @param progressMessage
- * @param handler if this importer works on the different thread than main one,
- * set appropriate handler object. If not, it is ok to set this null.
- */
- public VCardDataBuilder(ContentResolver resolver,
- ProgressDialog progressDialog,
- String progressMessage,
- Handler handler) {
- this(resolver, progressDialog, progressMessage, handler,
- null, null, false, false);
- }
-
- public VCardDataBuilder(ContentResolver resolver,
- ProgressDialog progressDialog,
- String progressMessage,
- Handler handler,
- String charset,
- boolean strictLineBreakParsing,
- boolean lastNameComesBeforeFirstName) {
- this(resolver, progressDialog, progressMessage, handler,
- null, charset, strictLineBreakParsing,
- lastNameComesBeforeFirstName);
- }
-
- /**
- * @hide
- */
- public VCardDataBuilder(ContentResolver resolver,
- ProgressDialog progressDialog,
- String progressMessage,
- Handler handler,
- String sourceCharset,
- String targetCharset,
- boolean strictLineBreakParsing,
- boolean lastNameComesBeforeFirstName) {
- if (sourceCharset != null) {
- mSourceCharset = sourceCharset;
- } else {
- mSourceCharset = VParser.DEFAULT_CHARSET;
- }
- if (targetCharset != null) {
- mTargetCharset = targetCharset;
- } else {
- mTargetCharset = DEFAULT_CHARSET;
- }
- mContentResolver = resolver;
- mStrictLineBreakParsing = strictLineBreakParsing;
- mHandler = handler;
- mProgressDialog = progressDialog;
- mProgressMessage = progressMessage;
- mLastNameComesBeforeFirstName = lastNameComesBeforeFirstName;
-
- tryGetOriginalProvider();
- }
-
- private void tryGetOriginalProvider() {
- final ContentResolver resolver = mContentResolver;
-
- if ((mMyContactsGroupId = Contacts.People.tryGetMyContactsGroupId(resolver)) == 0) {
- Log.e(LOG_TAG, "Could not get group id of MyContact");
- return;
- }
-
- IContentProvider iProviderForName = resolver.acquireProvider(Contacts.CONTENT_URI);
- ContentProvider contentProvider =
- ContentProvider.coerceToLocalContentProvider(iProviderForName);
- if (contentProvider == null) {
- Log.e(LOG_TAG, "Fail to get ContentProvider object.");
- return;
- }
-
- if (!(contentProvider instanceof AbstractSyncableContentProvider)) {
- Log.e(LOG_TAG,
- "Acquired ContentProvider object is not AbstractSyncableContentProvider.");
- return;
- }
-
- mProvider = (AbstractSyncableContentProvider)contentProvider;
- }
-
- public void setOnProgressRunnable(Runnable runnable) {
- mOnProgressRunnable = runnable;
- }
-
- public void start() {
- }
-
- public void end() {
- }
-
- /**
- * Assume that VCard is not nested. In other words, this code does not accept
- */
- public void startRecord(String type) {
- if (mCurrentVNode != null) {
- // This means startRecord() is called inside startRecord() - endRecord() block.
- // TODO: should throw some Exception
- Log.e(LOG_TAG, "Nested VCard code is not supported now.");
- }
- mCurrentVNode = new VNode();
- mCurrentVNode.parseStatus = 1;
- mCurrentVNode.VName = type;
- }
-
- public void endRecord() {
- mCurrentVNode.parseStatus = 0;
- long start = System.currentTimeMillis();
- ContactStruct contact = ContactStruct.constructContactFromVNode(mCurrentVNode,
- mLastNameComesBeforeFirstName ? ContactStruct.NAME_ORDER_TYPE_JAPANESE :
- ContactStruct.NAME_ORDER_TYPE_ENGLISH);
- mTimeCreateContactStruct += System.currentTimeMillis() - start;
- if (!contact.isIgnorable()) {
- if (mProgressDialog != null && mProgressMessage != null) {
- if (mHandler != null) {
- mHandler.post(new ProgressShower(contact));
- } else {
- mProgressDialog.setMessage(mProgressMessage + "\n" +
- contact.displayString());
- }
- }
- start = System.currentTimeMillis();
- if (mProvider != null) {
- contact.pushIntoAbstractSyncableContentProvider(
- mProvider, mMyContactsGroupId);
- } else {
- contact.pushIntoContentResolver(mContentResolver);
- }
- mTimePushIntoContentResolver += System.currentTimeMillis() - start;
- }
- if (mOnProgressRunnable != null) {
- mOnProgressRunnable.run();
- }
- mCurrentVNode = null;
- }
-
- public void startProperty() {
- mCurrentPropNode = new PropertyNode();
- }
-
- public void endProperty() {
- mCurrentVNode.propList.add(mCurrentPropNode);
- mCurrentPropNode = null;
- }
-
- public void propertyName(String name) {
- mCurrentPropNode.propName = name;
- }
-
- public void propertyGroup(String group) {
- mCurrentPropNode.propGroupSet.add(group);
- }
-
- public void propertyParamType(String type) {
- mCurrentParamType = type;
- }
-
- public void propertyParamValue(String value) {
- if (mCurrentParamType == null ||
- mCurrentParamType.equalsIgnoreCase("TYPE")) {
- mCurrentPropNode.paramMap_TYPE.add(value);
- } else {
- mCurrentPropNode.paramMap.put(mCurrentParamType, value);
- }
-
- mCurrentParamType = null;
- }
-
- private String encodeString(String originalString, String targetCharset) {
- if (mSourceCharset.equalsIgnoreCase(targetCharset)) {
- return originalString;
- }
- Charset charset = Charset.forName(mSourceCharset);
- ByteBuffer byteBuffer = charset.encode(originalString);
- // byteBuffer.array() "may" return byte array which is larger than
- // byteBuffer.remaining(). Here, we keep on the safe side.
- byte[] bytes = new byte[byteBuffer.remaining()];
- byteBuffer.get(bytes);
- try {
- return new String(bytes, targetCharset);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
- return new String(bytes);
- }
- }
-
- private String handleOneValue(String value, String targetCharset, String encoding) {
- if (encoding != null) {
- if (encoding.equals("BASE64") || encoding.equals("B")) {
- mCurrentPropNode.propValue_bytes =
- Base64.decodeBase64(value.getBytes());
- return value;
- } else if (encoding.equals("QUOTED-PRINTABLE")) {
- // "= " -> " ", "=\t" -> "\t".
- // Previous code had done this replacement. Keep on the safe side.
- StringBuilder builder = new StringBuilder();
- int length = value.length();
- for (int i = 0; i < length; i++) {
- char ch = value.charAt(i);
- if (ch == '=' && i < length - 1) {
- char nextCh = value.charAt(i + 1);
- if (nextCh == ' ' || nextCh == '\t') {
-
- builder.append(nextCh);
- i++;
- continue;
- }
- }
- builder.append(ch);
- }
- String quotedPrintable = builder.toString();
-
- String[] lines;
- if (mStrictLineBreakParsing) {
- lines = quotedPrintable.split("\r\n");
- } else {
- builder = new StringBuilder();
- length = quotedPrintable.length();
- ArrayList<String> list = new ArrayList<String>();
- for (int i = 0; i < length; i++) {
- char ch = quotedPrintable.charAt(i);
- if (ch == '\n') {
- list.add(builder.toString());
- builder = new StringBuilder();
- } else if (ch == '\r') {
- list.add(builder.toString());
- builder = new StringBuilder();
- if (i < length - 1) {
- char nextCh = quotedPrintable.charAt(i + 1);
- if (nextCh == '\n') {
- i++;
- }
- }
- } else {
- builder.append(ch);
- }
- }
- String finalLine = builder.toString();
- if (finalLine.length() > 0) {
- list.add(finalLine);
- }
- lines = list.toArray(new String[0]);
- }
-
- builder = new StringBuilder();
- for (String line : lines) {
- if (line.endsWith("=")) {
- line = line.substring(0, line.length() - 1);
- }
- builder.append(line);
- }
- byte[] bytes;
- try {
- bytes = builder.toString().getBytes(mSourceCharset);
- } catch (UnsupportedEncodingException e1) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + mSourceCharset);
- bytes = builder.toString().getBytes();
- }
-
- try {
- bytes = QuotedPrintableCodec.decodeQuotedPrintable(bytes);
- } catch (DecoderException e) {
- Log.e(LOG_TAG, "Failed to decode quoted-printable: " + e);
- return "";
- }
-
- try {
- return new String(bytes, targetCharset);
- } catch (UnsupportedEncodingException e) {
- Log.e(LOG_TAG, "Failed to encode: charset=" + targetCharset);
- return new String(bytes);
- }
- }
- // Unknown encoding. Fall back to default.
- }
- return encodeString(value, targetCharset);
- }
-
- public void propertyValues(List<String> values) {
- if (values == null || values.size() == 0) {
- mCurrentPropNode.propValue_bytes = null;
- mCurrentPropNode.propValue_vector.clear();
- mCurrentPropNode.propValue_vector.add("");
- mCurrentPropNode.propValue = "";
- return;
- }
-
- ContentValues paramMap = mCurrentPropNode.paramMap;
-
- String targetCharset = CharsetUtils.nameForDefaultVendor(paramMap.getAsString("CHARSET"));
- String encoding = paramMap.getAsString("ENCODING");
-
- Log.d("@@@", String.format("targetCharset: \"%s\", encoding: \"%s\"",
- targetCharset, encoding));
-
- if (TextUtils.isEmpty(targetCharset)) {
- targetCharset = mTargetCharset;
- }
-
- for (String value : values) {
- mCurrentPropNode.propValue_vector.add(
- handleOneValue(value, targetCharset, encoding));
- }
-
- mCurrentPropNode.propValue = listToString(mCurrentPropNode.propValue_vector);
- }
-
- public void showDebugInfo() {
- Log.d(LOG_TAG, "time for creating ContactStruct: " + mTimeCreateContactStruct + " ms");
- Log.d(LOG_TAG, "time for insert ContactStruct to database: " +
- mTimePushIntoContentResolver + " ms");
- }
-
- private String listToString(List<String> list){
- int size = list.size();
- if (size > 1) {
- StringBuilder builder = new StringBuilder();
- int i = 0;
- for (String type : list) {
- builder.append(type);
- if (i < size - 1) {
- builder.append(";");
- }
- }
- return builder.toString();
- } else if (size == 1) {
- return list.get(0);
- } else {
- return "";
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import java.util.List;
-
-import android.syncml.pim.VBuilder;
-
-@Deprecated
-public class VCardEntryCounter implements VBuilder {
- private int mCount;
-
- public int getCount() {
- return mCount;
- }
-
- public void start() {
- }
-
- public void end() {
- }
-
- public void startRecord(String type) {
- }
-
- public void endRecord() {
- mCount++;
- }
-
- public void startProperty() {
- }
-
- public void endProperty() {
- }
-
- public void propertyGroup(String group) {
- }
-
- public void propertyName(String name) {
- }
-
- public void propertyParamType(String type) {
- }
-
- public void propertyParamValue(String value) {
- }
-
- public void propertyValues(List<String> values) {
- }
-}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-@Deprecated
-public class VCardException extends java.lang.Exception{
- // constructors
-
- /**
- * Constructs a VCardException object
- */
-
- public VCardException()
- {
- }
-
- /**
- * Constructs a VCardException object
- *
- * @param message the error message
- */
-
- public VCardException( String message )
- {
- super( message );
- }
-
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-/**
- * VCardException thrown when VCard is nested without VCardParser's being notified.
- */
-@Deprecated
-public class VCardNestedException extends VCardException {
- public VCardNestedException() {}
- public VCardNestedException(String message) {
- super(message);
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import android.syncml.pim.VDataBuilder;
-import android.util.Config;
-import android.util.Log;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-@Deprecated
-public class VCardParser {
-
- // TODO: fix this.
- VCardParser_V21 mParser = null;
-
- public final static String VERSION_VCARD21 = "vcard2.1";
-
- public final static String VERSION_VCARD30 = "vcard3.0";
-
- final public static int VERSION_VCARD21_INT = 1;
-
- final public static int VERSION_VCARD30_INT = 2;
-
- String mVersion = null;
-
- static final private String TAG = "VCardParser";
-
- public VCardParser() {
- }
-
- /**
- * If version not given. Search from vcard string of the VERSION property.
- * Then instance mParser to appropriate parser.
- *
- * @param vcardStr
- * the content of vcard data
- */
- private void judgeVersion(String vcardStr) {
- if (mVersion == null) {// auto judge
- int verIdx = vcardStr.indexOf("\nVERSION:");
- if (verIdx == -1) // if not have VERSION, v2.1 default
- mVersion = VERSION_VCARD21;
- else {
- String verStr = vcardStr.substring(verIdx, vcardStr.indexOf(
- "\n", verIdx + 1));
- if (verStr.indexOf("2.1") > 0)
- mVersion = VERSION_VCARD21;
- else if (verStr.indexOf("3.0") > 0)
- mVersion = VERSION_VCARD30;
- else
- mVersion = VERSION_VCARD21;
- }
- }
- if (mVersion.equals(VERSION_VCARD21))
- mParser = new VCardParser_V21();
- if (mVersion.equals(VERSION_VCARD30))
- mParser = new VCardParser_V30();
- }
-
- /**
- * To make sure the vcard string has proper wrap character
- *
- * @param vcardStr
- * the string to be checked
- * @return string after verified
- */
- private String verifyVCard(String vcardStr) {
- this.judgeVersion(vcardStr);
- // -- indent line:
- vcardStr = vcardStr.replaceAll("\r\n", "\n");
- String[] strlist = vcardStr.split("\n");
- StringBuilder v21str = new StringBuilder("");
- for (int i = 0; i < strlist.length; i++) {
- if (strlist[i].indexOf(":") < 0) {
- if (strlist[i].length() == 0 && strlist[i + 1].indexOf(":") > 0)
- v21str.append(strlist[i]).append("\r\n");
- else
- v21str.append(" ").append(strlist[i]).append("\r\n");
- } else
- v21str.append(strlist[i]).append("\r\n");
- }
- return v21str.toString();
- }
-
- /**
- * Set current version
- *
- * @param version
- * the new version
- */
- private void setVersion(String version) {
- this.mVersion = version;
- }
-
- /**
- * Parse the given vcard string
- *
- * @param vcardStr
- * to content to be parsed
- * @param builder
- * the data builder to hold data
- * @return true if the string is successfully parsed, else return false
- * @throws VCardException
- * @throws IOException
- */
- public boolean parse(String vcardStr, VDataBuilder builder)
- throws VCardException, IOException {
-
- vcardStr = this.verifyVCard(vcardStr);
-
- boolean isSuccess = mParser.parse(new ByteArrayInputStream(vcardStr
- .getBytes()), "US-ASCII", builder);
- if (!isSuccess) {
- if (mVersion.equals(VERSION_VCARD21)) {
- if (Config.LOGD)
- Log.d(TAG, "Parse failed for vCard 2.1 parser."
- + " Try to use 3.0 parser.");
-
- this.setVersion(VERSION_VCARD30);
-
- return this.parse(vcardStr, builder);
- }
- throw new VCardException("parse failed.(even use 3.0 parser)");
- }
- return true;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import android.syncml.pim.VBuilder;
-import android.syncml.pim.VParser;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-
-/**
- * This class is used to parse vcard. Please refer to vCard Specification 2.1.
- */
-@Deprecated
-public class VCardParser_V21 {
- private static final String LOG_TAG = "VCardParser_V21";
-
- public static final String DEFAULT_CHARSET = VParser.DEFAULT_CHARSET;
-
- /** Store the known-type */
- private static final HashSet<String> sKnownTypeSet = new HashSet<String>(
- Arrays.asList("DOM", "INTL", "POSTAL", "PARCEL", "HOME", "WORK",
- "PREF", "VOICE", "FAX", "MSG", "CELL", "PAGER", "BBS",
- "MODEM", "CAR", "ISDN", "VIDEO", "AOL", "APPLELINK",
- "ATTMAIL", "CIS", "EWORLD", "INTERNET", "IBMMAIL",
- "MCIMAIL", "POWERSHARE", "PRODIGY", "TLX", "X400", "GIF",
- "CGM", "WMF", "BMP", "MET", "PMB", "DIB", "PICT", "TIFF",
- "PDF", "PS", "JPEG", "QTIME", "MPEG", "MPEG2", "AVI",
- "WAVE", "AIFF", "PCM", "X509", "PGP"));
-
- /** Store the known-value */
- private static final HashSet<String> sKnownValueSet = new HashSet<String>(
- Arrays.asList("INLINE", "URL", "CONTENT-ID", "CID"));
-
- /** Store the property names available in vCard 2.1 */
- private static final HashSet<String> sAvailablePropertyNameV21 =
- new HashSet<String>(Arrays.asList(
- "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
- "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
- "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER"));
-
- // Though vCard 2.1 specification does not allow "B" encoding, some data may have it.
- // We allow it for safety...
- private static final HashSet<String> sAvailableEncodingV21 =
- new HashSet<String>(Arrays.asList(
- "7BIT", "8BIT", "QUOTED-PRINTABLE", "BASE64", "B"));
-
- // Used only for parsing END:VCARD.
- private String mPreviousLine;
-
- /** The builder to build parsed data */
- protected VBuilder mBuilder = null;
-
- /** The encoding type */
- protected String mEncoding = null;
-
- protected final String sDefaultEncoding = "8BIT";
-
- // Should not directly read a line from this. Use getLine() instead.
- protected BufferedReader mReader;
-
- private boolean mCanceled;
-
- // In some cases, vCard is nested. Currently, we only consider the most interior vCard data.
- // See v21_foma_1.vcf in test directory for more information.
- private int mNestCount;
-
- // In order to reduce warning message as much as possible, we hold the value which made Logger
- // emit a warning message.
- protected HashSet<String> mWarningValueMap = new HashSet<String>();
-
- // Just for debugging
- private long mTimeTotal;
- private long mTimeStartRecord;
- private long mTimeEndRecord;
- private long mTimeStartProperty;
- private long mTimeEndProperty;
- private long mTimeParseItems;
- private long mTimeParseItem1;
- private long mTimeParseItem2;
- private long mTimeParseItem3;
- private long mTimeHandlePropertyValue1;
- private long mTimeHandlePropertyValue2;
- private long mTimeHandlePropertyValue3;
-
- /**
- * Create a new VCard parser.
- */
- public VCardParser_V21() {
- super();
- }
-
- public VCardParser_V21(VCardSourceDetector detector) {
- super();
- if (detector != null && detector.getType() == VCardSourceDetector.TYPE_FOMA) {
- mNestCount = 1;
- }
- }
-
- /**
- * Parse the file at the given position
- * vcard_file = [wsls] vcard [wsls]
- */
- protected void parseVCardFile() throws IOException, VCardException {
- boolean firstReading = true;
- while (true) {
- if (mCanceled) {
- break;
- }
- if (!parseOneVCard(firstReading)) {
- break;
- }
- firstReading = false;
- }
-
- if (mNestCount > 0) {
- boolean useCache = true;
- for (int i = 0; i < mNestCount; i++) {
- readEndVCard(useCache, true);
- useCache = false;
- }
- }
- }
-
- protected String getVersion() {
- return "2.1";
- }
-
- /**
- * @return true when the propertyName is a valid property name.
- */
- protected boolean isValidPropertyName(String propertyName) {
- if (!(sAvailablePropertyNameV21.contains(propertyName.toUpperCase()) ||
- propertyName.startsWith("X-")) &&
- !mWarningValueMap.contains(propertyName)) {
- mWarningValueMap.add(propertyName);
- Log.w(LOG_TAG, "Property name unsupported by vCard 2.1: " + propertyName);
- }
- return true;
- }
-
- /**
- * @return true when the encoding is a valid encoding.
- */
- protected boolean isValidEncoding(String encoding) {
- return sAvailableEncodingV21.contains(encoding.toUpperCase());
- }
-
- /**
- * @return String. It may be null, or its length may be 0
- * @throws IOException
- */
- protected String getLine() throws IOException {
- return mReader.readLine();
- }
-
- /**
- * @return String with it's length > 0
- * @throws IOException
- * @throws VCardException when the stream reached end of line
- */
- protected String getNonEmptyLine() throws IOException, VCardException {
- String line;
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException("Reached end of buffer.");
- } else if (line.trim().length() > 0) {
- return line;
- }
- }
- }
-
- /**
- * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
- * items *CRLF
- * "END" [ws] ":" [ws] "VCARD"
- */
- private boolean parseOneVCard(boolean firstReading) throws IOException, VCardException {
- boolean allowGarbage = false;
- if (firstReading) {
- if (mNestCount > 0) {
- for (int i = 0; i < mNestCount; i++) {
- if (!readBeginVCard(allowGarbage)) {
- return false;
- }
- allowGarbage = true;
- }
- }
- }
-
- if (!readBeginVCard(allowGarbage)) {
- return false;
- }
- long start;
- if (mBuilder != null) {
- start = System.currentTimeMillis();
- mBuilder.startRecord("VCARD");
- mTimeStartRecord += System.currentTimeMillis() - start;
- }
- start = System.currentTimeMillis();
- parseItems();
- mTimeParseItems += System.currentTimeMillis() - start;
- readEndVCard(true, false);
- if (mBuilder != null) {
- start = System.currentTimeMillis();
- mBuilder.endRecord();
- mTimeEndRecord += System.currentTimeMillis() - start;
- }
- return true;
- }
-
- /**
- * @return True when successful. False when reaching the end of line
- * @throws IOException
- * @throws VCardException
- */
- protected boolean readBeginVCard(boolean allowGarbage)
- throws IOException, VCardException {
- String line;
- do {
- while (true) {
- line = getLine();
- if (line == null) {
- return false;
- } else if (line.trim().length() > 0) {
- break;
- }
- }
- String[] strArray = line.split(":", 2);
- int length = strArray.length;
-
- // Though vCard 2.1/3.0 specification does not allow lower cases,
- // some data may have them, so we allow it (Actually, previous code
- // had explicitly allowed "BEGIN:vCard" though there's no example).
- //
- // TODO: ignore non vCard entry (e.g. vcalendar).
- // XXX: Not sure, but according to VDataBuilder.java, vcalendar
- // entry
- // may be nested. Just seeking "END:SOMETHING" may not be enough.
- // e.g.
- // BEGIN:VCARD
- // ... (Valid. Must parse this)
- // END:VCARD
- // BEGIN:VSOMETHING
- // ... (Must ignore this)
- // BEGIN:VSOMETHING2
- // ... (Must ignore this)
- // END:VSOMETHING2
- // ... (Must ignore this!)
- // END:VSOMETHING
- // BEGIN:VCARD
- // ... (Valid. Must parse this)
- // END:VCARD
- // INVALID_STRING (VCardException should be thrown)
- if (length == 2 &&
- strArray[0].trim().equalsIgnoreCase("BEGIN") &&
- strArray[1].trim().equalsIgnoreCase("VCARD")) {
- return true;
- } else if (!allowGarbage) {
- if (mNestCount > 0) {
- mPreviousLine = line;
- return false;
- } else {
- throw new VCardException(
- "Expected String \"BEGIN:VCARD\" did not come "
- + "(Instead, \"" + line + "\" came)");
- }
- }
- } while(allowGarbage);
-
- throw new VCardException("Reached where must not be reached.");
- }
-
- /**
- * The arguments useCache and allowGarbase are usually true and false accordingly when
- * this function is called outside this function itself.
- *
- * @param useCache When true, line is obtained from mPreviousline. Otherwise, getLine()
- * is used.
- * @param allowGarbage When true, ignore non "END:VCARD" line.
- * @throws IOException
- * @throws VCardException
- */
- protected void readEndVCard(boolean useCache, boolean allowGarbage)
- throws IOException, VCardException {
- String line;
- do {
- if (useCache) {
- // Though vCard specification does not allow lower cases,
- // some data may have them, so we allow it.
- line = mPreviousLine;
- } else {
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException("Expected END:VCARD was not found.");
- } else if (line.trim().length() > 0) {
- break;
- }
- }
- }
-
- String[] strArray = line.split(":", 2);
- if (strArray.length == 2 &&
- strArray[0].trim().equalsIgnoreCase("END") &&
- strArray[1].trim().equalsIgnoreCase("VCARD")) {
- return;
- } else if (!allowGarbage) {
- throw new VCardException("END:VCARD != \"" + mPreviousLine + "\"");
- }
- useCache = false;
- } while (allowGarbage);
- }
-
- /**
- * items = *CRLF item
- * / item
- */
- protected void parseItems() throws IOException, VCardException {
- /* items *CRLF item / item */
- boolean ended = false;
-
- if (mBuilder != null) {
- long start = System.currentTimeMillis();
- mBuilder.startProperty();
- mTimeStartProperty += System.currentTimeMillis() - start;
- }
- ended = parseItem();
- if (mBuilder != null && !ended) {
- long start = System.currentTimeMillis();
- mBuilder.endProperty();
- mTimeEndProperty += System.currentTimeMillis() - start;
- }
-
- while (!ended) {
- // follow VCARD ,it wont reach endProperty
- if (mBuilder != null) {
- long start = System.currentTimeMillis();
- mBuilder.startProperty();
- mTimeStartProperty += System.currentTimeMillis() - start;
- }
- ended = parseItem();
- if (mBuilder != null && !ended) {
- long start = System.currentTimeMillis();
- mBuilder.endProperty();
- mTimeEndProperty += System.currentTimeMillis() - start;
- }
- }
- }
-
- /**
- * item = [groups "."] name [params] ":" value CRLF
- * / [groups "."] "ADR" [params] ":" addressparts CRLF
- * / [groups "."] "ORG" [params] ":" orgparts CRLF
- * / [groups "."] "N" [params] ":" nameparts CRLF
- * / [groups "."] "AGENT" [params] ":" vcard CRLF
- */
- protected boolean parseItem() throws IOException, VCardException {
- mEncoding = sDefaultEncoding;
-
- String line = getNonEmptyLine();
- long start = System.currentTimeMillis();
-
- String[] propertyNameAndValue = separateLineAndHandleGroup(line);
- if (propertyNameAndValue == null) {
- return true;
- }
- if (propertyNameAndValue.length != 2) {
- throw new VCardException("Invalid line \"" + line + "\"");
- }
- String propertyName = propertyNameAndValue[0].toUpperCase();
- String propertyValue = propertyNameAndValue[1];
-
- mTimeParseItem1 += System.currentTimeMillis() - start;
-
- if (propertyName.equals("ADR") ||
- propertyName.equals("ORG") ||
- propertyName.equals("N")) {
- start = System.currentTimeMillis();
- handleMultiplePropertyValue(propertyName, propertyValue);
- mTimeParseItem3 += System.currentTimeMillis() - start;
- return false;
- } else if (propertyName.equals("AGENT")) {
- handleAgent(propertyValue);
- return false;
- } else if (isValidPropertyName(propertyName)) {
- if (propertyName.equals("BEGIN")) {
- if (propertyValue.equals("VCARD")) {
- throw new VCardNestedException("This vCard has nested vCard data in it.");
- } else {
- throw new VCardException("Unknown BEGIN type: " + propertyValue);
- }
- } else if (propertyName.equals("VERSION") &&
- !propertyValue.equals(getVersion())) {
- throw new VCardVersionException("Incompatible version: " +
- propertyValue + " != " + getVersion());
- }
- start = System.currentTimeMillis();
- handlePropertyValue(propertyName, propertyValue);
- mTimeParseItem2 += System.currentTimeMillis() - start;
- return false;
- }
-
- throw new VCardException("Unknown property name: \"" +
- propertyName + "\"");
- }
-
- static private final int STATE_GROUP_OR_PROPNAME = 0;
- static private final int STATE_PARAMS = 1;
- // vCard 3.1 specification allows double-quoted param-value, while vCard 2.1 does not.
- // This is just for safety.
- static private final int STATE_PARAMS_IN_DQUOTE = 2;
-
- protected String[] separateLineAndHandleGroup(String line) throws VCardException {
- int length = line.length();
- int state = STATE_GROUP_OR_PROPNAME;
- int nameIndex = 0;
-
- String[] propertyNameAndValue = new String[2];
-
- for (int i = 0; i < length; i++) {
- char ch = line.charAt(i);
- switch (state) {
- case STATE_GROUP_OR_PROPNAME:
- if (ch == ':') {
- String propertyName = line.substring(nameIndex, i);
- if (propertyName.equalsIgnoreCase("END")) {
- mPreviousLine = line;
- return null;
- }
- if (mBuilder != null) {
- mBuilder.propertyName(propertyName);
- }
- propertyNameAndValue[0] = propertyName;
- if (i < length - 1) {
- propertyNameAndValue[1] = line.substring(i + 1);
- } else {
- propertyNameAndValue[1] = "";
- }
- return propertyNameAndValue;
- } else if (ch == '.') {
- String groupName = line.substring(nameIndex, i);
- if (mBuilder != null) {
- mBuilder.propertyGroup(groupName);
- }
- nameIndex = i + 1;
- } else if (ch == ';') {
- String propertyName = line.substring(nameIndex, i);
- if (propertyName.equalsIgnoreCase("END")) {
- mPreviousLine = line;
- return null;
- }
- if (mBuilder != null) {
- mBuilder.propertyName(propertyName);
- }
- propertyNameAndValue[0] = propertyName;
- nameIndex = i + 1;
- state = STATE_PARAMS;
- }
- break;
- case STATE_PARAMS:
- if (ch == '"') {
- state = STATE_PARAMS_IN_DQUOTE;
- } else if (ch == ';') {
- handleParams(line.substring(nameIndex, i));
- nameIndex = i + 1;
- } else if (ch == ':') {
- handleParams(line.substring(nameIndex, i));
- if (i < length - 1) {
- propertyNameAndValue[1] = line.substring(i + 1);
- } else {
- propertyNameAndValue[1] = "";
- }
- return propertyNameAndValue;
- }
- break;
- case STATE_PARAMS_IN_DQUOTE:
- if (ch == '"') {
- state = STATE_PARAMS;
- }
- break;
- }
- }
-
- throw new VCardException("Invalid line: \"" + line + "\"");
- }
-
-
- /**
- * params = ";" [ws] paramlist
- * paramlist = paramlist [ws] ";" [ws] param
- * / param
- * param = "TYPE" [ws] "=" [ws] ptypeval
- * / "VALUE" [ws] "=" [ws] pvalueval
- * / "ENCODING" [ws] "=" [ws] pencodingval
- * / "CHARSET" [ws] "=" [ws] charsetval
- * / "LANGUAGE" [ws] "=" [ws] langval
- * / "X-" word [ws] "=" [ws] word
- * / knowntype
- */
- protected void handleParams(String params) throws VCardException {
- String[] strArray = params.split("=", 2);
- if (strArray.length == 2) {
- String paramName = strArray[0].trim();
- String paramValue = strArray[1].trim();
- if (paramName.equals("TYPE")) {
- handleType(paramValue);
- } else if (paramName.equals("VALUE")) {
- handleValue(paramValue);
- } else if (paramName.equals("ENCODING")) {
- handleEncoding(paramValue);
- } else if (paramName.equals("CHARSET")) {
- handleCharset(paramValue);
- } else if (paramName.equals("LANGUAGE")) {
- handleLanguage(paramValue);
- } else if (paramName.startsWith("X-")) {
- handleAnyParam(paramName, paramValue);
- } else {
- throw new VCardException("Unknown type \"" + paramName + "\"");
- }
- } else {
- handleType(strArray[0]);
- }
- }
-
- /**
- * ptypeval = knowntype / "X-" word
- */
- protected void handleType(String ptypeval) {
- String upperTypeValue = ptypeval;
- if (!(sKnownTypeSet.contains(upperTypeValue) || upperTypeValue.startsWith("X-")) &&
- !mWarningValueMap.contains(ptypeval)) {
- mWarningValueMap.add(ptypeval);
- Log.w(LOG_TAG, "Type unsupported by vCard 2.1: " + ptypeval);
- }
- if (mBuilder != null) {
- mBuilder.propertyParamType("TYPE");
- mBuilder.propertyParamValue(upperTypeValue);
- }
- }
-
- /**
- * pvalueval = "INLINE" / "URL" / "CONTENT-ID" / "CID" / "X-" word
- */
- protected void handleValue(String pvalueval) throws VCardException {
- if (sKnownValueSet.contains(pvalueval.toUpperCase()) ||
- pvalueval.startsWith("X-")) {
- if (mBuilder != null) {
- mBuilder.propertyParamType("VALUE");
- mBuilder.propertyParamValue(pvalueval);
- }
- } else {
- throw new VCardException("Unknown value \"" + pvalueval + "\"");
- }
- }
-
- /**
- * pencodingval = "7BIT" / "8BIT" / "QUOTED-PRINTABLE" / "BASE64" / "X-" word
- */
- protected void handleEncoding(String pencodingval) throws VCardException {
- if (isValidEncoding(pencodingval) ||
- pencodingval.startsWith("X-")) {
- if (mBuilder != null) {
- mBuilder.propertyParamType("ENCODING");
- mBuilder.propertyParamValue(pencodingval);
- }
- mEncoding = pencodingval;
- } else {
- throw new VCardException("Unknown encoding \"" + pencodingval + "\"");
- }
- }
-
- /**
- * vCard specification only allows us-ascii and iso-8859-xxx (See RFC 1521),
- * but some vCard contains other charset, so we allow them.
- */
- protected void handleCharset(String charsetval) {
- if (mBuilder != null) {
- mBuilder.propertyParamType("CHARSET");
- mBuilder.propertyParamValue(charsetval);
- }
- }
-
- /**
- * See also Section 7.1 of RFC 1521
- */
- protected void handleLanguage(String langval) throws VCardException {
- String[] strArray = langval.split("-");
- if (strArray.length != 2) {
- throw new VCardException("Invalid Language: \"" + langval + "\"");
- }
- String tmp = strArray[0];
- int length = tmp.length();
- for (int i = 0; i < length; i++) {
- if (!isLetter(tmp.charAt(i))) {
- throw new VCardException("Invalid Language: \"" + langval + "\"");
- }
- }
- tmp = strArray[1];
- length = tmp.length();
- for (int i = 0; i < length; i++) {
- if (!isLetter(tmp.charAt(i))) {
- throw new VCardException("Invalid Language: \"" + langval + "\"");
- }
- }
- if (mBuilder != null) {
- mBuilder.propertyParamType("LANGUAGE");
- mBuilder.propertyParamValue(langval);
- }
- }
-
- /**
- * Mainly for "X-" type. This accepts any kind of type without check.
- */
- protected void handleAnyParam(String paramName, String paramValue) {
- if (mBuilder != null) {
- mBuilder.propertyParamType(paramName);
- mBuilder.propertyParamValue(paramValue);
- }
- }
-
- protected void handlePropertyValue(
- String propertyName, String propertyValue) throws
- IOException, VCardException {
- if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
- long start = System.currentTimeMillis();
- String result = getQuotedPrintable(propertyValue);
- if (mBuilder != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(result);
- mBuilder.propertyValues(v);
- }
- mTimeHandlePropertyValue2 += System.currentTimeMillis() - start;
- } else if (mEncoding.equalsIgnoreCase("BASE64") ||
- mEncoding.equalsIgnoreCase("B")) {
- long start = System.currentTimeMillis();
- // It is very rare, but some BASE64 data may be so big that
- // OutOfMemoryError occurs. To ignore such cases, use try-catch.
- try {
- String result = getBase64(propertyValue);
- if (mBuilder != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(result);
- mBuilder.propertyValues(v);
- }
- } catch (OutOfMemoryError error) {
- Log.e(LOG_TAG, "OutOfMemoryError happened during parsing BASE64 data!");
- if (mBuilder != null) {
- mBuilder.propertyValues(null);
- }
- }
- mTimeHandlePropertyValue3 += System.currentTimeMillis() - start;
- } else {
- if (!(mEncoding == null || mEncoding.equalsIgnoreCase("7BIT")
- || mEncoding.equalsIgnoreCase("8BIT")
- || mEncoding.toUpperCase().startsWith("X-"))) {
- Log.w(LOG_TAG, "The encoding unsupported by vCard spec: \"" + mEncoding + "\".");
- }
-
- long start = System.currentTimeMillis();
- if (mBuilder != null) {
- ArrayList<String> v = new ArrayList<String>();
- v.add(maybeUnescapeText(propertyValue));
- mBuilder.propertyValues(v);
- }
- mTimeHandlePropertyValue1 += System.currentTimeMillis() - start;
- }
- }
-
- protected String getQuotedPrintable(String firstString) throws IOException, VCardException {
- // Specifically, there may be some padding between = and CRLF.
- // See the following:
- //
- // qp-line := *(qp-segment transport-padding CRLF)
- // qp-part transport-padding
- // qp-segment := qp-section *(SPACE / TAB) "="
- // ; Maximum length of 76 characters
- //
- // e.g. (from RFC 2045)
- // Now's the time =
- // for all folk to come=
- // to the aid of their country.
- if (firstString.trim().endsWith("=")) {
- // remove "transport-padding"
- int pos = firstString.length() - 1;
- while(firstString.charAt(pos) != '=') {
- }
- StringBuilder builder = new StringBuilder();
- builder.append(firstString.substring(0, pos + 1));
- builder.append("\r\n");
- String line;
- while (true) {
- line = getLine();
- if (line == null) {
- throw new VCardException(
- "File ended during parsing quoted-printable String");
- }
- if (line.trim().endsWith("=")) {
- // remove "transport-padding"
- pos = line.length() - 1;
- while(line.charAt(pos) != '=') {
- }
- builder.append(line.substring(0, pos + 1));
- builder.append("\r\n");
- } else {
- builder.append(line);
- break;
- }
- }
- return builder.toString();
- } else {
- return firstString;
- }
- }
-
- protected String getBase64(String firstString) throws IOException, VCardException {
- StringBuilder builder = new StringBuilder();
- builder.append(firstString);
-
- while (true) {
- String line = getLine();
- if (line == null) {
- throw new VCardException(
- "File ended during parsing BASE64 binary");
- }
- if (line.length() == 0) {
- break;
- }
- builder.append(line);
- }
-
- return builder.toString();
- }
-
- /**
- * Mainly for "ADR", "ORG", and "N"
- * We do not care the number of strnosemi here.
- *
- * addressparts = 0*6(strnosemi ";") strnosemi
- * ; PO Box, Extended Addr, Street, Locality, Region,
- * Postal Code, Country Name
- * orgparts = *(strnosemi ";") strnosemi
- * ; First is Organization Name,
- * remainder are Organization Units.
- * nameparts = 0*4(strnosemi ";") strnosemi
- * ; Family, Given, Middle, Prefix, Suffix.
- * ; Example:Public;John;Q.;Reverend Dr.;III, Esq.
- * strnosemi = *(*nonsemi ("\;" / "\" CRLF)) *nonsemi
- * ; To include a semicolon in this string, it must be escaped
- * ; with a "\" character.
- *
- * We are not sure whether we should add "\" CRLF to each value.
- * For now, we exclude them.
- */
- protected void handleMultiplePropertyValue(
- String propertyName, String propertyValue) throws IOException, VCardException {
- // vCard 2.1 does not allow QUOTED-PRINTABLE here, but some data have it.
- if (mEncoding.equalsIgnoreCase("QUOTED-PRINTABLE")) {
- propertyValue = getQuotedPrintable(propertyValue);
- }
-
- if (mBuilder != null) {
- // TODO: limit should be set in accordance with propertyName?
- StringBuilder builder = new StringBuilder();
- ArrayList<String> list = new ArrayList<String>();
- int length = propertyValue.length();
- for (int i = 0; i < length; i++) {
- char ch = propertyValue.charAt(i);
- if (ch == '\\' && i < length - 1) {
- char nextCh = propertyValue.charAt(i + 1);
- String unescapedString = maybeUnescape(nextCh);
- if (unescapedString != null) {
- builder.append(unescapedString);
- i++;
- } else {
- builder.append(ch);
- }
- } else if (ch == ';') {
- list.add(builder.toString());
- builder = new StringBuilder();
- } else {
- builder.append(ch);
- }
- }
- list.add(builder.toString());
- mBuilder.propertyValues(list);
- }
- }
-
- /**
- * vCard 2.1 specifies AGENT allows one vcard entry. It is not encoded at all.
- *
- * item = ...
- * / [groups "."] "AGENT"
- * [params] ":" vcard CRLF
- * vcard = "BEGIN" [ws] ":" [ws] "VCARD" [ws] 1*CRLF
- * items *CRLF "END" [ws] ":" [ws] "VCARD"
- *
- */
- protected void handleAgent(String propertyValue) throws VCardException {
- throw new VCardException("AGENT Property is not supported.");
- /* This is insufficient support. Also, AGENT Property is very rare.
- Ignore it for now.
- TODO: fix this.
-
- String[] strArray = propertyValue.split(":", 2);
- if (!(strArray.length == 2 ||
- strArray[0].trim().equalsIgnoreCase("BEGIN") &&
- strArray[1].trim().equalsIgnoreCase("VCARD"))) {
- throw new VCardException("BEGIN:VCARD != \"" + propertyValue + "\"");
- }
- parseItems();
- readEndVCard();
- */
- }
-
- /**
- * For vCard 3.0.
- */
- protected String maybeUnescapeText(String text) {
- return text;
- }
-
- /**
- * Returns unescaped String if the character should be unescaped. Return null otherwise.
- * e.g. In vCard 2.1, "\;" should be unescaped into ";" while "\x" should not be.
- */
- protected String maybeUnescape(char ch) {
- // Original vCard 2.1 specification does not allow transformation
- // "\:" -> ":", "\," -> ",", and "\\" -> "\", but previous implementation of
- // this class allowed them, so keep it as is.
- if (ch == '\\' || ch == ';' || ch == ':' || ch == ',') {
- return String.valueOf(ch);
- } else {
- return null;
- }
- }
-
- /**
- * Parse the given stream and constructs VCardDataBuilder object.
- * Note that vCard 2.1 specification allows "CHARSET" parameter, and some career sets
- * local encoding to it. For example, Japanese phone career uses Shift_JIS, which
- * is not formally allowed in vCard specification.
- * As a result, there is a case where the encoding given here does not do well with
- * the "CHARSET".
- *
- * In order to avoid such cases, It may be fine to use "ISO-8859-1" as an encoding,
- * and to encode each localized String afterward.
- *
- * RFC 2426 "recommends" (not forces) to use UTF-8, so it may be OK to use
- * UTF-8 as an encoding when parsing vCard 3.0. But note that some Japanese
- * phone uses Shift_JIS as a charset (e.g. W61SH), and another uses
- * "CHARSET=SHIFT_JIS", which is explicitly prohibited in vCard 3.0 specification
- * (e.g. W53K).
- *
- * @param is
- * The source to parse.
- * @param charset
- * The charset.
- * @param builder
- * The v builder which used to construct data.
- * @return Return true for success, otherwise false.
- * @throws IOException
- */
- public boolean parse(InputStream is, String charset, VBuilder builder)
- throws IOException, VCardException {
- // TODO: make this count error entries instead of just throwing VCardException.
-
- // TODO: If we really need to allow only CRLF as line break,
- // we will have to develop our own BufferedReader().
- mReader = new CustomBufferedReader(new InputStreamReader(is, charset));
-
- mBuilder = builder;
-
- long start = System.currentTimeMillis();
- if (mBuilder != null) {
- mBuilder.start();
- }
- parseVCardFile();
- if (mBuilder != null) {
- mBuilder.end();
- }
- mTimeTotal += System.currentTimeMillis() - start;
-
- return true;
- }
-
- public boolean parse(InputStream is, VBuilder builder) throws IOException, VCardException {
- return parse(is, DEFAULT_CHARSET, builder);
- }
-
- /**
- * Cancel parsing.
- * Actual cancel is done after the end of the current one vcard entry parsing.
- */
- public void cancel() {
- mCanceled = true;
- }
-
- /**
- * It is very, very rare case, but there is a case where
- * canceled may be already true outside this object.
- * @hide
- */
- public void parse(InputStream is, String charset, VBuilder builder, boolean canceled)
- throws IOException, VCardException {
- mCanceled = canceled;
- parse(is, charset, builder);
- }
-
- public void showDebugInfo() {
- Log.d(LOG_TAG, "total parsing time: " + mTimeTotal + " ms");
- if (mReader instanceof CustomBufferedReader) {
- Log.d(LOG_TAG, "total readLine time: " +
- ((CustomBufferedReader)mReader).getTotalmillisecond() + " ms");
- }
- Log.d(LOG_TAG, "mTimeStartRecord: " + mTimeStartRecord + " ms");
- Log.d(LOG_TAG, "mTimeEndRecord: " + mTimeEndRecord + " ms");
- Log.d(LOG_TAG, "mTimeParseItem1: " + mTimeParseItem1 + " ms");
- Log.d(LOG_TAG, "mTimeParseItem2: " + mTimeParseItem2 + " ms");
- Log.d(LOG_TAG, "mTimeParseItem3: " + mTimeParseItem3 + " ms");
- Log.d(LOG_TAG, "mTimeHandlePropertyValue1: " + mTimeHandlePropertyValue1 + " ms");
- Log.d(LOG_TAG, "mTimeHandlePropertyValue2: " + mTimeHandlePropertyValue2 + " ms");
- Log.d(LOG_TAG, "mTimeHandlePropertyValue3: " + mTimeHandlePropertyValue3 + " ms");
- }
-
- private boolean isLetter(char ch) {
- if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
- return true;
- }
- return false;
- }
-}
-
-class CustomBufferedReader extends BufferedReader {
- private long mTime;
-
- public CustomBufferedReader(Reader in) {
- super(in);
- }
-
- @Override
- public String readLine() throws IOException {
- long start = System.currentTimeMillis();
- String ret = super.readLine();
- long end = System.currentTimeMillis();
- mTime += end - start;
- return ret;
- }
-
- public long getTotalmillisecond() {
- return mTime;
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import android.util.Log;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashSet;
-
-/**
- * This class is used to parse vcard3.0. <br>
- * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426)
- */
-@Deprecated
-public class VCardParser_V30 extends VCardParser_V21 {
- private static final String LOG_TAG = "VCardParser_V30";
-
- private static final HashSet<String> acceptablePropsWithParam = new HashSet<String>(
- Arrays.asList(
- "BEGIN", "LOGO", "PHOTO", "LABEL", "FN", "TITLE", "SOUND",
- "VERSION", "TEL", "EMAIL", "TZ", "GEO", "NOTE", "URL",
- "BDAY", "ROLE", "REV", "UID", "KEY", "MAILER", // 2.1
- "NAME", "PROFILE", "SOURCE", "NICKNAME", "CLASS",
- "SORT-STRING", "CATEGORIES", "PRODID")); // 3.0
-
- // Although "7bit" and "BASE64" is not allowed in vCard 3.0, we allow it for safety.
- private static final HashSet<String> sAcceptableEncodingV30 = new HashSet<String>(
- Arrays.asList("7BIT", "8BIT", "BASE64", "B"));
-
- // Although RFC 2426 specifies some property must not have parameters, we allow it,
- // since there may be some careers which violates the RFC...
- private static final HashSet<String> acceptablePropsWithoutParam = new HashSet<String>();
-
- private String mPreviousLine;
-
- @Override
- protected String getVersion() {
- return "3.0";
- }
-
- @Override
- protected boolean isValidPropertyName(String propertyName) {
- if (!(acceptablePropsWithParam.contains(propertyName) ||
- acceptablePropsWithoutParam.contains(propertyName) ||
- propertyName.startsWith("X-")) &&
- !mWarningValueMap.contains(propertyName)) {
- mWarningValueMap.add(propertyName);
- Log.w(LOG_TAG, "Property name unsupported by vCard 3.0: " + propertyName);
- }
- return true;
- }
-
- @Override
- protected boolean isValidEncoding(String encoding) {
- return sAcceptableEncodingV30.contains(encoding.toUpperCase());
- }
-
- @Override
- protected String getLine() throws IOException {
- if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- } else {
- return mReader.readLine();
- }
- }
-
- /**
- * vCard 3.0 requires that the line with space at the beginning of the line
- * must be combined with previous line.
- */
- @Override
- protected String getNonEmptyLine() throws IOException, VCardException {
- String line;
- StringBuilder builder = null;
- while (true) {
- line = mReader.readLine();
- if (line == null) {
- if (builder != null) {
- return builder.toString();
- } else if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- }
- throw new VCardException("Reached end of buffer.");
- } else if (line.length() == 0) {
- if (builder != null) {
- return builder.toString();
- } else if (mPreviousLine != null) {
- String ret = mPreviousLine;
- mPreviousLine = null;
- return ret;
- }
- } else if (line.charAt(0) == ' ' || line.charAt(0) == '\t') {
- if (builder != null) {
- // See Section 5.8.1 of RFC 2425 (MIME-DIR document).
- // Following is the excerpts from it.
- //
- // DESCRIPTION:This is a long description that exists on a long line.
- //
- // Can be represented as:
- //
- // DESCRIPTION:This is a long description
- // that exists on a long line.
- //
- // It could also be represented as:
- //
- // DESCRIPTION:This is a long descrip
- // tion that exists o
- // n a long line.
- builder.append(line.substring(1));
- } else if (mPreviousLine != null) {
- builder = new StringBuilder();
- builder.append(mPreviousLine);
- mPreviousLine = null;
- builder.append(line.substring(1));
- } else {
- throw new VCardException("Space exists at the beginning of the line");
- }
- } else {
- if (mPreviousLine == null) {
- mPreviousLine = line;
- if (builder != null) {
- return builder.toString();
- }
- } else {
- String ret = mPreviousLine;
- mPreviousLine = line;
- return ret;
- }
- }
- }
- }
-
-
- /**
- * vcard = [group "."] "BEGIN" ":" "VCARD" 1*CRLF
- * 1*(contentline)
- * ;A vCard object MUST include the VERSION, FN and N types.
- * [group "."] "END" ":" "VCARD" 1*CRLF
- */
- @Override
- protected boolean readBeginVCard(boolean allowGarbage) throws IOException, VCardException {
- // TODO: vCard 3.0 supports group.
- return super.readBeginVCard(allowGarbage);
- }
-
- @Override
- protected void readEndVCard(boolean useCache, boolean allowGarbage)
- throws IOException, VCardException {
- // TODO: vCard 3.0 supports group.
- super.readEndVCard(useCache, allowGarbage);
- }
-
- /**
- * vCard 3.0 allows iana-token as paramType, while vCard 2.1 does not.
- */
- @Override
- protected void handleParams(String params) throws VCardException {
- try {
- super.handleParams(params);
- } catch (VCardException e) {
- // maybe IANA type
- String[] strArray = params.split("=", 2);
- if (strArray.length == 2) {
- handleAnyParam(strArray[0], strArray[1]);
- } else {
- // Must not come here in the current implementation.
- throw new VCardException(
- "Unknown params value: " + params);
- }
- }
- }
-
- @Override
- protected void handleAnyParam(String paramName, String paramValue) {
- // vCard 3.0 accept comma-separated multiple values, but
- // current PropertyNode does not accept it.
- // For now, we do not split the values.
- //
- // TODO: fix this.
- super.handleAnyParam(paramName, paramValue);
- }
-
- /**
- * vCard 3.0 defines
- *
- * param = param-name "=" param-value *("," param-value)
- * param-name = iana-token / x-name
- * param-value = ptext / quoted-string
- * quoted-string = DQUOTE QSAFE-CHAR DQUOTE
- */
- @Override
- protected void handleType(String ptypevalues) {
- String[] ptypeArray = ptypevalues.split(",");
- mBuilder.propertyParamType("TYPE");
- for (String value : ptypeArray) {
- int length = value.length();
- if (length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
- mBuilder.propertyParamValue(value.substring(1, value.length() - 1));
- } else {
- mBuilder.propertyParamValue(value);
- }
- }
- }
-
- @Override
- protected void handleAgent(String propertyValue) throws VCardException {
- // The way how vCard 3.0 supports "AGENT" is completely different from vCard 2.0.
- //
- // e.g.
- // AGENT:BEGIN:VCARD\nFN:Joe Friday\nTEL:+1-919-555-7878\n
- // TITLE:Area Administrator\, Assistant\n EMAIL\;TYPE=INTERN\n
- // ET:jfriday@host.com\nEND:VCARD\n
- //
- // TODO: fix this.
- //
- // issue:
- // vCard 3.0 also allows this as an example.
- //
- // AGENT;VALUE=uri:
- // CID:JQPUBLIC.part3.960129T083020.xyzMail@host3.com
- //
- // This is not VCARD. Should we support this?
- throw new VCardException("AGENT in vCard 3.0 is not supported yet.");
- }
-
- /**
- * vCard 3.0 does not require two CRLF at the last of BASE64 data.
- * It only requires that data should be MIME-encoded.
- */
- @Override
- protected String getBase64(String firstString) throws IOException, VCardException {
- StringBuilder builder = new StringBuilder();
- builder.append(firstString);
-
- while (true) {
- String line = getLine();
- if (line == null) {
- throw new VCardException(
- "File ended during parsing BASE64 binary");
- }
- if (line.length() == 0) {
- break;
- } else if (!line.startsWith(" ") && !line.startsWith("\t")) {
- mPreviousLine = line;
- break;
- }
- builder.append(line);
- }
-
- return builder.toString();
- }
-
- /**
- * ESCAPED-CHAR = "\\" / "\;" / "\," / "\n" / "\N")
- * ; \\ encodes \, \n or \N encodes newline
- * ; \; encodes ;, \, encodes ,
- *
- * Note: Apple escape ':' into '\:' while does not escape '\'
- */
- @Override
- protected String maybeUnescapeText(String text) {
- StringBuilder builder = new StringBuilder();
- int length = text.length();
- for (int i = 0; i < length; i++) {
- char ch = text.charAt(i);
- if (ch == '\\' && i < length - 1) {
- char next_ch = text.charAt(++i);
- if (next_ch == 'n' || next_ch == 'N') {
- builder.append("\r\n");
- } else {
- builder.append(next_ch);
- }
- } else {
- builder.append(ch);
- }
- }
- return builder.toString();
- }
-
- @Override
- protected String maybeUnescape(char ch) {
- if (ch == 'n' || ch == 'N') {
- return "\r\n";
- } else {
- return String.valueOf(ch);
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-import android.syncml.pim.VBuilder;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Class which tries to detects the source of the vCard from its properties.
- * Currently this implementation is very premature.
- */
-@Deprecated
-public class VCardSourceDetector implements VBuilder {
- // Should only be used in package.
- static final int TYPE_UNKNOWN = 0;
- static final int TYPE_APPLE = 1;
- static final int TYPE_JAPANESE_MOBILE_PHONE = 2; // Used in Japanese mobile phones.
- static final int TYPE_FOMA = 3; // Used in some Japanese FOMA mobile phones.
- static final int TYPE_WINDOWS_MOBILE_JP = 4;
- // TODO: Excel, etc.
-
- private static Set<String> APPLE_SIGNS = new HashSet<String>(Arrays.asList(
- "X-PHONETIC-FIRST-NAME", "X-PHONETIC-MIDDLE-NAME", "X-PHONETIC-LAST-NAME",
- "X-ABADR", "X-ABUID"));
-
- private static Set<String> JAPANESE_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
- "X-GNO", "X-GN", "X-REDUCTION"));
-
- private static Set<String> WINDOWS_MOBILE_PHONE_SIGNS = new HashSet<String>(Arrays.asList(
- "X-MICROSOFT-ASST_TEL", "X-MICROSOFT-ASSISTANT", "X-MICROSOFT-OFFICELOC"));
-
- // Note: these signes appears before the signs of the other type (e.g. "X-GN").
- // In other words, Japanese FOMA mobile phones are detected as FOMA, not JAPANESE_MOBILE_PHONES.
- private static Set<String> FOMA_SIGNS = new HashSet<String>(Arrays.asList(
- "X-SD-VERN", "X-SD-FORMAT_VER", "X-SD-CATEGORIES", "X-SD-CLASS", "X-SD-DCREATED",
- "X-SD-DESCRIPTION"));
- private static String TYPE_FOMA_CHARSET_SIGN = "X-SD-CHAR_CODE";
-
- private int mType = TYPE_UNKNOWN;
- // Some mobile phones (like FOMA) tells us the charset of the data.
- private boolean mNeedParseSpecifiedCharset;
- private String mSpecifiedCharset;
-
- public void start() {
- }
-
- public void end() {
- }
-
- public void startRecord(String type) {
- }
-
- public void startProperty() {
- mNeedParseSpecifiedCharset = false;
- }
-
- public void endProperty() {
- }
-
- public void endRecord() {
- }
-
- public void propertyGroup(String group) {
- }
-
- public void propertyName(String name) {
- if (name.equalsIgnoreCase(TYPE_FOMA_CHARSET_SIGN)) {
- mType = TYPE_FOMA;
- mNeedParseSpecifiedCharset = true;
- return;
- }
- if (mType != TYPE_UNKNOWN) {
- return;
- }
- if (WINDOWS_MOBILE_PHONE_SIGNS.contains(name)) {
- mType = TYPE_WINDOWS_MOBILE_JP;
- } else if (FOMA_SIGNS.contains(name)) {
- mType = TYPE_FOMA;
- } else if (JAPANESE_MOBILE_PHONE_SIGNS.contains(name)) {
- mType = TYPE_JAPANESE_MOBILE_PHONE;
- } else if (APPLE_SIGNS.contains(name)) {
- mType = TYPE_APPLE;
- }
- }
-
- public void propertyParamType(String type) {
- }
-
- public void propertyParamValue(String value) {
- }
-
- public void propertyValues(List<String> values) {
- if (mNeedParseSpecifiedCharset && values.size() > 0) {
- mSpecifiedCharset = values.get(0);
- }
- }
-
- int getType() {
- return mType;
- }
-
- /**
- * Return charset String guessed from the source's properties.
- * This method must be called after parsing target file(s).
- * @return Charset String. Null is returned if guessing the source fails.
- */
- public String getEstimatedCharset() {
- if (mSpecifiedCharset != null) {
- return mSpecifiedCharset;
- }
- switch (mType) {
- case TYPE_WINDOWS_MOBILE_JP:
- case TYPE_FOMA:
- case TYPE_JAPANESE_MOBILE_PHONE:
- return "SHIFT_JIS";
- case TYPE_APPLE:
- return "UTF-8";
- default:
- return null;
- }
- }
-}
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcard;
-
-/**
- * VCardException used only when the version of the vCard is different.
- */
-@Deprecated
-public class VCardVersionException extends VCardException {
- public VCardVersionException() {
- }
-
- public VCardVersionException(String message) {
- super(message);
- }
-}
+++ /dev/null
-<HTML>
-<BODY>
-Support classes for SyncML.
-{@hide}
-</BODY>
-</HTML>
\ No newline at end of file