KickJava   Java API By Example, From Geeks To Geeks.

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


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 org.apache.james.util.RFC2822Headers;
21 import org.apache.mailet.GenericMailet;
22 import org.apache.mailet.Mail;
23 import org.apache.mailet.MailAddress;
24 import org.apache.mailet.MailetException;
25
26 import javax.mail.MessagingException JavaDoc;
27 import javax.mail.internet.MimeMessage JavaDoc;
28 import javax.mail.internet.MimeMultipart JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.Vector JavaDoc;
32
33 /**
34  * An abstract implementation of a listserv. The underlying implementation must define
35  * various settings, and can vary in their individual configuration. Supports restricting
36  * to members only, allowing attachments or not, sending replies back to the list, and an
37  * optional subject prefix.
38  */

39 public abstract class GenericListserv extends GenericMailet {
40
41     /**
42      * Returns a Collection of MailAddress objects of members to receive this email
43      */

44     public abstract Collection JavaDoc getMembers() throws MessagingException JavaDoc;
45
46     /**
47      * Returns whether this list should restrict to senders only
48      */

49     public abstract boolean isMembersOnly() throws MessagingException JavaDoc;
50
51     /**
52      * Returns whether this listserv allow attachments
53      */

54     public abstract boolean isAttachmentsAllowed() throws MessagingException JavaDoc;
55
56     /**
57      * Returns whether listserv should add reply-to header
58      */

59     public abstract boolean isReplyToList() throws MessagingException JavaDoc;
60
61     /**
62      * The email address that this listserv processes on. If returns null, will use the
63      * recipient of the message, which hopefully will be the correct email address assuming
64      * the matcher was properly specified.
65      */

66     public MailAddress getListservAddress() throws MessagingException JavaDoc {
67         return null;
68     }
69
70     /**
71      * An optional subject prefix.
72      */

73     public abstract String JavaDoc getSubjectPrefix() throws MessagingException JavaDoc;
74
75     /**
76      * Should the subject prefix be automatically surrounded by [].
77      *
78      * @return whether the subject prefix will be surrounded by []
79      *
80      * @throws MessagingException never, for this implementation
81      */

82     public boolean isPrefixAutoBracketed() throws MessagingException JavaDoc {
83         return true; // preserve old behavior unless subclass overrides.
84
}
85
86     /**
87      * <p>This takes the subject string and reduces (normailzes) it.
88      * Multiple "Re:" entries are reduced to one, and capitalized. The
89      * prefix is always moved/placed at the beginning of the line, and
90      * extra blanks are reduced, so that the output is always of the
91      * form:</p>
92      * <code>
93      * &lt;prefix&gt; + &lt;one-optional-"Re:"*gt; + &lt;remaining subject&gt;
94      * </code>
95      * <p>I have done extensive testing of this routine with a standalone
96      * driver, and am leaving the commented out debug messages so that
97      * when someone decides to enhance this method, it can be yanked it
98      * from this file, embedded it with a test driver, and the comments
99      * enabled.</p>
100      */

101     static private String JavaDoc normalizeSubject(final String JavaDoc subj, final String JavaDoc prefix) {
102         // JDK IMPLEMENTATION NOTE! When we require JDK 1.4+, all
103
// occurrences of subject.toString.().indexOf(...) can be
104
// replaced by subject.indexOf(...).
105

106         StringBuffer JavaDoc subject = new StringBuffer JavaDoc(subj);
107         int prefixLength = prefix.length();
108
109         // System.err.println("In: " + subject);
110

111         // If the "prefix" is not at the beginning the subject line, remove it
112
int index = subject.toString().indexOf(prefix);
113         if (index != 0) {
114             // System.err.println("(p) index: " + index + ", subject: " + subject);
115
if (index > 0) {
116                 subject.delete(index, index + prefixLength);
117             }
118             subject.insert(0, prefix); // insert prefix at the front
119
}
120
121         // Replace Re: with RE:
122
String JavaDoc match = "Re:";
123         index = subject.toString().indexOf(match, prefixLength);
124
125         while(index > -1) {
126             // System.err.println("(a) index: " + index + ", subject: " + subject);
127
subject.replace(index, index + match.length(), "RE:");
128             index = subject.toString().indexOf(match, prefixLength);
129             // System.err.println("(b) index: " + index + ", subject: " + subject);
130
}
131
132         // Reduce them to one at the beginning
133
match ="RE:";
134         int indexRE = subject.toString().indexOf(match, prefixLength) + match.length();
135         index = subject.toString().indexOf(match, indexRE);
136         while(index > 0) {
137             // System.err.println("(c) index: " + index + ", subject: " + subject);
138
subject.delete(index, index + match.length());
139             index = subject.toString().indexOf(match, indexRE);
140             // System.err.println("(d) index: " + index + ", subject: " + subject);
141
}
142
143         // Reduce blanks
144
match = " ";
145         index = subject.toString().indexOf(match, prefixLength);
146         while(index > -1) {
147             // System.err.println("(e) index: " + index + ", subject: " + subject);
148
subject.replace(index, index + match.length(), " ");
149             index = subject.toString().indexOf(match, prefixLength);
150             // System.err.println("(f) index: " + index + ", subject: " + subject);
151
}
152
153
154         // System.err.println("Out: " + subject);
155

156         return subject.toString();
157     }
158     
159     /**
160      * Processes the message. Assumes it is the only recipient of this forked message.
161      */

162     public final void service(Mail mail) throws MessagingException JavaDoc {
163         try {
164             Collection JavaDoc members = getMembers();
165
166             //Check for members only flag....
167
if (isMembersOnly() && !members.contains(mail.getSender())) {
168                 //Need to bounce the message to say they can't send to this list
169
getMailetContext().bounce(mail, "Only members of this listserv are allowed to send a message to this address.");
170                 mail.setState(Mail.GHOST);
171                 return;
172             }
173
174             //Check for no attachments
175
if (!isAttachmentsAllowed() && mail.getMessage().getContent() instanceof MimeMultipart JavaDoc) {
176                 getMailetContext().bounce(mail, "You cannot send attachments to this listserv.");
177                 mail.setState(Mail.GHOST);
178                 return;
179             }
180
181             //Create a copy of this message to send out
182
MimeMessage JavaDoc message = new MimeMessage JavaDoc(mail.getMessage());
183             //We need to remove this header from the copy we're sending around
184
message.removeHeader(RFC2822Headers.RETURN_PATH);
185
186             //Figure out the listserv address.
187
MailAddress listservAddr = getListservAddress();
188             if (listservAddr == null) {
189                 //Use the recipient
190
listservAddr = (MailAddress)mail.getRecipients().iterator().next();
191             }
192
193             //Check if the X-been-there header is set to the listserv's name
194
// (the address). If it has, this means it's a message from this
195
// listserv that's getting bounced back, so we need to swallow it
196
if (listservAddr.equals(message.getHeader("X-been-there"))) {
197                 mail.setState(Mail.GHOST);
198                 return;
199             }
200
201             //Set the subject if set
202
String JavaDoc prefix = getSubjectPrefix();
203             if (prefix != null) {
204                 if (isPrefixAutoBracketed()) {
205                     StringBuffer JavaDoc prefixBuffer =
206                         new StringBuffer JavaDoc(64)
207                             .append("[")
208                             .append(prefix)
209                             .append("] ");
210                     prefix = prefixBuffer.toString();
211                 }
212                 String JavaDoc subj = message.getSubject();
213                 if (subj == null) {
214                     subj = "";
215                 }
216                 subj = normalizeSubject(subj, prefix);
217                 AbstractRedirect.changeSubject(message, subj);
218             }
219
220             //If replies should go to this list, we need to set the header
221
if (isReplyToList()) {
222                 message.setHeader(RFC2822Headers.REPLY_TO, listservAddr.toString());
223             }
224             //We're going to set this special header to avoid bounces
225
// getting sent back out to the list
226
message.setHeader("X-been-there", listservAddr.toString());
227
228             //Send the message to the list members
229
//We set the postmaster as the sender for now so bounces go to him/her
230
getMailetContext().sendMail(getMailetContext().getPostmaster(), members, message);
231
232             //Kill the old message
233
mail.setState(Mail.GHOST);
234         } catch (IOException JavaDoc ioe) {
235             throw new MailetException("Error creating listserv message", ioe);
236         }
237     }
238 }
239
Popular Tags