1 16 package org.apache.cocoon.mail; 17 18 import java.io.IOException ; 19 import java.text.SimpleDateFormat ; 21 import java.util.Date ; 22 import java.util.Enumeration ; 23 import javax.mail.Address ; 24 import javax.mail.Flags ; 25 import javax.mail.Folder ; 26 import javax.mail.Header ; 27 import javax.mail.Message ; 28 import javax.mail.MessagingException ; 29 import javax.mail.Multipart ; 30 import javax.mail.Part ; 31 import javax.mail.internet.ContentType ; 32 import javax.mail.internet.InternetAddress ; 33 import javax.mail.internet.MimeMultipart ; 34 import javax.mail.internet.MimePart ; 35 import javax.mail.internet.ParameterList ; 36 import javax.mail.internet.ParseException ; 37 import org.apache.avalon.framework.logger.AbstractLogEnabled; 38 import org.apache.excalibur.xml.sax.XMLizable; 39 import org.xml.sax.Attributes ; 40 import org.xml.sax.ContentHandler ; 41 import org.xml.sax.SAXException ; 42 import org.xml.sax.helpers.AttributesImpl ; 43 44 54 55 121 public class MailContentHandlerDelegate extends AbstractLogEnabled { 122 123 126 public final static String URI = "http://apache.org/cocoon/mail/1.0"; 127 128 131 public final static String PREFIX = "mail"; 132 133 137 private ContentHandler contentHandler; 138 139 143 private AttributesImpl attributes = null; 144 145 private SimpleDateFormat sdf; 146 147 private ContentTypePreference alternativeMailCtPref = new MailCtPref(); 148 149 150 155 public MailContentHandlerDelegate(ContentHandler contentHandler) { 156 this.contentHandler = contentHandler; 157 } 158 159 160 165 public void setSimpleDateFormat(SimpleDateFormat sdf) { 166 this.sdf = sdf; 167 } 168 169 170 175 public SimpleDateFormat getSimpleDateFormat() { 176 return sdf; 177 } 178 179 180 185 public void startDocument() throws SAXException { 186 startDocumentInternal(true); 187 } 188 189 190 195 public void startDocumentXMLizer() throws SAXException { 196 startDocumentInternal(false); 197 } 198 199 200 205 public void endDocument() throws SAXException { 206 endDocumentInternal(true); 207 } 208 209 210 215 public void endDocumentXMLizer() throws SAXException { 216 endDocumentInternal(false); 217 } 218 219 220 225 public void marshalFolderToSAX(Folder folder) { 226 try { 227 folderToSAX(this.contentHandler, folder); 228 } catch (Exception e) { 229 getLogger().error("Cannot generate SAX events from folder", e); 230 } 231 } 232 233 234 239 public void marshalFolderToSAX(Folder [] folders) { 240 try { 241 for (int i = 0; i < folders.length; i++) { 242 folderToSAX(this.contentHandler, folders[i]); 243 } 244 } catch (Exception e) { 245 getLogger().error("Cannot generate SAX events from folders", e); 246 } 247 } 248 249 250 255 public void marshalMessageEnvelopeToSAX(Message message) { 256 try { 257 messageEnvelopeToSAX(this.contentHandler, message); 258 } catch (Exception e) { 259 getLogger().error("Cannot generate SAX events from message envelope ", e); 260 } 261 } 262 263 264 269 public void marshalMessageToSAX(Message message) { 270 try { 271 messageEnvelopeToSAX(this.contentHandler, message); 272 partToSAX(this.contentHandler, message, 0); 273 } catch (Exception e) { 274 getLogger().error("Cannot generate SAX events from message ", e); 275 } 276 } 277 278 279 284 public void marshalPartToSAX(Part part) { 285 try { 286 partToSAX(this.contentHandler, part, 0); 287 } catch (Exception e) { 288 getLogger().error("Cannot generate SAX events part", e); 289 } 290 } 291 292 293 299 protected void startDocumentInternal(boolean emitStartDocument) throws SAXException { 300 if (emitStartDocument) { 301 this.contentHandler.startDocument(); 302 } 303 this.contentHandler.startPrefixMapping(PREFIX, URI); 304 305 attributes = new AttributesImpl (); 306 attributes.addAttribute("", PREFIX, "xmlns:" + PREFIX, "CDATA", URI); 307 startElement("mail", attributes); 308 } 309 310 311 317 protected void endDocumentInternal(boolean emitEndDocument) throws SAXException { 318 endElement("mail"); 319 320 this.contentHandler.endPrefixMapping(PREFIX); 321 if (emitEndDocument) { 322 this.contentHandler.endDocument(); 323 } 324 } 325 326 327 335 protected void folderToSAX(ContentHandler contentHandler, Folder folder) throws MessagingException , SAXException { 336 attributes.clear(); 337 addAttribute("name", folder.getName()); 338 addAttribute("full-name", folder.getFullName()); 339 addAttribute("url-name", folder.getURLName().toString()); 340 addAttribute("is-subscribed", folder.isSubscribed() ? "yes" : "no"); 341 addAttribute("is-directory", (folder.getType() & Folder.HOLDS_FOLDERS) != 0 ? "yes" : "no"); 342 343 if ((folder.getType() & Folder.HOLDS_MESSAGES) != 0) { 344 addAttribute("holds-messages", "yes"); 345 addAttribute("has-new-messages", folder.hasNewMessages() ? "yes" : "no"); 346 addAttribute("total-messages", String.valueOf(folder.getMessageCount())); 347 addAttribute("new-messages", String.valueOf(folder.getNewMessageCount())); 348 addAttribute("deleted-messages", String.valueOf(folder.getDeletedMessageCount())); 349 addAttribute("unread-messages", String.valueOf(folder.getUnreadMessageCount())); 350 } 351 352 startElement("folder", attributes); 353 endElement("folder"); 354 } 355 356 357 365 protected void messageEnvelopeToSAX(ContentHandler contentHandler, Message message) throws MessagingException , SAXException { 366 attributes.clear(); 367 startElement("message-envelope", attributes); 368 369 Address [] a; 370 if ((a = message.getFrom()) != null) { 372 for (int j = 0; j < a.length; j++) { 373 emitAddress("from", a[j]); 374 } 375 } 376 377 if ((a = message.getRecipients(Message.RecipientType.TO)) != null) { 379 for (int j = 0; j < a.length; j++) { 380 emitAddress("to", a[j]); 381 } 382 } 383 384 if ((a = message.getRecipients(Message.RecipientType.CC)) != null) { 386 for (int j = 0; j < a.length; j++) { 387 emitAddress("cc", a[j]); 388 } 389 } 390 if ((a = message.getRecipients(Message.RecipientType.BCC)) != null) { 392 for (int j = 0; j < a.length; j++) { 393 emitAddress("bcc", a[j]); 394 } 395 } 396 397 if ((a = message.getReplyTo()) != null) { 399 for (int j = 0; j < a.length; j++) { 400 emitAddress("reply-to", a[j]); 401 } 402 } 403 404 attributes.clear(); 406 startElement("subject", attributes); 407 characters(message.getSubject()); 408 endElement("subject"); 409 410 Date d; 412 d = message.getSentDate(); 413 emitDate("sent-date", d); 414 415 d = message.getReceivedDate(); 417 emitDate("received-date", d); 418 419 attributes.clear(); 421 startElement("size", attributes); 422 characters(String.valueOf(message.getSize())); 423 endElement("size"); 424 425 attributes.clear(); 427 startElement("message-number", attributes); 428 characters(String.valueOf(message.getMessageNumber())); 429 endElement("message-number"); 430 431 Flags flags = message.getFlags(); 433 Flags.Flag [] sf = flags.getSystemFlags(); 434 436 attributes.clear(); 437 for (int i = 0; i < sf.length; i++) { 438 Flags.Flag flag = sf[i]; 439 if (flag == Flags.Flag.ANSWERED) { 440 addAttribute("answered", "yes"); 441 } else if (flag == Flags.Flag.DELETED) { 442 addAttribute("deleted", "yes"); 443 } else if (flag == Flags.Flag.DRAFT) { 444 addAttribute("draft", "yes"); 445 } else if (flag == Flags.Flag.FLAGGED) { 446 addAttribute("flagged", "yes"); 447 } else if (flag == Flags.Flag.RECENT) { 448 addAttribute("recent", "yes"); 449 } else if (flag == Flags.Flag.SEEN) { 450 addAttribute("seen", "yes"); 451 } 452 } 453 startElement("flags", attributes); 454 endElement("flags"); 455 456 String [] uf = flags.getUserFlags(); 457 for (int i = 0; i < uf.length; i++) { 459 attributes.clear(); 460 startElement("user-flags", attributes); 461 characters(uf[i]); 462 endElement("user-flags"); 463 } 464 465 469 Enumeration allHeaders = message.getAllHeaders(); 470 if (allHeaders != null) { 471 while (allHeaders.hasMoreElements()) { 472 Header header = (Header ) allHeaders.nextElement(); 473 attributes.clear(); 474 addAttribute("name", header.getName()); 475 addAttribute("value", header.getValue()); 476 startElement("header", attributes); 477 478 endElement("header"); 479 } 480 } 481 482 endElement("message-envelope"); 483 } 484 485 486 496 protected void partToSAX(ContentHandler contentHandler, Part part, int i) throws MessagingException , IOException , SAXException { 497 attributes.clear(); 498 String v; 499 if ((v = part.getContentType()) != null) { 500 addAttribute("content-type", v); 502 try { 503 ContentType ct = new ContentType (v); 504 String s; 505 506 s = ct.getPrimaryType(); 508 if (s != null) { 509 addAttribute("primary-type", s.toLowerCase()); 510 } 511 512 s = ct.getSubType(); 514 if (s != null) { 515 addAttribute("secondary-type", s.toLowerCase()); 516 } 517 518 s = ct.getBaseType(); 520 if (s != null) { 521 addAttribute("base-type", s.toLowerCase()); 522 } 523 524 ParameterList pl = ct.getParameterList(); 526 Enumeration names = pl.getNames(); 527 while (names.hasMoreElements()) { 528 String key = (String ) names.nextElement(); 529 String value = pl.get(key); 530 addAttribute(key, value); 531 } 532 } catch (ParseException pe) { 533 String message = "Cannot parse content-type " + String.valueOf(v); 534 getLogger().error(message, pe); 535 } 536 } 537 538 if (i > 0) { 539 addAttribute("part-num", String.valueOf(i)); 540 541 if (part.getDescription() != null) { 542 addAttribute("description", part.getDescription()); 543 } 544 if (part.getDisposition() != null) { 545 addAttribute("disposition", part.getDisposition()); 546 addAttribute("disposition-inline", String.valueOf(part.getDisposition().equals(Part.INLINE))); 547 } 548 if (part.getFileName() != null) { 549 addAttribute("file-name", part.getFileName()); 550 } 551 } else { 552 boolean hasAttachments = false; 553 if (part.isMimeType("multipart/*")) { 554 Multipart mp = (Multipart ) part.getContent(); 555 if (mp.getCount() > 1) { 556 hasAttachments = true; 557 addAttribute("num-parts", String.valueOf(mp.getCount())); 558 } 559 } 560 addAttribute("has-attachments", String.valueOf(hasAttachments)); 561 } 562 563 startElement("part", attributes); 564 contentToSAX(contentHandler, part); 565 endElement("part"); 566 } 567 568 569 578 protected void contentToSAX(ContentHandler contentHandler, Part part) throws MessagingException , IOException , SAXException { 579 attributes.clear(); 580 startElement("content", attributes); 581 582 588 if (part.getContent() instanceof String && (part.isMimeType("text/plain"))) { 589 characters((String ) part.getContent()); 590 } else if (part.isMimeType("multipart/alternative")) { 591 MimeMultipart mp = (MimeMultipart ) part.getContent(); 592 MimePart bestPart = null; 593 int ctMax = 0; 594 for (int i = 0; i < mp.getCount(); i++) { 595 MimePart p = (MimePart ) mp.getBodyPart(i); 596 int ctPrefN = alternativeMailCtPref.preference(p); 597 if (ctPrefN > ctMax) { 598 ctMax = ctPrefN; 599 bestPart = p; 600 } 601 } 602 if (bestPart != null) { 603 partToSAX(contentHandler, bestPart, 0); 604 } 605 } else if (part.isMimeType("multipart/*")) { 606 Multipart mp = (Multipart ) part.getContent(); 607 608 int count = mp.getCount(); 609 for (int i = 0; i < count; i++) { 610 partToSAX(contentHandler, mp.getBodyPart(i), i); 611 } 612 } else if (part.isMimeType("message/rfc822")) { 613 partToSAX(contentHandler, (Part ) part.getContent(), 0); 614 } else { 615 629 } 630 endElement("content"); 631 } 632 633 634 641 protected void emitAddress(String nodeName, Address address) throws SAXException { 642 643 attributes.clear(); 644 645 if (address instanceof InternetAddress ) { 646 InternetAddress internetAddress = (InternetAddress ) address; 647 String personal = internetAddress.getPersonal(); 648 if (personal != null) { 649 addAttribute("personal", personal); 650 } 651 String emailAddress = internetAddress.getAddress(); 652 if (emailAddress != null) { 653 addAttribute("email-address", emailAddress); 654 } 655 } 656 657 startElement(nodeName, attributes); 658 String addressAsString = address.toString(); 659 characters(addressAsString); 660 endElement(nodeName); 661 } 662 663 664 671 protected void emitDate(String nodeName, Date d) throws SAXException { 672 attributes.clear(); 673 startElement(nodeName, attributes); 674 if (d != null) { 675 if (sdf != null) { 676 String formattedDate = sdf.format(d); 677 characters(formattedDate); 678 } else { 679 characters(d.toString()); 680 } 681 } 682 endElement(nodeName); 683 } 684 685 686 693 private void startElement(String nodeName, Attributes attributes) throws SAXException { 694 this.contentHandler.startElement(URI, nodeName, PREFIX + ":" + nodeName, attributes); 695 } 696 697 698 704 private void characters(String s) throws SAXException { 705 if (s != null) { 706 StringBuffer sb = new StringBuffer (); 709 char[] stringCharacters = s.toCharArray(); 710 for (int i = 0; i < stringCharacters.length; i++) { 711 if (stringCharacters[i] != 0x0d) { 712 sb.append(stringCharacters[i]); 713 } 714 } 715 stringCharacters = sb.toString().toCharArray(); 716 717 this.contentHandler.characters(stringCharacters, 0, stringCharacters.length); 718 } 719 } 720 721 722 728 private void endElement(String nodeName) throws SAXException { 729 this.contentHandler.endElement(URI, nodeName, PREFIX + ":" + nodeName); 730 } 731 732 733 739 private void addAttribute(String nodeName, String nodeValue) { 740 attributes.addAttribute("", nodeName, nodeName, "CDATA", nodeValue); 741 } 742 743 744 751 768 769 770 778 796 797 798 805 static class FolderXMLizer extends AbstractLogEnabled 806 implements XMLizable { 807 private Folder [] folders; 809 810 811 816 FolderXMLizer(Folder folder) { 817 this.folders = new Folder []{folder}; 818 } 819 820 821 826 FolderXMLizer(Folder [] folders) { 827 this.folders = folders; 828 } 829 830 831 837 public void toSAX(ContentHandler handler) throws SAXException { 838 MailContentHandlerDelegate mailContentHandlerDelegate = new MailContentHandlerDelegate(handler); 839 mailContentHandlerDelegate.enableLogging(getLogger()); 840 mailContentHandlerDelegate.startDocumentXMLizer(); 841 for (int i = 0; i < folders.length; i++) { 842 mailContentHandlerDelegate.marshalFolderToSAX(folders[i]); 843 } 844 mailContentHandlerDelegate.endDocumentXMLizer(); 845 } 846 } 847 848 849 856 static class MessageEnvelopeXMLizer extends AbstractLogEnabled 857 implements XMLizable { 858 private Message [] messages; 859 860 private SimpleDateFormat sdf; 861 862 863 868 public MessageEnvelopeXMLizer(Message message) { 869 this.messages = new Message [1]; 870 this.messages[0] = message; 871 } 872 873 874 879 public MessageEnvelopeXMLizer(Message [] messages) { 880 this.messages = messages; 881 } 882 883 884 889 public void setSimpleDateFormat(SimpleDateFormat sdf) { 890 this.sdf = sdf; 891 } 892 893 894 899 public void getSimpleDateFormat(SimpleDateFormat sdf) { 900 this.sdf = sdf; 901 } 902 903 904 910 public void toSAX(ContentHandler handler) throws SAXException { 911 MailContentHandlerDelegate mailContentHandlerDelegate = new MailContentHandlerDelegate(handler); 912 mailContentHandlerDelegate.enableLogging(getLogger()); 913 mailContentHandlerDelegate.setSimpleDateFormat(sdf); 914 mailContentHandlerDelegate.startDocumentXMLizer(); 915 916 for (int i = 0; i < messages.length; i++) { 917 mailContentHandlerDelegate.marshalMessageEnvelopeToSAX(messages[i]); 918 } 919 920 mailContentHandlerDelegate.endDocumentXMLizer(); 921 } 922 } 923 924 925 932 static class MessageXMLizer extends AbstractLogEnabled 933 implements XMLizable { 934 private Message message; 935 936 private SimpleDateFormat sdf; 937 938 939 944 public MessageXMLizer(Message message) { 945 this.message = message; 946 } 947 948 949 954 public void setSimpleDateFormat(SimpleDateFormat sdf) { 955 this.sdf = sdf; 956 } 957 958 959 964 public void getSimpleDateFormat(SimpleDateFormat sdf) { 965 this.sdf = sdf; 966 } 967 968 969 975 public void toSAX(ContentHandler handler) throws SAXException { 976 MailContentHandlerDelegate mailContentHandlerDelegate = new MailContentHandlerDelegate(handler); 977 mailContentHandlerDelegate.enableLogging(getLogger()); 978 mailContentHandlerDelegate.setSimpleDateFormat(sdf); 979 mailContentHandlerDelegate.startDocumentXMLizer(); 980 mailContentHandlerDelegate.marshalMessageToSAX(message); 981 mailContentHandlerDelegate.endDocumentXMLizer(); 982 } 983 } 984 } 985 986 | Popular Tags |