Package org.xmlBlaster.util.protocol.email

Source Code of org.xmlBlaster.util.protocol.email.MailUtil

/*------------------------------------------------------------------------------
Name:      MailUtil.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
Copyright: Parts learned from javamail-demo:
1996-2003 Sun Microsystems, Inc. All Rights Reserved.
Comment:   Converter used to convert native data to protocol-specific data.
------------------------------------------------------------------------------*/
package org.xmlBlaster.util.protocol.email;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import java.util.logging.Logger;

import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.event.StoreEvent;
import javax.mail.event.StoreListener;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MailDateFormat;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.ParseException;

import org.xmlBlaster.util.Base64;
import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.def.Constants;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.util.xbformat.ByteArray;

/**
* Utilities to dump mail messages. We provide a main() to play with POP3
* access. Show information about and contents of messages.
*
* @author John Mani
* @author Bill Shannon
* @author Marcel Ruff
*/
public class MailUtil {

   private static Logger log = Logger.getLogger(MailUtil.class.getName());

   static String url = null;

   static boolean verbose = false;

   static boolean debug = false;

   static boolean showStructure = false;

   static boolean showAlert = false;

   static boolean saveAttachments = false;

   static int attnum = 1;
  
   /**
    * Fixed name which is used for the normal email content / body
    */
   static public final String BODY_NAME = "body.xml";

   /**
    * Reading POP3 messages and dump them (for testing only). Usage:<br/>
    * <pre>
    *java org.xmlBlaster.util.protocol.email.MailUtil -L pop3://marcel:marcel@localhost/INBOX
    * </pre>
    * @param argv
    */
   public static void main(String argv[]) {
      for (int i = 0; i < argv.length; i++) {
         if (argv[i].equals("-v")) {
            verbose = true;
         } else if (argv[i].equals("-D")) {
            debug = true;
         } else if (argv[i].equals("-L")) {
            url = argv[++i];
         } else if (argv[i].equals("-s")) {
            showStructure = true;
         } else if (argv[i].equals("-S")) {
            saveAttachments = true;
         } else if (argv[i].equals("-a")) {
            showAlert = true;
         } else if (argv[i].equals("--")) {
            i++;
            break;
         } else if (argv[i].startsWith("-")) {
            System.out
                  .println("Usage:   java org.xmlBlaster.util.protocol.MailUtil [-L url]");
            System.out
                  .println("Example: java org.xmlBlaster.util.protocol.MailUtil -L pop3://marcel:marcel@localhost/INBOX");
            System.exit(1);
         } else {
            break;
         }
      }
      testPOP3Read();

   }
  
   /**
    * Transforms an email "date-time" string to a java.util.Date.
    * <pre>
     date-time   =  [ day "," ] date time        ; dd mm yy
                                                 ;  hh:mm:ss zzz

     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
                 /  "Fri"  / "Sat" /  "Sun"

     date        =  1*2DIGIT month 2DIGIT        ; day month year
                                                 ;  e.g. 20 Jun 82

     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
                 /  "May"  /  "Jun" /  "Jul"  /  "Aug"
                 /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"

     time        =  hour zone                    ; ANSI and Military

     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
                                                 ; 00:00:00 - 23:59:59

     zone        =  "UT"  / "GMT"                ; Universal Time
                                                 ; North American : UT
                 /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
                 /  "CST" / "CDT"                ;  Central:  - 6/ - 5
                 /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
                 /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
                 /  1ALPHA                       ; Military: Z = UT;
                                                 ;  A:-1; (J not used)
                                                 ;  M:-12; N:+1; Y:+12
                 / ( ("+" / "-") 4DIGIT )        ; Local differential
                                                 ;  hours+min. (HHMM)
    * </pre>
    * @param dateString The http://www.faqs.org/rfcs/rfc822.html "date-time" string
    * @return the date parsed
    * @see http://www.faqs.org/rfcs/rfc2156.html
    * @throws IllegalArgumentException on ParseException
    */
   public static Date dateTime(String dateString) {
      DateFormat df = new MailDateFormat();
      try {
         return df.parse(dateString);
      } catch (java.text.ParseException e) {
         throw new IllegalArgumentException("Can't parse date-time string '" + dateString + "', please check email RFC 822: " + e.toString());
      }    
   }

