IMAP: Fetch by id for Apple Mail, hide authenticate password in logs, use actual message list size instead of object count

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@382 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2009-02-20 17:06:03 +00:00
parent fda58f72e8
commit 1b7a121318
1 changed files with 128 additions and 53 deletions

View File

@ -77,11 +77,13 @@ public class ImapConnection extends AbstractConnection {
if (tokens.hasMoreTokens()) {
String authenticationMethod = tokens.nextToken();
if ("LOGIN".equalsIgnoreCase(authenticationMethod)) {
sendClient("+ " + base64Encode("Username:"));
userName = base64Decode(readClient());
sendClient("+ " + base64Encode("Password:"));
password = base64Decode(readClient());
try {
sendClient("+ " + base64Encode("Username:"));
state = State.LOGIN;
userName = base64Decode(readClient());
sendClient("+ " + base64Encode("Password:"));
state = State.PASSWORD;
password = base64Decode(readClient());
session = ExchangeSessionFactory.getInstance(userName, password);
sendClient(commandId + " OK Authenticated");
state = State.AUTHENTICATED;
@ -135,8 +137,8 @@ public class ImapConnection extends AbstractConnection {
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
currentFolder = session.getFolder(folderName);
messages = session.getAllMessages(currentFolder.folderUrl);
sendClient("* " + currentFolder.objectCount + " EXISTS");
sendClient("* " + currentFolder.objectCount + " RECENT");
sendClient("* " + messages.size() + " EXISTS");
sendClient("* " + messages.size() + " RECENT");
sendClient("* OK [UIDVALIDITY 1]");
if (messages.size() == 0) {
sendClient("* OK [UIDNEXT " + 1 + "]");
@ -186,42 +188,14 @@ public class ImapConnection extends AbstractConnection {
if (currentFolder == null) {
sendClient(commandId + " NO no folder selected");
} else {
RangeIterator rangeIterator = new RangeIterator(tokens.nextToken());
UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken());
String parameters = null;
if (tokens.hasMoreTokens()) {
parameters = tokens.nextToken();
}
while (rangeIterator.hasNext()) {
ExchangeSession.Message message = rangeIterator.next();
if (parameters == null || "FLAGS".equals(parameters)) {
sendClient("* " + (rangeIterator.currentIndex) + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))");
} else if ("BODYSTRUCTURE".equals(parameters)) {
sendClient("* " + (rangeIterator.currentIndex) + " FETCH (BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"windows-1252\") NIL NIL \"QUOTED-PRINTABLE\" " + message.size + " 50 NIL NIL NIL NIL))");
// send full message
} else if (parameters.indexOf("BODY[]") >= 0) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.write(baos);
baos.close();
DavGatewayTray.debug("Message size: " + message.size + " actual size:" + baos.size() + " message+headers: " + (message.size + baos.size()));
sendClient("* " + (rangeIterator.currentIndex) + " FETCH (UID " + message.getUidAsLong() + " RFC822.SIZE " + baos.size() + " BODY[]<0>" +
" {" + baos.size() + "}");
os.write(baos.toByteArray());
os.flush();
sendClient(")");
} else {
// write headers to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HeaderOutputStream headerOutputStream = new HeaderOutputStream(baos);
message.write(headerOutputStream);
baos.close();
sendClient("* " + (rangeIterator.currentIndex) + " FETCH (UID " + message.getUidAsLong() + " RFC822.SIZE " + headerOutputStream.size() + " BODY[HEADER.FIELDS ()" +
"] {" + baos.size() + "}");
os.write(baos.toByteArray());
os.flush();
sendClient(" FLAGS (" + (message.getImapFlags()) + "))");
}
while (uidRangeIterator.hasNext()) {
ExchangeSession.Message message = uidRangeIterator.next();
handleFetch(message, uidRangeIterator.currentIndex, parameters);
}
sendClient(commandId + " OK UID FETCH completed");
}
@ -267,21 +241,21 @@ public class ImapConnection extends AbstractConnection {
sendClient(commandId + " OK SEARCH completed");
} else if ("store".equalsIgnoreCase(subcommand)) {
RangeIterator rangeIterator = new RangeIterator(tokens.nextToken());
UIDRangeIterator UIDRangeIterator = new UIDRangeIterator(tokens.nextToken());
String action = tokens.nextToken();
String flags = tokens.nextToken();
while (rangeIterator.hasNext()) {
ExchangeSession.Message message = rangeIterator.next();
while (UIDRangeIterator.hasNext()) {
ExchangeSession.Message message = UIDRangeIterator.next();
updateFlags(message, action, flags);
sendClient("* " + (rangeIterator.currentIndex) + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))");
sendClient("* " + (UIDRangeIterator.currentIndex) + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))");
}
sendClient(commandId + " OK STORE completed");
} else if ("copy".equalsIgnoreCase(subcommand)) {
try {
RangeIterator rangeIterator = new RangeIterator(tokens.nextToken());
UIDRangeIterator UIDRangeIterator = new UIDRangeIterator(tokens.nextToken());
String targetName = BASE64MailboxDecoder.decode(tokens.nextToken());
while (rangeIterator.hasNext()) {
ExchangeSession.Message message = rangeIterator.next();
while (UIDRangeIterator.hasNext()) {
ExchangeSession.Message message = UIDRangeIterator.next();
session.copyMessage(message.messageUrl, targetName);
}
sendClient(commandId + " OK copy completed");
@ -292,6 +266,23 @@ public class ImapConnection extends AbstractConnection {
} else {
sendClient(commandId + " BAD command unrecognized");
}
} else if ("fetch".equalsIgnoreCase(command)) {
if (currentFolder == null) {
sendClient(commandId + " NO no folder selected");
} else {
RangeIterator rangeIterator = new RangeIterator(tokens.nextToken());
String parameters = null;
if (tokens.hasMoreTokens()) {
parameters = tokens.nextToken();
}
while (rangeIterator.hasNext()) {
ExchangeSession.Message message = rangeIterator.next();
handleFetch(message, rangeIterator.currentIndex, parameters);
}
sendClient(commandId + " OK FETCH completed");
}
} else if ("append".equalsIgnoreCase(command)) {
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
String flags = tokens.nextToken();
@ -345,8 +336,8 @@ public class ImapConnection extends AbstractConnection {
if (currentFolder != null) {
currentFolder = session.getFolder(currentFolder.folderName);
messages = session.getAllMessages(currentFolder.folderUrl);
sendClient("* " + currentFolder.objectCount + " EXISTS");
sendClient("* " + currentFolder.objectCount + " RECENT");
sendClient("* " + messages.size() + " EXISTS");
sendClient("* " + messages.size() + " RECENT");
}
sendClient(commandId + " OK " + command + " completed");
} else if ("subscribe".equalsIgnoreCase(command) || "unsubscribe".equalsIgnoreCase(command)) {
@ -356,23 +347,23 @@ public class ImapConnection extends AbstractConnection {
String encodedFolderName = tokens.nextToken();
String folderName = BASE64MailboxDecoder.decode(encodedFolderName);
ExchangeSession.Folder folder = session.getFolder(folderName);
// must retrieve messages
ExchangeSession.MessageList localMessages = session.getAllMessages(folder.folderUrl);
String parameters = tokens.nextToken();
StringBuilder answer = new StringBuilder();
StringTokenizer parametersTokens = new StringTokenizer(parameters);
while (parametersTokens.hasMoreTokens()) {
String token = parametersTokens.nextToken();
if ("MESSAGES".equalsIgnoreCase(token)) {
answer.append("MESSAGES ").append(folder.objectCount).append(" ");
answer.append("MESSAGES ").append(localMessages.size()).append(" ");
}
if ("RECENT".equalsIgnoreCase(token)) {
answer.append("RECENT ").append(folder.objectCount).append(" ");
answer.append("RECENT ").append(localMessages.size()).append(" ");
}
if ("UIDNEXT".equalsIgnoreCase(token)) {
if (folder.objectCount == 0) {
answer.append("UIDNEXT 1 ");
} else {
// must retrieve messages
ExchangeSession.MessageList localMessages = session.getAllMessages(folder.folderUrl);
if (localMessages.size() == 0) {
answer.append("UIDNEXT 1 ");
} else {
@ -435,6 +426,37 @@ public class ImapConnection extends AbstractConnection {
DavGatewayTray.resetIcon();
}
private void handleFetch(ExchangeSession.Message message, int currentIndex, String parameters) throws IOException {
if (parameters == null || "FLAGS".equals(parameters) || "FLAGS UID".equals(parameters)) {
sendClient("* " + (currentIndex) + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))");
} else if ("BODYSTRUCTURE".equals(parameters)) {
sendClient("* " + (currentIndex) + " FETCH (UID " + message.getUidAsLong() + " BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"windows-1252\") NIL NIL \"QUOTED-PRINTABLE\" " + message.size + " 50 NIL NIL NIL NIL))");
// send full message
} else if (parameters.indexOf("BODY[]") >= 0 || parameters.indexOf("BODY.PEEK[]") >= 0 || "BODY.PEEK[TEXT]".equals(parameters)) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.write(baos);
baos.close();
DavGatewayTray.debug("Message size: " + message.size + " actual size:" + baos.size() + " message+headers: " + (message.size + baos.size()));
sendClient("* " + (currentIndex) + " FETCH (UID " + message.getUidAsLong() + " RFC822.SIZE " + baos.size() + " BODY[]<0>" +
" {" + baos.size() + "}");
os.write(baos.toByteArray());
os.flush();
sendClient(")");
} else {
// write headers to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
HeaderOutputStream headerOutputStream = new HeaderOutputStream(baos);
message.write(headerOutputStream);
baos.close();
sendClient("* " + (currentIndex) + " FETCH (UID " + message.getUidAsLong() + " RFC822.SIZE " + headerOutputStream.size() + " BODY[HEADER.FIELDS ()" +
"] {" + baos.size() + "}");
os.write(baos.toByteArray());
os.flush();
sendClient(" FLAGS (" + (message.getImapFlags()) + "))");
}
}
static final class SearchConditions {
Boolean flagged = null;
Boolean answered = null;
@ -688,14 +710,14 @@ public class ImapConnection extends AbstractConnection {
}
}
protected class RangeIterator implements Iterator<ExchangeSession.Message> {
protected class UIDRangeIterator implements Iterator<ExchangeSession.Message> {
String[] ranges;
int currentIndex = 0;
int currentRangeIndex = 0;
long startUid;
long endUid;
protected RangeIterator(String value) {
protected UIDRangeIterator(String value) {
ranges = value.split(",");
}
@ -741,6 +763,59 @@ public class ImapConnection extends AbstractConnection {
}
}
protected class RangeIterator implements Iterator<ExchangeSession.Message> {
String[] ranges;
int currentIndex = 0;
int currentRangeIndex = 0;
long startUid;
long endUid;
protected RangeIterator(String value) {
ranges = value.split(",");
}
protected long convertToLong(String value) {
if ("*".equals(value)) {
return Long.MAX_VALUE;
} else {
return Long.parseLong(value);
}
}
protected void skipToStartUid() {
if (currentRangeIndex < ranges.length) {
String currentRange = ranges[currentRangeIndex++];
int colonIndex = currentRange.indexOf(':');
if (colonIndex > 0) {
startUid = convertToLong(currentRange.substring(0, colonIndex));
endUid = convertToLong(currentRange.substring(colonIndex + 1));
} else {
startUid = endUid = convertToLong(currentRange);
}
while (currentIndex < messages.size() && (currentIndex + 1) < startUid) {
currentIndex++;
}
} else {
currentIndex = messages.size();
}
}
public boolean hasNext() {
if (currentIndex < messages.size() && (currentIndex + 1) > endUid) {
skipToStartUid();
}
return currentIndex < messages.size();
}
public ExchangeSession.Message next() {
return messages.get(currentIndex++);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
class IMAPTokenizer extends StringTokenizer {
public IMAPTokenizer(String value) {
super(value);