KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > james > transport > mailets > Redirect


1 /***********************************************************************
2  * Copyright (c) 2000-2004 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 java.io.PrintWriter JavaDoc;
21 import java.io.StringWriter JavaDoc;
22
23 import java.util.Collection JavaDoc;
24 import java.util.Date JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.Locale JavaDoc;
29 import java.util.ArrayList JavaDoc;
30
31
32 import javax.mail.Message JavaDoc;
33 import javax.mail.MessagingException JavaDoc;
34 import javax.mail.Session JavaDoc;
35 import javax.mail.internet.InternetAddress JavaDoc;
36 import javax.mail.internet.MimeBodyPart JavaDoc;
37 import javax.mail.internet.MimeMessage JavaDoc;
38 import javax.mail.internet.MimeMultipart JavaDoc;
39
40 import org.apache.james.core.MailImpl;
41
42 import org.apache.mailet.GenericMailet;
43 import org.apache.mailet.Mail;
44 import org.apache.mailet.MailAddress;
45
46
47 /**
48  * <P>A mailet providing configurable redirection services.</P>
49  * <P>Can produce listserver, forward and notify behaviour, with the original
50  * message intact, attached, appended or left out altogether.</P>
51  * <P>It differs from {@link Resend} because
52  * (i) some defaults are different,
53  * notably for the following parameters: <I>&lt;recipients&gt;</I>, <I>&lt;to&gt;</I>,
54  * <I>&lt;reversePath&gt;</I> and <I>&lt;inline&gt;</I>;
55  * (ii) because it allows the use of the <I>&lt;static&gt;</I> parameter;.<BR>
56  * Use <CODE>Resend</CODE> if you need full control, <CODE>Redirect</CODE> if
57  * the more automatic behaviour of some parameters is appropriate.</P>
58  * <P>This built in functionality is controlled by the configuration as laid out below.
59  * In the table please note that the parameters controlling message headers
60  * accept the <B>&quot;unaltered&quot;</B> value, whose meaning is to keep the associated
61  * header unchanged and, unless stated differently, corresponds to the assumed default
62  * if the parameter is missing.</P>
63  * <P>The configuration parameters are:</P>
64  * <TABLE width="75%" border="1" cellspacing="2" cellpadding="2">
65  * <TR valign=top>
66  * <TD width="20%">&lt;recipients&gt;</TD>
67  * <TD width="80%">
68  * A comma delimited list of addresses for recipients of
69  * this message; it will use the &quot;to&quot; list if not specified, and &quot;unaltered&quot;
70  * if none of the lists is specified.<BR>
71  * These addresses will only appear in the To: header if no &quot;to&quot; list is
72  * supplied.<BR>
73  * Such addresses can contain &quot;full names&quot;, like
74  * <I>Mr. John D. Smith &lt;john.smith@xyz.com&gt;</I>.<BR>
75  * The list can include constants &quot;sender&quot;, &quot;from&quot;, &quot;replyTo&quot;, &quot;postmaster&quot;, &quot;reversePath&quot;, &quot;recipients&quot;, &quot;to&quot;, &quot;null&quot; and &quot;unaltered&quot;;
76  * &quot;replyTo&quot; uses the ReplyTo header if available, otherwise the
77  * From header if available, otherwise the Sender header if available, otherwise the return-path;
78  * &quot;from&quot; is made equivalent to &quot;sender&quot;, and &quot;to&quot; is made equivalent to &quot;recipients&quot;;
79  * &quot;null&quot; is ignored.
80  * </TD>
81  * </TR>
82  * <TR valign=top>
83  * <TD width="20%">&lt;to&gt;</TD>
84  * <TD width="80%">
85  * A comma delimited list of addresses to appear in the To: header;
86  * the email will be delivered to any of these addresses if it is also in the recipients
87  * list.<BR>
88  * The recipients list will be used if this list is not supplied;
89  * if none of the lists is specified it will be &quot;unaltered&quot;.<BR>
90  * Such addresses can contain &quot;full names&quot;, like
91  * <I>Mr. John D. Smith &lt;john.smith@xyz.com&gt;</I>.<BR>
92  * The list can include constants &quot;sender&quot;, &quot;from&quot;, &quot;replyTo&quot;, &quot;postmaster&quot;, &quot;reversePath&quot;, &quot;recipients&quot;, &quot;to&quot;, &quot;null&quot; and &quot;unaltered&quot;;
93  * &quot;from&quot; uses the From header if available, otherwise the Sender header if available,
94  * otherwise the return-path;
95  * &quot;replyTo&quot; uses the ReplyTo header if available, otherwise the
96  * From header if available, otherwise the Sender header if available, otherwise the return-path;
97  * &quot;recipients&quot; is made equivalent to &quot;to&quot;;
98  * if &quot;null&quot; is specified alone it will remove this header.
99  * </TD>
100  * </TR>
101  * <TR valign=top>
102  * <TD width="20%">&lt;sender&gt;</TD>
103  * <TD width="80%">
104  * A single email address to appear in the From: and Return-Path: headers and become the sender.<BR>
105  * It can include constants &quot;sender&quot;, &quot;postmaster&quot; and &quot;unaltered&quot;;
106  * &quot;sender&quot; is equivalent to &quot;unaltered&quot;.<BR>
107  * Default: &quot;unaltered&quot;.
108  * </TD>
109  * </TR>
110  * <TR valign=top>
111  * <TD width="20%">&lt;message&gt;</TD>
112  * <TD width="80%">
113  * A text message to insert into the body of the email.<BR>
114  * Default: no message is inserted.
115  * </TD>
116  * </TR>
117  * <TR valign=top>
118  * <TD width="20%">&lt;inline&gt;</TD>
119  * <TD width="80%">
120  * <P>One of the following items:</P>
121  * <UL>
122  * <LI>unaltered &nbsp;&nbsp;&nbsp;&nbsp;The original message is the new
123  * message, for forwarding/aliasing</LI>
124  * <LI>heads&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The
125  * headers of the original message are appended to the message</LI>
126  * <LI>body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The
127  * body of the original is appended to the new message</LI>
128  * <LI>all&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Both
129  * headers and body are appended</LI>
130  * <LI>none&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Neither
131  * body nor headers are appended</LI>
132  * </UL>
133  * Default: &quot;body&quot;.
134  * </TD>
135  * </TR>
136  * <TR valign=top>
137  * <TD width="20%">&lt;attachment&gt;</TD>
138  * <TD width="80%">
139  * <P>One of the following items:</P>
140  * <UL>
141  * <LI>heads&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The headers of the original
142  * are attached as text</LI>
143  * <LI>body&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The body of the original
144  * is attached as text</LI>
145  * <LI>all&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Both
146  * headers and body are attached as a single text file</LI>
147  * <LI>none&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Nothing is attached</LI>
148  * <LI>message &nbsp;The original message is attached as type message/rfc822,
149  * this means that it can, in many cases, be opened, resent, fw'd, replied
150  * to etc by email client software.</LI>
151  * </UL>
152  * Default: &quot;none&quot;.
153  * </TD>
154  * </TR>
155  * <TR valign=top>
156  * <TD width="20%">&lt;passThrough&gt;</TD>
157  * <TD width="80%">
158  * true or false, if true the original message continues in the
159  * mailet processor after this mailet is finished. False causes the original
160  * to be stopped.<BR>
161  * Default: false.
162  * </TD>
163  * </TR>
164  * <TR valign=top>
165  * <TD width="20%">&lt;fakeDomainCheck&gt;</TD>
166  * <TD width="80%">
167  * true or false, if true will check if the sender domain is valid.<BR>
168  * Default: true.
169  * </TD>
170  * </TR>
171  * <TR valign=top>
172  * <TD width="20%">&lt;attachError&gt;</TD>
173  * <TD width="80%">
174  * true or false, if true any error message available to the
175  * mailet is appended to the message body (except in the case of inline ==
176  * unaltered).<BR>
177  * Default: false.
178  * </TD>
179  * </TR>
180  * <TR valign=top>
181  * <TD width="20%">&lt;replyTo&gt;</TD>
182  * <TD width="80%">
183  * A single email address to appear in the Reply-To: header.<BR>
184  * It can include constants &quot;sender&quot;, &quot;postmaster&quot; &quot;null&quot; and &quot;unaltered&quot;;
185  * if &quot;null&quot; is specified it will remove this header.<BR>
186  * Default: &quot;unaltered&quot;.
187  * </TD>
188  * </TR>
189  * </TR>
190  * <TR valign=top>
191  * <TD width="20%">&lt;reversePath&gt;</TD>
192  * <TD width="80%">
193  * A single email address to appear in the Return-Path: header.<BR>
194  * It can include constants &quot;sender&quot;, &quot;postmaster&quot; and &quot;null&quot;;
195  * if &quot;null&quot; is specified then it will set it to <>, meaning &quot;null return path&quot;.<BR>
196  * Notice: the &quot;unaltered&quot; value is <I>not allowed</I>.<BR>
197  * Default: the value of the <I>&lt;sender&gt;</I> parameter, if set, otherwise remains unaltered.
198  * </TD>
199  * </TR>
200  * <TR valign=top>
201  * <TD width="20%">&lt;subject&gt;</TD>
202  * <TD width="80%">
203  * An optional string to use as the subject.<BR>
204  * Default: keep the original message subject.
205  * </TD>
206  * </TR>
207  * <TR valign=top>
208  * <TD width="20%">&lt;prefix&gt;</TD>
209  * <TD width="80%">
210  * An optional subject prefix prepended to the original message
211  * subject, or to a new subject specified with the <I>&lt;subject&gt;</I> parameter.<BR>
212  * For example: <I>[Undeliverable mail]</I>.<BR>
213  * Default: &quot;&quot;.
214  * </TD>
215  * </TR>
216  * <TR valign=top>
217  * <TD width="20%">&lt;isReply&gt;</TD>
218  * <TD width="80%">
219  * true or false, if true the IN_REPLY_TO header will be set to the
220  * id of the current message.<BR>
221  * Default: false.
222  * </TD>
223  * </TR>
224  * <TR valign=top>
225  * <TD width="20%">&lt;debug&gt;</TD>
226  * <TD width="80%">
227  * true or false. If this is true it tells the mailet to write some debugging
228  * information to the mailet log.<BR>
229  * Default: false.
230  * </TD>
231  * </TR>
232  * <TR valign=top>
233  * <TD width="20%">&lt;static&gt;</TD>
234  * <TD width="80%">
235  * true or false. If this is true it tells the mailet that it can
236  * reuse all the initial parameters (to, from, etc) without re-calculating
237  * their values. This will boost performance where a redirect task
238  * doesn't contain any dynamic values. If this is false, it tells the
239  * mailet to recalculate the values for each e-mail processed.<BR>
240  * Default: false.
241  * </TD>
242  * </TR>
243  * </TABLE>
244  *
245  * <P>Example:</P>
246  * <PRE><CODE>
247  * &lt;mailet match=&quot;RecipientIs=test@localhost&quot; class=&quot;Redirect&quot;&gt;
248  * &lt;recipients&gt;x@localhost, y@localhost, z@localhost&lt;/recipients&gt;
249  * &lt;to&gt;list@localhost&lt;/to&gt;
250  * &lt;sender&gt;owner@localhost&lt;/sender&gt;
251  * &lt;message&gt;sent on from James&lt;/message&gt;
252  * &lt;inline&gt;unaltered&lt;/inline&gt;
253  * &lt;passThrough&gt;FALSE&lt;/passThrough&gt;
254  * &lt;replyTo&gt;postmaster&lt;/replyTo&gt;
255  * &lt;prefix xml:space="preserve"&gt;[test mailing] &lt;/prefix&gt;
256  * &lt;!-- note the xml:space="preserve" to preserve whitespace --&gt;
257  * &lt;static&gt;TRUE&lt;/static&gt;
258  * &lt;/mailet&gt;
259  * </CODE></PRE>
260  *
261  * <P>and:</P>
262  *
263  * <PRE><CODE>
264  * &lt;mailet match=&quot;All&quot; class=&quot;Redirect&quot;&gt;
265  * &lt;recipients&gt;x@localhost&lt;/recipients&gt;
266  * &lt;sender&gt;postmaster&lt;/sender&gt;
267  * &lt;message xml:space="preserve"&gt;Message marked as spam:&lt;/message&gt;
268  * &lt;inline&gt;heads&lt;/inline&gt;
269  * &lt;attachment&gt;message&lt;/attachment&gt;
270  * &lt;passThrough&gt;FALSE&lt;/passThrough&gt;
271  * &lt;attachError&gt;TRUE&lt;/attachError&gt;
272  * &lt;replyTo&gt;postmaster&lt;/replyTo&gt;
273  * &lt;prefix&gt;[spam notification]&lt;/prefix&gt;
274  * &lt;static&gt;TRUE&lt;/static&gt;
275  * &lt;/mailet&gt;
276  * </CODE></PRE>
277  * <P><I>replyto</I> can be used instead of
278  * <I>replyTo</I>; such name is kept for backward compatibility.</P>
279  *
280  * @version CVS $Revision: 1.18.4.19 $ $Date: 2004/03/15 03:54:19 $
281  */

