1 package org.ibex.mail.target;
2 import org.ibex.mail.*;
3 import org.ibex.util.*;
4 import org.ibex.mail.*;
10 /** An exceptionally crude implementation of Mailbox relying on POSIXy filesystem semantics */
11 public class FileBasedMailbox extends Mailbox.Default {
13 private static final char slash = File.separatorChar;
14 private static final Hashtable instances = new Hashtable();
15 public static FileBasedMailbox getFileBasedMailbox(String path, boolean create) {
16 FileBasedMailbox ret = (FileBasedMailbox)instances.get(path);
17 if (ret != null) return ret;
18 File f = new File(path);
19 if (!create && !f.exists()) return null;
20 instances.put(path, ret = new FileBasedMailbox(path));
24 public static final FilenameFilter filter = new FilenameFilter() {
25 public boolean accept(File f, String s) {
26 return s.indexOf('.') != -1;
30 // Instance //////////////////////////////////////////////////////////////////////////////
34 private FileBasedMailbox(String path) throws MailException {
35 new File(this.path = path).mkdirs();
39 public Mailbox slash(String name, boolean create) {
40 return FileBasedMailbox.getFileBasedMailbox(path + slash + name, create); }
41 public Mailbox.Iterator iterator() { return new FileBasedMailbox.Iterator(); }
42 public int uidValidity() { return (int)(new File(path).lastModified() & 0xffffffL); }
44 public int uidNext() { return uidNext(false); }
45 public int uidNext(boolean inc) {
47 uidNext = new File(path + slash + "UIDNEXT");
48 if (!uidNext.exists()) {
49 File tmp = new File(uidNext + "-");
50 PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tmp)));
54 tmp.renameTo(uidNext);
57 BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(uidNext)));
58 int ret = Integer.parseInt(br.readLine());
60 File tmp = new File(uidNext + "-");
61 PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tmp)));
65 tmp.renameTo(uidNext);
68 } catch (IOException e) { throw new MailException.IOException(e); }
71 public synchronized int add(Message message) {
73 int num = new File(path).list(filter).length;
74 File target = new File(path + slash + uidNext(true) + ".");
75 File f = new File(target.getCanonicalPath() + "-");
76 FileOutputStream fo = new FileOutputStream(f);
81 } catch (IOException e) { throw new MailException.IOException(e); }
84 private class Iterator implements Mailbox.Default.Iterator {
86 private String[] names;
87 private boolean seen = false, deleted = false, draft = false, flagged = false, answered = false, recent = false;
88 public Iterator() { names = new File(path).list(filter); }
90 public Message cur() {
92 File file = new File(path + File.separatorChar + names[cur]);
93 return new Message(/* FIXME */ null, /* FIXME */ new Address[] { },
94 new LineReader(new InputStreamReader(new FileInputStream(file))));
95 } catch (IOException e) { throw new MailException.IOException(e); }
97 public boolean next() {
99 if (cur >= names.length) return false;
100 String name = names[cur].substring(names[cur].indexOf('.') + 1);
101 seen = name.indexOf('s') != -1;
102 deleted = name.indexOf('x') != -1;
103 flagged = name.indexOf('f') != -1;
104 draft = name.indexOf('d') != -1;
105 answered = name.indexOf('a') != -1;
106 recent = name.indexOf('r') != -1;
109 public int num() { return cur; }
111 try { return Integer.parseInt(names[cur].substring(0, names[cur].indexOf('.')));
112 } catch (NumberFormatException nfe) {
113 Log.warn(FileBasedMailbox.class, "NumberFormatException: " + names[cur].substring(0, names[cur].length() - 1));
116 private void fixflags() {
118 names[cur].substring(0, names[cur].indexOf('.') + 1) +
120 (deleted ? "x" : "") +
121 (flagged ? "f" : "") +
123 (recent ? "r" : "") +
124 (answered ? "a" : "");
125 new File(names[cur]).renameTo(new File(path + File.separatorChar + newName));
126 names[cur] = newName;
129 public void delete() { new File(names[cur]).delete(); }
130 public void set(String key, String val) { throw new MailException("not supported"); }
131 public String get(String key) { throw new MailException("not supported"); }
133 public boolean seen() { return seen; }
134 public boolean deleted() { return deleted; }
135 public boolean flagged() { return flagged; }
136 public boolean draft() { return draft; }
137 public boolean answered() { return answered; }
138 public boolean recent() { return recent; }
139 public void seen(boolean on) { seen = on; fixflags(); }
140 public void deleted(boolean on) { deleted = on; fixflags(); }
141 public void flagged(boolean on) { flagged = on; fixflags(); }
142 public void draft(boolean on) { draft = on; fixflags(); }
143 public void answered(boolean on) { answered = on; fixflags(); }
144 public void recent(boolean on) { recent = on; fixflags(); }