diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 53e91057..13734c15 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -458,40 +458,28 @@ public class ExchangeSession { * * @param folderUrl Exchange folder URL * @param messageName message name - * @param bcc blind carbon copy header + * @param properties message properties (flags) * @param messageBody mail body * @param allowOverwrite allow existing message overwrite * @throws java.io.IOException when unable to create message */ - public void createMessage(String folderUrl, String messageName, String bcc, String messageBody, boolean allowOverwrite) throws IOException { + public void createMessage(String folderUrl, String messageName, HashMap properties, String messageBody, boolean allowOverwrite) throws IOException { String messageUrl = URIUtil.encodePathQuery(folderUrl + "/" + messageName + ".EML"); - + PropPatchMethod patchMethod; // create the message first as draft - PropPatchMethod patchMethod = new PropPatchMethod(messageUrl); - if (!allowOverwrite) { - patchMethod.setRequestHeader("If-None-Match", "*"); - } - try { - // update message with blind carbon copy - if (bcc != null && bcc.length() > 0) { - patchMethod.addPropertyToSet("bcc", bcc, "b", "urn:schemas:mailheader:"); - } - patchMethod.addPropertyToSet("x0E070003", "9", "d", "http://schemas.microsoft.com/mapi/proptag/"); - int statusCode = wdr.retrieveSessionInstance().executeMethod(patchMethod); - if (statusCode != HttpStatus.SC_MULTI_STATUS) { - throw new IOException("Unable to add bcc recipients: " + bcc); - } - Enumeration responseEntityEnum = patchMethod.getResponses(); - - if (responseEntityEnum.hasMoreElements()) { - ResponseEntity entity = (ResponseEntity) responseEntityEnum.nextElement(); - if (entity.getStatusCode() != HttpStatus.SC_OK) { - throw new IOException("Unable to add bcc recipients: " + bcc); + if (properties.containsKey("draft")) { + patchMethod = new PropPatchMethod(messageUrl); + try { + // update message with blind carbon copy and other flags + addProperties(patchMethod, properties); + int statusCode = wdr.retrieveSessionInstance().executeMethod(patchMethod); + if (statusCode != HttpStatus.SC_MULTI_STATUS) { + throw new IOException("Unable to create message " + messageUrl + ": " + statusCode + " " + patchMethod.getStatusLine()); } - } - } finally { - patchMethod.releaseConnection(); + } finally { + patchMethod.releaseConnection(); + } } PutMethod putmethod = new PutMethod(messageUrl); @@ -504,7 +492,7 @@ public class ExchangeSession { putmethod.setRequestBody(bodyStream); int code = wdr.retrieveSessionInstance().executeMethod(putmethod); - if (code != HttpURLConnection.HTTP_OK) { + if (code != HttpStatus.SC_OK && code != HttpStatus.SC_CREATED) { throw new IOException("Unable to create message " + messageUrl + ": " + code + " " + putmethod.getStatusLine()); } } finally { @@ -518,6 +506,19 @@ public class ExchangeSession { putmethod.releaseConnection(); } + // add bcc and other properties + patchMethod = new PropPatchMethod(messageUrl); + try { + // update message with blind carbon copy and other flags + addProperties(patchMethod, properties); + int statusCode = wdr.retrieveSessionInstance().executeMethod(patchMethod); + if (statusCode != HttpStatus.SC_MULTI_STATUS) { + throw new IOException("Unable to patch message " + messageUrl + ": " + statusCode + " " + patchMethod.getStatusLine()); + } + + } finally { + patchMethod.releaseConnection(); + } } protected Message buildMessage(ResponseEntity responseEntity) throws URIException { @@ -540,6 +541,8 @@ public class ExchangeSession { message.flagged = "2".equals(prop.getPropertyAsString()); } else if ("x0E070003".equals(localName)) { message.draft = "9".equals(prop.getPropertyAsString()); + } else if ("x10810003".equals(localName)) { + message.answered = prop.getPropertyAsString().length() > 0; } else if ("message-id".equals(prop.getLocalName())) { message.messageId = prop.getPropertyAsString(); if (message.messageId.startsWith("<") && message.messageId.endsWith(">")) { @@ -566,18 +569,28 @@ public class ExchangeSession { } + protected void addProperties(PropPatchMethod patchMethod, Map properties) { + for (Map.Entry entry : properties.entrySet()) { + if ("read".equals(entry.getKey())) { + patchMethod.addPropertyToSet("read", entry.getValue(), "e", "urn:schemas:httpmail:"); + } else if ("junk".equals(entry.getKey())) { + patchMethod.addPropertyToSet("x10830003", entry.getValue(), "f", "http://schemas.microsoft.com/mapi/proptag/"); + } else if ("flagged".equals(entry.getKey())) { + patchMethod.addPropertyToSet("x10900003", entry.getValue(), "f", "http://schemas.microsoft.com/mapi/proptag/"); + } else if ("answered".equals(entry.getKey())) { + patchMethod.addPropertyToSet("x10810003", entry.getValue(), "f", "http://schemas.microsoft.com/mapi/proptag/"); + } else if ("bcc".equals(entry.getKey())) { + patchMethod.addPropertyToSet("bcc", entry.getValue(), "b", "urn:schemas:mailheader:"); + } else if ("draft".equals(entry.getKey())) { + patchMethod.addPropertyToSet("x0E070003", entry.getValue(), "f", "http://schemas.microsoft.com/mapi/proptag/"); + } + } + } + public void updateMessage(Message message, Map properties) throws IOException { PropPatchMethod patchMethod = new PropPatchMethod(URIUtil.encodePathQuery(message.messageUrl)); try { - for (Map.Entry entry : properties.entrySet()) { - if ("read".equals(entry.getKey())) { - patchMethod.addPropertyToSet("read", entry.getValue(), "e", "urn:schemas:httpmail:"); - } else if ("junk".equals(entry.getKey())) { - patchMethod.addPropertyToSet("x10830003", entry.getValue(), "f", "http://schemas.microsoft.com/mapi/proptag/"); - } else if ("flagged".equals(entry.getKey())) { - patchMethod.addPropertyToSet("x10900003", entry.getValue(), "f", "http://schemas.microsoft.com/mapi/proptag/"); - } - } + addProperties(patchMethod, properties); int statusCode = wdr.retrieveSessionInstance().executeMethod(patchMethod); if (statusCode != HttpStatus.SC_MULTI_STATUS) { throw new IOException("Unable to update message properties"); @@ -593,7 +606,7 @@ public class ExchangeSession { MessageList messages = new MessageList(); String searchRequest = "Select \"DAV:uid\", \"http://schemas.microsoft.com/mapi/proptag/x0e080003\"" + " ,\"http://schemas.microsoft.com/mapi/proptag/x10830003\", \"http://schemas.microsoft.com/mapi/proptag/x10900003\"" + - " ,\"http://schemas.microsoft.com/mapi/proptag/x0E070003\"" + + " ,\"http://schemas.microsoft.com/mapi/proptag/x0E070003\", \"http://schemas.microsoft.com/mapi/proptag/x10810003\"" + " ,\"urn:schemas:mailheader:message-id\", \"urn:schemas:httpmail:read\"" + " FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" + " WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = False\n" + @@ -770,11 +783,15 @@ public class ExchangeSession { bccBuffer.append(">"); } + String bcc = bccBuffer.toString(); + HashMap properties = new HashMap(); + if (bcc.length() > 0) { + properties.put("bcc", bcc); + } + String messageName = UUID.randomUUID().toString(); - createMessage(draftsUrl, messageName, - bccBuffer.toString() - , mailBuffer.toString(), false); + createMessage(draftsUrl, messageName, properties, mailBuffer.toString(), false); // warning : slide library expects *unencoded* urls String tempUrl = draftsUrl + "/" + messageName + ".EML"; @@ -925,6 +942,7 @@ public class ExchangeSession { public boolean junk; public boolean flagged; public boolean draft; + public boolean answered; public long getUidAsLong() { byte[] decodedValue = Base64.decode(uid.getBytes()); @@ -955,6 +973,9 @@ public class ExchangeSession { if (draft) { buffer.append("\\Draft "); } + if (answered) { + buffer.append("\\Answered "); + } return buffer.toString().trim(); } diff --git a/src/java/davmail/imap/ImapConnection.java b/src/java/davmail/imap/ImapConnection.java index 88af84d1..80455c60 100644 --- a/src/java/davmail/imap/ImapConnection.java +++ b/src/java/davmail/imap/ImapConnection.java @@ -303,43 +303,7 @@ public class ImapConnection extends AbstractConnection { ExchangeSession.Message message = messages.getByUid(uid); String action = tokens.nextToken(); String flags = tokens.nextToken(); - HashMap properties = new HashMap(); - if ("-Flags".equalsIgnoreCase(action)) { - StringTokenizer flagtokenizer = new StringTokenizer(flags); - while (flagtokenizer.hasMoreTokens()) { - String flag = flagtokenizer.nextToken(); - if ("\\Seen".equals(flag)) { - properties.put("read", "0"); - message.read = false; - } else if ("\\Flagged".equals(flag)) { - properties.put("flagged", "0"); - message.flagged = false; - } else if ("Junk".equals(flag)) { - properties.put("junk", "0"); - message.junk = false; - } - } - } else if ("+Flags".equalsIgnoreCase(action)) { - StringTokenizer flagtokenizer = new StringTokenizer(flags); - while (flagtokenizer.hasMoreTokens()) { - String flag = flagtokenizer.nextToken(); - if ("\\Seen".equals(flag)) { - properties.put("read", "1"); - message.read = true; - } else if ("\\Deleted".equals(flag)) { - message.deleted = true; - } else if ("\\Flagged".equals(flag)) { - properties.put("flagged", "2"); - message.flagged = true; - } else if ("Junk".equals(flag)) { - properties.put("junk", "1"); - message.junk = true; - } - } - } - if (properties.size() > 0) { - session.updateMessage(messages.getByUid(uid), properties); - } + updateFlags(message, action, flags); int index = 0; for (ExchangeSession.Message currentMessage : messages) { index++; @@ -387,6 +351,22 @@ public class ImapConnection extends AbstractConnection { String folderName = BASE64MailboxDecoder.decode(tokens.nextToken()); // TODO handle flags String flags = tokens.nextToken(); + HashMap properties = new HashMap(); + StringTokenizer flagtokenizer = new StringTokenizer(flags); + while (flagtokenizer.hasMoreTokens()) { + String flag = flagtokenizer.nextToken(); + if ("\\Seen".equals(flag)) { + properties.put("read", "1"); + } else if ("\\Flagged".equals(flag)) { + properties.put("flagged", "2"); + } else if ("\\Answered".equals(flag)) { + properties.put("answered", "103"); + } else if ("\\Draft".equals(flag)) { + properties.put("draft", "9"); + } else if ("Junk".equals(flag)) { + properties.put("junk", "1"); + } + } // skip optional date String dateOrSize = tokens.nextToken(); if (tokens.hasMoreTokens()) { @@ -407,7 +387,7 @@ public class ImapConnection extends AbstractConnection { readClient(); String messageName = UUID.randomUUID().toString(); - session.createMessage(session.getFolderPath(folderName), messageName, null, new String(buffer), false); + session.createMessage(session.getFolderPath(folderName), messageName, properties, new String(buffer), false); sendClient(commandId + " OK APPEND completed"); } else if ("noop".equalsIgnoreCase(command) || "check".equalsIgnoreCase(command)) { if (currentFolder != null) { @@ -473,6 +453,49 @@ public class ImapConnection extends AbstractConnection { } } + protected void updateFlags(ExchangeSession.Message message, String action, String flags) throws IOException { + HashMap properties = new HashMap(); + if ("-Flags".equalsIgnoreCase(action)) { + StringTokenizer flagtokenizer = new StringTokenizer(flags); + while (flagtokenizer.hasMoreTokens()) { + String flag = flagtokenizer.nextToken(); + if ("\\Seen".equals(flag)) { + properties.put("read", "0"); + message.read = false; + } else if ("\\Flagged".equals(flag)) { + properties.put("flagged", "0"); + message.flagged = false; + } else if ("Junk".equals(flag)) { + properties.put("junk", "0"); + message.junk = false; + } + } + } else if ("+Flags".equalsIgnoreCase(action)) { + StringTokenizer flagtokenizer = new StringTokenizer(flags); + while (flagtokenizer.hasMoreTokens()) { + String flag = flagtokenizer.nextToken(); + if ("\\Seen".equals(flag)) { + properties.put("read", "1"); + message.read = true; + } else if ("\\Deleted".equals(flag)) { + message.deleted = true; + } else if ("\\Flagged".equals(flag)) { + properties.put("flagged", "2"); + message.flagged = true; + } else if ("\\Answered".equals(flag)) { + properties.put("answered", "103"); + message.answered = true; + } else if ("Junk".equals(flag)) { + properties.put("junk", "1"); + message.junk = true; + } + } + } + if (properties.size() > 0) { + session.updateMessage(message, properties); + } + } + /** * Decode IMAP credentials *