2006-12-12 18:57:24 -05:00
|
|
|
package davmail.imap;
|
|
|
|
|
2009-01-29 17:18:53 -05:00
|
|
|
import com.sun.mail.imap.protocol.BASE64MailboxDecoder;
|
|
|
|
import com.sun.mail.imap.protocol.BASE64MailboxEncoder;
|
2006-12-12 18:57:24 -05:00
|
|
|
import davmail.AbstractConnection;
|
|
|
|
import davmail.exchange.ExchangeSession;
|
2008-10-31 13:12:30 -04:00
|
|
|
import davmail.exchange.ExchangeSessionFactory;
|
2009-01-29 17:18:53 -05:00
|
|
|
import davmail.tray.DavGatewayTray;
|
2009-01-26 18:51:08 -05:00
|
|
|
import org.apache.commons.httpclient.HttpException;
|
2006-12-12 18:57:24 -05:00
|
|
|
|
2009-01-29 17:18:53 -05:00
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
import java.io.FilterOutputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.net.Socket;
|
|
|
|
import java.net.SocketTimeoutException;
|
2009-02-03 12:56:38 -05:00
|
|
|
import java.net.SocketException;
|
2009-02-04 16:55:42 -05:00
|
|
|
import java.util.*;
|
2009-02-05 12:15:30 -05:00
|
|
|
import java.text.SimpleDateFormat;
|
2009-02-17 17:59:32 -05:00
|
|
|
import java.text.ParseException;
|
2009-01-29 17:18:53 -05:00
|
|
|
|
2006-12-12 18:57:24 -05:00
|
|
|
/**
|
|
|
|
* Dav Gateway smtp connection implementation.
|
|
|
|
* Still alpha code : need to find a way to handle message ids
|
|
|
|
*/
|
|
|
|
public class ImapConnection extends AbstractConnection {
|
|
|
|
|
2009-01-22 19:59:41 -05:00
|
|
|
ExchangeSession.Folder currentFolder;
|
2009-02-02 02:19:57 -05:00
|
|
|
ExchangeSession.MessageList messages;
|
2009-01-22 19:59:41 -05:00
|
|
|
|
2006-12-12 18:57:24 -05:00
|
|
|
// Initialize the streams and start the thread
|
2006-12-14 10:14:18 -05:00
|
|
|
public ImapConnection(Socket clientSocket) {
|
2008-11-29 09:24:12 -05:00
|
|
|
super("ImapConnection", clientSocket, null);
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
String line;
|
2009-02-03 12:56:38 -05:00
|
|
|
String commandId = null;
|
2006-12-12 18:57:24 -05:00
|
|
|
StringTokenizer tokens;
|
|
|
|
try {
|
2009-02-04 15:38:07 -05:00
|
|
|
ExchangeSessionFactory.checkConfig();
|
2009-01-22 19:59:41 -05:00
|
|
|
sendClient("* OK [CAPABILITY IMAP4REV1 AUTH=LOGIN] IMAP4rev1 DavMail server ready");
|
2006-12-12 18:57:24 -05:00
|
|
|
for (; ;) {
|
|
|
|
line = readClient();
|
|
|
|
// unable to read line, connection closed ?
|
|
|
|
if (line == null) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-02-17 17:59:32 -05:00
|
|
|
tokens = new IMAPTokenizer(line);
|
2006-12-12 18:57:24 -05:00
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-02-03 12:56:38 -05:00
|
|
|
commandId = tokens.nextToken();
|
2006-12-12 18:57:24 -05:00
|
|
|
if (tokens.hasMoreTokens()) {
|
|
|
|
String command = tokens.nextToken();
|
|
|
|
|
|
|
|
if ("LOGOUT".equalsIgnoreCase(command)) {
|
|
|
|
sendClient("* BYE Closing connection");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ("capability".equalsIgnoreCase(command)) {
|
2009-01-22 19:59:41 -05:00
|
|
|
sendClient("* CAPABILITY IMAP4REV1 AUTH=LOGIN");
|
2006-12-12 18:57:24 -05:00
|
|
|
sendClient(commandId + " OK CAPABILITY completed");
|
|
|
|
} else if ("login".equalsIgnoreCase(command)) {
|
|
|
|
parseCredentials(tokens);
|
|
|
|
try {
|
2008-10-31 13:12:30 -04:00
|
|
|
session = ExchangeSessionFactory.getInstance(userName, password);
|
2006-12-12 18:57:24 -05:00
|
|
|
sendClient(commandId + " OK Authenticated");
|
2009-01-29 17:18:53 -05:00
|
|
|
state = State.AUTHENTICATED;
|
2006-12-12 18:57:24 -05:00
|
|
|
} catch (Exception e) {
|
2008-11-24 07:35:58 -05:00
|
|
|
DavGatewayTray.error(e);
|
2006-12-12 18:57:24 -05:00
|
|
|
sendClient(commandId + " NO LOGIN failed");
|
2009-01-29 17:18:53 -05:00
|
|
|
state = State.INITIAL;
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
2009-01-22 19:59:41 -05:00
|
|
|
} else if ("AUTHENTICATE".equalsIgnoreCase(command)) {
|
|
|
|
if (tokens.hasMoreTokens()) {
|
|
|
|
String authenticationMethod = tokens.nextToken();
|
|
|
|
if ("LOGIN".equalsIgnoreCase(authenticationMethod)) {
|
|
|
|
try {
|
2009-02-20 12:06:03 -05:00
|
|
|
sendClient("+ " + base64Encode("Username:"));
|
|
|
|
state = State.LOGIN;
|
|
|
|
userName = base64Decode(readClient());
|
|
|
|
sendClient("+ " + base64Encode("Password:"));
|
|
|
|
state = State.PASSWORD;
|
|
|
|
password = base64Decode(readClient());
|
2009-01-22 19:59:41 -05:00
|
|
|
session = ExchangeSessionFactory.getInstance(userName, password);
|
|
|
|
sendClient(commandId + " OK Authenticated");
|
2009-01-29 17:18:53 -05:00
|
|
|
state = State.AUTHENTICATED;
|
2009-01-22 19:59:41 -05:00
|
|
|
} catch (Exception e) {
|
|
|
|
DavGatewayTray.error(e);
|
|
|
|
sendClient(commandId + " NO LOGIN failed");
|
2009-01-29 17:18:53 -05:00
|
|
|
state = State.INITIAL;
|
2009-01-22 19:59:41 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendClient(commandId + " NO unsupported authentication method");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD authentication method required");
|
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
} else {
|
2009-01-29 17:18:53 -05:00
|
|
|
if (state != State.AUTHENTICATED) {
|
2006-12-12 18:57:24 -05:00
|
|
|
sendClient(commandId + " BAD command authentication required");
|
|
|
|
} else {
|
2009-01-23 05:30:48 -05:00
|
|
|
if ("lsub".equalsIgnoreCase(command) || "list".equalsIgnoreCase(command)) {
|
2006-12-12 18:57:24 -05:00
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-01-29 17:18:53 -05:00
|
|
|
String folderContext = BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-01-22 19:59:41 -05:00
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-01-29 17:18:53 -05:00
|
|
|
String folderQuery = folderContext + BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-01-23 05:30:48 -05:00
|
|
|
if (folderQuery.endsWith("%/%")) {
|
|
|
|
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);
|
2009-01-22 19:59:41 -05:00
|
|
|
for (ExchangeSession.Folder folder : folders) {
|
2009-01-23 05:30:48 -05:00
|
|
|
sendClient("* " + command + " (" + folder.getFlags() + ") \"/\" \"" + BASE64MailboxEncoder.encode(folder.folderUrl) + "\"");
|
2009-01-22 19:59:41 -05:00
|
|
|
}
|
2009-01-23 05:30:48 -05:00
|
|
|
sendClient(commandId + " OK " + command + " completed");
|
2009-01-22 19:59:41 -05:00
|
|
|
} else {
|
|
|
|
ExchangeSession.Folder folder = session.getFolder(folderQuery);
|
|
|
|
if (folder != null) {
|
2009-01-23 05:30:48 -05:00
|
|
|
sendClient("* " + command + " (" + folder.getFlags() + ") \"/\" \"" + BASE64MailboxEncoder.encode(folder.folderUrl) + "\"");
|
|
|
|
sendClient(commandId + " OK " + command + " completed");
|
2009-01-22 19:59:41 -05:00
|
|
|
} else {
|
|
|
|
sendClient(commandId + " NO Folder not found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD missing folder argument");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD missing folder argument");
|
|
|
|
}
|
|
|
|
} else if ("select".equalsIgnoreCase(command) || "examine".equalsIgnoreCase(command)) {
|
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-01-29 17:18:53 -05:00
|
|
|
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-01-22 19:59:41 -05:00
|
|
|
currentFolder = session.getFolder(folderName);
|
|
|
|
messages = session.getAllMessages(currentFolder.folderUrl);
|
2009-02-20 12:06:03 -05:00
|
|
|
sendClient("* " + messages.size() + " EXISTS");
|
|
|
|
sendClient("* " + messages.size() + " RECENT");
|
2009-02-02 02:19:57 -05:00
|
|
|
sendClient("* OK [UIDVALIDITY 1]");
|
|
|
|
if (messages.size() == 0) {
|
2009-02-02 15:46:15 -05:00
|
|
|
sendClient("* OK [UIDNEXT " + 1 + "]");
|
2009-02-02 02:19:57 -05:00
|
|
|
} else {
|
2009-02-02 15:46:15 -05:00
|
|
|
sendClient("* OK [UIDNEXT " + (messages.get(messages.size() - 1).getUidAsLong() + 1) + "]");
|
2009-02-02 02:19:57 -05:00
|
|
|
}
|
2009-02-04 19:18:29 -05:00
|
|
|
sendClient("* FLAGS (\\Answered \\Deleted \\Draft \\Flagged \\Seen $Forwarded Junk)");
|
|
|
|
sendClient("* OK [PERMANENTFLAGS (\\Answered \\Deleted \\Draft \\Flagged \\Seen $Forwarded Junk \\*)]");
|
2009-01-22 19:59:41 -05:00
|
|
|
sendClient(commandId + " OK [READ-WRITE] " + command + " completed");
|
2006-12-12 18:57:24 -05:00
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD command unrecognized");
|
|
|
|
}
|
2009-02-04 18:06:30 -05:00
|
|
|
} else if ("close".equalsIgnoreCase(command) || "expunge".equalsIgnoreCase(command)) {
|
|
|
|
expunge();
|
2009-01-22 19:59:41 -05:00
|
|
|
currentFolder = null;
|
|
|
|
messages = null;
|
2009-02-05 12:50:15 -05:00
|
|
|
sendClient(commandId + " OK " + command + " completed");
|
2009-01-22 19:59:41 -05:00
|
|
|
} else if ("create".equalsIgnoreCase(command)) {
|
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-01-29 17:18:53 -05:00
|
|
|
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-01-23 08:01:46 -05:00
|
|
|
session.createFolder(folderName);
|
|
|
|
sendClient(commandId + " OK folder created");
|
2009-01-22 19:59:41 -05:00
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD missing create argument");
|
|
|
|
}
|
2009-01-26 18:51:08 -05:00
|
|
|
} else if ("rename".equalsIgnoreCase(command)) {
|
2009-01-29 17:18:53 -05:00
|
|
|
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
|
|
|
String targetName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-01-26 18:51:08 -05:00
|
|
|
try {
|
|
|
|
session.moveFolder(folderName, targetName);
|
|
|
|
sendClient(commandId + " OK rename completed");
|
|
|
|
} catch (HttpException e) {
|
|
|
|
sendClient(commandId + " NO " + e.getReason());
|
|
|
|
}
|
2009-02-02 18:29:44 -05:00
|
|
|
} else if ("delete".equalsIgnoreCase(command)) {
|
|
|
|
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
|
|
|
try {
|
|
|
|
session.deleteFolder(folderName);
|
|
|
|
sendClient(commandId + " OK delete completed");
|
|
|
|
} catch (HttpException e) {
|
|
|
|
sendClient(commandId + " NO " + e.getReason());
|
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
} else if ("uid".equalsIgnoreCase(command)) {
|
2009-01-23 06:20:20 -05:00
|
|
|
if (tokens.hasMoreTokens()) {
|
|
|
|
String subcommand = tokens.nextToken();
|
|
|
|
if ("fetch".equalsIgnoreCase(subcommand)) {
|
2009-02-04 17:17:34 -05:00
|
|
|
if (currentFolder == null) {
|
|
|
|
sendClient(commandId + " NO no folder selected");
|
|
|
|
} else {
|
2009-02-20 12:06:03 -05:00
|
|
|
UIDRangeIterator uidRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
2009-02-04 17:17:34 -05:00
|
|
|
String parameters = null;
|
|
|
|
if (tokens.hasMoreTokens()) {
|
|
|
|
parameters = tokens.nextToken();
|
2009-01-23 05:30:48 -05:00
|
|
|
}
|
2009-02-20 12:06:03 -05:00
|
|
|
while (uidRangeIterator.hasNext()) {
|
|
|
|
ExchangeSession.Message message = uidRangeIterator.next();
|
|
|
|
handleFetch(message, uidRangeIterator.currentIndex, parameters);
|
2009-01-23 05:30:48 -05:00
|
|
|
}
|
2009-02-04 17:17:34 -05:00
|
|
|
sendClient(commandId + " OK UID FETCH completed");
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
2009-02-04 17:17:34 -05:00
|
|
|
|
2009-01-23 06:20:20 -05:00
|
|
|
} else if ("search".equalsIgnoreCase(subcommand)) {
|
2009-02-17 19:09:42 -05:00
|
|
|
SearchConditions conditions = new SearchConditions();
|
2009-02-17 19:58:20 -05:00
|
|
|
conditions.append("AND (");
|
2009-02-17 17:59:32 -05:00
|
|
|
boolean undeleted = true;
|
2009-02-17 19:58:20 -05:00
|
|
|
boolean or = false;
|
2009-02-17 17:59:32 -05:00
|
|
|
|
2009-01-23 06:20:20 -05:00
|
|
|
while (tokens.hasMoreTokens()) {
|
2009-02-17 17:59:32 -05:00
|
|
|
String token = tokens.nextToken();
|
|
|
|
if ("UNDELETED".equals(token)) {
|
|
|
|
undeleted = true;
|
2009-02-17 19:58:20 -05:00
|
|
|
} else if ("OR".equals(token)) {
|
|
|
|
or = true;
|
2009-02-17 17:59:32 -05:00
|
|
|
} else if (token.startsWith("OR ")) {
|
2009-02-17 19:58:20 -05:00
|
|
|
or = true;
|
2009-02-23 05:06:12 -05:00
|
|
|
appendOrSearchParams(token, conditions);
|
2009-02-17 17:59:32 -05:00
|
|
|
} else {
|
2009-02-17 19:58:20 -05:00
|
|
|
String operator;
|
|
|
|
if (conditions.query.length() == 5) {
|
|
|
|
operator = "";
|
|
|
|
} else if (or) {
|
|
|
|
operator = " OR ";
|
|
|
|
} else {
|
|
|
|
operator = " AND ";
|
|
|
|
}
|
|
|
|
appendSearchParam(operator, tokens, token, conditions);
|
2009-02-17 17:59:32 -05:00
|
|
|
}
|
2009-01-23 06:20:20 -05:00
|
|
|
}
|
2009-02-17 19:58:20 -05:00
|
|
|
conditions.append(")");
|
2009-02-17 19:09:42 -05:00
|
|
|
DavGatewayTray.debug("Search: " + conditions.query);
|
2009-02-23 05:06:12 -05:00
|
|
|
ExchangeSession.MessageList localMessages = session.searchMessages(currentFolder.folderName, conditions.query.toString());
|
|
|
|
for (ExchangeSession.Message message : localMessages) {
|
2009-02-17 19:09:42 -05:00
|
|
|
if (((undeleted && !message.deleted) || !undeleted)
|
|
|
|
&& (conditions.flagged == null || message.flagged == conditions.flagged)
|
|
|
|
&& (conditions.answered == null || message.answered == conditions.answered)
|
|
|
|
) {
|
2009-02-17 17:59:32 -05:00
|
|
|
sendClient("* SEARCH " + message.getUidAsLong());
|
2009-01-23 06:20:20 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
sendClient(commandId + " OK SEARCH completed");
|
|
|
|
|
|
|
|
} else if ("store".equalsIgnoreCase(subcommand)) {
|
2009-02-20 12:06:03 -05:00
|
|
|
UIDRangeIterator UIDRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
2009-01-26 18:51:08 -05:00
|
|
|
String action = tokens.nextToken();
|
|
|
|
String flags = tokens.nextToken();
|
2009-02-20 12:06:03 -05:00
|
|
|
while (UIDRangeIterator.hasNext()) {
|
|
|
|
ExchangeSession.Message message = UIDRangeIterator.next();
|
2009-02-04 16:55:42 -05:00
|
|
|
updateFlags(message, action, flags);
|
2009-02-20 12:06:03 -05:00
|
|
|
sendClient("* " + (UIDRangeIterator.currentIndex) + " FETCH (UID " + message.getUidAsLong() + " FLAGS (" + (message.getImapFlags()) + "))");
|
2009-02-02 15:46:15 -05:00
|
|
|
}
|
2009-01-23 08:01:46 -05:00
|
|
|
sendClient(commandId + " OK STORE completed");
|
2009-02-02 18:29:44 -05:00
|
|
|
} else if ("copy".equalsIgnoreCase(subcommand)) {
|
|
|
|
try {
|
2009-02-20 12:06:03 -05:00
|
|
|
UIDRangeIterator UIDRangeIterator = new UIDRangeIterator(tokens.nextToken());
|
2009-02-03 11:18:29 -05:00
|
|
|
String targetName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-02-20 12:06:03 -05:00
|
|
|
while (UIDRangeIterator.hasNext()) {
|
|
|
|
ExchangeSession.Message message = UIDRangeIterator.next();
|
2009-02-03 11:18:29 -05:00
|
|
|
session.copyMessage(message.messageUrl, targetName);
|
|
|
|
}
|
2009-02-04 16:55:42 -05:00
|
|
|
sendClient(commandId + " OK copy completed");
|
|
|
|
} catch (HttpException e) {
|
|
|
|
sendClient(commandId + " NO " + e.getReason());
|
2009-02-02 18:29:44 -05:00
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD command unrecognized");
|
|
|
|
}
|
2009-02-20 12:06:03 -05:00
|
|
|
} 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");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-23 05:50:46 -05:00
|
|
|
} else if ("append".equalsIgnoreCase(command)) {
|
2009-01-29 17:18:53 -05:00
|
|
|
String folderName = BASE64MailboxDecoder.decode(tokens.nextToken());
|
2009-02-03 12:56:38 -05:00
|
|
|
String flags = tokens.nextToken();
|
2009-02-03 18:54:48 -05:00
|
|
|
HashMap<String, String> properties = new HashMap<String, String>();
|
|
|
|
StringTokenizer flagtokenizer = new StringTokenizer(flags);
|
|
|
|
while (flagtokenizer.hasMoreTokens()) {
|
|
|
|
String flag = flagtokenizer.nextToken();
|
|
|
|
if ("\\Seen".equals(flag)) {
|
|
|
|
properties.put("read", "1");
|
|
|
|
} else if ("\\Flagged".equals(flag)) {
|
|
|
|
properties.put("flagged", "2");
|
|
|
|
} else if ("\\Answered".equals(flag)) {
|
2009-02-04 19:18:29 -05:00
|
|
|
properties.put("answered", "102");
|
|
|
|
} else if ("$Forwarded".equals(flag)) {
|
|
|
|
properties.put("forwarded", "104");
|
2009-02-03 18:54:48 -05:00
|
|
|
} else if ("\\Draft".equals(flag)) {
|
|
|
|
properties.put("draft", "9");
|
|
|
|
} else if ("Junk".equals(flag)) {
|
|
|
|
properties.put("junk", "1");
|
|
|
|
}
|
|
|
|
}
|
2009-02-05 12:15:30 -05:00
|
|
|
// handle optional date
|
2009-02-03 12:56:38 -05:00
|
|
|
String dateOrSize = tokens.nextToken();
|
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-02-05 12:15:30 -05:00
|
|
|
SimpleDateFormat dateParser = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.ENGLISH);
|
|
|
|
Date dateReceived = dateParser.parse(dateOrSize);
|
|
|
|
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
|
|
|
dateFormatter.setTimeZone(ExchangeSession.GMT_TIMEZONE);
|
|
|
|
|
|
|
|
properties.put("datereceived", dateFormatter.format(dateReceived));
|
2009-02-03 12:56:38 -05:00
|
|
|
dateOrSize = tokens.nextToken();
|
|
|
|
}
|
|
|
|
int size = Integer.parseInt(dateOrSize);
|
2009-01-23 05:50:46 -05:00
|
|
|
sendClient("+ send literal data");
|
|
|
|
char[] buffer = new char[size];
|
2009-01-23 08:01:46 -05:00
|
|
|
int index = 0;
|
|
|
|
int count = 0;
|
|
|
|
while (count >= 0 && index < size) {
|
|
|
|
count = in.read(buffer, index, size - index);
|
|
|
|
if (count >= 0) {
|
|
|
|
index += count;
|
|
|
|
}
|
|
|
|
}
|
2009-01-23 05:50:46 -05:00
|
|
|
// empty line
|
|
|
|
readClient();
|
2009-02-03 09:38:05 -05:00
|
|
|
|
2009-02-03 11:58:18 -05:00
|
|
|
String messageName = UUID.randomUUID().toString();
|
2009-02-05 11:06:34 -05:00
|
|
|
session.createMessage(session.getFolderPath(folderName), messageName, properties, new String(buffer));
|
2009-01-23 05:50:46 -05:00
|
|
|
sendClient(commandId + " OK APPEND completed");
|
2009-02-02 02:19:57 -05:00
|
|
|
} else if ("noop".equalsIgnoreCase(command) || "check".equalsIgnoreCase(command)) {
|
2009-01-23 06:20:20 -05:00
|
|
|
if (currentFolder != null) {
|
|
|
|
currentFolder = session.getFolder(currentFolder.folderName);
|
2009-02-02 02:19:57 -05:00
|
|
|
messages = session.getAllMessages(currentFolder.folderUrl);
|
2009-02-20 12:06:03 -05:00
|
|
|
sendClient("* " + messages.size() + " EXISTS");
|
|
|
|
sendClient("* " + messages.size() + " RECENT");
|
2009-01-23 06:20:20 -05:00
|
|
|
}
|
2009-02-02 02:19:57 -05:00
|
|
|
sendClient(commandId + " OK " + command + " completed");
|
2009-02-05 11:06:34 -05:00
|
|
|
} else if ("subscribe".equalsIgnoreCase(command) || "unsubscribe".equalsIgnoreCase(command)) {
|
|
|
|
sendClient(commandId + " OK " + command + " completed");
|
2009-02-05 12:50:15 -05:00
|
|
|
} else if ("status".equalsIgnoreCase(command)) {
|
|
|
|
try {
|
|
|
|
String encodedFolderName = tokens.nextToken();
|
|
|
|
String folderName = BASE64MailboxDecoder.decode(encodedFolderName);
|
|
|
|
ExchangeSession.Folder folder = session.getFolder(folderName);
|
2009-02-20 12:06:03 -05:00
|
|
|
// must retrieve messages
|
|
|
|
ExchangeSession.MessageList localMessages = session.getAllMessages(folder.folderUrl);
|
2009-02-05 12:50:15 -05:00
|
|
|
String parameters = tokens.nextToken();
|
|
|
|
StringBuilder answer = new StringBuilder();
|
|
|
|
StringTokenizer parametersTokens = new StringTokenizer(parameters);
|
|
|
|
while (parametersTokens.hasMoreTokens()) {
|
|
|
|
String token = parametersTokens.nextToken();
|
|
|
|
if ("MESSAGES".equalsIgnoreCase(token)) {
|
2009-02-20 12:06:03 -05:00
|
|
|
answer.append("MESSAGES ").append(localMessages.size()).append(" ");
|
2009-02-05 12:50:15 -05:00
|
|
|
}
|
|
|
|
if ("RECENT".equalsIgnoreCase(token)) {
|
2009-02-20 12:06:03 -05:00
|
|
|
answer.append("RECENT ").append(localMessages.size()).append(" ");
|
2009-02-05 12:50:15 -05:00
|
|
|
}
|
|
|
|
if ("UIDNEXT".equalsIgnoreCase(token)) {
|
|
|
|
if (folder.objectCount == 0) {
|
|
|
|
answer.append("UIDNEXT 1 ");
|
|
|
|
} else {
|
|
|
|
if (localMessages.size() == 0) {
|
|
|
|
answer.append("UIDNEXT 1 ");
|
|
|
|
} else {
|
|
|
|
answer.append("UIDNEXT ").append((localMessages.get(localMessages.size() - 1).getUidAsLong() + 1)).append(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if ("UIDVALIDITY".equalsIgnoreCase(token)) {
|
|
|
|
answer.append("UIDVALIDITY 1 ");
|
|
|
|
}
|
|
|
|
if ("UNSEEN".equalsIgnoreCase(token)) {
|
|
|
|
answer.append("UNSEEN ").append(folder.unreadCount).append(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sendClient("* STATUS " + encodedFolderName + " (" + answer.toString().trim() + ")");
|
|
|
|
sendClient(commandId + " OK " + command + " completed");
|
|
|
|
} catch (HttpException e) {
|
|
|
|
sendClient(commandId + " NO folder not found");
|
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD command unrecognized");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
sendClient(commandId + " BAD missing command");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendClient("BAD Null command");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
os.flush();
|
2009-01-22 19:59:41 -05:00
|
|
|
} catch (SocketTimeoutException e) {
|
|
|
|
DavGatewayTray.debug("Closing connection on timeout");
|
|
|
|
try {
|
|
|
|
sendClient("* BYE Closing connection");
|
|
|
|
} catch (IOException e1) {
|
|
|
|
DavGatewayTray.debug("Exception closing connection on timeout");
|
|
|
|
}
|
2009-02-03 12:56:38 -05:00
|
|
|
} catch (SocketException e) {
|
|
|
|
DavGatewayTray.debug("Connection closed");
|
|
|
|
} catch (Exception e) {
|
|
|
|
try {
|
|
|
|
if (commandId != null) {
|
|
|
|
sendClient(commandId + " BAD unable to handle request: " + e.getMessage());
|
|
|
|
} else {
|
2009-02-04 15:38:07 -05:00
|
|
|
sendClient("* BYE unable to handle request: " + e.getMessage());
|
2009-02-03 12:56:38 -05:00
|
|
|
}
|
|
|
|
} catch (IOException e2) {
|
|
|
|
DavGatewayTray.warn("Exception sending error to client", e2);
|
|
|
|
}
|
2008-10-31 13:12:30 -04:00
|
|
|
DavGatewayTray.error("Exception handling client", e);
|
2006-12-12 18:57:24 -05:00
|
|
|
} finally {
|
2007-05-15 05:37:55 -04:00
|
|
|
close();
|
2006-12-12 18:57:24 -05:00
|
|
|
}
|
|
|
|
DavGatewayTray.resetIcon();
|
|
|
|
}
|
|
|
|
|
2009-02-20 12:06:03 -05:00
|
|
|
private void handleFetch(ExchangeSession.Message message, int currentIndex, String parameters) throws IOException {
|
2009-02-23 12:42:49 -05:00
|
|
|
StringBuilder buffer = new StringBuilder();
|
|
|
|
buffer.append("* " + (currentIndex) + " FETCH (UID " + message.getUidAsLong());
|
2009-02-20 12:06:03 -05:00
|
|
|
|
2009-02-23 12:42:49 -05:00
|
|
|
StringTokenizer paramTokens = new StringTokenizer(parameters);
|
|
|
|
while (paramTokens.hasMoreTokens()) {
|
|
|
|
String param = paramTokens.nextToken();
|
|
|
|
if ("FLAGS".equals(param)) {
|
|
|
|
buffer.append(" FLAGS (" + (message.getImapFlags()) + ")");
|
|
|
|
} else if ("BODYSTRUCTURE".equals(param)) {
|
|
|
|
buffer.append(" BODYSTRUCTURE (\"TEXT\" \"PLAIN\" (\"CHARSET\" \"windows-1252\") NIL NIL \"QUOTED-PRINTABLE\" " + message.size + " 50 NIL NIL NIL NIL))");
|
|
|
|
} else if ("INTERNALDATE".equals(param)) {
|
|
|
|
try {
|
|
|
|
SimpleDateFormat dateParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
|
|
|
dateParser.setTimeZone(ExchangeSession.GMT_TIMEZONE);
|
|
|
|
Date date = null;
|
|
|
|
date = dateParser.parse(message.date);
|
|
|
|
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.ENGLISH);
|
|
|
|
buffer.append(" INTERNALDATE \"" + dateFormatter.format(date) + "\"");
|
|
|
|
} catch (ParseException e) {
|
|
|
|
throw new IOException("Invalid date: " + message.date);
|
|
|
|
}
|
|
|
|
} else if ("BODY[]".equals(param) || "BODY.PEEK[]".equals(param)) {
|
|
|
|
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()));
|
|
|
|
buffer.append(" RFC822.SIZE " + baos.size() + " " + param + "<0> {" + (baos.size()-4) + "}");
|
|
|
|
sendClient(buffer.toString());
|
|
|
|
os.write(baos.toByteArray(), 0, baos.toByteArray().length-4);
|
|
|
|
os.flush();
|
|
|
|
buffer.setLength(0);
|
|
|
|
} else if ("BODY.PEEK[HEADER]".equals(param) || param.startsWith("BODY.PEEK[HEADER")) {
|
|
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
|
HeaderOutputStream headerOutputStream = new HeaderOutputStream(baos);
|
|
|
|
message.write(headerOutputStream);
|
|
|
|
baos.close();
|
|
|
|
buffer.append(" RFC822.SIZE " + baos.size() + " BODY[HEADER.FIELDS ()] {" + baos.size() + "}");
|
|
|
|
sendClient(buffer.toString());
|
|
|
|
os.write(baos.toByteArray());
|
|
|
|
os.flush();
|
|
|
|
buffer.setLength(0);
|
|
|
|
}
|
2009-02-20 12:06:03 -05:00
|
|
|
}
|
2009-02-23 12:42:49 -05:00
|
|
|
buffer.append(")");
|
|
|
|
sendClient(buffer.toString());
|
2009-02-20 12:06:03 -05:00
|
|
|
}
|
|
|
|
|
2009-02-17 19:09:42 -05:00
|
|
|
static final class SearchConditions {
|
|
|
|
Boolean flagged = null;
|
|
|
|
Boolean answered = null;
|
|
|
|
StringBuilder query = new StringBuilder();
|
|
|
|
|
|
|
|
public StringBuilder append(String value) {
|
|
|
|
return query.append(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-23 05:06:12 -05:00
|
|
|
protected void appendOrSearchParams(String token, SearchConditions conditions) throws IOException {
|
2009-02-17 19:58:20 -05:00
|
|
|
IMAPTokenizer innerTokens = new IMAPTokenizer(token);
|
|
|
|
innerTokens.nextToken();
|
|
|
|
boolean first = true;
|
|
|
|
while (innerTokens.hasMoreTokens()) {
|
|
|
|
String innerToken = innerTokens.nextToken();
|
|
|
|
String operator = "";
|
|
|
|
if (!first) {
|
|
|
|
operator = " OR ";
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
appendSearchParam(operator, innerTokens, innerToken, conditions);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-02-17 19:09:42 -05:00
|
|
|
protected void appendSearchParam(String operator, StringTokenizer tokens, String token, SearchConditions conditions) throws IOException {
|
2009-02-17 17:59:32 -05:00
|
|
|
if ("NOT".equals(token)) {
|
2009-02-17 19:09:42 -05:00
|
|
|
conditions.append(operator).append(" NOT ");
|
|
|
|
appendSearchParam("", tokens, tokens.nextToken(), conditions);
|
2009-02-17 19:58:20 -05:00
|
|
|
} else if (token.startsWith("OR ")) {
|
2009-02-23 05:06:12 -05:00
|
|
|
appendOrSearchParams(token, conditions);
|
2009-02-17 17:59:32 -05:00
|
|
|
} else if ("SUBJECT".equals(token)) {
|
2009-02-17 19:09:42 -05:00
|
|
|
conditions.append(operator).append("\"urn:schemas:httpmail:subject\" LIKE '%").append(tokens.nextToken()).append("%'");
|
2009-02-17 17:59:32 -05:00
|
|
|
} else if ("BODY".equals(token)) {
|
2009-02-17 19:09:42 -05:00
|
|
|
conditions.append(operator).append("\"http://schemas.microsoft.com/mapi/proptag/x01000001E\" LIKE '%").append(tokens.nextToken()).append("%'");
|
2009-02-17 17:59:32 -05:00
|
|
|
} else if ("FROM".equals(token)) {
|
2009-02-17 19:09:42 -05:00
|
|
|
conditions.append(operator).append("\"urn:schemas:mailheader:from\" LIKE '%").append(tokens.nextToken()).append("%'");
|
2009-02-17 19:58:20 -05:00
|
|
|
} else if ("TO".equals(token)) {
|
|
|
|
conditions.append(operator).append("\"urn:schemas:mailheader:to\" LIKE '%").append(tokens.nextToken()).append("%'");
|
|
|
|
} else if ("CC".equals(token)) {
|
|
|
|
conditions.append(operator).append("\"urn:schemas:mailheader:cc\" LIKE '%").append(tokens.nextToken()).append("%'");
|
|
|
|
} else if ("LARGER".equals(token)) {
|
|
|
|
conditions.append(operator).append("\"http://schemas.microsoft.com/mapi/proptag/x0e080003\" >= ").append(Long.parseLong(tokens.nextToken())).append("");
|
|
|
|
} else if ("SMALLER".equals(token)) {
|
|
|
|
conditions.append(operator).append("\"http://schemas.microsoft.com/mapi/proptag/x0e080003\" < ").append(Long.parseLong(tokens.nextToken())).append("");
|
2009-02-17 19:09:42 -05:00
|
|
|
} else if (token.startsWith("SENT")) {
|
|
|
|
conditions.append(operator);
|
|
|
|
appendDateSearchParam(tokens, token, conditions);
|
|
|
|
} else if ("SEEN".equals(token)) {
|
|
|
|
conditions.append(operator).append("\"urn:schemas:httpmail:read\" = True");
|
|
|
|
} else if ("UNSEEN".equals(token) || "NEW".equals(token)) {
|
|
|
|
conditions.append(operator).append("\"urn:schemas:httpmail:read\" = False");
|
|
|
|
} else if ("FLAGGED".equals(token)) {
|
|
|
|
conditions.flagged = Boolean.TRUE;
|
|
|
|
} else if ("UNFLAGGED".equals(token) || "NEW".equals(token)) {
|
|
|
|
conditions.flagged = Boolean.FALSE;
|
|
|
|
} else if ("ANSWERED".equals(token)) {
|
|
|
|
conditions.answered = Boolean.TRUE;
|
|
|
|
} else if ("UNANSWERED".equals(token)) {
|
|
|
|
conditions.answered = Boolean.FALSE;
|
2009-02-17 17:59:32 -05:00
|
|
|
} else if ("HEADER".equals(token)) {
|
2009-02-17 19:58:20 -05:00
|
|
|
String headerName = tokens.nextToken().toLowerCase();
|
2009-02-23 05:06:12 -05:00
|
|
|
conditions.append(operator).append("\"urn:schemas:mailheader:").append(headerName).append("\"='").append(tokens.nextToken()).append("'");
|
|
|
|
} else if ("UID".equals(token)) {
|
|
|
|
String range = tokens.nextToken();
|
|
|
|
if ("1:*".equals(range)) {
|
|
|
|
// ignore: this is a noop filter
|
|
|
|
} else {
|
|
|
|
throw new IOException("Invalid search parameters");
|
|
|
|
}
|
2009-02-17 19:09:42 -05:00
|
|
|
} else if ("OLD".equals(token)) {
|
|
|
|
// ignore
|
2009-02-17 17:59:32 -05:00
|
|
|
} else {
|
|
|
|
throw new IOException("Invalid search parameters");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-17 19:09:42 -05:00
|
|
|
protected void appendDateSearchParam(StringTokenizer tokens, String token, SearchConditions conditions) throws IOException {
|
|
|
|
Date startDate;
|
|
|
|
Date endDate;
|
|
|
|
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 {
|
|
|
|
startDate = parser.parse(tokens.nextToken());
|
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
|
calendar.setTime(startDate);
|
|
|
|
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
|
|
|
endDate = calendar.getTime();
|
|
|
|
} catch (ParseException e) {
|
|
|
|
throw new IOException("Invalid search parameters");
|
|
|
|
}
|
|
|
|
if ("SENTON".equals(token)) {
|
|
|
|
conditions.append("(\"urn:schemas:httpmail:date\" > '")
|
|
|
|
.append(dateFormatter.format(startDate))
|
|
|
|
.append("' AND \"urn:schemas:httpmail:date\" < '")
|
|
|
|
.append(dateFormatter.format(endDate))
|
|
|
|
.append("')");
|
|
|
|
} else if ("SENTBEFORE".equals(token)) {
|
|
|
|
conditions.append("\"urn:schemas:httpmail:date\" < '")
|
|
|
|
.append(dateFormatter.format(startDate))
|
|
|
|
.append("'");
|
|
|
|
} else if ("SENTSINCE".equals(token)) {
|
|
|
|
conditions.append("\"urn:schemas:httpmail:date\" >= '")
|
|
|
|
.append(dateFormatter.format(startDate))
|
|
|
|
.append("'");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2009-02-02 18:29:44 -05:00
|
|
|
protected void expunge() throws IOException {
|
|
|
|
if (messages != null) {
|
|
|
|
int index = 0;
|
|
|
|
for (ExchangeSession.Message message : messages) {
|
|
|
|
index++;
|
|
|
|
if (message.deleted) {
|
2009-02-03 16:02:33 -05:00
|
|
|
message.delete();
|
2009-02-03 09:38:05 -05:00
|
|
|
sendClient("* " + index + " EXPUNGE");
|
2009-02-02 18:29:44 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-03 18:54:48 -05:00
|
|
|
protected void updateFlags(ExchangeSession.Message message, String action, String flags) throws IOException {
|
|
|
|
HashMap<String, String> properties = new HashMap<String, String>();
|
2009-02-23 05:06:12 -05:00
|
|
|
if ("-Flags".equalsIgnoreCase(action) || "-FLAGS.SILENT".equalsIgnoreCase(action)) {
|
2009-02-03 18:54:48 -05:00
|
|
|
StringTokenizer flagtokenizer = new StringTokenizer(flags);
|
|
|
|
while (flagtokenizer.hasMoreTokens()) {
|
|
|
|
String flag = flagtokenizer.nextToken();
|
|
|
|
if ("\\Seen".equals(flag)) {
|
|
|
|
properties.put("read", "0");
|
|
|
|
message.read = false;
|
|
|
|
} else if ("\\Flagged".equals(flag)) {
|
|
|
|
properties.put("flagged", "0");
|
|
|
|
message.flagged = false;
|
|
|
|
} else if ("Junk".equals(flag)) {
|
|
|
|
properties.put("junk", "0");
|
|
|
|
message.junk = false;
|
|
|
|
}
|
|
|
|
}
|
2009-02-23 05:06:12 -05:00
|
|
|
} else if ("+Flags".equalsIgnoreCase(action) || "+FLAGS.SILENT".equalsIgnoreCase(action)) {
|
2009-02-03 18:54:48 -05:00
|
|
|
StringTokenizer flagtokenizer = new StringTokenizer(flags);
|
|
|
|
while (flagtokenizer.hasMoreTokens()) {
|
|
|
|
String flag = flagtokenizer.nextToken();
|
|
|
|
if ("\\Seen".equals(flag)) {
|
|
|
|
properties.put("read", "1");
|
|
|
|
message.read = true;
|
|
|
|
} else if ("\\Deleted".equals(flag)) {
|
|
|
|
message.deleted = true;
|
2009-02-04 18:06:30 -05:00
|
|
|
properties.put("deleted", "1");
|
2009-02-03 18:54:48 -05:00
|
|
|
} else if ("\\Flagged".equals(flag)) {
|
|
|
|
properties.put("flagged", "2");
|
|
|
|
message.flagged = true;
|
|
|
|
} else if ("\\Answered".equals(flag)) {
|
2009-02-04 19:18:29 -05:00
|
|
|
properties.put("answered", "102");
|
2009-02-03 18:54:48 -05:00
|
|
|
message.answered = true;
|
2009-02-04 19:18:29 -05:00
|
|
|
} else if ("$Forwarded".equals(flag)) {
|
|
|
|
properties.put("forwarded", "104");
|
|
|
|
message.forwarded = true;
|
2009-02-03 18:54:48 -05:00
|
|
|
} else if ("Junk".equals(flag)) {
|
|
|
|
properties.put("junk", "1");
|
|
|
|
message.junk = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (properties.size() > 0) {
|
|
|
|
session.updateMessage(message, properties);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-12 18:57:24 -05:00
|
|
|
/**
|
2009-01-09 17:41:10 -05:00
|
|
|
* Decode IMAP credentials
|
2009-01-22 19:59:41 -05:00
|
|
|
*
|
2009-01-09 17:41:10 -05:00
|
|
|
* @param tokens tokens
|
|
|
|
* @throws java.io.IOException on error
|
2006-12-12 18:57:24 -05:00
|
|
|
*/
|
|
|
|
protected void parseCredentials(StringTokenizer tokens) throws IOException {
|
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-01-29 17:18:53 -05:00
|
|
|
userName = tokens.nextToken();
|
2006-12-12 18:57:24 -05:00
|
|
|
} else {
|
|
|
|
throw new IOException("Invalid credentials");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tokens.hasMoreTokens()) {
|
2009-01-29 17:18:53 -05:00
|
|
|
password = tokens.nextToken();
|
2006-12-12 18:57:24 -05:00
|
|
|
} else {
|
|
|
|
throw new IOException("Invalid credentials");
|
|
|
|
}
|
|
|
|
int backslashindex = userName.indexOf("\\");
|
|
|
|
if (backslashindex > 0) {
|
|
|
|
userName = userName.substring(0, backslashindex) + userName.substring(backslashindex + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected String removeQuotes(String value) {
|
|
|
|
String result = value;
|
2009-01-26 18:51:08 -05:00
|
|
|
if (result.startsWith("\"") || result.startsWith("{") || result.startsWith("(")) {
|
2006-12-12 18:57:24 -05:00
|
|
|
result = result.substring(1);
|
|
|
|
}
|
2009-01-26 18:51:08 -05:00
|
|
|
if (result.endsWith("\"") || result.endsWith("}") || result.endsWith(")")) {
|
2006-12-12 18:57:24 -05:00
|
|
|
result = result.substring(0, result.length() - 1);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-01-26 18:51:08 -05:00
|
|
|
/**
|
|
|
|
* Filter to limit output lines to max body lines after header
|
|
|
|
*/
|
|
|
|
private static class HeaderOutputStream extends FilterOutputStream {
|
|
|
|
protected static final int START = 0;
|
|
|
|
protected static final int CR = 1;
|
|
|
|
protected static final int CRLF = 2;
|
|
|
|
protected static final int CRLFCR = 3;
|
|
|
|
protected static final int BODY = 4;
|
|
|
|
|
|
|
|
protected int state = START;
|
|
|
|
protected int size = 0;
|
|
|
|
|
|
|
|
public HeaderOutputStream(OutputStream os) {
|
|
|
|
super(os);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int size() {
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void write(int b) throws IOException {
|
|
|
|
size++;
|
|
|
|
if (state != BODY) {
|
|
|
|
super.write(b);
|
|
|
|
}
|
|
|
|
if (state == START) {
|
|
|
|
if (b == '\r') {
|
|
|
|
state = CR;
|
|
|
|
}
|
|
|
|
} else if (state == CR) {
|
|
|
|
if (b == '\n') {
|
|
|
|
state = CRLF;
|
|
|
|
} else {
|
|
|
|
state = START;
|
|
|
|
}
|
|
|
|
} else if (state == CRLF) {
|
|
|
|
if (b == '\r') {
|
|
|
|
state = CRLFCR;
|
|
|
|
} else {
|
|
|
|
state = START;
|
|
|
|
}
|
|
|
|
} else if (state == CRLFCR) {
|
|
|
|
if (b == '\n') {
|
|
|
|
state = BODY;
|
|
|
|
} else {
|
|
|
|
state = START;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-20 12:06:03 -05:00
|
|
|
protected class UIDRangeIterator implements Iterator<ExchangeSession.Message> {
|
2009-02-04 16:55:42 -05:00
|
|
|
String[] ranges;
|
|
|
|
int currentIndex = 0;
|
|
|
|
int currentRangeIndex = 0;
|
|
|
|
long startUid;
|
|
|
|
long endUid;
|
|
|
|
|
2009-02-20 12:06:03 -05:00
|
|
|
protected UIDRangeIterator(String value) {
|
2009-02-04 16:55:42 -05:00
|
|
|
ranges = value.split(",");
|
|
|
|
}
|
|
|
|
|
|
|
|
protected long convertToLong(String value) {
|
|
|
|
if ("*".equals(value)) {
|
|
|
|
return Long.MAX_VALUE;
|
|
|
|
} else {
|
|
|
|
return Long.parseLong(value);
|
|
|
|
}
|
|
|
|
}
|
2006-12-12 18:57:24 -05:00
|
|
|
|
2009-02-04 16:55:42 -05:00
|
|
|
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() && messages.get(currentIndex).getUidAsLong() < startUid) {
|
|
|
|
currentIndex++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
currentIndex = messages.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasNext() {
|
|
|
|
if (currentIndex < messages.size() && messages.get(currentIndex).getUidAsLong() > endUid) {
|
|
|
|
skipToStartUid();
|
|
|
|
}
|
|
|
|
return currentIndex < messages.size();
|
|
|
|
}
|
|
|
|
|
2009-02-20 12:06:03 -05:00
|
|
|
public ExchangeSession.Message next() {
|
|
|
|
return messages.get(currentIndex++);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void remove() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2009-02-04 16:55:42 -05:00
|
|
|
public ExchangeSession.Message next() {
|
|
|
|
return messages.get(currentIndex++);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void remove() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
}
|
2009-02-17 17:59:32 -05:00
|
|
|
|
|
|
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-04 16:55:42 -05:00
|
|
|
}
|