From cd20a970ce343c035c12a61aa55d21a55b3b9e6f Mon Sep 17 00:00:00 2001 From: mguessan Date: Tue, 17 Feb 2009 22:59:32 +0000 Subject: [PATCH] IMAP: search implementation git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@368 3d1905a2-6b24-0410-a738-b14d5a86fcbd --- .../davmail/exchange/ExchangeSession.java | 4 + src/java/davmail/imap/ImapConnection.java | 119 ++++++++++++++---- 2 files changed, 96 insertions(+), 27 deletions(-) diff --git a/src/java/davmail/exchange/ExchangeSession.java b/src/java/davmail/exchange/ExchangeSession.java index 3e0c4f2f..a04fd7ce 100644 --- a/src/java/davmail/exchange/ExchangeSession.java +++ b/src/java/davmail/exchange/ExchangeSession.java @@ -619,6 +619,9 @@ public class ExchangeSession { } public MessageList getAllMessages(String folderName) throws IOException { + return searchMessages(folderName, ""); + } + public MessageList searchMessages(String folderName, String conditions) throws IOException { String folderUrl = getFolderPath(folderName); MessageList messages = new MessageList(); String searchRequest = "Select \"DAV:uid\", \"http://schemas.microsoft.com/mapi/proptag/x0e080003\"" + @@ -627,6 +630,7 @@ public class ExchangeSession { " ,\"urn:schemas:mailheader:message-id\", \"urn:schemas:httpmail:read\", \"DAV:isdeleted\"" + " FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" + " WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = False\n" + + conditions+ " ORDER BY \"urn:schemas:httpmail:date\" ASC"; Enumeration folderEnum = DavGatewayHttpClientFacade.executeSearchMethod(wdr.retrieveSessionInstance(), folderUrl, searchRequest); diff --git a/src/java/davmail/imap/ImapConnection.java b/src/java/davmail/imap/ImapConnection.java index d81298de..80e03441 100644 --- a/src/java/davmail/imap/ImapConnection.java +++ b/src/java/davmail/imap/ImapConnection.java @@ -17,6 +17,7 @@ import java.net.SocketTimeoutException; import java.net.SocketException; import java.util.*; import java.text.SimpleDateFormat; +import java.text.ParseException; /** * Dav Gateway smtp connection implementation. @@ -48,21 +49,7 @@ public class ImapConnection extends AbstractConnection { break; } - tokens = new StringTokenizer(line) { - public String nextToken() { - StringBuilder nextToken = new StringBuilder(); - nextToken.append(super.nextToken()); - while (hasMoreTokens() && nextToken.length() > 0 && nextToken.charAt(0) == '"' - && nextToken.charAt(nextToken.length() - 1) != '"') { - nextToken.append(' ').append(super.nextToken()); - } - while (hasMoreTokens() && nextToken.length() > 0 && nextToken.charAt(0) == '(' - && nextToken.charAt(nextToken.length() - 1) != ')') { - nextToken.append(' ').append(super.nextToken()); - } - return removeQuotes(nextToken.toString()); - } - }; + tokens = new IMAPTokenizer(line); if (tokens.hasMoreTokens()) { commandId = tokens.nextToken(); if (tokens.hasMoreTokens()) { @@ -240,21 +227,38 @@ public class ImapConnection extends AbstractConnection { } } else if ("search".equalsIgnoreCase(subcommand)) { - // only create check search - String messageId = null; - long messageUid = 0; + StringBuilder conditions = new StringBuilder(); + boolean undeleted = true; + while (tokens.hasMoreTokens()) { - messageId = tokens.nextToken(); - } - // reload messages - messages = session.getAllMessages(currentFolder.folderName); - for (ExchangeSession.Message message : messages) { - if (messageId.equals(message.messageId)) { - messageUid = message.getUidAsLong(); + String token = tokens.nextToken(); + if ("UNDELETED".equals(token)) { + undeleted = true; + } else if (token.startsWith("OR ")) { + conditions.append(" AND ("); + IMAPTokenizer innerTokens = new IMAPTokenizer(token); + innerTokens.nextToken(); + boolean first = true; + while (innerTokens.hasMoreTokens()) { + String innerToken = innerTokens.nextToken(); + if (!first) { + conditions.append(" OR "); + } + first = false; + appendSearchParam(innerTokens, innerToken, conditions); + } + conditions.append(")"); + } else { + conditions.append(" AND "); + appendSearchParam(tokens, token, conditions); } } - if (messageUid > 0) { - sendClient("* SEARCH " + messageUid); + + messages = session.searchMessages(currentFolder.folderName, conditions.toString()); + for (ExchangeSession.Message message : messages) { + if ((undeleted && !message.deleted) || !undeleted) { + sendClient("* SEARCH " + message.getUidAsLong()); + } } sendClient(commandId + " OK SEARCH completed"); @@ -427,6 +431,45 @@ public class ImapConnection extends AbstractConnection { DavGatewayTray.resetIcon(); } + private void appendSearchParam(StringTokenizer tokens, String token, StringBuilder conditions) throws IOException { + if ("NOT".equals(token)) { + conditions.append(" NOT "); + appendSearchParam(tokens, tokens.nextToken(), conditions); + } else if ("SUBJECT".equals(token)) { + conditions.append("\"urn:schemas:httpmail:subject\" LIKE '%").append(tokens.nextToken()).append("%'"); + } else if ("BODY".equals(token)) { + conditions.append("\"http://schemas.microsoft.com/mapi/proptag/x01000001E\" LIKE '%").append(tokens.nextToken()).append("%'"); + } else if ("FROM".equals(token)) { + conditions.append("\"urn:schemas:mailheader:from\" LIKE '%").append(tokens.nextToken()).append("%'"); + } else if ("SENTON".equals(token)) { + SimpleDateFormat parser = new SimpleDateFormat("dd-MMM-yyyy", Locale.ENGLISH); + parser.setTimeZone(ExchangeSession.GMT_TIMEZONE); + SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); + dateFormatter.setTimeZone(ExchangeSession.GMT_TIMEZONE); + try { + Date startDate = parser.parse(tokens.nextToken()); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(startDate); + calendar.add(Calendar.DAY_OF_MONTH, 1); + conditions.append("(\"urn:schemas:httpmail:date\" > '") + .append(dateFormatter.format(startDate)) + .append("' AND \"urn:schemas:httpmail:date\" < '") + .append(dateFormatter.format(calendar.getTime())) + .append("')"); + } catch (ParseException e) { + throw new IOException("Invalid search parameters"); + } + + } else if ("HEADER".equals(token)) { + String headerName = tokens.nextToken(); + if ("Message-ID".equalsIgnoreCase(headerName)) { + conditions.append("\"urn:schemas:mailheader:message-id\"='").append(tokens.nextToken()).append("'"); + } + } else { + throw new IOException("Invalid search parameters"); + } + } + protected void expunge() throws IOException { if (messages != null) { int index = 0; @@ -627,4 +670,26 @@ public class ImapConnection extends AbstractConnection { throw new UnsupportedOperationException(); } } + + class IMAPTokenizer extends StringTokenizer { + public IMAPTokenizer(String value) { + super(value); + } + + @Override + public String nextToken() { + StringBuilder nextToken = new StringBuilder(); + nextToken.append(super.nextToken()); + while (hasMoreTokens() && nextToken.length() > 0 && nextToken.charAt(0) == '"' + && nextToken.charAt(nextToken.length() - 1) != '"') { + nextToken.append(' ').append(super.nextToken()); + } + while (hasMoreTokens() && nextToken.length() > 0 && nextToken.charAt(0) == '(' + && nextToken.charAt(nextToken.length() - 1) != ')') { + nextToken.append(' ').append(super.nextToken()); + } + return removeQuotes(nextToken.toString()); + } + } + } \ No newline at end of file