KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.suberic.pooka.cache;
2 import javax.mail.*;
3 import javax.mail.event.MessageCountEvent JavaDoc;
4 import javax.mail.internet.MimeMessage JavaDoc;
5 import javax.mail.event.MessageChangedEvent JavaDoc;
6 import javax.mail.event.ConnectionEvent JavaDoc;
7 import java.util.Vector JavaDoc;
8 import java.util.List JavaDoc;
9 import java.util.logging.*;
10 import java.util.StringTokenizer JavaDoc;
11 import java.util.HashMap JavaDoc;
12 import java.io.File JavaDoc;
13 import net.suberic.pooka.*;
14 import net.suberic.pooka.gui.MessageProxy;
15 import net.suberic.pooka.gui.FolderTableModel;
16 import net.suberic.util.thread.ActionThread;
17
18 /**
19  * A FolderInfo which caches its messages in a MessageCache.
20  * @author Allen Petersen
21  * @version $Revision: 1673 $
22  */

23
24 public class CachingFolderInfo extends net.suberic.pooka.UIDFolderInfo {
25   private MessageCache cache = null;
26
27   // the resource for the folder disconnected message
28
protected static String JavaDoc disconnectedMessage = "error.CachingFolder.disconnected";
29
30   boolean autoCache = false;
31
32   public CachingFolderInfo(StoreInfo parent, String JavaDoc fname) {
33     super(parent, fname);
34
35     if (! getCacheHeadersOnly()) {
36       autoCache = Pooka.getProperty(getFolderProperty() + ".autoCache", Pooka.getProperty(getParentStore().getStoreProperty() + ".autoCache", Pooka.getProperty("Pooka.autoCache", "false"))).equalsIgnoreCase("true");
37     }
38
39     Pooka.getResources().addValueChangeListener(this, getFolderProperty() + ".autoCache");
40   }
41
42   public CachingFolderInfo(FolderInfo parent, String JavaDoc fname) {
43     super(parent, fname);
44
45     if (! getCacheHeadersOnly()) {
46       autoCache = Pooka.getProperty(getFolderProperty() + ".autoCache", Pooka.getProperty(getParentStore().getStoreProperty() + ".autoCache", Pooka.getProperty("Pooka.autoCache", "false"))).equalsIgnoreCase("true");
47     }
48
49     Pooka.getResources().addValueChangeListener(this, getFolderProperty() + ".autoCache");
50     Pooka.getResources().addValueChangeListener(this, getFolderProperty() + ".cacheHeadersOnly");
51     Pooka.getResources().addValueChangeListener(this, getParentStore().getStoreProperty() + ".autoCache");
52     Pooka.getResources().addValueChangeListener(this, getParentStore().getStoreProperty() + ".cacheHeadersOnly");
53   }
54
55   /**
56    * Loads the column names and sizes.
57    */

58   protected FetchProfile createColumnInformation() {
59     FetchProfile fp = super.createColumnInformation();
60     // we need to get the full headers for the CachingFolderInfo.
61
fp = new FetchProfile();
62     fp.add(FetchProfile.Item.FLAGS);
63     fp.add(com.sun.mail.imap.IMAPFolder.FetchProfileItem.HEADERS);
64     return fp;
65   }
66
67   /**
68    * This actually loads up the Folder object itself. This is used so
69    * that we can have a FolderInfo even if we're not connected to the
70    * parent Store.
71    *
72    * Before we load the folder, the FolderInfo has the state of NOT_LOADED.
73    * Once the parent store is connected, we can try to load the folder.
74    * If the load is successful, we go to a CLOSED state. If it isn't,
75    * then we can either return to NOT_LOADED, or INVALID.
76    */

77   public void loadFolder() {
78     if (cache == null) {
79       try {
80         this.cache = new SimpleFileCache(this, getCacheDirectory());
81         type = type | Folder.HOLDS_MESSAGES;
82         setStatus(DISCONNECTED);
83       } catch (java.io.IOException JavaDoc ioe) {
84         System.out.println("Error creating cache!");
85         ioe.printStackTrace();
86         return;
87       }
88     }
89
90     if (isLoaded() || (loading && children == null))
91       return;
92
93     Folder[] tmpFolder = null;
94     Folder tmpParentFolder;
95
96     try {
97       loading = true;
98       if (getParentStore().isConnected()) {
99         if (getParentFolder() == null) {
100           try {
101             if (getLogger().isLoggable(Level.FINE))
102               System.out.println(Thread.currentThread() + "loading folder " + getFolderID() + ": checking parent store connection.");
103
104             Store store = getParentStore().getStore();
105             // first see if we're a namespace
106
try {
107               if (getLogger().isLoggable(Level.FINE)) {
108                 getLogger().log(Level.FINE, "checking to see if " + getFolderID() + " is a shared folder.");
109               }
110
111               Folder[] sharedFolders = store.getSharedNamespaces();
112
113               if (sharedFolders != null && sharedFolders.length > 0) {
114                 for (int i = 0; ( tmpFolder == null || tmpFolder.length == 0 ) && i < sharedFolders.length; i++) {
115                   if (sharedFolders[i].getName().equalsIgnoreCase(getFolderName())) {
116
117                     if (!mNamespace) {
118                       Pooka.setProperty(getFolderID() + "._namespace", "true");
119                       mNamespace = true;
120                     }
121
122                     tmpFolder = new Folder[1];
123                     tmpFolder[0] = sharedFolders[i] ;
124                   }
125                 }
126               }
127             } catch (Exception JavaDoc e) {
128               // if we get a not supported exception or some such here,
129
// just ignore it.
130
}
131
132             if (tmpFolder == null || tmpFolder.length == 0) {
133               // not a shared namespace
134
tmpParentFolder = store.getDefaultFolder();
135               if (getLogger().isLoggable(Level.FINE)) {
136                 getLogger().log(Level.FINE, "got " + tmpParentFolder + " as Default Folder for store.");
137                 getLogger().log(Level.FINE, "doing a list on default folder " + tmpParentFolder + " for folder " + getFolderName());
138               }
139
140               tmpFolder = tmpParentFolder.list(getFolderName());
141             }
142
143             if (getLogger().isLoggable(Level.FINE))
144               getLogger().log(Level.FINE, "got " + tmpFolder + " as Folder for folder " + getFolderID() + ".");
145
146           } catch (MessagingException me) {
147             if (getLogger().isLoggable(Level.FINE)) {
148               getLogger().log(Level.FINE, Thread.currentThread() + "loading folder " + getFolderID() + ": caught messaging exception from parentStore getting folder: " + me);
149               me.printStackTrace();
150             }
151             tmpFolder =null;
152           }
153         } else {
154           if (!getParentFolder().isLoaded())
155             getParentFolder().loadFolder();
156           if (!getParentFolder().isLoaded()) {
157             tmpFolder = null;
158           } else {
159             tmpParentFolder = getParentFolder().getFolder();
160             if (tmpParentFolder != null) {
161               tmpFolder = tmpParentFolder.list(getFolderName());
162             } else {
163               tmpFolder = null;
164             }
165           }
166         }
167         if (tmpFolder != null && tmpFolder.length > 0) {
168           setFolder(tmpFolder[0]);
169           setStatus(CLOSED);
170           getFolder().addMessageChangedListener(this);
171         } else {
172           if (cache != null)
173             setStatus(CACHE_ONLY);
174           else
175             setStatus(INVALID);
176           setFolder(new FolderProxy(getFolderName()));
177         }
178       } else {
179         setFolder(new FolderProxy(getFolderName()));
180       }
181
182     } catch (MessagingException me) {
183       if (getLogger().isLoggable(Level.FINE)) {
184         getLogger().log(Level.FINE, Thread.currentThread() + "loading folder " + getFolderID() + ": caught messaging exception; setting loaded to false: " + me.getMessage() );
185         me.printStackTrace();
186       }
187       setStatus(NOT_LOADED);
188       setFolder(new FolderProxy(getFolderName()));
189     } finally {
190       initializeFolderInfo();
191       loading = false;
192     }
193   }
194
195   /**
196    * called when the folder is opened.
197    */

198   public void opened (ConnectionEvent JavaDoc e) {
199     super.opened(e);
200     rematchFilters();
201   }
202
203   /**
204    * This method opens the Folder, and sets the FolderInfo to know that
205    * the Folder should be open. You should use this method instead of
206    * calling getFolder().open(), because if you use this method, then
207    * the FolderInfo will try to keep the Folder open, and will try to
208    * reopen the Folder if it gets closed before closeFolder is called.
209    *
210    * This method can also be used to reset the mode of an already
211    * opened folder.
212    */

213   public void openFolder(int mode, boolean pConnectStore) throws MessagingException {
214     try {
215       if (getLogger().isLoggable(Level.FINE))
216         getLogger().log(Level.FINE, this + ": checking parent store.");
217
218
219       if (!getParentStore().isConnected() && pConnectStore) {
220         if (getLogger().isLoggable(Level.FINE))
221           getLogger().log(Level.FINE, this + ": parent store isn't connected. trying connection.");
222         getParentStore().connectStore();
223       }
224
225       if (getLogger().isLoggable(Level.FINE))
226         getLogger().log(Level.FINE, this + ": loading folder.");
227
228       if (! isLoaded() && status != CACHE_ONLY)
229         loadFolder();
230
231       if (getLogger().isLoggable(Level.FINE))
232         getLogger().log(Level.FINE, this + ": folder loaded. status is " + status);
233
234       if (getLogger().isLoggable(Level.FINE))
235         getLogger().log(Level.FINE, this + ": checked on parent store. trying isLoaded() and isAvailable().");
236
237       if (status == CLOSED || status == LOST_CONNECTION || status == DISCONNECTED) {
238         if (getLogger().isLoggable(Level.FINE))
239           getLogger().log(Level.FINE, this + ": isLoaded() and isAvailable().");
240         if (getFolder().isOpen()) {
241           if (getFolder().getMode() == mode)
242             return;
243           else {
244             getFolder().close(false);
245             openFolder(mode);
246           }
247         } else {
248           Folder f = getFolder();
249           getFolder().open(mode);
250           updateFolderOpenStatus(true);
251           resetMessageCounts();
252         }
253       } else if (status == INVALID) {
254         throw new MessagingException(Pooka.getProperty("error.folderInvalid", "Error: folder is invalid. ") + getFolderID());
255       }
256     } catch (MessagingException me) {
257       setStatus(DISCONNECTED);
258       throw me;
259     } finally {
260       resetMessageCounts();
261     }
262   }
263
264
265   /**
266    * Called when the store in disconnected.
267    */

268   public void disconnected(ConnectionEvent JavaDoc e) {
269     super.disconnected(e);
270     rematchFilters();
271   }
272
273   /**
274    * Called when the folder is closed.
275    */

276   public void closed(ConnectionEvent JavaDoc e) {
277     super.closed(e);
278     rematchFilters();
279   }
280
281   /**
282    * gets all of the message proxies associated with this folder info
283    * and notifies them that they need to rematch their filters.
284    */

285   protected void rematchFilters() {
286     if (folderTableModel != null) {
287       List JavaDoc allProxies = folderTableModel.getAllProxies();
288       for (int i = 0; i < allProxies.size(); i++) {
289         ((MessageProxy) allProxies.get(i)).clearMatchedFilters();
290       }
291       //loaderThread.loadMessages(allProxies);
292
mMessageLoader.loadMessages(allProxies);
293     }
294   }
295
296   /**
297    * During loadAllMessages, updates the display to say that we're loading
298    * messages.
299    */

300   protected void updateDisplay(boolean start) {
301     if (getFolderDisplayUI() != null) {
302       if (start) {
303         getFolderDisplayUI().setBusy(true);
304         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("messages.CachingFolder.loading.starting", "Loading messages."));
305       } else {
306         getFolderDisplayUI().setBusy(false);
307         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("messages.CachingFolder.loading.finished", "Done loading messages."));
308       }
309     }
310   }
311
312   /**
313    * While loading messages, attempts to update the folder status.
314    */

