From: adam Date: Sat, 23 Oct 2004 05:31:16 +0000 (+0000) Subject: more fixups to FileBasedMailbox (sigh) X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=15f9f7dd7d8acd0f5021189248d775e53116ec1b;p=org.ibex.mail.git more fixups to FileBasedMailbox (sigh) darcs-hash:20041023053116-5007d-c28fbcdd411b701bdc174eea5bf4c40f1be2a330.gz --- diff --git a/src/org/ibex/mail/target/FileBasedMailbox.java b/src/org/ibex/mail/target/FileBasedMailbox.java index b9450be..04c26d8 100644 --- a/src/org/ibex/mail/target/FileBasedMailbox.java +++ b/src/org/ibex/mail/target/FileBasedMailbox.java @@ -44,7 +44,8 @@ public class FileBasedMailbox extends Mailbox.Default { public static class Cache implements Serializable { public final int uidValidity = new Random().nextInt(); private final Hashtable byname = new Hashtable(); - private transient final Hashtable byuid = new Hashtable(); + private final Hashtable byuid = new Hashtable(); + private final ArrayList linear = new ArrayList(); public final File dir; private int uidNext = 0; @@ -52,25 +53,44 @@ public class FileBasedMailbox extends Mailbox.Default { public void init(Prevayler prevayler) throws IOException { dir.mkdirs(); - Log.info(this, "initializing maildir " + dir.getAbsolutePath()); + Log.info(this, "initializing maildir " + dir.getParent()); boolean invalid = false; - for(String s : byname.keySet()) create(prevayler, s); + ArrayList kill = new ArrayList(); + for(String s : byname.keySet()) { + String name = dir.getParent() + slash + s; + if (!new File(name).exists() && !new File(name+"s").exists()) { + Log.error(this, "dropping message " + name); + kill.add(new Drop(byname.get(s).uid())); + } + } + for(Transaction t : kill) prevayler.execute(t); for(String file : new File(dir.getParent()).list()) - if (file.charAt(0)!='.' && !(new File(dir.getAbsolutePath() + slash + file).isDirectory())) - create(prevayler, file); - Log.info(this, " done initializing maildir " + dir.getAbsolutePath()); + if (file.charAt(0)!='.' && !(new File(dir.getParent() + slash + file).isDirectory())) + if (get(file) == null) new Entry(this, prevayler, file); + Log.info(this, " done initializing maildir " + dir.getParent()); prevayler.takeSnapshot(); } - public synchronized void create(Prevayler prevayler, String name) throws IOException { - if (get(name) != null) return; - new Entry(this, prevayler, name); + public static class Drop implements Transaction { + int uid; + public Drop(int uid) { this.uid = uid; } + public void executeOn(Object o, Date now) { + Cache c = (Cache)o; + Entry e = c.get(uid); + c.byname.remove(e.name); + c.linear.remove(e); + c.byuid.remove(uid); + } } - - public synchronized int size() { return byname.size(); } + + public synchronized int size() { return linear.size(); } public synchronized int uidNext(boolean increment) { return increment ? uidNext++ : uidNext; } public synchronized Entry get(int uid) { return byuid.get(uid); } - public synchronized Entry get(String name) { return byname.get(name); } + public synchronized Entry getLinear(int num) { return linear.get(num); } + public synchronized Entry get(String name) { + if (name.endsWith("s")) name = name.substring(0, name.length() - 1); + return byname.get(name); + } public static class Entry implements Serializable { public final MIME.Headers headers; @@ -79,14 +99,15 @@ public class FileBasedMailbox extends Mailbox.Default { private boolean seen; public Entry(Cache cache, Prevayler prevayler, String name) throws IOException { - seen = name.endsWith(".s"); - this.name = seen ? name.substring(0, name.length() - 2) : name; - headers = new MIME.Headers(new Stream(new FileInputStream(cache.dir.getAbsolutePath()+slash+name)), true); + seen = name.endsWith("s"); + this.name = seen ? name.substring(0, name.length() - 1) : name; + headers = new MIME.Headers(new Stream(new FileInputStream(cache.dir.getParent()+slash+name)), true); prevayler.execute(new Transaction() { public void executeOn(Object o, Date now) { Cache cache = (Cache)o; synchronized(cache) { Entry.this.uid = cache.uidNext(true); + cache.linear.add(Entry.this); cache.byuid.put(Entry.this.uid, Entry.this); cache.byname.put(Entry.this.name, Entry.this); } } }); @@ -95,21 +116,22 @@ public class FileBasedMailbox extends Mailbox.Default { public int uid() { return uid; } public boolean seen() { return seen; } public void seen(Cache cache, boolean seen) { - String base = cache.dir.getAbsolutePath() + slash + name; - File target = new File(base + (seen?".s":"")); + String base = cache.dir.getParent() + slash + name; + File target = new File(base + (seen?"s":"")); + this.seen = seen; if (target.exists()) return; - new File(base + (seen?"":".s")).renameTo(target); + new File(base + (seen?"":"s")).renameTo(target); } public void delete(Cache cache) { - String base = cache.dir.getAbsolutePath() + slash + name; + String base = cache.dir.getParent() + slash + name; File target = new File(base); - if (!target.exists()) target = new File(base + ".s"); + if (!target.exists()) target = new File(base + "s"); if (target.exists()) target.delete(); } public Message message(Cache cache) { try { - String base = cache.dir.getAbsolutePath() + slash + name; + String base = cache.dir.getParent() + slash + name; File target = new File(base); - if (!target.exists()) target = new File(base + ".s"); + if (!target.exists()) target = new File(base + "s"); FileInputStream fis = null; try { fis = new FileInputStream(target); @@ -169,12 +191,14 @@ public class FileBasedMailbox extends Mailbox.Default { public synchronized void add(Message message, int flags) { Log.info(path, message.summary()); try { - final String name = path.getAbsolutePath() + slash + cache.uidNext(true) + "." + - ((flags & Mailbox.Flag.SEEN) == Mailbox.Flag.SEEN ? "s" : ""); - File target = new File(name); - File f = new File(target.getCanonicalPath() + "-"); - if (f.exists() || target.exists()) - throw new RuntimeException("aieeee!!!! target of add() already exists: " + target.getAbsolutePath()); + String name; String fullname; File target; File f; + do { + name = cache.uidNext(true) + "." + ((flags & Mailbox.Flag.SEEN) == Mailbox.Flag.SEEN ? "s" : ""); + fullname = path.getAbsolutePath() + slash + name; + target = new File(fullname); + f = new File(target.getCanonicalPath() + "-"); + Log.error(this, "aieeee!!!! target of add() already exists: " + target.getAbsolutePath()); + } while (f.exists() || target.exists()); FileOutputStream fo = new FileOutputStream(f); Stream stream = new Stream(fo); if (message.envelope != null) { @@ -183,14 +207,14 @@ public class FileBasedMailbox extends Mailbox.Default { } message.dump(stream); fo.close(); - f.renameTo(new File(name)); + f.renameTo(new File(fullname)); new Cache.Entry(cache, prevayler, name); } catch (IOException e) { throw new MailException.IOException(e); } } - private class Iterator extends Mailbox.Default.Iterator implements Serializable { + private class Iterator extends Mailbox.Default.Iterator { int cur = -1; - private Cache.Entry entry() { return cache.get(cur); } + private Cache.Entry entry() { return cache.getLinear(cur); } public MIME.Headers head() { return done() ? null : entry().headers; } public boolean done() { return cur >= cache.size(); } public boolean next() { cur++; return !done(); } @@ -198,19 +222,19 @@ public class FileBasedMailbox extends Mailbox.Default { public int num() { return cur+1; } // EUDORA insists that message numbers start at 1, not 0 public int uid() { return done() ? -1 : entry().uid(); } public Message cur() { return done() ? null : entry().message(cache); } - public void seen(final boolean seen) { - if (done()) return; - final int cur = this.cur; - prevayler.execute(new Transaction() { - public void executeOn(Object c, Date d) { - ((Cache)c).get(cur).seen((Cache)c, seen); } }); - } - public void delete() { - if (done()) return; - final int cur = this.cur; - prevayler.execute(new Transaction() { - public void executeOn(Object c, Date d) { - ((Cache)c).get(cur).delete((Cache)c); } }); - } + public void seen(boolean seen) { prevayler.execute(new Seen(uid(), seen)); } + public void delete() { prevayler.execute(new Delete(uid())); } + } + + private static class Delete implements Transaction { + private int uid; + public Delete(int uid) { this.uid = uid; } + public void executeOn(Object c, Date d) { ((Cache)c).get(uid).delete((Cache)c); } + } + private static class Seen implements Transaction { + private int uid; + private boolean seen; + public Seen(int uid, boolean seen) { this.uid = uid; this.seen = seen; } + public void executeOn(Object c, Date d) { ((Cache)c).get(uid).seen((Cache)c, seen); } } }