KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > suberic > pooka > cache > SimpleFileCache


1 package net.suberic.pooka.cache;
2 import javax.mail.internet.*;
3 import net.suberic.pooka.FolderInfo;
4 import net.suberic.pooka.MessageInfo;
5 import java.util.HashMap JavaDoc;
6 import java.util.Vector JavaDoc;
7 import java.io.*;
8 import javax.mail.*;
9 import javax.mail.event.*;
10 import javax.activation.DataHandler JavaDoc;
11
12 /**
13  * A simple cache.
14  *
15  */

16 public class SimpleFileCache implements MessageCache {
17
18   // FIXME: why isn't anything synchronized?
19

20   public static int ADDED = 10;
21   public static int REMOVED = 11;
22
23   public static String JavaDoc DELIMETER = "_";
24   public static String JavaDoc CONTENT_EXT = "msg";
25   public static String JavaDoc HEADER_EXT = "hdr";
26   public static String JavaDoc FLAG_EXT = "flag";
27
28   protected long uidValidity;
29
30   // the source FolderInfo.
31
private CachingFolderInfo folderInfo;
32
33   // the directory in which the cache is stored.
34
private File cacheDir;
35
36   // the UIDValidity
37
private long newUidValidity;
38
39   // the currently cached uid's
40
private Vector JavaDoc cachedMessages;
41
42   // the currently cached Flags.
43
private HashMap JavaDoc cachedFlags;
44
45   // the currently cached Headers.
46
private HashMap JavaDoc cachedHeaders;
47
48   // the place where we store changes to happen later...
49
private ChangeCache changes = null;
50
51   // the last local UID used.
52
long lastLocalUID = -1;
53
54   /**
55    * Creates a new SimpleFileCache for the given FolderInfo, in the
56    * directory provided.
57    */

58   public SimpleFileCache(CachingFolderInfo folder, String JavaDoc directoryName) throws IOException {
59     folderInfo = folder;
60     cacheDir = new File(directoryName);
61     if ( ! cacheDir.exists() )
62       cacheDir.mkdirs();
63     else if (! cacheDir.isDirectory())
64       throw new IOException("not a directory.");
65
66     changes = new ChangeCache(cacheDir);
67
68     loadCache();
69   }
70
71   /**
72    * Returns the datahandler for the given message uid.
73    */

74   public DataHandler JavaDoc getDataHandler(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
75     if (newUidValidity != uidValidity) {
76       throw new StaleCacheException(uidValidity, newUidValidity);
77     }
78
79     DataHandler JavaDoc h = getHandlerFromCache(uid);
80     if (h != null) {
81       return h;
82     } else {
83       if (getFolderInfo().shouldBeConnected()) {
84         MimeMessage m = getFolderInfo().getRealMessageById(uid);
85         if (m != null) {
86           h = m.getDataHandler();
87           if (saveToCache)
88             cacheMessage(m, uid, newUidValidity, MESSAGE);
89           return h;
90         } else
91           throw new MessageRemovedException("No such message: " + uid);
92       } else {
93         throw new NotCachedException("Message is not cached, and folder is not available.");
94       }
95     }
96   }
97
98   /**
99    * Returns the datahandler for the given message uid.
100    */

101   public DataHandler JavaDoc getDataHandler(long uid, long newUidValidity) throws MessagingException {
102     return getDataHandler(uid, newUidValidity, true);
103   }
104
105   /**
106    * Returns a non-mutable Message representation of the given Message.
107    */

108   public MimeMessage getMessageRepresentation(long uid, long newUidValidity) throws MessagingException {
109     return getMessageRepresentation(uid, newUidValidity, true);
110   }
111
112   /**
113    * Returns a non-mutable Message representation of the given Message.
114    */

115   public MimeMessage getMessageRepresentation(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
116     if (newUidValidity != uidValidity) {
117       throw new StaleCacheException(uidValidity, newUidValidity);
118     }
119
120     DataHandler JavaDoc h = getHandlerFromCache(uid);
121
122     File f = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
123     if (f.exists()) {
124       try {
125         FileInputStream fis = new FileInputStream(f);
126         MimeMessage mm = new MimeMessage(net.suberic.pooka.Pooka.getDefaultSession(), fis);
127         return mm;
128       } catch (Exception JavaDoc e) {
129         return null;
130       }
131     } else {
132       if (getFolderInfo().shouldBeConnected()) {
133         MimeMessage m = getFolderInfo().getRealMessageById(uid);
134         if (m != null) {
135           if (saveToCache)
136             cacheMessage(m, uid, newUidValidity, MESSAGE);
137
138           return m;
139         } else
140           throw new MessageRemovedException("No such message: " + uid);
141       } else {
142         throw new NotCachedException("Message is not cached, and folder is not available.");
143       }
144     }
145   }
146
147
148   /**
149    * Adds the given Flags to the message with the given uid.
150    *
151    * This affects both the client cache as well as the message on the
152    * server, if the server is available.
153    */

154   public void addFlag(long uid, long newUidValidity, Flags flag) throws MessagingException {
155     if (newUidValidity != uidValidity) {
156       throw new StaleCacheException(uidValidity, newUidValidity);
157     }
158
159     Flags f = getFlags(uid, newUidValidity);
160     if (f != null) {
161       f.add(flag);
162     } else {
163       f = flag;
164     }
165
166     if (getFolderInfo().shouldBeConnected()) {
167       MimeMessage m = getFolderInfo().getRealMessageById(uid);
168       if (m != null)
169         m.setFlags(flag, true);
170
171       saveFlags(uid, uidValidity, f);
172
173     } else {
174       writeToChangeLog(uid, flag, ADDED);
175
176       saveFlags(uid, uidValidity, f);
177       final long fUid = uid;
178       getFolderInfo().getFolderThread().addToQueue(new net.suberic.util.thread.ActionWrapper(new javax.swing.AbstractAction JavaDoc() {
179           public void actionPerformed(java.awt.event.ActionEvent JavaDoc actionEvent) {
180             if (getFolderInfo() != null) {
181               MessageInfo mInfo = getFolderInfo().getMessageInfoByUid(fUid);
182               if (mInfo != null) {
183                 getFolderInfo().messageChanged(new MessageChangedEvent(SimpleFileCache.this, MessageChangedEvent.FLAGS_CHANGED, mInfo.getMessage()));
184               }
185             }
186           }
187         }, getFolderInfo().getFolderThread()), new java.awt.event.ActionEvent JavaDoc(SimpleFileCache.this, 1, "message-changed"));
188
189     }
190
191   }
192
193   /**
194    * Removes the given Flags from the message with the given uid.
195    *
196    * This affects both the client cache as well as the message on the
197    * server, if the server is available.
198    */

199   public void removeFlag(long uid, long newUidValidity, Flags flag) throws MessagingException {
200     if (newUidValidity != uidValidity) {
201       throw new StaleCacheException(uidValidity, newUidValidity);
202     }
203     Flags f = getFlags(uid, newUidValidity);
204     if (f != null) {
205       f.remove(flag);
206
207       if (getFolderInfo().shouldBeConnected()) {
208         MimeMessage m = getFolderInfo().getRealMessageById(uid);
209         if (m != null)
210           m.setFlags(flag, false);
211         saveFlags(uid, uidValidity, f);
212       } else {
213         saveFlags(uid, uidValidity, f);
214         writeToChangeLog(uid, flag, REMOVED);
215       }
216
217     }
218   }
219
220   /**
221    * Returns the InternetHeaders object for the given uid.
222    */

223   public InternetHeaders getHeaders(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
224     if (newUidValidity != uidValidity) {
225       throw new StaleCacheException(uidValidity, newUidValidity);
226     }
227     InternetHeaders h = getHeadersFromCache(uid);
228     if (h != null) {
229       return h;
230     } else {
231       if (getFolderInfo().shouldBeConnected()) {
232         MimeMessage m = getFolderInfo().getRealMessageById(uid);
233         if (m != null) {
234           java.util.Enumeration JavaDoc headerLines = m.getAllHeaderLines();
235           h = new InternetHeaders();
236           while (headerLines.hasMoreElements()) {
237             h.addHeaderLine((String JavaDoc) headerLines.nextElement());
238           }
239           if (saveToCache)
240             cacheMessage(m, uid, newUidValidity, HEADERS);
241           return h;
242         } else
243           throw new MessageRemovedException("No such message: " + uid);
244       } else {
245         throw new NotCachedException("Message is not cached, and folder is not available.");
246       }
247     }
248   }
249
250   public InternetHeaders getHeaders(long uid, long uidValidity) throws MessagingException {
251     return getHeaders(uid, uidValidity, true);
252   }
253
254   /**
255    * Returns the Flags object for the given uid.
256    */

257   public Flags getFlags(long uid, long newUidValidity, boolean saveToCache) throws MessagingException {
258     if (newUidValidity != uidValidity) {
259       throw new StaleCacheException(uidValidity, newUidValidity);
260     }
261     Flags f = getFlagsFromCache(uid);
262
263     if (f != null) {
264       return f;
265     } else {
266       if (getFolderInfo().shouldBeConnected()) {
267         MimeMessage m = getFolderInfo().getRealMessageById(uid);
268         if (m != null) {
269           f = m.getFlags();
270           if (saveToCache)
271             cacheMessage(m, uid, newUidValidity, FLAGS);
272           return f;
273         } else
274           throw new MessageRemovedException("No such message: " + uid);
275       } else {
276         throw new NotCachedException("Message is not cached, and folder is not available.");
277       }
278     }
279
280   }
281
282   /**
283    * Returns the Flags object for the given uid.
284    */

285   public Flags getFlags(long uid, long uidValidity) throws MessagingException {
286     return getFlags(uid, uidValidity, true);
287   }
288
289   /**
290    * Adds a message to the cache. Note that status is only used to
291    * determine whether or not the entire message is cached, or just
292    * the headers and flags.
293    *
294    * This does not affect the server, nor does it affect message
295    * count on the client.
296    */

297   public boolean cacheMessage(MimeMessage m, long uid, long newUidValidity, int status) throws MessagingException {
298     return cacheMessage(m, uid, newUidValidity, status, true);
299   }
300
301   /**
302    * Adds a message to the cache. Note that status is only used to
303    * determine whether or not the entire message is cached, or just
304    * the headers and flags.
305    *
306    * This does not affect the server, nor does it affect message
307    * count on the client.
308    */

309   public boolean cacheMessage(MimeMessage m, long uid, long newUidValidity, int status, boolean writeMsgFile) throws MessagingException {
310     if (newUidValidity != uidValidity) {
311       throw new StaleCacheException(uidValidity, newUidValidity);
312     }
313
314     if (m == null)
315       return false;
316
317     try {
318       if (status == CONTENT || status == MESSAGE) {
319         // we have to reset the seen flag if it's not set, since getting
320
// the message from the server sets the flag.
321

322         Flags flags = m.getFlags();
323         boolean resetSeen = (! flags.contains(Flags.Flag.SEEN));
324
325         ByteArrayOutputStream baos = new ByteArrayOutputStream();
326         m.writeTo(baos);
327
328         if (resetSeen) {
329           m.setFlag(Flags.Flag.SEEN, false);
330         }
331
332         File outFile = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
333         if (outFile.exists())
334           outFile.delete();
335
336         FileOutputStream fos = new FileOutputStream(outFile);
337         //m.writeTo(fos);
338
fos.write(baos.toByteArray());
339
340         fos.flush();
341         fos.close();
342       }
343
344       if (status == MESSAGE || status == FLAGS || status == FLAGS_AND_HEADERS) {
345         Flags flags = m.getFlags();
346         saveFlags(uid, uidValidity, flags);
347       }
348
349
350       if (status == MESSAGE || status == HEADERS || status == FLAGS_AND_HEADERS) {
351
352         StringWriter outString = new StringWriter();
353
354         java.util.Enumeration JavaDoc headerLines = m.getAllHeaderLines();
355         BufferedWriter bos = new BufferedWriter(outString);
356
357         int foo = 0;
358         while (headerLines.hasMoreElements()) {
359           bos.write((String JavaDoc) headerLines.nextElement());
360           bos.newLine();
361         }
362
363         bos.newLine();
364         bos.flush();
365         bos.close();
366
367         File outFile = new File(cacheDir, uid + DELIMETER + HEADER_EXT);
368         if (outFile.exists())
369           outFile.delete();
370
371         outFile.createNewFile();
372
373         FileWriter fos = new FileWriter(outFile);
374         bos = new BufferedWriter(fos);
375         /*
376           java.util.Enumeration enum = m.getAllHeaderLines();
377           BufferedWriter bos = new BufferedWriter(fos);
378
379           int foo = 0;
380           while (enum.hasMoreElements()) {
381           bos.write((String) enum.nextElement());
382           bos.newLine();
383           }
384         */

385         bos.write(outString.toString());
386         bos.flush();
387         bos.close();
388         fos.close();
389       }
390
391       if (! cachedMessages.contains(new Long JavaDoc(uid))) {
392         cachedMessages.add(new Long JavaDoc(uid));
393         if (writeMsgFile)
394           writeMsgFile();
395       }
396     } catch (IOException ioe) {
397       throw new MessagingException(ioe.getMessage(), ioe);
398     }
399
400     return true;
401   }
402
403   /**
404    * Removes a message from the cache only. This has no effect on the
405    * server.
406    */

407   public boolean invalidateCache(long uid, int status) {
408     invalidateCache(new long[] { uid }, status);
409
410     return true;
411   }
412
413   /**
414    * Invalidates all of the messages in the uids array in the cache.
415    */

416   public boolean invalidateCache(long[] uids, int status) {
417     for (int i = 0; i < uids.length; i++) {
418       FilenameFilter filter = new CacheFilenameFilter(uids[i], status);
419       File[] matchingFiles = cacheDir.listFiles(filter);
420       for (int j = 0; j < matchingFiles.length; j++)
421         matchingFiles[j].delete();
422
423       Long JavaDoc l = new Long JavaDoc(uids[i]);
424       if (status == MESSAGE || status == FLAGS_AND_HEADERS || status == FLAGS) {
425         cachedFlags.remove(l);
426       }
427       if (status == MESSAGE || status == FLAGS_AND_HEADERS || status == HEADERS) {
428         cachedHeaders.remove(l);
429       }
430
431       if (status == MESSAGE) {
432         cachedMessages.remove(l);
433         writeMsgFile();
434       }
435     }
436
437     return true;
438   }
439
440   /**
441    * Invalidates the entire cache. Usually called when the uidValidity
442    * is changed.
443    */

444   public void invalidateCache() {
445     File[] matchingFiles = cacheDir.listFiles();
446     if (matchingFiles != null)
447       for (int j = 0; j < matchingFiles.length; j++) {
448         if (matchingFiles[j].isFile())
449           matchingFiles[j].delete();
450       }
451
452     cachedMessages = new Vector JavaDoc();
453     cachedFlags = new HashMap JavaDoc();
454     cachedHeaders = new HashMap JavaDoc();
455
456     getChangeAdapter().invalidate();
457   }
458
459
460   /**
461    * Adds the messages to the given folder. Returns the uids for the
462    * message.
463    *
464    * This method changes both the client cache as well as the server, if
465    * the server is available.
466    */

467   public long[] appendMessages(MessageInfo[] msgs) throws MessagingException {
468     if (getFolderInfo().shouldBeConnected()) {
469       getFolderInfo().appendMessages(msgs);
470     } else {
471       LocalMimeMessage[] localMsgs = new LocalMimeMessage[msgs.length];
472       for (int i = 0; i < localMsgs.length; i++) {
473         Message m = msgs[i].getMessage();
474         localMsgs[i] = new LocalMimeMessage((MimeMessage)m);
475       }
476       MessageCountEvent mce = new MessageCountEvent(getFolderInfo().getFolder(), MessageCountEvent.ADDED, false, localMsgs);
477       getFolderInfo().messagesAdded(mce);
478     }
479
480     return new long[] {};
481   }
482
483   /**
484    * Removes all messages marked as 'DELETED' from the given folder.
485    * Returns the uids of all the removed messages.
486    *
487    * Note that if any message fails to be removed, then the ones
488    * that have succeeded should be returned in the long[].
489    *
490    * This method changes both the client cache as well as the server, if
491    * the server is available.
492    */

493   public void expungeMessages() throws MessagingException {
494     try {
495       getChangeAdapter().expunge();
496       Vector JavaDoc removedMessages = new Vector JavaDoc();
497       for (int i = cachedMessages.size() -1; i >= 0; i--) {
498         long uid = ((Long JavaDoc) cachedMessages.elementAt(i)).longValue();
499         Flags f = getFlagsFromCache(uid);
500         if (f.contains(Flags.Flag.DELETED)) {
501           Message m = getFolderInfo().getMessageInfoByUid(uid).getMessage();
502           ((CachingMimeMessage)m).setExpungedValue(true);
503           removedMessages.add(m);
504         }
505       }
506
507       if (removedMessages.size() > 0) {
508         Message[] rmMsg = new Message[removedMessages.size()];
509         for (int i = 0; i < removedMessages.size(); i++)
510           rmMsg[i] = (Message) removedMessages.elementAt(i);
511
512         MessageCountEvent mce = new MessageCountEvent(getFolderInfo().getFolder(), MessageCountEvent.REMOVED, true, rmMsg);
513         getFolderInfo().messagesRemoved(mce);
514       }
515     } catch (IOException ioe) {
516       throw new MessagingException(ioe.getMessage(), ioe);
517     }
518   }
519
520   /**
521    * This returns the uid's of the message which exist in updatedUids, but
522    * not in the current list of messsages.
523    */

524   public long[] getAddedMessages(long[] uids, long newUidValidity) throws StaleCacheException {
525     if (newUidValidity != uidValidity) {
526       throw new StaleCacheException(uidValidity, newUidValidity);
527     }
528     long[] added = new long[uids.length];
529     int addedCount = 0;
530
531     for (int i = 0; i < uids.length; i++) {
532       if (! cachedMessages.contains(new Long JavaDoc(uids[i]))) {
533         added[addedCount++]=uids[i];
534       }
535     }
536
537     long[] returnValue = new long[addedCount];
538     if (addedCount > 0)
539       System.arraycopy(added, 0, returnValue, 0, addedCount);
540
541     return returnValue;
542   }
543
544   /**
545    * This returns the uid's of the message which exist in the current
546    * list of messages, but no longer exist in the updatedUids.
547    */

548   public long[] getRemovedMessages(long[] uids, long newUidValidity) throws StaleCacheException {
549     if (newUidValidity != uidValidity) {
550       throw new StaleCacheException(uidValidity, newUidValidity);
551     }
552     Vector JavaDoc remainders = new Vector JavaDoc(cachedMessages);
553
554     for (int i = 0; i < uids.length; i++) {
555       remainders.remove(new Long JavaDoc(uids[i]));
556     }
557
558     long[] returnValue = new long[remainders.size()];
559     for (int i = 0; i < remainders.size(); i++)
560       returnValue[i] = ((Long JavaDoc) remainders.elementAt(i)).longValue();
561
562     return returnValue;
563   }
564
565   /**
566    * This returns the message id's of all the currently cached messages.
567    * Note that only the headers and flags of the message need to be
568    * cached for a message to be considered in the cache.
569    */

570   public long[] getMessageUids() {
571     long[] returnValue = new long[cachedMessages.size()];
572     for (int i = 0; i < cachedMessages.size(); i++)
573       returnValue[i] = ((Long JavaDoc) cachedMessages.elementAt(i)).longValue();
574
575     return returnValue;
576   }
577
578   /**
579    * Gets a DataHandler from the cache. Returns null if no handler is
580    * available in the cache.
581    */

582   protected DataHandler JavaDoc getHandlerFromCache(long uid) {
583     File f = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
584     if (f.exists()) {
585       try {
586         FileInputStream fis = new FileInputStream(f);
587         MimeMessage mm = new MimeMessage(net.suberic.pooka.Pooka.getDefaultSession(), fis);
588         javax.activation.DataSource JavaDoc source = new WrappedMimePartDataSource (mm, this, uid);
589         DataHandler JavaDoc dh = new DataHandler JavaDoc(source);
590         return dh;
591       } catch (Exception JavaDoc e) {
592         return null;
593       }
594       //return new DataHandler(new FileDataSource(f));
595
} else
596       return null;
597   }
598
599   /**
600    * Gets the InternetHeaders from the cache. Returns null if no headers are
601    * available in the cache.
602    */

603   InternetHeaders getHeadersFromCache(long uid) throws MessagingException {
604     InternetHeaders returnValue = (InternetHeaders) cachedHeaders.get(new Long JavaDoc(uid));
605     if (returnValue != null) {
606       return returnValue;
607     } else {
608
609       File f = new File(cacheDir, uid +DELIMETER + HEADER_EXT);
610       if (f.exists())
611         try {
612           FileInputStream fis = new FileInputStream(f);
613           returnValue = new InternetHeaders(fis);
614           cachedHeaders.put(new Long JavaDoc(uid), returnValue);
615           try {
616             fis.close();
617           } catch (java.io.IOException JavaDoc ioe) {
618           }
619           return returnValue;
620         } catch (FileNotFoundException fnfe) {
621           throw new MessagingException(fnfe.getMessage(), fnfe);
622         }
623       else
624         return null;
625     }
626   }
627
628   /**
629    * Gets the Flags from the cache. Returns null if no flagss are
630    * available in the cache.
631    */

632   Flags getFlagsFromCache(long uid) {
633     Flags returnValue = (Flags) cachedFlags.get(new Long JavaDoc(uid));
634     if (returnValue != null) {
635       return new Flags(returnValue);
636     } else {
637       File f = new File(cacheDir, uid + DELIMETER + FLAG_EXT);
638       if (f.exists()) {
639         try {
640           Flags newFlags = new Flags();
641           BufferedReader in = new BufferedReader(new FileReader(f));
642           for (String JavaDoc currentLine = in.readLine(); currentLine != null; currentLine = in.readLine()) {
643
644             if (currentLine.equalsIgnoreCase("Deleted"))
645               newFlags.add(Flags.Flag.DELETED);
646             else if (currentLine.equalsIgnoreCase("Answered"))
647               newFlags.add(Flags.Flag.ANSWERED);
648             else if (currentLine.equalsIgnoreCase("Draft"))
649               newFlags.add(Flags.Flag.DRAFT);
650             else if (currentLine.equalsIgnoreCase("Flagged"))
651               newFlags.add(Flags.Flag.FLAGGED);
652             else if (currentLine.equalsIgnoreCase("Recent"))
653               newFlags.add(Flags.Flag.RECENT);
654             else if (currentLine.equalsIgnoreCase("SEEN"))
655               newFlags.add(Flags.Flag.SEEN);
656             else
657               newFlags.add(new Flags(currentLine));
658           }
659
660           cachedFlags.put(new Long JavaDoc(uid), newFlags);
661           return newFlags;
662         } catch (FileNotFoundException fnfe) {
663           System.out.println("caught filenotfoundexception.");
664           return null;
665         } catch (IOException ioe) {
666           System.out.println("caught ioexception.");
667           return null;
668         }
669       }
670
671       return null;
672     }
673   }
674
675   /**
676    * Saves the given flags to the cache.
677    */

678   protected void saveFlags(long uid, long newUidValidity, Flags f) throws MessagingException {
679     Flags oldFlags = getFlagsFromCache(uid);
680     if (oldFlags == null || ! oldFlags.equals(f)) {
681       cachedFlags.put(new Long JavaDoc(uid), f);
682       try {
683         File outFile = new File(cacheDir, uid + DELIMETER + FLAG_EXT);
684         if (outFile.exists())
685           outFile.delete();
686
687         FileWriter fw = new FileWriter(outFile);
688         BufferedWriter bw = new BufferedWriter(fw);
689
690         Flags.Flag[] systemFlags = f.getSystemFlags();
691         for (int i = 0; i < systemFlags.length; i++) {
692           if (systemFlags[i] == Flags.Flag.ANSWERED) {
693             bw.write("Answered");
694             bw.newLine();
695           } else if (systemFlags[i] == Flags.Flag.DELETED) {
696             bw.write("Deleted");
697             bw.newLine();
698           } else if (systemFlags[i] == Flags.Flag.DRAFT) {
699             bw.write("Draft");
700             bw.newLine();
701           } else if (systemFlags[i] == Flags.Flag.FLAGGED) {
702             bw.write("Flagged");
703             bw.newLine();
704           } else if (systemFlags[i] == Flags.Flag.RECENT) {
705             // let's not cache the recent flag, eh?
706
} else if (systemFlags[i] == Flags.Flag.SEEN) {
707             bw.write("Seen");
708             bw.newLine();
709           }
710         }
711
712         String JavaDoc[] userFlags = f.getUserFlags();
713         for (int i = 0; i < userFlags.length; i++) {
714           bw.write(userFlags[i]);
715           bw.newLine();
716         }
717
718         bw.flush();
719         bw.close();
720       } catch (IOException ioe) {
721         throw new MessagingException (ioe.getMessage(), ioe);
722       }
723     }
724   }
725
726   protected void writeToChangeLog(long uid, Flags flags, int status) throws MessagingException {
727     try {
728       if (status == REMOVED)
729         getChangeAdapter().setFlags(uid, flags, false);
730       else
731         getChangeAdapter().setFlags(uid, flags, true);
732     } catch (IOException ioe) {
733       throw new MessagingException (ioe.getMessage(), ioe);
734     }
735   }
736
737   /**
738    * Initializes the cache from the file system.
739    */

740   public void loadCache() {
741     cachedMessages = new Vector JavaDoc();
742     cachedFlags = new HashMap JavaDoc();
743     cachedHeaders = new HashMap JavaDoc();
744
745     File msgListFile = new File(cacheDir, "messageList");
746     if (msgListFile.exists()) {
747       try {
748         BufferedReader in = new BufferedReader(new FileReader(msgListFile));
749         for (String JavaDoc nextLine = in.readLine(); nextLine != null; nextLine = in.readLine()) {
750           Long JavaDoc l = new Long JavaDoc(nextLine);
751           cachedMessages.add(l);
752           // this has the side effect of loading the cached flags
753
// to the cachedFlags HashMap. -- i think we do that now when
754
// we fetch?
755
//getFlagsFromCache(l.longValue());
756
//getHeadersFromCache(l.longValue());
757
}
758       } catch (Exception JavaDoc e) { }
759     }
760
761     File validityFile = new File(cacheDir, "validity");
762     if (validityFile.exists()) {
763       try {
764         BufferedReader in = new BufferedReader(new FileReader(validityFile));
765         uidValidity = Long.parseLong(in.readLine());
766       } catch (Exception JavaDoc e) {
767       }
768     }
769
770     File localMsgFile = new File(cacheDir, "lastLocal");
771     if (localMsgFile.exists()) {
772       try {
773         BufferedReader in = new BufferedReader(new FileReader(localMsgFile));
774         lastLocalUID = Long.parseLong(in.readLine());
775       } catch (Exception JavaDoc e) {
776       }
777     }
778
779   }
780
781   public void writeMsgFile() {
782     try {
783       File msgListFile = new File(cacheDir, "messageList");
784       if (! msgListFile.exists()) {
785         msgListFile.createNewFile();
786       }
787       BufferedWriter out = new BufferedWriter(new FileWriter(msgListFile));
788       for (int i = 0; i < cachedMessages.size(); i++) {
789         out.write(((Long JavaDoc) cachedMessages.elementAt(i)).toString());
790         out.newLine();
791       }
792       out.flush();
793       out.close();
794     } catch (Exception JavaDoc e) {
795     }
796   }
797
798   /**
799    * Writes any offline changes made back to the server.
800    */

801   public void writeChangesToServer(Folder f) throws MessagingException {
802     try {
803       getChangeAdapter().writeChanges((UIDFolder) f, getFolderInfo());
804     } catch (IOException ioe) {
805       throw new MessagingException(net.suberic.pooka.Pooka.getProperty("error.couldNotGetChanges", "Error: could not get cached changes."), ioe);
806     }
807   }
808
809   public CachingFolderInfo getFolderInfo() {
810     return folderInfo;
811   }
812
813   /**
814    * Returns the size of the given message, or -1 if the message is
815    * not cached.
816    */

817   public int getSize(long uid) {
818     File f = new File(cacheDir, uid + DELIMETER + CONTENT_EXT);
819     if (! f.exists()) {
820       return (int)f.length();
821     } else
822       return -1;
823
824   }
825
826   private class CacheID {
827     long id;
828     long lastAccessed;
829     long size;
830
831     CacheID(long newId, long newLastAccessed, long newSize) {
832       id = newId;
833       lastAccessed = newLastAccessed;
834       size = newSize;
835     }
836   }
837
838   private class CacheFilenameFilter implements FilenameFilter {
839     long uid;
840     int status;
841
842     public CacheFilenameFilter(long newUid, int newStatus) {
843       uid = newUid;
844       status = newStatus;
845     }
846
847     public boolean accept(File dir, String JavaDoc name) {
848       if (status == MESSAGE || status == CONTENT) {
849         if (name.startsWith(uid + DELIMETER + CONTENT_EXT))
850           return true;
851       }
852
853       if (status == FLAGS || status == FLAGS_AND_HEADERS || status == MESSAGE) {
854         if (name.startsWith(uid + DELIMETER + FLAG_EXT))
855           return true;
856       }
857
858       if (status == HEADERS || status == FLAGS_AND_HEADERS || status == MESSAGE) {
859         if (name.startsWith(uid + DELIMETER + HEADER_EXT))
860           return true;
861       }
862
863       return false;
864     }
865   }
866
867   /**
868    * This returns the number of messages in the cache.
869    */

870   public int getMessageCount() {
871     return cachedMessages.size();
872   }
873
874   /**
875    * This returns the number of unread messages in the cache.
876    */

877   public int getUnreadMessageCount() throws MessagingException {
878     // sigh.
879
int unreadCount = 0;
880     for (int i = 0; i < cachedMessages.size(); i++) {
881       Flags f = getFlags(((Long JavaDoc) cachedMessages.elementAt(i)).longValue(), uidValidity, false);
882       if (! f.contains(Flags.Flag.SEEN)) {
883         unreadCount++;
884       }
885     }
886
887     return unreadCount;
888   }
889
890   /**
891    * Returns whether a given uid exists fully in the cache or not.
892    */

893   public boolean isFullyCached(long uid) {
894     DataHandler JavaDoc dh = getHandlerFromCache(uid);
895     return (dh != null);
896   }
897
898   /**
899    * Returns the status of the given uid.
900    */

901   public int getCacheStatus(long uid) throws MessagingException {
902     if (isFullyCached(uid))
903       return CONTENT;
904     else {
905       InternetHeaders ih = getHeadersFromCache(uid);
906       Flags f = getFlagsFromCache(uid);
907       if (ih != null && f != null)
908         return FLAGS_AND_HEADERS;
909       else if (ih != null)
910         return HEADERS;
911       else if (f != null)
912         return FLAGS;
913       else
914         return NOT_CACHED;
915     }
916
917   }
918
919   public long getUIDValidity() {
920     return uidValidity;
921   }
922
923   public void setUIDValidity(long newValidity) {
924     try {
925       File f = new File(cacheDir, "validity");
926       if (f.exists())
927         f.delete();
928
929       f.createNewFile();
930
931       BufferedWriter out = new BufferedWriter(new FileWriter(f));
932       out.write(Long.toString(newValidity));
933       out.flush();
934       out.close();
935     } catch (Exception JavaDoc e) {
936     }
937
938     uidValidity = newValidity;
939   }
940
941   public ChangeCache getChangeAdapter() {
942     return changes;
943   }
944
945   /**
946    * Searches all of the cached messages and returns those which match
947    * the given SearchTerm.
948    */

949   public MessageInfo[] search(javax.mail.search.SearchTerm JavaDoc term) throws
950     javax.mail.MessagingException JavaDoc {
951     Vector JavaDoc matches = new Vector JavaDoc();
952
953     for (int i = 0; i < cachedMessages.size(); i++) {
954       MessageInfo info = getFolderInfo().getMessageInfoByUid(((Long JavaDoc)cachedMessages.elementAt(i)).longValue());
955       Message m = info.getMessage();
956       if (term.match(m))
957         matches.add(info);
958     }
959
960     MessageInfo[] returnValue = new MessageInfo[matches.size()];
961     for (int i = 0; i < matches.size(); i++) {
962       returnValue[i] = (MessageInfo) matches.elementAt(i);
963     }
964
965     return returnValue;
966   }
967
968   /**
969    * A class representing a local, cache-only message.
970    */

971   public class LocalMimeMessage extends javax.mail.internet.MimeMessage JavaDoc {
972
973     long uid;
974
975     public LocalMimeMessage(MimeMessage m) throws MessagingException {
976       super(m);
977       uid = generateLocalUID();
978     }
979
980     public long getUID() {
981       return uid;
982     }
983   }
984
985   /**
986    * Generates a local UID.
987    */

988   public synchronized long generateLocalUID() {
989     lastLocalUID--;
990     try {
991       File f = new File(cacheDir, "lastLocal");
992       if (f.exists())
993         f.delete();
994
995       f.createNewFile();
996
997       BufferedWriter out = new BufferedWriter(new FileWriter(f));
998       out.write(Long.toString(lastLocalUID));
999       out.flush();
1000      out.close();
1001    } catch (Exception JavaDoc e) {
1002    }
1003    return lastLocalUID;
1004  }
1005}
1006
1007
1008
Popular Tags