315   protected void updateFolderStatusForLoading() throws MessagingException {
316     if (preferredStatus < DISCONNECTED && !(isConnected() && getParentStore().getConnection().getStatus() == NetworkConnection.CONNECTED )) {
317       try {
318         openFolder(Folder.READ_WRITE);
319       } catch (MessagingException me) {
320         uidValidity = cache.getUIDValidity();
321         preferredStatus = DISCONNECTED;
322       }
323     }
324   }
325
326   /**
327    * Loads the MessageInfos and MesageProxies. Returns a List of
328    * newly created MessageProxies.
329    */

330   protected List JavaDoc createInfosAndProxies() throws MessagingException {
331
332     List JavaDoc messageProxies = new Vector JavaDoc();
333
334     if (getStatus() > CONNECTED) {
335       uidValidity = cache.getUIDValidity();
336     }
337
338     if (isConnected()) {
339       try {
340         // load the list of uid's.
341

342         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.CachingFolder.synchronizing.writingChanges", "Writing local changes to server..."));
343
344         // first write all the changes that we made back to the server.
345
getCache().writeChangesToServer(getFolder());
346
347         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing.loading", "Loading messages from folder..."));
348
349         FetchProfile uidFetchProfile = new FetchProfile();
350         uidFetchProfile.add(UIDFolder.FetchProfileItem.UID);
351         if (getLogger().isLoggable(Level.FINE))
352           getLogger().log(Level.FINE, "getting messages.");
353
354         Message JavaDoc[] messages = getFolder().getMessages();
355         if (getLogger().isLoggable(Level.FINE))
356           getLogger().log(Level.FINE, "fetching messages.");
357         getFolder().fetch(messages, uidFetchProfile);
358         if (getLogger().isLoggable(Level.FINE))
359           getLogger().log(Level.FINE, "done fetching messages. getting uid's");
360
361         long[] uids = new long[messages.length];
362
363         for (int i = 0; i < messages.length; i++) {
364           uids[i] = getUID(messages[i]);
365         }
366
367         MessageInfo mi;
368
369         for (int i = 0; i < uids.length; i++) {
370           Message JavaDoc m = new CachingMimeMessage(this, uids[i]);
371           mi = new MessageInfo(m, this);
372
373           messageProxies.add(new MessageProxy(getColumnValues() , mi));
374           messageToInfoTable.put(m, mi);
375           uidToInfoTable.put(new Long JavaDoc(uids[i]), mi);
376         }
377
378         return messageProxies;
379       } catch (Exception JavaDoc e) {
380         final Exception JavaDoc fe = e;
381         javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
382             public void run() {
383               if (getFolderDisplayUI() != null) {
384                 getFolderDisplayUI().showError(Pooka.getProperty("error.CachingFolder.synchronzing", "Error synchronizing with folder"), Pooka.getProperty("error.CachingFolder.synchronzing.title", "Error synchronizing with folder"), fe);
385               } else {
386                 Pooka.getUIFactory().showError(Pooka.getProperty("error.CachingFolder.synchronzing", "Error synchronizing with folder"), Pooka.getProperty("error.CachingFolder.synchronzing.title", "Error synchronizing with folder"), fe);
387
388               }
389             }
390           });
391       }
392     }
393
394     long[] uids = cache.getMessageUids();
395     MessageInfo mi;
396
397     for (int i = 0; i < uids.length; i++) {
398       Message JavaDoc m = new CachingMimeMessage(this, uids[i]);
399       mi = new MessageInfo(m, this);
400       MessageProxy mp = new MessageProxy(getColumnValues() , mi);
401       mp.setRefresh(true);
402       messageProxies.add(mp);
403       messageToInfoTable.put(m, mi);
404       uidToInfoTable.put(new Long JavaDoc(uids[i]), mi);
405     }
406
407     return messageProxies;
408   }
409
410   /**
411    * Updates any caching information, if necessary.
412    */

