diff options
Diffstat (limited to 'core/java/android/syncml')
27 files changed, 0 insertions, 7307 deletions
diff --git a/core/java/android/syncml/package.html b/core/java/android/syncml/package.html deleted file mode 100644 index cb4ca46..0000000 --- a/core/java/android/syncml/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Support classes for SyncML. -{@hide} -</BODY> -</HTML>
\ No newline at end of file diff --git a/core/java/android/syncml/pim/PropertyNode.java b/core/java/android/syncml/pim/PropertyNode.java deleted file mode 100644 index 983ecb8..0000000 --- a/core/java/android/syncml/pim/PropertyNode.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * 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; - -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; - } -} diff --git a/core/java/android/syncml/pim/VBuilder.java b/core/java/android/syncml/pim/VBuilder.java deleted file mode 100644 index 4528645..0000000 --- a/core/java/android/syncml/pim/VBuilder.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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; - -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); -} diff --git a/core/java/android/syncml/pim/VBuilderCollection.java b/core/java/android/syncml/pim/VBuilderCollection.java deleted file mode 100644 index f09c1c4..0000000 --- a/core/java/android/syncml/pim/VBuilderCollection.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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; - -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); - } - } -} diff --git a/core/java/android/syncml/pim/VDataBuilder.java b/core/java/android/syncml/pim/VDataBuilder.java deleted file mode 100644 index f6e5b65..0000000 --- a/core/java/android/syncml/pim/VDataBuilder.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * 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. - */ -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; - } -} diff --git a/core/java/android/syncml/pim/VNode.java b/core/java/android/syncml/pim/VNode.java deleted file mode 100644 index 9015415..0000000 --- a/core/java/android/syncml/pim/VNode.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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; - -public class VNode { - - public String VName; - - public ArrayList<PropertyNode> propList = new ArrayList<PropertyNode>(); - - /** 0:parse over. 1:parsing. */ - public int parseStatus = 1; -} diff --git a/core/java/android/syncml/pim/VParser.java b/core/java/android/syncml/pim/VParser.java deleted file mode 100644 index 57c5f7a..0000000 --- a/core/java/android/syncml/pim/VParser.java +++ /dev/null @@ -1,740 +0,0 @@ -/* - * 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 - * - */ -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; - } - -} diff --git a/core/java/android/syncml/pim/package.html b/core/java/android/syncml/pim/package.html deleted file mode 100644 index cb4ca46..0000000 --- a/core/java/android/syncml/pim/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Support classes for SyncML. -{@hide} -</BODY> -</HTML>
\ No newline at end of file diff --git a/core/java/android/syncml/pim/vcalendar/CalendarStruct.java b/core/java/android/syncml/pim/vcalendar/CalendarStruct.java deleted file mode 100644 index 3388ada..0000000 --- a/core/java/android/syncml/pim/vcalendar/CalendarStruct.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.vcalendar; - -import java.util.List; -import java.util.ArrayList; - -/** - * Same comment as ContactStruct. - */ -public class CalendarStruct{ - - public static class EventStruct{ - public String description; - public String dtend; - public String dtstart; - public String duration; - public String has_alarm; - public String last_date; - public String rrule; - public String status; - public String title; - public String event_location; - public String uid; - public List<String> reminderList; - - public void addReminderList(String method){ - if(reminderList == null) - reminderList = new ArrayList<String>(); - reminderList.add(method); - } - } - - public String timezone; - public List<EventStruct> eventList; - - public void addEventList(EventStruct stru){ - if(eventList == null) - eventList = new ArrayList<EventStruct>(); - eventList.add(stru); - } -} diff --git a/core/java/android/syncml/pim/vcalendar/VCalComposer.java b/core/java/android/syncml/pim/vcalendar/VCalComposer.java deleted file mode 100644 index 18b6719..0000000 --- a/core/java/android/syncml/pim/vcalendar/VCalComposer.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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.vcalendar; - -/** - * vCalendar string composer class - */ -public class VCalComposer { - - public final static String VERSION_VCALENDAR10 = "vcalendar1.0"; - public final static String VERSION_VCALENDAR20 = "vcalendar2.0"; - - public final static int VERSION_VCAL10_INT = 1; - public final static int VERSION_VCAL20_INT = 2; - - private static String mNewLine = "\r\n"; - private String mVersion = null; - - public VCalComposer() { - } - - /** - * Create a vCalendar String. - * @param struct see more from CalendarStruct class - * @param vcalversion MUST be VERSION_VCAL10 /VERSION_VCAL20 - * @return vCalendar string - * @throws VcalException if version is invalid or create failed - */ - public String createVCal(CalendarStruct struct, int vcalversion) - throws VCalException{ - - StringBuilder returnStr = new StringBuilder(); - - //Version check - if(vcalversion != 1 && vcalversion != 2) - throw new VCalException("version not match 1.0 or 2.0."); - if (vcalversion == 1) - mVersion = VERSION_VCALENDAR10; - else - mVersion = VERSION_VCALENDAR20; - - //Build vCalendar: - returnStr.append("BEGIN:VCALENDAR").append(mNewLine); - - if(vcalversion == VERSION_VCAL10_INT) - returnStr.append("VERSION:1.0").append(mNewLine); - else - returnStr.append("VERSION:2.0").append(mNewLine); - - returnStr.append("PRODID:vCal ID default").append(mNewLine); - - if(!isNull(struct.timezone)){ - if(vcalversion == VERSION_VCAL10_INT) - returnStr.append("TZ:").append(struct.timezone).append(mNewLine); - else//down here MUST have - returnStr.append("BEGIN:VTIMEZONE").append(mNewLine). - append("TZID:vCal default").append(mNewLine). - append("BEGIN:STANDARD").append(mNewLine). - append("DTSTART:16010101T000000").append(mNewLine). - append("TZOFFSETFROM:").append(struct.timezone).append(mNewLine). - append("TZOFFSETTO:").append(struct.timezone).append(mNewLine). - append("END:STANDARD").append(mNewLine). - append("END:VTIMEZONE").append(mNewLine); - } - //Build VEVNET - for(int i = 0; i < struct.eventList.size(); i++){ - String str = buildEventStr( struct.eventList.get(i) ); - returnStr.append(str); - } - - //Build VTODO - //TODO - - returnStr.append("END:VCALENDAR").append(mNewLine).append(mNewLine); - - return returnStr.toString(); - } - - private String buildEventStr(CalendarStruct.EventStruct stru){ - - StringBuilder strbuf = new StringBuilder(); - - strbuf.append("BEGIN:VEVENT").append(mNewLine); - - if(!isNull(stru.uid)) - strbuf.append("UID:").append(stru.uid).append(mNewLine); - - if(!isNull(stru.description)) - strbuf.append("DESCRIPTION:"). - append(foldingString(stru.description)).append(mNewLine); - - if(!isNull(stru.dtend)) - strbuf.append("DTEND:").append(stru.dtend).append(mNewLine); - - if(!isNull(stru.dtstart)) - strbuf.append("DTSTART:").append(stru.dtstart).append(mNewLine); - - if(!isNull(stru.duration)) - strbuf.append("DUE:").append(stru.duration).append(mNewLine); - - if(!isNull(stru.event_location)) - strbuf.append("LOCATION:").append(stru.event_location).append(mNewLine); - - if(!isNull(stru.last_date)) - strbuf.append("COMPLETED:").append(stru.last_date).append(mNewLine); - - if(!isNull(stru.rrule)) - strbuf.append("RRULE:").append(stru.rrule).append(mNewLine); - - if(!isNull(stru.title)) - strbuf.append("SUMMARY:").append(stru.title).append(mNewLine); - - if(!isNull(stru.status)){ - String stat = "TENTATIVE"; - switch (Integer.parseInt(stru.status)){ - case 0://Calendar.Calendars.STATUS_TENTATIVE - stat = "TENTATIVE"; - break; - case 1://Calendar.Calendars.STATUS_CONFIRMED - stat = "CONFIRMED"; - break; - case 2://Calendar.Calendars.STATUS_CANCELED - stat = "CANCELLED"; - break; - } - strbuf.append("STATUS:").append(stat).append(mNewLine); - } - //Alarm - if(!isNull(stru.has_alarm) - && stru.reminderList != null - && stru.reminderList.size() > 0){ - - if (mVersion.equals(VERSION_VCALENDAR10)){ - String prefix = ""; - for(String method : stru.reminderList){ - switch (Integer.parseInt(method)){ - case 0: - prefix = "DALARM"; - break; - case 1: - prefix = "AALARM"; - break; - case 2: - prefix = "MALARM"; - break; - case 3: - default: - prefix = "DALARM"; - break; - } - strbuf.append(prefix).append(":default").append(mNewLine); - } - }else {//version 2.0 only support audio-method now. - strbuf.append("BEGIN:VALARM").append(mNewLine). - append("ACTION:AUDIO").append(mNewLine). - append("TRIGGER:-PT10M").append(mNewLine). - append("END:VALARM").append(mNewLine); - } - } - strbuf.append("END:VEVENT").append(mNewLine); - return strbuf.toString(); - } - - /** Alter str to folding supported format. */ - private String foldingString(String str){ - return str.replaceAll("\r\n", "\n").replaceAll("\n", "\r\n "); - } - - /** is null */ - private boolean isNull(String str){ - if(str == null || str.trim().equals("")) - return true; - return false; - } -} diff --git a/core/java/android/syncml/pim/vcalendar/VCalException.java b/core/java/android/syncml/pim/vcalendar/VCalException.java deleted file mode 100644 index 48ea134..0000000 --- a/core/java/android/syncml/pim/vcalendar/VCalException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.vcalendar; - -public class VCalException extends java.lang.Exception{ - // constructors - - /** - * Constructs a VCalException object - */ - - public VCalException() - { - } - - /** - * Constructs a VCalException object - * - * @param message the error message - */ - - public VCalException( String message ) - { - super( message ); - } - -} diff --git a/core/java/android/syncml/pim/vcalendar/VCalParser.java b/core/java/android/syncml/pim/vcalendar/VCalParser.java deleted file mode 100644 index bc2d598..0000000 --- a/core/java/android/syncml/pim/vcalendar/VCalParser.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.vcalendar; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import android.util.Config; -import android.util.Log; - -import android.syncml.pim.VDataBuilder; -import android.syncml.pim.VParser; - -public class VCalParser{ - - private final static String TAG = "VCalParser"; - - public final static String VERSION_VCALENDAR10 = "vcalendar1.0"; - public final static String VERSION_VCALENDAR20 = "vcalendar2.0"; - - private VParser mParser = null; - private String mVersion = null; - - public VCalParser() { - } - - public boolean parse(String vcalendarStr, VDataBuilder builder) - throws VCalException { - - vcalendarStr = verifyVCal(vcalendarStr); - try{ - boolean isSuccess = mParser.parse( - new ByteArrayInputStream(vcalendarStr.getBytes()), - "US-ASCII", builder); - - if (!isSuccess) { - if (mVersion.equals(VERSION_VCALENDAR10)) { - if(Config.LOGD) - Log.d(TAG, "Parse failed for vCal 1.0 parser." - + " Try to use 2.0 parser."); - mVersion = VERSION_VCALENDAR20; - return parse(vcalendarStr, builder); - }else - throw new VCalException("parse failed.(even use 2.0 parser)"); - } - }catch (IOException e){ - throw new VCalException(e.getMessage()); - } - return true; - } - - /** - * Verify vCalendar string, and initialize mVersion according to it. - * */ - private String verifyVCal(String vcalStr) { - - //Version check - judgeVersion(vcalStr); - - vcalStr = vcalStr.replaceAll("\r\n", "\n"); - String[] strlist = vcalStr.split("\n"); - - StringBuilder replacedStr = 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) - replacedStr.append(strlist[i]).append("\r\n"); - else - replacedStr.append(" ").append(strlist[i]).append("\r\n"); - } else - replacedStr.append(strlist[i]).append("\r\n"); - } - if(Config.LOGD)Log.d(TAG, "After verify:\r\n" + replacedStr.toString()); - - return replacedStr.toString(); - } - - /** - * If version not given. Search from vcal string of the VERSION property. - * Then instance mParser to appropriate parser. - */ - private void judgeVersion(String vcalStr) { - - if (mVersion == null) { - int versionIdx = vcalStr.indexOf("\nVERSION:"); - - mVersion = VERSION_VCALENDAR10; - - if (versionIdx != -1){ - String versionStr = vcalStr.substring( - versionIdx, vcalStr.indexOf("\n", versionIdx + 1)); - if (versionStr.indexOf("2.0") > 0) - mVersion = VERSION_VCALENDAR20; - } - } - if (mVersion.equals(VERSION_VCALENDAR10)) - mParser = new VCalParser_V10(); - if (mVersion.equals(VERSION_VCALENDAR20)) - mParser = new VCalParser_V20(); - } -} - diff --git a/core/java/android/syncml/pim/vcalendar/VCalParser_V10.java b/core/java/android/syncml/pim/vcalendar/VCalParser_V10.java deleted file mode 100644 index 1b251f3..0000000 --- a/core/java/android/syncml/pim/vcalendar/VCalParser_V10.java +++ /dev/null @@ -1,1628 +0,0 @@ -/* - * 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.vcalendar; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import android.syncml.pim.VParser; - -public class VCalParser_V10 extends VParser { - - /* - * The names of the properties whose value are not separated by ";" - */ - private static final HashSet<String> mEvtPropNameGroup1 = new HashSet<String>( - Arrays.asList("ATTACH", "ATTENDEE", "DCREATED", "COMPLETED", - "DESCRIPTION", "DUE", "DTEND", "EXRULE", "LAST-MODIFIED", - "LOCATION", "RNUM", "PRIORITY", "RELATED-TO", "RRULE", - "SEQUENCE", "DTSTART", "SUMMARY", "TRANSP", "URL", "UID", - // above belong to simprop - "CLASS", "STATUS")); - - /* - * The names of properties whose value are separated by ";" - */ - private static final HashSet<String> mEvtPropNameGroup2 = new HashSet<String>( - Arrays.asList("AALARM", "CATEGORIES", "DALARM", "EXDATE", "MALARM", - "PALARM", "RDATE", "RESOURCES")); - - private static final HashSet<String> mValueCAT = new HashSet<String>(Arrays - .asList("APPOINTMENT", "BUSINESS", "EDUCATION", "HOLIDAY", - "MEETING", "MISCELLANEOUS", "PERSONAL", "PHONE CALL", - "SICK DAY", "SPECIAL OCCASION", "TRAVEL", "VACATION")); - - private static final HashSet<String> mValueCLASS = new HashSet<String>(Arrays - .asList("PUBLIC", "PRIVATE", "CONFIDENTIAL")); - - private static final HashSet<String> mValueRES = new HashSet<String>(Arrays - .asList("CATERING", "CHAIRS", "EASEL", "PROJECTOR", "VCR", - "VEHICLE")); - - private static final HashSet<String> mValueSTAT = new HashSet<String>(Arrays - .asList("ACCEPTED", "NEEDS ACTION", "SENT", "TENTATIVE", - "CONFIRMED", "DECLINED", "COMPLETED", "DELEGATED")); - - /* - * The names of properties whose value can contain escape characters - */ - private static final HashSet<String> mEscAllowedProps = new HashSet<String>( - Arrays.asList("DESCRIPTION", "SUMMARY", "AALARM", "DALARM", - "MALARM", "PALARM")); - - private static final HashMap<String, HashSet<String>> mSpecialValueSetMap = - new HashMap<String, HashSet<String>>(); - - static { - mSpecialValueSetMap.put("CATEGORIES", mValueCAT); - mSpecialValueSetMap.put("CLASS", mValueCLASS); - mSpecialValueSetMap.put("RESOURCES", mValueRES); - mSpecialValueSetMap.put("STATUS", mValueSTAT); - } - - public VCalParser_V10() { - } - - protected int parseVFile(int offset) { - return parseVCalFile(offset); - } - - private int parseVCalFile(int offset) { - int ret = 0, sum = 0; - - /* remove wsls */ - while (PARSE_ERROR != (ret = parseWsls(offset))) { - offset += ret; - sum += ret; - } - - ret = parseVCal(offset); // BEGIN:VCAL ... END:VCAL - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - } else { - return PARSE_ERROR; - } - - /* remove wsls */ - while (PARSE_ERROR != (ret = parseWsls(offset))) { - offset += ret; - sum += ret; - } - return sum; - } - - /** - * "BEGIN" [ws] ":" [ws] "VCALENDAR" [ws] 1*crlf calprop calentities [ws] - * *crlf "END" [ws] ":" [ws] "VCALENDAR" [ws] 1*CRLF - */ - private int parseVCal(int offset) { - int ret = 0, sum = 0; - - /* BEGIN */ - ret = parseString(offset, "BEGIN", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // ":" - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // "VCALENDAR - ret = parseString(offset, "VCALENDAR", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.startRecord("VCALENDAR"); - } - - /* [ws] */ - ret = removeWs(offset); - offset += ret; - sum += ret; - - // 1*CRLF - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - // calprop - ret = parseCalprops(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // calentities - ret = parseCalentities(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // *CRLF - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - // "END" - ret = parseString(offset, "END", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // ":" - // ":" - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // "VCALENDAR" - ret = parseString(offset, "VCALENDAR", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endRecord(); - } - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // 1 * CRLF - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - return sum; - } - - /** - * calprops * CRLF calprop / calprop - */ - private int parseCalprops(int offset) { - int ret = 0, sum = 0; - - if (mBuilder != null) { - mBuilder.startProperty(); - } - ret = parseCalprop(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endProperty(); - } - - for (;;) { - /* *CRLF */ - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - // follow VEVENT ,it wont reach endProperty - if (mBuilder != null) { - mBuilder.startProperty(); - } - ret = parseCalprop(offset); - if (PARSE_ERROR == ret) { - break; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endProperty(); - } - } - - return sum; - } - - /** - * calentities *CRLF calentity / calentity - */ - private int parseCalentities(int offset) { - int ret = 0, sum = 0; - - ret = parseCalentity(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - for (;;) { - /* *CRLF */ - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - ret = parseCalentity(offset); - if (PARSE_ERROR == ret) { - break; - } - offset += ret; - sum += ret; - } - - return sum; - } - - /** - * calprop = DAYLIGHT/ GEO/ PRODID/ TZ/ VERSION - */ - private int parseCalprop(int offset) { - int ret = 0; - - ret = parseCalprop0(offset, "DAYLIGHT"); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseCalprop0(offset, "GEO"); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseCalprop0(offset, "PRODID"); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseCalprop0(offset, "TZ"); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseCalprop1(offset); - if (PARSE_ERROR != ret) { - return ret; - } - return PARSE_ERROR; - } - - /** - * evententity / todoentity - */ - private int parseCalentity(int offset) { - int ret = 0; - - ret = parseEvententity(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseTodoentity(offset); - if (PARSE_ERROR != ret) { - return ret; - } - return PARSE_ERROR; - - } - - /** - * propName [params] ":" value CRLF - */ - private int parseCalprop0(int offset, String propName) { - int ret = 0, sum = 0, start = 0; - - ret = parseString(offset, propName, true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyName(propName); - } - - ret = parseParams(offset); - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - } - - ret = parseString(offset, ":", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - start = offset; - ret = parseValue(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - ArrayList<String> v = new ArrayList<String>(); - v.add(mBuffer.substring(start, offset)); - mBuilder.propertyValues(v); - } - - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - sum += ret; - - return sum; - } - - /** - * "VERSION" [params] ":" "1.0" CRLF - */ - private int parseCalprop1(int offset) { - int ret = 0, sum = 0; - - ret = parseString(offset, "VERSION", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyName("VERSION"); - } - - ret = parseParams(offset); - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - } - - ret = parseString(offset, ":", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = parseString(offset, "1.0", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - ArrayList<String> v = new ArrayList<String>(); - v.add("1.0"); - mBuilder.propertyValues(v); - } - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - sum += ret; - - return sum; - } - - /** - * "BEGIN" [ws] ":" [ws] "VEVENT" [ws] 1*CRLF entprops [ws] *CRLF "END" [ws] - * ":" [ws] "VEVENT" [ws] 1*CRLF - */ - private int parseEvententity(int offset) { - int ret = 0, sum = 0; - - ret = parseString(offset, "BEGIN", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // ":" - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // "VEVNET" - ret = parseString(offset, "VEVENT", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.startRecord("VEVENT"); - } - - /* [ws] */ - ret = removeWs(offset); - offset += ret; - sum += ret; - - // 1*CRLF - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - ret = parseEntprops(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // *CRLF - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - // "END" - ret = parseString(offset, "END", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // ":" - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // "VEVENT" - ret = parseString(offset, "VEVENT", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endRecord(); - } - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // 1 * CRLF - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - return sum; - } - - /** - * "BEGIN" [ws] ":" [ws] "VTODO" [ws] 1*CRLF entprops [ws] *CRLF "END" [ws] - * ":" [ws] "VTODO" [ws] 1*CRLF - */ - private int parseTodoentity(int offset) { - int ret = 0, sum = 0; - - ret = parseString(offset, "BEGIN", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // ":" - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // "VTODO" - ret = parseString(offset, "VTODO", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.startRecord("VTODO"); - } - - // 1*CRLF - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - ret = parseEntprops(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // *CRLF - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - // "END" - ret = parseString(offset, "END", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // ":" - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // "VTODO" - ret = parseString(offset, "VTODO", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endRecord(); - } - - // [ws] - ret = removeWs(offset); - offset += ret; - sum += ret; - - // 1 * CRLF - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - - return sum; - } - - /** - * entprops *CRLF entprop / entprop - */ - private int parseEntprops(int offset) { - int ret = 0, sum = 0; - if (mBuilder != null) { - mBuilder.startProperty(); - } - - ret = parseEntprop(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endProperty(); - } - - for (;;) { - while (PARSE_ERROR != (ret = parseCrlf(offset))) { - offset += ret; - sum += ret; - } - if (mBuilder != null) { - mBuilder.startProperty(); - } - - ret = parseEntprop(offset); - if (PARSE_ERROR == ret) { - break; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.endProperty(); - } - } - return sum; - } - - /** - * for VEVENT,VTODO prop. entprop0 / entprop1 - */ - private int parseEntprop(int offset) { - int ret = 0; - ret = parseEntprop0(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseEntprop1(offset); - if (PARSE_ERROR != ret) { - return ret; - } - return PARSE_ERROR; - } - - /** - * Same with card. ";" [ws] paramlist - */ - private int parseParams(int offset) { - int ret = 0, sum = 0; - - ret = parseString(offset, ";", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseParamlist(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - sum += ret; - - return sum; - } - - /** - * Same with card. paramlist [ws] ";" [ws] param / param - */ - private int parseParamlist(int offset) { - int ret = 0, sum = 0; - - ret = parseParam(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - int offsetTemp = offset; - int sumTemp = sum; - for (;;) { - ret = removeWs(offsetTemp); - offsetTemp += ret; - sumTemp += ret; - - ret = parseString(offsetTemp, ";", false); - if (PARSE_ERROR == ret) { - return sum; - } - offsetTemp += ret; - sumTemp += ret; - - ret = removeWs(offsetTemp); - offsetTemp += ret; - sumTemp += ret; - - ret = parseParam(offsetTemp); - if (PARSE_ERROR == ret) { - break; - } - offsetTemp += ret; - sumTemp += ret; - - // offset = offsetTemp; - sum = sumTemp; - } - return sum; - } - - /** - * param0 - param7 / knowntype - */ - private int parseParam(int offset) { - int ret = 0; - - ret = parseParam0(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam1(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam2(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam3(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam4(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam5(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam6(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseParam7(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - int start = offset; - ret = parseKnownType(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(null); - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return ret; - } - - /** - * simprop AND "CLASS" AND "STATUS" The value of these properties are not - * seperated by ";" - * - * [ws] simprop [params] ":" value CRLF - */ - private int parseEntprop0(int offset) { - int ret = 0, sum = 0, start = 0; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - String propName = getWord(offset).toUpperCase(); - if (!mEvtPropNameGroup1.contains(propName)) { - if (PARSE_ERROR == parseXWord(offset)) - return PARSE_ERROR; - } - ret = propName.length(); - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyName(propName); - } - - ret = parseParams(offset); - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - } - - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - start = offset; - ret = parseValue(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - ArrayList<String> v = new ArrayList<String>(); - v.add(exportEntpropValue(propName, mBuffer.substring(start, - offset))); - mBuilder.propertyValues(v); - // Filter value,match string, REFER:RFC - if (PARSE_ERROR == valueFilter(propName, v)) - return PARSE_ERROR; - } - - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - sum += ret; - return sum; - } - - /** - * other event prop names except simprop AND "CLASS" AND "STATUS" The value - * of these properties are seperated by ";" [ws] proper name [params] ":" - * value CRLF - */ - private int parseEntprop1(int offset) { - int ret = 0, sum = 0; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - String propName = getWord(offset).toUpperCase(); - if (!mEvtPropNameGroup2.contains(propName)) { - return PARSE_ERROR; - } - ret = propName.length(); - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyName(propName); - } - - ret = parseParams(offset); - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - } - - ret = parseString(offset, ":", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - int start = offset; - ret = parseValue(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - // mutil-values - if (mBuilder != null) { - int end = 0; - ArrayList<String> v = new ArrayList<String>(); - Pattern p = Pattern - .compile("([^;\\\\]*(\\\\[\\\\;:,])*[^;\\\\]*)(;?)"); - Matcher m = p.matcher(mBuffer.substring(start, offset)); - while (m.find()) { - String s = exportEntpropValue(propName, m.group(1)); - v.add(s); - end = m.end(); - if (offset == start + end) { - String endValue = m.group(3); - if (";".equals(endValue)) { - v.add(""); - } - break; - } - } - mBuilder.propertyValues(v); - // Filter value,match string, REFER:RFC - if (PARSE_ERROR == valueFilter(propName, v)) - return PARSE_ERROR; - } - - ret = parseCrlf(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - sum += ret; - return sum; - } - - /** - * "TYPE" [ws] = [ws] ptypeval - */ - private int parseParam0(int offset) { - int ret = 0, sum = 0, start = offset; - - ret = parseString(offset, "TYPE", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", false); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parsePtypeval(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - return sum; - } - - /** - * ["VALUE" [ws] "=" [ws]] pvalueval - */ - private int parseParam1(int offset) { - int ret = 0, sum = 0, start = offset; - boolean flag = false; - - ret = parseString(offset, "VALUE", true); - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - flag = true; - } - if (flag == true && mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR != ret) { - if (flag == false) { // "VALUE" does not exist - return PARSE_ERROR; - } - offset += ret; - sum += ret; - } else { - if (flag == true) { // "VALUE" exists - return PARSE_ERROR; - } - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parsePValueVal(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - } - - /** ["ENCODING" [ws] "=" [ws]] pencodingval */ - private int parseParam2(int offset) { - int ret = 0, sum = 0, start = offset; - boolean flag = false; - - ret = parseString(offset, "ENCODING", true); - if (PARSE_ERROR != ret) { - offset += ret; - sum += ret; - flag = true; - } - if (flag == true && mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR != ret) { - if (flag == false) { // "VALUE" does not exist - return PARSE_ERROR; - } - offset += ret; - sum += ret; - } else { - if (flag == true) { // "VALUE" exists - return PARSE_ERROR; - } - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parsePEncodingVal(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - } - - /** - * "CHARSET" [WS] "=" [WS] charsetval - */ - private int parseParam3(int offset) { - int ret = 0, sum = 0, start = offset; - - ret = parseString(offset, "CHARSET", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parseCharsetVal(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - } - - /** - * "LANGUAGE" [ws] "=" [ws] langval - */ - private int parseParam4(int offset) { - int ret = 0, sum = 0, start = offset; - - ret = parseString(offset, "LANGUAGE", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parseLangVal(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - } - - /** - * "ROLE" [ws] "=" [ws] roleval - */ - private int parseParam5(int offset) { - int ret = 0, sum = 0, start = offset; - - ret = parseString(offset, "ROLE", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parseRoleVal(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - } - - /** - * "STATUS" [ws] = [ws] statuval - */ - private int parseParam6(int offset) { - int ret = 0, sum = 0, start = offset; - - ret = parseString(offset, "STATUS", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parseStatuVal(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - - } - - /** - * XWord [ws] "=" [ws] word - */ - private int parseParam7(int offset) { - int ret = 0, sum = 0, start = offset; - - ret = parseXWord(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamType(mBuffer.substring(start, offset)); - } - - ret = removeWs(offset); - offset += ret; - sum += ret; - - ret = parseString(offset, "=", true); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - - ret = removeWs(offset); - offset += ret; - sum += ret; - - start = offset; - ret = parseWord(offset); - if (PARSE_ERROR == ret) { - return PARSE_ERROR; - } - offset += ret; - sum += ret; - if (mBuilder != null) { - mBuilder.propertyParamValue(mBuffer.substring(start, offset)); - } - - return sum; - - } - - /* - * "WAVE" / "PCM" / "VCARD" / XWORD - */ - private int parseKnownType(int offset) { - int ret = 0; - - ret = parseString(offset, "WAVE", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseString(offset, "PCM", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseString(offset, "VCARD", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseXWord(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - return PARSE_ERROR; - } - - /* - * knowntype / Xword - */ - private int parsePtypeval(int offset) { - int ret = 0; - - ret = parseKnownType(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseXWord(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - return PARSE_ERROR; - } - - /** - * "ATTENDEE" / "ORGANIZER" / "OWNER" / XWORD - */ - private int parseRoleVal(int offset) { - int ret = 0; - - ret = parseString(offset, "ATTENDEE", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseString(offset, "ORGANIZER", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseString(offset, "OWNER", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseXWord(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - return PARSE_ERROR; - } - - /** - * "ACCEPTED" / "NEED ACTION" / "SENT" / "TENTATIVE" / "CONFIRMED" / - * "DECLINED" / "COMPLETED" / "DELEGATED / XWORD - */ - private int parseStatuVal(int offset) { - int ret = 0; - - ret = parseString(offset, "ACCEPTED", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseString(offset, "NEED ACTION", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseString(offset, "TENTATIVE", true); - if (PARSE_ERROR != ret) { - return ret; - } - ret = parseString(offset, "CONFIRMED", true); - if (PARSE_ERROR != ret) { - return ret; - } - ret = parseString(offset, "DECLINED", true); - if (PARSE_ERROR != ret) { - return ret; - } - ret = parseString(offset, "COMPLETED", true); - if (PARSE_ERROR != ret) { - return ret; - } - ret = parseString(offset, "DELEGATED", true); - if (PARSE_ERROR != ret) { - return ret; - } - - ret = parseXWord(offset); - if (PARSE_ERROR != ret) { - return ret; - } - - return PARSE_ERROR; - } - - /** - * Check 4 special propName and it's value to match Hash. - * - * @return PARSE_ERROR:value not match. 1:go on,like nothing happen. - */ - private int valueFilter(String propName, ArrayList<String> values) { - if (propName == null || propName.equals("") || values == null - || values.isEmpty()) - return 1; // go on, like nothing happen. - - if (mSpecialValueSetMap.containsKey(propName)) { - for (String value : values) { - if (!mSpecialValueSetMap.get(propName).contains(value)) { - if (!value.startsWith("X-")) - return PARSE_ERROR; - } - } - } - - return 1; - } - - /** - * - * Translate escape characters("\\", "\;") which define in vcalendar1.0 - * spec. But for fault tolerance, we will translate "\:" and "\,", which - * isn't define in vcalendar1.0 explicitly, as the same behavior as other - * client. - * - * Though vcalendar1.0 spec does not defined the value of property - * "description", "summary", "aalarm", "dalarm", "malarm" and "palarm" could - * contain escape characters, we do support escape characters in these - * properties. - * - * @param str: - * the value string will be translated. - * @return the string which do not contain any escape character in - * vcalendar1.0 - */ - private String exportEntpropValue(String propName, String str) { - if (null == propName || null == str) - return null; - if ("".equals(propName) || "".equals(str)) - return ""; - - if (!mEscAllowedProps.contains(propName)) - return str; - - String tmp = str.replace("\\\\", "\n\r\n"); - tmp = tmp.replace("\\;", ";"); - tmp = tmp.replace("\\:", ":"); - tmp = tmp.replace("\\,", ","); - tmp = tmp.replace("\n\r\n", "\\"); - return tmp; - } -} diff --git a/core/java/android/syncml/pim/vcalendar/VCalParser_V20.java b/core/java/android/syncml/pim/vcalendar/VCalParser_V20.java deleted file mode 100644 index 5748379..0000000 --- a/core/java/android/syncml/pim/vcalendar/VCalParser_V20.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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.vcalendar; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashSet; - -import android.syncml.pim.VBuilder; - -public class VCalParser_V20 extends VCalParser_V10 { - private static final String V10LINEBREAKER = "\r\n"; - - private static final HashSet<String> acceptableComponents = new HashSet<String>( - Arrays.asList("VEVENT", "VTODO", "VALARM", "VTIMEZONE")); - - private static final HashSet<String> acceptableV20Props = new HashSet<String>( - Arrays.asList("DESCRIPTION", "DTEND", "DTSTART", "DUE", - "COMPLETED", "RRULE", "STATUS", "SUMMARY", "LOCATION")); - - private boolean hasTZ = false; // MUST only have one TZ property - - private String[] lines; - - private int index; - - @Override - public boolean parse(InputStream is, String encoding, VBuilder builder) - throws IOException { - // get useful info for android calendar, and alter to vcal 1.0 - byte[] bytes = new byte[is.available()]; - is.read(bytes); - String scStr = new String(bytes); - StringBuilder v10str = new StringBuilder(""); - - lines = splitProperty(scStr); - index = 0; - - if ("BEGIN:VCALENDAR".equals(lines[index])) - v10str.append("BEGIN:VCALENDAR" + V10LINEBREAKER); - else - return false; - index++; - if (false == parseV20Calbody(lines, v10str) - || index > lines.length - 1) - return false; - - if (lines.length - 1 == index && "END:VCALENDAR".equals(lines[index])) - v10str.append("END:VCALENDAR" + V10LINEBREAKER); - else - return false; - - return super.parse( - // use vCal 1.0 parser - new ByteArrayInputStream(v10str.toString().getBytes()), - encoding, builder); - } - - /** - * Parse and pick acceptable iCalendar body and translate it to - * calendarV1.0 format. - * @param lines iCalendar components/properties line list. - * @param buffer calendarV10 format string buffer - * @return true for success, or false - */ - private boolean parseV20Calbody(String[] lines, StringBuilder buffer) { - try { - while (!"VERSION:2.0".equals(lines[index])) - index++; - buffer.append("VERSION:1.0" + V10LINEBREAKER); - - index++; - for (; index < lines.length - 1; index++) { - String[] keyAndValue = lines[index].split(":", 2); - String key = keyAndValue[0]; - String value = keyAndValue[1]; - - if ("BEGIN".equals(key.trim())) { - if (!key.equals(key.trim())) - return false; // MUST be "BEGIN:componentname" - index++; - if (false == parseV20Component(value, buffer)) - return false; - } - } - } catch (ArrayIndexOutOfBoundsException e) { - return false; - } - - return true; - } - - /** - * Parse and pick acceptable calendar V2.0's component and translate it to - * V1.0 format. - * @param compName component name - * @param buffer calendarV10 format string buffer - * @return true for success, or false - * @throws ArrayIndexOutOfBoundsException - */ - private boolean parseV20Component(String compName, StringBuilder buffer) - throws ArrayIndexOutOfBoundsException { - String endTag = "END:" + compName; - String[] propAndValue; - String propName, value; - - if (acceptableComponents.contains(compName)) { - if ("VEVENT".equals(compName) || "VTODO".equals(compName)) { - buffer.append("BEGIN:" + compName + V10LINEBREAKER); - while (!endTag.equals(lines[index])) { - propAndValue = lines[index].split(":", 2); - propName = propAndValue[0].split(";", 2)[0]; - value = propAndValue[1]; - - if ("".equals(lines[index])) - buffer.append(V10LINEBREAKER); - else if (acceptableV20Props.contains(propName)) { - buffer.append(propName + ":" + value + V10LINEBREAKER); - } else if ("BEGIN".equals(propName.trim())) { - // MUST be BEGIN:VALARM - if (propName.equals(propName.trim()) - && "VALARM".equals(value)) { - buffer.append("AALARM:default" + V10LINEBREAKER); - while (!"END:VALARM".equals(lines[index])) - index++; - } else - return false; - } - index++; - } // end while - buffer.append(endTag + V10LINEBREAKER); - } else if ("VALARM".equals(compName)) { // VALARM component MUST - // only appear within either VEVENT or VTODO - return false; - } else if ("VTIMEZONE".equals(compName)) { - do { - if (false == hasTZ) {// MUST only have 1 time TZ property - propAndValue = lines[index].split(":", 2); - propName = propAndValue[0].split(";", 2)[0]; - - if ("TZOFFSETFROM".equals(propName)) { - value = propAndValue[1]; - buffer.append("TZ" + ":" + value + V10LINEBREAKER); - hasTZ = true; - } - } - index++; - } while (!endTag.equals(lines[index])); - } else - return false; - } else { - while (!endTag.equals(lines[index])) - index++; - } - - return true; - } - - /** split ever property line to String[], not split folding line. */ - private String[] splitProperty(String scStr) { - /* - * Property splitted by \n, and unfold folding lines by removing - * CRLF+LWSP-char - */ - scStr = scStr.replaceAll("\r\n", "\n").replaceAll("\n ", "") - .replaceAll("\n\t", ""); - String[] strs = scStr.split("\n"); - return strs; - } -} diff --git a/core/java/android/syncml/pim/vcalendar/package.html b/core/java/android/syncml/pim/vcalendar/package.html deleted file mode 100644 index cb4ca46..0000000 --- a/core/java/android/syncml/pim/vcalendar/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Support classes for SyncML. -{@hide} -</BODY> -</HTML>
\ No newline at end of file diff --git a/core/java/android/syncml/pim/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java deleted file mode 100644 index ecd719d..0000000 --- a/core/java/android/syncml/pim/vcard/ContactStruct.java +++ /dev/null @@ -1,978 +0,0 @@ -/* - * 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.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. - */ -// TODO: rename the class name, next step -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; - - // 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 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.nonTransactionalInsert(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.nonTransactionalInsert( - GroupMembership.CONTENT_URI, values); - if (resultUri == null) { - Log.e(LOG_TAG, "Faild to insert the person to MyContact."); - provider.nonTransactionalDelete(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.nonTransactionalInsert(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.nonTransactionalInsert( - 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.nonTransactionalInsert( - 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.nonTransactionalInsert( - 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.nonTransactionalInsert(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.nonTransactionalUpdate(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.beginTransaction(); - try { - pushIntoContentProviderOrResolver(provider, myContactsGroupId); - successful = true; - } finally { - provider.endTransaction(successful); - } - } - - public boolean isIgnorable() { - return TextUtils.isEmpty(name) && - TextUtils.isEmpty(phoneticName) && - (phoneList == null || phoneList.size() == 0) && - (contactmethodList == null || contactmethodList.size() == 0); - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardComposer.java b/core/java/android/syncml/pim/vcard/VCardComposer.java deleted file mode 100644 index 192736a..0000000 --- a/core/java/android/syncml/pim/vcard/VCardComposer.java +++ /dev/null @@ -1,353 +0,0 @@ -/* - * 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 - */ -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); - } - - 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); - } - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java deleted file mode 100644 index a0513f1..0000000 --- a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * 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.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. - */ -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"); - - 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); - } - - 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 ""; - } - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardEntryCounter.java b/core/java/android/syncml/pim/vcard/VCardEntryCounter.java deleted file mode 100644 index 03cd1d9..0000000 --- a/core/java/android/syncml/pim/vcard/VCardEntryCounter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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; - -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 diff --git a/core/java/android/syncml/pim/vcard/VCardException.java b/core/java/android/syncml/pim/vcard/VCardException.java deleted file mode 100644 index 35b31ec..0000000 --- a/core/java/android/syncml/pim/vcard/VCardException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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; - -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 ); - } - -} diff --git a/core/java/android/syncml/pim/vcard/VCardNestedException.java b/core/java/android/syncml/pim/vcard/VCardNestedException.java deleted file mode 100644 index def6f3b..0000000 --- a/core/java/android/syncml/pim/vcard/VCardNestedException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ -public class VCardNestedException extends VCardException { - public VCardNestedException() {} - public VCardNestedException(String message) { - super(message); - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardParser.java b/core/java/android/syncml/pim/vcard/VCardParser.java deleted file mode 100644 index 6dad852d..0000000 --- a/core/java/android/syncml/pim/vcard/VCardParser.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.syncml.pim.VParser; -import android.util.Config; -import android.util.Log; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -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; - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardParser_V21.java b/core/java/android/syncml/pim/vcard/VCardParser_V21.java deleted file mode 100644 index d865668..0000000 --- a/core/java/android/syncml/pim/vcard/VCardParser_V21.java +++ /dev/null @@ -1,975 +0,0 @@ -/* - * 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. - */ -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; - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardParser_V30.java b/core/java/android/syncml/pim/vcard/VCardParser_V30.java deleted file mode 100644 index e67525e..0000000 --- a/core/java/android/syncml/pim/vcard/VCardParser_V30.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * 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) - */ -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); - } - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardSourceDetector.java b/core/java/android/syncml/pim/vcard/VCardSourceDetector.java deleted file mode 100644 index 8c48391..0000000 --- a/core/java/android/syncml/pim/vcard/VCardSourceDetector.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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. - * @hide - */ -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; - } - } -} diff --git a/core/java/android/syncml/pim/vcard/VCardVersionException.java b/core/java/android/syncml/pim/vcard/VCardVersionException.java deleted file mode 100644 index 1ca88d1..0000000 --- a/core/java/android/syncml/pim/vcard/VCardVersionException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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. - */ -public class VCardVersionException extends VCardException { - public VCardVersionException() { - } - - public VCardVersionException(String message) { - super(message); - } -} diff --git a/core/java/android/syncml/pim/vcard/package.html b/core/java/android/syncml/pim/vcard/package.html deleted file mode 100644 index cb4ca46..0000000 --- a/core/java/android/syncml/pim/vcard/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Support classes for SyncML. -{@hide} -</BODY> -</HTML>
\ No newline at end of file |