+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache Public Source License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
+
package org.ibex.mail.protocol;
import org.ibex.io.*;
+import org.ibex.crypto.*;
import org.ibex.jinetd.Listener;
import org.ibex.jinetd.Worker;
-import org.ibex.net.*;
import org.ibex.mail.*;
import org.ibex.util.*;
import org.ibex.mail.target.*;
public class IMAP {
public IMAP() { }
- public static final float version = (float)0.1;
+ public static final float version = (float)0.2;
// API Class //////////////////////////////////////////////////////////////////////////////
}
public static interface Server {
+ public void setClient(IMAP.Client client);
public String[] capability();
public Hashtable id(Hashtable clientId);
public void copy(Query q, String to);
- public void login(String u, String p);
public void logout();
public void unselect();
public void delete(String m);
public int unseen(String mailbox);
public int recent(String mailbox);
public int count(String mailbox);
+ public int count();
+ public int maxuid();
public int uidNext(String mailbox);
public int uidValidity(String mailbox);
public int[] search(Query q, boolean uid);
public void fetch(Query q, int spec, String[] headers, int start, int end, boolean uid);
public void lsub(String start, String ref);
public void list(String start, String ref);
- public static interface Authenticator { public abstract Mailbox authenticate(String user, String pass); }
public static class Exn extends MailException { public Exn(String s) { super(s); } }
public static class Bad extends Exn { public Bad(String s) { super(s); } }
public static class No extends Exn { public No(String s) { super(s); } }
Mailbox selected = null;
Mailbox root = null;
Mailbox selected() { if (selected == null) throw new Bad("no mailbox selected"); return selected; }
- final Server.Authenticator auth;
+ final Login auth;
final Client client;
- public MailboxWrapper(Server.Authenticator auth, Client c) { this.auth=auth; this.client=c;}
+ public MailboxWrapper(Login auth, Client c) { this.auth=auth; this.client=c;}
+ public void setClient(IMAP.Client client) { }
- private Mailbox mailbox(String name, boolean create) {
+ private Mailbox mailbox(String name, boolean create) { return mailbox(name, create, true); }
+ private Mailbox mailbox(String name, boolean create, boolean throwexn) {
if (name.equalsIgnoreCase("inbox")) return inbox;
Mailbox m = root;
for(StringTokenizer st = new StringTokenizer(name, sep + ""); st.hasMoreTokens();)
- if ((m = m.slash(st.nextToken(), create)) == null) throw new Server.No("no such mailbox " + name);
+ if ((m = m.slash(st.nextToken(), create)) == null) {
+ if (throwexn) throw new Server.No("no such mailbox " + name);
+ return null;
+ }
return m;
}
String[] children = (start.length() == 0 ? root : mailbox(start, false)).children();
for(int i=0; i<children.length; i++) {
String s = children[i], pre = ref, kid = start + (start.length() > 0 ? sep+"" : "") + s;
+ if (mailbox(kid, false) == null) continue;
boolean phantom = mailbox(kid, false).phantom();
while(true) {
if (pre.length() == 0) {
/* */ void copy(Query q, Mailbox to) {
for(Mailbox.Iterator it=selected().iterator(q);it.next();) to.add(it.cur(), it.flags() | Mailbox.Flag.RECENT); }
- public void login(String u, String p) {
- if ((root = auth.authenticate(u,p)) == null) throw new No("Login failed.");
- inbox = mailbox("INBOX", false); // FEATURE: ??
- }
public void unselect() { selected = null; }
public void delete(String m0) { delete(mailbox(m0,false)); }
public void delete(Mailbox m) { if (!m.equals(inbox)) m.destroy(false); else throw new Bad("can't delete inbox"); }
- public void create(String m) { mailbox(m, true); }
+ public void create(String m) { mailbox(m, true, false); }
public void append(String m,int f,Date a,String b) { try {
- mailbox(m,false).add(new Message(null,null,b,a),f|Mailbox.Flag.RECENT);
+ mailbox(m,false).add(Message.newMessage(new Stream(b)),f|Mailbox.Flag.RECENT);
} catch (Message.Malformed e) { throw new No(e.getMessage()); } }
public void check() { }
public void noop() { }
public void expunge(Mailbox.Iterator it) { client.expunge(it.uid()); it.delete(); }
public void subscribe(String mailbox) { }
public void unsubscribe(String mailbox) { }
+ public int maxuid() {
+ int ret = 0;
+ Mailbox mb = selected();
+ if (mb == null) return 0;
+ for(Mailbox.Iterator it = mb.iterator(); it.next(); ) ret = it.uid();
+ return ret;
+ }
public int unseen(String mailbox) { return mailbox(mailbox, false).count(Query.not(Query.seen())); }
public int recent(String mailbox) { return mailbox(mailbox, false).count(Query.recent()); }
public int count(String mailbox) { return mailbox(mailbox, false).count(Query.all()); }
+ public int count() { return selected().count(Query.all()); }
public int uidNext(String mailbox) { return mailbox(mailbox, false).uidNext(); }
public int uidValidity(String mailbox) { return mailbox(mailbox, false).uidValidity(); }
public void select(String mailbox, boolean examineOnly) {
private void doFlags(Query q, int flags, boolean uid, int style, boolean silent) {
for(Mailbox.Iterator it = selected().iterator(q);it.next();) {
boolean recent = it.recent();
+ try { throw new Exception("flags " + flags); } catch (Exception e) { Log.error(this, e); }
if (style == -1) it.removeFlags(flags);
else if (style == 0) it.setFlags(flags);
else if (style == 1) it.addFlags(flags);
it.recent(recent);
- // FIXME
- //if (!silent) client.fetch(it.num(), it.flags(), -1, null, it.uid());
+ if (!silent) client.fetch(it.num(), it.flags(), -1, null, it.uid());
}
}
public void rename(String from0, String to) {
Server api;
Parser parser = null;
Connection conn = null;
- public Listener() { }
+ Login auth;
+ public Listener(Login auth) { api = new IMAP.MailboxWrapper(this.auth = auth, this); }
Parser.Token token() { return parser.token(); }
void println(String s) { conn.println(s); }
void newline() { parser.newline(); }
- Query query() { return parser.query(); }
+ Query query(int max) { return parser.query(max, maxn(true)); }
+
+ public void login(String u, String p) {
+ Object ret;
+ if ((ret = auth.login(u,p,IMAP.class)) == null) throw new Server.No("Login failed.");
+ if (ret instanceof IMAP.Server) {
+ api = (IMAP.Server)ret;
+ api.setClient(this);
+ } else {
+ Account account = (Account)ret;
+ ((MailboxWrapper)api).root = root = account.getMailbox(IMAP.class);
+ Log.warn(this, "logged in, root="+root);
+ ((MailboxWrapper)api).inbox = inbox = root.slash("INBOX", false);
+ if (inbox == null) ((MailboxWrapper)api).inbox = inbox = root;
+ }
+ }
+
+ private int maxn(boolean uid) { return uid ? api.maxuid() : api.count(); }
+
public void handleRequest(Connection conn) {
this.conn = conn;
parser = new Parser(conn);
- api = new IMAP.MailboxWrapper(new Main.BogusAuthenticator(), this);
conn.setTimeout(30 * 60 * 1000);
println("* OK " + conn.vhost + " " + IMAP.class.getName() + " IMAP4rev1 [RFC3501] v" + version + " server ready");
for(String tag = null;; newline()) try {
if (command.equalsIgnoreCase("UID")) { uid = true; command = token().atom(); }
int commandKey = ((Integer)commands.get(command.toUpperCase())).intValue();
switch(commandKey) {
- case LOGIN: api.login(token().astring(), token().astring()); break;
+ case LOGIN: login(token().astring(), token().astring()); break;
case CAPABILITY: println("* CAPABILITY " + Printer.join(" ", api.capability())); break;
case AUTHENTICATE: throw new Server.No("AUTHENTICATE not supported");
case LOGOUT: api.logout(); println("* BYE"); conn.close(); return;
- case LIST: api.list(token().q(), token().q()); break;
+ case LIST: api.list(token().q(), token().astring()); break; /*astring is a hack for EUDORA*/
case LSUB: api.lsub(token().q(), token().q()); break;
case SUBSCRIBE: api.subscribe(token().astring()); break;
case UNSUBSCRIBE: api.unsubscribe(token().astring()); break;
case RENAME: api.rename(token().astring(), token().astring()); break;
- case COPY: selected(); api.copy(Query.set(uid, token().set()), token().astring()); break;
+ case COPY: selected(); api.copy(Query.set(uid, token().set(maxn(uid))), token().astring()); break;
case DELETE: api.delete(token().atom()); break;
case CHECK: selected(); api.check(); break;
case NOOP: api.noop(); break;
case EXPUNGE: selected(); api.expunge(); break;
case UNSELECT: selected(); api.unselect(); selected = false; break;
case CREATE: api.create(token().astring()); break;
- case FETCH: selected(); fetch(Query.set(lastuid=uid, token().set()),
+ case FETCH: selected(); fetch(Query.set(lastuid=uid, token().set(maxn(uid))),
lastfetch=token().lx(), 0, 0, 0, uid, 0); break;
- case SEARCH: selected(); println("* SEARCH " + Printer.join(api.search(query(), uid))); break;
+ case SEARCH: {
+ selected();
+ int[] result = api.search(query(maxn(uid)), uid);
+ /*if (result.length > 0)*/ println("* SEARCH " + Printer.join(result));
+ break;
+ }
case EXAMINE:
case SELECT: {
String mailbox = token().astring();
println("* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)");
println("* " + api.count(mailbox) + " EXISTS");
println("* " + api.recent(mailbox) + " RECENT");
+ println("* OK [UNSEEN " + api.unseen(mailbox) + "]");
println("* OK [UIDVALIDITY " + api.uidValidity(mailbox) + "] UIDs valid");
println("* OK [UIDNEXT " + api.uidNext(mailbox) + "]");
println("* OK [PERMANENTFLAGS (\\Seen \\Draft \\Answered \\Deleted)]");
break; }
case STORE: {
selected();
- Query q = uid ? Query.uid(token().set()) : Query.num(token().set());
+ Query q = uid ? Query.uid(token().set(maxn(uid))) : Query.num(token().set(maxn(uid)));
String s = token().atom().toUpperCase();
int flags = token().flags();
if (s.equals("FLAGS")) api.setFlags(q, flags, uid, false);
}
println(tag+" OK "+command+" Completed. " +
(commandKey == LOGIN ? ("[CAPABILITY "+Printer.join(" ", api.capability())+"]") : ""));
- } catch (Server.Bad b) { println(tag==null ? "* BAD Invalid tag":(tag + " Bad " + b.toString())); Log.warn(this,b);
- } catch (Server.No n) { println(tag==null?"* BAD Invalid tag":(tag+" No " + n.toString())); Log.warn(this,n); }
+ } catch (Server.Bad b) { println(tag==null ? "* BAD Invalid tag":(tag + " Bad " + b.toString()));
+ } catch (Server.No n) { println(tag==null?"* BAD Invalid tag":(tag+" No " + n.toString())); }
}
private Parser.Token[] lastfetch = null; // hack
* - emit a fetch reply for the parsed spec with respect to message m
*/
private void fetch(Object o, Parser.Token[] t, int num, int flags, int size, boolean uid, int muid) {
- Query q = o instanceof Query ? (Query)o : null;
- Message m = o instanceof Message ? (Message)o : null;
+ Query q = o == null ? null : o instanceof Query ? (Query)o : null;
+ Message m = o == null ? null : o instanceof Message ? (Message)o : null;
boolean e = q == null;
lastfetch = t;
String[] headers = null;
int start = -1, end = -1;
StringBuffer r = new StringBuffer();
- if (e) { r.append(uid ? muid : num); r.append(" FETCH ("); }
+ if (e) { r.append(num); r.append(" FETCH ("); }
int initlen = r.length();
if (uid) {
boolean good = false;
} else if (s.equals("INTERNALDATE")) { spec|=INTERNALDATE; if(e){r.append(" ");r.append(Printer.date(m.arrival));}
} else if (s.equals("RFC822")) { spec|=RFC822; if(e){r.append(" ");r.append(Printer.message(m));}
} else if (s.equals("RFC822.TEXT")) { spec|=RFC822TEXT; if(e){r.append(" ");r.append(Printer.qq(m.body));}
- } else if (s.equals("RFC822.HEADER")){ spec|=HEADER;if(e){r.append(" ");r.append(Printer.qq(m.allHeaders+"\r\n"));}
+ } else if (s.equals("RFC822.HEADER")){ spec|=HEADER;if(e){r.append(" ");r.append(Printer.qq(m.headers.raw+"\r\n"));}
} else if (s.equals("RFC822.SIZE")) { spec|=RFC822SIZE; if(e){r.append(" ");r.append(m.size());}
} else if (s.equals("UID")) { spec|=UID; if(e){r.append(" ");r.append(muid); }
} else if (!(s.equals("BODY.PEEK") || s.equals("BODY"))) { throw new Server.No("unknown fetch argument: " + s);
Parser.Token[] list = t[++i].l();
s = list.length == 0 ? "" : list[0].s.toUpperCase();
r.append(s);
- if (list.length == 0) { spec |= RFC822TEXT; if(e) payload = m.allHeaders+"\r\n"+m.body; }
- else if (s.equals("")) { spec |= RFC822TEXT; if(e) payload = m.allHeaders+"\r\n"+m.body; }
+ if (list.length == 0) { spec |= RFC822TEXT; if(e) payload = m.headers.raw+"\r\n"+m.body; }
+ else if (s.equals("") || s.equals("1")) { spec |= RFC822TEXT; if(e) payload = m.headers.raw+"\r\n"+m.body; }
else if (s.equals("TEXT")) { spec |= RFC822TEXT; if(e) payload = m.body; }
- else if (s.equals("HEADER")) { spec |= HEADER; if(e) payload = m.allHeaders+"\r\n"; }
+ else if (s.equals("HEADER")) { spec |= HEADER; if(e) payload = m.headers.raw+"\r\n"; }
else if (s.equals("HEADER.FIELDS")) { spec |= FIELDS; payload=headers(r,t[i].l()[1].sl(),false,m,e); }
else if (s.equals("HEADER.FIELDS.NOT")) { spec |= FIELDSNOT; payload=headers(r,t[i].l()[1].sl(),true,m,e); }
else if (s.equals("MIME")) { throw new Server.Bad("MIME not supported"); }
if (!negate) {
if(e) for(int j=0; j<headers.length; j++) {
r.append(headers[j] + (j<headers.length-1?" ":""));
- if (m.headers.get(headers[j]) != null) payload += headers[j]+": "+m.headers.get(headers[j])+"\r\n";
+ if (m.headers.gets(headers[j]) != null) payload += headers[j]+": "+m.headers.gets(headers[j])+"\r\n";
}
} else {
throw new Server.No("HEADERS.NOT temporarily disaled");
if(e) { OUTER: for(Enumeration x=m.headers.keys(); x.hasMoreElements();) {
String key = (String)x.nextElement();
for(int j=0; j<headers.length; j++) if (key.equalsIgnoreCase(headers[j])) continue OUTER;
- payload += key + ": " + m.headers.get(key)+"\r\n";
+ payload += key + ": " + m.headers.gets(key)+"\r\n";
} }
*/
}
private Stream stream;
public Parser(Stream from) { this.stream = from; }
public Token token(String s) { return new Token(s); }
- protected Query query() {
+ protected Query query(int max, int maxuid) {
String s = null;
boolean not = false;
Query q = null;
+ Query ret = null;
while(true) {
Parser.Token t = token(false);
if (t == null) break;
if (t.type == t.LIST) throw new Server.No("nested queries not yet supported FIXME");
- else if (t.type == t.SET) return Query.num(t.set());
+ else if (t.type == t.SET) return Query.num(t.set(max));
s = t.atom().toUpperCase();
- if (s.equals("NOT")) { not = true; continue; }
- if (s.equals("OR")) return Query.or(query(), query()); // FIXME parse rest of list
- if (s.equals("AND")) return Query.and(query(), query());
+ if (s.equals("NOT")) return Query.not(query(max, maxuid));
+ if (s.equals("OR")) return Query.or(query(max, maxuid), query(max, maxuid)); // FIXME parse rest of list
+ if (s.equals("AND")) return Query.and(query(max, maxuid), query(max, maxuid));
+
+ if (s.startsWith("UN")) { not = true; s = s.substring(2); }
+ if (s.equals("ANSWERED")) q = Query.answered();
+ else if (s.equals("DELETED")) q = Query.deleted();
+ else if (s.equals("ALL")) q = Query.all();
+ else if (s.equals("DRAFT")) q = Query.draft();
+ else if (s.equals("FLAGGED")) q = Query.flagged();
+ else if (s.equals("RECENT")) q = Query.recent();
+ else if (s.equals("SEEN")) q = Query.seen();
+ else if (s.equals("OLD")) { not = true; q = Query.recent(); }
+ else if (s.equals("NEW")) q = Query.and(Query.recent(), Query.not(Query.seen()));
+ else if (s.equals("KEYWORD")) q = Query.header("keyword", token().flag());
+ else if (s.equals("HEADER")) q = Query.header(token().astring(), token().astring());
+ else if (s.equals("BCC")) q = Query.header("bcc", token().astring());
+ else if (s.equals("CC")) q = Query.header("cc", token().astring());
+ else if (s.equals("FROM")) q = Query.header("from", token().astring());
+ else if (s.equals("TO")) q = Query.header("to", token().astring());
+ else if (s.equals("SUBJECT")) q = Query.header("subject", token().astring());
+ else if (s.equals("LARGER")) q = Query.size(token().n(), Integer.MAX_VALUE);
+ else if (s.equals("SMALLER")) q = Query.size(Integer.MIN_VALUE, token().n());
+ else if (s.equals("BODY")) q = Query.body(token().astring());
+ else if (s.equals("TEXT")) q = Query.full(token().astring());
+ else if (s.equals("BEFORE")) q = Query.arrival(new Date(0), token().date());
+ else if (s.equals("SINCE")) q = Query.arrival(token().date(), new Date(Long.MAX_VALUE));
+ else if (s.equals("ON")) { Date d = token().date(); q = Query.arrival(d, new Date(d.getTime() + 24 * 60 * 60)); }
+ else if (s.equals("SENTBEFORE")) q = Query.sent(new Date(0), token().date());
+ else if (s.equals("SENTSINCE")) q = Query.sent(token().date(), new Date(Long.MAX_VALUE));
+ else if (s.equals("SENTON")) { Date d = token().date(); q = Query.sent(d, new Date(d.getTime() + 24 * 60 * 60)); }
+ else if (s.equals("UID")) q = Query.uid(token().set(max));
+ q = not ? Query.not(q) : q;
+ ret = ret == null ? q : Query.and(ret, q);
}
- if (s.startsWith("UN")) { not = true; s = s.substring(2); }
- if (s.equals("ANSWERED")) q = Query.answered();
- else if (s.equals("DELETED")) q = Query.deleted();
- else if (s.equals("ALL")) q = Query.all();
- else if (s.equals("DRAFT")) q = Query.draft();
- else if (s.equals("FLAGGED")) q = Query.flagged();
- else if (s.equals("RECENT")) q = Query.recent();
- else if (s.equals("SEEN")) q = Query.seen();
- else if (s.equals("OLD")) { not = true; q = Query.recent(); }
- else if (s.equals("NEW")) q = Query.and(Query.recent(), Query.not(Query.seen()));
- else if (s.equals("KEYWORD")) q = Query.header("keyword", token().flag());
- else if (s.equals("HEADER")) q = Query.header(token().astring(), token().astring());
- else if (s.equals("BCC")) q = Query.header("bcc", token().astring());
- else if (s.equals("CC")) q = Query.header("cc", token().astring());
- else if (s.equals("FROM")) q = Query.header("from", token().astring());
- else if (s.equals("TO")) q = Query.header("to", token().astring());
- else if (s.equals("SUBJECT")) q = Query.header("subject", token().astring());
- else if (s.equals("LARGER")) q = Query.size(token().n(), Integer.MAX_VALUE);
- else if (s.equals("SMALLER")) q = Query.size(Integer.MIN_VALUE, token().n());
- else if (s.equals("BODY")) q = Query.body(token().astring());
- else if (s.equals("TEXT")) q = Query.full(token().astring());
- else if (s.equals("BEFORE")) q = Query.arrival(new Date(0), token().date());
- else if (s.equals("SINCE")) q = Query.arrival(token().date(), new Date(Long.MAX_VALUE));
- else if (s.equals("ON")) { Date d = token().date(); q = Query.arrival(d, new Date(d.getTime() + 24 * 60 * 60)); }
- else if (s.equals("SENTBEFORE")) q = Query.sent(new Date(0), token().date());
- else if (s.equals("SENTSINCE")) q = Query.sent(token().date(), new Date(Long.MAX_VALUE));
- else if (s.equals("SENTON")) { Date d = token().date(); q = Query.sent(d, new Date(d.getTime() + 24 * 60 * 60)); }
- else if (s.equals("UID")) q = Query.uid(token().set());
- return q;
+ return ret;
}
private static void bad(String s) { throw new Server.Bad(s); }
public Token() { this.s = null; n = 0; l = null; type = NIL; }
public Token(String s) { this(s, false); }
public Token(String s, boolean quoted) { this.s = s; n = 0; l = null; type = quoted ? QUOTED : ATOM; }
- public Token(Parser.Token[] list) { this.s = null; n = 0; l = list; type = LIST; }
+ public Token(Parser.Token[] list) { this.s = null; n = 0; l = list; type = LIST; }
public Token(int number) { this.s = null; n = number; l = null; type = NUMBER; }
public String flag() { if (type != ATOM) bad("expected a flag"); return s; }
}
return ret;
}
- public int[] set() {
+ public int[] set(int largest) {
if (type != ATOM) bad("expected a messageid set");
Vec.Int ids = new Vec.Int();
StringTokenizer st = new StringTokenizer(s, ",");
while(st.hasMoreTokens()) {
String s = st.nextToken();
if (s.indexOf(':') == -1) {
- if (s.equals("*")) {
- ids.addElement(0);
- ids.addElement(Integer.MAX_VALUE);
- } else {
- ids.addElement(Integer.parseInt(s));
- ids.addElement(Integer.parseInt(s));
- }
- continue; }
+ if (s.equals("*")) {
+ ids.addElement(largest);
+ ids.addElement(largest);
+ } else {
+ ids.addElement(Integer.parseInt(s));
+ ids.addElement(Integer.parseInt(s));
+ }
+ continue; }
int start = Integer.parseInt(s.substring(0, s.indexOf(':')));
String end_s = s.substring(s.indexOf(':')+1);
- if (end_s.equals("*")) { ids.addElement(start); ids.addElement(Integer.MAX_VALUE); }
- else {
- int end = Integer.parseInt(end_s);
- for(int j=Math.min(start,end); j<=Math.max(start,end); j++) {
- ids.addElement(j);
- ids.addElement(j);
- }
+ int end = end_s.equals("*") ? largest : Integer.parseInt(end_s);
+ for(int j=Math.min(start,end); j<=Math.max(start,end); j++) {
+ ids.addElement(j);
+ ids.addElement(j);
}
}
return ids.dump();
public static String addressList(Object a) {
if (a == null) return "NIL";
if (a instanceof Address) return "("+address((Address)a)+")";
+ if (a instanceof String) return "("+address(Address.parse((String)a))+")";
Address[] aa = (Address[])a;
StringBuffer ret = new StringBuffer();
ret.append("(");
return "(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" "+m.size()+" "+m.lines+")";
}
static String message(Message m) { return m.toString(); }
- static String date(Date d) { return d.toString(); }
+ static String date(Date d) { return "\""+d.toString()+"\""; }
static String envelope(Message m) {
return
"(" + quotify(m.arrival.toString()) +
" " + quotify(m.subject) +
" " + addressList(m.from) +
- " " + addressList(m.headers.get("sender")) +
+ " " + addressList(m.headers.gets("sender")) +
" " + addressList(m.replyto) +
" " + addressList(m.to) +
" " + addressList(m.cc) +
" " + addressList(m.bcc) +
- " " + quotify((String)m.headers.get("in-reply-to")) +
+ " " + quotify((String)m.headers.gets("in-reply-to")) +
" " + quotify(m.messageid) +
")";
}
public static String qq(String s) {
StringBuffer ret = new StringBuffer();
ret.append('{');
- ret.append(s.length());
+ ret.append(s.getBytes().length);
ret.append('}');
ret.append('\r');
ret.append('\n');
// Main //////////////////////////////////////////////////////////////////////////////
- /** simple listener for testing purposes */
- public static void main(String[] args) throws Exception {
- ServerSocket ss = new ServerSocket(143);
- for(;;) {
- final Socket s = ss.accept();
- new Thread() { public void run() { try {
- final Mailbox root = FileBasedMailbox.getFileBasedMailbox(Mailbox.STORAGE_ROOT+File.separatorChar+"imap", true);
- new Listener();
- } catch (Exception e) { e.printStackTrace(); } } }.start();
- }
- }
-
public static final int
PEEK=0x1, BODYSTRUCTURE=0x2, ENVELOPE=0x4, FLAGS=0x8, INTERNALDATE=0x10, FIELDS=0x800, FIELDSNOT=0x1000,
RFC822=0x20, RFC822TEXT=0x40, RFC822SIZE=0x80, HEADERNOT=0x100, UID=0x200, HEADER=0x400;
+
}