413   protected void updateCache() throws MessagingException {
414     if (isConnected()) {
415       synchronizeCache();
416     }
417   }
418
419   /**
420    * Fetches the information for the given messages using the given
421    * FetchProfile.
422    */

423   /* original version
424      public void fetch(MessageInfo[] messages, FetchProfile profile) throws MessagingException {
425      // if we're connected, go ahead and fetch these.
426
427      if (getLogger().isLoggable(Level.FINE)) {
428      if (messages == null)
429      getLogger().log(Level.FINE, "cachingFolderInfo: fetching with null messages.");
430      else
431      getLogger().log(Level.FINE, "cachingFolderInfo: fetching " + messages.length + " messages.");
432      }
433
434      int cacheStatus = -1;
435      boolean doFlags = profile.contains(FetchProfile.Item.FLAGS);
436      boolean doHeaders = (profile.contains(FetchProfile.Item.ENVELOPE) || profile.contains(FetchProfile.Item.CONTENT_INFO));
437
438      if (doFlags && doHeaders) {
439      cacheStatus = SimpleFileCache.FLAGS_AND_HEADERS;
440      } else if (doFlags) {
441      cacheStatus = SimpleFileCache.FLAGS;
442      } else if (doHeaders) {
443      cacheStatus = SimpleFileCache.HEADERS;
444      }
445
446      if (isConnected()) {
447
448      if (getLogger().isLoggable(Level.FINE)) {
449      getLogger().log(Level.FINE, "CachingFolderInfo: running fetch against folder.");
450      }
451      super.fetch(messages, profile);
452
453      if (cacheStatus != -1) {
454      for (int i = 0; i < messages.length; i++) {
455      Message m = messages[i].getRealMessage();
456      if (m != null) {
457      long uid = getUID(m);
458      getCache().cacheMessage((MimeMessage)m, uid, cache.getUIDValidity(), cacheStatus);
459      }
460      }
461      }
462      } else {
463      // if we're not connected, then go ahead and preload the cache for
464      // these.
465      for (int i = 0; i < messages.length; i++) {
466      Message current = messages[i].getMessage();
467      if (current != null && current instanceof UIDMimeMessage) {
468      long uid = ((UIDMimeMessage) current).getUID();
469      if (cacheStatus == SimpleFileCache.FLAGS_AND_HEADERS || cacheStatus == SimpleFileCache.FLAGS) {
470      getCache().getFlags(uid, cache.getUIDValidity());
471      }
472
473      if (cacheStatus == SimpleFileCache.FLAGS_AND_HEADERS || cacheStatus == SimpleFileCache.HEADERS) {
474      getCache().getHeaders(uid, cache.getUIDValidity());
475      }
476      }
477
478      messages[i].setFetched(true);
479      }
480      }
481
482      }
483   */

484   // new version
485
public void fetch(MessageInfo[] messages, FetchProfile profile) throws MessagingException {
486     // if we're connected, go ahead and fetch these.
487

488     if (getLogger().isLoggable(Level.FINE)) {
489       if (messages == null)
490         getLogger().log(Level.FINE, "cachingFolderInfo: fetching with null messages.");
491       else
492         getLogger().log(Level.FINE, "cachingFolderInfo: fetching " + messages.length + " messages.");
493     }
494
495     int cacheStatus = -1;
496     boolean doFlags = profile.contains(FetchProfile.Item.FLAGS);
497     String JavaDoc[] headers = profile.getHeaderNames();
498     boolean doHeaders = (profile.contains(FetchProfile.Item.ENVELOPE) || profile.contains(FetchProfile.Item.CONTENT_INFO) || profile.contains(com.sun.mail.imap.IMAPFolder.FetchProfileItem.HEADERS) || (headers != null && headers.length > 0));
499
500     if (doFlags && doHeaders) {
501       cacheStatus = SimpleFileCache.FLAGS_AND_HEADERS;
502     } else if (doFlags) {
503       cacheStatus = SimpleFileCache.FLAGS;
504     } else if (doHeaders) {
505       cacheStatus = SimpleFileCache.HEADERS;
506     }
507
508     if (isConnected()) {
509
510       if (getLogger().isLoggable(Level.FINE)) {
511         getLogger().log(Level.FINE, "CachingFolderInfo: connected. checking for already-cached messages.");
512       }
513
514       if (doHeaders) {
515         // assume that headers don't change.
516
FetchProfile fp = new FetchProfile();
517         if (doFlags) {
518           fp.add(FetchProfile.Item.FLAGS);
519         }
520
521         java.util.LinkedList JavaDoc flagsOnly = new java.util.LinkedList JavaDoc();
522         java.util.LinkedList JavaDoc headersAndFlags = new java.util.LinkedList JavaDoc();
523
524         for (int i = 0 ; i < messages.length; i++) {
525           Message JavaDoc current = messages[i].getMessage();
526           if (current != null && current instanceof UIDMimeMessage) {
527             long uid = ((UIDMimeMessage) current).getUID();
528             if (getCache().getCacheStatus(((UIDMimeMessage) current).getUID()) >= MessageCache.HEADERS) {
529               flagsOnly.add(messages[i]);
530             } else {
531               headersAndFlags.add(messages[i]);
532             }
533           }
534         }
535
536         if (getLogger().isLoggable(Level.FINE)) {
537           getLogger().log(Level.FINE, "CachingFolderInfo: running fetch against " + headersAndFlags.size() + " full messages, plus " + flagsOnly.size() + " flags-only messages");
538         }
539
540         MessageInfo[] headersAndFlagsArray = (MessageInfo[]) headersAndFlags.toArray(new MessageInfo[0]);
541         MessageInfo[] flagsOnlyArray = (MessageInfo[]) flagsOnly.toArray(new MessageInfo[0]);
542         super.fetch(headersAndFlagsArray, profile);
543         super.fetch(flagsOnlyArray, fp);
544
545         if (cacheStatus != -1) {
546           for (int i = 0; i < headersAndFlagsArray.length; i++) {
547             Message JavaDoc m = headersAndFlagsArray[i].getRealMessage();
548             if (m != null) {
549               long uid = getUID(m);
550               getCache().cacheMessage((MimeMessage JavaDoc)m, uid, cache.getUIDValidity(), cacheStatus);
551             }
552           }
553
554           for (int i = 0; i < flagsOnlyArray.length; i++) {
555             Message JavaDoc m = flagsOnlyArray[i].getRealMessage();
556             if (m != null) {
557               long uid = getUID(m);
558               getCache().cacheMessage((MimeMessage JavaDoc)m, uid, cache.getUIDValidity(), MessageCache.FLAGS);
559             }
560           }
561         }
562       } else {
563         if (getLogger().isLoggable(Level.FINE)) {
564           getLogger().log(Level.FINE, "CachingFolderInfo: running fetch against folder.");
565         }
566         super.fetch(messages, profile);
567
568         if (cacheStatus != -1) {
569           for (int i = 0; i < messages.length; i++) {
570             Message JavaDoc m = messages[i].getRealMessage();
571             if (m != null) {
572               long uid = getUID(m);
573               getCache().cacheMessage((MimeMessage JavaDoc)m, uid, cache.getUIDValidity(), cacheStatus);
574             }
575           }
576         }
577
578       }
579     } else {
580       // if we're not connected, then go ahead and preload the cache for
581
// these.
582
for (int i = 0; i < messages.length; i++) {
583         Message JavaDoc current = messages[i].getMessage();
584         if (current != null && current instanceof UIDMimeMessage) {
585           long uid = ((UIDMimeMessage) current).getUID();
586           if (cacheStatus == SimpleFileCache.FLAGS_AND_HEADERS || cacheStatus == SimpleFileCache.FLAGS) {
587             getCache().getFlags(uid, cache.getUIDValidity());
588           }
589
590           if (cacheStatus == SimpleFileCache.FLAGS_AND_HEADERS || cacheStatus == SimpleFileCache.HEADERS) {
591             getCache().getHeaders(uid, cache.getUIDValidity());
592           }
593         }
594
595         messages[i].setFetched(true);
596       }
597     }
598
599   }
600   // end new version
601
/**
602    * Refreshes the headers for the given MessageInfo.
603    */

