import java.text.*;
import java.io.*;
-// FIXME: tagged responses
-
+// FEATURE: hoist all the ok()'s?
// FEATURE: pipelining
// FEATURE: support [charset]
public class IMAP extends MessageProtocol {
new Thread() {
public void run() {
try {
- service(s);
+ new Listener(s, "megacz.com").handleRequest();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- public static class IMAPException extends MailException { public IMAPException(String s) { super(s); } }
- public static class No extends IMAPException { public No(String s) { super(s); } }
- public static class Bad extends IMAPException { public Bad(String s) { super(s); } }
-
- public static void service(Socket s) { /* FIXME */ }
+ public static class Exn extends MailException {
+ public Exn(String s) { super(s); }
+ public static class No extends Exn { public No(String s) { super(s); } }
+ public static class Bad extends Exn { public Bad(String s) { super(s); } }
+ }
private static class Listener extends Incoming {
- private InputStream is;
- private PushbackReader r;
-
- Socket conn;
- String vhost;
-
Mailbox selected = null;
Mailbox root = null;
+ Socket conn;
+ String vhost;
PrintWriter pw;
- LineReader lr;
-
+ InputStream is;
+ PushbackReader r;
public void init() { }
- public Listener(Socket conn, String vhost) { this.vhost = vhost; this.conn = conn; this.selected = null; }
+ public Listener(Socket conn, String vhost) throws IOException {
+ this.vhost = vhost;
+ this.conn = conn;
+ this.selected = null;
+ this.pw = new PrintWriter(new OutputStreamWriter(conn.getOutputStream()));
+ this.is = conn.getInputStream();
+ this.r = new PushbackReader(new InputStreamReader(is));
+ }
- private void ok(String s) { star("OK " + s); }
+ // ugly: not concurrent
+ String tag;
+ private void ok(String s) { pw.println(tag + " OK " + s); }
private void star(String s) { pw.println("* " + s); }
- private boolean auth(String user, String pass) { /* FEATURE */ return user.equals("megacz") && pass.equals(""); }
+
+ // FIXME should throw a No if mailbox not found and create==false
private Mailbox getMailbox(String name, boolean create) {
Mailbox m = root;
while(name.length() > 0) {
return m;
}
- // sharing problem? immutability helps
- public void copy(int[] set, Mailbox target) {
- for(int i=0; i<set.length; i++) target.add(selected.get(set[i]));
- }
-
+ public void lsub(Mailbox m, String s) { star("LIST () \".\" INBOX"); ok("LSUB completed"); } // FIXME
+ public void list(Mailbox m, String s) { star("LIST () \".\" INBOX"); ok("LIST completed"); } // FIXME
- public void login(String user, String password) { if (!auth(user, password)) throw new No("Liar, liar, pants on fire."); }
+ private boolean auth(String user, String pass) { /* FEATURE */ return user.equals("megacz") && pass.equals(""); }
+ public void copy(int[] set, Mailbox target) { for(int i=0; i<set.length; i++) target.add(selected.get(set[i])); }
+ public void login(String user, String password) {if (!auth(user,password))throw new Exn.No("Liar, liar, pants on fire."); }
public void capability() { star("CAPABILITY IMAP4rev1"); ok("Completed"); }
public void noop() { ok("Completed"); }
public void logout() { star("BYE LOGOUT received"); ok("Completed"); }
- public void delete(Mailbox m) { if (!m.getName().toLowerCase().equals("inbox")) m.destroy(); }
+ public void delete(Mailbox m) { if (!m.getName().toLowerCase().equals("inbox")) m.destroy(); ok("Completed"); }
public void subscribe(String[] args) { ok("SUBSCRIBE ignored"); }
public void unsubscribe(String[] args) { ok("UNSUBSCRIBE ignored"); }
- public void check(String[] args, boolean examineOnly) { ok("check complete"); }
- public void lsub(Mailbox m, String s) { list(m, s); }
- public void list(Mailbox m, String s) { star("LIST () \".\" INBOX"); ok("LIST completed"); } // FIXME
+ public void check() { ok("CHECK ignored"); }
public void create(String mailbox){if(!mailbox.endsWith(".")&&!mailbox.equalsIgnoreCase("inbox"))getMailbox(mailbox,true);}
public void rename(Mailbox from, String to) {
- if (from.getName().toLowerCase().equals("inbox")) from.moveAllMessagesTo(getMailbox(to, true));
- else if (to.toLowerCase().equals("inbox")) { from.moveAllMessagesTo(getMailbox(to, true)); from.destroy(); }
+ if (from.getName().equalsIgnoreCase("inbox")) from.moveAllMessagesTo(getMailbox(to, true));
+ else if (to.equalsIgnoreCase("inbox")) { from.moveAllMessagesTo(getMailbox(to, true)); from.destroy(); }
else from.rename(to);
}
public void status(Mailbox m, Token[] attrs) {
- boolean messages = false, recent = false, uidnext = false, uidvalidity = false, unseen = false;
- for(int i=0; i<attrs.length; i++) {
- String s = attrs[i].atom();
- if (s.equals("MESSAGES")) messages = true;
- if (s.equals("RECENT")) recent = true;
- if (s.equals("UIDNEXT")) uidnext = true;
- if (s.equals("UIDVALIDITY")) uidvalidity = true;
- if (s.equals("UNSEEN")) unseen = true;
- }
- int[] list = m.list(); int numRecent = 0, numUnseen = 0;
+ int[] list = m.list();
+ int recent = 0, unseen = 0;
for(int i=0; i<list.length; i++) {
Message message = m.get(list[i]);
- if (!message.seen) numUnseen++;
- if (message.recent) numRecent++;
+ if (!message.seen) unseen++;
+ if (message.recent) recent++;
}
- star("STATUS FIXME ( " +
- (messages ? ("MESSAGES " + list.length + " ") : "") +
- (recent ? ("RECENT " + numRecent + " ") : "") +
- (unseen ? ("UNSEEN " + numUnseen + " ") : "") +
- (uidvalidity ? ("UIDVALIDITY " + m.uidvalidity + " ") : "") +
- (uidnext ? ("UIDNEXT " + m.uidnext + " ") : "") + ")");
+ String response = "";
+ for(int i=0; i<attrs.length; i++) {
+ String s = attrs[i].atom();
+ if (s.equals("MESSAGES")) response += "MESSAGES " + list.length;
+ if (s.equals("RECENT")) response += "RECENT " + recent;
+ if (s.equals("UIDNEXT")) response += "UNSEEN " + unseen;
+ if (s.equals("UIDVALIDITY")) response += "UIDVALIDITY " + m.uidvalidity;
+ if (s.equals("UNSEEN")) response += "UIDNEXT " + m.uidnext;
+ }
+ star("STATUS " + m.getName() + " (" + response + ")");
}
- public void select(String[] args, boolean examineOnly) {
- if (args.length < 1) throw new Bad("Not enough arguments");
- selected = getMailbox(args[0], false);
- if (selected == null) throw new No("No such mailbox");
+ public void select(String mailbox, boolean examineOnly) {
+ selected = getMailbox(mailbox, false);
star(selected.list().length + " EXISTS");
- star("1 RECENT");
+ int recent = 0;
+ int[] list = selected.list(); for(int i=0; i<list.length; i++) if (selected.get(list[i]).recent) recent++;
+ star(recent + " RECENT");
//star("OK [UNSEEN 12] Message 12 is first unseen"); FEATURE
star("OK [UIDVALIDITY " + selected.uidvalidity + "] UIDs valid");
star("FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)");
- ok(/* FEATURE: READ-WRITE / READ-ONLY */ (examineOnly ? "EXAMINE" : "SELECT") + " completed");
+ // FEATURE: READ-WRITE / READ-ONLY
+ ok((examineOnly ? "EXAMINE" : "SELECT") + " completed");
}
- public void close(String[] args, boolean examineOnly) {
- if (selected == null) throw new Bad("no mailbox selected");
- expunge(new String[] { }, false, true);
+ public void close(boolean examineOnly) {
+ if (selected == null) throw new Exn.Bad("no mailbox selected");
+ expunge(false, true);
selected = null;
ok("CLOSE completed");
}
- public void expunge(String[] args, boolean examineOnly, boolean silent) {
- if (selected == null) throw new Bad("no mailbox selected");
+ public void expunge(boolean examineOnly, boolean silent) {
+ if (selected == null) throw new Exn.Bad("no mailbox selected");
int[] messages = selected.list();
for(int i=0; i<messages.length; i++) {
Message m = selected.get(messages[i]);
String literal = q();
try {
Message message = new Message(null, null, new LineReader(new StringReader(literal)));
- if (flags != null) setFlags(flags, message);
- //if (arrival != null) message.arrival = arrival; FIXME
+ if (flags != null) { /* FEATURE */ }
selected.add(message);
} catch (IOException e) {
- e.printStackTrace();
+ throw new MailException.IOException(e);
}
}
- public void setFlags(Token[] t, Message m) { /* FIXME */ }
-
- // FIXME set
public void fetch(int[] set, Token t) {
Token[] tl = null;
int start = -1, end = -1;
- boolean peek = false;
+ boolean peek = false, fast = false, all = false, full = false;
if (t.type == Token.LIST) tl = t.l();
- else if (t.atom().equals("FULL")) tl = (Token[]) parse("FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY");
- else if (t.atom().equals("ALL")) tl = (Token[]) parse("FLAGS INTERNALDATE RFC822.SIZE ENVELOPE");
- else if (t.atom().equals("FAST")) tl = (Token[]) parse("FLAGS INTERNALDATE RFC822.SIZE");
+ else if (t.atom().equals("FULL")) full = true;
+ else if (t.atom().equals("ALL")) all = true;
+ else if (t.atom().equals("FAST")) fast = true;
// FEATURE: range requests
StringBuffer reply = new StringBuffer();
- Message m = null; // FIXME
- for (int i=0; i<tl.length; i++) {
- String s = tl[i].atom();
- if (s.startsWith("BODY.PEEK")) { peek = true; s = "BODY" + s.substring(9); }
- if (s.startsWith("BODY.1")) s = "BODY" + s.substring(6);
- if (s.indexOf('<') != -1) {
- String range = s.substring(s.indexOf('<') + 1, s.indexOf('>'));
- s = s.substring(0, s.indexOf('<'));
- if (range.indexOf('.') == -1) end = Integer.MAX_VALUE;
- else {
- end = Integer.parseInt(range.substring(range.indexOf('.') + 1));
- range = range.substring(0, range.indexOf('.'));
+ for(int j=0; j<set.length; j++) {
+ Message m = selected.get(set[j]);
+ for (int i=0; i<tl.length; i++) {
+ String s = tl[i].atom();
+ if (s.startsWith("BODY.PEEK")) { peek = true; s = "BODY" + s.substring(9); }
+ if (s.startsWith("BODY.1")) s = "BODY" + s.substring(6);
+ if (s.indexOf('<') != -1) {
+ String range = s.substring(s.indexOf('<') + 1, s.indexOf('>'));
+ s = s.substring(0, s.indexOf('<'));
+ if (range.indexOf('.') == -1) end = Integer.MAX_VALUE;
+ else {
+ end = Integer.parseInt(range.substring(range.indexOf('.') + 1));
+ range = range.substring(0, range.indexOf('.'));
+ }
+ start = Integer.parseInt(range);
}
- start = Integer.parseInt(range);
+ if (s.equals("ENVELOPE") || all || full) reply.append("ENVELOPE " + envelope(m) + " ");
+ if (s.equals("FLAGS") || full || all || fast) reply.append("FLAGS (" + flags(m) + ") ");
+ if (s.equals("INTERNALDATE") || full || all || fast) reply.append("INTERNALDATE "+quotify(m.arrival)+" ");
+ if (s.equals("RFC822.SIZE") || full || all || fast) reply.append("RFC822.SIZE " + m.rfc822size() + " ");
+ if (s.equals("RFC822.HEADER") || s.equals("BODY[HEADER]"))
+ { reply.append("BODY[HEADER] {" + m.allHeaders.length() + "}\r\n"); reply.append(m.allHeaders); }
+ if (s.equals("RFC822")||s.equals("RFC822.TEXT")||s.equals("BODY")||s.equals("BODY[]")||s.equals("TEXT")||full)
+ { reply.append("BODY[TEXT] {" + m.body.length() + "}\r\n"); reply.append(m.body); }
+ if (s.equals("UID")) reply.append("UID " + m.uid);
+ if (s.equals("MIME")) throw new Exn.No("FETCH BODY.MIME not supported");
+ if (s.startsWith("BODY[HEADER.FIELDS")) throw new Exn.No("partial headers not supported");
+ if (s.startsWith("BODY[HEADER.FIELDS.NOT")) throw new Exn.No("partial headers not supported");
+ if (s.equals("BODYSTRUCTURE"))
+ reply.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" " +
+ m.rfc822size()+" "+ m.numLines() +")");
}
- if (s.equals("ENVELOPE")) reply.append("ENVELOPE " + envelope(m) + " ");
- else if (s.equals("FLAGS")) reply.append("FLAGS (" + flags(m) + ") ");
- else if (s.equals("INTERNALDATE")) reply.append("INTERNALDATE " + quotify(m.arrival) + " ");
- else if (s.equals("RFC822.SIZE")) reply.append("RFC822.SIZE " + m.rfc822size() + " ");
- else if (s.equals("RFC822.HEADER") || s.equals("BODY[HEADER]"))
- { reply.append("BODY[HEADER] {" + m.allHeaders.length() + "}\r\n"); reply.append(m.allHeaders); }
- else if (s.equals("RFC822")||s.equals("RFC822.TEXT")||s.equals("BODY") || s.equals("BODY[]") || s.equals("TEXT"))
- { reply.append("BODY[TEXT] {" + m.body.length() + "}\r\n"); reply.append(m.body); }
- else if (s.equals("UID")) reply.append("UID " + m.uid);
- else if (s.equals("MIME")) throw new No("FETCH BODY.MIME not supported");
- else if (s.startsWith("BODY[HEADER.FIELDS")) throw new No("partial headers not supported");
- else if (s.startsWith("BODY[HEADER.FIELDS.NOT")) throw new No("partial headers not supported");
- else if (s.equals("BODYSTRUCTURE"))
- reply.append("(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" " +
- m.rfc822size()+" "+ m.numLines() +")");
- else if (s.startsWith("BODY")) throw new No("FETCH BODY[*] not supported");
- else throw new Bad("unrecognized FETCH argument \"" + s + "\"");
+ star(m.messageNum + " FETCH (" + reply.toString() + ")");
+ // FEATURE set seen flag if not BODY.PEEK
}
- star(m.messageNum + " FETCH (" + reply.toString() + ")");
- // FEATURE set seen flag if not BODY.PEEK
}
public void store(int[] messages, String what, Token[] flags) {
}
}
- public boolean handleRequest(LineReader r, PrintWriter pw) throws IOException {
+ public boolean handleRequest() throws IOException {
+ LineReader lr = new LineReader(r);
pw.println("* OK " + vhost + " " + IMAP.class.getName() + " IMAP4 v0.1 server ready");
while(true) {
boolean uid = false;
- String s = r.readLine();
+ String s = lr.readLine();
if (s.indexOf(' ') == -1) { pw.println("* BAD Invalid tag"); continue; }
- String tag = atom();
+ tag = atom();
String command = atom();
if (command.equals("UID")) { uid = true; command = atom(); }
if (command.equals("AUTHENTICATE")) { login(astring(), astring()); }
else if (command.equals("LOGOUT")) { logout(); conn.close(); return false; }
else if (command.equals("RENAME")) rename(mailbox(), atom());
else if (command.equals("APPEND")) append(mailbox(), token());
- //else if (command.equals("EXAMINE")) examine(mailbox()); FIXME
+ else if (command.equals("EXAMINE")) select(astring(), true);
+ else if (command.equals("SELECT")) select(astring(), false);
else if (command.equals("COPY")) copy(set(), mailbox());
else if (command.equals("DELETE")) delete(mailbox());
- //else if (command.equals("CREATE")) create(mailbox()); FIXME
+ else if (command.equals("CHECK")) check();
+ else if (command.equals("CREATE")) create(astring());
else if (command.equals("STORE")) store(set(), atom(), l());
else if (command.equals("FETCH")) fetch(set(), token());
else if (command.equals("STATUS")) status(mailbox(), l());
- else throw new Bad("unrecognized command \"" + command + "\"");
+ else throw new Exn.Bad("unrecognized command \"" + command + "\"");
}
}
- static String quotify(String s){return s==null?"NIL":"\""+s.replaceAll("\\\\","\\\\").replaceAll("\"","\\\\\"")+"\"";}
- static String quotify(Date d) { throw new Error("not implemented"); }
- static String address(Address a) {return"("+quotify(a.description)+" NIL "+quotify(a.user)+" "+quotify(a.host)+")"; }
- public static String addressList(Object a) {
- if (a == null) return "NIL";
- if (a instanceof Address) return "("+address((Address)a)+")";
- Address[] aa = (Address[])a;
- StringBuffer ret = new StringBuffer();
- ret.append("(");
- for(int i=0; i<aa.length; i++) { ret.append(aa[i]); if (i < aa.length - 1) ret.append(" "); }
- ret.append(")");
- return ret.toString();
- }
- static String flags(Message m) {
- return
- (m.deleted ? "\\Deleted " : "") +
- (m.seen ? "\\Seen " : "") +
- (m.flagged ? "\\Flagged " : "") +
- (m.draft ? "\\Draft " : "") +
- (m.answered ? "\\Answered " : "") +
- (m.recent ? "\\Recent " : "");
- }
- static String envelope(Message m) {
- return
- "(" + quotify(m.arrival.toString()) +
- " " + quotify(m.subject) +
- " " + addressList(m.from) +
- " " + addressList(m.headers.get("sender")) +
- " " + addressList(m.replyto) +
- " " + addressList(m.to) +
- " " + addressList(m.cc) +
- " " + addressList(m.bcc) +
- " " + quotify((String)m.headers.get("in-reply-to")) +
- " " + quotify(m.messageid) +
- ")";
- }
-
+ static String quotify(String s){return s==null?"NIL":"\""+s.replaceAll("\\\\","\\\\").replaceAll("\"","\\\\\"")+"\"";}
+ static String quotify(Date d) { return new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss +zzzz").format(d); }
+ static String address(Address a) {return"("+quotify(a.description)+" NIL "+quotify(a.user)+" "+quotify(a.host)+")"; }
+ public static String addressList(Object a) {
+ if (a == null) return "NIL";
+ if (a instanceof Address) return "("+address((Address)a)+")";
+ Address[] aa = (Address[])a;
+ StringBuffer ret = new StringBuffer();
+ ret.append("(");
+ for(int i=0; i<aa.length; i++) { ret.append(aa[i]); if (i < aa.length - 1) ret.append(" "); }
+ ret.append(")");
+ return ret.toString();
+ }
+ static String flags(Message m) {
+ return
+ (m.deleted ? "\\Deleted " : "") +
+ (m.seen ? "\\Seen " : "") +
+ (m.flagged ? "\\Flagged " : "") +
+ (m.draft ? "\\Draft " : "") +
+ (m.answered ? "\\Answered " : "") +
+ (m.recent ? "\\Recent " : "");
+ }
+ static String envelope(Message m) {
+ return
+ "(" + quotify(m.arrival.toString()) +
+ " " + quotify(m.subject) +
+ " " + addressList(m.from) +
+ " " + addressList(m.headers.get("sender")) +
+ " " + addressList(m.replyto) +
+ " " + addressList(m.to) +
+ " " + addressList(m.cc) +
+ " " + addressList(m.bcc) +
+ " " + quotify((String)m.headers.get("in-reply-to")) +
+ " " + quotify(m.messageid) +
+ ")";
+ }
- Token[] parse(String s) { /* FIXME */ return null; }
Query query() {
String s = null;
boolean not = false;
Query q = null;
while(true) {
Token t = token();
- if (t.type == t.LIST) throw new No("nested queries not yet supported");
+ if (t.type == t.LIST) throw new Exn.No("nested queries not yet supported");
else if (t.type == t.SET) return Query.set(t.set());
s = t.atom();
if (s.equals("NOT")) { not = true; continue; }
return q;
}
-
class Token {
private byte type;
private final String s;
public Token(Token[] list) { l = list; s = null; type = LIST; n = 0; }
public Token(int number) { n = number; l = null; s = null; type = NUMBER; }
- // assumes token is a flag list or a fag
+ // assumes token is a flag list or a flag
public void setFlags(Message m) { }
public void addFlags(Message m) { }
public void deleteFlags(Message m) { }
- public String mailboxPattern() throws Bad {
+ public String mailboxPattern() throws Exn.Bad {
if (type == ATOM) return s;
if (type == QUOTED) return s;
- throw new Bad("exepected a mailbox pattern");
+ throw new Exn.Bad("exepected a mailbox pattern");
}
- public String flag() throws Bad {
- if (type != ATOM) throw new Bad("expected a flag");
+ public String flag() throws Exn.Bad {
+ if (type != ATOM) throw new Exn.Bad("expected a flag");
return s; // if first char != backslash, it is a keyword-flag
}
- public int n() throws Bad {
- if (type != NUMBER) throw new Bad("expected number");
+ public int n() throws Exn.Bad {
+ if (type != NUMBER) throw new Exn.Bad("expected number");
return n;
}
- public int nz() throws Bad {
- if (type != NUMBER) throw new Bad("expected number");
- if (n == 0) throw new Bad("expected nonzero number");
+ public int nz() throws Exn.Bad {
+ if (type != NUMBER) throw new Exn.Bad("expected number");
+ if (n == 0) throw new Exn.Bad("expected nonzero number");
return n;
}
- public String q() throws Bad {
+ public String q() throws Exn.Bad {
if (type == NIL) return null;
- if (type != QUOTED) throw new Bad("expected qstring");
+ if (type != QUOTED) throw new Exn.Bad("expected qstring");
return s;
}
- public Token[] l() throws Bad {
+ public Token[] l() throws Exn.Bad {
if (type == NIL) return null;
- if (type != LIST) throw new Bad("expected parenthesized list");
+ if (type != LIST) throw new Exn.Bad("expected parenthesized list");
return l;
}
- public int[] set() throws Bad {
- if (type != ATOM) throw new Bad("expected a messageid set");
+ public int[] set() throws Exn.Bad {
+ if (type != ATOM) throw new Exn.Bad("expected a messageid set");
Vec ids = new Vec();
StringTokenizer st = new StringTokenizer(s, ",");
while(st.hasMoreTokens()) {
}
}
int[] ret = new int[ids.size()];
- //ids.copyInto(ret); FIXME
+ for(int i=0; i<ret.length; i++) ret[i] = ((Integer)ids.elementAt(i)).intValue();
return ret;
}
- public Date date() throws Bad {
- if (type != QUOTED && type != ATOM) throw new Bad("Expected quoted or unquoted date");
+ public Date date() throws Exn.Bad {
+ if (type != QUOTED && type != ATOM) throw new Exn.Bad("Expected quoted or unquoted date");
try { return new SimpleDateFormat("dd-MMM-yyyy").parse(s);
- } catch (ParseException p) { throw new Bad("invalid date format; " + p); }
+ } catch (ParseException p) { throw new Exn.Bad("invalid date format; " + p); }
}
- public Date datetime() throws Bad {
- if (type != QUOTED && type != ATOM) throw new Bad("Expected quoted or unquoted datetime");
+ public Date datetime() throws Exn.Bad {
+ if (type != QUOTED && type != ATOM) throw new Exn.Bad("Expected quoted or unquoted datetime");
try { return new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss +zzzz").parse(s);
- } catch (ParseException p) { throw new Bad("invalid datetime format; " + p); }
+ } catch (ParseException p) { throw new Exn.Bad("invalid datetime format; " + p); }
}
- public String nstring() throws Bad {
+ public String nstring() throws Exn.Bad {
if (type == NIL) return null;
if (type == QUOTED) return s;
- throw new Bad("expected NIL or string");
+ throw new Exn.Bad("expected NIL or string");
}
- public String astring() throws Bad {
+ public String astring() throws Exn.Bad {
if (type == ATOM) return s;
if (type == QUOTED) return s;
- throw new Bad("expected atom or string");
+ throw new Exn.Bad("expected atom or string");
}
- public String atom() throws Bad {
- if (type != ATOM) throw new Bad("expected atom");
+ public String atom() throws Exn.Bad {
+ if (type != ATOM) throw new Exn.Bad("expected atom");
for(int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (c == '(' || c == ')' || c == '{' || c == ' ' || c == '%' || c == '*')
- throw new Bad("invalid char in atom: " + c);
+ throw new Exn.Bad("invalid char in atom: " + c);
}
return s;
}
- public Mailbox mailbox() throws Bad, IOException {
+ public Mailbox mailbox() throws Exn.Bad {
if (type == BAREWORD && s.toLowerCase().equals("inbox")) return getMailbox("INBOX", false);
return getMailbox(astring(), false);
}
else if (c == '\"') break;
else sb.append(c);
}
+ return new Token(sb.toString());
} else if (c == ')') {
return null;
} else if (c == '(') {
if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '{') break;
sb.append(getc());
}
- //return toks.toArray();
- return null; // FIXME
+ return new Token(sb.toString());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
- public String mailboxPattern() throws Bad { return token().mailboxPattern(); }
- public String flag() throws Bad { return token().flag(); }
- public int n() throws Bad { return token().n(); }
- public int nz() throws Bad { return token().nz(); }
- public String q() throws Bad { return token().q(); }
- public Token[] l() throws Bad { return token().l(); }
- public int[] set() throws Bad { return token().set(); }
- public Date date() throws Bad { return token().date(); }
- public Date datetime() throws Bad { return token().datetime(); }
- public String nstring() throws Bad { return token().nstring(); }
- public String astring() throws Bad { return token().astring(); }
- public String atom() throws Bad { return token().atom(); }
- public Mailbox mailbox() throws Bad, IOException { return token().mailbox(); }
+ public String mailboxPattern() throws Exn.Bad { return token().mailboxPattern(); }
+ public String flag() throws Exn.Bad { return token().flag(); }
+ public int n() throws Exn.Bad { return token().n(); }
+ public int nz() throws Exn.Bad { return token().nz(); }
+ public String q() throws Exn.Bad { return token().q(); }
+ public Token[] l() throws Exn.Bad { return token().l(); }
+ public int[] set() throws Exn.Bad { return token().set(); }
+ public Date date() throws Exn.Bad { return token().date(); }
+ public Date datetime() throws Exn.Bad { return token().datetime(); }
+ public String nstring() throws Exn.Bad { return token().nstring(); }
+ public String astring() throws Exn.Bad { return token().astring(); }
+ public String atom() throws Exn.Bad { return token().atom(); }
+ public Mailbox mailbox() throws Exn.Bad, IOException { return token().mailbox(); }
}
}