From: adam Date: Mon, 31 May 2004 06:13:08 +0000 (+0000) Subject: restructuring; broke out Query, cleaned up Mailbox X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=034f6baad8db618ac7c3a93a5653b2071cf5f796;p=org.ibex.mail.git restructuring; broke out Query, cleaned up Mailbox darcs-hash:20040531061308-5007d-fe7e563b65b1ed9b90425754bf769009c64af353.gz --- diff --git a/src/org/ibex/mail/Flag.java b/src/org/ibex/mail/Flag.java new file mode 100644 index 0000000..9707d76 --- /dev/null +++ b/src/org/ibex/mail/Flag.java @@ -0,0 +1,10 @@ +package org.ibex.mail; + +public class Flag { + public static final int DELETED = 0x0001; + public static final int SEEN = 0x0002; + public static final int FLAGGED = 0x0004; + public static final int DRAFT = 0x0010; + public static final int ANSWERED = 0x0020; + public static final int RECENT = 0x0040; +} diff --git a/src/org/ibex/mail/MIME.java b/src/org/ibex/mail/MIME.java new file mode 100644 index 0000000..76ea5b1 --- /dev/null +++ b/src/org/ibex/mail/MIME.java @@ -0,0 +1,7 @@ +package org.ibex.mail; + +// FEATURE: MIME RFC2045, 2046, 2049 + +/** This class contains logic for encoding and decoding MIME multipart messages */ +public class MIME { +} diff --git a/src/org/ibex/mail/Message.java b/src/org/ibex/mail/Message.java index 5ee6864..9e2105b 100644 --- a/src/org/ibex/mail/Message.java +++ b/src/org/ibex/mail/Message.java @@ -11,14 +11,22 @@ import java.io.*; // folded headers: can insert CRLF anywhere that whitespace appears (before the whitespace) // date/time parsing: see spec, 3.3 -// FEATURE: MIME RFC2045, 2046, 2049 // FEATURE: PGP-signature-parsing // FEATURE: mailing list header parsing // FEATURE: delivery status notification (and the sneaky variety) // FEATURE: threading as in http://www.jwz.org/doc/threading.html +// FEATURE: lazy body +/** + * [immutable] This class encapsulates a message "floating in the + * ether": RFC2822 data but no storage-specific flags or other + * metadata. + */ public class Message extends JSReflection { + public static interface Visitor { public abstract void visit(Message m); } + + // FIXME make this immutable private static class CaseInsensitiveHash extends Hashtable { public Object get(Object o) { if (o instanceof String) return super.get(((String)o).toLowerCase()); diff --git a/src/org/ibex/mail/Query.java b/src/org/ibex/mail/Query.java index e39f8b4..45b5659 100644 --- a/src/org/ibex/mail/Query.java +++ b/src/org/ibex/mail/Query.java @@ -1,29 +1,76 @@ package org.ibex.mail; import java.util.*; +/** + * [immutable] This class encapsulates a query against a mailbox. + * + * The default implementation of Mailbox.query() simply retrieves + * each message and calls Query.match() on it to filter out any + * messages which do not match. + * + * Production-quality Mailbox implementations will want to inspect + * the Query object passed to Mailbox.query() to perform more + * efficient queries. + */ public class Query { - public static Query not(Query q) { return null; } - public static Query and(Query a1, Query a2) { return null; } - public static Query or(Query a1, Query a2) { return null; } - public static Query set(int[] set) { return null; } - public static Query sent(Date d, boolean foo0, boolean foo) { return null; } - public static Query arrival(Date d, boolean foo, boolean bar) { return null; } - public static Query uid(int uid) { return null; } - public static Query uid(int[] uid) { return null; } - public static Query header(String name) { return null; } - public static Query header(String name, String val) { return null; } - public static Query size(int size, boolean foo) { return null; } - public static Query fullText(String searchFor, boolean foo, boolean bar) { return null; } + public static Query not(Query q) { return new Query(NOT, new Query[] { q }, 0, 0, 0, null, null, null, null); } + public static Query and(Query q1, Query q2) { return new Query(AND, new Query[] { q1, q2 }, 0, 0, 0, null, null, null, null); } + public static Query and(Query[] q) { return new Query(AND, q, 0, 0, 0, null, null, null, null); } + public static Query or(Query q1, Query q2) { return new Query(OR, new Query[] { q1, q2 }, 0, 0, 0, null, null, null, null); } + public static Query or(Query[] q) { return new Query(OR, q, 0, 0, 0, null, null, null, null); } + public static Query uid(int min, int max) { return new Query(UID, null, min, max, 0, null, null, null, null); } + public static Query messagenum(int min, int max) { return new Query(MESSAGENUM, null, min, max, 0, null, null, null, null); } + public static Query sent(Date earliest, Date latest) { return new Query(SENT, null,0,0,0,null,null, earliest, latest); } + public static Query arrival(Date earliest, Date latest) { return new Query(ARRIVAL, null,0,0,0,null,null, earliest, latest); } + public static Query header(String name, String val) { return new Query(HEADER, null, 0, 0, 0, name, val, null, null); } + public static Query size(int min, int max) { return new Query(SIZE, null, min, max, 0, null, null, null, null); } + public static Query body(String text) { return new Query(BODY, null, 0, 0, 0, null, text, null, null); } + public static Query flags(int flags) { return new Query(FLAGS, null, 0, 0, flags, null, null, null, null); } - // FIXME - public static class Flag { - public static final Query ANSWERED = null; - public static final Query SEEN = null; - public static final Query DRAFT = null; - public static final Query FLAGGED = null; - public static final Query RECENT = null; - public static final Query DELETED = null; + private Query(int type, Query[] q, int min, int max, int flags, String key, String text, Date earliest, Date latest) { + this.type = type; this.q = q; this.min = min; this.max = max; this.flags = flags; this.key = key; this.text = text; + this.earliest = earliest; this.latest = latest; } + + public static int ALL = 0; + public static int NOT = 1; + public static int AND = 2; + public static int OR = 3; + public static int UID = 4; + public static int MESSAGENUM = 5; + public static int SENT = 6; + public static int ARRIVAL = 7; + public static int HEADER = 8; + public static int SIZE = 9; + public static int FLAGS = 10; + public static int BODY = 11; + + public final int type; + public final Query[] q; + public final int min; + public final int max; + public final int flags; + public final String key; + public final String text; + public final Date earliest; + public final Date latest; + + public boolean match(Mailbox mbox, Message m) { + switch(type) { + case ALL: return true; + case NOT: return !q[0].match(mbox, m); + case OR: for(int i=0; i= min && mbox.uid <= max; + case MESSAGENUM: return mbox.messagenum(m) >= min && mbox.messagenum(m) <= max; + case SENT: return (latest == null || m.sent.before(latest)) &&(earliest == null || m.sent.after(earliest)); + case ARRIVAL: return (latest == null || m.arrival.before(latest)) &&(earliest == null || m.arrival.after(earliest)); + case SIZE: return m.size >= min && m.size <= max; + case FLAGS: return mbox.getFlags(flags); + case HEADER: return m.headers.get(key) != null && ((String)m.headers.get(key)).indexOf(text) != -1; + case HEADER: return m.body.indexOf(text) != -1; + default: throw new Error("this should not happen"); + } } } diff --git a/src/org/ibex/mail/target/Mailbox.java b/src/org/ibex/mail/target/Mailbox.java index 53ce945..a7f32d5 100644 --- a/src/org/ibex/mail/target/Mailbox.java +++ b/src/org/ibex/mail/target/Mailbox.java @@ -7,80 +7,35 @@ import java.net.*; import java.util.*; import java.text.*; -// FIXME: appallingly inefficient public class Mailbox extends Target { - private static final String STORAGE_ROOT = - System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail"); - public static FileBased root = null; - public static Transcript transcript = null; - static { - try { - root = new FileBased(STORAGE_ROOT + File.separatorChar); - transcript = new Transcript(STORAGE_ROOT + File.separatorChar + "transcript"); - } catch (Exception e) { - e.printStackTrace(); - } - } + // metadata + public void set(Message m, String key, String val) { throw new MailException.MetadataNotSupported(); } + public String get(Message m, String key) { throw new MailException.MetadataNotSupported(); } + + // flags + public final boolean getFlag(Message m, int flags) { return (flags(m) & flag) == flags; } + public final void setFlag(Message m, int flag) { flags(m, flags | flag); } + public final void clearFlag(Message m, int flag) { flags(m, flags & ~flag); } + protected abstract void flags(Message m, int newFlags); // set the flags for a given message + protected abstract int flags(Message m); // get the flags for a given message + public abstract int uid(Message m); // get the uid for a given message (see IMAP RFC) + public abstract int num(Message m); // get the "message number" for a given message (see IMAP RFC) + public abstract int uidNext(); // get the next uid to be assigned + public abstract int uidValidity(); // get the uid validity identifier (see IMAP RFC) + + // messages + public int add(Message message) throws MailException { throw new Error("not implemented"); } + public int delete(Message message) throws MailException { throw new Error("not implemented"); } + public void query(Query q, Message.Visitor v) throws MailException { throw new Error("not implemented"); } + public int count(Query q) throws MailException { throw new Error("not implemented"); } + public void move(Query q, Mailbox dest, boolean copy) throws MailException { throw new Error("not implemented"); } + + // submailboxes + public void rename(String newName) throws MailException { throw new Error("not implemented"); } + public void destroy() throws MailException { throw new Error("not implemented"); } + public Mailbox slash(String name, boolean create) throws MailException { throw new Error("not implemented"); } - public int uidvalidity; - public int uidnext; - - public void setDeleted(int i, boolean b) { } - public void setSeen(int i, boolean b) { } - public void setFlagged(int i, boolean b) { } - public void setDraft(int i, boolean b) { } - public void setAnswered(int i, boolean b) { } - public void setRecent(int i, boolean b) { } - public boolean deleted(int i) { return false; } - public boolean seen(int i) { return false; } - public boolean flagged(int i) { return false; } - public boolean draft(int i) { return false; } - public boolean answered(int i) { return false; } - public boolean recent(int i) { return false; } - public int uid(int i) { return -1; } - public int uid(Message m) { return -1; } - - public void moveAllMessagesTo(Mailbox m) throws MailException { throw new Error("moveAllMessagesTo() not implemented"); } - public String getName() throws MailException { throw new Error("Mailbox.getName() not implemented"); } - public void rename(String newName) throws MailException { throw new Error("Mailbox.rename() not implemented"); } - public void destroy() throws MailException { throw new Error("Mailbox.destroy() not implemented"); } - public void accept(Message m) throws MailException { add(m); } - public Mailbox slash(String name) throws MailException { return slash(name, false); } - public Mailbox slash(String name, boolean create) throws MailException { - throw new Error(this.getClass().getName() + " does not support the slash() method"); } - public int[] list() { throw new Error(this.getClass().getName() + " does not support the list() method"); } - public int add(Message message) throws MailException { - throw new Error(this.getClass().getName() + " does not support the add() method"); } - public int delete(Message message) throws MailException { - throw new Error(this.getClass().getName() + " does not support the delete() method"); } - public Message get(int messagenum) throws MailException { - throw new Error(this.getClass().getName() + " does not support the get() method"); } - public Message[] query(int maxResults) { - throw new Error(this.getClass().getName() + " does not support the query() method"); } - /* - public static class Mailbox extends Mailbox { - String user; - private static Hashtable cache = new Hashtable(); - public static Mailbox getForUser(String user) { - Mailbox ret = (Mailbox)cache.get(user); - if (ret == null) ret = new Mailbox(user); - return ret; - } - Mailbox(String user) { this.user = user; } - public Mailbox slash(String name) throws MailException { - throw new Error(this.getClass().getName() + " does not support the slash() method"); } - public synchronized int add(Message message) throws MailException { - FileOutputStream fos = new FileOutputStream("/var/mail/" + user, true); - PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos)); - pw.println("From " + message.envelopeFrom); - pw.flush(); - message.dump(fos); - fos.close(); - return -1; - } - } - */ /** a fast-write, slow-read place to stash all messages we touch -- in case of a major f*ckup */ public static class Transcript extends Mailbox { private String path; @@ -179,4 +134,40 @@ public class Mailbox extends Target { } + + String user; + private static Hashtable cache = new Hashtable(); + public static Mailbox getForUser(String user) { + Mailbox ret = (Mailbox)cache.get(user); + if (ret == null) ret = new Mailbox(user); + return ret; + } + Mailbox(String user) { this.user = user; } + public Mailbox slash(String name) throws MailException { + throw new Error(this.getClass().getName() + " does not support the slash() method"); } + public synchronized int add(Message message) throws MailException { + FileOutputStream fos = new FileOutputStream("/var/mail/" + user, true); + PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos)); + pw.println("From " + message.envelopeFrom); + pw.flush(); + message.dump(fos); + fos.close(); + return -1; + } + + + private static final String STORAGE_ROOT = + System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail"); + public static FileBased root = null; + public static Transcript transcript = null; + static { + try { + root = new FileBased(STORAGE_ROOT + File.separatorChar); + transcript = new Transcript(STORAGE_ROOT + File.separatorChar + "transcript"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public final void accept(Message m) throws MailException { add(m); } }