604   public void refreshHeaders(MessageInfo mi) throws MessagingException {
605     cacheMessage(mi, SimpleFileCache.HEADERS);
606   }
607
608   /**
609    * Refreshes the flags for the given MessageInfo.
610    */

611   public void refreshFlags(MessageInfo mi) throws MessagingException {
612     if (isConnected())
613       cacheMessage(mi, SimpleFileCache.FLAGS);
614   }
615
616
617   /**
618    * Gets the row number of the first unread message. Returns -1 if
619    * there are no unread messages, or if the FolderTableModel is not
620    * set or empty.
621    */

622
623   public int getFirstUnreadMessage() {
624     // one part brute, one part force, one part ignorance.
625

626     if (getLogger().isLoggable(Level.FINE))
627       getLogger().log(Level.FINE, "getting first unread message");
628
629     if (! tracksUnreadMessages())
630       return -1;
631
632     if (getFolderTableModel() == null)
633       return -1;
634
635     if (isConnected()) {
636       return super.getFirstUnreadMessage();
637     } else {
638       try {
639         int countUnread = 0;
640         int i;
641
642         int unreadCount = cache.getUnreadMessageCount();
643
644         if (unreadCount > 0) {
645           long[] uids = getCache().getMessageUids();
646
647           for (i = uids.length - 1; ( i >= 0 && countUnread < unreadCount) ; i--) {
648             MessageInfo mi = getMessageInfoByUid(uids[i]);
649
650             if (! mi.getFlags().contains(Flags.Flag.SEEN))
651               countUnread++;
652           }
653           if (getLogger().isLoggable(Level.FINE))
654             getLogger().log(Level.FINE, "Returning " + i);
655
656           return i + 1;
657         } else {
658           if (getLogger().isLoggable(Level.FINE))
659             getLogger().log(Level.FINE, "Returning -1");
660           return -1;
661         }
662       } catch (MessagingException me) {
663         if (getLogger().isLoggable(Level.FINE))
664           getLogger().log(Level.FINE, "Messaging Exception. Returning -1");
665         return -1;
666       }
667     }
668
669   }
670
671   public boolean hasUnread() {
672     if (! tracksUnreadMessages())
673       return false;
674     else
675       return (getUnreadCount() > 0);
676   }
677
678   /*
679     public int getUnreadCount() {
680     if (! tracksUnreadMessages())
681     return -1;
682     else {
683     try {
684     if (getCache() != null)
685     unreadCount = getCache().getUnreadMessageCount();
686     } catch (MessagingException me) {
687
688     }
689     return unreadCount;
690     }
691     }
692
693     public int getMessageCount() {
694     try {
695     if (getCache() != null)
696     messageCount = getCache().getMessageCount();
697     } catch (MessagingException me) {
698     }
699     return messageCount;
700     }
701   */

702
703   /**
704    * This forces an update of both the total and unread message counts.
705    */

706   public void resetMessageCounts() {
707     try {
708       if (getLogger().isLoggable(Level.FINE)) {
709         if (getFolder() != null)
710           getLogger().log(Level.FINE, "running resetMessageCounts. unread message count is " + getFolder().getUnreadMessageCount());
711         else
712           getLogger().log(Level.FINE, "running resetMessageCounts. getFolder() is null.");
713       }
714
715       if (isConnected()) {
716         if (tracksUnreadMessages())
717           unreadCount = getFolder().getUnreadMessageCount();
718         messageCount = getFolder().getMessageCount();
719       } else if (getCache() != null) {
720         messageCount = getCache().getMessageCount();
721         if (tracksUnreadMessages())
722           unreadCount = getCache().getUnreadMessageCount();
723       } else {
724         // if there's no cache and no connection, don't do anything.
725
}
726     } catch (MessagingException me) {
727       // if we lose the connection to the folder, we'll leave the old
728
// messageCount and set the unreadCount to zero.
729
unreadCount = 0;
730     }
731     updateNode();
732   }
733
734   /**
735    * This synchronizes the cache with the new information from the
736    * Folder.
737    */

