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:
parent
09de523391
commit
f2e19291ab
@ -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;
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user