   /**
    * @param dateString The http://www.faqs.org/rfcs/rfc822.html "date-time" string
    * @return the timestamp parsed
    * @throws IllegalArgumentException on ParseException
    */
   public static java.sql.Timestamp dateTimeTS(String dateString) {
      Date date = dateTime(dateString);
      return new Timestamp(date.getTime());
   }
  
   /**
    * @param date
    * @return The http://www.faqs.org/rfcs/rfc822.html "date-time" string
    */
   public static String dateTime(Date date) {
      DateFormat df = new MailDateFormat();
      return df.format(date);    
   }
  
   /**
    * @param ts
    * @return The http://www.faqs.org/rfcs/rfc822.html "date-time" string
    * @see org.xmlBlaster.util.IsoDateParser
    */
   public static String dateTime(java.sql.Timestamp ts) {
      Date date = new Date(ts.getTime());
      return dateTime(date);
   }
  
   private static void testPOP3Read() {
      try {
         final String mbox = "INBOX";
         // Get a Properties object
         Properties props = System.getProperties();

         // Get a Session object
         Session session = Session.getInstance(props, null);
         session.setDebug(debug);

         // Get a Store object
         Store store = null;
         if (url != null) {
            URLName urln = new URLName(url);
            store = session.getStore(urln);
            if (showAlert) {
               store.addStoreListener(new StoreListener() {
                  public void notification(StoreEvent e) {
                     String s;
                     if (e.getMessageType() == StoreEvent.ALERT)
                        s = "ALERT: ";
                     else
                        s = "NOTICE: ";
                     System.out.println(s + e.getMessage());
                  }
               });
            }
            store.connect();
         }

         Folder folder = store.getDefaultFolder();
         if (folder == null) {
            System.out.println("No default folder");
            System.exit(1);
         }

         folder = folder.getFolder(mbox);
         if (folder == null) {
            System.out.println("Invalid folder");
            System.exit(1);
         }

         // try to open read/write and if that fails try read-only
         try {
            folder.open(Folder.READ_WRITE);
         } catch (MessagingException ex) {
            folder.open(Folder.READ_ONLY);
         }
         int totalMessages = folder.getMessageCount();

         if (totalMessages == 0) {
            System.out.println("Empty folder");
            folder.close(false);
            store.close();
            System.exit(1);
         }

         if (verbose) {
            int newMessages = folder.getNewMessageCount();
            System.out.println("Total messages = " + totalMessages);
            System.out.println("New messages = " + newMessages);
            System.out.println("===============================");
         }

         // Attributes & Flags for all messages ..
         Message[] msgs = folder.getMessages();

         // Use a suitable FetchProfile
         FetchProfile fp = new FetchProfile();
         fp.add(FetchProfile.Item.ENVELOPE);
         fp.add(FetchProfile.Item.FLAGS);
         fp.add("X-Mailer");
         folder.fetch(msgs, fp);

         for (int i = 0; i < msgs.length; i++) {
            int level = 0;
            System.out.println("\n=========MESSAGE #" + (i + 1) + ":=================");
            dumpEnvelope(msgs[i], level);
            level = dumpPart(msgs[i], level);
         }

         folder.close(false);
         store.close();
      } catch (Exception ex) {
         System.out.println("Oops, got exception! " + ex.getMessage());
         ex.printStackTrace();
         System.exit(1);
      }
      System.exit(0);
   }

   public static void dumpMessage(Message msg) throws Exception {
      int level = 0;
      dumpEnvelope(msg, level);
      level = dumpPart(msg, level);
   }
  
   public static void dumpMessages(Message[] msgs) throws Exception {
      for (int i = 0; i < msgs.length; i++) {
         int level = 0;
         System.out.println("\n=========MESSAGE #" + (i + 1) + ":=================");
         dumpEnvelope(msgs[i], level);
         level = dumpPart(msgs[i], level);
      }
   }
  
   /**
    * Access all attachments.
    * @param p
    * @return a list of AttachmentHolder instances
    * @throws Exception
    */
   public static ArrayList accessAttachments(Part p) throws XmlBlasterException {
      ArrayList attachments = new ArrayList();
      int level = 0;
      accessPart(p, level, attachments);
      return attachments;
   }