738   public void synchronizeCache() throws MessagingException {
739
740     if (getLogger().isLoggable(Level.FINE))
741       getLogger().log(Level.FINE, "synchronizing cache.");
742
743     try {
744       showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing", "Re-synchronizing with folder..."));
745       if (getFolderDisplayUI() != null) {
746         getFolderDisplayUI().setBusy(true);
747       }
748
749       long cacheUidValidity = getCache().getUIDValidity();
750
751       if (uidValidity != cacheUidValidity) {
752         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("error.UIDFolder.validityMismatch", "Error: validity not correct. reloading..."));
753
754         getCache().invalidateCache();
755         getCache().setUIDValidity(uidValidity);
756         cacheUidValidity = uidValidity;
757       }
758
759
760       showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.CachingFolder.synchronizing.writingChanges", "Writing local changes to server..."));
761
762       // first write all the changes that we made back to the server.
763
showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronzing.writingChanges", "Writing local changes to server"));
764
765       getCache().writeChangesToServer(getFolder());
766
767       showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing.loading", "Loading messages from folder..."));
768
769       // load the list of uid's.
770

771       FetchProfile fp = new FetchProfile();
772       fp.add(UIDFolder.FetchProfileItem.UID);
773       // adding FLAGS to make getFirstUnreadMessage() more efficient
774
fp.add(FetchProfile.Item.FLAGS);
775
776       if (getLogger().isLoggable(Level.FINE))
777         getLogger().log(Level.FINE, "getting messages.");
778
779       Message JavaDoc[] messages = getFolder().getMessages();
780
781       if (getLogger().isLoggable(Level.FINE))
782         getLogger().log(Level.FINE, "fetching messages.");
783
784       String JavaDoc messageCount = messages == null ? "null" : Integer.toString(messages.length);
785
786       showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing.fetchingMessages", "Fetching") + " " + messageCount + " " + Pooka.getProperty("message.UIDFolder.synchronizing.messages", "messages."));
787
788       getFolder().fetch(messages, fp);
789       if (getLogger().isLoggable(Level.FINE))
790         getLogger().log(Level.FINE, "done fetching messages. getting uid's");
791
792       long[] uids = new long[messages.length];
793
794       for (int i = 0; i < messages.length; i++) {
795         uids[i] = getUID(messages[i]);
796       }
797
798       if (getLogger().isLoggable(Level.FINE))
799         getLogger().log(Level.FINE, "synchronizing--uids.length = " + uids.length);
800
801       showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing", "Comparing new messages to current list..."));
802
803       long[] addedUids = cache.getAddedMessages(uids, uidValidity);
804
805       if (getLogger().isLoggable(Level.FINE))
806         getLogger().log(Level.FINE, "synchronizing--addedUids.length = " + addedUids.length);
807
808       if (addedUids.length > 0) {
809         Message JavaDoc[] addedMsgs = ((UIDFolder)getFolder()).getMessagesByUID(addedUids);
810         MessageCountEvent JavaDoc mce = new MessageCountEvent JavaDoc(getFolder(), MessageCountEvent.ADDED, false, addedMsgs);
811
812         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing.loadingMessages", "Loading") + " " + addedUids.length + " " + Pooka.getProperty("message.UIDFolder.synchronizing.messages", "messages."));
813
814         messagesAdded(mce);
815       }
816
817       long[] removedUids = cache.getRemovedMessages(uids, uidValidity);
818       if (getLogger().isLoggable(Level.FINE))
819         getLogger().log(Level.FINE, "synchronizing--removedUids.length = " + removedUids.length);
820
821       if (removedUids.length > 0) {
822         Message JavaDoc[] removedMsgs = new Message JavaDoc[removedUids.length];
823         for (int i = 0 ; i < removedUids.length; i++) {
824
825           MessageInfo mi = getMessageInfoByUid(removedUids[i]);
826           if (mi != null)
827             removedMsgs[i] = mi.getMessage();
828
829           if (removedMsgs[i] == null) {
830             removedMsgs[i] = new CachingMimeMessage(this, removedUids[i]);
831           }
832         }
833         MessageCountEvent JavaDoc mce = new MessageCountEvent JavaDoc(getFolder(), MessageCountEvent.REMOVED, false, removedMsgs);
834
835         showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing.removingMessages", "Removing") + " " + removedUids.length + " " + Pooka.getProperty("message.UIDFolder.synchronizing.messages", "messages."));
836
837         messagesRemoved(mce);
838       }
839
840       updateFlags(uids, messages, cacheUidValidity);
841
842     } finally {
843       if (getFolderDisplayUI() != null) {
844         getFolderDisplayUI().clearStatusMessage();
845         getFolderDisplayUI().setBusy(false);
846       } else
847         Pooka.getUIFactory().clearStatus();
848     }
849
850   }
851
852   protected void runMessagesAdded(MessageCountEvent JavaDoc mce) {
853     if (folderTableModel != null) {
854       Message JavaDoc[] addedMessages = mce.getMessages();
855
856       int fetchBatchSize = 25;
857       int loadBatchSize = 25;
858       try {
859         fetchBatchSize = Integer.parseInt(Pooka.getProperty("Pooka.fetchBatchSize", "50"));
860       } catch (NumberFormatException JavaDoc nfe) {
861       }
862
863       MessageInfo mi;
864       Vector JavaDoc addedProxies = new Vector JavaDoc();
865       List JavaDoc addedInfos = new java.util.ArrayList JavaDoc();
866       for (int i = 0; i < addedMessages.length; i++) {
867         if (addedMessages[i] instanceof CachingMimeMessage) {
868           long uid = ((CachingMimeMessage) addedMessages[i]).getUID();
869           mi = getMessageInfoByUid(uid);
870           if (mi != null) {
871             addedInfos.add(mi);
872             if (getLogger().isLoggable(Level.FINE))
873               getLogger().log(Level.FINE, getFolderID() + ": this is a duplicate. not making a new messageinfo for it.");
874           } else {
875             mi = new MessageInfo(addedMessages[i], CachingFolderInfo.this);
876             addedInfos.add(mi);
877             addedProxies.add(new MessageProxy(getColumnValues(), mi));
878             messageToInfoTable.put(addedMessages[i], mi);
879             uidToInfoTable.put(new Long JavaDoc(((CachingMimeMessage) addedMessages[i]).getUID()), mi);
880           }
881
882           // we need to autoCache either way.
883
/*
884             try {
885             if (autoCache) {
886             showStatusMessage(getFolderDisplayUI(), "caching " + i + " of " + addedMessages.length + " messages....");
887             getCache().cacheMessage((MimeMessage)addedMessages[i], ((CachingMimeMessage)addedMessages[i]).getUID(), getUIDValidity(), SimpleFileCache.MESSAGE, false);
888             } else {
889             getCache().cacheMessage((MimeMessage)addedMessages[i], ((CachingMimeMessage)addedMessages[i]).getUID(), getUIDValidity(), SimpleFileCache.FLAGS_AND_HEADERS, false);
890             }
891             } catch (MessagingException me) {
892             getLogger().log(Level.FINE, "caught exception: " + me);
893             me.printStackTrace();
894             }
895           */

896         } else {
897           // it's a 'real' message from the server.
898

899           long uid = -1;
900           try {
901             uid = getUID(addedMessages[i]);
902           } catch (MessagingException me) {
903           }
904
905           mi = getMessageInfoByUid(uid);
906           if (mi != null) {
907             addedInfos.add(mi);
908             if (getLogger().isLoggable(Level.FINE))
909               getLogger().log(Level.FINE, getFolderID() + ": this is a duplicate. not making a new messageinfo for it.");
910
911             // but we still need to autocache it if we're autocaching.
912
if (autoCache) {
913               mMessageLoader.cacheMessages(new MessageProxy[] { getMessageInfoByUid(uid).getMessageProxy()});
914             }
915           } else {
916             CachingMimeMessage newMsg = new CachingMimeMessage(CachingFolderInfo.this, uid);
917             mi = new MessageInfo(newMsg, CachingFolderInfo.this);
918             addedInfos.add(mi);
919             addedProxies.add(new MessageProxy(getColumnValues(), mi));
920             messageToInfoTable.put(newMsg, mi);
921             uidToInfoTable.put(new Long JavaDoc(uid), mi);
922           }
923
924           /*
925             try {
926             if (autoCache) {
927             showStatusMessage(getFolderDisplayUI(), getFolderID() + ": " + Pooka.getProperty("info.UIDFolder.synchronizing.cachingMessages", "Caching") + " " + i + " " + Pooka.getProperty("info.UIDFolder.synchronizing.of", "of") + " " + addedMessages.length + Pooka.getProperty("info.UIDFolder.synchronizing.messages", "messages") + "....");
928             getCache().cacheMessage((MimeMessage)addedMessages[i], uid, getUIDValidity(), SimpleFileCache.MESSAGE, false);
929             } else {
930             getCache().cacheMessage((MimeMessage)addedMessages[i], uid, getUIDValidity(), SimpleFileCache.FLAGS_AND_HEADERS, false);
931             }
932             } catch (MessagingException me) {
933             getLogger().log(Level.FINE, "caught exception: " + me);
934             me.printStackTrace();
935             }
936           */

937         }
938       }
939
940       try {
941         List JavaDoc preloadMessages = addedInfos;
942         if (addedInfos.size() > fetchBatchSize) {
943           preloadMessages = addedInfos.subList(0, fetchBatchSize);
944         }
945         MessageInfo[] preloadArray = new MessageInfo[preloadMessages.size()];
946         for (int i = 0; i < preloadMessages.size(); i++) {
947           preloadArray[i] = (MessageInfo) preloadMessages.get(i);
948         }
949         fetch(preloadArray, fetchProfile);
950       } catch (MessagingException me) {
951         getLogger().warning("error prefetching messages: " + me.toString());
952       }
953       /*
954         for (int i = 0; i < preloadMessages.length; i++) {
955         long uid = -1;
956         try {
957         uid = getUID(preloadMessages[i]);
958         } catch (MessagingException me) {
959         }
960         try {
961         // FIXME
962         getCache().cacheMessage((MimeMessage)preloadMessages[i], uid, getUIDValidity(), SimpleFileCache.FLAGS_AND_HEADERS, false);
963         } catch (Exception e) {
964
965         }
966         }
967       */

968
969       getCache().writeMsgFile();
970
971       clearStatusMessage(getFolderDisplayUI());
972
973       addedProxies.removeAll(applyFilters(addedProxies));
974       if (addedProxies.size() > 0) {
975         if (getFolderTableModel() != null)
976           getFolderTableModel().addRows(addedProxies);
977         setNewMessages(true);
978         resetMessageCounts();
979
980         // notify the message loaded thread.
981
MessageProxy[] addedArray = (MessageProxy[]) addedProxies.toArray(new MessageProxy[0]);
982         //loaderThread.loadMessages(addedArray, net.suberic.pooka.thread.LoadMessageThread.HIGH);
983
mMessageLoader.loadMessages(addedArray, net.suberic.pooka.thread.MessageLoader.HIGH);
984
985         if (autoCache) {
986           mMessageLoader.cacheMessages(addedArray);
987         }
988
989         // change the Message objects in the MessageCountEvent to
990
// our UIDMimeMessages.
991
Message JavaDoc[] newMsgs = new Message JavaDoc[addedProxies.size()];
992         for (int i = 0; i < addedProxies.size(); i++) {
993           newMsgs[i] = ((MessageProxy)addedProxies.elementAt(i)).getMessageInfo().getMessage();
994         }
995         MessageCountEvent JavaDoc newMce = new MessageCountEvent JavaDoc(getFolder(), mce.getType(), mce.isRemoved(), newMsgs);
996         fireMessageCountEvent(newMce);
997       }
998
999     }
1000  }
1001
1002  /**
1003   * This does the real work when messages are removed.
1004   *
1005   * This method should always be run on the FolderThread.
1006   */

