mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-13 11:12:22 -05:00
Carddav: refactor VCard handling to merge with VCalendar code
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1316 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
1344e4c9bd
commit
3725a147c4
@ -2083,7 +2083,7 @@ public abstract class ExchangeSession {
|
|||||||
result.writeLine("CLASS:PRIVATE");
|
result.writeLine("CLASS:PRIVATE");
|
||||||
} else if ("PRIVATE".equalsIgnoreCase(eventClass)) {
|
} else if ("PRIVATE".equalsIgnoreCase(eventClass)) {
|
||||||
result.writeLine("CLASS:CONFIDENTIAL");
|
result.writeLine("CLASS:CONFIDENTIAL");
|
||||||
} else {
|
} else if (eventClass != null) {
|
||||||
result.writeLine("CLASS:" + eventClass);
|
result.writeLine("CLASS:" + eventClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2786,9 +2786,8 @@ public abstract class ExchangeSession {
|
|||||||
Map<String, String> properties = new HashMap<String, String>();
|
Map<String, String> properties = new HashMap<String, String>();
|
||||||
properties.put("outlookmessageclass", "IPM.Contact");
|
properties.put("outlookmessageclass", "IPM.Contact");
|
||||||
|
|
||||||
VCardReader reader = new VCardReader(new StringReader(itemBody));
|
VObject vcard = new VObject(new ICSBufferedReader(new StringReader(itemBody)));
|
||||||
VCardReader.Property property;
|
for (VProperty property:vcard.getProperties()) {
|
||||||
while ((property = reader.readProperty()) != null) {
|
|
||||||
if ("FN".equals(property.getKey())) {
|
if ("FN".equals(property.getKey())) {
|
||||||
properties.put("cn", property.getValue());
|
properties.put("cn", property.getValue());
|
||||||
properties.put("subject", property.getValue());
|
properties.put("subject", property.getValue());
|
||||||
@ -3331,6 +3330,7 @@ public abstract class ExchangeSession {
|
|||||||
* @param end end date in Exchange zulu format
|
* @param end end date in Exchange zulu format
|
||||||
* @param interval freebusy interval in minutes
|
* @param interval freebusy interval in minutes
|
||||||
* @return freebusy data or null
|
* @return freebusy data or null
|
||||||
|
* @throws IOException on error
|
||||||
*/
|
*/
|
||||||
protected abstract String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException;
|
protected abstract String getFreeBusyData(String attendee, String start, String end, int interval) throws IOException;
|
||||||
|
|
||||||
|
@ -1,238 +0,0 @@
|
|||||||
/*
|
|
||||||
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
|
|
||||||
* Copyright (C) 2010 Mickael Guessant
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
package davmail.exchange;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* VCARD reader.
|
|
||||||
*/
|
|
||||||
public class VCardReader extends ICSBufferedReader {
|
|
||||||
/**
|
|
||||||
* VCard property
|
|
||||||
*/
|
|
||||||
public static class Property {
|
|
||||||
protected String key;
|
|
||||||
protected Map<String, Set<String>> params;
|
|
||||||
protected List<String> values;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property key, without optional parameters (e.g. TEL).
|
|
||||||
*
|
|
||||||
* @return key
|
|
||||||
*/
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property value.
|
|
||||||
*
|
|
||||||
* @return value
|
|
||||||
*/
|
|
||||||
public String getValue() {
|
|
||||||
if (values == null || values.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return values.get(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Property values.
|
|
||||||
*
|
|
||||||
* @return values
|
|
||||||
*/
|
|
||||||
public List<String> getValues() {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasParam(String paramName, String paramValue) {
|
|
||||||
return params != null && params.containsKey(paramName) && params.get(paramName).contains(paramValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addParam(String paramName, Set<String> paramValues) {
|
|
||||||
if (params == null) {
|
|
||||||
params = new HashMap<String, Set<String>>();
|
|
||||||
}
|
|
||||||
if (params.get(paramName) == null) {
|
|
||||||
params.put(paramName, paramValues);
|
|
||||||
} else {
|
|
||||||
params.get(paramName).addAll(paramValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addValue(String value) {
|
|
||||||
if (values == null) {
|
|
||||||
values = new ArrayList<String>();
|
|
||||||
}
|
|
||||||
values.add(decodeValue(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String decodeValue(String value) {
|
|
||||||
if (value == null || (value.indexOf('\\') < 0 && value.indexOf(',') < 0)) {
|
|
||||||
return value;
|
|
||||||
} else {
|
|
||||||
// decode value
|
|
||||||
StringBuilder decodedValue = new StringBuilder();
|
|
||||||
for (int i = 0; i < value.length(); i++) {
|
|
||||||
char c = value.charAt(i);
|
|
||||||
if (c == '\\') {
|
|
||||||
//noinspection AssignmentToForLoopParameter
|
|
||||||
c = value.charAt(++i);
|
|
||||||
if (c == 'n') {
|
|
||||||
c = '\n';
|
|
||||||
} else if (c == 'r') {
|
|
||||||
c = '\r';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// iPhone encodes category separator
|
|
||||||
if (c == ',' &&
|
|
||||||
// multivalued properties
|
|
||||||
("N".equals(key) ||
|
|
||||||
"ADR".equals(key) ||
|
|
||||||
"CATEGORIES".equals(key) ||
|
|
||||||
"NICKNAME".equals(key)
|
|
||||||
)) {
|
|
||||||
// convert multiple values to multiline values (e.g. street)
|
|
||||||
c = '\n';
|
|
||||||
}
|
|
||||||
decodedValue.append(c);
|
|
||||||
}
|
|
||||||
return decodedValue.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKey(String key) {
|
|
||||||
int dotIndex = key.indexOf('.');
|
|
||||||
if (dotIndex < 0) {
|
|
||||||
this.key = key;
|
|
||||||
} else {
|
|
||||||
this.key = key.substring(dotIndex + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a VCARD reader on the provided reader
|
|
||||||
*
|
|
||||||
* @param in input reader
|
|
||||||
* @throws IOException on error
|
|
||||||
*/
|
|
||||||
public VCardReader(Reader in) throws IOException {
|
|
||||||
super(in);
|
|
||||||
String firstLine = readLine();
|
|
||||||
if (firstLine == null || !"BEGIN:VCARD".equals(firstLine)) {
|
|
||||||
throw new IOException("Invalid VCard body: " + firstLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static enum State {
|
|
||||||
KEY, PARAM_NAME, PARAM_VALUE, QUOTED_PARAM_VALUE, VALUE, BACKSLASH
|
|
||||||
}
|
|
||||||
|
|
||||||
public Property readProperty() throws IOException {
|
|
||||||
Property property = null;
|
|
||||||
String line = readLine();
|
|
||||||
if (line != null && !"END:VCARD".equals(line)) {
|
|
||||||
property = new Property();
|
|
||||||
State state = State.KEY;
|
|
||||||
String paramName = null;
|
|
||||||
Set<String> paramValues = null;
|
|
||||||
int startIndex = 0;
|
|
||||||
for (int i = 0; i < line.length(); i++) {
|
|
||||||
char currentChar = line.charAt(i);
|
|
||||||
if (state == State.KEY) {
|
|
||||||
if (currentChar == ':') {
|
|
||||||
property.setKey(line.substring(startIndex, i));
|
|
||||||
state = State.VALUE;
|
|
||||||
startIndex = i + 1;
|
|
||||||
} else if (currentChar == ';') {
|
|
||||||
property.setKey(line.substring(startIndex, i));
|
|
||||||
state = State.PARAM_NAME;
|
|
||||||
startIndex = i + 1;
|
|
||||||
}
|
|
||||||
} else if (state == State.PARAM_NAME) {
|
|
||||||
if (currentChar == '=') {
|
|
||||||
paramName = line.substring(startIndex, i).toUpperCase();
|
|
||||||
state = State.PARAM_VALUE;
|
|
||||||
paramValues = new HashSet<String>();
|
|
||||||
startIndex = i + 1;
|
|
||||||
} else if (currentChar == ';') {
|
|
||||||
// param with no value
|
|
||||||
paramName = line.substring(startIndex, i).toUpperCase();
|
|
||||||
property.addParam(paramName, null);
|
|
||||||
state = State.PARAM_NAME;
|
|
||||||
startIndex = i + 1;
|
|
||||||
} else if (currentChar == ':') {
|
|
||||||
// param with no value
|
|
||||||
paramName = line.substring(startIndex, i).toUpperCase();
|
|
||||||
property.addParam(paramName, null);
|
|
||||||
state = State.VALUE;
|
|
||||||
startIndex = i + 1;
|
|
||||||
}
|
|
||||||
} else if (state == State.PARAM_VALUE) {
|
|
||||||
if (currentChar == '"') {
|
|
||||||
state = State.QUOTED_PARAM_VALUE;
|
|
||||||
startIndex = i + 1;
|
|
||||||
} else if (currentChar == ':') {
|
|
||||||
if (startIndex < i) {
|
|
||||||
paramValues.add(line.substring(startIndex, i).toLowerCase());
|
|
||||||
}
|
|
||||||
property.addParam(paramName, paramValues);
|
|
||||||
state = State.VALUE;
|
|
||||||
startIndex = i + 1;
|
|
||||||
} else if (currentChar == ';') {
|
|
||||||
if (startIndex < i) {
|
|
||||||
paramValues.add(line.substring(startIndex, i).toLowerCase());
|
|
||||||
}
|
|
||||||
property.addParam(paramName, paramValues);
|
|
||||||
state = State.PARAM_NAME;
|
|
||||||
startIndex = i + 1;
|
|
||||||
} else if (currentChar == ',') {
|
|
||||||
if (startIndex < i) {
|
|
||||||
paramValues.add(line.substring(startIndex, i).toLowerCase());
|
|
||||||
}
|
|
||||||
startIndex = i + 1;
|
|
||||||
}
|
|
||||||
} else if (state == State.QUOTED_PARAM_VALUE) {
|
|
||||||
if (currentChar == '"') {
|
|
||||||
state = State.PARAM_VALUE;
|
|
||||||
paramValues.add(line.substring(startIndex, i).toLowerCase());
|
|
||||||
startIndex = i + 1;
|
|
||||||
}
|
|
||||||
} else if (state == State.VALUE) {
|
|
||||||
if (currentChar == '\\') {
|
|
||||||
state = State.BACKSLASH;
|
|
||||||
} else if (currentChar == ';') {
|
|
||||||
property.addValue(line.substring(startIndex, i));
|
|
||||||
startIndex = i + 1;
|
|
||||||
}
|
|
||||||
} else if (state == State.BACKSLASH) {
|
|
||||||
state = State.VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
property.addValue(line.substring(startIndex));
|
|
||||||
}
|
|
||||||
return property;
|
|
||||||
}
|
|
||||||
}
|
|
126
src/java/davmail/exchange/VObject.java
Normal file
126
src/java/davmail/exchange/VObject.java
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
|
||||||
|
* Copyright (C) 2010 Mickael Guessant
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
package davmail.exchange;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for VCalendar, VTimezone, VEvent.
|
||||||
|
*/
|
||||||
|
public class VObject {
|
||||||
|
/**
|
||||||
|
* VObject properties
|
||||||
|
*/
|
||||||
|
ArrayList<VProperty> properties;
|
||||||
|
/**
|
||||||
|
* Inner VObjects (e.g. VEVENT, VALARM, ...)
|
||||||
|
*/
|
||||||
|
ArrayList<VObject> objects;
|
||||||
|
/**
|
||||||
|
* Object base name (VCALENDAR, VEVENT, VCARD...).
|
||||||
|
*/
|
||||||
|
public String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create VObject with given type
|
||||||
|
*
|
||||||
|
* @param beginProperty first line property
|
||||||
|
* @param reader stream reader just after the BEGIN:TYPE line
|
||||||
|
* @throws IOException on error
|
||||||
|
*/
|
||||||
|
public VObject(VProperty beginProperty, BufferedReader reader) throws IOException {
|
||||||
|
if (!"BEGIN".equals(beginProperty.getKey())) {
|
||||||
|
throw new IOException("Invalid first line: " + beginProperty);
|
||||||
|
}
|
||||||
|
type = beginProperty.getValue();
|
||||||
|
String endLine = "END:" + type;
|
||||||
|
String line = reader.readLine();
|
||||||
|
while (line != null && !endLine.equals(line)) {
|
||||||
|
handleLine(line, reader);
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
if (line == null) {
|
||||||
|
throw new IOException("Unexpected end of stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create VObject from reader.
|
||||||
|
*
|
||||||
|
* @param reader stream reader just after the BEGIN:TYPE line
|
||||||
|
* @throws IOException on error
|
||||||
|
*/
|
||||||
|
public VObject(BufferedReader reader) throws IOException {
|
||||||
|
this(new VProperty(reader.readLine()), reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void handleLine(String line, BufferedReader reader) throws IOException {
|
||||||
|
VProperty property = new VProperty(line);
|
||||||
|
// inner object
|
||||||
|
if ("BEGIN".equals(property.getKey())) {
|
||||||
|
addObject(new VObject(property, reader));
|
||||||
|
} else {
|
||||||
|
addProperty(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addObject(VObject object) {
|
||||||
|
if (objects == null) {
|
||||||
|
objects = new ArrayList<VObject>();
|
||||||
|
}
|
||||||
|
objects.add(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addProperty(VProperty property) {
|
||||||
|
if (properties == null) {
|
||||||
|
properties = new ArrayList<VProperty>();
|
||||||
|
}
|
||||||
|
properties.add(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeTo(ICSBufferedWriter writer) {
|
||||||
|
writer.write("BEGIN:");
|
||||||
|
writer.writeLine(type);
|
||||||
|
if (properties != null) {
|
||||||
|
for (VProperty property : properties) {
|
||||||
|
writer.writeLine(property.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (objects != null) {
|
||||||
|
for (VObject object : objects) {
|
||||||
|
object.writeTo(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.write("END:");
|
||||||
|
writer.writeLine(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
ICSBufferedWriter writer = new ICSBufferedWriter();
|
||||||
|
writeTo(writer);
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VProperty> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
318
src/java/davmail/exchange/VProperty.java
Normal file
318
src/java/davmail/exchange/VProperty.java
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
|
||||||
|
* Copyright (C) 2010 Mickael Guessant
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
package davmail.exchange;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VCard property
|
||||||
|
*/
|
||||||
|
public class VProperty {
|
||||||
|
protected static enum State {
|
||||||
|
KEY, PARAM_NAME, PARAM_VALUE, QUOTED_PARAM_VALUE, VALUE, BACKSLASH
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class Param {
|
||||||
|
String name;
|
||||||
|
List<String> values;
|
||||||
|
|
||||||
|
public void addAll(List<String> paramValues) {
|
||||||
|
if (values == null) {
|
||||||
|
values = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
values.addAll(paramValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String key;
|
||||||
|
protected List<Param> params;
|
||||||
|
protected List<String> values;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create VProperty from line.
|
||||||
|
*
|
||||||
|
* @param line card line
|
||||||
|
*/
|
||||||
|
public VProperty(String line) {
|
||||||
|
if (line != null && !"END:VCARD".equals(line)) {
|
||||||
|
State state = State.KEY;
|
||||||
|
String paramName = null;
|
||||||
|
List<String> paramValues = null;
|
||||||
|
int startIndex = 0;
|
||||||
|
for (int i = 0; i < line.length(); i++) {
|
||||||
|
char currentChar = line.charAt(i);
|
||||||
|
if (state == State.KEY) {
|
||||||
|
if (currentChar == ':') {
|
||||||
|
setKey(line.substring(startIndex, i));
|
||||||
|
state = State.VALUE;
|
||||||
|
startIndex = i + 1;
|
||||||
|
} else if (currentChar == ';') {
|
||||||
|
setKey(line.substring(startIndex, i));
|
||||||
|
state = State.PARAM_NAME;
|
||||||
|
startIndex = i + 1;
|
||||||
|
}
|
||||||
|
} else if (state == State.PARAM_NAME) {
|
||||||
|
if (currentChar == '=') {
|
||||||
|
paramName = line.substring(startIndex, i).toUpperCase();
|
||||||
|
state = State.PARAM_VALUE;
|
||||||
|
paramValues = new ArrayList<String>();
|
||||||
|
startIndex = i + 1;
|
||||||
|
} else if (currentChar == ';') {
|
||||||
|
// param with no value
|
||||||
|
paramName = line.substring(startIndex, i).toUpperCase();
|
||||||
|
addParam(paramName, null);
|
||||||
|
state = State.PARAM_NAME;
|
||||||
|
startIndex = i + 1;
|
||||||
|
} else if (currentChar == ':') {
|
||||||
|
// param with no value
|
||||||
|
paramName = line.substring(startIndex, i).toUpperCase();
|
||||||
|
addParam(paramName, null);
|
||||||
|
state = State.VALUE;
|
||||||
|
startIndex = i + 1;
|
||||||
|
}
|
||||||
|
} else if (state == State.PARAM_VALUE) {
|
||||||
|
if (currentChar == '"') {
|
||||||
|
state = State.QUOTED_PARAM_VALUE;
|
||||||
|
startIndex = i + 1;
|
||||||
|
} else if (currentChar == ':') {
|
||||||
|
if (startIndex < i) {
|
||||||
|
paramValues.add(line.substring(startIndex, i));
|
||||||
|
}
|
||||||
|
addParam(paramName, paramValues);
|
||||||
|
state = State.VALUE;
|
||||||
|
startIndex = i + 1;
|
||||||
|
} else if (currentChar == ';') {
|
||||||
|
if (startIndex < i) {
|
||||||
|
paramValues.add(line.substring(startIndex, i));
|
||||||
|
}
|
||||||
|
addParam(paramName, paramValues);
|
||||||
|
state = State.PARAM_NAME;
|
||||||
|
startIndex = i + 1;
|
||||||
|
} else if (currentChar == ',') {
|
||||||
|
if (startIndex < i) {
|
||||||
|
paramValues.add(line.substring(startIndex, i));
|
||||||
|
}
|
||||||
|
startIndex = i + 1;
|
||||||
|
}
|
||||||
|
} else if (state == State.QUOTED_PARAM_VALUE) {
|
||||||
|
if (currentChar == '"') {
|
||||||
|
state = State.PARAM_VALUE;
|
||||||
|
paramValues.add(line.substring(startIndex, i));
|
||||||
|
startIndex = i + 1;
|
||||||
|
}
|
||||||
|
} else if (state == State.VALUE) {
|
||||||
|
if (currentChar == '\\') {
|
||||||
|
state = State.BACKSLASH;
|
||||||
|
} else if (currentChar == ';') {
|
||||||
|
addValue(line.substring(startIndex, i));
|
||||||
|
startIndex = i + 1;
|
||||||
|
}
|
||||||
|
} else if (state == State.BACKSLASH) {
|
||||||
|
state = State.VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addValue(line.substring(startIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property key, without optional parameters (e.g. TEL).
|
||||||
|
*
|
||||||
|
* @return key
|
||||||
|
*/
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property value.
|
||||||
|
*
|
||||||
|
* @return value
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
if (values == null || values.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return values.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property values.
|
||||||
|
*
|
||||||
|
* @return values
|
||||||
|
*/
|
||||||
|
public List<String> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the property has a param named paramName with given value.
|
||||||
|
*
|
||||||
|
* @param paramName param name
|
||||||
|
* @param paramValue param value
|
||||||
|
* @return true if property has param name and value
|
||||||
|
*/
|
||||||
|
public boolean hasParam(String paramName, String paramValue) {
|
||||||
|
return params != null && getParam(paramName) != null && containsIgnoreCase(getParam(paramName).values, paramValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean containsIgnoreCase(List<String> stringCollection, String value) {
|
||||||
|
for (String collectionValue : stringCollection) {
|
||||||
|
if (value.equalsIgnoreCase(collectionValue)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addParam(String paramName, List<String> paramValues) {
|
||||||
|
if (params == null) {
|
||||||
|
params = new ArrayList<Param>();
|
||||||
|
}
|
||||||
|
Param currentParam = getParam(paramName);
|
||||||
|
if (currentParam == null) {
|
||||||
|
currentParam = new Param();
|
||||||
|
currentParam.name = paramName;
|
||||||
|
params.add(currentParam);
|
||||||
|
}
|
||||||
|
currentParam.addAll(paramValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Param getParam(String paramName) {
|
||||||
|
if (params != null) {
|
||||||
|
for (Param param:params) {
|
||||||
|
if (paramName.equals(param.name)) {
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addValue(String value) {
|
||||||
|
if (values == null) {
|
||||||
|
values = new ArrayList<String>();
|
||||||
|
}
|
||||||
|
values.add(decodeValue(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String decodeValue(String value) {
|
||||||
|
if (value == null || (value.indexOf('\\') < 0 && value.indexOf(',') < 0)) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
// decode value
|
||||||
|
StringBuilder decodedValue = new StringBuilder();
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c == '\\') {
|
||||||
|
//noinspection AssignmentToForLoopParameter
|
||||||
|
c = value.charAt(++i);
|
||||||
|
if (c == 'n') {
|
||||||
|
c = '\n';
|
||||||
|
} else if (c == 'r') {
|
||||||
|
c = '\r';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// iPhone encodes category separator
|
||||||
|
if (c == ',' &&
|
||||||
|
// multivalued properties
|
||||||
|
("N".equals(key) ||
|
||||||
|
"ADR".equals(key) ||
|
||||||
|
"CATEGORIES".equals(key) ||
|
||||||
|
"NICKNAME".equals(key)
|
||||||
|
)) {
|
||||||
|
// convert multiple values to multiline values (e.g. street)
|
||||||
|
c = '\n';
|
||||||
|
}
|
||||||
|
decodedValue.append(c);
|
||||||
|
}
|
||||||
|
return decodedValue.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set property key.
|
||||||
|
*
|
||||||
|
* @param key property key
|
||||||
|
*/
|
||||||
|
public void setKey(String key) {
|
||||||
|
int dotIndex = key.indexOf('.');
|
||||||
|
if (dotIndex < 0) {
|
||||||
|
this.key = key;
|
||||||
|
} else {
|
||||||
|
this.key = key.substring(dotIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
buffer.append(key);
|
||||||
|
if (params != null) {
|
||||||
|
for (Param param : params) {
|
||||||
|
buffer.append(';').append(param.name);
|
||||||
|
if (param.values != null) {
|
||||||
|
buffer.append('=');
|
||||||
|
for (String value : param.values) {
|
||||||
|
appendParamValue(buffer, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.append(':');
|
||||||
|
if (values != null) {
|
||||||
|
boolean firstValue = true;
|
||||||
|
for (String value : values) {
|
||||||
|
if (firstValue) {
|
||||||
|
firstValue = false;
|
||||||
|
} else {
|
||||||
|
buffer.append(';');
|
||||||
|
}
|
||||||
|
appendMultilineEncodedValue(buffer, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void appendParamValue(StringBuilder buffer, String value) {
|
||||||
|
if (Math.max(value.indexOf(';'), value.indexOf(',')) >= 0) {
|
||||||
|
buffer.append('"').append(value).append('"');
|
||||||
|
} else {
|
||||||
|
buffer.append(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append and encode \n to \\n in value.
|
||||||
|
*
|
||||||
|
* @param buffer line buffer
|
||||||
|
* @param value value
|
||||||
|
*/
|
||||||
|
protected void appendMultilineEncodedValue(StringBuilder buffer, String value) {
|
||||||
|
for (int i = 0; i < value.length(); i++) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
if (c == '\n') {
|
||||||
|
buffer.append("\\n");
|
||||||
|
} else {
|
||||||
|
buffer.append(value.charAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -258,7 +258,7 @@ public class TestExchangeSessionContact extends AbstractExchangeSessionTestCase
|
|||||||
|
|
||||||
assertNull(contact.get("private"));
|
assertNull(contact.get("private"));
|
||||||
|
|
||||||
assertNull(contact.get("haspicture"));
|
assertTrue(contact.get("haspicture") == null || "false".equals(contact.get("haspicture")));
|
||||||
|
|
||||||
assertNull(session.getContactPhoto(contact));
|
assertNull(session.getContactPhoto(contact));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user