diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 669167a2..e3293449 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -633,6 +633,10 @@ public abstract class ExchangeSession { */ public abstract MessageList searchMessages(String folderName, Set attributes, Condition condition) throws IOException; + public String getServerVersion() { + return serverVersion; + } + @SuppressWarnings({"JavaDoc"}) public enum Operator { Or, And, Not, IsEqualTo, diff --git a/src/java/davmail/exchange/VCalendar.java b/src/java/davmail/exchange/VCalendar.java index 63377ffa..8ffa0e66 100644 --- a/src/java/davmail/exchange/VCalendar.java +++ b/src/java/davmail/exchange/VCalendar.java @@ -469,9 +469,9 @@ public class VCalendar extends VObject { * VCalendar recipients for notifications */ public static class Recipients { - String attendees; - String optionalAttendees; - String organizer; + public String attendees; + public String optionalAttendees; + public String organizer; } /** diff --git a/src/java/davmail/exchange/ews/EWSMethod.java b/src/java/davmail/exchange/ews/EWSMethod.java index 4322171a..df83bdce 100644 --- a/src/java/davmail/exchange/ews/EWSMethod.java +++ b/src/java/davmail/exchange/ews/EWSMethod.java @@ -677,6 +677,8 @@ public abstract class EWSMethod extends PostMethod { handleMimeContent(reader, responseItem); } else if ("Attachments".equals(tagLocalName)) { responseItem.attachments = handleAttachments(reader); + } else if ("EmailAddresses".equals(tagLocalName)) { + handleEmailAddresses(reader, responseItem); } else { if (tagLocalName.endsWith("Id")) { value = getAttributeValue(reader, "Id"); @@ -695,6 +697,18 @@ public abstract class EWSMethod extends PostMethod { return responseItem; } + protected void handleEmailAddresses(XMLStreamReader reader, Item item) throws XMLStreamException { + while (reader.hasNext() && !(XMLStreamUtil.isEndTag(reader, "EmailAddresses"))) { + reader.next(); + if (XMLStreamUtil.isStartTag(reader)) { + String tagLocalName = reader.getLocalName(); + if ("Entry".equals(tagLocalName)) { + item.put(reader.getAttributeValue(null, "Key"), reader.getElementText()); + } + } + } + } + protected List handleAttachments(XMLStreamReader reader) throws XMLStreamException { List attachments = new ArrayList(); while (reader.hasNext() && !(XMLStreamUtil.isEndTag(reader, "Attachments"))) { diff --git a/src/java/davmail/exchange/ews/EwsExchangeSession.java b/src/java/davmail/exchange/ews/EwsExchangeSession.java index 3525c014..8ca73cda 100644 --- a/src/java/davmail/exchange/ews/EwsExchangeSession.java +++ b/src/java/davmail/exchange/ews/EwsExchangeSession.java @@ -898,16 +898,27 @@ public class EwsExchangeSession extends ExchangeSession { protected Contact() { } - protected List buildProperties() { - ArrayList list = new ArrayList(); + protected void buildProperties(List updates) { for (Map.Entry entry : entrySet()) { if ("photo".equals(entry.getKey())) { - list.add(Field.createFieldUpdate("haspicture", "true")); - } else if (!entry.getKey().startsWith("email")) { - list.add(Field.createFieldUpdate(entry.getKey(), entry.getValue())); + updates.add(Field.createFieldUpdate("haspicture", "true")); + } else if (!entry.getKey().startsWith("email") && !entry.getKey().startsWith("smtpemail")) { + updates.add(Field.createFieldUpdate(entry.getKey(), entry.getValue())); } } - return list; + // handle email addresses + IndexedFieldUpdate emailFieldUpdate = null; + for (Map.Entry entry : entrySet()) { + if (entry.getKey().startsWith("smtpemail")) { + if (emailFieldUpdate == null) { + emailFieldUpdate = new IndexedFieldUpdate("EmailAddresses"); + } + emailFieldUpdate.addFieldValue(Field.createFieldUpdate(entry.getKey(), entry.getValue())); + } + } + if (emailFieldUpdate != null) { + updates.add(emailFieldUpdate); + } } @@ -955,8 +966,9 @@ public class EwsExchangeSession extends ExchangeSession { } } - List properties = buildProperties(); + List properties = new ArrayList(); if (currentItemId != null) { + buildProperties(properties); // update createOrUpdateItemMethod = new UpdateItemMethod(MessageDisposition.SaveOnly, ConflictResolution.AlwaysOverwrite, @@ -968,6 +980,7 @@ public class EwsExchangeSession extends ExchangeSession { newItem.type = "Contact"; // force urlcompname on create properties.add(Field.createFieldUpdate("urlcompname", convertItemNameToEML(itemName))); + buildProperties(properties); newItem.setFieldUpdates(properties); createOrUpdateItemMethod = new CreateItemMethod(MessageDisposition.SaveOnly, getFolderId(folderPath), newItem); } @@ -1103,12 +1116,26 @@ public class EwsExchangeSession extends ExchangeSession { } else { updates.add(Field.createFieldUpdate("apptstateflags", "0")); } + + if (vCalendar.isMeeting()) { + VCalendar.Recipients recipients = vCalendar.getRecipients(false); + if (recipients.attendees != null) { + updates.add(Field.createFieldUpdate("to", recipients.attendees)); + } + if (recipients.optionalAttendees != null) { + updates.add(Field.createFieldUpdate("cc", recipients.optionalAttendees)); + } + if (recipients.organizer != null && !vCalendar.isMeetingOrganizer()) { + updates.add(Field.createFieldUpdate("from", recipients.optionalAttendees)); + } + } + // patch allday date values if (vCalendar.isCdoAllDay()) { updates.add(Field.createFieldUpdate("dtstart", convertCalendarDateToExchange(vCalendar.getFirstVeventPropertyValue("DTSTART")))); updates.add(Field.createFieldUpdate("dtend", convertCalendarDateToExchange(vCalendar.getFirstVeventPropertyValue("DTEND")))); } - updates.add(Field.createFieldUpdate("busystatus", "BUSY".equals(vCalendar.getFirstVeventPropertyValue("X-MICROSOFT-CDO-BUSYSTATUS"))?"Busy":"Free")); + updates.add(Field.createFieldUpdate("busystatus", "BUSY".equals(vCalendar.getFirstVeventPropertyValue("X-MICROSOFT-CDO-BUSYSTATUS")) ? "Busy" : "Free")); if (vCalendar.isCdoAllDay()) { if ("Exchange2010".equals(serverVersion)) { updates.add(Field.createFieldUpdate("starttimezone", vCalendar.getVTimezone().getPropertyValue("TZID"))); diff --git a/src/java/davmail/exchange/ews/Field.java b/src/java/davmail/exchange/ews/Field.java index febad8bd..bd64bdf6 100644 --- a/src/java/davmail/exchange/ews/Field.java +++ b/src/java/davmail/exchange/ews/Field.java @@ -71,6 +71,10 @@ public class Field { FIELD_MAP.put("datereceived", new ExtendedFieldURI(0x0e06, ExtendedFieldURI.PropertyType.SystemTime));// PR_MESSAGE_DELIVERY_TIME FIELD_MAP.put("bcc", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "bcc")); + FIELD_MAP.put("to", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "to")); + FIELD_MAP.put("cc", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "cc")); + FIELD_MAP.put("from", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.InternetHeaders, "from")); + // folder FIELD_MAP.put("folderclass", new ExtendedFieldURI(0x3613, ExtendedFieldURI.PropertyType.String)); diff --git a/src/java/davmail/exchange/ews/FieldUpdate.java b/src/java/davmail/exchange/ews/FieldUpdate.java index f50a0022..6df9a6a8 100644 --- a/src/java/davmail/exchange/ews/FieldUpdate.java +++ b/src/java/davmail/exchange/ews/FieldUpdate.java @@ -25,8 +25,8 @@ import java.io.Writer; * Field update */ public class FieldUpdate { - final FieldURI fieldURI; - final String value; + FieldURI fieldURI; + String value; /** * Create field update with value. @@ -39,6 +39,10 @@ public class FieldUpdate { this.value = value; } + protected FieldUpdate() { + // empty constructor for subclass + } + /** * Write field to request writer. * diff --git a/src/java/davmail/exchange/ews/IndexedFieldURI.java b/src/java/davmail/exchange/ews/IndexedFieldURI.java index fad78cff..4dbc2860 100644 --- a/src/java/davmail/exchange/ews/IndexedFieldURI.java +++ b/src/java/davmail/exchange/ews/IndexedFieldURI.java @@ -45,31 +45,9 @@ public class IndexedFieldURI implements FieldURI { } public void appendValue(StringBuilder buffer, String itemType, String value) { - if (fieldURI.startsWith("message")) { - itemType = "Message"; - } else if (fieldURI.startsWith("contacts")) { - itemType = "Contact"; - } - appendTo(buffer); - buffer.append("'); - if (fieldURI.endsWith("EmailAddress")) { - buffer.append(""); - buffer.append(StringUtil.xmlEncode(value)); - buffer.append(""); - } else { - buffer.append("'); - buffer.append(StringUtil.xmlEncode(value)); - buffer.append("'); - } - buffer.append("'); + buffer.append(""); + buffer.append(StringUtil.xmlEncode(value)); + buffer.append(""); } public String getResponseName() { diff --git a/src/java/davmail/exchange/ews/IndexedFieldUpdate.java b/src/java/davmail/exchange/ews/IndexedFieldUpdate.java new file mode 100644 index 00000000..a5eb403b --- /dev/null +++ b/src/java/davmail/exchange/ews/IndexedFieldUpdate.java @@ -0,0 +1,73 @@ +/* + * 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.ews; + +import java.io.IOException; +import java.io.Writer; +import java.util.HashSet; +import java.util.Set; + +/** + * Field update with multiple values. + */ +public class IndexedFieldUpdate extends FieldUpdate { + Set updates = new HashSet(); + protected String collectionName; + + public IndexedFieldUpdate(String collectionName) { + this.collectionName = collectionName; + } + + public void addFieldValue(FieldUpdate fieldUpdate) { + updates.add(fieldUpdate); + } + + /** + * Write field to request writer. + * + * @param itemType item type + * @param writer request writer + * @throws IOException on error + */ + @Override + public void write(String itemType, Writer writer) throws IOException { + if (itemType == null) { + // use collection name on create + writer.write(""); + + StringBuilder buffer = new StringBuilder(); + for (FieldUpdate fieldUpdate : updates) { + fieldUpdate.fieldURI.appendValue(buffer, itemType, fieldUpdate.value); + } + writer.write(buffer.toString()); + + writer.write(""); + } else { + // on update, write each fieldupdate + for (FieldUpdate fieldUpdate : updates) { + fieldUpdate.write(itemType, writer); + } + } + } + +} diff --git a/src/java/davmail/exchange/ews/InternetMessageHeaderFieldURI.java b/src/java/davmail/exchange/ews/InternetMessageHeaderFieldURI.java deleted file mode 100644 index bb9f70b0..00000000 --- a/src/java/davmail/exchange/ews/InternetMessageHeaderFieldURI.java +++ /dev/null @@ -1,33 +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.ews; - -/** - * Internet Message Header Field. - */ -public class InternetMessageHeaderFieldURI extends IndexedFieldURI { - /** - * Create header field for field name. - * - * @param fieldName header field name - */ - public InternetMessageHeaderFieldURI(String fieldName) { - super("item:InternetMessageHeader", fieldName); - } -} diff --git a/src/java/davmail/util/StringUtil.java b/src/java/davmail/util/StringUtil.java index 26d0eb97..02edcbca 100644 --- a/src/java/davmail/util/StringUtil.java +++ b/src/java/davmail/util/StringUtil.java @@ -267,6 +267,12 @@ public final class StringUtil { if (result.indexOf(':') >= 0) { result = COLON_PATTERN.matcher(result).replaceAll("%3A"); } + if (result.indexOf('<') >= 0) { + result = LT_PATTERN.matcher(result).replaceAll("%3C"); + } + if (result.indexOf('>') >= 0) { + result = GT_PATTERN.matcher(result).replaceAll("%3E"); + } return result; } diff --git a/src/test/davmail/exchange/TestExchangeSessionContact.java b/src/test/davmail/exchange/TestExchangeSessionContact.java index b5e74c38..350a8a5e 100644 --- a/src/test/davmail/exchange/TestExchangeSessionContact.java +++ b/src/test/davmail/exchange/TestExchangeSessionContact.java @@ -18,6 +18,7 @@ */ package davmail.exchange; +import davmail.Settings; import davmail.util.IOUtil; import org.apache.commons.codec.binary.Base64; @@ -179,7 +180,9 @@ public class TestExchangeSessionContact extends AbstractExchangeSessionTestCase assertEquals("http://fburl", contact.get("fburl")); assertEquals("true", contact.get("haspicture")); - assertNotNull(session.getContactPhoto(contact)); + if (!Settings.getBooleanProperty("davmail.enableEws") || "Exchange2010".equals(session.getServerVersion())) { + assertNotNull(session.getContactPhoto(contact)); + } } public void testUpdateContact() throws IOException {