Coverage Report - org.apache.commons.mail.util.MimeMessageParser
 
Classes in this File Line Coverage Branch Coverage Complexity
MimeMessageParser
96%
73/76
77%
37/48
2.136
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.mail.util;
 18  
 
 19  
 import javax.activation.DataHandler;
 20  
 import javax.activation.DataSource;
 21  
 import javax.mail.Message;
 22  
 import javax.mail.MessagingException;
 23  
 import javax.mail.Multipart;
 24  
 import javax.mail.Part;
 25  
 import javax.mail.internet.InternetAddress;
 26  
 import javax.mail.internet.MimeBodyPart;
 27  
 import javax.mail.internet.MimeMessage;
 28  
 import javax.mail.internet.MimePart;
 29  
 import javax.mail.internet.MimeUtility;
 30  
 import javax.mail.util.ByteArrayDataSource;
 31  
 import java.io.BufferedInputStream;
 32  
 import java.io.BufferedOutputStream;
 33  
 import java.io.ByteArrayOutputStream;
 34  
 import java.io.IOException;
 35  
 import java.io.InputStream;
 36  
 import java.io.UnsupportedEncodingException;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Arrays;
 39  
 import java.util.List;
 40  
 
 41  
 /**
 42  
  * Parses a MimeMessage and stores the individual parts such a plain text,
 43  
  * HTML text and attachments.
 44  
  *
 45  
  * @since 1.3
 46  
  * @version $Id: MimeMessageParser.java 1420381 2012-12-11 20:18:05Z tn $
 47  
  */
 48  
 public class MimeMessageParser
 49  
 {
 50  
     /** The MimeMessage to convert */
 51  
     private final MimeMessage mimeMessage;
 52  
 
 53  
     /** Plain mail content from MimeMessage */
 54  
     private String plainContent;
 55  
 
 56  
     /** Html mail content from MimeMessage */
 57  
     private String htmlContent;
 58  
 
 59  
     /** List of attachments of MimeMessage */
 60  
     private final List<DataSource> attachmentList;
 61  
 
 62  
     /** Is this a Multipart email */
 63  
     private boolean isMultiPart;
 64  
 
 65  
     /**
 66  
      * Constructs an instance with the MimeMessage to be extracted.
 67  
      *
 68  
      * @param message the message to parse
 69  
      */
 70  
     public MimeMessageParser(final MimeMessage message)
 71  16
     {
 72  16
         attachmentList = new ArrayList<DataSource>();
 73  16
         this.mimeMessage = message;
 74  16
         this.isMultiPart = false;
 75  16
     }
 76  
 
 77  
     /**
 78  
      * Does the actual extraction.
 79  
      *
 80  
      * @return this instance
 81  
      * @throws Exception parsing the mime message failed
 82  
      */
 83  
     public MimeMessageParser parse() throws Exception
 84  
     {
 85  16
         this.parse(null, mimeMessage);
 86  16
         return this;
 87  
     }
 88  
 
 89  
     /**
 90  
      * @return the 'to' recipients of the message
 91  
      * @throws Exception determining the recipients failed
 92  
      */
 93  
     public List<javax.mail.Address> getTo() throws Exception
 94  
     {
 95  6
         javax.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.TO);
 96  6
         return recipients != null ? Arrays.asList(recipients) : new ArrayList<javax.mail.Address>();
 97  
     }
 98  
 
 99  
     /**
 100  
      * @return the 'cc' recipients of the message
 101  
      * @throws Exception determining the recipients failed
 102  
      */
 103  
     public List<javax.mail.Address> getCc() throws Exception
 104  
     {
 105  6
         javax.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.CC);
 106  6
         return recipients != null ? Arrays.asList(recipients) : new ArrayList<javax.mail.Address>();
 107  
     }
 108  
 
 109  
     /**
 110  
      * @return the 'bcc' recipients of the message
 111  
      * @throws Exception determining the recipients failed
 112  
      */
 113  
     public List<javax.mail.Address> getBcc() throws Exception
 114  
     {
 115  6
         javax.mail.Address[] recipients = this.mimeMessage.getRecipients(Message.RecipientType.BCC);
 116  6
         return recipients != null ? Arrays.asList(recipients) : new ArrayList<javax.mail.Address>();
 117  
     }
 118  
 
 119  
     /**
 120  
      * @return the 'from' field of the message
 121  
      * @throws Exception parsing the mime message failed
 122  
      */
 123  
     public String getFrom() throws Exception
 124  
     {
 125  5
         javax.mail.Address[] addresses = this.mimeMessage.getFrom();
 126  5
         if ((addresses == null) || (addresses.length == 0))
 127  
         {
 128  0
             return null;
 129  
         }
 130  
         else
 131  
         {
 132  5
             return ((InternetAddress) addresses[0]).getAddress();
 133  
         }
 134  
     }
 135  
 
 136  
     /**
 137  
      * @return the 'replyTo' address of the email
 138  
      * @throws Exception parsing the mime message failed
 139  
      */
 140  
     public String getReplyTo() throws Exception
 141  
     {
 142  5
         javax.mail.Address[] addresses = this.mimeMessage.getReplyTo();
 143  5
         if ((addresses == null) || (addresses.length == 0))
 144  
         {
 145  0
             return null;
 146  
         }
 147  
         else
 148  
         {
 149  5
             return ((InternetAddress) addresses[0]).getAddress();
 150  
         }
 151  
     }
 152  
 
 153  
     /**
 154  
      * @return the mail subject
 155  
      * @throws Exception parsing the mime message failed
 156  
      */
 157  
     public String getSubject() throws Exception
 158  
     {
 159  6
         return this.mimeMessage.getSubject();
 160  
     }
 161  
 
 162  
     /**
 163  
      * Extracts the content of a MimeMessage recursively.
 164  
      *
 165  
      * @param parent the parent multi-part
 166  
      * @param part   the current MimePart
 167  
      * @throws MessagingException parsing the MimeMessage failed
 168  
      * @throws IOException        parsing the MimeMessage failed
 169  
      */
 170  
     protected void parse(Multipart parent, MimePart part)
 171  
         throws MessagingException, IOException
 172  
     {
 173  67
         if (part.isMimeType("text/plain") && (plainContent == null))
 174  
         {
 175  7
             plainContent = (String) part.getContent();
 176  
         }
 177  
         else
 178  
         {
 179  60
             if (part.isMimeType("text/html") && (htmlContent == null))
 180  
             {
 181  12
                 htmlContent = (String) part.getContent();
 182  
             }
 183  
             else
 184  
             {
 185  48
                 if (part.isMimeType("multipart/*"))
 186  
                 {
 187  30
                     this.isMultiPart = true;
 188  30
                     Multipart mp = (Multipart) part.getContent();
 189  30
                     int count = mp.getCount();
 190  
 
 191  
                     // iterate over all MimeBodyPart
 192  
 
 193  81
                     for (int i = 0; i < count; i++)
 194  
                     {
 195  51
                         parse(mp, (MimeBodyPart) mp.getBodyPart(i));
 196  
                     }
 197  30
                 }
 198  
                 else
 199  
                 {
 200  18
                     this.attachmentList.add(createDataSource(parent, part));
 201  
                 }
 202  
             }
 203  
         }
 204  67
     }
 205  
 
 206  
     /**
 207  
      * Parses the MimePart to create a DataSource.
 208  
      *
 209  
      * @param parent the parent multi-part
 210  
      * @param part   the current part to be processed
 211  
      * @return the DataSource
 212  
      * @throws MessagingException creating the DataSource failed
 213  
      * @throws IOException        creating the DataSource failed
 214  
      */
 215  
     protected DataSource createDataSource(Multipart parent, MimePart part)
 216  
         throws MessagingException, IOException
 217  
     {
 218  18
         DataHandler dataHandler = part.getDataHandler();
 219  18
         DataSource dataSource = dataHandler.getDataSource();
 220  18
         String contentType = getBaseMimeType(dataSource.getContentType());
 221  18
         byte[] content = this.getContent(dataSource.getInputStream());
 222  18
         ByteArrayDataSource result = new ByteArrayDataSource(content, contentType);
 223  18
         String dataSourceName = getDataSourceName(part, dataSource);
 224  
 
 225  18
         result.setName(dataSourceName);
 226  18
         return result;
 227  
     }
 228  
 
 229  
     /** @return Returns the mimeMessage. */
 230  
     public MimeMessage getMimeMessage()
 231  
     {
 232  6
         return mimeMessage;
 233  
     }
 234  
 
 235  
     /** @return Returns the isMultiPart. */
 236  
     public boolean isMultipart()
 237  
     {
 238  6
         return isMultiPart;
 239  
     }
 240  
 
 241  
     /** @return Returns the plainContent if any */
 242  
     public String getPlainContent()
 243  
     {
 244  6
         return plainContent;
 245  
     }
 246  
 
 247  
     /** @return Returns the attachmentList. */
 248  
     public List<DataSource> getAttachmentList()
 249  
     {
 250  21
         return attachmentList;
 251  
     }
 252  
 
 253  
     /** @return Returns the htmlContent if any */
 254  
     public String getHtmlContent()
 255  
     {
 256  10
         return htmlContent;
 257  
     }
 258  
 
 259  
     /** @return true if a plain content is available */
 260  
     public boolean hasPlainContent()
 261  
     {
 262  6
         return this.plainContent != null;
 263  
     }
 264  
 
 265  
     /** @return true if HTML content is available */
 266  
     public boolean hasHtmlContent()
 267  
     {
 268  6
         return this.htmlContent != null;
 269  
     }
 270  
 
 271  
     /** @return true if attachments are available */
 272  
     public boolean hasAttachments()
 273  
     {
 274  5
         return this.attachmentList.size() > 0;
 275  
     }
 276  
 
 277  
     /**
 278  
      * Find an attachment using its name.
 279  
      *
 280  
      * @param name the name of the attachment
 281  
      * @return the corresponding datasource or null if nothing was found
 282  
      */
 283  
     public DataSource findAttachmentByName(String name)
 284  
     {
 285  
         DataSource dataSource;
 286  
 
 287  4
         for (int i = 0; i < getAttachmentList().size(); i++)
 288  
         {
 289  4
             dataSource = getAttachmentList().get(i);
 290  4
             if (name.equalsIgnoreCase(dataSource.getName()))
 291  
             {
 292  3
                 return dataSource;
 293  
             }
 294  
         }
 295  
 
 296  0
         return null;
 297  
     }
 298  
 
 299  
     /**
 300  
      * Determines the name of the data source if it is not already set.
 301  
      *
 302  
      * @param part the mail part
 303  
      * @param dataSource the data source
 304  
      * @return the name of the data source or {@code null} if no name can be determined
 305  
      * @throws MessagingException accessing the part failed
 306  
      * @throws UnsupportedEncodingException decoding the text failed
 307  
      */
 308  
     protected String getDataSourceName(Part part, DataSource dataSource)
 309  
         throws MessagingException, UnsupportedEncodingException
 310  
     {
 311  18
         String result = dataSource.getName();
 312  
 
 313  18
         if (result == null || result.length() == 0)
 314  
         {
 315  2
             result = part.getFileName();
 316  
         }
 317  
 
 318  18
         if (result != null && result.length() > 0)
 319  
         {
 320  17
             result = MimeUtility.decodeText(result);
 321  
         }
 322  
         else
 323  
         {
 324  1
             result = null;
 325  
         }
 326  
 
 327  18
         return result;
 328  
     }
 329  
 
 330  
     /**
 331  
      * Read the content of the input stream.
 332  
      *
 333  
      * @param is the input stream to process
 334  
      * @return the content of the input stream
 335  
      * @throws IOException reading the input stream failed
 336  
      */
 337  
     private byte[] getContent(InputStream is)
 338  
         throws IOException
 339  
     {
 340  
         int ch;
 341  
         byte[] result;
 342  
 
 343  18
         ByteArrayOutputStream os = new ByteArrayOutputStream();
 344  18
         BufferedInputStream isReader = new BufferedInputStream(is);
 345  18
         BufferedOutputStream osWriter = new BufferedOutputStream(os);
 346  
 
 347  192740
         while ((ch = isReader.read()) != -1)
 348  
         {
 349  192722
             osWriter.write(ch);
 350  
         }
 351  
 
 352  18
         osWriter.flush();
 353  18
         result = os.toByteArray();
 354  18
         osWriter.close();
 355  
 
 356  18
         return result;
 357  
     }
 358  
 
 359  
     /**
 360  
      * Parses the mimeType.
 361  
      *
 362  
      * @param fullMimeType the mime type from the mail api
 363  
      * @return the real mime type
 364  
      */
 365  
     private String getBaseMimeType(String fullMimeType)
 366  
     {
 367  18
         int pos = fullMimeType.indexOf(';');
 368  18
         if (pos >= 0)
 369  
         {
 370  11
             return fullMimeType.substring(0, pos);
 371  
         }
 372  
         else
 373  
         {
 374  7
             return fullMimeType;
 375  
         }
 376  
     }
 377  
 }