From 1d3cd69a7ea54d96cd4ef05f90767657c1cc8a34 Mon Sep 17 00:00:00 2001 From: mguessan Date: Thu, 29 Oct 2009 17:19:00 +0000 Subject: [PATCH] IMAP: implement store by id and ENVELOPE git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@801 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- .../davmail/exchange/ExchangeSession.java | 20 ++- src/java/davmail/imap/ImapConnection.java | 135 ++++++++++++++---- 2 files changed, 128 insertions(+), 27 deletions(-) diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 209fdcc2..992c5bd0 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -287,7 +287,7 @@ public class ExchangeSession { if (path.startsWith("/")) { // path is absolute, replace method path uri.setPath(path); - } else if (path.startsWith("http://") || path.startsWith("https://")){ + } else if (path.startsWith("http://") || path.startsWith("https://")) { return path; } else { // relative path, build new path @@ -1100,8 +1100,8 @@ public class ExchangeSession { /** * Create Exchange folder with given folder class. * - * @param folderName logical folder name - * @param folderClass folder class + * @param folderName logical folder name + * @param folderClass folder class * @throws IOException on error */ public void createFolder(String folderName, String folderClass) throws IOException { @@ -1350,6 +1350,11 @@ public class ExchangeSession { */ public boolean forwarded; + /** + * Message content parsed in a MIME message. + */ + protected MimeMessage mimeMessage; + /** * IMAP uid , unique in folder (x0e230003) * @@ -1453,6 +1458,15 @@ public class ExchangeSession { } } + public MimeMessage getMimeMessage() throws IOException, MessagingException { + if (mimeMessage == null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + write(baos); + mimeMessage = new MimeMessage(null, new ByteArrayInputStream(baos.toByteArray())); + } + return mimeMessage; + } + /** * Delete message. * diff --git a/src/java/davmail/imap/ImapConnection.java b/src/java/davmail/imap/ImapConnection.java index 998b99c0..2d357121 100644 --- a/src/java/davmail/imap/ImapConnection.java +++ b/src/java/davmail/imap/ImapConnection.java @@ -30,11 +30,9 @@ import davmail.exchange.ExchangeSessionFactory; import davmail.ui.tray.DavGatewayTray; import org.apache.commons.httpclient.HttpException; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimePart; +import javax.mail.internet.*; import javax.mail.MessagingException; +import javax.mail.Address; import java.io.*; import java.net.Socket; import java.net.SocketTimeoutException; @@ -278,13 +276,7 @@ public class ImapConnection extends AbstractConnection { UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken()); String action = tokens.nextToken(); String flags = tokens.nextToken(); - while (uidRangeIterator.hasNext()) { - DavGatewayTray.switchIcon(); - ExchangeSession.Message message = uidRangeIterator.next(); - updateFlags(message, action, flags); - sendClient("* " + (uidRangeIterator.currentIndex) + " FETCH (UID " + message.getImapUid() + " FLAGS (" + (message.getImapFlags()) + "))"); - } - sendClient(commandId + " OK STORE completed"); + handleStore(commandId, uidRangeIterator, action, flags); } else if ("copy".equalsIgnoreCase(subcommand)) { try { UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken()); @@ -333,6 +325,11 @@ public class ImapConnection extends AbstractConnection { sendClient(commandId + " OK FETCH completed"); } + } else if ("store".equalsIgnoreCase(command)) { + RangeIterator rangeIterator = new RangeIterator(tokens.nextToken()); + String action = tokens.nextToken(); + String flags = tokens.nextToken(); + handleStore(commandId, rangeIterator, action, flags); } else if ("append".equalsIgnoreCase(command)) { String folderName = BASE64MailboxDecoder.decode(tokens.nextToken()); @@ -506,6 +503,8 @@ public class ImapConnection extends AbstractConnection { String param = paramTokens.nextToken(); if ("FLAGS".equals(param)) { buffer.append(" FLAGS (").append(message.getImapFlags()).append(')'); + } else if ("ENVELOPE".equals(param)) { + appendEnvelope(buffer, message); } else if ("BODYSTRUCTURE".equals(param)) { if (parameters.indexOf("BODY.") >= 0) { // Apple Mail: send structure with body, need exact RFC822.SIZE @@ -596,6 +595,17 @@ public class ImapConnection extends AbstractConnection { sendClient(buffer.toString()); } + protected void handleStore(String commandId, AbstractRangeIterator rangeIterator, String action, String flags) throws IOException { + while (rangeIterator.hasNext()) { + DavGatewayTray.switchIcon(); + ExchangeSession.Message message = rangeIterator.next(); + updateFlags(message, action, flags); + sendClient("* " + (rangeIterator.getCurrentIndex()) + " FETCH (UID " + message.getImapUid() + " FLAGS (" + (message.getImapFlags()) + "))"); + } + sendClient(commandId + " OK STORE completed"); + } + + protected List handleSearch(IMAPTokenizer tokens) throws IOException { List uidList = new ArrayList(); SearchConditions conditions = new SearchConditions(); @@ -642,13 +652,88 @@ public class ImapConnection extends AbstractConnection { return uidList; } + protected void appendEnvelope(StringBuilder buffer, ExchangeSession.Message message) throws IOException { + buffer.append(" ENVELOPE ("); + + try { + MimeMessage mimeMessage = message.getMimeMessage(); + // Fake envelope for date, subject, from, sender, reply-to, to, cc, bcc,in-reply-to, message-id + appendEnvelopeHeader(buffer, mimeMessage.getHeader("Date")); + appendEnvelopeHeader(buffer, mimeMessage.getHeader("Subject")); + appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("From", ",")); + appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("Sender", ",")); + appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("Reply-To", ",")); + appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("CC", ",")); + appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("BCC", ",")); + appendMailEnvelopeHeader(buffer, mimeMessage.getHeader("In-Reply-To", ",")); + appendEnvelopeHeader(buffer, mimeMessage.getHeader("Messagee-Id")); + + } catch (MessagingException me) { + DavGatewayTray.warn(me); + // send fake envelope + buffer.append(" nil nil nil nil nil nil nil nil nil nil"); + } + buffer.append(')'); + } + + protected void appendEnvelopeHeader(StringBuilder buffer, String[] value) { + buffer.append(' '); + if (value != null && value.length > 0) { + try { + buffer.append('"'); + // TODO: replace with MimeUtility.unfold + buffer.append(MimeUtility.decodeText(value[0]).replaceAll("\r\n", "")); + buffer.append('"'); + } catch (UnsupportedEncodingException e) { + DavGatewayTray.warn(e); + buffer.append("nil"); + } + } else { + buffer.append("nil"); + } + } + + protected void appendMailEnvelopeHeader(StringBuilder buffer, String value) { + buffer.append(' '); + if (value != null) { + try { + InternetAddress[] addresses = InternetAddress.parseHeader(value, false); + buffer.append('('); + for (InternetAddress address : addresses) { + buffer.append('('); + String personal = address.getPersonal(); + if (personal != null) { + buffer.append('"').append(personal).append('"'); + } else { + buffer.append("nil"); + } + buffer.append(" nil "); + String mail = address.getAddress(); + int atIndex = mail.indexOf('@'); + if (atIndex >= 0) { + buffer.append('"').append(mail.substring(0, atIndex)).append('"'); + buffer.append(' '); + buffer.append('"').append(mail.substring(atIndex + 1)).append('"'); + } else { + buffer.append("nil nil"); + } + buffer.append(')'); + } + buffer.append(')'); + } catch (AddressException e) { + DavGatewayTray.warn(e); + buffer.append("nil"); + } + } else { + buffer.append("nil"); + } + } + protected void appendBodyStructure(StringBuilder buffer, ExchangeSession.Message message) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - message.write(baos); buffer.append(" BODYSTRUCTURE "); try { - MimeMessage mimeMessage = new MimeMessage(null, new ByteArrayInputStream(baos.toByteArray())); + MimeMessage mimeMessage = message.getMimeMessage(); Object mimeBody = mimeMessage.getContent(); if (mimeBody instanceof MimeMultipart) { buffer.append('('); @@ -674,16 +759,12 @@ public class ImapConnection extends AbstractConnection { } } catch (UnsupportedEncodingException e) { DavGatewayTray.warn(e); - // dump message in log - DavGatewayTray.debug(new BundleMessage("LOG_MESSAGE", new String(baos.toByteArray()))); // failover: send default bodystructure - buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL ").append(baos.size()).append(" NIL)"); + buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL NIL NIL)"); } catch (MessagingException me) { DavGatewayTray.warn(me); - // dump message in log - DavGatewayTray.debug(new BundleMessage("LOG_MESSAGE", new String(baos.toByteArray()))); // failover: send default bodystructure - buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL ").append(baos.size()).append(" NIL)"); + buffer.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL NIL NIL NIL)"); } } @@ -1138,9 +1219,16 @@ public class ImapConnection extends AbstractConnection { } } - protected class UIDRangeIterator implements Iterator { - final String[] ranges; + protected abstract class AbstractRangeIterator implements Iterator { int currentIndex; + + protected int getCurrentIndex() { + return currentIndex; + } + } + + protected class UIDRangeIterator extends AbstractRangeIterator { + final String[] ranges; int currentRangeIndex; long startUid; long endUid; @@ -1219,9 +1307,8 @@ public class ImapConnection extends AbstractConnection { } } - protected class RangeIterator implements Iterator { + protected class RangeIterator extends AbstractRangeIterator { final String[] ranges; - int currentIndex; int currentRangeIndex; long startUid; long endUid;