From 61b3f9c7a54a5a5e201da5cf88e4b3c38972a751 Mon Sep 17 00:00:00 2001 From: mguessan Date: Mon, 2 Feb 2009 23:29:44 +0000 Subject: [PATCH] IMAP: Implement copy and delete actions on messages and folders git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@313 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- .../davmail/exchange/ExchangeSession.java | 55 ++++++++++++++++++- src/java/davmail/imap/ImapConnection.java | 42 +++++++++++++- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 24790f6f..996c67d1 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -16,6 +16,7 @@ import org.apache.webdav.lib.WebdavResource; import org.apache.webdav.lib.methods.MoveMethod; import org.apache.webdav.lib.methods.PropPatchMethod; import org.apache.webdav.lib.methods.SearchMethod; +import org.apache.webdav.lib.methods.CopyMethod; import org.htmlcleaner.CommentToken; import org.htmlcleaner.HtmlCleaner; import org.htmlcleaner.TagNode; @@ -545,7 +546,7 @@ public class ExchangeSession { } else if ("message-id".equals(prop.getLocalName())) { message.messageId = prop.getPropertyAsString(); if (message.messageId.startsWith("<") && message.messageId.endsWith(">")) { - message.messageId = message.messageId.substring(1, message.messageId.length()-1); + message.messageId = message.messageId.substring(1, message.messageId.length() - 1); } } } @@ -849,6 +850,27 @@ public class ExchangeSession { } } + public void copyMessage(String messageUrl, String targetName) throws IOException { + String targetPath = getFolderPath(targetName) + messageUrl.substring(messageUrl.lastIndexOf('/')); + CopyMethod method = new CopyMethod(URIUtil.encodePath(messageUrl), + URIUtil.encodePath(targetPath)); + method.setOverwrite(false); + method.addRequestHeader("Allow-Rename", "t"); + try { + int statusCode = wdr.retrieveSessionInstance().executeMethod(method); + if (statusCode == HttpStatus.SC_PRECONDITION_FAILED) { + throw new HttpException("Unable to move message, target already exists"); + } else if (statusCode != HttpStatus.SC_CREATED) { + HttpException ex = new HttpException(); + ex.setReasonCode(method.getStatusCode()); + ex.setReason(method.getStatusText()); + throw ex; + } + } finally { + method.releaseConnection(); + } + } + public void moveFolder(String folderName, String targetName) throws IOException { String folderPath = getFolderPath(folderName); String targetPath = getFolderPath(targetName); @@ -897,6 +919,7 @@ public class ExchangeSession { public int size; public String messageId; public boolean read; + public boolean deleted; public long getUidAsLong() { byte[] decodedValue = Base64.decode(uid.getBytes()); @@ -910,6 +933,17 @@ public class ExchangeSession { return result; } + public String getImapFlags() { + StringBuilder buffer = new StringBuilder(); + if (read) { + buffer.append("\\Seen "); + } + if (deleted) { + buffer.append("\\Deleted"); + } + return buffer.toString(); + } + public void write(OutputStream os) throws IOException { HttpMethod method = null; BufferedReader reader = null; @@ -989,7 +1023,7 @@ public class ExchangeSession { } public int compareTo(Object message) { - return (int)(getUidAsLong()-((Message)message).getUidAsLong()); + return (int) (getUidAsLong() - ((Message) message).getUidAsLong()); } } @@ -1263,6 +1297,23 @@ public class ExchangeSession { return status; } + + public void deleteFolder(String path) throws IOException { + wdr.deleteMethod(getFolderPath(path)); + int status = wdr.getStatusCode(); + if (status != HttpStatus.SC_OK) { + HttpException ex = new HttpException(); + ex.setReasonCode(status); + ex.setReason(wdr.getStatusMessage()); + throw ex; + } + } + + public int deleteMessage(String path) throws IOException { + wdr.deleteMethod(path); + return wdr.getStatusCode(); + } + public int deleteEvent(String path) throws IOException { wdr.deleteMethod(calendarUrl + "/" + URIUtil.decode(path)); return wdr.getStatusCode(); diff --git a/src/java/davmail/imap/ImapConnection.java b/src/java/davmail/imap/ImapConnection.java index 2c2ecc2c..1ed1c499 100644 --- a/src/java/davmail/imap/ImapConnection.java +++ b/src/java/davmail/imap/ImapConnection.java @@ -142,6 +142,8 @@ public class ImapConnection extends AbstractConnection { sendClient(commandId + " BAD missing folder argument"); } } else if ("select".equalsIgnoreCase(command) || "examine".equalsIgnoreCase(command)) { + // first purge previous folder + expunge(); if (tokens.hasMoreTokens()) { String folderName = BASE64MailboxDecoder.decode(tokens.nextToken()); currentFolder = session.getFolder(folderName); @@ -182,6 +184,14 @@ public class ImapConnection extends AbstractConnection { } catch (HttpException e) { sendClient(commandId + " NO " + e.getReason()); } + } else if ("delete".equalsIgnoreCase(command)) { + String folderName = BASE64MailboxDecoder.decode(tokens.nextToken()); + try { + session.deleteFolder(folderName); + sendClient(commandId + " OK delete completed"); + } catch (HttpException e) { + sendClient(commandId + " NO " + e.getReason()); + } } else if ("uid".equalsIgnoreCase(command)) { if (tokens.hasMoreTokens()) { String subcommand = tokens.nextToken(); @@ -222,7 +232,7 @@ public class ImapConnection extends AbstractConnection { int count = 0; for (ExchangeSession.Message message : messages) { count++; - sendClient("* " + count + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.read ? "\\Seen" : "") + "))"); + sendClient("* " + count + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))"); } sendClient(commandId + " OK UID FETCH completed"); } else { @@ -255,7 +265,7 @@ public class ImapConnection extends AbstractConnection { "] {" + baos.size() + "}"); os.write(baos.toByteArray()); os.flush(); - sendClient(" FLAGS (" + (message.read ? "\\Seen" : "") + "))"); + sendClient(" FLAGS (" + (message.getImapFlags()) + "))"); } } } @@ -307,6 +317,8 @@ public class ImapConnection extends AbstractConnection { if ("\\Seen".equals(flag)) { properties.put("read", "1"); message.read = true; + } else if ("\\Deleted".equals(flag)) { + message.deleted = true; } } } @@ -315,10 +327,20 @@ public class ImapConnection extends AbstractConnection { for (ExchangeSession.Message currentMessage : messages) { index++; if (currentMessage == message) { - sendClient("* " + index + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.read ? "\\Seen" : "") + "))"); + sendClient("* " + index + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))"); } } sendClient(commandId + " OK STORE completed"); + } else if ("copy".equalsIgnoreCase(subcommand)) { + long uid = Long.parseLong(tokens.nextToken()); + ExchangeSession.Message message = messages.getByUid(uid); + String targetName = BASE64MailboxDecoder.decode(tokens.nextToken()); + try { + session.copyMessage(message.messageUrl, targetName); + sendClient(commandId + " OK rename completed"); + } catch (HttpException e) { + sendClient(commandId + " NO " + e.getReason()); + } } } else { sendClient(commandId + " BAD command unrecognized"); @@ -372,6 +394,7 @@ public class ImapConnection extends AbstractConnection { sendClient(commandId + " OK APPEND completed"); } else if ("noop".equalsIgnoreCase(command) || "check".equalsIgnoreCase(command)) { if (currentFolder != null) { + expunge(); currentFolder = session.getFolder(currentFolder.folderName); messages = session.getAllMessages(currentFolder.folderUrl); sendClient("* " + currentFolder.objectCount + " EXISTS"); @@ -409,6 +432,19 @@ public class ImapConnection extends AbstractConnection { DavGatewayTray.resetIcon(); } + protected void expunge() throws IOException { + if (messages != null) { + int index = 0; + for (ExchangeSession.Message message : messages) { + index++; + if (message.deleted) { + session.deleteMessage(message.messageUrl); + sendClient("* "+index+" EXPUNGE"); + } + } + } + } + /** * Decode IMAP credentials *