1 21 22 package org.armedbear.j.mail; 23 24 import java.io.BufferedReader ; 25 import java.io.BufferedWriter ; 26 import java.io.FileWriter ; 27 import java.io.IOException ; 28 import java.io.StringReader ; 29 import java.text.SimpleDateFormat ; 30 import java.util.ArrayList ; 31 import java.util.Calendar ; 32 import java.util.Iterator ; 33 import java.util.List ; 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 mboxList; 47 48 private final Mutex mutex = new Mutex(); 49 private final File file; 50 51 private long lastModified; 52 private ArrayList 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 (); 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 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 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 public synchronized final List 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 (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 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 (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 text = reader.readLine(); 185 if (text == null) { 186 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; if (text.length() == 0) 215 break; 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 writeSummary(); 238 Log.debug("Mbox.read - after writeSummary"); 239 lastModified = file.lastModified(); 240 } 241 } 242 catch (IOException e) { 243 Log.error(e); 244 } 245 finally { 246 if (reader != null) { 247 try { 248 reader.close(); 249 } 250 catch (IOException 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 reader = 264 new BufferedReader (new StringReader (message.getRawText())); 265 BufferedWriter writer = 266 new BufferedWriter (new FileWriter (file.canonicalPath(), true)); 267 final long messageStart = file.length(); 268 writer.write("From - "); 269 SimpleDateFormat dateFormatter = 270 new SimpleDateFormat ("EEE MMM d HH:mm:ss yyyy"); 271 Calendar cal = Calendar.getInstance(); 272 String dateString = dateFormatter.format(cal.getTime()); 273 writer.write(dateString); 274 writer.write('\n'); 275 FastStringBuffer sb = new FastStringBuffer(2048); 277 while (true) { 278 String s = reader.readLine(); 279 if (s == null) 280 return false; if (s.length() == 0) { 282 String status = "X-J-Status: " + flags + "\n"; 285 writer.write(status); 286 sb.append(status); 287 writer.write('\n'); 288 break; 289 } 290 if (s.toUpperCase().startsWith("X-UIDL")) 292 continue; 293 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 while (true) { 303 String s = reader.readLine(); 304 if (s == null) 305 break; 306 if (s.startsWith("From ")) { 307 writer.write('>'); 309 } 310 writer.write(s); 311 writer.write('\n'); 312 } 313 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 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 (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 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 376 { 377 Log.debug("Mbox.finalize " + file); 378 super.finalize(); 379 } 380 } 381 | Popular Tags |