CardDav: move Contact getBody to ExchangeSession and add more attributes support
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1113 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
f52ea840e4
commit
d7506d9f67
|
@ -183,31 +183,31 @@ public abstract class ExchangeSession {
|
|||
LOGGER.debug("Session " + this + " created");
|
||||
}
|
||||
|
||||
protected String formatSearchDate(Date date) {
|
||||
protected static String formatSearchDate(Date date) {
|
||||
SimpleDateFormat dateFormatter = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS, Locale.ENGLISH);
|
||||
dateFormatter.setTimeZone(GMT_TIMEZONE);
|
||||
return dateFormatter.format(date);
|
||||
}
|
||||
|
||||
protected SimpleDateFormat getZuluDateFormat() {
|
||||
protected static SimpleDateFormat getZuluDateFormat() {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(YYYYMMDD_T_HHMMSS_Z, Locale.ENGLISH);
|
||||
dateFormat.setTimeZone(GMT_TIMEZONE);
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
protected SimpleDateFormat getExchangeZuluDateFormat() {
|
||||
protected static SimpleDateFormat getExchangeZuluDateFormat() {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(YYYY_MM_DD_T_HHMMSS_Z, Locale.ENGLISH);
|
||||
dateFormat.setTimeZone(GMT_TIMEZONE);
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
protected SimpleDateFormat getExchangeZuluDateFormatMillisecond() {
|
||||
protected static SimpleDateFormat getExchangeZuluDateFormatMillisecond() {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(YYYY_MM_DD_T_HHMMSS_SSS_Z, Locale.ENGLISH);
|
||||
dateFormat.setTimeZone(GMT_TIMEZONE);
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
protected Date parseDate(String dateString) throws ParseException {
|
||||
protected static Date parseDate(String dateString) throws ParseException {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||
dateFormat.setTimeZone(GMT_TIMEZONE);
|
||||
return dateFormat.parse(dateString);
|
||||
|
@ -594,7 +594,7 @@ public abstract class ExchangeSession {
|
|||
/**
|
||||
* Exchange search filter.
|
||||
*/
|
||||
public abstract static class Condition {
|
||||
public static interface Condition {
|
||||
/**
|
||||
* Append condition to buffer.
|
||||
*
|
||||
|
@ -606,7 +606,7 @@ public abstract class ExchangeSession {
|
|||
/**
|
||||
* Attribute condition.
|
||||
*/
|
||||
public abstract static class AttributeCondition extends Condition {
|
||||
public abstract static class AttributeCondition implements Condition {
|
||||
protected String attributeName;
|
||||
protected Operator operator;
|
||||
protected String value;
|
||||
|
@ -621,7 +621,7 @@ public abstract class ExchangeSession {
|
|||
/**
|
||||
* Multiple condition.
|
||||
*/
|
||||
public abstract static class MultiCondition extends Condition {
|
||||
public abstract static class MultiCondition implements Condition {
|
||||
protected Operator operator;
|
||||
protected List<Condition> conditions;
|
||||
|
||||
|
@ -645,7 +645,7 @@ public abstract class ExchangeSession {
|
|||
/**
|
||||
* Not condition.
|
||||
*/
|
||||
public abstract static class NotCondition extends Condition {
|
||||
public abstract static class NotCondition implements Condition {
|
||||
protected Condition condition;
|
||||
|
||||
protected NotCondition(Condition condition) {
|
||||
|
@ -656,7 +656,7 @@ public abstract class ExchangeSession {
|
|||
/**
|
||||
* Single search filter condition.
|
||||
*/
|
||||
public abstract static class MonoCondition extends Condition {
|
||||
public abstract static class MonoCondition implements Condition {
|
||||
protected String attributeName;
|
||||
protected Operator operator;
|
||||
|
||||
|
@ -1689,6 +1689,70 @@ public abstract class ExchangeSession {
|
|||
return "text/vcard";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getBody() throws HttpException {
|
||||
// build RFC 2426 VCard from contact information
|
||||
VCardWriter writer = new VCardWriter();
|
||||
writer.startCard();
|
||||
writer.appendProperty("UID", getUid());
|
||||
// common name
|
||||
writer.appendProperty("FN", get("cn"));
|
||||
// RFC 2426: Family Name, Given Name, Additional Names, Honorific Prefixes, and Honorific Suffixes
|
||||
writer.appendProperty("N", get("sn"), get("givenName"), get("middlename"), get("personaltitle"), get("namesuffix"));
|
||||
|
||||
writer.appendProperty("TEL;TYPE=cell", get("mobile"));
|
||||
writer.appendProperty("TEL;TYPE=work", get("telephoneNumber"));
|
||||
writer.appendProperty("TEL;TYPE=home", get("homePhone"));
|
||||
writer.appendProperty("TEL;TYPE=fax", get("facsimiletelephonenumber"));
|
||||
writer.appendProperty("TEL;TYPE=pager", get("pager"));
|
||||
|
||||
// The structured type value corresponds, in sequence, to the post office box; the extended address;
|
||||
// the street address; the locality (e.g., city); the region (e.g., state or province);
|
||||
// the postal code; the country name
|
||||
writer.appendProperty("ADR;TYPE=home",
|
||||
null, null, get("homeStreet"), get("homeCity"), get("homeState"), get("homePostalCode"), get("homeCountry"));
|
||||
writer.appendProperty("ADR;TYPE=work",
|
||||
get("postofficebox"), get("roomnumber"), get("street"), get("l"), get("st"), get("postalcode"), get("co"));
|
||||
|
||||
writer.appendProperty("EMAIL;TYPE=work", get("email1"));
|
||||
writer.appendProperty("EMAIL;TYPE=home", get("email2"));
|
||||
writer.appendProperty("EMAIL;TYPE=other", get("email3"));
|
||||
|
||||
writer.appendProperty("ORG", get("o"), get("department"));
|
||||
writer.appendProperty("URL;WORK", get("businesshomepage"));
|
||||
writer.appendProperty("TITLE", get("title"));
|
||||
writer.appendProperty("NOTE", get("textdescription"));
|
||||
|
||||
writer.appendProperty("CUSTOM1", get("extensionattribute1"));
|
||||
writer.appendProperty("CUSTOM2", get("extensionattribute2"));
|
||||
writer.appendProperty("CUSTOM3", get("extensionattribute3"));
|
||||
writer.appendProperty("CUSTOM4", get("extensionattribute4"));
|
||||
|
||||
writer.appendProperty("ROLE", get("profession"));
|
||||
writer.appendProperty("NICKNAME", get("nickname"));
|
||||
writer.appendProperty("X-AIM", get("im"));
|
||||
|
||||
writer.appendProperty("BDAY", get("bday"));
|
||||
|
||||
writer.appendProperty("X-EVOLUTION-ASSISTANT", get("secretarycn"));
|
||||
writer.appendProperty("X-EVOLUTION-MANAGER", get("manager"));
|
||||
writer.appendProperty("X-EVOLUTION-SPOUSE", get("spousecn"));
|
||||
|
||||
|
||||
|
||||
String lastModified = get("lastmodified");
|
||||
if (lastModified != null) {
|
||||
try {
|
||||
writer.appendProperty("REV", getZuluDateFormat().format(getExchangeZuluDateFormatMillisecond().parse(lastModified)));
|
||||
} catch (ParseException e) {
|
||||
LOGGER.warn("Invalid date: "+lastModified);
|
||||
}
|
||||
}
|
||||
writer.endCard();
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2344,7 +2408,7 @@ public abstract class ExchangeSession {
|
|||
* @throws IOException on error
|
||||
*/
|
||||
public List<ExchangeSession.Contact> getAllContacts(String folderPath) throws IOException {
|
||||
return searchContacts(folderPath, ITEM_PROPERTIES, equals("contentclass", "urn:content-classes:person"));
|
||||
return searchContacts(folderPath, ITEM_PROPERTIES, equals("outlookmessageclass", "IPM.Contact"));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2368,7 +2432,7 @@ public abstract class ExchangeSession {
|
|||
*/
|
||||
public List<Event> getEventMessages(String folderPath) throws IOException {
|
||||
return searchEvents(folderPath, ITEM_PROPERTIES,
|
||||
and(equals("contentclass", "urn:content-classes:calendarmessage"),
|
||||
and(equals("outlookmessageclass", "IPM.Schedule.Meeting.Request"),
|
||||
or(isNull("processed"), isFalse("processed"))));
|
||||
}
|
||||
|
||||
|
@ -2399,7 +2463,7 @@ public abstract class ExchangeSession {
|
|||
and(or(isNull("instancetype"),
|
||||
equals("instancetype", 1),
|
||||
and(equals("instancetype", 0), dateCondition)),
|
||||
equals("contentclass", "urn:content-classes:appointment"),
|
||||
equals("outlookmessageclass", "IPM.Appointment"),
|
||||
privateCondition));
|
||||
}
|
||||
|
||||
|
@ -2820,6 +2884,7 @@ public abstract class ExchangeSession {
|
|||
CONTACT_ATTRIBUTES.add("department");
|
||||
CONTACT_ATTRIBUTES.add("email1");
|
||||
CONTACT_ATTRIBUTES.add("email2");
|
||||
CONTACT_ATTRIBUTES.add("email3");
|
||||
CONTACT_ATTRIBUTES.add("facsimiletelephonenumber");
|
||||
CONTACT_ATTRIBUTES.add("givenName");
|
||||
CONTACT_ATTRIBUTES.add("homeCity");
|
||||
|
@ -2849,6 +2914,8 @@ public abstract class ExchangeSession {
|
|||
CONTACT_ATTRIBUTES.add("title");
|
||||
CONTACT_ATTRIBUTES.add("textdescription");
|
||||
CONTACT_ATTRIBUTES.add("im");
|
||||
CONTACT_ATTRIBUTES.add("middlename");
|
||||
CONTACT_ATTRIBUTES.add("lastmodified");
|
||||
}
|
||||
|
||||
|
||||
|
@ -2887,7 +2954,7 @@ public abstract class ExchangeSession {
|
|||
|
||||
Map<String, Map<String, String>> results = new HashMap<String, Map<String, String>>();
|
||||
|
||||
List<Contact> contacts = searchContacts(CONTACTS, CONTACT_ATTRIBUTES, and(equals("contentclass", "urn:content-classes:person"), condition));
|
||||
List<Contact> contacts = searchContacts(CONTACTS, CONTACT_ATTRIBUTES, and(equals("outlookmessageclass", "IPM.Contact"), condition));
|
||||
|
||||
Map<String, String> item;
|
||||
for (Contact contact : contacts) {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* VCard Writer
|
||||
*/
|
||||
public class VCardWriter extends ICSBufferedWriter {
|
||||
public void startCard() {
|
||||
writeLine("BEGIN:VCARD");
|
||||
writeLine("VERSION:3.0");
|
||||
}
|
||||
|
||||
public void appendProperty(String propertyName, String propertyValue) {
|
||||
if (propertyValue != null && propertyValue.length() > 0) {
|
||||
write(propertyName);
|
||||
write(":");
|
||||
if (propertyValue.indexOf('\n') >= 0) {
|
||||
writeLine(propertyValue.replaceAll("\\n", "\\\\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void appendProperty(String propertyName, String... propertyValue) {
|
||||
boolean hasValue = false;
|
||||
for (String value : propertyValue) {
|
||||
if ((value != null) && (value.length() > 0)) {
|
||||
hasValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasValue) {
|
||||
write(propertyName);
|
||||
write(":");
|
||||
boolean first = true;
|
||||
StringBuilder valueBuffer = new StringBuilder();
|
||||
for (String value : propertyValue) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
valueBuffer.append(';');
|
||||
}
|
||||
if (value != null) {
|
||||
valueBuffer.append(value);
|
||||
}
|
||||
}
|
||||
writeLine(valueBuffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void endCard() {
|
||||
writeLine("END:VCARD");
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ import davmail.exception.DavMailException;
|
|||
import davmail.exception.HttpNotFoundException;
|
||||
import davmail.exchange.ExchangeSession;
|
||||
import davmail.exchange.ICSBufferedReader;
|
||||
import davmail.exchange.ICSBufferedWriter;
|
||||
import davmail.http.DavGatewayHttpClientFacade;
|
||||
import davmail.ui.tray.DavGatewayTray;
|
||||
import davmail.util.StringUtil;
|
||||
|
@ -357,7 +356,6 @@ public class DavExchangeSession extends ExchangeSession {
|
|||
super(operator, condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
boolean first = true;
|
||||
|
||||
|
@ -384,7 +382,6 @@ public class DavExchangeSession extends ExchangeSession {
|
|||
super(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append("(Not ");
|
||||
condition.appendTo(buffer);
|
||||
|
@ -417,7 +414,6 @@ public class DavExchangeSession extends ExchangeSession {
|
|||
isIntValue = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append('"').append(Field.get(attributeName).getUri()).append('"');
|
||||
buffer.append(operatorMap.get(operator));
|
||||
|
@ -464,7 +460,6 @@ public class DavExchangeSession extends ExchangeSession {
|
|||
super(attributeName, operator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuilder buffer) {
|
||||
buffer.append('"').append(Field.get(attributeName).getUri()).append('"');
|
||||
buffer.append(operatorMap.get(operator));
|
||||
|
@ -576,68 +571,9 @@ public class DavExchangeSession extends ExchangeSession {
|
|||
super(messageUrl, contentClass, itemBody, etag, noneMatch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody() throws HttpException {
|
||||
// first retrieve contact details
|
||||
String result = null;
|
||||
|
||||
PropFindMethod propFindMethod = null;
|
||||
try {
|
||||
propFindMethod = new PropFindMethod(URIUtil.encodePath(permanentUrl));
|
||||
DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propFindMethod);
|
||||
MultiStatus responses = propFindMethod.getResponseBodyAsMultiStatus();
|
||||
if (responses.getResponses().length > 0) {
|
||||
DavPropertySet properties = responses.getResponses()[0].getProperties(HttpStatus.SC_OK);
|
||||
|
||||
ICSBufferedWriter writer = new ICSBufferedWriter();
|
||||
writer.writeLine("BEGIN:VCARD");
|
||||
writer.writeLine("VERSION:3.0");
|
||||
writer.write("UID:");
|
||||
writer.writeLine(getUid());
|
||||
writer.write("FN:");
|
||||
writer.writeLine(getPropertyIfExists(properties, "cn"));
|
||||
// RFC 2426: Family Name, Given Name, Additional Names, Honorific Prefixes, and Honorific Suffixes
|
||||
writer.write("N:");
|
||||
writer.write(getPropertyIfExists(properties, "sn"));
|
||||
writer.write(";");
|
||||
writer.write(getPropertyIfExists(properties, "givenName"));
|
||||
writer.write(";");
|
||||
writer.writeLine(getPropertyIfExists(properties, "middlename"));
|
||||
|
||||
writer.write("TEL;TYPE=cell:");
|
||||
writer.writeLine(getPropertyIfExists(properties, "mobile"));
|
||||
writer.write("TEL;TYPE=work:");
|
||||
writer.writeLine(getPropertyIfExists(properties, "telephoneNumber"));
|
||||
//writer.writeLine(getPropertyIfExists(properties, DavPropertyName.create("initials", URN_SCHEMAS_CONTACTS), ""));
|
||||
|
||||
// The structured type value corresponds, in sequence, to the post office box; the extended address;
|
||||
// the street address; the locality (e.g., city); the region (e.g., state or province);
|
||||
// the postal code; the country name
|
||||
// ADR;TYPE=dom,home,postal,parcel:;;123 Main Street;Any Town;CA;91921-1234
|
||||
writer.write("ADR;TYPE=home:;;");
|
||||
writer.write(getPropertyIfExists(properties, "homepostaladdress"));
|
||||
writer.write(";;;");
|
||||
writer.newLine();
|
||||
writer.writeLine("END:VCARD");
|
||||
result = writer.toString();
|
||||
|
||||
}
|
||||
} catch (DavException e) {
|
||||
throw buildHttpException(e);
|
||||
} catch (IOException e) {
|
||||
throw buildHttpException(e);
|
||||
} finally {
|
||||
if (propFindMethod != null) {
|
||||
propFindMethod.releaseConnection();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
protected List<DavConstants> buildProperties() throws IOException {
|
||||
ArrayList<DavConstants> list = new ArrayList<DavConstants>();
|
||||
list.add(Field.createDavProperty("contentClass", contentClass));
|
||||
list.add(Field.createDavProperty("contentclass", contentClass));
|
||||
list.add(Field.createDavProperty("outlookmessageclass", "IPM.Contact"));
|
||||
|
||||
ICSBufferedReader reader = new ICSBufferedReader(new StringReader(itemBody));
|
||||
|
@ -1299,7 +1235,9 @@ public class DavExchangeSession extends ExchangeSession {
|
|||
}
|
||||
String contentClass = getPropertyIfExists(responses[0].getProperties(HttpStatus.SC_OK), "contentclass");
|
||||
if ("urn:content-classes:person".equals(contentClass)) {
|
||||
return new Contact(responses[0]);
|
||||
// retrieve Contact properties
|
||||
// TODO: need to check list size
|
||||
return searchContacts(itemPath.substring(0, itemPath.lastIndexOf('/')), CONTACT_ATTRIBUTES, equals("urlcompname", itemPath.substring(itemPath.lastIndexOf('/')+1))).get(0);
|
||||
} else if ("urn:content-classes:appointment".equals(contentClass)
|
||||
|| "urn:content-classes:calendarmessage".equals(contentClass)) {
|
||||
return new Event(responses[0]);
|
||||
|
|
|
@ -69,7 +69,7 @@ public class Field {
|
|||
ApplicationTime, ApplicationTimeArray, Binary, BinaryArray, Boolean, CLSID, CLSIDArray, Currency, CurrencyArray,
|
||||
Double, DoubleArray, Error, Float, FloatArray, Integer, IntegerArray, Long, LongArray, Null, Object,
|
||||
ObjectArray, Short, ShortArray, SystemTime, SystemTimeArray, String, StringArray,
|
||||
Custom
|
||||
String10
|
||||
}
|
||||
|
||||
protected static final Map<PropertyType, String> propertyTypeMap = new HashMap<PropertyType, String>();
|
||||
|
@ -78,9 +78,9 @@ public class Field {
|
|||
propertyTypeMap.put(PropertyType.Long, "0003");
|
||||
propertyTypeMap.put(PropertyType.Boolean, "000b");
|
||||
propertyTypeMap.put(PropertyType.SystemTime, "0040");
|
||||
propertyTypeMap.put(PropertyType.String, "001f");
|
||||
propertyTypeMap.put(PropertyType.String, "001f"); // 001f is PT_UNICODE_STRING, 001E is PT_STRING
|
||||
propertyTypeMap.put(PropertyType.Binary, "0102");
|
||||
propertyTypeMap.put(PropertyType.Custom, "0030");
|
||||
propertyTypeMap.put(PropertyType.String10, "0030"); // decimal PT_STRING
|
||||
}
|
||||
|
||||
protected static enum DistinguishedPropertySetType {
|
||||
|
@ -123,7 +123,7 @@ public class Field {
|
|||
createField(URN_SCHEMAS_HTTPMAIL, "read");
|
||||
//createField("read", 0x0e69, PropertyType.Boolean);//PR_READ
|
||||
createField("deleted", DistinguishedPropertySetType.Common, 0x8570, "deleted");
|
||||
createField("writedeleted", DistinguishedPropertySetType.Common, 0x8570, PropertyType.Custom);
|
||||
createField("writedeleted", DistinguishedPropertySetType.Common, 0x8570, PropertyType.String10);
|
||||
|
||||
createField(URN_SCHEMAS_HTTPMAIL, "date");//PR_CLIENT_SUBMIT_TIME, 0x0039
|
||||
//createField("date", 0x0e06, PropertyType.SystemTime);//PR_MESSAGE_DELIVERY_TIME
|
||||
|
@ -141,10 +141,11 @@ public class Field {
|
|||
createField(URN_SCHEMAS_MAILHEADER, "to"); // DistinguishedPropertySetType.InternetHeaders/To/String
|
||||
createField(URN_SCHEMAS_MAILHEADER, "cc"); // DistinguishedPropertySetType.InternetHeaders/To/String
|
||||
|
||||
createField("lastmodified", 0x3008, PropertyType.SystemTime);//PR_LAST_MODIFICATION_TIME DAV:getlastmodified
|
||||
createField("lastmodified", DAV, "getlastmodified"); // PR_LAST_MODIFICATION_TIME 0x3008 SystemTime
|
||||
|
||||
// failover search
|
||||
createField(DAV, "displayname");
|
||||
createField("urlcompname", 0x10f3, PropertyType.String); //PR_URL_COMP_NAME
|
||||
|
||||
// items
|
||||
createField("etag", DAV, "getetag");
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
*/
|
||||
package davmail.exchange.ews;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* EWS Search Expression.
|
||||
*/
|
||||
public interface SearchExpression {
|
||||
public void appendTo(StringBuilder buffer);
|
||||
/**
|
||||
* Append search expression to buffer.
|
||||
*
|
||||
* @param buffer search buffer
|
||||
*/
|
||||
public void appendTo(StringBuilder buffer);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue