public int unseen(String mailbox);
public int recent(String mailbox);
public int count(String mailbox);
+ public int count();
+ public int maxuid();
public int uidNext(String mailbox);
public int uidValidity(String mailbox);
public int[] search(Query q, boolean uid);
public void expunge(Mailbox.Iterator it) { client.expunge(it.uid()); 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;
+ }
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()); }
public int count(String mailbox) { return mailbox(mailbox, false).count(Query.all()); }
+ public int count() { return selected().count(Query.all()); }
public int uidNext(String mailbox) { return mailbox(mailbox, false).uidNext(); }
public int uidValidity(String mailbox) { return mailbox(mailbox, false).uidValidity(); }
public void select(String mailbox, boolean examineOnly) {
private void doFlags(Query q, int flags, boolean uid, int style, boolean silent) {
for(Mailbox.Iterator it = selected().iterator(q);it.next();) {
boolean recent = it.recent();
+ try { throw new Exception("flags " + flags); } catch (Exception e) { Log.error(this, e); }
if (style == -1) it.removeFlags(flags);
else if (style == 0) it.setFlags(flags);
else if (style == 1) it.addFlags(flags);
it.recent(recent);
- // FIXME
- //if (!silent) client.fetch(it.num(), it.flags(), -1, null, it.uid());
+ if (!silent) client.fetch(it.num(), it.flags(), -1, null, it.uid());
}
}
public void rename(String from0, String to) {
Parser.Token token() { return parser.token(); }
void println(String s) { conn.println(s); }
void newline() { parser.newline(); }
- Query query() { return parser.query(); }
+ Query query(int max) { return parser.query(max, maxn(true)); }
public void login(String u, String p) {
Object ret;
}
}
+ private int maxn(boolean uid) { return uid ? api.maxuid() : api.count(); }
+
public void handleRequest(Connection conn) {
this.conn = conn;
parser = new Parser(conn);
case SUBSCRIBE: api.subscribe(token().astring()); break;
case UNSUBSCRIBE: api.unsubscribe(token().astring()); break;
case RENAME: api.rename(token().astring(), token().astring()); break;
- case COPY: selected(); api.copy(Query.set(uid, token().set()), token().astring()); break;
+ case COPY: selected(); api.copy(Query.set(uid, token().set(maxn(uid))), token().astring()); break;
case DELETE: api.delete(token().atom()); break;
case CHECK: selected(); api.check(); break;
case NOOP: api.noop(); break;
case EXPUNGE: selected(); api.expunge(); break;
case UNSELECT: selected(); api.unselect(); selected = false; break;
case CREATE: api.create(token().astring()); break;
- case FETCH: selected(); fetch(Query.set(lastuid=uid, token().set()),
+ case FETCH: selected(); fetch(Query.set(lastuid=uid, token().set(maxn(uid))),
lastfetch=token().lx(), 0, 0, 0, uid, 0); break;
case SEARCH: selected(); println("* SEARCH " + Printer.join(api.search(query(), uid))); break;
case EXAMINE:
break; }
case STORE: {
selected();
- Query q = uid ? Query.uid(token().set()) : Query.num(token().set());
+ Query q = uid ? Query.uid(token().set(maxn(uid))) : Query.num(token().set(maxn(uid)));
String s = token().atom().toUpperCase();
int flags = token().flags();
if (s.equals("FLAGS")) api.setFlags(q, flags, uid, false);
* - 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) {
- Query q = o instanceof Query ? (Query)o : null;
- Message m = o instanceof Message ? (Message)o : null;
+ 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;
lastfetch = t;
String[] headers = null;
int start = -1, end = -1;
StringBuffer r = new StringBuffer();
- if (e) { r.append(uid ? muid : num); r.append(" FETCH ("); }
+ if (e) { r.append(num); r.append(" FETCH ("); }
int initlen = r.length();
if (uid) {
boolean good = false;
private Stream stream;
public Parser(Stream from) { this.stream = from; }
public Token token(String s) { return new Token(s); }
- protected Query query() {
+ protected Query query(int max, int maxuid) {
String s = null;
boolean not = false;
Query q = null;
+ Query ret = null;
while(true) {
Parser.Token t = token(false);
if (t == null) break;
if (t.type == t.LIST) throw new Server.No("nested queries not yet supported FIXME");
- else if (t.type == t.SET) return Query.num(t.set());
+ else if (t.type == t.SET) return Query.num(t.set(max));
s = t.atom().toUpperCase();
- if (s.equals("NOT")) { not = true; continue; }
- if (s.equals("OR")) return Query.or(query(), query()); // FIXME parse rest of list
- if (s.equals("AND")) return Query.and(query(), query());
+ if (s.equals("NOT")) return Query.not(query(max, maxuid));
+ if (s.equals("OR")) return Query.or(query(max, maxuid), query(max, maxuid)); // FIXME parse rest of list
+ if (s.equals("AND")) return Query.and(query(max, maxuid), query(max, maxuid));
+
+ if (s.startsWith("UN")) { not = true; s = s.substring(2); }
+ if (s.equals("ANSWERED")) q = Query.answered();
+ else if (s.equals("DELETED")) q = Query.deleted();
+ else if (s.equals("ALL")) q = Query.all();
+ else if (s.equals("DRAFT")) q = Query.draft();
+ else if (s.equals("FLAGGED")) q = Query.flagged();
+ else if (s.equals("RECENT")) q = Query.recent();
+ else if (s.equals("SEEN")) q = Query.seen();
+ else if (s.equals("OLD")) { not = true; q = Query.recent(); }
+ else if (s.equals("NEW")) q = Query.and(Query.recent(), Query.not(Query.seen()));
+ else if (s.equals("KEYWORD")) q = Query.header("keyword", token().flag());
+ else if (s.equals("HEADER")) q = Query.header(token().astring(), token().astring());
+ else if (s.equals("BCC")) q = Query.header("bcc", token().astring());
+ else if (s.equals("CC")) q = Query.header("cc", token().astring());
+ else if (s.equals("FROM")) q = Query.header("from", token().astring());
+ else if (s.equals("TO")) q = Query.header("to", token().astring());
+ else if (s.equals("SUBJECT")) q = Query.header("subject", token().astring());
+ else if (s.equals("LARGER")) q = Query.size(token().n(), Integer.MAX_VALUE);
+ else if (s.equals("SMALLER")) q = Query.size(Integer.MIN_VALUE, token().n());
+ else if (s.equals("BODY")) q = Query.body(token().astring());
+ else if (s.equals("TEXT")) q = Query.full(token().astring());
+ else if (s.equals("BEFORE")) q = Query.arrival(new Date(0), token().date());
+ else if (s.equals("SINCE")) q = Query.arrival(token().date(), new Date(Long.MAX_VALUE));
+ else if (s.equals("ON")) { Date d = token().date(); q = Query.arrival(d, new Date(d.getTime() + 24 * 60 * 60)); }
+ else if (s.equals("SENTBEFORE")) q = Query.sent(new Date(0), token().date());
+ else if (s.equals("SENTSINCE")) q = Query.sent(token().date(), new Date(Long.MAX_VALUE));
+ else if (s.equals("SENTON")) { Date d = token().date(); q = Query.sent(d, new Date(d.getTime() + 24 * 60 * 60)); }
+ else if (s.equals("UID")) q = Query.uid(token().set(max));
+ q = not ? Query.not(q) : q;
+ ret = ret == null ? q : Query.and(ret, q);
}
- if (s.startsWith("UN")) { not = true; s = s.substring(2); }
- if (s.equals("ANSWERED")) q = Query.answered();
- else if (s.equals("DELETED")) q = Query.deleted();
- else if (s.equals("ALL")) q = Query.all();
- else if (s.equals("DRAFT")) q = Query.draft();
- else if (s.equals("FLAGGED")) q = Query.flagged();
- else if (s.equals("RECENT")) q = Query.recent();
- else if (s.equals("SEEN")) q = Query.seen();
- else if (s.equals("OLD")) { not = true; q = Query.recent(); }
- else if (s.equals("NEW")) q = Query.and(Query.recent(), Query.not(Query.seen()));
- else if (s.equals("KEYWORD")) q = Query.header("keyword", token().flag());
- else if (s.equals("HEADER")) q = Query.header(token().astring(), token().astring());
- else if (s.equals("BCC")) q = Query.header("bcc", token().astring());
- else if (s.equals("CC")) q = Query.header("cc", token().astring());
- else if (s.equals("FROM")) q = Query.header("from", token().astring());
- else if (s.equals("TO")) q = Query.header("to", token().astring());
- else if (s.equals("SUBJECT")) q = Query.header("subject", token().astring());
- else if (s.equals("LARGER")) q = Query.size(token().n(), Integer.MAX_VALUE);
- else if (s.equals("SMALLER")) q = Query.size(Integer.MIN_VALUE, token().n());
- else if (s.equals("BODY")) q = Query.body(token().astring());
- else if (s.equals("TEXT")) q = Query.full(token().astring());
- else if (s.equals("BEFORE")) q = Query.arrival(new Date(0), token().date());
- else if (s.equals("SINCE")) q = Query.arrival(token().date(), new Date(Long.MAX_VALUE));
- else if (s.equals("ON")) { Date d = token().date(); q = Query.arrival(d, new Date(d.getTime() + 24 * 60 * 60)); }
- else if (s.equals("SENTBEFORE")) q = Query.sent(new Date(0), token().date());
- else if (s.equals("SENTSINCE")) q = Query.sent(token().date(), new Date(Long.MAX_VALUE));
- else if (s.equals("SENTON")) { Date d = token().date(); q = Query.sent(d, new Date(d.getTime() + 24 * 60 * 60)); }
- else if (s.equals("UID")) q = Query.uid(token().set());
- return not ? Query.not(q) : q;
+ return ret;
}
private static void bad(String s) { throw new Server.Bad(s); }
}
return ret;
}
- public int[] set() {
+ public int[] set(int largest) {
if (type != ATOM) bad("expected a messageid set");
Vec.Int ids = new Vec.Int();
StringTokenizer st = new StringTokenizer(s, ",");
while(st.hasMoreTokens()) {
String s = st.nextToken();
if (s.indexOf(':') == -1) {
- if (s.equals("*")) {
- ids.addElement(0);
- ids.addElement(Integer.MAX_VALUE);
- } else {
- ids.addElement(Integer.parseInt(s));
- ids.addElement(Integer.parseInt(s));
- }
- continue; }
+ if (s.equals("*")) {
+ ids.addElement(largest);
+ ids.addElement(largest);
+ } else {
+ ids.addElement(Integer.parseInt(s));
+ ids.addElement(Integer.parseInt(s));
+ }
+ continue; }
int start = Integer.parseInt(s.substring(0, s.indexOf(':')));
String end_s = s.substring(s.indexOf(':')+1);
- if (end_s.equals("*")) { ids.addElement(start); ids.addElement(Integer.MAX_VALUE); }
- else {
- int end = Integer.parseInt(end_s);
- for(int j=Math.min(start,end); j<=Math.max(start,end); j++) {
- ids.addElement(j);
- ids.addElement(j);
- }
+ int end = end_s.equals("*") ? largest : Integer.parseInt(end_s);
+ for(int j=Math.min(start,end); j<=Math.max(start,end); j++) {
+ ids.addElement(j);
+ ids.addElement(j);
}
}
return ids.dump();
public static String qq(String s) {
StringBuffer ret = new StringBuffer();
ret.append('{');
- ret.append(s.length());
+ ret.append(s.getBytes().length);
ret.append('}');
ret.append('\r');
ret.append('\n');