1007  protected void runMessagesRemoved(MessageCountEvent JavaDoc mce) {
1008    Message JavaDoc[] removedMessages = mce.getMessages();
1009    Message JavaDoc[] removedCachingMessages = new Message JavaDoc[removedMessages.length];
1010
1011    if (getLogger().isLoggable(Level.FINE))
1012      getLogger().log(Level.FINE, "removedMessages was of size " + removedMessages.length);
1013    MessageInfo mi;
1014    Vector JavaDoc removedProxies=new Vector JavaDoc();
1015
1016    for (int i = 0; i < removedMessages.length; i++) {
1017      if (getLogger().isLoggable(Level.FINE))
1018        getLogger().log(Level.FINE, "checking for existence of message.");
1019
1020      if (removedMessages[i] != null && removedMessages[i] instanceof CachingMimeMessage) {
1021        removedCachingMessages[i] = removedMessages[i];
1022        long uid = ((CachingMimeMessage) removedMessages[i]).getUID();
1023        mi = getMessageInfoByUid(uid);
1024
1025        if (mi != null) {
1026          if (getLogger().isLoggable(Level.FINE))
1027            getLogger().log(Level.FINE, "message exists--removing");
1028          if ( mi.getMessageProxy() != null) {
1029            mi.getMessageProxy().close();
1030            removedProxies.add(mi.getMessageProxy());
1031          }
1032          messageToInfoTable.remove(mi);
1033          uidToInfoTable.remove(new Long JavaDoc(((CachingMimeMessage) removedMessages[i]).getUID()));
1034        }
1035
1036        getCache().invalidateCache(((CachingMimeMessage) removedMessages[i]).getUID(), SimpleFileCache.MESSAGE);
1037
1038      } else {
1039        // not a CachingMimeMessage.
1040
long uid = -1;
1041        try {
1042          uid = getUID(removedMessages[i]);
1043        } catch (MessagingException me) {
1044        }
1045
1046        mi = getMessageInfoByUid(uid);
1047        if (mi != null) {
1048          removedCachingMessages[i] = mi.getMessage();
1049          if (mi.getMessageProxy() != null)
1050            mi.getMessageProxy().close();
1051
1052          if (getLogger().isLoggable(Level.FINE))
1053            getLogger().log(Level.FINE, "message exists--removing");
1054
1055          Message JavaDoc localMsg = mi.getMessage();
1056          removedProxies.add(mi.getMessageProxy());
1057          messageToInfoTable.remove(localMsg);
1058          uidToInfoTable.remove(new Long JavaDoc(uid));
1059        } else {
1060          removedCachingMessages[i] = removedMessages[i];
1061        }
1062        getCache().invalidateCache(uid, SimpleFileCache.MESSAGE);
1063      }
1064    }
1065
1066    MessageCountEvent JavaDoc newMce = new MessageCountEvent JavaDoc(getFolder(), mce.getType(), mce.isRemoved(), removedCachingMessages);
1067
1068    if (getFolderDisplayUI() != null) {
1069      if (removedProxies.size() > 0) {
1070        getFolderDisplayUI().removeRows(removedProxies);
1071      }
1072      resetMessageCounts();
1073      fireMessageCountEvent(newMce);
1074    } else {
1075      resetMessageCounts();
1076      fireMessageCountEvent(newMce);
1077      if (removedProxies.size() > 0)
1078        getFolderTableModel().removeRows(removedProxies);
1079    }
1080  }
1081
1082  /**
1083   * This updates the TableInfo on the changed messages.
1084   *
1085   * As defined by java.mail.MessageChangedListener.
1086   */

