From 260c2d47c04ee6f82462a3a414ff02fbd71db733 Mon Sep 17 00:00:00 2001 From: adam Date: Sat, 12 Jun 2004 06:19:00 +0000 Subject: [PATCH] able to load headers and message body in mozilla darcs-hash:20040612061900-5007d-87b52a5d8924a72a8b7fd7adb1eac2a879771f43.gz --- src/org/ibex/mail/Query.java | 10 +- src/org/ibex/mail/protocol/IMAP.java | 231 ++++++++++++++++++++++++++-------- 2 files changed, 183 insertions(+), 58 deletions(-) diff --git a/src/org/ibex/mail/Query.java b/src/org/ibex/mail/Query.java index 8dcd389..4037b4b 100644 --- a/src/org/ibex/mail/Query.java +++ b/src/org/ibex/mail/Query.java @@ -78,10 +78,14 @@ public class Query { case NOT: return !q[0].match(it); case OR: for(int i=0; i= min && it.uid() <= max; - case NUM: if (set != null){for(int i=0; i= it.uid()) return true; + return false; } else return it.uid() >= min && it.uid() <= max; + case NUM: if (set != null) { + for(int i=0; i= it.num()) return true; + return false; } + else return it.num() >= min && it.num() <= max; case SENT: return (latest==null||it.cur().date.before(latest)) && (earliest==null||it.cur().date.after(earliest)); case ARRIVAL: return (latest == null || it.cur().arrival.before(latest)) && diff --git a/src/org/ibex/mail/protocol/IMAP.java b/src/org/ibex/mail/protocol/IMAP.java index d98572e..04d7194 100644 --- a/src/org/ibex/mail/protocol/IMAP.java +++ b/src/org/ibex/mail/protocol/IMAP.java @@ -156,54 +156,67 @@ public class IMAP extends MessageProtocol { if (flags != null) { /* FEATURE */ } } - public void fetch(Query q, Token t) { - Token[] tl = null; - int start = -1, end = -1; - boolean peek = false, fast = false, all = false, full = false; - if (t == null) { tl = new Token[] { new Token("BODY", false) }; } - else if (t.type == Token.LIST) tl = t.l(); - else if (t.atom().equals("FULL")) full = true; - else if (t.atom().equals("ALL")) all = true; - else if (t.atom().equals("FAST")) fast = true; - StringBuffer reply = new StringBuffer(); + public static String qq(String s) { + StringBuffer ret = new StringBuffer(s.length() + 20); + ret.append('{'); + ret.append(s.length()); + ret.append('}'); + ret.append('\r'); + ret.append('\n'); + ret.append(s); + ret.append('\r'); + ret.append('\n'); + return ret.toString(); + } + + public void fetch(Query q, FetchRequest[] fr, boolean uid) { + System.err.println("query == " + q); for(Mailbox.Iterator it = selected.iterator(q); it.next(); ) { Message m = it.cur(); - for (int i=0; i')); - s = s.substring(0, s.indexOf('<')); - if (range.indexOf(imapSeparator) == -1) end = Integer.MAX_VALUE; - else { - end = Integer.parseInt(range.substring(range.indexOf(imapSeparator) + 1)); - range = range.substring(0, range.indexOf(imapSeparator)); + System.err.println("message == " + m); + StringBuffer reply = new StringBuffer(); + boolean peek = false; + for(int i=0; i" + qq(payload.substring(0, frb.end + 1))); + else reply.append("<" + frb.start + "." + frb.end + ">" + qq(payload.substring(frb.start, frb.end + 1))); + } else throw new Error("this should never happen"); + star((uid ? it.uid() : it.num()) + " FETCH (" + reply.toString() + (uid ? " UID " + it.uid() : "") + ")"); + if (!peek) it.seen(true); } } + // FEATURE: hoist the parsing here public void store(Query q, String what, Token[] flags) { for(Mailbox.Iterator it = selected.iterator(q); it.next(); ) { @@ -239,6 +252,8 @@ public class IMAP extends MessageProtocol { 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("SUBSCRIBE")) { /* FIXME */ } + else if (command.equalsIgnoreCase("UNSUBSCRIBE")) { /* FIXME */ } else if (command.equalsIgnoreCase("CAPABILITY")) { capability(); } else if (command.equalsIgnoreCase("LOGIN")) login(astring(), astring()); else if (command.equalsIgnoreCase("LOGOUT")) { logout(); conn.close(); return false; } @@ -252,11 +267,12 @@ public class IMAP extends MessageProtocol { 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("FETCH")) fetch(uid ? Query.uid(set()) : Query.num(set()), + parseFetchRequest(l()), uid); else if (command.equalsIgnoreCase("STATUS")) status(mailbox(), l()); else throw new Exn.Bad("unrecognized command \"" + command + "\""); - pw.println(tag + " OK " + command + " Completed."); - System.err.println(tag + " OK " + command + " Completed."); + pw.println(tag + " OK uid " + command + " Completed."); + System.err.println(tag + " OK uid " + 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()); } @@ -354,10 +370,10 @@ public class IMAP extends MessageProtocol { } class Token { - private byte type; - private final String s; - private final Token[] l; - private final int n; + public byte type; + public final String s; + public final Token[] l; + public final int n; private static final byte NIL = 0; private static final byte LIST = 1; private static final byte QUOTED = 2; @@ -409,13 +425,14 @@ public class IMAP extends MessageProtocol { String end_s = s.substring(s.indexOf(':')+1); if (end_s.equals("*")) { ids.addElement(new Integer(start)); - ids.addElement(new Integer(-1)); + ids.addElement(new Integer(Integer.MAX_VALUE)); } else { int end = Integer.parseInt(end_s); for(int j=start; j<=end; j++) ids.addElement(new Integer(j)); } } else { ids.addElement(new Integer(Integer.parseInt(s))); + ids.addElement(new Integer(Integer.parseInt(s))); } } int[] ret = new int[ids.size()]; @@ -512,18 +529,21 @@ public class IMAP extends MessageProtocol { else sb.append(c); } return new Token(sb.toString(), true); - } else if (c == ')') { - return null; - } else if (c == '(') { + + // NOTE: this is technically a violation of the IMAP grammar, since atoms like FOO[BAR should be legal + } else if (c == ']' || c == ')') { return null; + } else if (c == '[' || c == '(') { Token t; do { t = token(); if (t != null) toks.addElement(t); } while (t != null); Token[] ret = new Token[toks.size()]; toks.copyInto(ret); - return null; // FIXME + return new Token(ret); // FIXME + } else while(true) { sb.append(c); c = peekc(); - if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '{' || c == '\n' || c == '\r') + if (c == ' ' || c == '\"' || c == '(' || c == ')' || c == '[' || c == ']' || + c == '{' || c == '\n' || c == '\r') return new Token(sb.toString(), false); getc(); } @@ -547,5 +567,106 @@ public class IMAP extends MessageProtocol { public String astring() throws Exn.Bad { return token().astring(); } public String atom() throws Exn.Bad { return token().atom(); } public Mailbox mailbox() throws Exn.Bad, IOException { return token().mailbox(); } + + public final FetchRequest BODYSTRUCTURE = new FetchRequest(); + public final FetchRequest ENVELOPE = new FetchRequest(); + public final FetchRequest FLAGS = new FetchRequest(); + public final FetchRequest INTERNALDATE = new FetchRequest(); + public final FetchRequest RFC822 = new FetchRequest(); + public final FetchRequest RFC822HEADER = new FetchRequest(); + public final FetchRequest RFC822SIZE = new FetchRequest(); + public final FetchRequest RFC822TEXT = new FetchRequest(); + public final FetchRequest UID = new FetchRequest(); + public final FetchRequest BODY = new FetchRequest(); + public final FetchRequest BODYPEEK = new FetchRequest(); + public class FetchRequest { + } + public class FetchRequestBody extends FetchRequest { + int type = 0; + boolean peek = false; + int[] path = null; + int start = -1; + int end = -1; + Token[] headers = null; + public static final int PATH = 0; + public static final int TEXT = 1; + public static final int MIME = 2; + public static final int HEADER = 3; + public static final int FIELDS = 4; + public static final int FIELDS_NOT= 5; + } + + public FetchRequest[] parseFetchRequest(Token[] t) { + FetchRequest[] ret = new FetchRequest[t.length]; + for(int i=0; i")) { + startend = s.substring(s.indexOf('<'), s.indexOf('>')); + s = s.substring(0, s.indexOf('<')); + } + + if (s.equalsIgnoreCase("BODY.PEEK")) b.peek = true; + else if (s.equalsIgnoreCase("BODY")) b.peek = false; + else throw new Exn.No("unknown fetch argument: " + s); + + if (i= '0' && s2.charAt(0) <= '9') { + mimeVec.addElement(new Integer(Integer.parseInt(s2.substring(0, s2.indexOf('.'))))); + s2 = s2.substring(s2.indexOf('.') + 1); + } + if (mimeVec.size() > 0) { + b.path = new int[mimeVec.size()]; + for(int j=0; j