   public static int accessPart(Part p, int level, ArrayList attachments) throws XmlBlasterException {
      if (level > 0 && p instanceof Message) {
         log.warning("Unexpected Message type in level " + level);
         return level;
      }

      try {
         String ct = p.getContentType();
         String fileName = p.getFileName();
         if (fileName == null) fileName = BODY_NAME;
  
         /*
          * Using isMimeType to determine the content type avoids fetching the
          * actual content data until we need it.
          */
         if (p.isMimeType("text/plain")) { // All "UTF-8"
            AttachmentHolder a = null;
            if (p instanceof MimeBodyPart && Constants.EMAIL_TRANSFER_ENCODING.equals(((MimeBodyPart)p).getEncoding())) {
               byte[] content = Base64.decode((String)p.getContent());
               a = new AttachmentHolder(fileName, ct, content);
            }
            else {
               a = new AttachmentHolder(fileName, ct, ((String)p.getContent()).getBytes(Constants.UTF8_ENCODING));
            }
            attachments.add(a);
         } else if (p.isMimeType("multipart/*")) { // Go one level deeper ...
            Multipart mp = (Multipart) p.getContent();
            level++;
            int count = mp.getCount();
            for (int i = 0; i < count; i++)
               level = accessPart(mp.getBodyPart(i), level, attachments);
            level--;
         } else if (p.isMimeType("message/rfc822")) {
            level++;
            level = accessPart((Part) p.getContent(), level, attachments);
            level--;
         } else {
               byte[] content;
               Object o = p.getContent();
               if (o instanceof String) {
                  content = ((String)o).getBytes(Constants.UTF8_ENCODING);
               } else if (o instanceof InputStream) {
                  InputStream is = (InputStream) o;
                  ByteArray ba = new ByteArray(p.getSize() > 0 ? p.getSize() : 1024, is);
                  content = ba.toByteArray();
               } else {
                  content = (o.toString()).getBytes(Constants.UTF8_ENCODING);
               }
              
               if (p instanceof MimeBodyPart && Constants.EMAIL_TRANSFER_ENCODING.equals(((MimeBodyPart)p).getEncoding())) {
                  content = Base64.decode((String)p.getContent());
               }
               AttachmentHolder a = new AttachmentHolder(fileName, ct, content);
               attachments.add(a);
         }
      }catch (Exception e) {
         throw new XmlBlasterException(Global.instance(), ErrorCode.RESOURCE_CONFIGURATION, MailUtil.class.getName(), "Can't access email attachments", e);
      }
      return level;
   }
  
