From a0339007c4589168d2c4bfdf2a812d6b7ea22da3 Mon Sep 17 00:00:00 2001 From: mguessan Date: Fri, 9 Jul 2010 23:53:28 +0000 Subject: [PATCH] EWS: implement calendar event create or update, processed field, subfolder path handling git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1164 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- .../davmail/exchange/ExchangeSession.java | 8 +- .../exchange/dav/DavExchangeSession.java | 6 +- .../exchange/ews/EwsExchangeSession.java | 84 +++++++++++++++---- src/java/davmail/exchange/ews/Field.java | 6 +- 4 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 7f1e7a76..100ec07a 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -647,7 +647,11 @@ public abstract class ExchangeSession { protected MultiCondition(Operator operator, Condition... conditions) { this.operator = operator; this.conditions = new ArrayList(); - this.conditions.addAll(Arrays.asList(conditions)); + for (Condition condition:conditions) { + if (condition != null) { + this.conditions.add(condition); + } + } } /** @@ -2475,7 +2479,7 @@ public abstract class ExchangeSession { } - protected abstract ItemResult createOrUpdate(byte[] content) throws IOException; + protected abstract ItemResult createOrUpdate(byte[] mimeContent) throws IOException; } diff --git a/src/java/davmail/exchange/dav/DavExchangeSession.java b/src/java/davmail/exchange/dav/DavExchangeSession.java index 6b3c6acc..4942a567 100644 --- a/src/java/davmail/exchange/dav/DavExchangeSession.java +++ b/src/java/davmail/exchange/dav/DavExchangeSession.java @@ -749,7 +749,7 @@ public class DavExchangeSession extends ExchangeSession { * @inheritDoc */ @Override - protected ItemResult createOrUpdate(byte[] messageContent) throws IOException { + protected ItemResult createOrUpdate(byte[] mimeContent) throws IOException { PutMethod putmethod = new PutMethod(URIUtil.encodePath(getHref())); putmethod.setRequestHeader("Translate", "f"); putmethod.setRequestHeader("Overwrite", "f"); @@ -760,7 +760,7 @@ public class DavExchangeSession extends ExchangeSession { putmethod.setRequestHeader("If-None-Match", noneMatch); } putmethod.setRequestHeader("Content-Type", "message/rfc822"); - putmethod.setRequestEntity(new ByteArrayRequestEntity(messageContent, "message/rfc822")); + putmethod.setRequestEntity(new ByteArrayRequestEntity(mimeContent, "message/rfc822")); int status; try { status = httpClient.executeMethod(putmethod); @@ -793,7 +793,7 @@ public class DavExchangeSession extends ExchangeSession { // Set contentclass to make ActiveSync happy propertyList.add(Field.createDavProperty("contentclass", contentClass)); // ... but also set PR_INTERNET_CONTENT to preserve custom properties - propertyList.add(Field.createDavProperty("internetContent", new String(Base64.encodeBase64(messageContent)))); + propertyList.add(Field.createDavProperty("internetContent", new String(Base64.encodeBase64(mimeContent)))); PropPatchMethod propPatchMethod = new PropPatchMethod(URIUtil.encodePath(getHref()), propertyList); int patchStatus = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, propPatchMethod); if (patchStatus != HttpStatus.SC_MULTI_STATUS) { diff --git a/src/java/davmail/exchange/ews/EwsExchangeSession.java b/src/java/davmail/exchange/ews/EwsExchangeSession.java index 2c000332..93097e37 100644 --- a/src/java/davmail/exchange/ews/EwsExchangeSession.java +++ b/src/java/davmail/exchange/ews/EwsExchangeSession.java @@ -492,12 +492,12 @@ public class EwsExchangeSession extends ExchangeSession { @Override public Condition isTrue(String attributeName) { - return new AttributeCondition(attributeName, Operator.IsEqualTo, "True"); + return new AttributeCondition(attributeName, Operator.IsEqualTo, "true"); } @Override public Condition isFalse(String attributeName) { - return new AttributeCondition(attributeName, Operator.IsEqualTo, "False"); + return new AttributeCondition(attributeName, Operator.IsEqualTo, "false"); } protected static final HashSet FOLDER_PROPERTIES = new HashSet(); @@ -529,8 +529,15 @@ public class EwsExchangeSession extends ExchangeSession { */ @Override public List getSubFolders(String folderPath, Condition condition, boolean recursive) throws IOException { + String baseFolderPath = folderPath; + if (baseFolderPath.startsWith("/users/")) { + int index = baseFolderPath.indexOf('/', "/users/".length()); + if (index >= 0) { + baseFolderPath = baseFolderPath.substring(index+1); + } + } List folders = new ArrayList(); - appendSubFolders(folders, folderPath, getFolderId(folderPath), condition, recursive); + appendSubFolders(folders, baseFolderPath, getFolderId(folderPath), condition, recursive); return folders; } @@ -760,7 +767,6 @@ public class EwsExchangeSession extends ExchangeSession { itemResult.etag = getItemMethod.getResponseItem().get(Field.get("etag").getResponseName()); return itemResult; - } } @@ -774,6 +780,7 @@ public class EwsExchangeSession extends ExchangeSession { permanentUrl = response.get(Field.get("permanenturl").getResponseName()); etag = response.get(Field.get("etag").getResponseName()); displayName = response.get(Field.get("displayname").getResponseName()); + itemName = response.get(Field.get("urlcompname").getResponseName()); } /** @@ -785,29 +792,70 @@ public class EwsExchangeSession extends ExchangeSession { @Override - protected ItemResult createOrUpdate(byte[] content) throws IOException { - EWSMethod.Item item = new EWSMethod.Item(); - item.type = "Message"; - item.mimeContent = Base64.encodeBase64(content); - // TODO: handle etag and noneMatch - CreateItemMethod createItemMethod = new CreateItemMethod(MessageDisposition.SaveOnly, getFolderId(folderPath), item); - executeMethod(createItemMethod); + protected ItemResult createOrUpdate(byte[] mimeContent) throws IOException { + ItemResult itemResult = new ItemResult(); + EWSMethod createOrUpdateItemMethod; - // TODO: detect create/update - int status = createItemMethod.getStatusCode(); - if (status == HttpURLConnection.HTTP_OK) { + // first try to load existing event + String urlcompname = convertItemNameToEML(itemName); + String currentEtag = null; + ItemId currentItemId = null; + List responses = searchItems(folderPath, EVENT_REQUEST_PROPERTIES, EwsExchangeSession.this.equals("urlcompname", urlcompname), FolderQueryTraversal.SHALLOW); + if (!responses.isEmpty()) { + EWSMethod.Item response = responses.get(0); + currentItemId = new ItemId(response); + currentEtag = response.get(Field.get("etag").getResponseName()); + } + if ("*".equals(noneMatch)) { + // create requested + if (currentItemId != null) { + itemResult.status = HttpStatus.SC_PRECONDITION_FAILED; + return itemResult; + } + } else if (etag != null) { + // update requested + if (currentItemId == null || !etag.equals(currentEtag)) { + itemResult.status = HttpStatus.SC_PRECONDITION_FAILED; + return itemResult; + } + } + + if (currentItemId != null) { + Set updates = new HashSet(); + updates.add(new FieldUpdate(Field.get("mimeContent"), String.valueOf(Base64.encodeBase64(mimeContent)))); + // update + createOrUpdateItemMethod = new UpdateItemMethod(MessageDisposition.SaveOnly, + ConflictResolution.AlwaysOverwrite, + CalendarItemCreateOrDeleteOperation.SendToNone, + currentItemId, updates); + } else { + // create + EWSMethod.Item newItem = new EWSMethod.Item(); + newItem.type = "Message"; + newItem.mimeContent = Base64.encodeBase64(mimeContent); + createOrUpdateItemMethod = new CreateItemMethod(MessageDisposition.SaveOnly, getFolderId(folderPath), newItem); + } + + executeMethod(createOrUpdateItemMethod); + + itemResult.status = createOrUpdateItemMethod.getStatusCode(); + if (itemResult.status == HttpURLConnection.HTTP_OK) { + //noinspection VariableNotUsedInsideIf if (etag != null) { + itemResult.status = HttpStatus.SC_CREATED; LOGGER.debug("Updated event " + getHref()); } else { LOGGER.warn("Overwritten event " + getHref()); } } - ItemResult itemResult = new ItemResult(); - itemResult.status = status; - // TODO: get etag - // itemResult.etag = ??? + + ItemId newItemId = new ItemId(createOrUpdateItemMethod.getResponseItem()); + GetItemMethod getItemMethod = new GetItemMethod(BaseShape.ID_ONLY, newItemId, false); + executeMethod(getItemMethod); + itemResult.etag = getItemMethod.getResponseItem().get(Field.get("etag").getResponseName()); return itemResult; + } @Override diff --git a/src/java/davmail/exchange/ews/Field.java b/src/java/davmail/exchange/ews/Field.java index ac574bbf..30eab247 100644 --- a/src/java/davmail/exchange/ews/Field.java +++ b/src/java/davmail/exchange/ews/Field.java @@ -37,6 +37,8 @@ public class Field { FIELD_MAP.put("permanenturl", new ExtendedFieldURI(0x670E, ExtendedFieldURI.PropertyType.String)); //PR_FLAT_URL_NAME FIELD_MAP.put("instancetype", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.PublicStrings, "urn:schemas:calendar:instancetype")); + FIELD_MAP.put("mimeContent", new UnindexedFieldURI("item:MimeContent")); + // use PR_RECORD_KEY as unique key FIELD_MAP.put("uid", new ExtendedFieldURI(0x0FF9, ExtendedFieldURI.PropertyType.Binary)); FIELD_MAP.put("messageFlags", new ExtendedFieldURI(0x0e07, ExtendedFieldURI.PropertyType.Integer));//PR_MESSAGE_FLAGS @@ -131,7 +133,9 @@ public class Field { FIELD_MAP.put("sensitivity", new ExtendedFieldURI(0x0036, ExtendedFieldURI.PropertyType.Long)); FIELD_MAP.put("haspicture", new ExtendedFieldURI(ExtendedFieldURI.DistinguishedPropertySetType.Address, 0x8015, ExtendedFieldURI.PropertyType.Boolean)); - + + // calendar + FIELD_MAP.put("processed", new ExtendedFieldURI(0x65e8, ExtendedFieldURI.PropertyType.Boolean)); } /**