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