mirror of
https://github.com/moparisthebest/davmail
synced 2024-12-13 03:02:22 -05:00
Caldav: implement task percent complete and status over WebDav
git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1764 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
parent
4d79c262ca
commit
e9c9aad7b9
@ -2146,7 +2146,7 @@ public abstract class ExchangeSession {
|
|||||||
fixICS(itemBody.getBytes("UTF-8"), false);
|
fixICS(itemBody.getBytes("UTF-8"), false);
|
||||||
// fix task item name
|
// fix task item name
|
||||||
if (vCalendar.isTodo() && this.itemName.endsWith(".ics")) {
|
if (vCalendar.isTodo() && this.itemName.endsWith(".ics")) {
|
||||||
this.itemName = itemName.substring(0, itemName.length() - 3)+".EML";
|
this.itemName = itemName.substring(0, itemName.length() - 3)+"EML";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +82,23 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
WELL_KNOWN_FOLDERS.add(Field.getPropertyName("outbox"));
|
WELL_KNOWN_FOLDERS.add(Field.getPropertyName("outbox"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final Map<String, String> vTodoToTaskStatusMap = new HashMap<String, String>();
|
||||||
|
static final Map<String, String> taskTovTodoStatusMap = new HashMap<String, String>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
//taskTovTodoStatusMap.put("0", null);
|
||||||
|
taskTovTodoStatusMap.put("1", "IN-PROCESS");
|
||||||
|
taskTovTodoStatusMap.put("2", "COMPLETED");
|
||||||
|
taskTovTodoStatusMap.put("3", "NEEDS-ACTION");
|
||||||
|
taskTovTodoStatusMap.put("4", "CANCELLED");
|
||||||
|
|
||||||
|
//vTodoToTaskStatusMap.put(null, "0");
|
||||||
|
vTodoToTaskStatusMap.put("IN-PROCESS", "1");
|
||||||
|
vTodoToTaskStatusMap.put("COMPLETED", "2");
|
||||||
|
vTodoToTaskStatusMap.put("NEEDS-ACTION", "3");
|
||||||
|
vTodoToTaskStatusMap.put("CANCELLED", "4");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Various standard mail boxes Urls
|
* Various standard mail boxes Urls
|
||||||
*/
|
*/
|
||||||
@ -1349,34 +1366,36 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
byte[] result = null;
|
byte[] result = null;
|
||||||
|
|
||||||
// experimental: build VCALENDAR from properties
|
// experimental: build VCALENDAR from properties
|
||||||
DavPropertyNameSet davPropertyNameSet = new DavPropertyNameSet();
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("method"));
|
|
||||||
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("created"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("calendarlastmodified"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("dtstamp"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("calendaruid"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("subject"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("dtstart"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("dtend"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("transparent"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("organizer"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("to"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("description"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("rrule"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("exdate"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("sensitivity"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("alldayevent"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("busystatus"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("reminderset"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("reminderdelta"));
|
|
||||||
// task
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("importance"));
|
|
||||||
davPropertyNameSet.add(Field.getPropertyName("uid"));
|
|
||||||
|
|
||||||
PropFindMethod propFindMethod = new PropFindMethod(permanentUrl, davPropertyNameSet, 0);
|
|
||||||
try {
|
try {
|
||||||
MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeMethod(httpClient, propFindMethod);
|
//MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeMethod(httpClient, propFindMethod);
|
||||||
|
Set<String> eventProperties = new HashSet<String>();
|
||||||
|
eventProperties.add("method");
|
||||||
|
|
||||||
|
eventProperties.add("created");
|
||||||
|
eventProperties.add("calendarlastmodified");
|
||||||
|
eventProperties.add("dtstamp");
|
||||||
|
eventProperties.add("calendaruid");
|
||||||
|
eventProperties.add("subject");
|
||||||
|
eventProperties.add("dtstart");
|
||||||
|
eventProperties.add("dtend");
|
||||||
|
eventProperties.add("transparent");
|
||||||
|
eventProperties.add("organizer");
|
||||||
|
eventProperties.add("to");
|
||||||
|
eventProperties.add("description");
|
||||||
|
eventProperties.add("rrule");
|
||||||
|
eventProperties.add("exdate");
|
||||||
|
eventProperties.add("sensitivity");
|
||||||
|
eventProperties.add("alldayevent");
|
||||||
|
eventProperties.add("busystatus");
|
||||||
|
eventProperties.add("reminderset");
|
||||||
|
eventProperties.add("reminderdelta");
|
||||||
|
// task
|
||||||
|
eventProperties.add("importance");
|
||||||
|
eventProperties.add("uid");
|
||||||
|
eventProperties.add("percentcomplete");
|
||||||
|
|
||||||
|
MultiStatusResponse[] responses = searchItems(folderPath, eventProperties, DavExchangeSession.this.isEqualTo("urlcompname", convertItemNameToEML(itemName)), FolderQueryTraversal.Shallow, 1);
|
||||||
if (responses.length == 0) {
|
if (responses.length == 0) {
|
||||||
throw new HttpNotFoundException(permanentUrl + " not found");
|
throw new HttpNotFoundException(permanentUrl + " not found");
|
||||||
}
|
}
|
||||||
@ -1398,6 +1417,9 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
vEvent.setPropertyValue("PRIORITY", convertPriorityFromExchange(getPropertyIfExists(davPropertySet, "importance")));
|
vEvent.setPropertyValue("PRIORITY", convertPriorityFromExchange(getPropertyIfExists(davPropertySet, "importance")));
|
||||||
if (instancetype == null) {
|
if (instancetype == null) {
|
||||||
vEvent.type = "VTODO";
|
vEvent.type = "VTODO";
|
||||||
|
vEvent.setPropertyValue("PERCENT-COMPLETE", String.valueOf(getDoublePropertyIfExists(davPropertySet, "percentcomplete")*100));
|
||||||
|
vEvent.setPropertyValue("STATUS", taskTovTodoStatusMap.get(getPropertyIfExists(davPropertySet, "taskstatus")));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
vEvent.type = "VEVENT";
|
vEvent.type = "VEVENT";
|
||||||
// check mandatory dtstart value
|
// check mandatory dtstart value
|
||||||
@ -1485,8 +1507,6 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.warn("Unable to rebuild event content: " + e.getMessage(), e);
|
LOGGER.warn("Unable to rebuild event content: " + e.getMessage(), e);
|
||||||
throw buildHttpException(e);
|
throw buildHttpException(e);
|
||||||
} finally {
|
|
||||||
propFindMethod.releaseConnection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -1545,6 +1565,12 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
propertyValues.add(Field.createPropertyValue("subject", vCalendar.getFirstVeventPropertyValue("SUMMARY")));
|
propertyValues.add(Field.createPropertyValue("subject", vCalendar.getFirstVeventPropertyValue("SUMMARY")));
|
||||||
propertyValues.add(Field.createPropertyValue("description", vCalendar.getFirstVeventPropertyValue("DESCRIPTION")));
|
propertyValues.add(Field.createPropertyValue("description", vCalendar.getFirstVeventPropertyValue("DESCRIPTION")));
|
||||||
propertyValues.add(Field.createPropertyValue("importance", convertPriorityToExchange(vCalendar.getFirstVeventPropertyValue("PRIORITY"))));
|
propertyValues.add(Field.createPropertyValue("importance", convertPriorityToExchange(vCalendar.getFirstVeventPropertyValue("PRIORITY"))));
|
||||||
|
String percentComplete = vCalendar.getFirstVeventPropertyValue("PERCENT-COMPLETE");
|
||||||
|
if (percentComplete == null) {
|
||||||
|
percentComplete = "0";
|
||||||
|
}
|
||||||
|
propertyValues.add(Field.createPropertyValue("percentcomplete", String.valueOf(Double.parseDouble(percentComplete) / 100)));
|
||||||
|
propertyValues.add(Field.createPropertyValue("taskstatus", vTodoToTaskStatusMap.get(vCalendar.getFirstVeventPropertyValue("STATUS"))));
|
||||||
|
|
||||||
ExchangePropPatchMethod propPatchMethod = new ExchangePropPatchMethod(encodedHref, propertyValues);
|
ExchangePropPatchMethod propPatchMethod = new ExchangePropPatchMethod(encodedHref, propertyValues);
|
||||||
propPatchMethod.setRequestHeader("Translate", "f");
|
propPatchMethod.setRequestHeader("Translate", "f");
|
||||||
@ -1859,6 +1885,15 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected double getDoublePropertyIfExists(DavPropertySet properties, String alias) {
|
||||||
|
DavProperty property = properties.get(Field.getResponsePropertyName(alias));
|
||||||
|
if (property == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return Double.parseDouble((String) property.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected byte[] getBinaryPropertyIfExists(DavPropertySet properties, String alias) {
|
protected byte[] getBinaryPropertyIfExists(DavPropertySet properties, String alias) {
|
||||||
byte[] property = null;
|
byte[] property = null;
|
||||||
String base64Property = getPropertyIfExists(properties, alias);
|
String base64Property = getPropertyIfExists(properties, alias);
|
||||||
@ -1990,7 +2025,12 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
|
|
||||||
protected MultiStatusResponse[] searchItems(String folderPath, Set<String> attributes, Condition condition,
|
protected MultiStatusResponse[] searchItems(String folderPath, Set<String> attributes, Condition condition,
|
||||||
FolderQueryTraversal folderQueryTraversal, int maxCount) throws IOException {
|
FolderQueryTraversal folderQueryTraversal, int maxCount) throws IOException {
|
||||||
String folderUrl = getFolderPath(folderPath);
|
String folderUrl;
|
||||||
|
if (folderPath.startsWith("http")) {
|
||||||
|
folderUrl = folderPath;
|
||||||
|
} else {
|
||||||
|
folderUrl = getFolderPath(folderPath);
|
||||||
|
}
|
||||||
StringBuilder searchRequest = new StringBuilder();
|
StringBuilder searchRequest = new StringBuilder();
|
||||||
searchRequest.append("SELECT ")
|
searchRequest.append("SELECT ")
|
||||||
.append(Field.getRequestPropertyString("permanenturl"));
|
.append(Field.getRequestPropertyString("permanenturl"));
|
||||||
@ -2037,15 +2077,19 @@ public class DavExchangeSession extends ExchangeSession {
|
|||||||
String itemPath = getFolderPath(folderPath) + '/' + emlItemName;
|
String itemPath = getFolderPath(folderPath) + '/' + emlItemName;
|
||||||
MultiStatusResponse[] responses = null;
|
MultiStatusResponse[] responses = null;
|
||||||
try {
|
try {
|
||||||
responses = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, URIUtil.encodePath(itemPath), 0, EVENT_REQUEST_PROPERTIES_NAME_SET);
|
try {
|
||||||
if (responses.length == 0 && isMainCalendar(folderPath)) {
|
responses = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, URIUtil.encodePath(itemPath), 0, EVENT_REQUEST_PROPERTIES_NAME_SET);
|
||||||
|
} catch (HttpNotFoundException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
if (responses == null || responses.length == 0 && isMainCalendar(folderPath)) {
|
||||||
if (itemName.endsWith(".ics")) {
|
if (itemName.endsWith(".ics")) {
|
||||||
itemName = itemName.substring(0, itemName.length() - 3) + "EML";
|
itemName = itemName.substring(0, itemName.length() - 3) + "EML";
|
||||||
}
|
}
|
||||||
// look for item in tasks folder
|
// look for item in tasks folder
|
||||||
responses = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, URIUtil.encodePath(getFolderPath(TASKS) + '/' + emlItemName), 0, EVENT_REQUEST_PROPERTIES_NAME_SET);
|
responses = DavGatewayHttpClientFacade.executePropFindMethod(httpClient, URIUtil.encodePath(getFolderPath(TASKS) + '/' + emlItemName), 0, EVENT_REQUEST_PROPERTIES_NAME_SET);
|
||||||
}
|
}
|
||||||
if (responses.length == 0) {
|
if (responses == null || responses.length == 0) {
|
||||||
throw new HttpNotFoundException(itemPath + " not found");
|
throw new HttpNotFoundException(itemPath + " not found");
|
||||||
}
|
}
|
||||||
} catch (HttpNotFoundException e) {
|
} catch (HttpNotFoundException e) {
|
||||||
|
@ -122,10 +122,14 @@ public class ExchangePropPatchMethod extends PostMethod {
|
|||||||
writer.write(':');
|
writer.write(':');
|
||||||
writer.write(propertyValue.getName());
|
writer.write(propertyValue.getName());
|
||||||
if (propertyType != null) {
|
if (propertyType != null) {
|
||||||
|
String typeString = propertyType.toString().toLowerCase();
|
||||||
|
if ("integer".equals(typeString)) {
|
||||||
|
typeString = "int";
|
||||||
|
}
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
writer.write(nameSpaceMap.get(TYPE_NAMESPACE));
|
writer.write(nameSpaceMap.get(TYPE_NAMESPACE));
|
||||||
writer.write(":dt=\"");
|
writer.write(":dt=\"");
|
||||||
writer.write(propertyType.toString().toLowerCase());
|
writer.write(typeString);
|
||||||
writer.write("\"");
|
writer.write("\"");
|
||||||
}
|
}
|
||||||
writer.write('>');
|
writer.write('>');
|
||||||
|
@ -78,6 +78,7 @@ public class Field {
|
|||||||
propertyTypeMap.put(PropertyType.SystemTime, "0040"); // PT_SYSTIME
|
propertyTypeMap.put(PropertyType.SystemTime, "0040"); // PT_SYSTIME
|
||||||
propertyTypeMap.put(PropertyType.String, "001f"); // 001f is PT_UNICODE_STRING, 001E is PT_STRING
|
propertyTypeMap.put(PropertyType.String, "001f"); // 001f is PT_UNICODE_STRING, 001E is PT_STRING
|
||||||
propertyTypeMap.put(PropertyType.Binary, "0102"); // PT_BINARY
|
propertyTypeMap.put(PropertyType.Binary, "0102"); // PT_BINARY
|
||||||
|
propertyTypeMap.put(PropertyType.Double, "0005"); // PT_DOUBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"UnusedDeclaration"})
|
@SuppressWarnings({"UnusedDeclaration"})
|
||||||
@ -325,6 +326,8 @@ public class Field {
|
|||||||
|
|
||||||
// task
|
// task
|
||||||
createField(URN_SCHEMAS_MAILHEADER, "importance");//PS_INTERNET_HEADERS/importance
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static String toHexString(int propertyTag) {
|
protected static String toHexString(int propertyTag) {
|
||||||
@ -362,11 +365,15 @@ public class Field {
|
|||||||
if (propertySetType == DistinguishedPropertySetType.Address) {
|
if (propertySetType == DistinguishedPropertySetType.Address) {
|
||||||
// Address namespace expects integer names
|
// Address namespace expects integer names
|
||||||
name = String.valueOf(propertyTag);
|
name = String.valueOf(propertyTag);
|
||||||
|
updateAlias = "_x0030_x" + toHexString(propertyTag);
|
||||||
|
} else if (propertySetType == DistinguishedPropertySetType.Task) {
|
||||||
|
name = "0x" + toHexString(propertyTag);
|
||||||
|
updateAlias = "0x0000" + toHexString(propertyTag);
|
||||||
} else {
|
} else {
|
||||||
// Common namespace expects hex names
|
// Common namespace expects hex names
|
||||||
name = "0x" + toHexString(propertyTag);
|
name = "0x" + toHexString(propertyTag);
|
||||||
|
updateAlias = "_x0030_x" + toHexString(propertyTag);
|
||||||
}
|
}
|
||||||
updateAlias = "_x0030_x" + toHexString(propertyTag);
|
|
||||||
Field field = new Field(alias, Namespace.getNamespace(SCHEMAS_MAPI_ID.getURI() +
|
Field field = new Field(alias, Namespace.getNamespace(SCHEMAS_MAPI_ID.getURI() +
|
||||||
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name, propertyType, responseAlias, null, updateAlias);
|
'{' + distinguishedPropertySetMap.get(propertySetType) + "}/"), name, propertyType, responseAlias, null, updateAlias);
|
||||||
fieldMap.put(field.alias, field);
|
fieldMap.put(field.alias, field);
|
||||||
@ -397,6 +404,7 @@ public class Field {
|
|||||||
protected final boolean isIntValue;
|
protected final boolean isIntValue;
|
||||||
protected final boolean isMultivalued;
|
protected final boolean isMultivalued;
|
||||||
protected final boolean isBooleanValue;
|
protected final boolean isBooleanValue;
|
||||||
|
protected final boolean isFloatValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create field for namespace and name, use name as alias.
|
* Create field for namespace and name, use name as alias.
|
||||||
@ -443,6 +451,7 @@ public class Field {
|
|||||||
isMultivalued = propertyType != null && propertyType.toString().endsWith("Array");
|
isMultivalued = propertyType != null && propertyType.toString().endsWith("Array");
|
||||||
isIntValue = propertyType == PropertyType.Long || propertyType == PropertyType.Integer || propertyType == PropertyType.Short;
|
isIntValue = propertyType == PropertyType.Long || propertyType == PropertyType.Integer || propertyType == PropertyType.Short;
|
||||||
isBooleanValue = propertyType == PropertyType.Boolean;
|
isBooleanValue = propertyType == PropertyType.Boolean;
|
||||||
|
isFloatValue = propertyType == PropertyType.Float || propertyType == PropertyType.Double;
|
||||||
|
|
||||||
this.uri = namespace.getURI() + name;
|
this.uri = namespace.getURI() + name;
|
||||||
if (responseAlias == null) {
|
if (responseAlias == null) {
|
||||||
@ -567,6 +576,10 @@ public class Field {
|
|||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Invalid value for " + field.alias + ": " + value);
|
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);
|
||||||
|
} else if (field.isIntValue) {
|
||||||
|
return new PropertyValue(field.updatePropertyName.getNamespace().getURI(), field.updatePropertyName.getName(), StringUtil.xmlEncode(value), PropertyType.Integer);
|
||||||
} else {
|
} else {
|
||||||
return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), StringUtil.xmlEncode(value));
|
return new PropertyValue(davPropertyName.getNamespace().getURI(), davPropertyName.getName(), StringUtil.xmlEncode(value));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user