this.r = new PushbackReader(new InputStreamReader(is));
}
- private void star(String s) { pw.println("* " + s); }
+ private void star(String s) {
+ pw.println("* " + s);
+ System.err.println("* " + s);
+ pw.flush();
+ }
+ // FIXME: user-inbox-relative stuff
// FIXME should throw a No if mailbox not found and create==false
private Mailbox getMailbox(String name, boolean create) {
Mailbox m = root;
int end = name.length();
if (name.indexOf(imapSeparator) != -1) end = name.indexOf(imapSeparator);
m = m.slash(name.substring(0, end), create);
- name = name.substring(end);
+ if (end == name.length()) break;
+ name = name.substring(end+1);
}
return m;
}
- private boolean auth(String user, String pass) { /* FEATURE */ return user.equals("megacz") && pass.equals(""); }
+ private boolean auth(String user, String pass) { /* FEATURE */ return user.equals("megacz") && pass.equals("pass"); }
+
+ // FEATURE: manage subscriptions
+ public void lsub(Mailbox m, String s) {
+ star("LSUB () \".\" INBOX");
+ }
+
+ // FIXME
+ public void list(Mailbox m, String s) {
+ //star("LIST () \".\" INBOX");
+ star("LIST () \".\" users.megacz.imap");
+ }
- public void lsub(Mailbox m, String s) { star("LIST () \".\" INBOX"); } // FEATURE
- public void list(Mailbox m, String s) { star("LIST () \".\" INBOX"); } // FEATURE
public void copy(final Query q, Mailbox to) { for(Mailbox.Iterator it=selected.iterator(q);it.next();) to.add(it.cur()); }
public void login(String user, String pass) { if (!auth(user, pass)) throw new Exn.No("Liar, liar, pants on fire."); }
public void capability() { star("CAPABILITY IMAP4rev1"); }
public void create(String mailbox){if(!mailbox.endsWith(".")&&!mailbox.equalsIgnoreCase("inbox"))getMailbox(mailbox,true);}
public void close(boolean examineOnly) { expunge(false, true); selected = null; }
public void check() { }
+ public void noop() { }
public void rename(Mailbox from, String to) {
if (from.equals(inbox)) from.copy(Query.all(), getMailbox(to, true));
public void select(String mailbox, boolean examineOnly) {
selected = getMailbox(mailbox, false);
+ if (selected == null) throw new Exn.No("no such mailbox"); // should this be 'Bad'?
star(selected.count(Query.all()) + " EXISTS");
star(selected.count(Query.recent()) + " RECENT");
//star("OK [UNSEEN 12] Message 12 is first unseen"); FEATURE
if (t.type == t.LIST) { flags = t.l(); t = token(); }
if (t.type == t.QUOTED) { arrival = t.datetime(); t = token(); }
String literal = q();
- selected.add(new Message(null, null, new LineReader(new StringReader(literal))));
+ m.add(new Message(null, new Address[] { null }, new LineReader(new StringReader(literal))));
if (flags != null) { /* FEATURE */ }
}
}
public boolean handleRequest() throws IOException {
- LineReader lr = new LineReader(r);
pw.println("* OK " + vhost + " " + IMAP.class.getName() + " IMAP4 v0.1 server ready");
+ System.err.println("* OK " + vhost + " " + IMAP.class.getName() + " IMAP4 v0.1 server ready");
+ pw.flush();
while(true) {
String tag = null;
try {
boolean uid = false;
- String s = lr.readLine();
- if (s.indexOf(' ') == -1) throw new Exn.Bad("BAD Invalid tag");
+ tag = null;
+ // FIXME better error if atom() fails
tag = atom();
String command = atom();
- if (command.equals("UID")) { uid = true; command = atom(); }
- if (command.equals("AUTHENTICATE")) { login(astring(), astring()); }
- else if (command.equals("LIST")) list(mailbox(), mailboxPattern());
- else if (command.equals("LSUB")) lsub(mailbox(), mailboxPattern());
- else if (command.equals("CAPABILITY")) { capability(); }
- else if (command.equals("LOGIN")) 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")) select(astring(), true);
- else if (command.equals("SELECT")) select(astring(), false);
- else if (command.equals("COPY")) copy(Query.num(set()), mailbox());
- else if (command.equals("DELETE")) delete(mailbox());
- else if (command.equals("CHECK")) check();
- else if (command.equals("CREATE")) create(astring());
- else if (command.equals("STORE")) store(Query.num(set()), atom(), l());
- else if (command.equals("FETCH")) fetch(Query.num(set()), token());
- else if (command.equals("STATUS")) status(mailbox(), l());
+ if (command.equalsIgnoreCase("UID")) { uid = true; command = atom(); }
+ if (command.equalsIgnoreCase("AUTHENTICATE")) { login(astring(), astring()); }
+ else if (command.equalsIgnoreCase("LIST")) list(mailbox(), mailboxPattern());
+ else if (command.equalsIgnoreCase("LSUB")) lsub(mailbox(), mailboxPattern());
+ else if (command.equalsIgnoreCase("CAPABILITY")) { capability(); }
+ else if (command.equalsIgnoreCase("LOGIN")) login(astring(), astring());
+ else if (command.equalsIgnoreCase("LOGOUT")) { logout(); conn.close(); return false; }
+ else if (command.equalsIgnoreCase("RENAME")) rename(mailbox(), atom());
+ else if (command.equalsIgnoreCase("APPEND")) append(mailbox(), token());
+ else if (command.equalsIgnoreCase("EXAMINE")) select(astring(), true);
+ else if (command.equalsIgnoreCase("SELECT")) select(astring(), false);
+ else if (command.equalsIgnoreCase("COPY")) copy(Query.num(set()), mailbox());
+ else if (command.equalsIgnoreCase("DELETE")) delete(mailbox());
+ else if (command.equalsIgnoreCase("CHECK")) check();
+ else if (command.equalsIgnoreCase("NOOP")) noop();
+ else if (command.equalsIgnoreCase("CREATE")) create(astring());
+ else if (command.equalsIgnoreCase("STORE")) store(Query.num(set()), atom(), l());
+ else if (command.equalsIgnoreCase("FETCH")) fetch(Query.num(set()), token());
+ else if (command.equalsIgnoreCase("STATUS")) status(mailbox(), l());
else throw new Exn.Bad("unrecognized command \"" + command + "\"");
pw.println(tag + " OK " + command + " Completed.");
- } catch (Exn.Bad b) { pw.println(tag + " Bad " + b.toString());
- } catch (Exn.No n) { pw.println(tag + " OK " + n.toString());
+ System.err.println(tag + " OK " + command + " Completed.");
+ } catch (Exn.Bad b) { pw.println(tag + " Bad " + b.toString()); System.err.println(tag + " Bad " + b.toString()); b.printStackTrace();
+ } catch (Exn.No n) { pw.println(tag + " OK " + n.toString()); System.err.println(tag + " OK " + n.toString());
}
pw.flush();
+ newline();
}
}
private static final byte BAREWORD = 5;
private static final byte SET = 6;
public Token() { n = 0; l = null; s = null; type = NIL; }
- public Token(String quoted) { s = quoted; l = null; type = QUOTED; n = 0; }
+ public Token(String s, boolean quoted) { this.s = s; l = null; type = quoted ? QUOTED : ATOM; n = 0; }
public Token(Token[] list) { l = list; s = null; type = LIST; n = 0; }
public Token(int number) { n = number; l = null; s = null; type = NUMBER; }
}
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 Exn.Bad("invalid datetime format; " + p); }
+ try { return new SimpleDateFormat("dd-MM-yyyy hh:mm:ss").parse(s.trim());
+ } catch (ParseException p) { throw new Exn.Bad("invalid datetime format " + s + " : " + p); }
}
public String nstring() throws Exn.Bad {
if (type == NIL) return null;
public char getc() throws IOException {
int ret = r.read();
if (ret == -1) throw new EOFException();
+ System.err.print((char)ret);
+ System.err.flush();
return (char)ret;
}
public char peekc() throws IOException {
}
}
- public Token token() {
+ public void newline() {
+ try {
+ for(char c = peekc(); c == ' ';) { getc(); c = peekc(); };
+ for(char c = peekc(); c == '\r' || c == '\n';) { getc(); c = peekc(); };
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public Token token() {
try {
Vec toks = new Vec();
StringBuffer sb = new StringBuffer();
char c = getc(); while (c == ' ') c = getc();
- if (c == '{') {
+ if (c == '\r' || c == '\n') {
+ throw new Exn.Bad("unexpected end of line");
+ } if (c == '{') {
while(peekc() != '}') sb.append(getc());
int octets = Integer.parseInt(sb.toString());
while(peekc() == ' ') getc(); // whitespace
- while (getc() != '\n') { }
+ while (getc() != '\n' && getc() != '\r') { }
byte[] bytes = new byte[octets];
fill(bytes);
- return new Token(new String(bytes));
+ return new Token(new String(bytes), true);
} else if (c == '\"') {
while(true) {
c = getc();
else if (c == '\"') break;
else sb.append(c);
}
- return new Token(sb.toString());
+ return new Token(sb.toString(), true);
} else if (c == ')') {
return null;
} else if (c == '(') {
toks.copyInto(ret);
return null; // FIXME
} else while(true) {
+ sb.append(c);
c = peekc();
- if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '{') break;
- sb.append(getc());
+ if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '{' || c == '\n' || c == '\r')
+ return new Token(sb.toString(), false);
+ getc();
}
- return new Token(sb.toString());
} catch (IOException e) {
e.printStackTrace();
return null;