print out tokens in IMAP
[org.ibex.mail.git] / src / org / ibex / mail / IMAP.java
index 9c1ee6b..81f1820 100644 (file)
@@ -52,7 +52,7 @@ public class IMAP {
     public static interface Client {
         public void expunge(int uid);
         public void list(char separator, String mailbox, boolean lsub, boolean phantom);
-        public void fetch(int num, int flags, int size, Message m, int muid);  // m may be null or incomplete
+        public void fetchResponse(int num, int flags, int size, Message m, int muid);  // m may be null or incomplete
     }
 
     public static interface Server {
@@ -206,17 +206,25 @@ public class IMAP {
         public void check() { }
         public void noop() { }
         public void logout() { }
-        public void close() { for(Mailbox.Iterator it=selected().iterator(Query.deleted()); it.next();) it.delete(); }
+        public void close() {
+            for(Mailbox.Iterator it=selected().iterator(Query.deleted()); it.next();) {
+                Log.error("imap", "deleting a message due to close(): " + it.cur().summary());
+                it.delete();
+            }
+        }
         public void expunge() { for(Mailbox.Iterator it = selected().iterator(Query.deleted());it.next();) expunge(it); }
-        public void expunge(Mailbox.Iterator it) { client.expunge(it.uid()); it.delete(); }
+        public void expunge(Mailbox.Iterator it) {
+            client.expunge(it.uid());
+            Log.error("imap", "deleting a message due to expunge(): " + it.cur().summary());
+            it.delete();
+        }
         public void subscribe(String mailbox) { }
         public void unsubscribe(String mailbox) { }
         public int maxuid() {
             int ret = 0;
             Mailbox mb = selected();
             if (mb == null) return 0;
-            for(Mailbox.Iterator it = mb.iterator(); it.next(); ) ret = it.uid();
-            return ret;
+            return mb.maxuid();
         }
         public int unseen(String mailbox)      { return mailbox(mailbox, false).count(Query.not(Query.seen())); }
         public int recent(String mailbox)      { return mailbox(mailbox, false).count(Query.recent()); }
@@ -248,17 +256,22 @@ public class IMAP {
                 else if (style == 0) it.setFlags(flags);
                 else if (style == 1) it.setFlags(it.getFlags() | flags);
                 //it.setFlag(Mailbox.Flag.RECENT, recent);
-                if (!silent) client.fetch(it.imapNumber(), it.getFlags(), -1, null, it.uid());
+                if (!silent) client.fetchResponse(it.imapNumber(), it.getFlags(), -1, null, it.uid());
             }
         }
 
         public void fetch(Query q, int spec, String[] headers, int start, int end, boolean uid) {
             for(Mailbox.Iterator it = selected().iterator(q); it.next(); ) {
+                // FIXME it would be great if we could avoid instantiating the entire message just because RFC822SIZE was requested
                 Message message =
-                    ((spec & (BODYSTRUCTURE | ENVELOPE | INTERNALDATE | FIELDS | FIELDSNOT | RFC822 |
-                                            RFC822TEXT | RFC822SIZE | HEADERNOT | HEADER)) != 0) ? it.cur() : null;
+                    ((spec & (BODYSTRUCTURE | RFC822 | RFC822TEXT | RFC822SIZE)) != 0)
+                    ? it.cur()
+                    : ((spec & (ENVELOPE | INTERNALDATE | FIELDS | FIELDSNOT | RFC822SIZE | HEADERNOT | HEADER)) != 0)
+                    ? Message.newMessage(Fountain.Util.concat(it.head(), Fountain.Util.create("\r\n\r\n")))
+                    : null;
+                if (message != null) Log.warn("spec", spec);
                 long size = message == null ? 0 : message.getLength();
-                client.fetch(it.imapNumber(), it.getFlags(), (int)size, message, it.uid());
+                client.fetchResponse(it.imapNumber(), it.getFlags(), (int)size, message,it.uid());
                 it.setFlags(it.getFlags() & ~Mailbox.Flag.RECENT);
             }
         }
@@ -294,7 +307,7 @@ public class IMAP {
             } else {
                 Account account = (Account)ret;
                 ((MailboxWrapper)api).root = root = account.getMailbox(IMAP.class);
-                MailTree ibt = root.slash("INBOX", false);
+                MailTree ibt = root.slash("inbox", false);
                 Mailbox ib = ibt==null ? null : ibt.getMailbox();
                 ((MailboxWrapper)api).inbox = inbox = ib;
             }
@@ -331,10 +344,10 @@ public class IMAP {
                     case EXPUNGE:      selected(); api.expunge(); break;
                     case UNSELECT:     selected(); api.unselect(); selected = false; break;
                     case CREATE:       api.create(token().astring()); break;
-                    case FETCH:        selected(); lastuid = uid; fetch((uid
-                                                                         ? Query.uid(token().set(maxn(uid)))
-                                                                         : Query.imapNumber(token().set(maxn(uid)))),
-                                                                        lastfetch=token().lx(), 0, 0, 0, uid, 0); break;
+                    case FETCH:        selected(); lastuid = uid; _fetch((uid
+                                                                          ? Query.uid(token().set(maxn(uid)))
+                                                                          : Query.imapNumber(token().set(maxn(uid)))),
+                                                                         lastfetch=token().lx(), 0, 0, 0, uid, 0); break;
                     case COPY:         selected(); api.copy(uid
                                                             ? Query.uid(token().set(maxn(uid)))
                                                             : Query.imapNumber(token().set(maxn(uid))), token().astring()); break;
@@ -419,7 +432,7 @@ public class IMAP {
         // Callbacks //////////////////////////////////////////////////////////////////////////////
 
         public void expunge(int uid) { println("* " + uid + " EXPUNGE"); }
-        public void fetch(int n, int f, int size, Message m, int muid) { fetch(m, lastfetch, n, f, size, lastuid, muid); }
+        public void fetchResponse(int n, int f, int size, Message m, int muid) { _fetch(m, lastfetch, n, f, size, lastuid, muid); }
         public void list(char sep, String mb, boolean sub, boolean p) {
             println("* " + (sub?"LSUB":"LIST")+" ("+(p?"\\Noselect":"")+") \""+sep+"\" \""+mb+"\"");}
 
@@ -431,7 +444,7 @@ public class IMAP {
          *      - parse the fetch request in Token[] t and return a fetch spec
          *      - emit a fetch reply for the parsed spec with respect to message m
          */
-        private void fetch(Object o, Parser.Token[] t, int num, int flags, int size, boolean uid, int muid) {
+        private void _fetch(Object o, Parser.Token[] t, int num, int flags, int size, boolean uid, int muid) {
             Query q   = o == null ? null : o instanceof Query ? (Query)o : null;
             Message m = o == null ? null : o instanceof Message ? (Message)o : null;
             boolean e = q == null;
@@ -444,8 +457,8 @@ public class IMAP {
 
             lastfetch = t;
             int spec = 0;                              // spec; see constants for flags
+            int start = 0, len = 0;
             String[] headers = null;
-            int start = -1, end = -1;
             StringBuffer r = new StringBuffer();
             if (e) { r.append(num); r.append(" FETCH ("); }
             int initlen = r.length();
@@ -492,7 +505,8 @@ public class IMAP {
                     if (s.equalsIgnoreCase("BODY.PEEK"))   spec |= PEEK;
                     looked_at_body = true;
                     if (i >= t.length - 1 || t[i+1].type != Parser.Token.LIST) {
-                       spec |= BODYSTRUCTURE;
+                        // not sure why this was uncommented....
+                       //spec |= BODYSTRUCTURE;
                        if (e) { r.append(" "); r.append(Printer.bodystructure(m)); } continue;
                        //if (e) { r.append(" "); r.append(Printer.qq(m.getBody().getStream())); } continue;
                    }
@@ -509,19 +523,28 @@ public class IMAP {
                     else if (s.equals("HEADER.FIELDS.NOT")) { spec |= FIELDSNOT;    payload=Fountain.Util.create(headers(r,t[i].l()[1].sl(),true,m,e)); }
                     else if (s.equals("MIME")) {              throw new Server.Bad("MIME not supported"); }
                     else                                      throw new Server.Bad("unknown section type " + s);
+
                     if (i<t.length - 1 && (t[i+1].s != null && t[i+1].s.startsWith("<"))) {
                         i++;
                         s = t[i].s.substring(1, t[i].s.indexOf('>'));
                         int dot = s.indexOf('.');
                         start = dot == -1 ? Integer.parseInt(s) : Integer.parseInt(s.substring(0, s.indexOf('.')));
-                        end = dot == -1 ? -1 : Integer.parseInt(s.substring(s.indexOf('.') + 1));
+                        len   = dot == -1 ? -1 : Integer.parseInt(s.substring(s.indexOf('.') + 1));
                         if (e) {
-                            //payload = payload.substring(start, Math.min(end+1,payload.getLength())); r.append("<"+start+">");
-                            // FIXME
-                            throw new RuntimeException("this had to be disabled");
+                            if (start == 0 && len == -1) {
+                            } else if (len == -1) {
+                                payload = Fountain.Util.subFountain(payload, start);
+                            } else {
+                                len = (int)Math.min(len, payload.getLength()-start);
+                                payload = Fountain.Util.subFountain(payload, start, len);
+                            }
+                            r.append("]");
+                            r.append("<"+start+"> ");
                         }
+                    } else {
+                        if (e) r.append("] ");
                     }
-                    if (e) { r.append("] "); r.append(Printer.qq(payload.getStream())); }
+                    if (e) r.append(Printer.qq(payload.getStream()));
                 }
             }
             if ((spec & PEEK) == 0 && looked_at_body && e)
@@ -530,7 +553,7 @@ public class IMAP {
                r.append(")");
                println("* " + r.toString());
            } else {
-               api.fetch(q, spec, headers, start, end, uid);
+               api.fetch(q, spec, headers, start, (len==-1?0:len), uid);
            }
         }
 
@@ -652,6 +675,20 @@ public class IMAP {
             public Token(Parser.Token[] list)      { this.s = null; n = 0;      l = list; type = LIST; }
             public Token(int number)               { this.s = null; n = number; l = null; type = NUMBER; }
 
+            public String toString() {
+                // FIXME hack
+                switch(type) {
+                    case NIL: return "NIL";
+                    case LIST: return "(" + Printer.join(", ", l) + ")";
+                    case QUOTED: return s;
+                    case NUMBER: return n+"";
+                    case ATOM: return s;
+                    case BAREWORD: return s;
+                    case SET: return "<set>";
+                }
+                return "???";
+            }
+
             public String   flag()    { if (type != ATOM) bad("expected a flag"); return s; }
             public int      n()       { if (type != NUMBER) bad("expected number"); return n; }
             public int      nz()      { int n = n(); if (n == 0) bad("expected nonzero number"); return n; }
@@ -693,6 +730,7 @@ public class IMAP {
                     else if (flag.equals("\\Draft"))    ret |= Mailbox.Flag.DRAFT;
                     else if (flag.equals("\\Answered")) ret |= Mailbox.Flag.ANSWERED;
                     else if (flag.equals("\\Recent"))   ret |= Mailbox.Flag.RECENT;
+                    else                                Log.warn(this, "unknown flag: " + flag);
                 }
                 return ret;
             }
@@ -894,5 +932,4 @@ public class IMAP {
     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;
-
 }