1 21 22 package org.armedbear.j.mail; 23 24 import java.awt.Image ; 25 import java.awt.Rectangle ; 26 import java.io.BufferedReader ; 27 import java.io.IOException ; 28 import java.io.StringReader ; 29 import java.util.ArrayList ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Vector ; 33 import javax.swing.Icon ; 34 import javax.swing.SwingUtilities ; 35 import org.armedbear.j.Annotation; 36 import org.armedbear.j.Buffer; 37 import org.armedbear.j.BufferIterator; 38 import org.armedbear.j.Debug; 39 import org.armedbear.j.Display; 40 import org.armedbear.j.Editor; 41 import org.armedbear.j.EditorIterator; 42 import org.armedbear.j.File; 43 import org.armedbear.j.FastStringBuffer; 44 import org.armedbear.j.FastStringReader; 45 import org.armedbear.j.Headers; 46 import org.armedbear.j.ImageLine; 47 import org.armedbear.j.ImageLoader; 48 import org.armedbear.j.Line; 49 import org.armedbear.j.LineSequence; 50 import org.armedbear.j.Log; 51 import org.armedbear.j.MessageDialog; 52 import org.armedbear.j.MessageHeaderLine; 53 import org.armedbear.j.Position; 54 import org.armedbear.j.ProgressNotifier; 55 import org.armedbear.j.Property; 56 import org.armedbear.j.SaveFileDialog; 57 import org.armedbear.j.Sidebar; 58 import org.armedbear.j.SystemBuffer; 59 import org.armedbear.j.TextLine; 60 import org.armedbear.j.Utilities; 61 import org.armedbear.j.WebBuffer; 62 import org.armedbear.j.WebFormatter; 63 import org.armedbear.j.WebLine; 64 import org.armedbear.j.WebLoader; 65 66 public class MessageBuffer extends Buffer 67 { 68 protected Mailbox mailbox; 69 protected MailboxEntry entry; 70 protected Message message; 71 protected boolean showFullHeaders; 72 protected boolean showRawText; 73 protected String allHeaders; 74 protected String defaultHeaders; 75 protected String rawBody; 76 protected String body; 77 protected String mimeBody; 78 protected MimePart selectedPart; 79 protected int headerLineCount; 80 81 private boolean wrap = true; 82 83 protected MessageBuffer() 84 { 85 super(); 86 setInitialized(true); 87 } 88 89 public MessageBuffer(String rawText) 90 { 91 initializeUndo(); 92 type = TYPE_NORMAL; 93 lineSeparator = "\n"; 94 mode = MessageMode.getMode(); 95 setFormatter(new MessageFormatter(this)); 96 readOnly = true; 97 message = new Message(rawText); 98 parseMessage(); 99 title = message.getHeaderValue(Headers.SUBJECT); 100 if (title == null) 101 title = ""; 102 allHeaders = message.getAllHeaders(); 103 defaultHeaders = getDefaultHeaders(allHeaders); 104 rawBody = message.getRawBody(); 105 setText(); 106 renumber(); 107 formatter.parseBuffer(); 108 setInitialized(true); 109 } 110 111 public final boolean isPrimary() 112 { 113 if (mailbox == null) 114 return true; 115 return mailbox.getPreviewBuffer() != this; 116 } 117 118 public final boolean isSecondary() 119 { 120 if (mailbox == null) 121 return false; 122 return mailbox.getPreviewBuffer() == this; 123 } 124 125 public final Buffer getPrimary() 126 { 127 if (mailbox != null && mailbox.getPreviewBuffer() == this) 128 return mailbox; 129 return null; 130 } 131 132 public final void promote() 133 { 134 if (mailbox != null && mailbox.getPreviewBuffer() == this) 135 mailbox.setPreviewBuffer(null); 136 } 137 138 public int getHeaderLineCount() 139 { 140 return headerLineCount; 141 } 142 143 public int getDisplayHeight() 144 { 145 int height = 0; 146 for (Line line = getFirstLine(); line != null; line = line.nextVisible()) 147 height += line.getHeight(); 148 return height; 149 } 150 151 public int getDisplayWidth() 152 { 153 int width = 0; 154 for (Line line = getFirstLine(); line != null; line = line.nextVisible()) { 155 int lineWidth = line.getWidth(); 156 if (lineWidth > width) 157 width = lineWidth; 158 } 159 return Display.getGutterWidth(this) + width + Display.getCharWidth(); 160 } 161 162 public int getY(Line target) 164 { 165 int y = 0; 166 for (Line line = getFirstLine(); line != null && line != target; line = line.nextVisible()) 167 y += line.getHeight(); 168 return y; 169 } 170 171 protected void setEntry(MailboxEntry entry) 172 { 173 Debug.assertTrue(entry != null); 174 reset(); 175 this.entry = entry; 176 FastStringBuffer sb = new FastStringBuffer(); 177 sb.append(mailbox.getLineNumberForEntry(entry) + 1); 178 sb.append('/'); 179 sb.append(mailbox.getLineCount()); 180 sb.append(' '); 181 sb.append(entry.formatSubject()); 182 title = sb.toString(); 183 Sidebar.setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST); 184 } 185 186 protected void reset() 187 { 188 try { 189 lockWrite(); 190 } 191 catch (InterruptedException e) { 192 Log.debug(e); 193 return; 194 } 195 try { 196 empty(); 197 message = null; 198 mimeBody = null; 199 selectedPart = null; 200 } 201 finally { 202 unlockWrite(); 203 } 204 } 205 206 public int load() 207 { 208 Debug.assertTrue(false); return LOAD_COMPLETED; 210 } 211 212 protected void loadMessage(ProgressNotifier progressNotifier) 213 { 214 Debug.assertTrue(entry != null); 215 mailbox.setBusy(true); 216 message = mailbox.getMessage(entry, progressNotifier); 217 mailbox.setBusy(false); 218 if (message == null) 219 return; 220 parseMessage(); 221 allHeaders = message.getAllHeaders(); 222 defaultHeaders = getDefaultHeaders(allHeaders); 223 rawBody = message.getRawBody(); 224 wrap = true; 225 setText(); 226 formatter.parseBuffer(); 227 int flags = entry.getFlags(); 228 if ((flags & MailboxEntry.SEEN) == 0) { 229 flags |= MailboxEntry.SEEN; 230 flags &= ~MailboxEntry.RECENT; 231 entry.setFlags(flags); 232 mailbox.setDirty(true); 233 mailbox.updateEntry(entry); 234 mailbox.countMessages(); 235 } 236 Runnable r = new Runnable () { 237 public void run() 238 { 239 setBusy(false); 240 for (EditorIterator it = new EditorIterator(); it.hasNext();) { 241 Editor ed = it.nextEditor(); 242 if (ed.getBuffer() == MessageBuffer.this) { 243 ed.setDot(getFirstLine(), 0); 244 ed.setUpdateFlag(REFRAME); 245 ed.moveCaretToDotCol(); 246 ed.setTopLine(getFirstLine()); 247 ed.setMark(null); 248 ed.setUpdateFlag(REPAINT); 249 ed.updateDisplay(); 250 } else if (ed.getBuffer() == mailbox) 251 ed.updateDisplay(); 252 } 253 Sidebar.repaintBufferListInAllFrames(); 254 } 255 }; 256 SwingUtilities.invokeLater(r); 257 } 258 259 public final MailboxEntry getMailboxEntry() 260 { 261 return entry; 262 } 263 264 public final Message getMessage() 265 { 266 return message; 267 } 268 269 public final int getMessageNumber() 270 { 271 Debug.assertTrue(entry != null); 272 return entry.getMessageNumber(); 273 } 274 275 public final Mailbox getMailbox() 276 { 277 return mailbox; 278 } 279 280 public void nextMessage() 281 { 282 if (entry == null) 283 return; 284 Editor editor = Editor.currentEditor(); 285 MailboxEntry nextEntry = mailbox.getNextUndeleted(entry); 286 if (nextEntry != null) { 287 mailbox.setDotEntry(nextEntry); 288 load(editor, nextEntry); 289 } else { 290 MailCommands.messageIndex(editor); 291 editor.status("Last undeleted message"); 292 } 293 } 294 295 public void previousMessage() 296 { 297 if (entry == null) 298 return; 299 Editor editor = Editor.currentEditor(); 300 MailboxEntry previousEntry = mailbox.getPreviousUndeleted(entry); 301 if (previousEntry != null) { 302 mailbox.setDotEntry(previousEntry); 303 load(editor, previousEntry); 304 } else { 305 MailCommands.messageIndex(editor); 306 editor.status("First undeleted message"); 307 } 308 } 309 310 public void nextInThread() 311 { 312 if (entry == null) 313 return; 314 Editor editor = Editor.currentEditor(); 315 MailboxEntry nextEntry = mailbox.getNextInThread(entry); 316 if (nextEntry != null) { 317 mailbox.setDotEntry(nextEntry); 318 load(editor, nextEntry); 319 } else { 320 MailCommands.messageIndex(editor); 321 editor.status("Last message in thread"); 322 } 323 } 324 325 public void previousInThread() 326 { 327 if (entry == null) 328 return; 329 Editor editor = Editor.currentEditor(); 330 MailboxEntry previousEntry = mailbox.getPreviousInThread(entry); 331 if (previousEntry != null) { 332 mailbox.setDotEntry(previousEntry); 333 load(editor, previousEntry); 334 } else { 335 MailCommands.messageIndex(editor); 336 editor.status("First message in thread"); 337 } 338 } 339 340 public void parentMessage() 341 { 342 final Editor editor = Editor.currentEditor(); 343 String inReplyTo = message.getHeaderValue(Headers.IN_REPLY_TO); 344 Log.debug("inReplyTo = |" + inReplyTo + "|"); 345 if (inReplyTo != null) { 346 String msgId = extractMessageId(inReplyTo); 347 if (msgId != null) { 348 Log.debug("msgId = |" + msgId + "|"); 349 MailboxEntry parentEntry = mailbox.getEntryForMessageId(msgId); 350 if (parentEntry != null) { 351 load(editor, parentEntry); 352 return; 353 } 354 } 355 } 356 String references = message.getHeaderValue(Headers.REFERENCES); 357 Log.debug("references = |" + references + "|"); 358 if (references != null) { 359 List list = extractAllMessageIds(references); 360 if (list != null) { 361 for (int i = 0; i < list.size(); i++) { 362 String msgId = (String ) list.get(i); 363 if (msgId != null) { 364 Log.debug("msgId = |" + msgId + "|"); 365 MailboxEntry parentEntry = 366 mailbox.getEntryForMessageId(msgId); 367 if (parentEntry != null) { 368 load(editor, parentEntry); 369 return; 370 } 371 } 372 } 373 } 374 } 375 editor.status("No parent"); 376 } 377 378 private static String extractMessageId(String s) 379 { 380 if (s == null) 381 return null; 382 int begin = s.indexOf('<'); 383 if (begin < 0) 384 return null; 385 int end = s.indexOf('>'); 386 if (end < 0) 387 return null; 388 return s.substring(begin, end + 1); 389 } 390 391 private static List extractAllMessageIds(String s) 392 { 393 if (s == null) 394 return null; 395 ArrayList list = null; 396 while (s.length() > 2) { 397 int begin = s.indexOf('<'); 398 if (begin < 0) 399 break; 400 int end = s.indexOf('>'); 401 if (end < 0) 402 break; 403 String msgId = s.substring(begin, end + 1); 404 if (list == null) 405 list = new ArrayList (); 406 Log.debug("adding |" + msgId + "|"); 407 list.add(msgId); 408 s = s.substring(end+1); 409 } 410 return list; 411 } 412 413 private void load(Editor editor, MailboxEntry nextEntry) 414 { 415 if (mailbox.lock()) { 416 setBusy(true); 417 setEntry(nextEntry); 418 Runnable r = new Runnable () { 419 public void run() 420 { 421 try { 422 loadMessage(null); 423 } 424 finally { 425 mailbox.unlock(); 426 } 427 } 428 }; 429 new Thread (r).start(); 430 } else 431 editor.status("Mailbox is locked"); 432 } 433 434 public String quoteBody(int wrapCol) 436 { 437 String toBeQuoted = mimeBody != null ? mimeBody : rawBody; 438 if (toBeQuoted == null) { 439 Log.debug("quoteBody toBeQuoted is null"); 440 return null; 441 } 442 if (Utilities.isWhitespace(toBeQuoted)) { 443 Log.debug("quoteBody toBeQuoted is whitespace"); 444 return null; 445 } 446 String wrapped = wrap(toBeQuoted, wrapCol-2, 8); 447 FastStringReader reader = new FastStringReader(wrapped); 448 FastStringBuffer sb = new FastStringBuffer(4096); 449 String s; 450 while ((s = reader.readLine()) != null) { 451 sb.append('>'); 452 if (s.length() > 0) { 453 sb.append(' '); 454 sb.append(s); 455 } 456 sb.append('\n'); 457 } 458 return sb.toString(); 459 } 460 461 private static final String wrap(String s, int wrapCol, int tabWidth) 462 { 463 FastStringReader reader = new FastStringReader(s); 464 FastStringBuffer sb = new FastStringBuffer(4096); 465 java.io.StringWriter writer = new java.io.StringWriter (); 466 String line; 467 while ((line = reader.readLine()) != null) { 468 if (line.length() == 0) { 469 if (sb.length() > 0) { 470 writer.write(Utilities.wrap(sb.toString(), wrapCol, 471 tabWidth)); 472 sb.setLength(0); 473 writer.write('\n'); 474 } 475 writer.write('\n'); 476 } else { 477 if (sb.length() == 0 && 479 Utilities.getDetabbedLength(line, tabWidth) <= 78) { 480 writer.write(line); 482 writer.write('\n'); 483 continue; 484 } 485 char c = line.charAt(0); 486 if (c == ' ' || c == '\t' || c == '>') { 487 if (sb.length() > 0) { 488 writer.write(Utilities.wrap(sb.toString(), wrapCol, 489 tabWidth)); 490 sb.setLength(0); 491 writer.write('\n'); 492 } 493 writer.write(line); 494 writer.write('\n'); 495 } else { 496 if (sb.length() > 0) { 497 c = sb.charAt(sb.length()-1); 499 if (c != ' ' && c != '\t') 500 sb.append(' '); 501 } 502 sb.append(line); 503 } 504 } 505 } 506 if (sb.length() > 0) { 507 writer.write(Utilities.wrap(sb.toString(), wrapCol, tabWidth)); 508 sb.append('\n'); 509 } 510 return writer.toString(); 511 } 512 513 public void deleteMessage() {} 514 515 public void flagMessage() {} 516 517 public void moveMessage() {} 518 519 public void bounce() 520 { 521 Debug.assertTrue(SwingUtilities.isEventDispatchThread()); 522 final Editor editor = Editor.currentEditor(); 523 final MailAddress[] to = MailCommands.bounceGetTo(editor, 1); 524 if (to == null) 525 return; 526 Runnable bounceRunnable = new Runnable () { 527 public void run() 528 { 529 Log.debug("MessageBuffer bounceRunnable.run()"); 530 boolean succeeded = false; 531 try { 532 succeeded = Mail.bounceMessage(message, to); 533 } 534 finally { 535 setBusy(false); 536 editor.updateDisplayLater(); 537 } 538 if (succeeded) { 539 Runnable successRunnable = new Runnable () { 540 public void run() 541 { 542 editor.status("Message bounced"); 543 } 544 }; 545 SwingUtilities.invokeLater(successRunnable); 546 } else { 547 Runnable errorRunnable = new Runnable () { 548 public void run() 549 { 550 MessageDialog.showMessageDialog(editor, "Failed", 551 "Bounce Message"); 552 } 553 }; 554 SwingUtilities.invokeLater(errorRunnable); 555 } 556 } 557 }; 558 setBusy(true); 559 new Thread (bounceRunnable).start(); 560 } 561 562 protected String getBeautifiedHeaders() 563 { 564 if (message == null) 565 return ""; 566 Headers headers = Headers.parse(message.getRawHeaders()); 567 ArrayList names = new ArrayList (); names.add("From"); 569 names.add("To"); 570 names.add("Cc"); 571 names.add("Subject"); 572 names.add("Date"); 573 int width = 0; 574 for (Iterator it = names.iterator(); it.hasNext();) { 575 int w = ((String )it.next()).length(); 576 if (w > width) 577 width = w; 578 } 579 FastStringBuffer sb = new FastStringBuffer(); 580 for (Iterator it = names.iterator(); it.hasNext();) { 581 String name = (String ) it.next(); 582 String value = headers.getValue(name); 583 if (value != null) { 584 if (name == "From" || name== "To" || name == "Cc") { 585 MailAddress[] array = 586 MailAddress.parseAddresses(RFC2047.decode(value)); 587 ArrayList list = new ArrayList (); 588 for (int i = 0; i < array.length; i++) 589 list.add(array[i]); 590 String prefix = 591 Utilities.rightJustify(name, width).concat(": "); 592 sb.append(MailUtilities.constructAddressHeader(prefix, 593 list, prefix.length())); 594 } else { 595 sb.append(Utilities.rightJustify(name, width)); 597 sb.append(": "); 598 sb.append(RFC2047.decode(value)); 599 } 600 sb.append('\n'); 601 } 602 } 603 return sb.toString(); 604 } 605 606 protected String getDefaultHeaders(String s) 607 { 608 FastStringBuffer sb = new FastStringBuffer(); 609 if (s.length() > 0) { 610 BufferedReader reader = new BufferedReader (new StringReader (s)); 611 boolean maybeContinuation = false; 612 try { 613 while (true) { 614 String text = reader.readLine(); 615 if (text == null || text.length() == 0) 616 break; 617 if (maybeContinuation && 618 Character.isWhitespace(text.charAt(0))) { 619 sb.append(text); 620 sb.append('\n'); 621 } else if (isDefaultHeader(text)) { 622 sb.append(text); 623 sb.append('\n'); 624 maybeContinuation = true; 625 } else 626 maybeContinuation = false; 627 } 628 } 629 catch (IOException e) { 630 Log.error(e); 631 } 632 } 633 return sb.toString(); 634 } 635 636 private boolean isDefaultHeader(String s) 637 { 638 s = s.toLowerCase(); 639 if (s.startsWith("from:") || 640 s.startsWith("to:") || 641 s.startsWith("cc:") || 642 s.startsWith("subject:") || 643 s.startsWith("date:")) 644 return true; 645 return false; 646 } 647 648 public void viewAttachment() 649 { 650 final MimePart part = getAttachmentAtDot(); 651 if (part == null) 652 return; 653 final Editor editor = Editor.currentEditor(); 654 editor.setWaitCursor(); 655 final String contentType = part.getContentType(); 656 if (contentType != null && contentType.equals("message/rfc822")) { 657 final String rawText = part.getRawBody(); 658 Buffer buf = null; 659 for (BufferIterator it = new BufferIterator(); it.hasNext();) { 661 Buffer b = it.nextBuffer(); 662 if (b instanceof MessageBuffer) { 663 MessageBuffer mb = (MessageBuffer) b; 664 Message m = mb.getMessage(); 665 if (m.getRawText().equals(rawText)) { 666 buf = b; 667 break; 668 } 669 } 670 } 671 if (buf == null) buf = new MessageBuffer(rawText); 673 editor.makeNext(buf); 674 editor.switchToBuffer(buf); 675 return; 676 } 677 File cache = part.cacheDecoded(); 678 if (cache == null || !cache.isFile()) { 679 MessageDialog.showMessageDialog("Unable to decode attachment", 680 "View Attachment"); 681 return; 682 } 683 if (contentType != null && contentType.equals("text/html")) { 684 WebBuffer.browse(editor, cache, null); 685 return; 686 } 687 Buffer buf = editor.openFile(cache); 688 if (buf != null) { 689 editor.makeNext(buf); 690 editor.switchToBuffer(buf); 691 } 692 } 693 694 public void saveAttachment() 695 { 696 MimePart part = getAttachmentAtDot(); 697 if (part == null) 698 return; 699 final Editor editor = Editor.currentEditor(); 700 SaveFileDialog d = 701 new SaveFileDialog(editor, "Save Attachment", "File:"); 702 File suggested = File.getInstance(editor.getCurrentDirectory(), 703 part.getAttachmentFileName()); 704 if (suggested != null) 705 d.setInitialText(suggested.canonicalPath()); 706 editor.centerDialog(d); 707 d.show(); 708 File saveAs = d.getDestination(); 709 if (saveAs == null) 710 return; 711 editor.repaintNow(); 712 editor.setWaitCursor(); 713 boolean success = part.saveDecoded(saveAs); 714 editor.setDefaultCursor(); 715 if (!success) 716 MessageDialog.showMessageDialog("Unable to save attachment", 717 "Save Attachment"); 718 } 719 720 private MimePart getAttachmentAtDot() 721 { 722 Position dot = Editor.currentEditor().getDot(); 723 if (dot != null) { 724 Annotation annotation = dot.getLine().getAnnotation(); 725 if (annotation != null) { 726 Object obj = annotation.getUserObject(); 727 if (obj instanceof MimePart) 728 return (MimePart) obj; 729 } 730 } 731 return null; 732 } 733 734 public void toggleRaw() 735 { 736 showRawText = !showRawText; 737 if (mailbox != null) 738 mailbox.showRawText = showRawText; 739 reloadInternal(); 740 FastStringBuffer sb = new FastStringBuffer("Raw mode "); 741 sb.append(showRawText ? "on" : "off"); 742 Editor.currentEditor().status(sb.toString()); 743 } 744 745 public void toggleHeaders() 746 { 747 if (mailbox != null) 748 mailbox.showFullHeaders = showFullHeaders = !showFullHeaders; 749 reloadInternal(); 750 } 751 752 public void toggleWrap() 753 { 754 wrap = !wrap; 755 reloadInternal(); 756 FastStringBuffer sb = new FastStringBuffer("Wrap "); 757 sb.append(wrap ? "on" : "off"); 758 Editor.currentEditor().status(sb.toString()); 759 } 760 761 private void reloadInternal() 762 { 763 setText(); 764 formatter.parseBuffer(); 765 for (EditorIterator it = new EditorIterator(); it.hasNext();) { 766 Editor ed = it.nextEditor(); 767 if (ed.getBuffer() == this) { 768 ed.setDot(getFirstLine(), 0); 769 ed.moveCaretToDotCol(); 770 ed.setMark(null); 771 ed.setTopLine(getFirstLine()); 772 ed.repaintDisplay(); 773 } 774 } 775 } 776 777 protected void parseMessage() 778 { 779 if (mimeBody != null) 780 Debug.bug(); 781 message.parse(); 782 List parts = message.getParts(); 783 if (parts == null || parts.size() == 0) { 784 mimeBody = message.getDecodedBody(); 786 return; 787 } 788 for (Iterator it = parts.iterator(); it.hasNext();) { 789 MimePart part = (MimePart) it.next(); 790 final String contentType = part.getContentType(); 791 if (contentType == null || contentType.equals("text/plain")) { 792 selectedPart = part; 793 mimeBody = part.getDecodedBody(); 794 return; 795 } 796 } 797 for (Iterator it = parts.iterator(); it.hasNext();) { 798 MimePart part = (MimePart) it.next(); 799 final String contentType = part.getContentType(); 800 if (contentType == null || contentType.equals("text/html")) { 801 selectedPart = part; 802 mimeBody = part.getDecodedBody(); 803 return; 804 } 805 } 806 mimeBody = ""; 807 } 808 809 private List getAttachmentLines() 810 { 811 List parts = message.getParts(); 812 if (parts == null || parts.size() == 0) { 813 return null; 815 } 816 int shown = -1; 817 ArrayList list = new ArrayList (); 818 list.add(new MessageHeaderLine("Parts/Attachments:")); 819 for (int i = 0; i < parts.size(); i++) { 820 FastStringBuffer sb = new FastStringBuffer(); 821 sb.append(" "); 822 sb.append(i+1); 823 MimePart part = (MimePart) parts.get(i); 824 final String contentType = part.getContentType(); 825 if (part == selectedPart) { 826 sb.append(" Shown"); 827 } else { 828 String filename = part.getAttachmentFileName(); 829 if (filename != null && filename.length() > 0) { 830 if (part.isAttachment()) 831 sb.append(" Attachment:"); 832 else if (part.isInline()) 833 sb.append(" Inline:"); 834 sb.append(' '); 835 sb.append(filename); 836 } else if (part.isAttachment()) { 837 sb.append(" Attachment"); 838 } else if (part.isInline()) { 839 sb.append(" Inline"); 840 } 841 } 842 sb.append(" ("); 843 if (contentType != null) { 844 sb.append(contentType); 845 sb.append(", "); 846 } 847 final String encoding = part.getTransferEncoding(); 848 if (encoding != null) { 849 sb.append(encoding); 850 sb.append(", "); 851 } 852 sb.append(part.getSize()); 853 sb.append(" bytes)"); 854 Line line = new MessageHeaderLine(sb.toString()); 855 line.setAnnotation(new Annotation(part)); 856 list.add(line); 857 } 858 return list; 859 } 860 861 protected void setText() 862 { 863 try { 864 lockWrite(); 865 } 866 catch (InterruptedException e) { 867 Log.debug(e); 868 return; 869 } 870 try { 871 _setText(); 872 setLoaded(true); 873 } 874 finally { 875 unlockWrite(); 876 } 877 } 878 879 private void _setText() 880 { 881 empty(); 882 if (showRawText) { 883 body = rawBody; 884 setText(message.getRawText()); 885 headerLineCount = Utilities.countLines(allHeaders); 886 if (!(formatter instanceof MessageFormatter)) 887 setFormatter(new MessageFormatter(this)); 888 return; 889 } 890 final String headers; 892 if (showFullHeaders) 893 headers = allHeaders; 894 else if (Editor.preferences().getBooleanProperty(Property.BEAUTIFY_HEADERS)) 895 headers = getBeautifiedHeaders(); 896 else 897 headers = defaultHeaders; 898 final String contentType = message.getContentType(); 899 if (contentType != null) { 900 if (contentType.startsWith("image/")) { 901 File cache = message.cacheDecoded(); 902 if (cache != null && cache.isFile()) { 903 ImageLoader loader = new ImageLoader(cache); 904 Image image = loader.loadImage(); 905 appendHeaderLines(headers); 906 appendHeaderLine(""); 907 if (image != null) { 908 final int lineHeight = new TextLine("").getHeight(); 909 final int imageHeight = image.getHeight(null); 910 final int imageWidth = image.getWidth(null); 911 int y = 0; 912 while (y < imageHeight) { 913 Rectangle r = new Rectangle (0, y, imageWidth, 914 Math.min(lineHeight, imageHeight - y)); 915 appendLine(new ImageLine(image, r)); 916 y += lineHeight; 917 } 918 } 919 renumber(); 920 } else { 921 appendHeaderLines(headers); 922 appendHeaderLine(""); 923 append(body); 924 } 925 renumber(); 926 if (!(formatter instanceof MessageFormatter)) 927 setFormatter(new MessageFormatter(this)); 928 return; 929 } 930 if (contentType.equals("text/html")) { 931 appendHeaderLines(headers); 932 appendHeaderLine(""); 933 StringReader reader = 934 new StringReader (message.getDecodedBody()); 935 WebLoader loader = new WebLoader(reader); 936 LineSequence lines = loader.load(); 937 Line lastLine = getLastLine(); 938 lastLine.setNext(lines.getFirstLine()); 939 lines.getFirstLine().setPrevious(lastLine); 940 renumber(); 941 if (!(formatter instanceof WebFormatter)) 942 setFormatter(new WebFormatter(this)); 943 return; 944 } 945 } 946 appendHeaderLines(headers); 947 headerLineCount = Utilities.countLines(headers); 948 List attachmentLines = getAttachmentLines(); 949 if (attachmentLines != null) { 950 appendHeaderLine(""); 951 ++headerLineCount; 952 Iterator iter = attachmentLines.iterator(); 953 while (iter.hasNext()) { 954 Line line = (Line) iter.next(); 955 if (!(line instanceof MessageHeaderLine)) 956 Debug.bug(); 957 appendLine(line); 958 ++headerLineCount; 959 } 960 } 961 if (mimeBody != null) 962 body = mimeBody; 963 else 964 body = rawBody; 965 if (selectedPart != null && "text/html".equals(selectedPart.getContentType())) { 966 appendLine(""); 967 StringReader reader = new StringReader (mimeBody); 968 WebLoader loader = new WebLoader(reader); 969 LineSequence lines = loader.load(); 970 Line lastLine = getLastLine(); 971 lastLine.setNext(lines.getFirstLine()); 972 lines.getFirstLine().setPrevious(lastLine); 973 if (!(formatter instanceof WebFormatter)) 974 setFormatter(new WebFormatter(this)); 975 } else { 976 if (wrap) 977 body = wrapBody(body); 978 appendLine(""); 979 append(body); 980 if (!(formatter instanceof MessageFormatter)) 981 setFormatter(new MessageFormatter(this)); 982 } 983 if (message.getSize() < 1024 * 1024) { 985 List parts = message.getParts(); 986 if (parts != null) { 987 for (int i = 0; i < parts.size(); i++) { 988 MimePart part = (MimePart) parts.get(i); 989 String partContentType = part.getContentType(); 990 if (partContentType == null) 991 continue; 992 File cache = null; 993 if (partContentType.equals("application/octet-stream")) { 994 String filename = part.getAttachmentFileName(); 995 if (filename == null) 996 continue; 997 filename = filename.toLowerCase(); 998 if (filename.endsWith(".jpg") || 999 filename.endsWith(".jpeg") || 1000 filename.endsWith(".png") || 1001 filename.endsWith(".gif")) 1002 cache = part.cacheDecoded(); 1003 } else if (partContentType.startsWith("image/")) 1004 cache = part.cacheDecoded(); 1005 if (cache != null && cache.isFile()) { 1006 ImageLoader loader = new ImageLoader(cache); 1007 Image image = loader.loadImage(); 1008 if (image != null) { 1009 if (getLastLine() instanceof ImageLine) 1010 appendLine(""); 1011 final int lineHeight = new TextLine("").getHeight(); 1012 final int imageHeight = image.getHeight(null); 1013 final int imageWidth = image.getWidth(null); 1014 int y = 0; 1015 while (y < imageHeight) { 1016 Rectangle r = new Rectangle (0, y, imageWidth, 1017 Math.min(lineHeight, imageHeight - y)); 1018 appendLine(new ImageLine(image, r)); 1019 y += lineHeight; 1020 } 1021 } 1022 } 1023 } 1024 } 1025 } 1026 renumber(); 1027 } 1028 1029 private static String wrapBody(String body) 1030 { 1031 final int wrapCol = Editor.currentEditor().getDisplay().getColumns(); 1032 final int tabWidth = 8; 1033 final int IN_DIFF = 1; 1034 SystemBuffer buf = new SystemBuffer(); 1035 FastStringReader reader = new FastStringReader(body); 1036 String s; 1037 while ((s = reader.readLine()) != null) 1038 buf.appendLine(s); 1039 boolean containsDiff = false; 1040 boolean inDiff = false; 1041 for (Line line = buf.getFirstLine(); line != null; line = line.next()) { 1042 if (inDiff) { 1043 if (MessageFormatter.isDiffContinuation(line)) 1044 line.setFlags(IN_DIFF); 1045 else { 1046 inDiff = false; 1047 line.setFlags(0); 1048 } 1049 continue; 1050 } 1051 if (MessageFormatter.isDiffStart(line)) { 1053 inDiff = true; 1054 line.setFlags(IN_DIFF); 1055 containsDiff = true; 1056 continue; 1057 } 1058 line.setFlags(0); 1060 } 1061 if (!containsDiff) 1062 return Utilities.wrap(body, wrapCol, tabWidth); 1063 FastStringBuffer out = new FastStringBuffer(); 1065 FastStringBuffer in = new FastStringBuffer(); 1066 for (Line line = buf.getFirstLine(); line != null; line = line.next()) { 1067 if (line.flags() == IN_DIFF) { 1068 if (in.length() > 0) { 1069 out.append(Utilities.wrap(in.toString(), wrapCol, tabWidth)); 1070 in.setLength(0); 1071 } 1072 out.append(line.getText()); 1073 out.append('\n'); 1074 } else { 1075 in.append(line.getText()); 1077 in.append('\n'); 1078 } 1079 } 1080 if (in.length() > 0) 1081 out.append(Utilities.wrap(in.toString(), wrapCol, tabWidth)); 1082 return out.toString(); 1083 } 1084 1085 protected void appendHeaderLines(String headers) 1086 { 1087 if (headers != null) { 1088 FastStringReader reader = new FastStringReader(headers); 1089 String s; 1090 while ((s = reader.readLine()) != null) 1091 appendHeaderLine(s); 1092 } 1093 } 1094 1095 protected void appendHeaderLine(String s) 1096 { 1097 appendLine(new MessageHeaderLine(s)); 1098 } 1099 1100 public String toString() 1101 { 1102 return title; 1103 } 1104 1105 public Icon getIcon() 1107 { 1108 return Utilities.getIconFromFile("message.png"); 1109 } 1110 1111 public String getFileNameForDisplay() 1112 { 1113 return ""; 1114 } 1115 1116 private static final String SPLIT_KEY = "MessageBuffer.split"; 1117 1118 public void saveWindowState(Editor editor) 1119 { 1120 if (editor.getBuffer() != this) 1121 return; 1122 Editor otherEditor = editor.getOtherEditor(); 1123 if (otherEditor != null) { 1124 float height = (float) editor.getHeight(); 1125 float split = 1126 height / (editor.getFrame().getEditorPane().getHeight()); 1127 Editor.getSessionProperties().setFloatProperty(SPLIT_KEY, split); 1128 } 1129 } 1130 1131 public float getSplit() 1132 { 1133 return Editor.getSessionProperties().getFloatProperty(SPLIT_KEY, 0.5F); 1134 } 1135 1136 public void windowClosing() 1137 { 1138 Editor editor = Editor.currentEditor(); 1139 if (editor.getBuffer() == this) 1140 saveWindowState(editor); 1141 else { 1142 Editor otherEditor = editor.getOtherEditor(); 1143 if (otherEditor != null && otherEditor.getBuffer() == this) 1144 saveWindowState(otherEditor); 1145 } 1146 } 1147 1148 public void dispose() 1149 { 1150 if (mailbox != null && mailbox.getPreviewBuffer() == this) 1151 mailbox.setPreviewBuffer(null); 1152 flushImages(); 1153 } 1154 1155 public void empty() 1156 { 1157 flushImages(); 1158 super.empty(); 1159 } 1160 1161 private void flushImages() 1162 { 1163 for (Line line = getFirstLine(); line != null; line = line.next()) { 1164 if (line instanceof ImageLine) 1165 ((ImageLine)line).flushImage(); 1166 } 1167 } 1168} 1169 | Popular Tags |