+ public void newline() { stream.readln(); }
+
+ public Token token() { return token(true); }
+ public Token token(boolean freak) {
+ Vec toks = new Vec();
+ StringBuffer sb = new StringBuffer();
+ char c = stream.getc(); while (c == ' ') c = stream.getc();
+ if (c == '\r' || c == '\n') { if (freak) bad("unexpected end of line"); return null; }
+ else if (c == '{') {
+ while(stream.peekc() != '}') sb.append(stream.getc());
+ stream.getc();
+ stream.println("+ Ready when you are...");
+ int octets = Integer.parseInt(sb.toString());
+ while(stream.peekc() == ' ') stream.getc(); // whitespace
+ while(stream.peekc() == '\n' || stream.peekc() == '\r') stream.getc();
+ byte[] bytes = new byte[octets];
+ int numread = 0;
+ while(numread < bytes.length) {
+ int n = stream.read(bytes, numread, bytes.length - numread);
+ if (n == -1) bad("end of stream while reading IMAP qstring");
+ numread += n;
+ }
+ return new Token(new String(bytes), true);
+ } else if (c == '\"') {
+ while(true) {
+ c = stream.getc();
+ if (c == '\\') sb.append(stream.getc());
+ else if (c == '\"') break;
+ else sb.append(c);
+ }
+ return new Token(sb.toString(), true);
+
+ // NOTE: this is technically a violation of the IMAP grammar, since atoms like FOO[BAR should be legal
+ } else if (c == ']' || c == ')') { return null;
+ } else if (c == '[' || c == '(') {
+ Token t;
+ do { t = token(); if (t != null) toks.addElement(t); } while (t != null);
+ Token[] ret = new Token[toks.size()];
+ toks.copyInto(ret);
+ return new Token(ret);
+
+ } else while(true) {
+ sb.append(c);
+ c = stream.peekc();
+ if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '[' || c == ']' ||
+ c == '{' || c == '\n' || c == '\r')
+ return new Token(sb.toString(), false);
+ stream.getc();
+ }
+ }
+ }
+
+ public static class Printer {
+ 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)+")";
+ if (a instanceof String) return "("+address(Address.parse((String)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(Mailbox.Iterator it) {
+ return
+ (it.deleted() ? "\\Deleted " : "") +
+ (it.seen() ? "\\Seen " : "") +
+ (it.flagged() ? "\\Flagged " : "") +
+ (it.draft() ? "\\Draft " : "") +
+ (it.answered() ? "\\Answered " : "") +
+ (it.recent() ? "\\Recent " : "");
+ }
+ static String flags(int flags) {
+ String ret = "(" +
+ (((flags & Mailbox.Flag.DELETED) == Mailbox.Flag.DELETED) ? "\\Deleted " : "") +
+ (((flags & Mailbox.Flag.SEEN) == Mailbox.Flag.SEEN) ? "\\Seen " : "") +
+ (((flags & Mailbox.Flag.FLAGGED) == Mailbox.Flag.FLAGGED) ? "\\Flagged " : "") +
+ (((flags & Mailbox.Flag.DRAFT) == Mailbox.Flag.DRAFT) ? "\\Draft " : "") +
+ (((flags & Mailbox.Flag.ANSWERED) == Mailbox.Flag.ANSWERED)? "\\Answered " : "") +
+ (((flags & Mailbox.Flag.RECENT) == Mailbox.Flag.RECENT) ? "\\Recent " : "");
+ if (ret.endsWith(" ")) ret = ret.substring(0, ret.length() - 1);
+ return ret + ")";
+ }
+ static String bodystructure(Message m) {
+ // FIXME
+ return "(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" "+m.getLength()+" "+m.getNumLines()+")";
+ }
+ static String message(Message m) { return m.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.replyto) +
+ " " + addressList(m.to) +
+ " " + addressList(m.cc) +
+ " " + addressList(m.bcc) +
+ " " + quotify((String)m.headers.get("in-reply-to")) +
+ " " + quotify(m.messageid) +
+ ")";