1
0
mirror of https://github.com/moparisthebest/davmail synced 2024-08-13 16:53:51 -04:00

IMAP message list and fetch now working

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@302 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2009-01-23 10:30:48 +00:00
parent 09de523391
commit f2e19291ab
2 changed files with 125 additions and 24 deletions

View File

@ -61,10 +61,21 @@ public class ExchangeSession {
WELL_KNOWN_FOLDERS.add("urn:schemas:httpmail:calendar"); WELL_KNOWN_FOLDERS.add("urn:schemas:httpmail:calendar");
} }
public static final HashMap<String, String> PRIORITIES = new HashMap<String, String>();
static {
PRIORITIES.put("-2", "5 (Lowest)");
PRIORITIES.put("-1", "4 (Low)");
PRIORITIES.put("1", "2 (High)");
PRIORITIES.put("2", "1 (Highest)");
}
/** /**
* Date parser from Exchange format * Date parser/formatter from Exchange format
*/ */
private final SimpleDateFormat dateFormatter; private final SimpleDateFormat dateFormatter;
private final SimpleDateFormat dateParser;
/** /**
* Various standard mail boxes Urls * Various standard mail boxes Urls
@ -102,6 +113,10 @@ public class ExchangeSession {
// SimpleDateFormat are not thread safe, need to create one instance for // SimpleDateFormat are not thread safe, need to create one instance for
// each session // each session
dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); dateFormatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
dateParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
dateParser.setTimeZone(GMT_TIMEZONE);
LOGGER.debug("Session " + this + " created"); LOGGER.debug("Session " + this + " created");
} }
@ -513,6 +528,23 @@ public class ExchangeSession {
message.size = Integer.parseInt(prop.getPropertyAsString()); message.size = Integer.parseInt(prop.getPropertyAsString());
} else if ("uid".equals(localName)) { } else if ("uid".equals(localName)) {
message.uid = prop.getPropertyAsString(); message.uid = prop.getPropertyAsString();
} else if ("date".equals(prop.getLocalName())) {
message.date = prop.getPropertyAsString();
} else if ("message-id".equals(prop.getLocalName())) {
message.messageId = prop.getPropertyAsString();
} else if ("from".equals(prop.getLocalName())) {
message.from = prop.getPropertyAsString();
} else if ("to".equals(prop.getLocalName())) {
message.to = prop.getPropertyAsString();
} else if ("cc".equals(prop.getLocalName())) {
message.cc = prop.getPropertyAsString();
} else if ("subject".equals(prop.getLocalName())) {
message.subject = prop.getPropertyAsString();
} else if ("priority".equals(prop.getLocalName())) {
String priorityLabel = PRIORITIES.get(prop.getPropertyAsString());
if (priorityLabel != null) {
message.priority = priorityLabel;
}
} }
} }
@ -538,6 +570,7 @@ public class ExchangeSession {
String folderUrl = getFolderPath(folderName); String folderUrl = getFolderPath(folderName);
List<Message> messages = new ArrayList<Message>(); List<Message> messages = new ArrayList<Message>();
String searchRequest = "Select \"DAV:uid\", \"http://schemas.microsoft.com/mapi/proptag/x0e080003\"" + String searchRequest = "Select \"DAV:uid\", \"http://schemas.microsoft.com/mapi/proptag/x0e080003\"" +
" ,\"urn:schemas:mailheader:from\",\"urn:schemas:mailheader:to\",\"urn:schemas:mailheader:cc\",\"urn:schemas:httpmail:subject\",\"urn:schemas:mailheader:date\",\"urn:schemas:mailheader:message-id\",\"urn:schemas:httpmail:priority\""+
" FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" + " FROM Scope('SHALLOW TRAVERSAL OF \"" + folderUrl + "\"')\n" +
" WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = False\n" + " WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = False\n" +
" ORDER BY \"urn:schemas:httpmail:date\" ASC"; " ORDER BY \"urn:schemas:httpmail:date\" ASC";
@ -552,11 +585,12 @@ public class ExchangeSession {
return messages; return messages;
} }
public List<Folder> getSubFolders(String folderName) throws IOException { public List<Folder> getSubFolders(String folderName,boolean recursive) throws IOException {
String mode = recursive?"DEEP":"SHALLOW";
List<Folder> folders = new ArrayList<Folder>(); List<Folder> folders = new ArrayList<Folder>();
String searchRequest = "Select \"DAV:nosubs\", \"DAV:hassubs\"," + String searchRequest = "Select \"DAV:nosubs\", \"DAV:hassubs\"," +
" \"DAV:hassubs\",\"urn:schemas:httpmail:unreadcount\"" + " \"DAV:hassubs\",\"urn:schemas:httpmail:unreadcount\"" +
" FROM Scope('SHALLOW TRAVERSAL OF \"" + getFolderPath(folderName) + "\"')\n" + " FROM Scope('"+mode+" TRAVERSAL OF \"" + getFolderPath(folderName) + "\"')\n" +
" WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = True \n"; " WHERE \"DAV:ishidden\" = False AND \"DAV:isfolder\" = True \n";
Enumeration folderEnum = DavGatewayHttpClientFacade.executeSearchMethod(wdr.retrieveSessionInstance(), mailPath, searchRequest); Enumeration folderEnum = DavGatewayHttpClientFacade.executeSearchMethod(wdr.retrieveSessionInstance(), mailPath, searchRequest);
@ -585,7 +619,13 @@ public class ExchangeSession {
if ("unreadcount".equals(property.getLocalName())) { if ("unreadcount".equals(property.getLocalName())) {
folder.unreadCount = Integer.parseInt(property.getPropertyAsString()); folder.unreadCount = Integer.parseInt(property.getPropertyAsString());
} }
if ("getlastmodified".equals(property.getLocalName())) {
try {
folder.lastModified = dateParser.parse(property.getPropertyAsString()).getTime();
} catch (ParseException e) {
LOGGER.error("Unable to parse date: "+e);
}
}
} }
if (href.endsWith("/")) { if (href.endsWith("/")) {
href = href.substring(0, href.length()-1); href = href.substring(0, href.length()-1);
@ -757,6 +797,7 @@ public class ExchangeSession {
reqProps.add("DAV:nosubs"); reqProps.add("DAV:nosubs");
reqProps.add("DAV:objectcount"); reqProps.add("DAV:objectcount");
reqProps.add("urn:schemas:httpmail:unreadcount"); reqProps.add("urn:schemas:httpmail:unreadcount");
reqProps.add("DAV:getlastmodified");
Enumeration folderEnum = wdr.propfindMethod(folder.folderUrl, 0, reqProps); Enumeration folderEnum = wdr.propfindMethod(folder.folderUrl, 0, reqProps);
if (folderEnum.hasMoreElements()) { if (folderEnum.hasMoreElements()) {
@ -772,6 +813,7 @@ public class ExchangeSession {
public int unreadCount; public int unreadCount;
public boolean hasChildren; public boolean hasChildren;
public boolean noInferiors; public boolean noInferiors;
public long lastModified;
public String getFlags() { public String getFlags() {
if (noInferiors) { if (noInferiors) {
@ -788,6 +830,13 @@ public class ExchangeSession {
public String messageUrl; public String messageUrl;
public String uid; public String uid;
public int size; public int size;
public String from;
public String date;
public String messageId;
public String subject;
public String priority;
public String cc;
public String to;
public void write(OutputStream os) throws IOException { public void write(OutputStream os) throws IOException {
HttpMethod method = null; HttpMethod method = null;

View File

@ -6,6 +6,7 @@ import java.net.SocketException;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.List; import java.util.List;
import java.io.IOException; import java.io.IOException;
import java.io.ByteArrayOutputStream;
import davmail.AbstractConnection; import davmail.AbstractConnection;
import davmail.tray.DavGatewayTray; import davmail.tray.DavGatewayTray;
@ -50,6 +51,10 @@ public class ImapConnection extends AbstractConnection {
&& nextToken.charAt(nextToken.length() - 1) != '"') { && nextToken.charAt(nextToken.length() - 1) != '"') {
nextToken.append(' ').append(super.nextToken()); nextToken.append(' ').append(super.nextToken());
} }
while (hasMoreTokens() && nextToken.length() > 0 && nextToken.charAt(0) == '('
&& nextToken.charAt(nextToken.length() - 1) != ')') {
nextToken.append(' ').append(super.nextToken());
}
return nextToken.toString(); return nextToken.toString();
} }
}; };
@ -103,24 +108,26 @@ public class ImapConnection extends AbstractConnection {
if (state != AUTHENTICATED) { if (state != AUTHENTICATED) {
sendClient(commandId + " BAD command authentication required"); sendClient(commandId + " BAD command authentication required");
} else { } else {
if ("lsub".equalsIgnoreCase(command)) { if ("lsub".equalsIgnoreCase(command) || "list".equalsIgnoreCase(command)) {
sendClient(commandId + " OK LSUB completed");
} else if ("list".equalsIgnoreCase(command)) {
if (tokens.hasMoreTokens()) { if (tokens.hasMoreTokens()) {
String folderContext = BASE64MailboxDecoder.decode(removeQuotes(tokens.nextToken())); String folderContext = BASE64MailboxDecoder.decode(removeQuotes(tokens.nextToken()));
if (tokens.hasMoreTokens()) { if (tokens.hasMoreTokens()) {
String folderQuery = folderContext + BASE64MailboxDecoder.decode(removeQuotes(tokens.nextToken())); String folderQuery = folderContext + BASE64MailboxDecoder.decode(removeQuotes(tokens.nextToken()));
if (folderQuery.endsWith("%")) { if (folderQuery.endsWith("%/%")) {
List<ExchangeSession.Folder> folders = session.getSubFolders(folderQuery.substring(0, folderQuery.length() - 1)); folderQuery = folderQuery.substring(0, folderQuery.length() - 2);
}
if (folderQuery.endsWith("%") || folderQuery.endsWith("*")) {
boolean recursive = folderQuery.endsWith("*");
List<ExchangeSession.Folder> folders = session.getSubFolders(folderQuery.substring(0, folderQuery.length() - 1), recursive);
for (ExchangeSession.Folder folder : folders) { for (ExchangeSession.Folder folder : folders) {
sendClient("* LIST (" + folder.getFlags() + ") \"/\" \"" + BASE64MailboxEncoder.encode(folder.folderUrl) + "\""); sendClient("* " + command + " (" + folder.getFlags() + ") \"/\" \"" + BASE64MailboxEncoder.encode(folder.folderUrl) + "\"");
} }
sendClient(commandId + " OK LIST completed"); sendClient(commandId + " OK " + command + " completed");
} else { } else {
ExchangeSession.Folder folder = session.getFolder(folderQuery); ExchangeSession.Folder folder = session.getFolder(folderQuery);
if (folder != null) { if (folder != null) {
sendClient("* LIST (" + folder.getFlags() + ") \"/\" \"" + BASE64MailboxEncoder.encode(folder.folderUrl) + "\""); sendClient("* " + command + " (" + folder.getFlags() + ") \"/\" \"" + BASE64MailboxEncoder.encode(folder.folderUrl) + "\"");
sendClient(commandId + " OK LIST completed"); sendClient(commandId + " OK " + command + " completed");
} else { } else {
sendClient(commandId + " NO Folder not found"); sendClient(commandId + " NO Folder not found");
} }
@ -138,11 +145,11 @@ public class ImapConnection extends AbstractConnection {
messages = session.getAllMessages(currentFolder.folderUrl); messages = session.getAllMessages(currentFolder.folderUrl);
sendClient("* " + currentFolder.objectCount + " EXISTS"); sendClient("* " + currentFolder.objectCount + " EXISTS");
sendClient("* " + currentFolder.objectCount + " RECENT"); sendClient("* " + currentFolder.objectCount + " RECENT");
sendClient("* OK [UIDVALIDITY " + System.currentTimeMillis() + "]"); sendClient("* OK [UIDVALIDITY " + currentFolder.lastModified + "]");
sendClient("* OK [UIDNEXT " + (currentFolder.objectCount + 1) + "]"); sendClient("* OK [UIDNEXT " + (currentFolder.objectCount + 1) + "]");
sendClient("* FLAGS (\\Answered \\Deleted \\Draft \\Flagged \\Seen)"); sendClient("* FLAGS (\\Answered \\Deleted \\Draft \\Flagged \\Seen $Forwarded $MDNSent Forwarded $Junk $NotJunk Junk JunkRecorded NonJunk NotJunk)");
sendClient("* OK [PERMANENTFLAGS (\\Answered \\Deleted \\Draft \\Flagged \\Seen)]"); sendClient("* OK [PERMANENTFLAGS (\\Answered \\Deleted \\Draft \\Flagged \\Seen $Forwarded $MDNSent Forwarded \\*)] junk-related flags are not permanent");
sendClient("* [UNSEEN 1] first unseen message in inbox"); //sendClient("* [UNSEEN 1] first unseen message in inbox");
sendClient(commandId + " OK [READ-WRITE] " + command + " completed"); sendClient(commandId + " OK [READ-WRITE] " + command + " completed");
} else { } else {
sendClient(commandId + " BAD command unrecognized"); sendClient(commandId + " BAD command unrecognized");
@ -166,17 +173,60 @@ public class ImapConnection extends AbstractConnection {
} else if ("uid".equalsIgnoreCase(command)) { } else if ("uid".equalsIgnoreCase(command)) {
if (tokens.hasMoreTokens() && "fetch".equalsIgnoreCase(tokens.nextToken())) { if (tokens.hasMoreTokens() && "fetch".equalsIgnoreCase(tokens.nextToken())) {
if (tokens.hasMoreTokens()) { if (tokens.hasMoreTokens()) {
String parameter = tokens.nextToken(); String messageParameter = tokens.nextToken();
if (currentFolder == null) { if (currentFolder == null) {
sendClient(commandId + " NO no folder selected"); sendClient(commandId + " NO no folder selected");
} }
if ("1:*".equals(parameter)) { int startIndex;
for (int i = 0; i < currentFolder.objectCount; i++) { int endIndex;
sendClient("* FETCH (UID " + (i + 1) + " FLAGS (\\Recent))"); int colonIndex = messageParameter.indexOf(":");
if (colonIndex < 0) {
startIndex = endIndex = Integer.parseInt(messageParameter);
} else {
startIndex = Integer.parseInt(messageParameter.substring(0, colonIndex));
if (messageParameter.endsWith("*")) {
endIndex = messages.size();
} else {
endIndex = Integer.parseInt(messageParameter.substring(colonIndex + 1));
}
}
if ("1:*".equals(messageParameter)) {
int count = 0;
for (ExchangeSession.Message message : messages) {
count++;
sendClient("* " + count + " FETCH (UID " + count + " FLAGS (\\Seen))");
} }
sendClient(commandId + " OK UID FETCH completed"); sendClient(commandId + " OK UID FETCH completed");
} else { } else {
sendClient(commandId + " BAD command unrecognized"); if (tokens.hasMoreTokens()) {
String parameters = tokens.nextToken();
for (int messageIndex = startIndex; messageIndex <= endIndex; messageIndex++) {
ExchangeSession.Message message = messages.get(messageIndex - 1);
if ("(BODYSTRUCTURE)".equals(parameters)) {
sendClient("* " + messageIndex + " FETCH (BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"windows-1252\") NIL NIL \"QUOTED-PRINTABLE\" " + message.size + " 50 NIL NIL NIL NIL))");
} else if (parameters.indexOf("BODY[]") >= 0) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.write(baos);
baos.close();
sendClient("* " + messageIndex + " FETCH (UID " + messageIndex + " RFC822.SIZE " + baos.size() + " BODY[]<0>" +
" {" + baos.size() + "}");
message.write(os);
sendClient(")");
} else {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.write(baos);
baos.close();
sendClient("* " + messageIndex + " FETCH (UID " + messageIndex + " RFC822.SIZE " + baos.size() + " BODY[HEADER.FIELDS (FROM TO CC SUBJECT DATE MESSAGE-ID PRIORITY X-PRIORITY REFERENCES NEWSGROUPS IN-REPLY-TO CONTENT-TYPE)" +
"] {" + baos.size() + "}");
message.write(os);
sendClient(" FLAGS (\\Seen))");
}
}
sendClient(commandId + " OK FETCH completed");
}
} }
} else { } else {
sendClient(commandId + " BAD command unrecognized"); sendClient(commandId + " BAD command unrecognized");
@ -191,15 +241,17 @@ public class ImapConnection extends AbstractConnection {
if (tokens.hasMoreTokens()) { if (tokens.hasMoreTokens()) {
String parameters = tokens.nextToken(); String parameters = tokens.nextToken();
if ("(BODYSTRUCTURE)".equals(parameters)) { if ("(BODYSTRUCTURE)".equals(parameters)) {
sendClient("* "+messageIndex+" FETCH (BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"windows-1252\") NIL NIL \"QUOTED-PRINTABLE\" "+message.size+" 50 NIL NIL NIL NIL))"); sendClient("* " + messageIndex + " FETCH (BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"windows-1252\") NIL NIL \"QUOTED-PRINTABLE\" " + message.size + " 50 NIL NIL NIL NIL))");
sendClient(commandId + " OK FETCH completed"); sendClient(commandId + " OK FETCH completed");
} else { } else {
sendClient("* "+messageIndex+" 1 FETCH (BODY[TEXT]<0> {" + message.size + "}"); sendClient("* " + messageIndex + " 1 FETCH (BODY[TEXT]<0> {" + message.size + "}");
message.write(os); message.write(os);
sendClient(commandId + " OK FETCH completed"); sendClient(commandId + " OK FETCH completed");
} }
} }
} }
} else if ("noop".equalsIgnoreCase(command)) {
sendClient(commandId + " OK NOOP completed");
} else { } else {
sendClient(commandId + " BAD command unrecognized"); sendClient(commandId + " BAD command unrecognized");
} }