View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  
22  package org.apache.james.transport.mailets;
23  
24  import org.apache.mailet.base.GenericMailet;
25  import org.apache.mailet.Mail;
26  import org.apache.mailet.base.RFC2822Headers;
27  
28  import javax.mail.MessagingException;
29  import javax.mail.internet.MimeBodyPart;
30  import javax.mail.internet.MimeMessage;
31  import javax.mail.internet.MimeMultipart;
32  import javax.mail.internet.MimePart;
33  
34  import java.io.IOException;
35  import java.io.UnsupportedEncodingException;
36  
37  /**
38   * An abstract implementation of a mailet that add a Footer to an email
39   */
40  public abstract class AbstractAddFooter extends GenericMailet {
41  
42      /**
43       * Takes the message and attaches a footer message to it.  Right now, it only
44       * supports simple messages.  Needs to have additions to make it support
45       * messages with alternate content types or with attachments.
46       *
47       * @param mail the mail being processed
48       *
49       * @throws MessagingException if an error arises during message processing
50       */
51      public void service(Mail mail) throws MessagingException {
52          try {
53              MimeMessage message = mail.getMessage();
54  
55              if (attachFooter(message)) {
56                  message.saveChanges();
57              } else {
58                  log("Unable to add footer to mail " + mail.getName());
59              }
60          } catch (UnsupportedEncodingException e) {
61              log("UnsupportedEncoding Unable to add footer to mail "
62                      + mail.getName());
63          } catch (IOException ioe) {
64              throw new MessagingException("Could not read message", ioe);
65          }
66      }
67  
68      /**
69       * Prepends the content of the MimePart as text to the existing footer
70       *
71       * @param part the MimePart to attach
72       *
73       * @throws MessagingException
74       * @throws IOException
75       */
76      protected void addToText(MimePart part) throws MessagingException,
77              IOException {
78          //        log("Trying to add footer to " + part.getContent().toString());
79          String contentType = part.getContentType();
80          String content = (String) part.getContent();
81  
82          if (!content.endsWith("\n")) {
83              content += "\r\n";
84          }
85          content += getFooterText();
86  
87          part.setContent(content, contentType);
88          part.setHeader(RFC2822Headers.CONTENT_TYPE, contentType);
89          //        log("After adding footer: " + part.getContent().toString());
90      }
91  
92      /**
93       * Prepends the content of the MimePart as HTML to the existing footer
94       *
95       * @param part the MimePart to attach
96       *
97       * @throws MessagingException
98       * @throws IOException
99       */
100     protected void addToHTML(MimePart part) throws MessagingException,
101             IOException {
102         //        log("Trying to add footer to " + part.getContent().toString());
103         String contentType = part.getContentType();
104         String content = (String) part.getContent();
105 
106         /* This HTML part may have a closing <BODY> tag.  If so, we
107          * want to insert out footer immediately prior to that tag.
108          */
109         int index = content.lastIndexOf("</body>");
110         if (index == -1)
111             index = content.lastIndexOf("</BODY>");
112         String insert = "<br>" + getFooterHTML();
113         content = index == -1 ? content + insert : content.substring(0, index)
114                 + insert + content.substring(index);
115 
116         part.setContent(content, contentType);
117         part.setHeader(RFC2822Headers.CONTENT_TYPE, contentType);
118         //        log("After adding footer: " + part.getContent().toString());
119     }
120 
121     /**
122      * Attach a footer a MimePart
123      *
124      * @param part the MimePart to which the footer is to be attached
125      *
126      * @return whether a footer was successfully attached
127      * @throws MessagingException
128      * @throws IOException
129      */
130     protected boolean attachFooter(MimePart part) throws MessagingException,
131             IOException {
132         //        log("Content type is " + part.getContentType());
133         if (part.isMimeType("text/plain")
134                 && part.getContent() instanceof String) {
135             addToText(part);
136             return true;
137         } else if (part.isMimeType("text/html")
138                 && part.getContent() instanceof String) {
139             addToHTML(part);
140             return true;
141         } else if (part.isMimeType("multipart/mixed")
142                 || part.isMimeType("multipart/related")) {
143             //Find the first body part, and determine what to do then.
144             MimeMultipart multipart = (MimeMultipart) part.getContent();
145             MimeBodyPart firstPart = (MimeBodyPart) multipart.getBodyPart(0);
146             boolean isFooterAttached = attachFooter(firstPart);
147             if (isFooterAttached) {
148                 //We have to do this because of a bug in JavaMail (ref id 4403733)
149                 //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4403733
150                 part.setContent(multipart);
151             }
152             return isFooterAttached;
153         } else if (part.isMimeType("multipart/alternative")) {
154             MimeMultipart multipart = (MimeMultipart) part.getContent();
155             int count = multipart.getCount();
156             //            log("number of alternatives = " + count);
157             boolean isFooterAttached = false;
158             for (int index = 0; index < count; index++) {
159                 //                log("processing alternative #" + index);
160                 MimeBodyPart mimeBodyPart = (MimeBodyPart) multipart
161                         .getBodyPart(index);
162                 isFooterAttached |= attachFooter(mimeBodyPart);
163             }
164             if (isFooterAttached) {
165                 //We have to do this because of a bug in JavaMail (ref id 4403733)
166                 //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4403733
167                 part.setContent(multipart);
168             }
169             return isFooterAttached;
170         } else {
171             //Give up... we won't attach the footer to this MimePart
172             return false;
173         }
174     }
175 
176     /**
177      * This is exposed as a method for easy subclassing to provide alternate ways
178      * to get the footer text.
179      *
180      * @return the footer text
181      */
182     protected abstract String getFooterText();
183 
184     /**
185      * This is exposed as a method for easy subclassing to provide alternate ways
186      * to get the footer text.  By default, this will take the footer text,
187      * converting the linefeeds to &lt;br&gt; tags.
188      *
189      * @return the HTML version of the footer text
190      */
191     protected abstract String getFooterHTML();
192 
193 }