1 package net.suberic.pooka.cache; 2 import javax.mail.*; 3 import javax.mail.event.MessageCountEvent ; 4 import javax.mail.internet.MimeMessage ; 5 import javax.mail.event.MessageChangedEvent ; 6 import javax.mail.event.ConnectionEvent ; 7 import java.util.Vector ; 8 import java.util.List ; 9 import java.util.logging.*; 10 import java.util.StringTokenizer ; 11 import java.util.HashMap ; 12 import java.io.File ; 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 23 24 public class CachingFolderInfo extends net.suberic.pooka.UIDFolderInfo { 25 private MessageCache cache = null; 26 27 protected static String disconnectedMessage = "error.CachingFolder.disconnected"; 29 30 boolean autoCache = false; 31 32 public CachingFolderInfo(StoreInfo parent, String 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 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 58 protected FetchProfile createColumnInformation() { 59 FetchProfile fp = super.createColumnInformation(); 60 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 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 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 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 e) { 128 } 131 132 if (tmpFolder == null || tmpFolder.length == 0) { 133 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 198 public void opened (ConnectionEvent e) { 199 super.opened(e); 200 rematchFilters(); 201 } 202 203 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 268 public void disconnected(ConnectionEvent e) { 269 super.disconnected(e); 270 rematchFilters(); 271 } 272 273 276 public void closed(ConnectionEvent e) { 277 super.closed(e); 278 rematchFilters(); 279 } 280 281 285 protected void rematchFilters() { 286 if (folderTableModel != null) { 287 List allProxies = folderTableModel.getAllProxies(); 288 for (int i = 0; i < allProxies.size(); i++) { 289 ((MessageProxy) allProxies.get(i)).clearMatchedFilters(); 290 } 291 mMessageLoader.loadMessages(allProxies); 293 } 294 } 295 296 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 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 330 protected List createInfosAndProxies() throws MessagingException { 331 332 List messageProxies = new Vector (); 333 334 if (getStatus() > CONNECTED) { 335 uidValidity = cache.getUIDValidity(); 336 } 337 338 if (isConnected()) { 339 try { 340 342 showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.CachingFolder.synchronizing.writingChanges", "Writing local changes to server...")); 343 344 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 [] 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 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 (uids[i]), mi); 376 } 377 378 return messageProxies; 379 } catch (Exception e) { 380 final Exception fe = e; 381 javax.swing.SwingUtilities.invokeLater(new Runnable () { 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 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 (uids[i]), mi); 405 } 406 407 return messageProxies; 408 } 409 410 413 protected void updateCache() throws MessagingException { 414 if (isConnected()) { 415 synchronizeCache(); 416 } 417 } 418 419 423 484 public void fetch(MessageInfo[] messages, FetchProfile profile) throws MessagingException { 486 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 [] 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 FetchProfile fp = new FetchProfile(); 517 if (doFlags) { 518 fp.add(FetchProfile.Item.FLAGS); 519 } 520 521 java.util.LinkedList flagsOnly = new java.util.LinkedList (); 522 java.util.LinkedList headersAndFlags = new java.util.LinkedList (); 523 524 for (int i = 0 ; i < messages.length; i++) { 525 Message 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 m = headersAndFlagsArray[i].getRealMessage(); 548 if (m != null) { 549 long uid = getUID(m); 550 getCache().cacheMessage((MimeMessage )m, uid, cache.getUIDValidity(), cacheStatus); 551 } 552 } 553 554 for (int i = 0; i < flagsOnlyArray.length; i++) { 555 Message m = flagsOnlyArray[i].getRealMessage(); 556 if (m != null) { 557 long uid = getUID(m); 558 getCache().cacheMessage((MimeMessage )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 m = messages[i].getRealMessage(); 571 if (m != null) { 572 long uid = getUID(m); 573 getCache().cacheMessage((MimeMessage )m, uid, cache.getUIDValidity(), cacheStatus); 574 } 575 } 576 } 577 578 } 579 } else { 580 for (int i = 0; i < messages.length; i++) { 583 Message 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 604 public void refreshHeaders(MessageInfo mi) throws MessagingException { 605 cacheMessage(mi, SimpleFileCache.HEADERS); 606 } 607 608 611 public void refreshFlags(MessageInfo mi) throws MessagingException { 612 if (isConnected()) 613 cacheMessage(mi, SimpleFileCache.FLAGS); 614 } 615 616 617 622 623 public int getFirstUnreadMessage() { 624 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 702 703 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 } 726 } catch (MessagingException me) { 727 unreadCount = 0; 730 } 731 updateNode(); 732 } 733 734 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 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 771 FetchProfile fp = new FetchProfile(); 772 fp.add(UIDFolder.FetchProfileItem.UID); 773 fp.add(FetchProfile.Item.FLAGS); 775 776 if (getLogger().isLoggable(Level.FINE)) 777 getLogger().log(Level.FINE, "getting messages."); 778 779 Message [] messages = getFolder().getMessages(); 780 781 if (getLogger().isLoggable(Level.FINE)) 782 getLogger().log(Level.FINE, "fetching messages."); 783 784 String 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 [] addedMsgs = ((UIDFolder)getFolder()).getMessagesByUID(addedUids); 810 MessageCountEvent mce = new MessageCountEvent (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 [] removedMsgs = new Message [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 mce = new MessageCountEvent (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 mce) { 853 if (folderTableModel != null) { 854 Message [] 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 nfe) { 861 } 862 863 MessageInfo mi; 864 Vector addedProxies = new Vector (); 865 List addedInfos = new java.util.ArrayList (); 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 (((CachingMimeMessage) addedMessages[i]).getUID()), mi); 880 } 881 882 896 } else { 897 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 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 (uid), mi); 922 } 923 924 937 } 938 } 939 940 try { 941 List 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 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 MessageProxy[] addedArray = (MessageProxy[]) addedProxies.toArray(new MessageProxy[0]); 982 mMessageLoader.loadMessages(addedArray, net.suberic.pooka.thread.MessageLoader.HIGH); 984 985 if (autoCache) { 986 mMessageLoader.cacheMessages(addedArray); 987 } 988 989 Message [] newMsgs = new Message [addedProxies.size()]; 992 for (int i = 0; i < addedProxies.size(); i++) { 993 newMsgs[i] = ((MessageProxy)addedProxies.elementAt(i)).getMessageInfo().getMessage(); 994 } 995 MessageCountEvent newMce = new MessageCountEvent (getFolder(), mce.getType(), mce.isRemoved(), newMsgs); 996 fireMessageCountEvent(newMce); 997 } 998 999 } 1000 } 1001 1002 1007 protected void runMessagesRemoved(MessageCountEvent mce) { 1008 Message [] removedMessages = mce.getMessages(); 1009 Message [] removedCachingMessages = new Message [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 removedProxies=new Vector (); 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 (((CachingMimeMessage) removedMessages[i]).getUID())); 1034 } 1035 1036 getCache().invalidateCache(((CachingMimeMessage) removedMessages[i]).getUID(), SimpleFileCache.MESSAGE); 1037 1038 } else { 1039 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 localMsg = mi.getMessage(); 1056 removedProxies.add(mi.getMessageProxy()); 1057 messageToInfoTable.remove(localMsg); 1058 uidToInfoTable.remove(new Long (uid)); 1059 } else { 1060 removedCachingMessages[i] = removedMessages[i]; 1061 } 1062 getCache().invalidateCache(uid, SimpleFileCache.MESSAGE); 1063 } 1064 } 1065 1066 MessageCountEvent newMce = new MessageCountEvent (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 1087 1088 public void runMessageChanged(MessageChangedEvent mce) { 1089 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 } 1103 1104 if (updateInfo) { 1105 try { 1106 Message 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 )msg, uid, uidValidity, SimpleFileCache.FLAGS); 1113 else if (mce.getMessageChangeType() == MessageChangedEvent.ENVELOPE_CHANGED) 1114 getCache().cacheMessage((MimeMessage )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 } 1130 1131 if (! (mce instanceof net.suberic.pooka.event.MessageTableInfoChangedEvent)) { 1134 resetMessageCounts(); 1135 } 1136 1137 } 1138 1139 fireMessageChangedEvent(mce); 1140 } 1141 1142 1145 public void setFlags(MessageInfo[] msgs, Flags flag, boolean value) throws MessagingException { 1146 for (int i = 0; i < msgs.length; i++) { 1148 msgs[i].getRealMessage().setFlags(flag, value); 1149 } 1150 } 1151 1152 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 1165 public void appendMessages(MessageInfo[] msgs) throws MessagingException { 1166 if (isAvailable()) { 1167 if (isConnected()) { 1168 super.appendMessages(msgs); 1169 } else { 1170 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 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 1197 public void cacheMessage (MessageInfo info, int cacheStatus) throws MessagingException { 1198 if (status == CONNECTED) { 1199 Message m = info.getMessage(); 1200 if (m instanceof CachingMimeMessage) { 1201 long uid = ((CachingMimeMessage)m).getUID(); 1202 MimeMessage realMessage = getRealMessageById(uid); 1203 getCache().cacheMessage(realMessage, uid, uidValidity, cacheStatus); 1204 } else if (m instanceof MimeMessage ) { 1205 long uid = getUID(m); 1206 getCache().cacheMessage((MimeMessage )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 1220 1221 public void updateChildren() { 1222 Vector newChildren = new Vector (); 1223 1224 String childList = Pooka.getProperty(getFolderProperty() + ".folderList", ""); 1225 if (childList != "") { 1226 StringTokenizer tokens = new StringTokenizer (childList, ":"); 1227 1228 String newFolderName; 1229 1230 for (int i = 0 ; tokens.hasMoreTokens() ; i++) { 1231 newFolderName = (String )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 1260 public void closeFolder(boolean expunge) throws MessagingException { 1261 closeFolder(expunge, false); 1262 } 1263 1264 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 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 1300 public void unsubscribe() { 1301 super.unsubscribe(); 1302 getCache().invalidateCache(); 1303 } 1304 1305 1312 public MessageInfo[] search(javax.mail.search.SearchTerm term) 1313 throws MessagingException { 1314 if (isConnected()) { 1315 return super.search(term); 1316 } else { 1317 return getCache().search(term); 1318 } 1319 } 1320 1321 1324 protected String 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 1336 public boolean isCached(long uid) { 1337 return getCache().isFullyCached(uid); 1338 } 1339 1340 1344 public MessageCache getCache() { 1345 return cache; 1346 } 1347 1348 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 1369 public String getCacheDirectory() { 1370 String 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 subDir = new StringBuffer (); 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 1402 public long getUID(Message 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 1413 public void showStatusMessage(net.suberic.pooka.gui.FolderDisplayUI pUI, String message) { 1414 if (pUI != null) 1415 pUI.showStatusMessage(message); 1416 else 1417 Pooka.getUIFactory().showStatusMessage(message); 1418 } 1419 1420 1425 1426 public void valueChanged(String 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 1446 public boolean getCacheHeadersOnly() { 1447 return Pooka.getProperty(getFolderProperty() + ".cacheHeadersOnly", Pooka.getProperty(getParentStore().getStoreProperty() + ".cacheHeadersOnly", "false")).equalsIgnoreCase("true"); 1448 } 1449} 1450 1451 | Popular Tags |