- }
-
- private FileBasedMailbox(String path) throws MailException, IOException, ClassNotFoundException {
- new File(this.path = path).mkdirs();
- new File(path + slash + ".cache").mkdirs();
- File uidValidityFile = new File(path + slash + ".uidValidity");
- if (!uidValidityFile.exists()) uidValidityFile.createNewFile();
- uidValidity = (int)(uidValidityFile.lastModified() & 0xffffffff);
- lock = new RandomAccessFile(this.path + slash + ".cache" + slash + "lock", "rw").getChannel().tryLock();
- if (lock == null) throw new IOException("unable to lock FileBasedMailbox");
- prevayler = PrevaylerFactory.createPrevayler(new ArrayList<CacheEntry>(), path + slash + ".cache");
- cache = (ArrayList<CacheEntry>)prevayler.prevalentSystem();
- for(int i=0; i<cache.size(); i++) if (cache.get(i) != null) uidNext = Math.max(uidNext, cache.get(i).uid()+1);
- if (cache.size() == 0) {
- Log.warn(this, "rebuilding cache for " + path);
- String[] files = new File(path).list(new FilenameFilter() {
- public boolean accept(File f, String s) {
- return s.substring(1).indexOf('.') != -1 && !s.equals("..");
- } });
- long last = System.currentTimeMillis();
- CacheEntry[] entries = new CacheEntry[files.length];
- for(int i=0; i<files.length; i++) {
- if (System.currentTimeMillis() - last > 1000 * 1) {
- Log.warn(this, "rebuilding cache for " + path + ": " + Math.ceil((((float)i)/((float)files.length)) * 100)+ "%");
- last = System.currentTimeMillis();
- }
- CacheEntry ce = new CacheEntry(new File(path + slash + files[i]));
- entries[i] = ce;
- uidNext = Math.max(uidNext, ce.uid()+1);
+
+ public synchronized int size() { return byname.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 static class Entry implements Serializable {
+ public final MIME.Headers headers;
+ public final String name;
+ private int uid;
+ 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);
+ prevayler.execute(new Transaction() {
+ public void executeOn(Object o, Date now) {
+ Cache cache = (Cache)o;
+ synchronized(cache) {
+ Entry.this.uid = cache.uidNext(true);
+ cache.byuid.put(Entry.this.uid, Entry.this);
+ cache.byname.put(Entry.this.name, Entry.this);
+ } } });
+ }
+
+ 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":""));
+ if (target.exists()) return;
+ new File(base + (seen?"":".s")).renameTo(target);
+ }
+ public void delete(Cache cache) {
+ String base = cache.dir.getAbsolutePath() + slash + name;
+ File target = new File(base);
+ 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;
+ File target = new File(base);
+ if (!target.exists()) target = new File(base + ".s");
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(target);
+ return new Message(new Stream(fis), new Message.Envelope(null, null, new Date(target.lastModified())));
+ } finally { if (fis != null) fis.close(); }
+ } catch (IOException e) { throw new MailException.IOException(e);
+ } catch (Message.Malformed e) { throw new MailException(e.getMessage()); }