From: adam Date: Thu, 10 Jun 2004 04:42:03 +0000 (+0000) Subject: append sorta works; dates are broken X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=76be0d989d6b938e9304416515dcf898ff581230;p=org.ibex.mail.git append sorta works; dates are broken darcs-hash:20040610044203-5007d-b36fe433c8afb21397ad179459e725705087c70a.gz --- diff --git a/Makefile b/Makefile index c432e83..d37d5ca 100644 --- a/Makefile +++ b/Makefile @@ -26,5 +26,8 @@ mail.jar: $(sources) @javac -d build/class -classpath upstream/org.ibex.core/build/class $^ @cd build/class; jar cvf ../../mail.jar . +#run: mail.jar +# java -cp mail.jar:upstream/org.ibex.core/build/class org.ibex.mail.protocol.SMTP + run: mail.jar - java -cp mail.jar:upstream/org.ibex.core/build/class org.ibex.mail.protocol.SMTP \ No newline at end of file + sudo java -cp mail.jar:upstream/org.ibex.core/build/class -Dibex.mail.root=`pwd`/mail-root org.ibex.mail.protocol.IMAP \ No newline at end of file diff --git a/src/org/ibex/mail/Message.java b/src/org/ibex/mail/Message.java index f4644f8..477d88c 100644 --- a/src/org/ibex/mail/Message.java +++ b/src/org/ibex/mail/Message.java @@ -97,8 +97,6 @@ public class Message extends JSReflection { public static class Malformed extends MailException.Malformed { public Malformed(String s) { super(s); } } public Message(Address envelopeFrom, Address[] envelopeTo, LineReader rs) { try { - this.envelopeFrom = envelopeFrom; - this.envelopeTo = envelopeTo; this.arrival = new Date(); this.headers = new CaseInsensitiveHash(); String key = null; @@ -134,9 +132,13 @@ public class Message extends JSReflection { } } + // FIXME what if all are null? + this.to = headers.get("To") == null ? envelopeTo[0] : new Address((String)headers.get("To")); + this.from = headers.get("From") == null ? envelopeFrom : new Address((String)headers.get("From")); + this.envelopeFrom = envelopeFrom == null ? this.from : envelopeFrom; + this.envelopeTo = envelopeTo == null ? new Address[] { this.to } : envelopeTo; + this.date = (Date)headers.get("Date"); - this.to = new Address((String)headers.get("To")); // FIXME what if null? - this.from = headers.get("From") == null ? envelopeFrom : new Address((String)headers.get("From")); this.replyto = headers.get("Reply-To") == null ? null : new Address((String)headers.get("Reply-To")); this.subject = (String)headers.get("Subject"); this.messageid = (String)headers.get("Message-Id"); diff --git a/src/org/ibex/mail/protocol/IMAP.java b/src/org/ibex/mail/protocol/IMAP.java index a2a7b76..bb7fc67 100644 --- a/src/org/ibex/mail/protocol/IMAP.java +++ b/src/org/ibex/mail/protocol/IMAP.java @@ -62,8 +62,13 @@ public class IMAP extends MessageProtocol { 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; @@ -71,15 +76,25 @@ public class IMAP extends MessageProtocol { 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"); } @@ -88,6 +103,7 @@ public class IMAP extends MessageProtocol { 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)); @@ -112,6 +128,7 @@ public class IMAP extends MessageProtocol { 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 @@ -135,7 +152,7 @@ public class IMAP extends MessageProtocol { 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 */ } } @@ -206,40 +223,44 @@ public class IMAP extends MessageProtocol { } 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(); } } @@ -344,7 +365,7 @@ public class IMAP extends MessageProtocol { 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; } @@ -407,8 +428,8 @@ public class IMAP extends MessageProtocol { } 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; @@ -439,6 +460,8 @@ public class IMAP extends MessageProtocol { 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 { @@ -456,19 +479,30 @@ public class IMAP extends MessageProtocol { } } - 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(); @@ -476,7 +510,7 @@ public class IMAP extends MessageProtocol { 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 == '(') { @@ -486,11 +520,12 @@ public class IMAP extends MessageProtocol { 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; diff --git a/src/org/ibex/mail/target/FileBasedMailbox.java b/src/org/ibex/mail/target/FileBasedMailbox.java index fb5e9aa..5952406 100644 --- a/src/org/ibex/mail/target/FileBasedMailbox.java +++ b/src/org/ibex/mail/target/FileBasedMailbox.java @@ -21,12 +21,12 @@ public class FileBasedMailbox extends Mailbox.Default { return ret; } - public static final FilenameFilter filter = new FilenameFilter() { public boolean accept(File f, String s) { return s.indexOf('.') != -1; } }; + // Instance ////////////////////////////////////////////////////////////////////////////// private String path; diff --git a/src/org/ibex/mail/target/Script.java b/src/org/ibex/mail/target/Script.java index 206fdd0..5564ba6 100644 --- a/src/org/ibex/mail/target/Script.java +++ b/src/org/ibex/mail/target/Script.java @@ -55,14 +55,17 @@ public class Script extends Target { // FIXME: this should extend org.ibex.core.Ibex public static class ScriptEnv extends JS { - private static PropertyFile prefs; + private static PropertyFile prefs = null; + /* static { try { + // FIXME prefs = new PropertyFile(new File("/etc/org.ibex.mail.properties")); } catch (IOException e) { Log.error(ScriptEnv.class, e); } } + */ /** lets us put multi-level get/put/call keys all in the same method */ private class Sub extends JS {