1087
1088  public void runMessageChanged(MessageChangedEvent JavaDoc mce) {
1089    // if the message is getting deleted, then we don't
1090
// really need to update the table info. for that
1091
// matter, it's likely that we'll get MessagingExceptions
1092
// if we do, anyway.
1093

1094    boolean updateInfo = false;
1095    try {
1096      updateInfo = (!mce.getMessage().isSet(Flags.Flag.DELETED) || ! Pooka.getProperty("Pooka.autoExpunge", "true").equalsIgnoreCase("true"));
1097    } catch (MessagingException me) {
1098      // if we catch a MessagingException, it just means
1099
// that the message has already been expunged. in
1100
// that case, assume it's ok if we don't update; it'll
1101
// happen in the messagesRemoved().
1102
}
1103
1104    if (updateInfo) {
1105      try {
1106        Message JavaDoc msg = mce.getMessage();
1107        long uid = -1;
1108        uid = getUID(msg);
1109
1110        if (msg != null){
1111          if (mce.getMessageChangeType() == MessageChangedEvent.FLAGS_CHANGED)
1112            getCache().cacheMessage((MimeMessage JavaDoc)msg, uid, uidValidity, SimpleFileCache.FLAGS);
1113          else if (mce.getMessageChangeType() == MessageChangedEvent.ENVELOPE_CHANGED)
1114            getCache().cacheMessage((MimeMessage JavaDoc)msg, uid, uidValidity, SimpleFileCache.HEADERS);
1115        }
1116
1117        MessageInfo mi = getMessageInfoByUid(uid);
1118        if (mi != null) {
1119          MessageProxy mp = mi.getMessageProxy();
1120          if (mp != null) {
1121            mp.unloadTableInfo();
1122            mp.loadTableInfo();
1123          }
1124        }
1125
1126      } catch (MessagingException me) {
1127        // if we catch a MessagingException, it just means
1128
// that the message has already been expunged.
1129
}
1130
1131      // if we're not just a tableinfochanged event, do a resetmessagecouts.
1132
// don't do this if we're just a delete.
1133
if (! (mce instanceof net.suberic.pooka.event.MessageTableInfoChangedEvent)) {
1134        resetMessageCounts();
1135      }
1136
1137    }
1138
1139    fireMessageChangedEvent(mce);
1140  }
1141
1142  /**
1143   * This sets the given Flag for all the MessageInfos given.
1144   */

1145  public void setFlags(MessageInfo[] msgs, Flags flag, boolean value) throws MessagingException {
1146    // no optimization here.
1147
for (int i = 0; i < msgs.length; i++) {
1148      msgs[i].getRealMessage().setFlags(flag, value);
1149    }
1150  }
1151
1152  /**
1153   * This copies the given messages to the given FolderInfo.
1154   */

1155  public void copyMessages(MessageInfo[] msgs, FolderInfo targetFolder) throws MessagingException {
1156    if (isConnected())
1157      super.copyMessages(msgs, targetFolder);
1158    else
1159      targetFolder.appendMessages(msgs);
1160  }
1161
1162  /**
1163   * This appends the given message to the given FolderInfo.
1164   */

1165  public void appendMessages(MessageInfo[] msgs) throws MessagingException {
1166    if (isAvailable()) {
1167      if (isConnected()) {
1168        super.appendMessages(msgs);
1169      } else {
1170        // make sure we've loaded
1171
if (! isLoaded())
1172          loadFolder();
1173        getCache().appendMessages(msgs);
1174      }
1175    } else {
1176      throw new MessagingException("cannot append messages to an unavailable folder.");
1177    }
1178  }
1179
1180  /**
1181   * This expunges the deleted messages from the Folder.
1182   */

1183  public void expunge() throws MessagingException {
1184    if (isConnected())
1185      getFolder().expunge();
1186    else if (shouldBeConnected()) {
1187      openFolder(Folder.READ_WRITE);
1188      getFolder().expunge();
1189    } else {
1190      getCache().expungeMessages();
1191    }
1192  }
1193
1194  /**
1195   * This attempts to cache the message represented by this MessageInfo.
1196   */

1197  public void cacheMessage (MessageInfo info, int cacheStatus) throws MessagingException {
1198    if (status == CONNECTED) {
1199      Message JavaDoc m = info.getMessage();
1200      if (m instanceof CachingMimeMessage) {
1201        long uid = ((CachingMimeMessage)m).getUID();
1202        MimeMessage JavaDoc realMessage = getRealMessageById(uid);
1203        getCache().cacheMessage(realMessage, uid, uidValidity, cacheStatus);
1204      } else if (m instanceof MimeMessage JavaDoc) {
1205        long uid = getUID(m);
1206        getCache().cacheMessage((MimeMessage JavaDoc)m, uid, uidValidity, cacheStatus);
1207      } else {
1208        throw new MessagingException(Pooka.getProperty("error.CachingFolderInfo.unknownMessageType", "Error: unknownMessageType."));
1209      }
1210    } else {
1211      throw new MessagingException(Pooka.getProperty("error.CachingFolderInfo.cacheWhileDisconnected", "Error: You cannot cache messages unless you\nare connected to the folder."));
1212    }
1213  }
1214
1215
1216  /**
1217   * This updates the children of the current folder. Generally called
1218   * when the folderList property is changed.
1219   */

1220
1221  public void updateChildren() {
1222    Vector JavaDoc newChildren = new Vector JavaDoc();
1223
1224    String JavaDoc childList = Pooka.getProperty(getFolderProperty() + ".folderList", "");
1225    if (childList != "") {
1226      StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(childList, ":");
1227
1228      String JavaDoc newFolderName;
1229
1230      for (int i = 0 ; tokens.hasMoreTokens() ; i++) {
1231        newFolderName = (String JavaDoc)tokens.nextToken();
1232        FolderInfo childFolder = getChild(newFolderName);
1233        if (childFolder == null) {
1234          if (! Pooka.getProperty(getFolderProperty() + "." + newFolderName + ".cacheMessages", "true").equalsIgnoreCase("false"))
1235            childFolder = new CachingFolderInfo(this, newFolderName);
1236          else if (Pooka.getProperty(getParentStore().getStoreProperty() + ".protocol", "mbox").equalsIgnoreCase("imap")) {
1237            childFolder = new UIDFolderInfo(this, newFolderName);
1238          } else
1239            childFolder = new FolderInfo(this, newFolderName);
1240
1241          newChildren.add(childFolder);
1242        } else {
1243          newChildren.add(childFolder);
1244        }
1245      }
1246
1247      children = newChildren;
1248
1249      if (folderNode != null)
1250        folderNode.loadChildren();
1251    }
1252  }
1253
1254  /**
1255   * This method closes the Folder. If you open the Folder using
1256   * openFolder (which you should), then you should use this method
1257   * instead of calling getFolder.close(). If you don't, then the
1258   * FolderInfo will try to reopen the folder.
1259   */

1260  public void closeFolder(boolean expunge) throws MessagingException {
1261    closeFolder(expunge, false);
1262  }
1263
1264  /**
1265   * This method closes the Folder. If you open the Folder using
1266   * openFolder (which you should), then you should use this method
1267   * instead of calling getFolder.close(). If you don't, then the
1268   * FolderInfo will try to reopen the folder.
1269   */

