rename SqliteJdbcMailbox -> SqliteMailbox
[org.ibex.mail.git] / src / org / ibex / mail / SqliteMailbox.java
diff --git a/src/org/ibex/mail/SqliteMailbox.java b/src/org/ibex/mail/SqliteMailbox.java
new file mode 100644 (file)
index 0000000..66ed674
--- /dev/null
@@ -0,0 +1,108 @@
+package org.ibex.mail;
+
+import org.ibex.io.Fountain;
+import org.ibex.io.Stream;
+import java.sql.Timestamp;
+import java.sql.*;
+import java.net.*;
+import java.io.*;
+import java.util.*;
+
+// nntpNumber (column)
+// uid (column)
+// uidvalidity
+public class SqliteMailbox extends Mailbox.Default {
+
+    private Connection conn;
+    private static final String columns  =
+        "                                        messageid_,       from_,to_,date_,subject_,headers_,body_,flags_";
+
+    /**
+     *  from http://www.sqlite.org/autoinc.html
+     *  "If a column has the type INTEGER PRIMARY KEY AUTOINCREMENT
+     *   then a slightly different ROWID selection algorithm is
+     *   used. The ROWID chosen for the new row is one larger than the
+     *   largest ROWID that has ever before existed in that same
+     *   table. If the table has never before contained any data, then
+     *   a ROWID of 1 is used. If the table has previously held a row
+     *   with the largest possible ROWID, then new INSERTs are not
+     *   allowed and any attempt to insert a new row will fail with an
+     *   SQLITE_FULL error.
+     */
+    private static final String columns_ =
+        "uid_ INTEGER PRIMARY KEY AUTOINCREMENT, messageid_ unique,from_,to_,date_,subject_,headers_,body_,flags_";
+
+    public SqliteMailbox(String filename) {
+        try {
+            Class.forName("org.sqlite.JDBC");
+            conn = DriverManager.getConnection("jdbc:sqlite:"+filename);
+            conn.prepareStatement("create virtual table if not exists 'mail' using FTS2("+columns_+")").executeUpdate();
+        }
+        catch (SQLException e) { throw new RuntimeException(e); }
+        catch (ClassNotFoundException e) { throw new RuntimeException(e); }
+    }
+
+    public int              uidNext()                    { throw new RuntimeException("not supported"); }
+    public Mailbox.Iterator iterator()                   { return new SqliteJdbcIterator(); }
+    public void             insert(Message m, int flags) {
+        // FIXME: flags
+        try {
+            PreparedStatement add =
+                conn.prepareStatement("insert into 'mail' ("+columns+") values (?,?,?,?,?,?,?,?)");
+            add.setString(1, m.messageid+"");
+            add.setString(2, m.from+"");
+            add.setString(3, m.to+"");
+            add.setString(4, m.date+"");
+            add.setString(5, m.subject+"");
+            add.setString(6, streamToString(m.headers.getStream()));
+            add.setString(7, streamToString(m.getBody().getStream()));
+            add.setInt   (8, flags);
+            add.executeUpdate();
+        } catch (Exception e) { throw new RuntimeException(e); }
+    }
+
+    private class SqliteJdbcIterator extends Mailbox.Default.Iterator {
+        // could be more efficient in a ton of ways
+        private ResultSet rs;
+        private int count  = 1;
+        private int flags;
+        private Message m  = null;
+        public SqliteJdbcIterator() {
+            try {
+                PreparedStatement query = conn.prepareStatement("select messageid_ from 'mail'");
+                rs = query.executeQuery();
+                rs.next();
+            } catch (Exception e) { throw new RuntimeException(e); }
+        }
+        public Message cur()    {
+            try {
+                if (m!=null) return m;
+                rs.next();
+                PreparedStatement query = conn.prepareStatement("select headers_,body_,flags_ from 'mail' where messageid_=?");
+                query.setString(1, rs.getString(1));
+                ResultSet rs2 = query.executeQuery();
+                if (!rs.next()) return null;
+                m = Message.newMessage(Fountain.Util.concat(Fountain.Util.create(rs.getString(1)),
+                                                            Fountain.Util.create("\r\n\r\n"),
+                                                            Fountain.Util.create(rs.getString(2))));
+                flags = rs.getInt(3);
+                return m;
+            } catch (Exception e) { throw new RuntimeException(e); }
+        }
+        public int     getFlags()   { if (m==null) /* could be more efficient */ cur(); return flags; }
+        public Headers head()       { return cur().headers; }
+        public boolean next()       { try { m = null; count++; return rs.next(); } catch (Exception e) { throw new RuntimeException(e); } }
+        public int     uid()        { throw new RuntimeException("not supported"); }
+        public int     imapNumber() { return count; }
+        public int     nntpNumber() { throw new RuntimeException("not supported"); }
+        public void    delete()     { throw new RuntimeException("not supported"); }
+    }
+
+    private static String streamToString(Stream stream) throws Exception {
+        StringBuffer b = new StringBuffer();
+        for(String s = stream.readln(); s!=null; s=stream.readln())
+            b.append(s+"\n");
+        return b.toString();
+    }
+
+}