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.MailetUtil;
25 import org.apache.mailet.base.RFC2822Headers;
26 import org.apache.mailet.base.GenericMailet;
27 import org.apache.mailet.Mail;
28 import org.apache.mailet.MailAddress;
29 import org.apache.mailet.MailetException;
30
31 import javax.mail.MessagingException;
32 import javax.mail.internet.MimeMessage;
33 import javax.mail.internet.MimeMultipart;
34 import java.io.IOException;
35 import java.util.Collection;
36
37 /**
38 * An abstract implementation of a listserv. The underlying implementation must define
39 * various settings, and can vary in their individual configuration. Supports restricting
40 * to members only, allowing attachments or not, sending replies back to the list, and an
41 * optional subject prefix.
42 */
43 public abstract class GenericListserv extends GenericMailet {
44
45 /**
46 * Returns a Collection of MailAddress objects of members to receive this email
47 */
48 public abstract Collection getMembers() throws MessagingException;
49
50 /**
51 * Returns whether this list should restrict to senders only
52 */
53 public abstract boolean isMembersOnly() throws MessagingException;
54
55 /**
56 * Returns whether this listserv allow attachments
57 */
58 public abstract boolean isAttachmentsAllowed() throws MessagingException;
59
60 /**
61 * Returns whether listserv should add reply-to header
62 */
63 public abstract boolean isReplyToList() throws MessagingException;
64
65 /**
66 * The email address that this listserv processes on. If returns null, will use the
67 * recipient of the message, which hopefully will be the correct email address assuming
68 * the matcher was properly specified.
69 */
70 public MailAddress getListservAddress() throws MessagingException {
71 return null;
72 }
73
74 /**
75 * An optional subject prefix.
76 */
77 public abstract String getSubjectPrefix() throws MessagingException;
78
79 /**
80 * Should the subject prefix be automatically surrounded by [].
81 *
82 * @return whether the subject prefix will be surrounded by []
83 *
84 * @throws MessagingException never, for this implementation
85 */
86 public boolean isPrefixAutoBracketed() throws MessagingException {
87 return true; // preserve old behavior unless subclass overrides.
88 }
89
90
91 /**
92 * Processes the message. Assumes it is the only recipient of this forked message.
93 */
94 public final void service(Mail mail) throws MessagingException {
95 try {
96 Collection members = getMembers();
97
98 //Check for members only flag....
99 if (isMembersOnly() && !members.contains(mail.getSender())) {
100 //Need to bounce the message to say they can't send to this list
101 getMailetContext().bounce(mail, "Only members of this listserv are allowed to send a message to this address.");
102 mail.setState(Mail.GHOST);
103 return;
104 }
105
106 //Check for no attachments
107 if (!isAttachmentsAllowed() && mail.getMessage().getContent() instanceof MimeMultipart) {
108 getMailetContext().bounce(mail, "You cannot send attachments to this listserv.");
109 mail.setState(Mail.GHOST);
110 return;
111 }
112
113 //Create a copy of this message to send out
114 MimeMessage message = new MimeMessage(mail.getMessage());
115 //We need to remove this header from the copy we're sending around
116 message.removeHeader(RFC2822Headers.RETURN_PATH);
117
118 //Figure out the listserv address.
119 MailAddress listservAddr = getListservAddress();
120 if (listservAddr == null) {
121 //Use the recipient
122 listservAddr = (MailAddress)mail.getRecipients().iterator().next();
123 }
124
125 //Check if the X-been-there header is set to the listserv's name
126 // (the address). If it has, this means it's a message from this
127 // listserv that's getting bounced back, so we need to swallow it
128 if (listservAddr.equals(message.getHeader("X-been-there"))) {
129 mail.setState(Mail.GHOST);
130 return;
131 }
132
133 //Set the subject if set
134 String prefix = getSubjectPrefix();
135 if (prefix != null) {
136 if (isPrefixAutoBracketed()) {
137 StringBuffer prefixBuffer =
138 new StringBuffer(64)
139 .append("[")
140 .append(prefix)
141 .append("] ");
142 prefix = prefixBuffer.toString();
143 }
144 String subj = message.getSubject();
145 if (subj == null) {
146 subj = "";
147 }
148 subj = MailetUtil.normalizeSubject(subj, prefix);
149 AbstractRedirect.changeSubject(message, subj);
150 }
151
152 //If replies should go to this list, we need to set the header
153 if (isReplyToList()) {
154 message.setHeader(RFC2822Headers.REPLY_TO, listservAddr.toString());
155 }
156 //We're going to set this special header to avoid bounces
157 // getting sent back out to the list
158 message.setHeader("X-been-there", listservAddr.toString());
159
160 //Send the message to the list members
161 //We set the postmaster as the sender for now so bounces go to him/her
162 getMailetContext().sendMail(getMailetContext().getPostmaster(), members, message);
163
164 //Kill the old message
165 mail.setState(Mail.GHOST);
166 } catch (IOException ioe) {
167 throw new MailetException("Error creating listserv message", ioe);
168 }
169 }
170 }