1270  public void closeFolder(boolean expunge, boolean closeDisplay) throws MessagingException {
1271
1272    if (closeDisplay && getFolderDisplayUI() != null)
1273      getFolderDisplayUI().closeFolderDisplay();
1274
1275    if (isLoaded() && isAvailable()) {
1276      if (isConnected()) {
1277        try {
1278          getFolder().close(expunge);
1279        } catch (java.lang.IllegalStateException JavaDoc ise) {
1280          throw new MessagingException(ise.getMessage(), ise);
1281        }
1282      }
1283
1284      if (getCache() != null) {
1285        setStatus(DISCONNECTED);
1286      } else {
1287        setStatus(CLOSED);
1288      }
1289    }
1290
1291  }
1292
1293  /**
1294   * This unsubscribes this FolderInfo and all of its children, if
1295   * applicable.
1296   *
1297   * For the CachingFolderInfo, this calls super.unsubscribe() and
1298   * getCache().invalidateCache().
1299   */

1300  public void unsubscribe() {
1301    super.unsubscribe();
1302    getCache().invalidateCache();
1303  }
1304
1305  /**
1306   * Searches for messages in this folder which match the given
1307   * SearchTerm.
1308   *
1309   * Basically wraps the call to Folder.search(), and then wraps the
1310   * returned Message objects as MessageInfos.
1311   */

1312  public MessageInfo[] search(javax.mail.search.SearchTerm JavaDoc term)
1313    throws MessagingException {
1314    if (isConnected()) {
1315      return super.search(term);
1316    } else {
1317      return getCache().search(term);
1318    }
1319  }
1320
1321  /**
1322   * The resource for the default display filters.
1323   */

1324  protected String JavaDoc getDefaultDisplayFiltersResource() {
1325    if (getCacheHeadersOnly()) {
1326      return super.getDefaultDisplayFiltersResource();
1327    } else if (isSentFolder())
1328      return "CachingFolderInfo.sentFolderDefaultDisplayFilters";
1329    else
1330      return "CachingFolderInfo.defaultDisplayFilters";
1331  }
1332
1333  /**
1334   * Returns whether or not a given message is fully cached.
1335   */

1336  public boolean isCached(long uid) {
1337    return getCache().isFullyCached(uid);
1338  }
1339
1340  /**
1341   * This returns the MessageCache associated with this FolderInfo,
1342   * if any.
1343   */

1344  public MessageCache getCache() {
1345    return cache;
1346  }
1347
1348  /**
1349   * Returns whether or not we should be showing cache information in
1350   * the FolderDisplay. Uses the FolderProperty.showCacheInfo property
1351   * to determine--if this is set to true, we will show the cache info.
1352   * Otherwise, if we're connected, don't show the info, and if we're
1353   * not connected, do.
1354   */

1355  public boolean showCacheInfo() {
1356    if (Pooka.getProperty(getFolderProperty() + ".showCacheInfo", "false").equalsIgnoreCase("true"))
1357      return true;
1358    else {
1359      if (getStatus() == CONNECTED) {
1360        return false;
1361      } else
1362        return true;
1363    }
1364  }
1365
1366  /**
1367   * Returns the cache directory for this FolderInfo.
1368   */

1369  public String JavaDoc getCacheDirectory() {
1370    String JavaDoc localDir = Pooka.getProperty(getFolderProperty() + ".cacheDir", "");
1371    if (!localDir.equals(""))
1372      return localDir;
1373
1374    localDir = Pooka.getProperty("Pooka.defaultMailSubDir", "");
1375    if (localDir.equals(""))
1376      localDir = System.getProperty("user.home") + File.separator + ".pooka";
1377
1378    localDir = localDir + File.separatorChar + "cache";
1379    FolderInfo currentFolder = this;
1380    StringBuffer JavaDoc subDir = new StringBuffer JavaDoc();
1381    subDir.insert(0, currentFolder.getFolderName());
1382    subDir.insert(0, File.separatorChar);
1383    while (currentFolder.getParentFolder() != null) {
1384      currentFolder = currentFolder.getParentFolder();
1385      subDir.insert(0, currentFolder.getFolderName());
1386      subDir.insert(0, File.separatorChar);
1387    }
1388
1389    subDir.insert(0, currentFolder.getParentStore().getStoreID());
1390    subDir.insert(0, File.separatorChar);
1391
1392    return localDir + subDir.toString();
1393  }
1394
1395  public boolean isLoaded() {
1396    return (getFolder() != null && ( ! (getFolder() instanceof FolderProxy)) && cache != null);
1397  }
1398
1399  /**
1400   * Gets the UID for the given Message.
1401   */

1402  public long getUID(Message JavaDoc m) throws MessagingException {
1403    if (m instanceof SimpleFileCache.LocalMimeMessage) {
1404      return ((SimpleFileCache.LocalMimeMessage) m).getUID();
1405    } else {
1406      return super.getUID(m);
1407    }
1408  }
1409
1410  /**
1411   * Shows a status message, using the given FolderDisplayUI if not null.
1412   */

1413  public void showStatusMessage(net.suberic.pooka.gui.FolderDisplayUI pUI, String JavaDoc message) {
1414    if (pUI != null)
1415      pUI.showStatusMessage(message);
1416    else
1417      Pooka.getUIFactory().showStatusMessage(message);
1418  }
1419
1420  /**
1421   * This handles the changes if the source property is modified.
1422   *
1423   * As defined in net.suberic.util.ValueChangeListener.
1424   */

1425
1426  public void valueChanged(String JavaDoc changedValue) {
1427    if (changedValue.equals(getFolderProperty() + ".autoCache") || changedValue.equals(getParentStore().getStoreProperty() + ".autoCache")) {
1428      if (! getCacheHeadersOnly()) {
1429        autoCache = Pooka.getProperty(getFolderProperty() + ".autoCache", Pooka.getProperty(getFolderProperty() + ".autoCache", Pooka.getProperty(getParentStore().getStoreProperty() + ".autoCache", Pooka.getProperty("Pooka.autoCache", "false")))).equalsIgnoreCase("true");
1430      }
1431    } else if (changedValue.equals(getFolderProperty() + ".cacheHeadersOnly") || changedValue.equals(getParentStore().getStoreProperty() + ".cacheHeadersOnly")) {
1432      if (! getCacheHeadersOnly()) {
1433        autoCache = Pooka.getProperty(getFolderProperty() + ".autoCache", Pooka.getProperty(getParentStore().getStoreProperty() + ".autoCache", Pooka.getProperty("Pooka.autoCache", "false"))).equalsIgnoreCase("true");
1434      }
1435      createFilters();
1436      if (getFolderNode() != null)
1437        getFolderNode().popupMenu = null;
1438    } else {
1439      super.valueChanged(changedValue);
1440    }
1441  }
1442
1443  /**
1444   * Returns if we're caching only headers.
1445   */

1446  public boolean getCacheHeadersOnly() {
1447    return Pooka.getProperty(getFolderProperty() + ".cacheHeadersOnly", Pooka.getProperty(getParentStore().getStoreProperty() + ".cacheHeadersOnly", "false")).equalsIgnoreCase("true");
1448  }
1449}
1450
1451
Popular Tags