+ private HashMap<Integer,Integer> imapToUid = new HashMap<Integer,Integer>();
+ private HashMap<Integer,Integer> uidToImap = new HashMap<Integer,Integer>();
+ private boolean imapNumberCacheValid = false;
+ public void updateImapNumberCache() throws SQLException {
+ synchronized(this) {
+ Log.warn(this+"", "rebuilding imapNumberCache...");
+ imapToUid.clear();
+ uidToImap.clear();
+ PreparedStatement q = conn.prepareStatement("select uid_ from mail");
+ ResultSet rs = q.executeQuery();
+ try {
+ int num = 1;
+ while(rs.next()) {
+ imapToUid.put(num, rs.getInt(1));
+ uidToImap.put(rs.getInt(1), num);
+ num++;
+ }
+ imapNumberCacheValid = true;
+ } finally { db.close(rs); }
+ }
+ }
+ public int queryImapNumberCache(int uid) throws SQLException {
+ synchronized(this) {
+ if (!imapNumberCacheValid) updateImapNumberCache();
+ Integer ret = uidToImap.get(uid);
+ if (ret == null) return -1;
+ return ret;
+ }
+ }
+ public int queryUidForImapNum(int imapNumber) throws SQLException {
+ synchronized(this) {
+ if (!imapNumberCacheValid) updateImapNumberCache();
+ Integer ret = imapToUid.get(imapNumber);
+ if (ret == null) return -1;
+ return ret;
+ }
+ }
+
+
+ public int maxuid() { return uidNext(); }
+ public int uidNext() {
+ try {
+ PreparedStatement q = conn.prepareStatement("select max(uid_) from mail");
+ ResultSet rs = q.executeQuery();
+ //if (!rs.next()) return -1;
+ try {
+ if (!rs.next()) throw new RuntimeException("select max(uid_) returned no rows!");
+ return rs.getInt(1)+1;
+ } finally { db.close(rs); }
+ } catch (Exception e) { throw new RuntimeException(e); }
+ }
+
+ public Mailbox.Iterator iterator() {
+ Log.warn(this, "performance warning: called iterator() on entire mailbox");
+ Log.printStackTrace(this, Log.WARN);
+ return new SqliteJdbcIterator();
+ }
+ private String set(int[] set, String arg) {
+ String whereClause = "";
+ boolean needsOr = false;
+ for(int i=0; i<set.length; i+=2) {
+ if (needsOr) whereClause += " or ";
+ whereClause += "(";
+ whereClause += arg+">=" + set[i];
+ whereClause += " and ";
+ while(i+2 < set.length && set[i+2] == (set[i+1]+1)) i += 2;
+ whereClause += arg+"<=" + set[i+1];
+ whereClause += ")";
+ needsOr = true;
+ }
+ return whereClause;
+ }
+ private String getWhereClause(Query q) throws UnsupportedQueryException {
+ String op;
+ switch(q.type) {
+ case Query.NOT: return "not ("+getWhereClause(q.q[0])+")";
+ case Query.AND: op = "and";
+ case Query.OR: op = "or";
+ {
+ boolean add = false;
+ StringBuffer sb = new StringBuffer();
+ for(int i=0; i<q.q.length; i++) {
+ if (add) sb.append(" " + op);
+ sb.append(" (");
+ sb.append(getWhereClause(q.q[i]));
+ sb.append(")");
+ add = true;
+ }
+ return sb.toString();
+ }
+ case Query.ALL: return "1=1";
+ case Query.UID: return set(q.set, "uid_");
+ case Query.DELETED: return "((flags_ & "+(Mailbox.Flag.DELETED)+")!=0)";
+ case Query.SEEN: return "((flags_ & "+(Mailbox.Flag.SEEN)+")!=0)";
+ case Query.FLAGGED: return "((flags_ & "+(Mailbox.Flag.FLAGGED)+")!=0)";
+ case Query.DRAFT: return "((flags_ & "+(Mailbox.Flag.DRAFT)+")!=0)";
+ case Query.ANSWERED: return "((flags_ & "+(Mailbox.Flag.ANSWERED)+")!=0)";
+ case Query.RECENT: return "((flags_ & "+(Mailbox.Flag.RECENT)+")!=0)";
+ /*
+ public static final int SENT = 5;
+ public static final int ARRIVAL = 6;
+ public static final int HEADER = 7;
+ public static final int SIZE = 8;
+ public static final int BODY = 9;
+ public static final int FULL = 10;
+ public static final int IMAPNUM = 11;
+ */
+
+ case Query.IMAPNUM: {
+ try {
+ // translate queries in terms of imap numbers into queries in terms of uids
+ // RELIES ON THE FACT THAT UIDS ARE MONOTONICALLY INCREASING
+ int[] set = new int[q.set==null ? 2 : q.set.length];
+ if (q.set==null) { set[0] = q.min; set[1] = q.max; }
+ else System.arraycopy(q.set, 0, set, 0, q.set.length);
+ for(int i=0; i<set.length; i++) {
+ int uid = queryUidForImapNum(set[i]);
+ if (uid==-1) {
+ Log.info(SqliteMailbox.class, "PROBLEM => resorting to superclass: " + q);
+ throw new UnsupportedQueryException();
+ }
+ set[i] = uid;
+ }
+ return getWhereClause(Query.uid(set));
+ } catch (SQLException e) {
+ Log.error(this, e);
+ Log.info(SqliteMailbox.class, "resorting to superclass: " + q);
+ throw new UnsupportedQueryException();
+ }
+ }
+
+ default: {
+ Log.info(SqliteMailbox.class, "resorting to superclass: " + q);
+ throw new UnsupportedQueryException();
+ }
+ }
+ }
+ private static class UnsupportedQueryException extends Exception { }
+ public Mailbox.Iterator iterator(Query q) {