diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 543a1a50..73bc316d 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -291,21 +291,7 @@ public abstract class ExchangeSession { * @throws NoRouteToHostException on error * @throws UnknownHostException on error */ - public boolean isExpired() throws NoRouteToHostException, UnknownHostException { - boolean isExpired = false; - try { - DavGatewayHttpClientFacade.executePropFindMethod( - httpClient, URIUtil.encodePath(inboxUrl), 0, DISPLAY_NAME); - } catch (UnknownHostException exc) { - throw exc; - } catch (NoRouteToHostException exc) { - throw exc; - } catch (IOException e) { - isExpired = true; - } - - return isExpired; - } + public abstract boolean isExpired() throws NoRouteToHostException, UnknownHostException; /** * Test authentication mode : form based or basic. @@ -604,85 +590,7 @@ public abstract class ExchangeSession { * @param messageBody mail body * @throws IOException when unable to create message */ - public void createMessage(String folderPath, String messageName, HashMap properties, String messageBody) throws IOException { - String messageUrl = URIUtil.encodePathQuery(getFolderPath(folderPath) + '/' + messageName + ".EML"); - PropPatchMethod patchMethod; - // create the message first as draft - if (properties.containsKey("draft")) { - patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties)); - try { - // update message with blind carbon copy and other flags - int statusCode = httpClient.executeMethod(patchMethod); - if (statusCode != HttpStatus.SC_MULTI_STATUS) { - throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine()); - } - - } finally { - patchMethod.releaseConnection(); - } - } - - PutMethod putmethod = new PutMethod(messageUrl); - putmethod.setRequestHeader("Translate", "f"); - try { - // use same encoding as client socket reader - putmethod.setRequestEntity(new ByteArrayRequestEntity(messageBody.getBytes())); - int code = httpClient.executeMethod(putmethod); - - if (code != HttpStatus.SC_OK && code != HttpStatus.SC_CREATED) { - throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, code, ' ', putmethod.getStatusLine()); - } - } finally { - putmethod.releaseConnection(); - } - - // add bcc and other properties - if (!properties.isEmpty()) { - patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties)); - try { - // update message with blind carbon copy and other flags - int statusCode = httpClient.executeMethod(patchMethod); - if (statusCode != HttpStatus.SC_MULTI_STATUS) { - throw new DavMailException("EXCEPTION_UNABLE_TO_PATCH_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine()); - } - - } finally { - patchMethod.releaseConnection(); - } - } - } - - protected List buildProperties(Map properties) { - ArrayList list = new ArrayList(); - for (Map.Entry entry : properties.entrySet()) { - if ("read".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("read", URN_SCHEMAS_HTTPMAIL), entry.getValue())); - } else if ("junk".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x10830003", SCHEMAS_MAPI_PROPTAG), entry.getValue())); - } else if ("flagged".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x10900003", SCHEMAS_MAPI_PROPTAG), entry.getValue())); - } else if ("answered".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x10810003", SCHEMAS_MAPI_PROPTAG), entry.getValue())); - if ("102".equals(entry.getValue())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x10800003", SCHEMAS_MAPI_PROPTAG), "261")); - } - } else if ("forwarded".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x10810003", SCHEMAS_MAPI_PROPTAG), entry.getValue())); - if ("104".equals(entry.getValue())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x10800003", SCHEMAS_MAPI_PROPTAG), "262")); - } - } else if ("bcc".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("bcc", Namespace.getNamespace("urn:schemas:mailheader:")), entry.getValue())); - } else if ("draft".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("x0E070003", SCHEMAS_MAPI_PROPTAG), entry.getValue())); - } else if ("deleted".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("_x0030_x8570", Namespace.getNamespace("http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/")), entry.getValue())); - } else if ("datereceived".equals(entry.getKey())) { - list.add(new DefaultDavProperty(DavPropertyName.create("datereceived", URN_SCHEMAS_HTTPMAIL), entry.getValue())); - } - } - return list; - } + public abstract void createMessage(String folderPath, String messageName, HashMap properties, String messageBody) throws IOException; /** * Update given properties on message. @@ -691,23 +599,15 @@ public abstract class ExchangeSession { * @param properties Webdav properties map * @throws IOException on error */ - public void updateMessage(Message message, Map properties) throws IOException { - PropPatchMethod patchMethod = new PropPatchMethod(message.permanentUrl, buildProperties(properties)) { - @Override - protected void processResponseBody(HttpState httpState, HttpConnection httpConnection) { - // ignore response body, sometimes invalid with exchange mapi properties - } - }; - try { - int statusCode = httpClient.executeMethod(patchMethod); - if (statusCode != HttpStatus.SC_MULTI_STATUS) { - throw new DavMailException("EXCEPTION_UNABLE_TO_UPDATE_MESSAGE"); - } + public abstract void updateMessage(Message message, Map properties) throws IOException; - } finally { - patchMethod.releaseConnection(); - } - } + /** + * Send message to recipients, properties contains bcc recipients and other non MIME flags. + * @param properties additional message properties + * @param messageBody MIME message body + * @throws IOException on error + */ + public abstract void sendMessage(HashMap properties, String messageBody) throws IOException; protected static final List POP_MESSAGE_ATTRIBUTES = new ArrayList(); @@ -742,6 +642,12 @@ public abstract class ExchangeSession { IMAP_MESSAGE_ATTRIBUTES.add("date"); } + protected static final List UID_MESSAGE_ATTRIBUTES = new ArrayList(); + + static { + UID_MESSAGE_ATTRIBUTES.add("uid"); + } + /** * Get all folder messages. * @@ -865,8 +771,7 @@ public abstract class ExchangeSession { * @throws IOException on error */ public List getSubFolders(String folderName, boolean recursive) throws IOException { - return getSubFolders(folderName, - or(equals("folderclass", "IPF.Note"), isNull("folderclass")), + return getSubFolders(folderName, or(equals("folderclass", "IPF.Note"), isNull("folderclass")), recursive); } @@ -902,32 +807,25 @@ public abstract class ExchangeSession { public void purgeOldestTrashAndSentMessages() throws IOException { int keepDelay = Settings.getIntProperty("davmail.keepDelay"); if (keepDelay != 0) { - purgeOldestFolderMessages(deleteditemsUrl, keepDelay); + purgeOldestFolderMessages(TRASH, keepDelay); } // this is a new feature, default is : do nothing int sentKeepDelay = Settings.getIntProperty("davmail.sentKeepDelay"); if (sentKeepDelay != 0) { - purgeOldestFolderMessages(sentitemsUrl, sentKeepDelay); + purgeOldestFolderMessages(SENT, sentKeepDelay); } } - protected void purgeOldestFolderMessages(String folderUrl, int keepDelay) throws IOException { + protected void purgeOldestFolderMessages(String folderPath, int keepDelay) throws IOException { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, -keepDelay); - LOGGER.debug("Delete messages in " + folderUrl + " since " + cal.getTime()); + LOGGER.debug("Delete messages in " + folderPath + " not modified since " + cal.getTime()); - String searchRequest = "Select \"DAV:uid\"" + - " FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" + - " WHERE \"DAV:isfolder\" = False\n" + - " AND \"DAV:getlastmodified\" < '" + formatSearchDate(cal.getTime()) + "'\n"; - MultiStatusResponse[] responses = DavGatewayHttpClientFacade.executeSearchMethod( - httpClient, URIUtil.encodePath(folderUrl), searchRequest); + MessageList messages = searchMessages(folderPath, UID_MESSAGE_ATTRIBUTES, + lt("lastmodified", formatSearchDate(cal.getTime()))); - for (MultiStatusResponse response : responses) { - String messageUrl = URIUtil.decode(response.getHref()); - - LOGGER.debug("Delete " + messageUrl); - DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(messageUrl)); + for (Message message : messages) { + message.delete(); } } @@ -995,16 +893,7 @@ public abstract class ExchangeSession { properties.put("bcc", bcc); } - String messageName = UUID.randomUUID().toString(); - - createMessage("Drafts", messageName, properties, mailBuffer.toString()); - - String tempUrl = draftsUrl + '/' + messageName + ".EML"; - MoveMethod method = new MoveMethod(URIUtil.encodePath(tempUrl), URIUtil.encodePath(sendmsgUrl), true); - int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); - if (status != HttpStatus.SC_OK) { - throw DavGatewayHttpClientFacade.buildHttpException(method); - } + sendMessage(properties, mailBuffer.toString()); } /** @@ -1101,23 +990,7 @@ public abstract class ExchangeSession { * @param folderClass folder class * @throws IOException on error */ - public void createFolder(String folderName, String folderClass) throws IOException { - String folderPath = getFolderPath(folderName); - ArrayList list = new ArrayList(); - list.add(new DefaultDavProperty(DavPropertyName.create("outlookfolderclass", Namespace.getNamespace("http://schemas.microsoft.com/exchange/")), folderClass)); - // standard MkColMethod does not take properties, override PropPatchMethod instead - PropPatchMethod method = new PropPatchMethod(URIUtil.encodePath(folderPath), list) { - @Override - public String getName() { - return "MKCOL"; - } - }; - int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); - // ok or already exists - if (status != HttpStatus.SC_MULTI_STATUS && status != HttpStatus.SC_METHOD_NOT_ALLOWED) { - throw DavGatewayHttpClientFacade.buildHttpException(method); - } - } + public abstract void createFolder(String folderName, String folderClass) throws IOException; /** * Delete Exchange folder. @@ -1125,9 +998,7 @@ public abstract class ExchangeSession { * @param folderName logical folder name * @throws IOException on error */ - public void deleteFolder(String folderName) throws IOException { - DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(getFolderPath(folderName))); - } + public abstract void deleteFolder(String folderName) throws IOException; /** * Copy message to target folder @@ -1136,22 +1007,7 @@ public abstract class ExchangeSession { * @param targetFolder target folder * @throws IOException on error */ - public void copyMessage(Message message, String targetFolder) throws IOException { - String targetPath = URIUtil.encodePath(getFolderPath(targetFolder)) + '/' + UUID.randomUUID().toString(); - CopyMethod method = new CopyMethod(message.permanentUrl, targetPath, false); - // allow rename if a message with the same name exists - method.addRequestHeader("Allow-Rename", "t"); - try { - int statusCode = httpClient.executeMethod(method); - if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) { - throw new DavMailException("EXCEPTION_UNABLE_TO_COPY_MESSAGE"); - } else if (statusCode != HttpStatus.SC_CREATED) { - throw DavGatewayHttpClientFacade.buildHttpException(method); - } - } finally { - method.releaseConnection(); - } - } + public abstract void copyMessage(Message message, String targetFolder) throws IOException; /** * Move folder to target name. @@ -1160,39 +1016,9 @@ public abstract class ExchangeSession { * @param targetName target folder name/path * @throws IOException on error */ - public void moveFolder(String folderName, String targetName) throws IOException { - String folderPath = getFolderPath(folderName); - String targetPath = getFolderPath(targetName); - MoveMethod method = new MoveMethod(URIUtil.encodePath(folderPath), URIUtil.encodePath(targetPath), false); - try { - int statusCode = httpClient.executeMethod(method); - if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) { - throw new DavMailException("EXCEPTION_UNABLE_TO_MOVE_FOLDER"); - } else if (statusCode != HttpStatus.SC_CREATED) { - throw DavGatewayHttpClientFacade.buildHttpException(method); - } - } finally { - method.releaseConnection(); - } - } + public abstract void moveFolder(String folderName, String targetName) throws IOException; - protected void moveToTrash(String encodedMessageUrl) throws IOException { - String destination = URIUtil.encodePath(deleteditemsUrl) + '/' + UUID.randomUUID().toString(); - LOGGER.debug("Deleting : " + encodedMessageUrl + " to " + destination); - MoveMethod method = new MoveMethod(encodedMessageUrl, destination, false); - method.addRequestHeader("Allow-rename", "t"); - - int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); - // do not throw error if already deleted - if (status != HttpStatus.SC_CREATED && status != HttpStatus.SC_NOT_FOUND) { - throw DavGatewayHttpClientFacade.buildHttpException(method); - } - if (method.getResponseHeader("Location") != null) { - destination = method.getResponseHeader("Location").getValue(); - } - - LOGGER.debug("Deleted to :" + destination); - } + protected abstract void moveToTrash(Message message) throws IOException; /** * Exchange folder with IMAP properties @@ -1688,6 +1514,7 @@ public abstract class ExchangeSession { * @throws IOException on error */ public void delete() throws IOException { + LOGGER.debug("Delete " + permanentUrl + " (" + messageUrl + ")"); DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, permanentUrl); } @@ -1702,7 +1529,7 @@ public abstract class ExchangeSession { properties.put("read", "1"); updateMessage(this, properties); - ExchangeSession.this.moveToTrash(permanentUrl); + ExchangeSession.this.moveToTrash(this); } /** diff --git a/src/java/davmail/exchange/dav/DavExchangeSession.java b/src/java/davmail/exchange/dav/DavExchangeSession.java index ce8b691b..47d30881 100644 --- a/src/java/davmail/exchange/dav/DavExchangeSession.java +++ b/src/java/davmail/exchange/dav/DavExchangeSession.java @@ -24,23 +24,24 @@ import davmail.exception.DavMailException; import davmail.exchange.ExchangeSession; import davmail.http.DavGatewayHttpClientFacade; import davmail.ui.tray.DavGatewayTray; -import org.apache.commons.httpclient.HttpMethod; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.URIException; +import org.apache.commons.httpclient.*; +import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; +import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.util.URIUtil; import org.apache.jackrabbit.webdav.MultiStatusResponse; +import org.apache.jackrabbit.webdav.client.methods.CopyMethod; +import org.apache.jackrabbit.webdav.client.methods.MoveMethod; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import org.apache.jackrabbit.webdav.property.DavProperty; -import org.apache.jackrabbit.webdav.property.DavPropertyName; -import org.apache.jackrabbit.webdav.property.DavPropertyNameSet; -import org.apache.jackrabbit.webdav.property.DavPropertySet; +import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod; +import org.apache.jackrabbit.webdav.property.*; import org.apache.jackrabbit.webdav.xml.Namespace; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.net.NoRouteToHostException; import java.net.URL; +import java.net.UnknownHostException; import java.util.*; /** @@ -196,6 +197,26 @@ public class DavExchangeSession extends ExchangeSession { } } + /** + * @inheritDoc + */ + @Override + public boolean isExpired() throws NoRouteToHostException, UnknownHostException { + boolean isExpired = false; + try { + DavGatewayHttpClientFacade.executePropFindMethod( + httpClient, URIUtil.encodePath(inboxUrl), 0, DISPLAY_NAME); + } catch (UnknownHostException exc) { + throw exc; + } catch (NoRouteToHostException exc) { + throw exc; + } catch (IOException e) { + isExpired = true; + } + + return isExpired; + } + protected static class MultiCondition extends ExchangeSession.MultiCondition { protected MultiCondition(Operator operator, Condition... condition) { super(operator, condition); @@ -455,6 +476,55 @@ public class DavExchangeSession extends ExchangeSession { return folders; } + /** + * @inheritDoc + */ + public void createFolder(String folderName, String folderClass) throws IOException { + String folderPath = getFolderPath(folderName); + ArrayList list = new ArrayList(); + list.add(Field.createDavProperty("folderclass", folderClass)); + // standard MkColMethod does not take properties, override PropPatchMethod instead + PropPatchMethod method = new PropPatchMethod(URIUtil.encodePath(folderPath), list) { + @Override + public String getName() { + return "MKCOL"; + } + }; + int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); + // ok or already exists + if (status != HttpStatus.SC_MULTI_STATUS && status != HttpStatus.SC_METHOD_NOT_ALLOWED) { + throw DavGatewayHttpClientFacade.buildHttpException(method); + } + } + + /** + * @inheritDoc + */ + @Override + public void deleteFolder(String folderName) throws IOException { + DavGatewayHttpClientFacade.executeDeleteMethod(httpClient, URIUtil.encodePath(getFolderPath(folderName))); + } + + /** + * @inheritDoc + */ + @Override + public void moveFolder(String folderName, String targetName) throws IOException { + String folderPath = getFolderPath(folderName); + String targetPath = getFolderPath(targetName); + MoveMethod method = new MoveMethod(URIUtil.encodePath(folderPath), URIUtil.encodePath(targetPath), false); + try { + int statusCode = httpClient.executeMethod(method); + if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) { + throw new DavMailException("EXCEPTION_UNABLE_TO_MOVE_FOLDER"); + } else if (statusCode != HttpStatus.SC_CREATED) { + throw DavGatewayHttpClientFacade.buildHttpException(method); + } + } finally { + method.releaseConnection(); + } + } + protected String getPropertyIfExists(DavPropertySet properties, String name) { DavProperty property = properties.get(name, EMPTY); if (property == null) { @@ -549,4 +619,174 @@ public class DavExchangeSession extends ExchangeSession { Collections.sort(messages); return messages; } + + protected List buildProperties(Map properties) { + ArrayList list = new ArrayList(); + for (Map.Entry entry : properties.entrySet()) { + if ("read".equals(entry.getKey())) { + list.add(Field.createDavProperty("read", entry.getValue())); + } else if ("junk".equals(entry.getKey())) { + list.add(Field.createDavProperty("junk", entry.getValue())); + } else if ("flagged".equals(entry.getKey())) { + list.add(Field.createDavProperty("flagStatus", entry.getValue())); + } else if ("answered".equals(entry.getKey())) { + list.add(Field.createDavProperty("lastVerbExecuted", entry.getValue())); + if ("102".equals(entry.getValue())) { + list.add(Field.createDavProperty("iconIndex", "261")); + } + } else if ("forwarded".equals(entry.getKey())) { + list.add(Field.createDavProperty("lastVerbExecuted", entry.getValue())); + if ("104".equals(entry.getValue())) { + list.add(Field.createDavProperty("iconIndex", "262")); + } + } else if ("bcc".equals(entry.getKey())) { + list.add(Field.createDavProperty("bcc", entry.getValue())); + } else if ("draft".equals(entry.getKey())) { + list.add(Field.createDavProperty("messageFlags", entry.getValue())); + } else if ("deleted".equals(entry.getKey())) { + // TODO: need to test this + list.add(Field.createDavProperty("writedeleted", entry.getValue())); + } else if ("datereceived".equals(entry.getKey())) { + list.add(new DefaultDavProperty(DavPropertyName.create("datereceived", URN_SCHEMAS_HTTPMAIL), entry.getValue())); + } + } + return list; + } + + /** + * Create message in specified folder. + * Will overwrite an existing message with same subject in the same folder + * + * @param folderPath Exchange folder path + * @param messageName message name + * @param properties message properties (flags) + * @param messageBody mail body + * @throws IOException when unable to create message + */ + public void createMessage(String folderPath, String messageName, HashMap properties, String messageBody) throws IOException { + String messageUrl = URIUtil.encodePathQuery(getFolderPath(folderPath) + '/' + messageName + ".EML"); + PropPatchMethod patchMethod; + // create the message first as draft + if (properties.containsKey("draft")) { + patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties)); + try { + // update message with blind carbon copy and other flags + int statusCode = httpClient.executeMethod(patchMethod); + if (statusCode != HttpStatus.SC_MULTI_STATUS) { + throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine()); + } + + } finally { + patchMethod.releaseConnection(); + } + } + + PutMethod putmethod = new PutMethod(messageUrl); + putmethod.setRequestHeader("Translate", "f"); + try { + // use same encoding as client socket reader + putmethod.setRequestEntity(new ByteArrayRequestEntity(messageBody.getBytes())); + int code = httpClient.executeMethod(putmethod); + + if (code != HttpStatus.SC_OK && code != HttpStatus.SC_CREATED) { + throw new DavMailException("EXCEPTION_UNABLE_TO_CREATE_MESSAGE", messageUrl, code, ' ', putmethod.getStatusLine()); + } + } finally { + putmethod.releaseConnection(); + } + + // add bcc and other properties + if (!properties.isEmpty()) { + patchMethod = new PropPatchMethod(messageUrl, buildProperties(properties)); + try { + // update message with blind carbon copy and other flags + int statusCode = httpClient.executeMethod(patchMethod); + if (statusCode != HttpStatus.SC_MULTI_STATUS) { + throw new DavMailException("EXCEPTION_UNABLE_TO_PATCH_MESSAGE", messageUrl, statusCode, ' ', patchMethod.getStatusLine()); + } + + } finally { + patchMethod.releaseConnection(); + } + } + } + + /** + * @inheritDoc + */ + @Override + public void updateMessage(Message message, Map properties) throws IOException { + PropPatchMethod patchMethod = new PropPatchMethod(message.permanentUrl, buildProperties(properties)) { + @Override + protected void processResponseBody(HttpState httpState, HttpConnection httpConnection) { + // ignore response body, sometimes invalid with exchange mapi properties + } + }; + try { + int statusCode = httpClient.executeMethod(patchMethod); + if (statusCode != HttpStatus.SC_MULTI_STATUS) { + throw new DavMailException("EXCEPTION_UNABLE_TO_UPDATE_MESSAGE"); + } + + } finally { + patchMethod.releaseConnection(); + } + } + + /** + * @inheritDoc + */ + @Override + public void sendMessage(HashMap properties, String messageBody) throws IOException { + String messageName = UUID.randomUUID().toString(); + + createMessage("Drafts", messageName, properties, messageBody); + + String tempUrl = draftsUrl + '/' + messageName + ".EML"; + MoveMethod method = new MoveMethod(URIUtil.encodePath(tempUrl), URIUtil.encodePath(sendmsgUrl), true); + int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); + if (status != HttpStatus.SC_OK) { + throw DavGatewayHttpClientFacade.buildHttpException(method); + } + } + + /** + * @inheritDoc + */ + @Override + public void copyMessage(Message message, String targetFolder) throws IOException { + String targetPath = URIUtil.encodePath(getFolderPath(targetFolder)) + '/' + UUID.randomUUID().toString(); + CopyMethod method = new CopyMethod(message.permanentUrl, targetPath, false); + // allow rename if a message with the same name exists + method.addRequestHeader("Allow-Rename", "t"); + try { + int statusCode = httpClient.executeMethod(method); + if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) { + throw new DavMailException("EXCEPTION_UNABLE_TO_COPY_MESSAGE"); + } else if (statusCode != HttpStatus.SC_CREATED) { + throw DavGatewayHttpClientFacade.buildHttpException(method); + } + } finally { + method.releaseConnection(); + } + } + + @Override + protected void moveToTrash(Message message) throws IOException { + String destination = URIUtil.encodePath(deleteditemsUrl) + '/' + UUID.randomUUID().toString(); + LOGGER.debug("Deleting : " + message.permanentUrl + " to " + destination); + MoveMethod method = new MoveMethod(message.permanentUrl, destination, false); + method.addRequestHeader("Allow-rename", "t"); + + int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); + // do not throw error if already deleted + if (status != HttpStatus.SC_CREATED && status != HttpStatus.SC_NOT_FOUND) { + throw DavGatewayHttpClientFacade.buildHttpException(method); + } + if (method.getResponseHeader("Location") != null) { + destination = method.getResponseHeader("Location").getValue(); + } + + LOGGER.debug("Deleted to :" + destination); + } } diff --git a/src/java/davmail/exchange/dav/Field.java b/src/java/davmail/exchange/dav/Field.java index a9c1332b..a1e11b09 100644 --- a/src/java/davmail/exchange/dav/Field.java +++ b/src/java/davmail/exchange/dav/Field.java @@ -19,6 +19,7 @@ package davmail.exchange.dav; import org.apache.jackrabbit.webdav.property.DavPropertyName; +import org.apache.jackrabbit.webdav.property.DefaultDavProperty; import org.apache.jackrabbit.webdav.xml.Namespace; import java.util.HashMap; @@ -94,11 +95,14 @@ public class Field { createField("flagStatus", 0x1090, PropertyType.Integer);//PR_FLAG_STATUS createField("messageFlags", 0x0e07, PropertyType.Integer);//PR_MESSAGE_FLAGS createField("lastVerbExecuted", 0x1081, PropertyType.Integer);//PR_LAST_VERB_EXECUTED + createField("iconIndex", 0x1080, PropertyType.Integer);//PR_ICON_INDEX createField(URN_SCHEMAS_HTTPMAIL, "read"); //createField("read", 0x0e69, PropertyType.Boolean);//PR_READ createField("deleted", DistinguishedPropertySetType.Common, 0x8570); - createField(URN_SCHEMAS_HTTPMAIL, "date"); //PR_CLIENT_SUBMIT_TIME, 0x0039 + createField("writedeleted", DistinguishedPropertySetType.Common, 0x8570, PropertyType.Integer); + createField(URN_SCHEMAS_HTTPMAIL, "date");//PR_CLIENT_SUBMIT_TIME, 0x0039 //createField("date", 0x0e06, PropertyType.SystemTime);//PR_MESSAGE_DELIVERY_TIME + createField(URN_SCHEMAS_MAILHEADER, "bcc");//PS_INTERNET_HEADERS/bcc // IMAP search @@ -129,6 +133,12 @@ public class Field { fieldMap.put(field.alias, field); } + protected static void createField(String alias, DistinguishedPropertySetType propertySetType, int propertyTag, PropertyType propertyType) { + String name = '{' + distinguishedPropertySetMap.get(propertySetType) + "}/_x" +propertyTypeMap.get(propertyType)+"_x"+Integer.toHexString(propertyTag); + Field field = new Field(alias, SCHEMAS_MAPI_ID, name); + fieldMap.put(field.alias, field); + } + protected static void createField(Namespace namespace, String name) { Field field = new Field(namespace, name); fieldMap.put(field.alias, field); @@ -185,4 +195,8 @@ public class Field { String name = '{' + distinguishedPropertySetMap.get(DistinguishedPropertySetType.InternetHeaders) + "}/" + headerName; return new Field(SCHEMAS_MAPI_STRING, name); } + + public static DefaultDavProperty createDavProperty(String alias, String value) { + return new DefaultDavProperty(Field.get(alias).davPropertyName, value); + } }