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 package org.apache.james.transport.mailets;
21
22 import org.apache.avalon.framework.service.ServiceException;
23 import org.apache.avalon.framework.service.ServiceManager;
24 import org.apache.james.Constants;
25 import org.apache.james.services.JamesUser;
26 import org.apache.james.services.User;
27 import org.apache.james.services.UsersRepository;
28 import org.apache.james.services.UsersStore;
29 import org.apache.mailet.RFC2822Headers;
30
31 import org.apache.mailet.GenericMailet;
32 import org.apache.mailet.Mail;
33 import org.apache.mailet.MailAddress;
34
35 import javax.mail.MessagingException;
36 import javax.mail.internet.MimeMessage;
37
38 import java.util.Collection;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.LinkedList;
42 import java.util.Vector;
43
44 /***
45 * Receives a Mail from JamesSpoolManager and takes care of delivery of the
46 * message to local inboxes.
47 *
48 * Available configurations are:
49 *
50 * <enableAliases>true</enableAliases>: specify wether the user aliases should
51 * be looked up or not. Default is false.
52 *
53 * <enableForwarding>true</enableForwarding>: enable the forwarding. Default to
54 * false.
55 *
56 * <usersRepository>LocalAdmins</usersRepository>: specific users repository
57 * name. Default to empty. If empty does lookup the default userRepository.
58 */
59 public class UsersRepositoryAliasingForwarding extends GenericMailet {
60
61 /***
62 * The user repository for this mail server. Contains all the users with
63 * inboxes on this server.
64 */
65 private UsersRepository usersRepository;
66
67 /***
68 * Whether to enable aliasing for users on this server
69 */
70 private boolean enableAliases;
71
72 /***
73 * Whether to enable forwarding for users on this server
74 */
75 private boolean enableForwarding;
76
77 /***
78 * Whether to ignore case when looking up user names on this server
79 */
80 private boolean ignoreCase;
81
82 /***
83 * Delivers a mail to a local mailbox.
84 *
85 * @param mail
86 * the mail being processed
87 *
88 * @throws MessagingException
89 * if an error occurs while storing the mail
90 */
91 public void service(Mail mail) throws MessagingException {
92 Collection recipients = mail.getRecipients();
93 Collection errors = new Vector();
94
95 MimeMessage message = mail.getMessage();
96
97
98
99
100
101 message
102 .setHeader(RFC2822Headers.RETURN_PATH,
103 (mail.getSender() == null ? "<>" : "<"
104 + mail.getSender() + ">"));
105
106 Collection newRecipients = new LinkedList();
107 for (Iterator i = recipients.iterator(); i.hasNext();) {
108 MailAddress recipient = (MailAddress) i.next();
109 try {
110 String username = processMail(mail.getSender(), recipient,
111 message);
112
113
114
115 if (username == null) {
116 i.remove();
117 } else if (!username.equals(recipient.getUser())) {
118 i.remove();
119
120
121 newRecipients.add(new MailAddress(username, recipient
122 .getHost()));
123 }
124
125 } catch (Exception ex) {
126 getMailetContext().log("Error while storing mail.", ex);
127 errors.add(recipient);
128 }
129 }
130
131 if (newRecipients.size() > 0) {
132 recipients.addAll(newRecipients);
133 }
134
135 if (!errors.isEmpty()) {
136
137
138
139
140
141
142
143 getMailetContext().sendMail(mail.getSender(), errors, message,
144 Mail.ERROR);
145 }
146
147 if (recipients.size() == 0) {
148
149 mail.setState(Mail.GHOST);
150 }
151 }
152
153 /***
154 * Return a string describing this mailet.
155 *
156 * @return a string describing this mailet
157 */
158 public String getMailetInfo() {
159 return "Local User Aliasing and Forwarding Mailet";
160 }
161
162 /***
163 * Return null when the mail should be GHOSTed, the username string when it
164 * should be changed due to the ignoreUser configuration.
165 *
166 * @param sender
167 * @param recipient
168 * @param message
169 * @throws MessagingException
170 */
171 public String processMail(MailAddress sender, MailAddress recipient,
172 MimeMessage message) throws MessagingException {
173 String username;
174 if (recipient == null) {
175 throw new IllegalArgumentException(
176 "Recipient for mail to be spooled cannot be null.");
177 }
178 if (message == null) {
179 throw new IllegalArgumentException(
180 "Mail message to be spooled cannot be null.");
181 }
182 if (ignoreCase) {
183 String originalUsername = recipient.getUser();
184 username = usersRepository.getRealName(originalUsername);
185 if (username == null) {
186 StringBuffer errorBuffer = new StringBuffer(128).append(
187 "The inbox for user ").append(originalUsername).append(
188 " was not found on this server.");
189 throw new MessagingException(errorBuffer.toString());
190 }
191 } else {
192 username = recipient.getUser();
193 }
194 User user;
195 if (enableAliases || enableForwarding) {
196 user = usersRepository.getUserByName(username);
197 if (user instanceof JamesUser) {
198 if (enableAliases && ((JamesUser) user).getAliasing()) {
199 username = ((JamesUser) user).getAlias();
200 }
201
202 if (enableForwarding && ((JamesUser) user).getForwarding()) {
203 MailAddress forwardTo = ((JamesUser) user).getForwardingDestination();
204 if (forwardTo == null) {
205 StringBuffer errorBuffer = new StringBuffer(128)
206 .append("Forwarding was enabled for ")
207 .append(username)
208 .append(
209 " but no forwarding address was set for this account.");
210 throw new MessagingException(errorBuffer.toString());
211 }
212 Collection recipients = new HashSet();
213 recipients.add(forwardTo);
214 try {
215 getMailetContext().sendMail(sender, recipients, message);
216 StringBuffer logBuffer = new StringBuffer(128).append(
217 "Mail for ").append(username).append(
218 " forwarded to ").append(forwardTo.toString());
219 getMailetContext().log(logBuffer.toString());
220 return null;
221 } catch (MessagingException me) {
222 StringBuffer logBuffer = new StringBuffer(128).append(
223 "Error forwarding mail to ").append(
224 forwardTo.toString()).append(
225 "attempting local delivery");
226 getMailetContext().log(logBuffer.toString());
227 throw me;
228 }
229 }
230 }
231 }
232 return username;
233 }
234
235 /***
236 * @see org.apache.mailet.GenericMailet#init()
237 */
238 public void init() throws MessagingException {
239 super.init();
240 ServiceManager compMgr = (ServiceManager) getMailetContext()
241 .getAttribute(Constants.AVALON_COMPONENT_MANAGER);
242
243 UsersStore usersStore;
244 try {
245 usersStore = (UsersStore) compMgr.lookup(UsersStore.ROLE);
246
247
248 enableAliases = new Boolean(getInitParameter("enableAliases",
249 getMailetContext().getAttribute(Constants.DEFAULT_ENABLE_ALIASES).toString()
250 )).booleanValue();
251 enableForwarding = new Boolean(getInitParameter("enableForwarding",
252 getMailetContext().getAttribute(Constants.DEFAULT_ENABLE_FORWARDING).toString()
253 )).booleanValue();
254 ignoreCase = new Boolean(getInitParameter("ignoreCase",
255 getMailetContext().getAttribute(Constants.DEFAULT_IGNORE_USERNAME_CASE).toString()
256 )).booleanValue();
257
258 String userRep = getInitParameter("usersRepository");
259 if (userRep == null || userRep.length() == 0) {
260 try {
261 usersRepository = (UsersRepository) compMgr
262 .lookup(UsersRepository.ROLE);
263 } catch (ServiceException e) {
264 log("Failed to retrieve UsersRepository component:"
265 + e.getMessage());
266 }
267 } else {
268 usersRepository = usersStore.getRepository(userRep);
269 }
270
271 } catch (ServiceException cnfe) {
272 log("Failed to retrieve UsersStore component:" + cnfe.getMessage());
273 }
274
275 }
276
277 }