   public static int dumpPart(Part p, int level) throws Exception {
      if (level > 0 && p instanceof Message)
         dumpEnvelope((Message) p, level);

      String ct = p.getContentType();
      try {
         pr("CONTENT-TYPE: " + (new ContentType(ct)).toString(), level);
      } catch (ParseException pex) {
         pr("BAD CONTENT-TYPE: " + ct, level);
      }
      String filename = p.getFileName();
      if (filename != null)
         pr("FILENAME: " + filename, level);

      /*
       * Using isMimeType to determine the content type avoids fetching the
       * actual content data until we need it.
       */
      if (p.isMimeType("text/plain")) {
         pr("", level);
         pr("=========This is plain text, level="+level+"===========", level);
         if (!showStructure && !saveAttachments)
            System.out.println((String) p.getContent());
      } else if (p.isMimeType("multipart/*")) {
         pr("=========This is a Multipart " + level + "==================", level);
         Multipart mp = (Multipart) p.getContent();
         level++;
         int count = mp.getCount();
         for (int i = 0; i < count; i++)
            level = dumpPart(mp.getBodyPart(i), level);
         level--;
      } else if (p.isMimeType("message/rfc822")) {
         pr("This is a Nested Message", level);
         pr("===========================", level);
         level++;
         level = dumpPart((Part) p.getContent(), level);
         level--;
      } else {
         if (!showStructure && !saveAttachments) {
            /*
             * If we actually want to see the data, and it's not a MIME type we
             * know, fetch it and check its Java type.
             */
            Object o = p.getContent();
            if (o instanceof String) {
               pr("===============This is a string, level="+level+"============", level);
               System.out.println((String) o);
            } else if (o instanceof InputStream) {
               pr("========This is a binary input stream, level="+level+"======", level);
               InputStream is = (InputStream) o;
               int c;
               System.out.print('[');
               while ((c = is.read()) != -1) {
                  if (c == 0)
                     System.out.print('*');
                  else
                     System.out.write(c);
               }
               System.out.print(']');
            } else {
               pr("================This is an unknown type, level="+level+"===========", level);
               pr(o.toString(), level);
            }
         } else {
            // just a separator
            pr("********************************", level);
         }
      }

      /*
       * If we're saving attachments, write out anything that looks like an
       * attachment into an appropriately named file. Don't overwrite existing
       * files to prevent mistakes.
       */
      if (saveAttachments && level != 0 && !p.isMimeType("multipart/*")) {
         String disp = p.getDisposition();
         // many mailers don't include a Content-Disposition
         if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT)) {
            if (filename == null)
               filename = "Attachment" + attnum++;
            pr("Saving attachment to file " + filename, level);
            try {
               File f = new File(filename);
               if (f.exists())
                  // XXX - could try a series of names
                  throw new IOException("file exists");
               OutputStream os = new BufferedOutputStream(new FileOutputStream(
                     f));
               InputStream is = p.getInputStream();
               int c;
               while ((c = is.read()) != -1)
                  os.write(c);
               os.close();
            } catch (IOException ex) {
               pr("Failed to save attachment: " + ex, level);
            }
            pr("---------------------------", level);
         }
      }
      return level;
   }

   public static void dumpEnvelope(Message m, int level) throws Exception {
      pr("------ This is the message envelope START ------", level);
      Address[] a;
      // FROM
      if ((a = m.getFrom()) != null) {
         for (int j = 0; j < a.length; j++)
            pr("FROM: " + a[j].toString(), level);
      }

      // TO
      if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
         for (int j = 0; j < a.length; j++) {
            pr("TO: " + a[j].toString(), level);
            InternetAddress ia = (InternetAddress) a[j];
            if (ia.isGroup()) {
               InternetAddress[] aa = ia.getGroup(false);
               for (int k = 0; k < aa.length; k++)
                  pr("  GROUP: " + aa[k].toString(), level);
            }
         }
      }

      // SUBJECT
      pr("SUBJECT: " + m.getSubject(), level);

      // DATE
      Date d = m.getSentDate();
      pr("SendDate: " + (d != null ? d.toString() : "UNKNOWN"), level);

      // FLAGS (not supported by POP3)
      Flags flags = m.getFlags();
      StringBuffer sb = new StringBuffer();
      Flags.Flag[] sf = flags.getSystemFlags(); // get the system flags

      boolean first = true;
      for (int i = 0; i < sf.length; i++) {
         String s;
         Flags.Flag f = sf[i];
         if (f == Flags.Flag.ANSWERED)
            s = "\\Answered";
         else if (f == Flags.Flag.DELETED)
            s = "\\Deleted";
         else if (f == Flags.Flag.DRAFT)
            s = "\\Draft";
         else if (f == Flags.Flag.FLAGGED)
            s = "\\Flagged";
         else if (f == Flags.Flag.RECENT)
            s = "\\Recent";
         else if (f == Flags.Flag.SEEN)
            s = "\\Seen";
         else
            continue; // skip it
         if (first)
            first = false;
         else
            sb.append(' ');
         sb.append(s);
      }

      String[] uf = flags.getUserFlags(); // get the user flag strings
      for (int i = 0; i < uf.length; i++) {
         if (first)
            first = false;
         else
            sb.append(' ');
         sb.append(uf[i]);
      }
      pr("FLAGS: " + sb.toString(), level);

      pr("HEADERS", level);
      Enumeration e = m.getAllHeaders();
      while (e.hasMoreElements()) {
         javax.mail.Header head = (javax.mail.Header) e.nextElement();
         pr(head.getName() + ": " + head.getValue(), level);
      }
      pr("------ This is the message envelope END ------", level);
   }

   static String indentStr = "                                               ";

   /**
    * Print a, possibly indented, string.
    */
   public static void pr(String s, int level) {
      if (showStructure)
         System.out.print(indentStr.substring(0, level * 2));
      System.out.println(s);
   }
}

