diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index c75f331a..9c2cbbde 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -2111,22 +2111,6 @@ public abstract class ExchangeSession { return writer.toString(); } - protected String convertZuluDateToBday(String value) { - String result = null; - if (value != null && value.length() > 0) { - try { - SimpleDateFormat parser = ExchangeSession.getZuluDateFormat(); - Calendar cal = Calendar.getInstance(); - cal.setTime(parser.parse(value)); - cal.add(Calendar.HOUR_OF_DAY, 12); - result = ExchangeSession.getVcardBdayFormat().format(cal.getTime()); - } catch (ParseException e) { - LOGGER.warn("Invalid date: " + value); - } - } - return result; - } - } /** @@ -2912,6 +2896,22 @@ public abstract class ExchangeSession { return internalCreateOrUpdateContact(folderPath, itemName, properties, etag, noneMatch); } + protected String convertZuluDateToBday(String value) { + String result = null; + if (value != null && value.length() > 0) { + try { + SimpleDateFormat parser = ExchangeSession.getZuluDateFormat(); + Calendar cal = Calendar.getInstance(); + cal.setTime(parser.parse(value)); + cal.add(Calendar.HOUR_OF_DAY, 12); + result = ExchangeSession.getVcardBdayFormat().format(cal.getTime()); + } catch (ParseException e) { + LOGGER.warn("Invalid date: " + value); + } + } + return result; + } + protected String convertBDayToZulu(String value) { String result = null; if (value != null && value.length() > 0) { diff --git a/src/java/davmail/exchange/dav/DavExchangeSession.java b/src/java/davmail/exchange/dav/DavExchangeSession.java index 9ada8d30..7e2061bd 100644 --- a/src/java/davmail/exchange/dav/DavExchangeSession.java +++ b/src/java/davmail/exchange/dav/DavExchangeSession.java @@ -1395,6 +1395,8 @@ public class DavExchangeSession extends ExchangeSession { eventProperties.add("uid"); eventProperties.add("percentcomplete"); eventProperties.add("keywords"); + eventProperties.add("startdate"); + eventProperties.add("duedate"); MultiStatusResponse[] responses = searchItems(folderPath, eventProperties, DavExchangeSession.this.isEqualTo("urlcompname", convertItemNameToEML(itemName)), FolderQueryTraversal.Shallow, 1); if (responses.length == 0) { @@ -1409,6 +1411,9 @@ public class DavExchangeSession extends ExchangeSession { vEvent.setPropertyValue("CREATED", convertDateFromExchange(getPropertyIfExists(davPropertySet, "created"))); vEvent.setPropertyValue("LAST-MODIFIED", convertDateFromExchange(getPropertyIfExists(davPropertySet, "calendarlastmodified"))); vEvent.setPropertyValue("DTSTAMP", convertDateFromExchange(getPropertyIfExists(davPropertySet, "dtstamp"))); + vEvent.setPropertyValue("DUE;VALUE=DATE", convertDateFromExchangeToTaskDate(getPropertyIfExists(davPropertySet, "duedate"))); + vEvent.setPropertyValue("DTSTART;VALUE=DATE", convertDateFromExchangeToTaskDate(getPropertyIfExists(davPropertySet, "startdate"))); + String uid = getPropertyIfExists(davPropertySet, "calendaruid"); if (uid == null) { uid = getPropertyIfExists(davPropertySet, "uid"); @@ -1578,6 +1583,8 @@ public class DavExchangeSession extends ExchangeSession { propertyValues.add(Field.createPropertyValue("percentcomplete", String.valueOf(Double.parseDouble(percentComplete) / 100))); propertyValues.add(Field.createPropertyValue("taskstatus", vTodoToTaskStatusMap.get(vCalendar.getFirstVeventPropertyValue("STATUS")))); propertyValues.add(Field.createPropertyValue("keywords", vCalendar.getFirstVeventPropertyValue("CATEGORIES"))); + propertyValues.add(Field.createPropertyValue("duedate", convertTaskDateToZulu(vCalendar.getFirstVeventPropertyValue("DUE")))); + propertyValues.add(Field.createPropertyValue("startdate", convertTaskDateToZulu(vCalendar.getFirstVeventPropertyValue("DTSTART")))); ExchangePropPatchMethod propPatchMethod = new ExchangePropPatchMethod(encodedHref, propertyValues); propPatchMethod.setRequestHeader("Translate", "f"); @@ -2880,4 +2887,45 @@ public class DavExchangeSession extends ExchangeSession { return dateFormatter.format(date); } + protected String convertTaskDateToZulu(String value) { + String result = null; + if (value != null && value.length() > 0) { + try { + SimpleDateFormat parser; + if (value.length() == 8) { + parser = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH); + parser.setTimeZone(GMT_TIMEZONE); + } else if (value.length() == 15) { + parser = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH); + parser.setTimeZone(GMT_TIMEZONE); + } else { + parser = ExchangeSession.getExchangeZuluDateFormat(); + } + Calendar calendarValue = Calendar.getInstance(GMT_TIMEZONE); + calendarValue.setTime(parser.parse(value)); + calendarValue.set(Calendar.HOUR, 0); + calendarValue.set(Calendar.MINUTE, 0); + calendarValue.set(Calendar.SECOND, 0); + result = ExchangeSession.getExchangeZuluDateFormatMillisecond().format(calendarValue.getTime()); + } catch (ParseException e) { + LOGGER.warn("Invalid date: " + value); + } + } + + return result; + } + + protected String convertDateFromExchangeToTaskDate(String exchangeDateValue) throws DavMailException { + String result = null; + if (exchangeDateValue != null) { + try { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH); + dateFormat.setTimeZone(GMT_TIMEZONE); + result = dateFormat.format(getExchangeZuluDateFormatMillisecond().parse(exchangeDateValue)); + } catch (ParseException e) { + throw new DavMailException("EXCEPTION_INVALID_DATE", exchangeDateValue); + } + } + return result; + } } diff --git a/src/java/davmail/exchange/dav/ExchangePropPatchMethod.java b/src/java/davmail/exchange/dav/ExchangePropPatchMethod.java index 52df6ec8..5fc5789b 100644 --- a/src/java/davmail/exchange/dav/ExchangePropPatchMethod.java +++ b/src/java/davmail/exchange/dav/ExchangePropPatchMethod.java @@ -87,7 +87,7 @@ public class ExchangePropPatchMethod extends PostMethod { final Set deletePropertyValues = new HashSet(); for (PropertyValue propertyValue : propertyValues) { // data type namespace - if (!nameSpaceMap.containsKey(TYPE_NAMESPACE) && propertyValue.getType() != null) { + if (!nameSpaceMap.containsKey(TYPE_NAMESPACE) && propertyValue.getTypeString() != null) { nameSpaceMap.put(TYPE_NAMESPACE, currentChar++); } // property namespace @@ -115,17 +115,13 @@ public class ExchangePropPatchMethod extends PostMethod { if (!setPropertyValues.isEmpty()) { writer.write(""); for (PropertyValue propertyValue : setPropertyValues) { - PropertyType propertyType = propertyValue.getType(); + String typeString = propertyValue.getTypeString(); char nameSpaceChar = (char) nameSpaceMap.get(propertyValue.getNamespaceUri()).intValue(); writer.write('<'); writer.write(nameSpaceChar); writer.write(':'); writer.write(propertyValue.getName()); - if (propertyType != null) { - String typeString = propertyType.toString().toLowerCase(); - if ("integer".equals(typeString)) { - typeString = "int"; - } + if (typeString != null) { writer.write(' '); writer.write(nameSpaceMap.get(TYPE_NAMESPACE)); writer.write(":dt=\""); diff --git a/src/java/davmail/exchange/dav/Field.java b/src/java/davmail/exchange/dav/Field.java index 0b714967..9bcf9573 100644 --- a/src/java/davmail/exchange/dav/Field.java +++ b/src/java/davmail/exchange/dav/Field.java @@ -328,6 +328,8 @@ public class Field { createField(URN_SCHEMAS_MAILHEADER, "importance");//PS_INTERNET_HEADERS/importance createField("percentcomplete", DistinguishedPropertySetType.Task, 0x8102, "percentcomplete", PropertyType.Double); createField("taskstatus", DistinguishedPropertySetType.Task, 0x8101, "taskstatus", PropertyType.Integer); + createField("startdate", DistinguishedPropertySetType.Task, 0x8104, "startdate", PropertyType.SystemTime); + createField("duedate", DistinguishedPropertySetType.Task, 0x8105, "duedate", PropertyType.SystemTime); createField("categories", DistinguishedPropertySetType.PublicStrings, 0x9000, "categories", PropertyType.StringArray); } @@ -407,6 +409,7 @@ public class Field { protected final boolean isMultivalued; protected final boolean isBooleanValue; protected final boolean isFloatValue; + protected final boolean isDateValue; /** * Create field for namespace and name, use name as alias. @@ -454,6 +457,7 @@ public class Field { isIntValue = propertyType == PropertyType.Long || propertyType == PropertyType.Integer || propertyType == PropertyType.Short; isBooleanValue = propertyType == PropertyType.Boolean; isFloatValue = propertyType == PropertyType.Float || propertyType == PropertyType.Double; + isDateValue = propertyType == PropertyType.SystemTime; this.uri = namespace.getURI() + name; if (responseAlias == null) { @@ -572,16 +576,18 @@ public class Field { return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), buffer.toString()); } else if (field.isBooleanValue) { if ("true".equals(value)) { - return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), "1", PropertyType.Boolean); + return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), "1", "boolean"); } else if ("false".equals(value)) { - return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), "0", PropertyType.Boolean); + return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), "0", "boolean"); } else { throw new RuntimeException("Invalid value for " + field.alias + ": " + value); } } else if (field.isFloatValue) { - return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), StringUtil.xmlEncode(value), PropertyType.Float); + return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), StringUtil.xmlEncode(value), "float"); } else if (field.isIntValue) { - return new PropertyValue(field.updatePropertyName.getNamespace().getURI(), field.updatePropertyName.getName(), StringUtil.xmlEncode(value), PropertyType.Integer); + return new PropertyValue(field.updatePropertyName.getNamespace().getURI(), field.updatePropertyName.getName(), StringUtil.xmlEncode(value), "int"); + } else if (field.isDateValue) { + return new PropertyValue(field.updatePropertyName.getNamespace().getURI(), field.updatePropertyName.getName(), StringUtil.xmlEncode(value), "dateTime.tz"); } else { return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), StringUtil.xmlEncode(value)); } diff --git a/src/java/davmail/exchange/dav/PropertyValue.java b/src/java/davmail/exchange/dav/PropertyValue.java index d76cae52..24622580 100644 --- a/src/java/davmail/exchange/dav/PropertyValue.java +++ b/src/java/davmail/exchange/dav/PropertyValue.java @@ -25,7 +25,7 @@ public class PropertyValue { protected final String namespaceUri; protected final String name; protected final String xmlEncodedValue; - protected final PropertyType type; + protected final String typeString; /** * Create Dav property value. @@ -54,13 +54,13 @@ public class PropertyValue { * @param namespaceUri property namespace * @param name property name * @param xmlEncodedValue xml encoded value - * @param type property type + * @param typeString property type */ - public PropertyValue(String namespaceUri, String name, String xmlEncodedValue, PropertyType type) { + public PropertyValue(String namespaceUri, String name, String xmlEncodedValue, String typeString) { this.namespaceUri = namespaceUri; this.name = name; this.xmlEncodedValue = xmlEncodedValue; - this.type = type; + this.typeString = typeString; } /** @@ -86,8 +86,8 @@ public class PropertyValue { * * @return property type */ - public PropertyType getType() { - return type; + public String getTypeString() { + return typeString; } /**