KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > mail > Mbox


1 /*
2  * Mbox.java
3  *
4  * Copyright (C) 2000-2002 Peter Graves
5  * $Id: Mbox.java,v 1.1.1.1 2002/09/24 16:09:45 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j.mail;
23
24 import java.io.BufferedReader JavaDoc;
25 import java.io.BufferedWriter JavaDoc;
26 import java.io.FileWriter JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.StringReader JavaDoc;
29 import java.text.SimpleDateFormat JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Calendar JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import org.armedbear.j.Buffer;
35 import org.armedbear.j.BufferIterator;
36 import org.armedbear.j.Debug;
37 import org.armedbear.j.Editor;
38 import org.armedbear.j.File;
39 import org.armedbear.j.FastStringBuffer;
40 import org.armedbear.j.Log;
41 import org.armedbear.j.Mutex;
42 import org.armedbear.j.ProgressNotifier;
43
44 public final class Mbox
45 {
46     private static ArrayList JavaDoc mboxList;
47
48     private final Mutex mutex = new Mutex();
49     private final File file;
50
51     private long lastModified;
52     private ArrayList JavaDoc entries;
53
54     private Mbox(File file)
55     {
56         this.file = file;
57         Debug.assertTrue(file != null);
58     }
59
60     public static synchronized Mbox getInstance(File file)
61     {
62         if (mboxList == null)
63             mboxList = new ArrayList JavaDoc();
64         else {
65             for (int i = mboxList.size()-1; i >= 0; i--) {
66                 Mbox mbox = (Mbox) mboxList.get(i);
67                 if (mbox.getFile().equals(file))
68                     return mbox;
69             }
70         }
71         // Not found.
72
Mbox mbox = new Mbox(file);
73         mboxList.add(mbox);
74         return mbox;
75     }
76
77     public static synchronized void cleanup()
78     {
79         Log.debug("Mbox.cleanup");
80         if (mboxList == null || mboxList.size() == 0)
81             return;
82         Iterator JavaDoc iter = mboxList.iterator();
83         while (iter.hasNext()) {
84             Mbox mbox = (Mbox) iter.next();
85             if (findMailbox(mbox) == null) {
86                 Log.debug("removing Mbox for " + mbox.getFile());
87                 iter.remove();
88             }
89         }
90     }
91
92     private static Mailbox findMailbox(Mbox mbox)
93     {
94         File file = mbox.getFile();
95         BufferIterator iter = new BufferIterator();
96         while (iter.hasNext()) {
97             Buffer buf = iter.nextBuffer();
98             if (buf instanceof LocalMailbox) {
99                 LocalMailbox mb = (LocalMailbox) buf;
100                 if (mb.getMailboxFile().equals(file))
101                     return mb;
102             }
103         }
104         return null;
105     }
106
107     public final File getFile()
108     {
109         return file;
110     }
111
112     // Return a copy.
113
public synchronized final List JavaDoc getEntries(ProgressNotifier progressNotifier)
114     {
115         Log.debug("Mbox.getEntries");
116         Debug.assertTrue(isLocked());
117         if (entries != null) {
118             if (file.lastModified() > lastModified) {
119                 Log.debug("mbox last modified later than entries last modified");
120                 entries = null;
121             }
122         }
123         if (entries == null) {
124             File summaryFile = getSummaryFile();
125             if (summaryFile.isFile() && summaryFile.lastModified() > file.lastModified()) {
126                 Log.debug("using summary");
127                 MboxSummary summary = MboxSummary.read(summaryFile);
128                 if (summary != null) {
129                     Log.debug("summary is valid");
130                     if (summary.lastModified() == file.lastModified()) {
131                         if (summary.length() == file.length()) {
132                             entries = summary.getEntries();
133                             lastModified = file.lastModified();
134                         }
135                     }
136                 }
137             }
138             if (entries == null) {
139                 Log.debug("entries == null, calling read...");
140                 read(progressNotifier);
141             }
142         }
143         return new ArrayList JavaDoc(entries);
144     }
145
146     public synchronized boolean lock()
147     {
148         Log.debug("Mbox.lock " + file.canonicalPath());
149         try {
150             return mutex.attempt();
151         }
152         catch (InterruptedException JavaDoc e) {
153             return false;
154         }
155     }
156
157     public synchronized void unlock()
158     {
159         Log.debug("Mbox.unlock " + file.canonicalPath());
160         mutex.release();
161     }
162
163     public synchronized boolean isLocked()
164     {
165         return mutex.isInUse();
166     }
167
168     private synchronized void read(ProgressNotifier progressNotifier)
169     {
170         Log.debug("entering Mbox.read");
171         long start = System.currentTimeMillis();
172         Debug.assertTrue(isLocked());
173         entries = new ArrayList JavaDoc(1000);
174         long messageStart = 0;
175         MailReader reader = null;
176         try {
177             if (!file.isFile())
178                 return;
179             reader = new MailReader(file.getInputStream());
180             FastStringBuffer sb = new FastStringBuffer(1024);
181             boolean complete = false;
182             while (true) {
183                 long here = reader.getOffset();
184                 String JavaDoc text = reader.readLine();
185                 if (text == null) {
186                     // End of file.
187
Log.debug("read - end of file");
188                     if (entries.size() > 0) {
189                         LocalMailboxEntry entry =
190                             (LocalMailboxEntry) entries.get(entries.size()-1);
191                         entry.setSize((int)(here - messageStart));
192                         entry.setNextMessageStart(here);
193                     }
194                     complete = true;
195                     break;
196                 }
197                 if (text.startsWith("From ")) {
198                     if (entries.size() > 0) {
199                         LocalMailboxEntry entry =
200                             (LocalMailboxEntry) entries.get(entries.size()-1);
201                         entry.setSize((int)(here - messageStart));
202                         entry.setNextMessageStart(here);
203                         messageStart = here;
204                     }
205                     if (progressNotifier != null && progressNotifier.cancelled()) {
206                         Log.debug("Mbox.read cancelled!");
207                         break;
208                     }
209                     sb.setLength(0);
210                     while (true) {
211                         text = reader.readLine();
212                         if (text == null)
213                             return; // Shouldn't happen.
214
if (text.length() == 0)
215                             break; // End of header.
216
sb.append(text);
217                         sb.append('\n');
218                     }
219                     LocalMailboxEntry entry =
220                         new LocalMailboxEntry(entries.size()+1, here, sb.toString());
221                     entries.add(entry);
222                     if (progressNotifier != null) {
223                         sb.setLength(0);
224                         sb.append("Read ");
225                         sb.append(entries.size());
226                         sb.append(" message");
227                         if (entries.size() > 1)
228                             sb.append('s');
229                         progressNotifier.progress(sb.toString());
230                     }
231                 }
232             }
233             if (complete) {
234                 long elapsed = System.currentTimeMillis() - start;
235                 Log.debug("Mbox.read " + elapsed + " ms");
236                 // User did not cancel.
237
writeSummary();
238                 Log.debug("Mbox.read - after writeSummary");
239                 lastModified = file.lastModified();
240             }
241         }
242         catch (IOException JavaDoc e) {
243             Log.error(e);
244         }
245         finally {
246             if (reader != null) {
247                 try {
248                     reader.close();
249                 }
250                 catch (IOException JavaDoc e) {
251                     Log.error(e);
252                 }
253             }
254             Log.debug("leaving Mbox.read");
255         }
256     }
257
258     public synchronized boolean appendMessage(Message message, final int flags)
259     {
260         Log.debug("Mbox.appendMessage flags = " + flags);
261         Debug.assertTrue(isLocked());
262         try {
263             BufferedReader JavaDoc reader =
264                 new BufferedReader JavaDoc(new StringReader JavaDoc(message.getRawText()));
265             BufferedWriter JavaDoc writer =
266                 new BufferedWriter JavaDoc(new FileWriter JavaDoc(file.canonicalPath(), true));
267             final long messageStart = file.length();
268             writer.write("From - ");
269             SimpleDateFormat JavaDoc dateFormatter =
270                 new SimpleDateFormat JavaDoc ("EEE MMM d HH:mm:ss yyyy");
271             Calendar JavaDoc cal = Calendar.getInstance();
272             String JavaDoc dateString = dateFormatter.format(cal.getTime());
273             writer.write(dateString);
274             writer.write('\n');
275             // Headers.
276
FastStringBuffer sb = new FastStringBuffer(2048);
277             while (true) {
278                 String JavaDoc s = reader.readLine();
279                 if (s == null)
280                     return false; // Error! (Reached end of stream before reaching end of headers.)
281
if (s.length() == 0) {
282                     // Reached end of headers.
283
// Add X-J-Status.
284
String JavaDoc status = "X-J-Status: " + flags + "\n";
285                     writer.write(status);
286                     sb.append(status);
287                     writer.write('\n');
288                     break;
289                 }
290                 // Skip X-UIDL.
291
if (s.toUpperCase().startsWith("X-UIDL"))
292                     continue;
293                 // Skip X-J-Status.
294
if (s.startsWith("X-J-Status:"))
295                     continue;
296                 writer.write(s);
297                 writer.write('\n');
298                 sb.append(s);
299                 sb.append('\n');
300             }
301             // Body.
302
while (true) {
303                 String JavaDoc s = reader.readLine();
304                 if (s == null)
305                     break;
306                 if (s.startsWith("From ")) {
307                     // Mangle lines starting with "From " in body of message.
308
writer.write('>');
309                 }
310                 writer.write(s);
311                 writer.write('\n');
312             }
313             // Add a newline after the end of the message.
314
writer.write('\n');
315             writer.flush();
316             writer.close();
317             reader.close();
318             if (entries != null) {
319                 final long nextMessageStart = file.length();
320                 LocalMailboxEntry entry =
321                     new LocalMailboxEntry(entries.size()+1, messageStart,
322                         sb.toString());
323                 entry.setNextMessageStart(nextMessageStart);
324                 entry.setSize((int)(nextMessageStart - messageStart));
325                 entries.add(entry);
326             } else
327                 Log.debug("appendMessage entries == null");
328             return true;
329         }
330         catch (IOException JavaDoc e) {
331             Log.error(e);
332             return false;
333         }
334     }
335
336     public synchronized void updateViews()
337     {
338         if (entries == null)
339             return;
340         for (BufferIterator it = new BufferIterator(); it.hasNext();) {
341             Buffer buf = it.nextBuffer();
342             if (buf instanceof LocalMailbox) {
343                 LocalMailbox mb = (LocalMailbox) buf;
344                 if (mb.getMailboxFile().equals(file)) {
345                     if (mb.lock()){
346                         try {
347                             mb.saveDisplayState();
348                             mb.setEntries(new ArrayList JavaDoc(entries));
349                             mb.refreshBuffer();
350                             mb.updateDisplay();
351                         }
352                         finally {
353                             mb.unlock();
354                         }
355                     }
356                 }
357             }
358         }
359     }
360
361     private final File getSummaryFile()
362     {
363         return File.getInstance(file.canonicalPath() + ".summary");
364     }
365
366     // Called only from read().
367
private void writeSummary()
368     {
369         Debug.assertTrue(isLocked());
370         File summaryFile = getSummaryFile();
371         MboxSummary summary = new MboxSummary(file, entries);
372         summary.write(summaryFile);
373     }
374
375     protected void finalize() throws Throwable JavaDoc
376     {
377         Log.debug("Mbox.finalize " + file);
378         super.finalize();
379     }
380 }
381
Popular Tags