282
283 public class Redirect extends AbstractRedirect {
284
285     /**
286      * Returns a string describing this mailet.
287      *
288      * @return a string describing this mailet
289      */

290     public String JavaDoc getMailetInfo() {
291         return "Redirect Mailet";
292     }
293
294     /** Gets the expected init parameters. */
295     protected String JavaDoc[] getAllowedInitParameters() {
296         String JavaDoc[] allowedArray = {
297             "static",
298             "debug",
299             "passThrough",
300             "fakeDomainCheck",
301             "inline",
302             "attachment",
303             "message",
304             "recipients",
305             "to",
306             "replyTo",
307             "replyto",
308             "reversePath",
309             "sender",
310             "subject",
311             "prefix",
312             "attachError",
313             "isReply"
314         };
315         return allowedArray;
316     }
317
318     /* ******************************************************************** */
319     /* ****************** Begin of getX and setX methods ****************** */
320     /* ******************************************************************** */
321
322     /**
323      * @return the <CODE>static</CODE> init parameter
324     */

325     protected boolean isStatic() {
326         return isStatic;
327     }
328
329     /**
330      * @return the <CODE>inline</CODE> init parameter
331      */

332     protected int getInLineType() throws MessagingException JavaDoc {
333         if(getInitParameter("inline") == null) {
334             return BODY;
335         } else {
336             return getTypeCode(getInitParameter("inline"));
337         }
338     }
339
340     /**
341      * @return the <CODE>recipients</CODE> init parameter
342      * or the postmaster address
343      * or <CODE>SpecialAddress.SENDER</CODE>
344      * or <CODE>SpecialAddress.REVERSE_PATH</CODE>
345      * or <CODE>SpecialAddress.UNALTERED</CODE>
346      * or the <CODE>to</CODE> init parameter if missing
347      * or <CODE>null</CODE> if also the latter is missing
348      */

349     protected Collection JavaDoc getRecipients() throws MessagingException JavaDoc {
350         Collection JavaDoc newRecipients = new HashSet JavaDoc();
351         String JavaDoc addressList = (getInitParameter("recipients") == null)
352                                  ? getInitParameter("to")
353                                  : getInitParameter("recipients");
354                                  
355         // if nothing was specified, return <CODE>null</CODE> meaning no change
356
if (addressList == null) {
357             return null;
358         }
359
360         try {
361             InternetAddress JavaDoc[] iaarray = InternetAddress.parse(addressList, false);
362             for (int i = 0; i < iaarray.length; i++) {
363                 String JavaDoc addressString = iaarray[i].getAddress();
364                 MailAddress specialAddress = getSpecialAddress(addressString,
365                 new String JavaDoc[] {"postmaster", "sender", "from", "replyTo", "reversePath", "unaltered", "recipients", "to", "null"});
366                 if (specialAddress != null) {
367                     newRecipients.add(specialAddress);
368                 } else {
369                     newRecipients.add(new MailAddress(iaarray[i]));
370                 }
371             }
372         } catch (Exception JavaDoc e) {
373             throw new MessagingException JavaDoc("Exception thrown in getRecipients() parsing: " + addressList, e);
374         }
375         if (newRecipients.size() == 0) {
376             throw new MessagingException JavaDoc("Failed to initialize \"recipients\" list; empty <recipients> init parameter found.");
377         }
378
379         return newRecipients;
380     }
381
382     /**
383      * @return the <CODE>to</CODE> init parameter
384      * or the postmaster address
385      * or <CODE>SpecialAddress.SENDER</CODE>
386      * or <CODE>SpecialAddress.REVERSE_PATH</CODE>
387      * or <CODE>SpecialAddress.UNALTERED</CODE>
388      * or the <CODE>recipients</CODE> init parameter if missing
389      * or <CODE>null</CODE> if also the latter is missing
390      */

391     protected InternetAddress JavaDoc[] getTo() throws MessagingException JavaDoc {
392         InternetAddress JavaDoc[] iaarray = null;
393         String JavaDoc addressList = (getInitParameter("to") == null)
394                                  ? getInitParameter("recipients")
395                                  : getInitParameter("to");
396
397         // if nothing was specified, return null meaning no change
398
if (addressList == null) {
399             return null;
400         }
401
402         try {
403             iaarray = InternetAddress.parse(addressList, false);
404             for(int i = 0; i < iaarray.length; ++i) {
405                 String JavaDoc addressString = iaarray[i].getAddress();
406                 MailAddress specialAddress = getSpecialAddress(addressString,
407                                                 new String JavaDoc[] {"postmaster", "sender", "from", "replyTo", "reversePath", "unaltered", "recipients", "to", "null"});
408                 if (specialAddress != null) {
409                     iaarray[i] = specialAddress.toInternetAddress();
410                 }
411             }
412         } catch (Exception JavaDoc e) {
413             throw new MessagingException JavaDoc("Exception thrown in getTo() parsing: " + addressList, e);
414         }
415         if (iaarray.length == 0) {
416             throw new MessagingException JavaDoc("Failed to initialize \"to\" list; empty <to> init parameter found.");
417         }
418
419         return iaarray;
420     }
421
422     /**
423      * @return the <CODE>reversePath</CODE> init parameter
424      * or the postmaster address
425      * or <CODE>SpecialAddress.SENDER</CODE>
426      * or <CODE>SpecialAddress.NULL</CODE>
427      * or <CODE>null</CODE> if missing
428      */

429     protected MailAddress getReversePath() throws MessagingException JavaDoc {
430         String JavaDoc addressString = getInitParameter("reversePath");
431         if(addressString != null) {
432             MailAddress specialAddress = getSpecialAddress(addressString,
433                                             new String JavaDoc[] {"postmaster", "sender", "null"});
434             if (specialAddress != null) {
435                 return specialAddress;
436             }
437
438             try {
439                 return new MailAddress(addressString);
440             } catch(Exception JavaDoc e) {
441                 throw new MessagingException JavaDoc("Exception thrown in getReversePath() parsing: " + addressString, e);
442             }
443         }
444
445         return null;
446     }
447
448     /**
449      * @return {@link AbstractRedirect#getReversePath()};
450      * if null return {@link AbstractRedirect#getSender(Mail)},
451      * meaning the new requested sender if any
452      */

453     protected MailAddress getReversePath(Mail originalMail) throws MessagingException JavaDoc {
454         MailAddress reversePath = super.getReversePath(originalMail);
455         if (reversePath == null) {
456             reversePath = getSender(originalMail);
457         }
458         return reversePath;
459     }
460
461     /* ******************************************************************** */
462     /* ******************* End of getX and setX methods ******************* */
463     /* ******************************************************************** */
464
465 }
466
Popular Tags