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