pretty much working
[org.ibex.mail.git] / src / org / ibex / mail / target / FileSystem.java
1 package org.ibex.mail.target;
2 import org.ibex.mail.*;
3 import org.ibex.util.*;
4 import org.ibex.mail.*;
5 import java.io.*;
6 import java.net.*;
7 import java.util.*;
8 import java.text.*;
9
10 // FIXME: appallingly inefficient
11 public class FileSystem extends Target {
12
13     private static final String STORAGE_ROOT =
14         System.getProperty("ibex.mail.root", File.separatorChar + "var" + File.separatorChar + "org.ibex.mail");
15     public static FileBased root = null;
16     public static Transcript transcript = null;
17     static {
18         try {
19             root = new FileBased(STORAGE_ROOT + File.separatorChar);
20             transcript = new Transcript(STORAGE_ROOT + File.separatorChar + "transcript");
21         } catch (Exception e) {
22             e.printStackTrace();
23         }
24     }
25
26     public void accept(Message m) throws IOException { add(m); }
27     public FileSystem slash(String name) throws IOException {
28         throw new Error(this.getClass().getName() + " does not support the slash() method"); }
29     public int[] list() { throw new Error(this.getClass().getName() + " does not support the list() method"); }
30     public int add(Message message) throws IOException {
31         throw new Error(this.getClass().getName() + " does not support the add() method"); }
32     public int delete(Message message) throws IOException {
33         throw new Error(this.getClass().getName() + " does not support the delete() method"); }
34     public Message get(int messagenum) throws IOException {
35         throw new Error(this.getClass().getName() + " does not support the get() method"); }
36     public Message[] query(int maxResults) {
37         throw new Error(this.getClass().getName() + " does not support the query() method"); }
38
39     public static class Mailbox extends FileSystem {
40         String user;
41         private static Hashtable cache = new Hashtable();
42         public static Mailbox getForUser(String user) {
43             Mailbox ret = (Mailbox)cache.get(user);
44             if (ret == null) ret = new Mailbox(user);
45             return ret;
46         }
47         Mailbox(String user) { this.user = user; }
48         public FileSystem slash(String name) throws IOException {
49             throw new Error(this.getClass().getName() + " does not support the slash() method"); }
50         public synchronized int add(Message message) throws IOException {
51             FileOutputStream fos = new FileOutputStream("/var/mail/" + user, true);
52             PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos));
53             pw.println("From " + message.envelopeFrom);
54             pw.flush();
55             message.dump(fos);
56             fos.close();
57             return -1;
58         }
59     }
60
61     /** a fast-write, slow-read place to stash all messages we touch -- in case of a major f*ckup */
62     public static class Transcript extends FileSystem {
63         private String path;
64         public Transcript(String path) throws IOException { new File(this.path = path).mkdirs(); }
65         private static String lastTime = null;
66         private static int lastCounter = 0;
67
68         /** returns a message identifier */
69         public synchronized int add(Message message) throws IOException {
70             File today = new File(path + File.separatorChar + (new SimpleDateFormat("yy-MMM-dd").format(new Date())));
71             today.mkdirs();
72             
73             String time = new SimpleDateFormat("HH:mm:ss").format(new Date());
74             synchronized (Transcript.class) {
75                 if (lastTime != null && lastTime.equals(time)) {
76                     time += "." + (++lastCounter);
77                 } else {
78                     lastTime = time;
79                 }
80             }
81             
82             File target = new File(today.getPath() + File.separatorChar + time + ".txt");
83             OutputStream os = new FileOutputStream(target);
84             message.dump(os);
85             os.close();
86             return -1;
87         }
88     }
89
90     public static class FileBased extends FileSystem {
91         private String path;
92         private FileBased(String path) throws IOException { new File(this.path = path).mkdirs(); }
93         public FileSystem slash(String name) throws IOException { return new FileBased(path + "/" + name); }
94
95         public int[] list() {
96             String[] names = new File(path).list();
97             int[] ret = new int[names.length];
98             for(int i=0, j=0; j<ret.length; i++, j++) {
99                 try {
100                     ret[j] = Integer.parseInt(names[i].substring(0, names[i].length() - 1));
101                 } catch (NumberFormatException nfe) {
102                     Log.warn(FileBased.class, "NumberFormatException: " + names[i].substring(0, names[i].length() - 1));
103                     j--;
104                     int[] newret = new int[ret.length - 1];
105                     System.arraycopy(ret, 0, newret, 0, newret.length);
106                     ret = newret;
107                 }
108             }
109             return ret;
110         }
111
112         /** returns a message identifier */
113         public synchronized int add(Message message) throws IOException {
114             int[] all = list();
115             int max = 0;
116             for(int i=0; i<all.length; i++) max = Math.max(max, all[i]);
117             int target = max++;
118             File f = new File(path + File.separatorChar + max + ".-");
119             FileOutputStream fo = new FileOutputStream(f);
120             message.dump(fo);
121             fo.close();
122             f.renameTo(new File(path + File.separatorChar + max + "."));
123             return target;
124         }
125
126         public Message get(int messagenum) throws IOException {
127             File f = new File(path + File.separatorChar + messagenum + ".");        
128             if (!f.exists()) throw new FileNotFoundException(f.toString());
129             //try {
130                 // FIXME: need to store envelope from/to
131                 //Message ret = new Message(new LineReader(new InputStreamReader(new FileInputStream(f))));
132                 // FIXME: set answered/read/etc here
133                 //return ret;
134                 return null;
135                 /*
136             } catch (MailException.Malformed malf) {
137                 Log.error(this, "This should never happen");
138                 Log.error(this, malf);
139                 return null;
140             }
141                 */
142         }
143
144         // query types: stringmatch (headers, body), header element, deletion status, date range, message size
145         public Message[] query(int maxResults) {
146             throw new RuntimeException("FileBased.query() not implemented yet");
147         }
148
149     }
150
151 }