append sorta works; dates are broken
authoradam <adam@megacz.com>
Thu, 10 Jun 2004 04:42:03 +0000 (04:42 +0000)
committeradam <adam@megacz.com>
Thu, 10 Jun 2004 04:42:03 +0000 (04:42 +0000)
darcs-hash:20040610044203-5007d-b36fe433c8afb21397ad179459e725705087c70a.gz

Makefile
src/org/ibex/mail/Message.java
src/org/ibex/mail/protocol/IMAP.java
src/org/ibex/mail/target/FileBasedMailbox.java
src/org/ibex/mail/target/Script.java

index c432e83..d37d5ca 100644 (file)
--- 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
index f4644f8..477d88c 100644 (file)
@@ -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");
index a2a7b76..bb7fc67 100644 (file)
@@ -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;
index fb5e9aa..5952406 100644 (file)
@@ -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;
index 206fdd0..5564ba6 100644 (file)
@@ -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 {