1 package net.suberic.pooka; 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 net.suberic.pooka.*; 8 import java.util.Vector ; 9 import java.util.List ; 10 import java.util.StringTokenizer ; 11 import java.util.HashMap ; 12 import java.util.Set ; 13 import java.util.logging.Level ; 14 import net.suberic.pooka.gui.MessageProxy; 15 import net.suberic.pooka.gui.FolderTableModel; 16 17 23 24 public class UIDFolderInfo extends FolderInfo { 25 protected HashMap uidToInfoTable = new HashMap (); 26 protected long uidValidity = -1000; 27 28 protected static String disconnectedMessage = "error.UIDFolder.disconnected"; 30 31 public UIDFolderInfo(StoreInfo parent, String fname) { 32 super(parent, fname); 33 } 34 35 public UIDFolderInfo(FolderInfo parent, String fname) { 36 super(parent, fname); 37 } 38 39 43 protected List createInfosAndProxies() throws MessagingException { 44 int fetchBatchSize = 50; 45 try { 46 fetchBatchSize = Integer.parseInt(Pooka.getProperty("Pooka.fetchBatchSize", "50")); 47 } catch (NumberFormatException nfe) { 48 } 49 50 Vector messageProxies = new Vector (); 51 52 Folder f = getFolder(); 53 if (f == null) 54 throw new MessagingException("Folder does not exist or is unavailable."); 55 56 Message [] msgs = getFolder().getMessages(); 57 58 FetchProfile uidProfile = new FetchProfile(); 60 uidProfile.add(UIDFolder.FetchProfileItem.UID); 61 uidProfile.add(FetchProfile.Item.FLAGS); 63 64 getFolder().fetch(msgs, uidProfile); 65 66 Message [] toFetch = msgs; 67 68 if (msgs.length > fetchBatchSize) { 71 toFetch = new Message [fetchBatchSize]; 72 System.arraycopy(msgs, msgs.length - fetchBatchSize, toFetch, 0, fetchBatchSize); 73 } 74 75 getFolder().fetch(toFetch, fetchProfile); 76 77 int firstFetched = Math.max(msgs.length - fetchBatchSize, 0); 78 79 MessageInfo mi; 80 81 for (int i = 0; i < msgs.length; i++) { 82 long uid = getUID(msgs[i]); 83 UIDMimeMessage newMessage = new UIDMimeMessage(this, uid); 84 mi = new MessageInfo(newMessage, this); 85 86 if ( i >= firstFetched) 87 mi.setFetched(true); 88 89 messageProxies.add(new MessageProxy(getColumnValues() , mi)); 90 messageToInfoTable.put(newMessage, mi); 91 uidToInfoTable.put(new Long (uid), mi); 92 } 93 94 return messageProxies; 95 } 96 97 102 public void checkFolder() throws javax.mail.MessagingException { 103 getLogger().log(Level.FINE, "checking folder " + getFolderName()); 104 105 108 StoreInfo s = null; 109 if (isConnected()) { 110 Folder current = getFolder(); 111 if (current != null && current.isOpen()) { 112 current.getNewMessageCount(); 113 current.getUnreadMessageCount(); 114 resetMessageCounts(); 115 } 116 } else if (isAvailable() && (status == PASSIVE || status == LOST_CONNECTION)) { 117 s = getParentStore(); 118 if (! s.isConnected()) 119 s.connectStore(); 120 121 openFolder(Folder.READ_WRITE); 122 123 resetMessageCounts(); 124 125 if (isAvailable() && preferredStatus == PASSIVE) 126 closeFolder(false); 127 } 128 } 129 130 protected void updateFolderOpenStatus(boolean isNowOpen) { 131 if (isNowOpen) { 132 setStatus(CONNECTED); 133 try { 134 if (uidValidity == -1000) { 135 uidValidity = ((UIDFolder) getFolder()).getUIDValidity(); 136 } 137 if (getFolderTableModel() != null) 138 synchronizeCache(); 139 } catch (Exception e) { } 140 141 } else 142 setStatus(CLOSED); 143 } 144 145 149 public void synchronizeCache() throws MessagingException { 150 getLogger().log(Level.FINE, "synchronizing cache."); 151 152 if (getFolderDisplayUI() != null) 153 getFolderDisplayUI().showStatusMessage(Pooka.getProperty("message.UIDFolder.synchronizing", "Re-synchronizing with folder...")); 154 155 long newValidity = ((UIDFolder)getFolder()).getUIDValidity(); 156 if (uidValidity != newValidity) { 157 if (getFolderDisplayUI() != null) 158 getFolderDisplayUI().showStatusMessage(Pooka.getProperty("error.UIDFolder.validityMismatch", "Error: validity not correct. reloading...")); 159 160 folderTableModel = null; 161 loadAllMessages(); 162 if (getFolderDisplayUI() != null) 163 getFolderDisplayUI().resetFolderTableModel(folderTableModel); 164 165 if (getFolderDisplayUI() != null) 166 getFolderDisplayUI().clearStatusMessage(); 167 168 } else { 169 if (getFolderDisplayUI() != null) 170 getFolderDisplayUI().showStatusMessage(Pooka.getProperty("message.UIDFolder.synchronizing.loading", "Loading messages from folder...")); 171 FetchProfile fp = new FetchProfile(); 172 fp.add(UIDFolder.FetchProfileItem.UID); 175 Message [] messages = getFolder().getMessages(); 176 getFolder().fetch(messages, fp); 177 178 if (getFolderDisplayUI() != null) 179 getFolderDisplayUI().showStatusMessage(Pooka.getProperty("message.UIDFolder.synchronizing", "Comparing new messages to current list...")); 180 181 long[] uids = new long[messages.length]; 182 183 for (int i = 0; i < messages.length; i++) { 184 uids[i] = getUID(messages[i]); 185 } 186 187 getLogger().log(Level.FINE, "synchronizing--uids.length = " + uids.length); 188 189 long[] addedUids = getAddedMessages(uids, uidValidity); 190 getLogger().log(Level.FINE, "synchronizing--addedUids.length = " + addedUids.length); 191 192 if (addedUids.length > 0) { 193 Message [] addedMsgs = ((UIDFolder)getFolder()).getMessagesByUID(addedUids); 194 MessageCountEvent mce = new MessageCountEvent (getFolder(), MessageCountEvent.ADDED, false, addedMsgs); 195 messagesAdded(mce); 196 } 197 198 long[] removedUids = getRemovedMessages(uids, uidValidity); 199 getLogger().log(Level.FINE, "synchronizing--removedUids.length = " + removedUids.length); 200 201 if (removedUids.length > 0) { 202 Message [] removedMsgs = new Message [removedUids.length]; 203 for (int i = 0 ; i < removedUids.length; i++) { 204 removedMsgs[i] = getMessageInfoByUid(removedUids[i]).getMessage(); 207 } 208 MessageCountEvent mce = new MessageCountEvent (getFolder(), MessageCountEvent.REMOVED, false, removedMsgs); 209 messagesRemoved(mce); 210 211 } 212 213 updateFlags(uids, messages, uidValidity); 214 215 if (getFolderDisplayUI() != null) 216 getFolderDisplayUI().clearStatusMessage(); 217 } 218 } 219 220 223 protected long[] getAddedMessages(long[] newUids, long uidValidity) { 224 long[] added = new long[newUids.length]; 225 int addedCount = 0; 226 Set currentUids = uidToInfoTable.keySet(); 227 228 for (int i = 0; i < newUids.length; i++) { 229 if (! currentUids.contains(new Long (newUids[i]))) { 230 added[addedCount++]=newUids[i]; 231 } 232 } 233 234 long[] returnValue = new long[addedCount]; 235 if (addedCount > 0) 236 System.arraycopy(added, 0, returnValue, 0, addedCount); 237 238 return returnValue; 239 240 } 241 242 245 protected long[] getRemovedMessages(long[] newUids, long uidValidity) { 246 Vector remainders = new Vector (uidToInfoTable.keySet()); 247 248 for (int i = 0; i < newUids.length; i++) { 249 remainders.remove(new Long (newUids[i])); 250 } 251 252 long[] returnValue = new long[remainders.size()]; 253 for (int i = 0; i < remainders.size(); i++) 254 returnValue[i] = ((Long ) remainders.elementAt(i)).longValue(); 255 256 return returnValue; 257 } 258 259 protected void updateFlags(long[] uids, Message [] messages, long uidValidity) throws MessagingException { 260 262 Vector proxies = new Vector (); 263 for (int i = 0; i < messages.length; i++) { 264 MessageInfo mi = getMessageInfo(messages[i]); 266 MessageProxy mp = mi.getMessageProxy(); 267 mi.setFetched(false); 268 mp.setRefresh(true); 269 proxies.add(mp); 270 } 271 272 getLogger().log(Level.FINE, "updating flags for " + proxies.size() + " messages."); 273 274 mMessageLoader.loadMessages(proxies); 276 277 } 278 279 protected void runMessagesAdded(MessageCountEvent mce) { 280 if (folderTableModel != null) { 281 try { 282 Message [] addedMessages = mce.getMessages(); 283 289 290 showStatusMessage(getFolderDisplayUI(), Pooka.getProperty("message.UIDFolder.synchronizing.fetchingMessages", "Fetching") + " " + addedMessages.length + " " + Pooka.getProperty("message.UIDFolder.synchronizing.messages", "messages.")); 291 getLogger().log(Level.FINE, "UIDFolderInfo: runMessagesAdded(). getting " + addedMessages.length + " messages."); 292 293 if (fetchProfile != null) { 294 FetchProfile fp = null; 295 if (! fetchProfile.contains(UIDFolder.FetchProfileItem.UID)) { 296 fp = new FetchProfile(); 298 FetchProfile.Item[] items = fetchProfile.getItems(); 299 String [] headers = fetchProfile.getHeaderNames(); 300 if (items != null) { 301 for (int i = 0; i < items.length; i++) { 302 fp.add(items[i]); 303 } 304 } 305 306 if (headers != null) { 307 for (int i = 0; i < headers.length; i++) { 308 fp.add(headers[i]); 309 } 310 } 311 312 fp.add(UIDFolder.FetchProfileItem.UID); 313 314 } else { 315 fp = fetchProfile; 316 } 317 getFolder().fetch(addedMessages, fp); 318 } else { 319 FetchProfile fp = new FetchProfile(); 320 fp.add(FetchProfile.Item.ENVELOPE); 321 fp.add(FetchProfile.Item.FLAGS); 322 fp.add(UIDFolder.FetchProfileItem.UID); 323 324 getFolder().fetch(addedMessages, fp); 325 } 326 327 MessageInfo mi; 328 Vector addedProxies = new Vector (); 329 for (int i = 0; i < addedMessages.length; i++) { 330 UIDMimeMessage newMsg = getUIDMimeMessage(addedMessages[i]); 331 long uid = newMsg.getUID(); 332 if (getMessageInfoByUid(uid) != null) { 333 getLogger().log(Level.FINE, getFolderID() + ": this is a duplicate. not making a new messageinfo for it."); 334 } else { 335 mi = new MessageInfo(newMsg, this); 336 mi.setFetched(true); 338 339 addedProxies.add(new MessageProxy(getColumnValues(), mi)); 340 messageToInfoTable.put(newMsg, mi); 341 uidToInfoTable.put(new Long (uid), mi); 342 } 343 } 344 345 getLogger().log(Level.FINE, "filtering proxies."); 346 addedProxies.removeAll(applyFilters(addedProxies)); 347 348 getLogger().log(Level.FINE, "filters run; adding " + addedProxies.size() + " messages."); 349 if (addedProxies.size() > 0) { 350 getFolderTableModel().addRows(addedProxies); 351 setNewMessages(true); 352 resetMessageCounts(); 353 354 MessageProxy[] addedArray = (MessageProxy[]) addedProxies.toArray(new MessageProxy[0]); 356 mMessageLoader.loadMessages(addedArray, net.suberic.pooka.thread.MessageLoader.HIGH); 358 359 Message [] newMsgs = new Message [addedProxies.size()]; 362 for (int i = 0; i < addedProxies.size(); i++) { 363 newMsgs[i] = ((MessageProxy)addedProxies.elementAt(i)).getMessageInfo().getMessage(); 364 } 365 MessageCountEvent newMce = new MessageCountEvent (getFolder(), mce.getType(), mce.isRemoved(), newMsgs); 366 fireMessageCountEvent(newMce); 367 } 368 } catch (MessagingException me) { 369 if (getFolderDisplayUI() != null) 370 getFolderDisplayUI().showError(Pooka.getProperty("error.handlingMessages", "Error handling messages."), Pooka.getProperty("error.handlingMessages.title", "Error handling messages."), me); 371 } finally { 372 clearStatusMessage(getFolderDisplayUI()); 373 } 374 } 375 376 } 377 378 381 protected void runMessagesRemoved(MessageCountEvent mce) { 382 getLogger().log(Level.FINE, "running MessagesRemoved on " + getFolderID()); 383 384 MessageCountEvent newMce = null; 385 if (folderTableModel != null) { 386 Message [] removedMessages = mce.getMessages(); 387 Message [] uidRemovedMessages = new Message [removedMessages.length]; 388 389 getLogger().log(Level.FINE, "removedMessages was of size " + removedMessages.length); 390 391 MessageInfo mi; 392 Vector removedProxies=new Vector (); 393 for (int i = 0; i < removedMessages.length; i++) { 394 getLogger().log(Level.FINE, "checking for existence of message " + removedMessages[i]); 395 396 try { 397 UIDMimeMessage removedMsg = getUIDMimeMessage(removedMessages[i]); 398 399 if (removedMsg != null) 400 uidRemovedMessages[i] = removedMsg; 401 else 402 uidRemovedMessages[i] = removedMessages[i]; 403 404 mi = getMessageInfo(removedMsg); 405 if (mi != null) { 406 if (mi.getMessageProxy() != null) 407 mi.getMessageProxy().close(); 408 409 getLogger().log(Level.FINE, "message exists--removing"); 410 removedProxies.add(mi.getMessageProxy()); 411 messageToInfoTable.remove(mi); 412 uidToInfoTable.remove(new Long (removedMsg.getUID())); 413 } else { 414 getLogger().log(Level.FINE, "message with uid " + removedMessages[i] + " not found; not removing."); 415 } 416 } catch (MessagingException me) { 417 getLogger().log(Level.FINE, "caught exception running messagesRemoved on " + removedMessages[i] + ": " + me.getMessage()); 418 } 419 } 420 newMce = new MessageCountEvent (getFolder(), mce.getType(), mce.isRemoved(), uidRemovedMessages); 421 if (getFolderDisplayUI() != null) { 422 if (removedProxies.size() > 0) 423 getFolderDisplayUI().removeRows(removedProxies); 424 resetMessageCounts(); 425 fireMessageCountEvent(newMce); 426 } else { 427 resetMessageCounts(); 428 fireMessageCountEvent(newMce); 429 if (removedProxies.size() > 0) 430 getFolderTableModel().removeRows(removedProxies); 431 } 432 } else { 433 resetMessageCounts(); 434 fireMessageCountEvent(mce); 435 } 436 } 437 438 protected void runMessageChanged(MessageChangedEvent mce) { 439 boolean updateInfo = false; 444 try { 445 updateInfo = (!mce.getMessage().isSet(Flags.Flag.DELETED) || ! Pooka.getProperty("Pooka.autoExpunge", "true").equalsIgnoreCase("true")); 446 } catch (MessagingException me) { 447 } 452 453 if (updateInfo) { 454 try { 455 Message msg = mce.getMessage(); 456 UIDMimeMessage changedMsg = getUIDMimeMessage(msg); 457 long uid = changedMsg.getUID(); 458 459 MessageInfo mi = getMessageInfoByUid(uid); 460 if (mi != null) { 461 MessageProxy mp = mi.getMessageProxy(); 462 if (mp != null) { 463 mp.unloadTableInfo(); 464 mp.loadTableInfo(); 465 } 466 } 467 } catch (MessagingException me) { 468 } 471 472 if (! (mce instanceof net.suberic.pooka.event.MessageTableInfoChangedEvent)) { 475 resetMessageCounts(); 476 } 477 } 478 479 482 try { 483 Message msg = mce.getMessage(); 484 UIDMimeMessage changedMsg = getUIDMimeMessage(msg); 485 if (changedMsg != null) { 486 MessageChangedEvent newMce = new MessageChangedEvent (mce.getSource(), mce.getMessageChangeType(), changedMsg); 487 fireMessageChangedEvent(newMce); 488 } else 489 fireMessageChangedEvent(mce); 490 } catch (MessagingException me) { 491 fireMessageChangedEvent(mce); 494 495 } 496 } 497 498 499 503 public void updateChildren() { 504 Vector newChildren = new Vector (); 505 506 String childList = Pooka.getProperty(getFolderProperty() + ".folderList", ""); 507 if (childList != "") { 508 StringTokenizer tokens = new StringTokenizer (childList, ":"); 509 510 String newFolderName; 511 512 for (int i = 0 ; tokens.hasMoreTokens() ; i++) { 513 newFolderName = (String )tokens.nextToken(); 514 FolderInfo childFolder = getChild(newFolderName); 515 if (childFolder == null) { 516 childFolder = new UIDFolderInfo(this, newFolderName); 517 newChildren.add(childFolder); 518 } else { 519 newChildren.add(childFolder); 520 } 521 } 522 523 children = newChildren; 524 525 if (folderNode != null) 526 folderNode.loadChildren(); 527 } 528 } 529 530 534 public void fetch(MessageInfo[] messages, FetchProfile profile) throws MessagingException { 535 if (messages == null) 536 getLogger().log(Level.FINE, "UIDFolderInfo: fetching with null messages."); 537 else 538 getLogger().log(Level.FINE, "UIDFolderInfo: fetching " + messages.length + " messages."); 539 540 java.util.ArrayList realMsgList = new java.util.ArrayList (); 543 for (int i = 0; i < messages.length; i++) { 544 Message currentMsg = messages[i].getRealMessage(); 545 if (currentMsg != null && currentMsg instanceof UIDMimeMessage) { 546 currentMsg = ((UIDMimeMessage)currentMsg).getMessage(); 547 } 548 if (currentMsg != null) 549 realMsgList.add(currentMsg); 550 } 551 552 Message [] realMsgs = (Message []) realMsgList.toArray(new Message [0]); 553 554 if (realMsgs == null) 555 getLogger().log(Level.FINE, "UIDFolderInfo: running fetch with null real messages."); 556 else 557 getLogger().log(Level.FINE, "UIDFolderInfo: fetching " + realMsgs.length + " messages."); 558 559 getFolder().fetch(realMsgs, profile); 560 561 for (int i = 0 ; i < messages.length; i++) { 562 messages[i].setFetched(true); 563 } 564 } 565 566 574 public void unloadAllMessages() { 575 } 577 578 584 public void closeFolder(boolean expunge, boolean closeDisplay) throws MessagingException { 585 586 if (closeDisplay && getFolderDisplayUI() != null) 587 getFolderDisplayUI().closeFolderDisplay(); 588 589 597 598 if (isLoaded() && isAvailable()) { 599 if (isConnected()) { 600 try { 601 getFolder().close(expunge); 602 } catch (java.lang.IllegalStateException ise) { 603 throw new MessagingException(ise.getMessage(), ise); 604 } 605 } 606 setStatus(CLOSED); 607 } 608 609 610 } 611 612 614 617 public UIDMimeMessage getUIDMimeMessage(Message m) throws MessagingException { 618 if (m instanceof UIDMimeMessage) 619 return (UIDMimeMessage) m; 620 621 long uid = getUID(m); 623 MessageInfo mi = getMessageInfoByUid(uid); 624 if (mi != null) 625 return (UIDMimeMessage) mi.getMessage(); 626 627 return new UIDMimeMessage(this, uid); 629 } 630 631 634 public Message getRealMessage(MessageInfo mi) throws MessagingException { 635 Message wrappingMessage = mi.getMessage(); 636 if (wrappingMessage instanceof UIDMimeMessage) 637 return ((UIDMimeMessage)wrappingMessage).getMessage(); 638 else 639 return wrappingMessage; 640 } 641 642 646 public javax.mail.internet.MimeMessage getRealMessageById(long uid) throws MessagingException { 647 Folder f = getFolder(); 648 if (f != null && f instanceof UIDFolder) { 649 javax.mail.internet.MimeMessage m = null; 650 try { 651 m = (javax.mail.internet.MimeMessage ) ((UIDFolder) f).getMessageByUID(uid); 652 return m; 653 } catch (IllegalStateException ise) { 654 throw new MessagingException(ise.getMessage()); 655 } 656 } else { 657 throw new MessagingException("Error: Folder unavailable or is not a UIDFolder"); 658 } 659 } 660 661 664 public MessageInfo getMessageInfo(Message m) { 665 if (m instanceof UIDMimeMessage) 666 return (MessageInfo) messageToInfoTable.get(m); 667 else { 668 try { 669 long uid = getUID(m); 670 return getMessageInfoByUid(uid); 671 } catch (MessagingException me) { 672 return null; 673 } 674 } 675 } 676 677 680 public MessageInfo getMessageInfoByUid(long uid) { 681 return (MessageInfo) uidToInfoTable.get(new Long (uid)); 682 } 683 684 685 688 public long getUID(Message m) throws MessagingException { 689 if (m instanceof UIDMimeMessage) 690 return ((UIDMimeMessage)m).getUID(); 691 else { 692 return ((UIDFolder)getFolder()).getUID(m); 693 } 694 } 695 696 public long getUIDValidity() { 697 return uidValidity; 698 } 699 700 } 701 702 | Popular Tags |