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 <br> tags.
188 *
189 * @return the HTML version of the footer text
190 */
191 protected abstract String getFooterHTML();
192
193 }