From 9ebdf91c8174027d4f34e812abe647805daf3973 Mon Sep 17 00:00:00 2001 From: mguessan Date: Thu, 21 Jan 2010 10:49:23 +0000 Subject: [PATCH] IMAP: brand new IMAP uid workaround and refresh folder on Expunge from Gellule git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@924 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- .../davmail/exchange/ExchangeSession.java | 70 +++++++++++++++---- src/java/davmail/imap/ImapConnection.java | 29 ++++---- src/java/log4j.properties | 2 + 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 738bd80c..5cdf5ddc 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -1156,8 +1156,6 @@ public class ExchangeSession { currentFolder.noInferiors = newFolder.noInferiors; currentFolder.unreadCount = newFolder.unreadCount; currentFolder.contenttag = newFolder.contenttag; - // keep previous messages for Thunderbird workaround - currentFolder.previousMessages = currentFolder.messages; currentFolder.loadMessages(); return true; } else { @@ -1204,7 +1202,7 @@ public class ExchangeSession { } }; int status = DavGatewayHttpClientFacade.executeHttpMethod(httpClient, method); - // ok or alredy exists + // ok or already exists if (status != HttpStatus.SC_MULTI_STATUS && status != HttpStatus.SC_METHOD_NOT_ALLOWED) { throw DavGatewayHttpClientFacade.buildHttpException(method); } @@ -1318,10 +1316,10 @@ public class ExchangeSession { */ public ExchangeSession.MessageList messages; /** - * Previous folder message list before refresh. + * PermanentURL to UID map. */ - public ExchangeSession.MessageList previousMessages; - + private final HashMap uidUrlHashMap = new HashMap(); + /** * Get IMAP folder flags. * @@ -1343,7 +1341,46 @@ public class ExchangeSession { * @throws IOException on error */ public void loadMessages() throws IOException { - messages = searchMessages(folderPath, ""); + messages = ExchangeSession.this.searchMessages(folderPath, ""); + fixUids(messages); + } + + /** + * Search messages in folder matching query. + * + * @param query search query + * @return message list + * @throws IOException on error + */ + public MessageList searchMessages(String query) throws IOException { + MessageList localMessages = ExchangeSession.this.searchMessages(folderName, query); + fixUids(localMessages); + return localMessages; + } + + /** + * Restore previous uids changed by a PROPPATCH (flag change). + * + * @param messages message list + */ + protected void fixUids(MessageList messages) { + boolean sortNeeded = false; + for (Message message : messages) { + if (uidUrlHashMap.containsKey(message.getPermanentUrl())) { + long previousUid = uidUrlHashMap.get(message.getPermanentUrl()); + if (message.getImapUid() != previousUid) { + LOGGER.debug("Restoring IMAP uid " + message.getImapUid() + " -> " + previousUid + " for message " + message.getPermanentUrl() + " (" + message.messageUrl + ')'); + message.setImapUid(previousUid); + sortNeeded = true; + } + } else { + // add message to uid map + uidUrlHashMap.put(message.getPermanentUrl(), message.getImapUid()); + } + } + if (sortNeeded) { + Collections.sort(messages); + } } /** @@ -1446,6 +1483,14 @@ public class ExchangeSession { return imapUid; } + /** + * Set IMAP uid. + * @param imapUid new uid + */ + public void setImapUid(long imapUid) { + this.imapUid = imapUid; + } + /** * Exchange uid. * @@ -1459,9 +1504,8 @@ public class ExchangeSession { * Return permanent message url. * * @return permanent message url - * @throws URIException on error */ - public String getPermanentUrl() throws URIException { + public String getPermanentUrl() { return permanentUrl; } @@ -2222,10 +2266,10 @@ public class ExchangeSession { || line.indexOf("RSVP=TRUE") >= 0 || line.indexOf("PARTSTAT=NEEDS-ACTION") >= 0 // need to include other PARTSTATs participants for CANCEL notifications - || line.indexOf("PARTSTAT=ACCEPTED") >=0 - || line.indexOf("PARTSTAT=DECLINED") >=0 - || line.indexOf("PARTSTAT=TENTATIVE") >=0 - )) { + || line.indexOf("PARTSTAT=ACCEPTED") >= 0 + || line.indexOf("PARTSTAT=DECLINED") >= 0 + || line.indexOf("PARTSTAT=TENTATIVE") >= 0 + )) { if (line.indexOf("ROLE=OPT-PARTICIPANT") >= 0) { optionalAttendees.add(value); } else { diff --git a/src/java/davmail/imap/ImapConnection.java b/src/java/davmail/imap/ImapConnection.java index a8ecf285..0242936b 100644 --- a/src/java/davmail/imap/ImapConnection.java +++ b/src/java/davmail/imap/ImapConnection.java @@ -209,8 +209,15 @@ public class ImapConnection extends AbstractConnection { } else { sendClient(commandId + " BAD command unrecognized"); } - } else if ("close".equalsIgnoreCase(command) || "expunge".equalsIgnoreCase(command)) { - expunge("close".equalsIgnoreCase(command)); + } else if ("expunge".equalsIgnoreCase(command)) { + expunge(false); + // need to refresh folder to avoid 404 errors + session.refreshFolder(currentFolder); + sendClient(commandId + " OK " + command + " completed"); + } else if ("close".equalsIgnoreCase(command)) { + expunge(true); + // deselect folder + currentFolder = null; sendClient(commandId + " OK " + command + " completed"); } else if ("create".equalsIgnoreCase(command)) { if (tokens.hasMoreTokens()) { @@ -252,7 +259,7 @@ public class ImapConnection extends AbstractConnection { if (tokens.hasMoreTokens()) { parameters = tokens.nextToken(); } - UIDRangeIterator uidRangeIterator = getUIDRangeIterator(currentFolder, ranges); + UIDRangeIterator uidRangeIterator = new UIDRangeIterator(currentFolder.messages, ranges); while (uidRangeIterator.hasNext()) { DavGatewayTray.switchIcon(); ExchangeSession.Message message = uidRangeIterator.next(); @@ -275,13 +282,13 @@ public class ImapConnection extends AbstractConnection { sendClient(commandId + " OK SEARCH completed"); } else if ("store".equalsIgnoreCase(subcommand)) { - UIDRangeIterator uidRangeIterator = getUIDRangeIterator(currentFolder, tokens.nextToken()); + UIDRangeIterator uidRangeIterator = new UIDRangeIterator(currentFolder.messages, tokens.nextToken()); String action = tokens.nextToken(); String flags = tokens.nextToken(); handleStore(commandId, uidRangeIterator, action, flags); } else if ("copy".equalsIgnoreCase(subcommand)) { try { - UIDRangeIterator uidRangeIterator = getUIDRangeIterator(currentFolder, tokens.nextToken()); + UIDRangeIterator uidRangeIterator = new UIDRangeIterator(currentFolder.messages, tokens.nextToken()); String targetName = BASE64MailboxDecoder.decode(tokens.nextToken()); while (uidRangeIterator.hasNext()) { DavGatewayTray.switchIcon(); @@ -648,7 +655,7 @@ public class ImapConnection extends AbstractConnection { if ("AND ()".equals(query)) { query = null; } - ExchangeSession.MessageList localMessages = session.searchMessages(currentFolder.folderName, query); + ExchangeSession.MessageList localMessages = currentFolder.searchMessages(query); int index = 1; for (ExchangeSession.Message message : localMessages) { if ((conditions.deleted == null || message.deleted == conditions.deleted) @@ -1177,16 +1184,6 @@ public class ImapConnection extends AbstractConnection { return result; } - protected UIDRangeIterator getUIDRangeIterator(ExchangeSession.Folder folder, String ranges) { - UIDRangeIterator uidRangeIterator = new UIDRangeIterator(folder.messages, ranges); - if (!uidRangeIterator.hasNext() && folder.previousMessages != null) { - // message not found in current list, try to get message - // from previous list to handle recent uid change - uidRangeIterator = new UIDRangeIterator(folder.previousMessages, ranges); - } - return uidRangeIterator; - } - /** * Filter to output only headers, also count full size */ diff --git a/src/java/log4j.properties b/src/java/log4j.properties index 15f09876..e2485431 100644 --- a/src/java/log4j.properties +++ b/src/java/log4j.properties @@ -11,3 +11,5 @@ log4j.appender.ConsoleAppender=org.apache.log4j.ConsoleAppender log4j.appender.ConsoleAppender.layout=org.apache.log4j.PatternLayout log4j.appender.ConsoleAppender.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c %x - %m%n +#log4j.logger.org.apache.commons.httpclient.util.IdleConnectionHandler=DEBUG +#log4j.logger.org.apache.commons.httpclient.util.MultiThreadedHttpConnectionManager=DEBUG