/* Without attachment:
*
------ This is the message envelope START ------
FROM: Marcel Ruff <marcel@localhost>
TO: marcel@localhost
SUBJECT: Subject, without attachment
SendDate: Thu Oct 27 17:00:10 CEST 2005
FLAGS:
HEADERS
Return-Path: <marcel@localhost>
Received: from localhost ([127.0.0.1])
          by noty (JAMES SMTP Server 2.2.0) with SMTP ID 204
          for <marcel@localhost>;
          Thu, 27 Oct 2005 17:00:11 +0200 (CEST)
Message-ID: <4360EB7A.5060401@localhost>
Date: Thu, 27 Oct 2005 17:00:10 +0200
From: Marcel Ruff <marcel@localhost>
User-Agent: Mozilla Thunderbird 1.0.6 (X11/20050716)
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: marcel@localhost
Subject: Subject, without attachment
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Delivered-To: marcel@localhost
------ This is the message envelope END ------
CONTENT-TYPE: text/plain; format=flowed; charset=ISO-8859-1

=========This is plain text, level=0===========
Some body text!
*/

/*
* Example with a zip attachment:
=========MESSAGE #1:=================
------ This is the message envelope START ------
FROM: Marcel Ruff <marcel@localhost>
TO: marcel@localhost
SUBJECT: Subject with binary attachment
SendDate: Thu Oct 27 16:51:00 CEST 2005
FLAGS:
HEADERS
Return-Path: <marcel@localhost>
Received: from localhost ([127.0.0.1])
          by noty (JAMES SMTP Server 2.2.0) with SMTP ID 137
          for <marcel@localhost>;
          Thu, 27 Oct 2005 16:51:00 +0200 (CEST)
Message-ID: <4360E954.4060409@localhost>
Date: Thu, 27 Oct 2005 16:51:00 +0200
From: Marcel Ruff <marcel@localhost>
User-Agent: Mozilla Thunderbird 1.0.6 (X11/20050716)
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: marcel@localhost
Subject: Subject with binary attachment
Content-Type: multipart/mixed;
boundary="------------050806000406010507060909"
Delivered-To: marcel@localhost
------ This is the message envelope END ------
CONTENT-TYPE: multipart/mixed; boundary=------------050806000406010507060909
=========This is a Multipart 0==================
CONTENT-TYPE: text/plain; format=flowed; charset=ISO-8859-1

=========This is plain text, level=1===========
This is the normal body text!


CONTENT-TYPE: application/zip; name=something.zip
FILENAME: something.zip
========This is a binary input stream, level=1======
PK
j[3�

   sometextUT   �C�CUxfHello World
PK
*/


/* Example with one text attachment
*
------ This is the message envelope START ------
FROM: Marcel Ruff <marcel@localhost>
TO: marcel@localhost
SUBJECT: Subject with text attachment
SendDate: Thu Oct 27 16:59:36 CEST 2005
FLAGS:
HEADERS
Return-Path: <marcel@localhost>
Received: from localhost ([127.0.0.1])
          by noty (JAMES SMTP Server 2.2.0) with SMTP ID 687
          for <marcel@localhost>;
          Thu, 27 Oct 2005 16:59:36 +0200 (CEST)
Message-ID: <4360EB58.7060205@localhost>
Date: Thu, 27 Oct 2005 16:59:36 +0200
From: Marcel Ruff <marcel@localhost>
User-Agent: Mozilla Thunderbird 1.0.6 (X11/20050716)
X-Accept-Language: en-us, en
MIME-Version: 1.0
To: marcel@localhost
Subject: Subject with text attachment
Content-Type: multipart/mixed;
boundary="------------060303010309020708030505"
Delivered-To: marcel@localhost
------ This is the message envelope END ------
CONTENT-TYPE: multipart/mixed; boundary=------------060303010309020708030505
=========This is a Multipart 0==================
CONTENT-TYPE: text/plain; format=flowed; charset=ISO-8859-1

=========This is plain text, level=1===========
Some body text!


CONTENT-TYPE: application/unknown; name=sometext.txt
FILENAME: sometext.txt
========This is a binary input stream, level=1======
Hello World


*/
TOP

Related Classes of org.xmlBlaster.util.protocol.email.MailUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.