1 /************************************************************************
2 * Copyright (c) 2000-2006 The Apache Software Foundation. *
3 * All rights reserved. *
4 * ------------------------------------------------------------------- *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
6 * may not use this file except in compliance with the License. You *
7 * 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 *
14 * implied. See the License for the specific language governing *
15 * permissions and limitations under the License. *
16 ***********************************************************************/
17
18 package org.apache.james.transport.mailets;
19
20 import org.apache.mailet.RFC2822Headers;
21 import org.apache.mailet.Mail;
22 import org.apache.mailet.MailAddress;
23
24 import javax.mail.MessagingException;
25 import javax.mail.internet.InternetAddress;
26 import javax.mail.internet.MimeMessage;
27 import java.io.PrintWriter;
28 import java.io.StringWriter;
29 import java.util.Collection;
30 import java.util.Iterator;
31
32 /***
33 * <P>Abstract mailet providing configurable notification services.<BR>
34 * This mailet can be subclassed to make authoring notification mailets simple.<BR>
35 * <P>Provides the following functionalities to all notification subclasses:</P>
36 * <UL>
37 * <LI>A common notification message layout.</LI>
38 * <LI>A sender of the notification message can optionally be specified.
39 * If one is not specified, the postmaster's address will be used.</LI>
40 * <LI>A notice text can be specified, and in such case will be inserted into the
41 * notification inline text.</LI>
42 * <LI>If the notified message has an "error message" set, it will be inserted into the
43 * notification inline text. If the <CODE>attachStackTrace</CODE> init parameter
44 * is set to true, such error message will be attached to the notification message.</LI>
45 * <LI>The notified messages are attached in their entirety (headers and
46 * content) and the resulting MIME part type is "message/rfc822".</LI>
47 * <LI>Supports by default the <CODE>passThrough</CODE> init parameter (true if missing).</LI>
48 * </UL>
49 *
50 * <P>Sample configuration common to all notification mailet subclasses:</P>
51 * <PRE><CODE>
52 * <mailet match="All" class="<I>a notification mailet</I>">
53 * <sender><I>an address or postmaster or sender or unaltered, default=postmaster</I></sender>
54 * <attachError><I>true or false, default=false</I></attachError>
55 * <message><I>notice attached to the original message text (optional)</I></message>
56 * <prefix><I>optional subject prefix prepended to the original message</I></prefix>
57 * <inline><I>see {@link Redirect}, default=none</I></inline>
58 * <attachment><I>see {@link Redirect}, default=message</I></attachment>
59 * <passThrough><I>true or false, default=true</I></passThrough>
60 * <fakeDomainCheck><I>true or false, default=true</I></fakeDomainCheck>
61 * <debug><I>true or false, default=false</I></debug>
62 * </mailet>
63 * </CODE></PRE>
64 * <P><I>notice</I> and <I>senderAddress</I> can be used instead of
65 * <I>message</I> and <I>sender</I>; such names are kept for backward compatibility.</P>
66 *
67 * @version CVS $Revision: 382444 $ $Date: 2006-03-02 16:56:32 +0000 (gio, 02 mar 2006) $
68 * @since 2.2.0
69 */
70 public abstract class AbstractNotify extends AbstractRedirect {
71
72
73
74
75
76 /***
77 * @return the <CODE>passThrough</CODE> init parameter, or true if missing
78 */
79 protected boolean getPassThrough() throws MessagingException {
80 return new Boolean(getInitParameter("passThrough","true")).booleanValue();
81 }
82
83 /***
84 * @return the <CODE>inline</CODE> init parameter, or <CODE>NONE</CODE> if missing
85 */
86 protected int getInLineType() throws MessagingException {
87 return getTypeCode(getInitParameter("inline","none"));
88 }
89
90 /***
91 * @return the <CODE>attachment</CODE> init parameter, or <CODE>MESSAGE</CODE> if missing
92 */
93 protected int getAttachmentType() throws MessagingException {
94 return getTypeCode(getInitParameter("attachment","message"));
95 }
96
97 /***
98 * @return the <CODE>notice</CODE> init parameter,
99 * or the <CODE>message</CODE> init parameter if missing,
100 * or a default string if both are missing
101 */
102 protected String getMessage() {
103 return getInitParameter("notice",
104 getInitParameter("message",
105 "We were unable to deliver the attached message because of an error in the mail server."));
106 }
107
108 /***
109 * @return the full message to append, built from the Mail object
110 */
111 protected String getMessage(Mail originalMail) throws MessagingException {
112 MimeMessage message = originalMail.getMessage();
113 StringWriter sout = new StringWriter();
114 PrintWriter out = new PrintWriter(sout, true);
115
116
117
118 out.println(getMessage());
119
120 if (originalMail.getErrorMessage() != null) {
121 out.println();
122 out.println("Error message below:");
123 out.println(originalMail.getErrorMessage());
124 }
125 out.println();
126 out.println("Message details:");
127
128 if (message.getSubject() != null) {
129 out.println(" Subject: " + message.getSubject());
130 }
131 if (message.getSentDate() != null) {
132 out.println(" Sent date: " + message.getSentDate());
133 }
134 out.println(" MAIL FROM: " + originalMail.getSender());
135 Iterator rcptTo = originalMail.getRecipients().iterator();
136 out.println(" RCPT TO: " + rcptTo.next());
137 while (rcptTo.hasNext()) {
138 out.println(" " + rcptTo.next());
139 }
140 String[] addresses = null;
141 addresses = message.getHeader(RFC2822Headers.FROM);
142 if (addresses != null) {
143 out.print(" From: ");
144 for (int i = 0; i < addresses.length; i++) {
145 out.print(addresses[i] + " ");
146 }
147 out.println();
148 }
149 addresses = message.getHeader(RFC2822Headers.TO);
150 if (addresses != null) {
151 out.print(" To: ");
152 for (int i = 0; i < addresses.length; i++) {
153 out.print(addresses[i] + " ");
154 }
155 out.println();
156 }
157 addresses = message.getHeader(RFC2822Headers.CC);
158 if (addresses != null) {
159 out.print(" CC: ");
160 for (int i = 0; i < addresses.length; i++) {
161 out.print(addresses[i] + " ");
162 }
163 out.println();
164 }
165 out.println(" Size (in bytes): " + message.getSize());
166 if (message.getLineCount() >= 0) {
167 out.println(" Number of lines: " + message.getLineCount());
168 }
169
170 return sout.toString();
171 }
172
173
174 abstract protected Collection getRecipients() throws MessagingException;
175
176 /***
177 * @return null
178 */
179 protected InternetAddress[] getTo() throws MessagingException {
180 return null;
181 }
182
183 /***
184 * @return <CODE>SpecialAddress.NULL</CODE>, that will remove the "ReplyTo:" header
185 */
186 protected MailAddress getReplyTo() throws MessagingException {
187 return SpecialAddress.NULL;
188 }
189
190 /***
191 * @return {@link AbstractRedirect#getSender(Mail)}, meaning the new requested sender if any
192 */
193 protected MailAddress getReversePath(Mail originalMail) throws MessagingException {
194 return getSender(originalMail);
195 }
196
197 /***
198 * @return the value of the <CODE>sendingAddress</CODE> init parameter,
199 * or the value of the <CODE>sender</CODE> init parameter if missing,
200 * or the postmaster address if both are missing
201 * @return the <CODE>sendingAddress</CODE> init parameter
202 * or the <CODE>sender</CODE> init parameter
203 * or the postmaster address if both are missing;
204 * possible special addresses returned are
205 * <CODE>SpecialAddress.SENDER</CODE>
206 * and <CODE>SpecialAddress.UNALTERED</CODE>
207 */
208 protected MailAddress getSender() throws MessagingException {
209 String addressString = getInitParameter("sendingAddress",getInitParameter("sender"));
210
211 if (addressString == null) {
212 return getMailetContext().getPostmaster();
213 }
214
215 MailAddress specialAddress = getSpecialAddress(addressString,
216 new String[] {"postmaster", "sender", "unaltered"});
217 if (specialAddress != null) {
218 return specialAddress;
219 }
220
221 try {
222 return new MailAddress(addressString);
223 } catch(Exception e) {
224 throw new MessagingException("Exception thrown in getSender() parsing: " + addressString, e);
225 }
226 }
227
228 /***
229 * @return null
230 */
231 protected String getSubject() throws MessagingException {
232 return null;
233 }
234
235 /***
236 * @return the <CODE>prefix</CODE> init parameter or "Re:" if missing
237 */
238 protected String getSubjectPrefix() {
239 return getInitParameter("prefix","Re:");
240 }
241
242 /***
243 * Builds the subject of <I>newMail</I> appending the subject
244 * of <I>originalMail</I> to <I>subjectPrefix</I>, but avoiding a duplicate.
245 */
246 protected void setSubjectPrefix(Mail newMail, String subjectPrefix, Mail originalMail) throws MessagingException {
247 String subject = originalMail.getMessage().getSubject();
248 if (subject == null) {
249 subject = "";
250 }
251 if (subjectPrefix==null || subject.indexOf(subjectPrefix) == 0) {
252 newMail.getMessage().setSubject(subject);
253 } else {
254 newMail.getMessage().setSubject(subjectPrefix + subject);
255 }
256 }
257
258 /***
259 * @return true
260 */
261 protected boolean isReply() {
262 return true;
263 }
264
265
266
267
268
269 }