treat BODY[1] as BODY for now
[org.ibex.mail.git] / src / org / ibex / mail / protocol / IMAP.java
index 5b74005..e0cc718 100644 (file)
@@ -76,7 +76,6 @@ public class IMAP {
         public void      fetch(Query q, int spec, String[] headers, int start, int end, boolean uid);
         public void      lsub(String start, String ref);
         public void      list(String start, String ref);
-        public static interface Authenticator { public abstract Mailbox authenticate(String user, String pass); } 
         public static class Exn extends MailException { public Exn(String s) { super(s); } }
         public static class Bad extends Exn { public Bad(String s) { super(s); } }
         public static class No extends Exn { public No(String s) { super(s); } }
@@ -94,16 +93,20 @@ public class IMAP {
         Mailbox selected = null;
         Mailbox root = null;
         Mailbox selected() { if (selected == null) throw new Bad("no mailbox selected"); return selected; }
-        final Server.Authenticator auth;
+        final Login auth;
         final Client client;
 
-        public MailboxWrapper(Server.Authenticator auth, Client c) { this.auth=auth; this.client=c;}
+        public MailboxWrapper(Login auth, Client c) { this.auth=auth; this.client=c;}
 
-        private Mailbox mailbox(String name, boolean create) {
+        private Mailbox mailbox(String name, boolean create) { return mailbox(name, create, true); }
+        private Mailbox mailbox(String name, boolean create, boolean throwexn) {
             if (name.equalsIgnoreCase("inbox")) return inbox;
             Mailbox m = root;
             for(StringTokenizer st = new StringTokenizer(name, sep + ""); st.hasMoreTokens();)
-                if ((m = m.slash(st.nextToken(), create)) == null) throw new Server.No("no such mailbox " + name);
+                if ((m = m.slash(st.nextToken(), create)) == null) {
+                    if (throwexn) throw new Server.No("no such mailbox " + name);
+                    return null;
+                }
             return m;
         }
 
@@ -117,6 +120,7 @@ public class IMAP {
             String[] children = (start.length() == 0 ? root : mailbox(start, false)).children();
             for(int i=0; i<children.length; i++) {
                 String s = children[i], pre = ref, kid = start + (start.length() > 0 ? sep+"" : "") + s;                
+                if (mailbox(kid, false) == null) continue;
                 boolean phantom = mailbox(kid, false).phantom();
                 while(true) {
                     if (pre.length() == 0) {
@@ -151,13 +155,16 @@ public class IMAP {
             for(Mailbox.Iterator it=selected().iterator(q);it.next();) to.add(it.cur(), it.flags() | Mailbox.Flag.RECENT); }
 
         public void login(String u, String p) {
-            if ((root = auth.authenticate(u,p)) == null) throw new No("Login failed.");
-            inbox = mailbox("INBOX", false);  // FEATURE: ??
+            Account account = null;
+            if ((account = auth.login(u,p)) == null) throw new No("Login failed.");
+            root = account.getMailbox(IMAP.class);
+            inbox = root.slash("INBOX", false);
+            if (inbox == null) inbox = root;
         }
         public void unselect() { selected = null; }
         public void delete(String m0) { delete(mailbox(m0,false)); }
         public void delete(Mailbox m) { if (!m.equals(inbox)) m.destroy(false); else throw new Bad("can't delete inbox"); }
-        public void create(String m) { mailbox(m, true); }
+        public void create(String m) { mailbox(m, true, false); }
         public void append(String m,int f,Date a,String b) { try {
             mailbox(m,false).add(new Message(new Stream(b), new Message.Envelope(null,null,a)),f|Mailbox.Flag.RECENT);
         } catch (Message.Malformed e) { throw new No(e.getMessage()); } }
@@ -227,9 +234,10 @@ public class IMAP {
         String selectedName = null;
         Mailbox inbox = null, root = null;
         Server api;
+        Login auth = null;
         Parser parser = null;
         Connection conn = null;
-        public Listener() { }
+        public Listener(Login auth) { this.auth = auth; }
         Parser.Token token() { return parser.token(); }
         void println(String s) { conn.println(s); }
         void newline() { parser.newline(); }
@@ -237,7 +245,7 @@ public class IMAP {
         public void handleRequest(Connection conn) {
             this.conn = conn;
             parser = new Parser(conn);
-            api = new IMAP.MailboxWrapper(new BogusAuthenticator(), this);
+            api = new IMAP.MailboxWrapper(auth, this);
             conn.setTimeout(30 * 60 * 1000);
             println("* OK " + conn.vhost + " " + IMAP.class.getName() + " IMAP4rev1 [RFC3501] v" + version + " server ready");
             for(String tag = null;; newline()) try {
@@ -252,7 +260,7 @@ public class IMAP {
                     case CAPABILITY:   println("* CAPABILITY " + Printer.join(" ", api.capability())); break;
                     case AUTHENTICATE: throw new Server.No("AUTHENTICATE not supported");
                     case LOGOUT:       api.logout(); println("* BYE"); conn.close(); return;
-                    case LIST:         api.list(token().q(), token().q()); break;
+                    case LIST:         api.list(token().q(), token().astring()); break; /*astring is a hack for EUDORA*/
                     case LSUB:         api.lsub(token().q(), token().q()); break;
                     case SUBSCRIBE:    api.subscribe(token().astring()); break;
                     case UNSUBSCRIBE:  api.unsubscribe(token().astring()); break;
@@ -410,7 +418,7 @@ public class IMAP {
                     s = list.length == 0 ? "" : list[0].s.toUpperCase();
                     r.append(s);
                     if (list.length == 0)                   { spec |= RFC822TEXT;   if(e) payload = m.headers.raw+"\r\n"+m.body; }
-                    else if (s.equals(""))                  { spec |= RFC822TEXT;   if(e) payload = m.headers.raw+"\r\n"+m.body; }
+                    else if (s.equals("") || s.equals("1")) { spec |= RFC822TEXT;   if(e) payload = m.headers.raw+"\r\n"+m.body; }
                     else if (s.equals("TEXT"))              { spec |= RFC822TEXT;   if(e) payload = m.body; }
                     else if (s.equals("HEADER"))            { spec |= HEADER;       if(e) payload = m.headers.raw+"\r\n"; }
                     else if (s.equals("HEADER.FIELDS"))     { spec |= FIELDS;     payload=headers(r,t[i].l()[1].sl(),false,m,e); }
@@ -710,6 +718,7 @@ public class IMAP {
             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("(");
@@ -742,7 +751,7 @@ public class IMAP {
             return "(\"TEXT\" \"PLAIN\" (\"CHARSET\" \"ISO-8859-1\") NIL NIL \"7BIT\" "+m.size()+" "+m.lines+")";
         }
         static String message(Message m) { return m.toString(); }
-        static String date(Date d) { return d.toString(); }
+        static String date(Date d) { return "\""+d.toString()+"\""; }
         static String envelope(Message m) {
             return
                 "(" + quotify(m.envelope.arrival.toString()) +
@@ -790,26 +799,8 @@ public class IMAP {
 
     // Main //////////////////////////////////////////////////////////////////////////////
 
-    /** simple listener for testing purposes */
-    public static void main(String[] args) throws Exception {
-        ServerSocket ss = new ServerSocket(143);
-        for(;;) {
-            final Socket s = ss.accept();
-            new Thread() { public void run() { try {
-                final Mailbox root = FileBasedMailbox.getFileBasedMailbox(Mailbox.STORAGE_ROOT+File.separatorChar+"imap", true);
-                new Listener();
-            } catch (Exception e) { e.printStackTrace(); } } }.start();
-        }
-    }
-
     public static final int
         PEEK=0x1, BODYSTRUCTURE=0x2, ENVELOPE=0x4, FLAGS=0x8, INTERNALDATE=0x10, FIELDS=0x800, FIELDSNOT=0x1000,
         RFC822=0x20, RFC822TEXT=0x40, RFC822SIZE=0x80, HEADERNOT=0x100, UID=0x200, HEADER=0x400;
 
-
-    public static class BogusAuthenticator implements IMAP.Server.Authenticator {
-        final Mailbox root = FileBasedMailbox.getFileBasedMailbox(Mailbox.STORAGE_ROOT, true).slash("user", true);
-        public Mailbox authenticate(String user, String pass) {
-            return EtcPasswd.verify(user, pass) ? root.slash(user, false) : null; }
-    }
 }