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.cornerstone.services.store.Store;
21 import org.apache.avalon.framework.configuration.DefaultConfiguration;
22 import org.apache.avalon.framework.container.ContainerUtil;
23 import org.apache.avalon.framework.service.ServiceException;
24 import org.apache.avalon.framework.service.ServiceManager;
25 import org.apache.james.Constants;
26 import org.apache.james.James;
27 import org.apache.james.core.MailImpl;
28 import org.apache.james.services.MailRepository;
29 import org.apache.james.services.MailServer;
30 import org.apache.mailet.RFC2822Headers;
31
32 import org.apache.mailet.GenericMailet;
33 import org.apache.mailet.Mail;
34 import org.apache.mailet.MailAddress;
35
36 import javax.mail.Header;
37 import javax.mail.MessagingException;
38 import javax.mail.internet.MimeMessage;
39 import javax.mail.internet.InternetHeaders;
40
41 import java.util.Collection;
42 import java.util.Enumeration;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.Vector;
46
47 /***
48 * Receives a Mail from JamesSpoolManager and takes care of delivery of the
49 * message to local inboxes or a specific repository.
50 *
51 * Differently from LocalDelivery this does not lookup the UserRepository This
52 * simply store the message in a repository named like the local part of the
53 * recipient address.
54 *
55 * If no repository is specified then this fallback to MailServer.getUserInbox.
56 * Otherwise you can add your own configuration for the repository
57 *
58 * e.g: <repositoryUrl>file://var/spool/userspools/</repositoryUrl>
59 * <repositoryType>SPOOL</repositoryType>
60 *
61 * <repositoryUrl>file://var/mail/inboxes/</repositoryUrl> <repositoryType>MAIL</repositoryType>
62 *
63 * Header "Delivered-To" can be added to every message adding the
64 * <addDeliveryHeader>Delivered-To</addDeliveryHeader>
65 *
66 */
67 public class ToMultiRepository extends GenericMailet {
68 /***
69 * The number of mails generated. Access needs to be synchronized for thread
70 * safety and to ensure that all threads see the latest value.
71 */
72 private static long count;
73
74 /***
75 * The mailserver reference
76 */
77 private MailServer mailServer;
78
79 /***
80 * The mailstore
81 */
82 private Store store;
83
84 /***
85 * The optional repositoryUrl
86 */
87 private String repositoryUrl;
88
89 /***
90 * The optional repositoryType
91 */
92 private String repositoryType;
93
94 /***
95 * The delivery header
96 */
97 private String deliveryHeader;
98
99 /***
100 * resetReturnPath
101 */
102 private boolean resetReturnPath;
103
104 /***
105 * Delivers a mail to a local mailbox.
106 *
107 * @param mail
108 * the mail being processed
109 *
110 * @throws MessagingException
111 * if an error occurs while storing the mail
112 */
113 public void service(Mail mail) throws MessagingException {
114 Collection recipients = mail.getRecipients();
115 Collection errors = new Vector();
116
117 MimeMessage message = null;
118 if (deliveryHeader != null || resetReturnPath) {
119 message = mail.getMessage();
120 }
121
122 if (resetReturnPath) {
123
124
125
126
127 message.setHeader(RFC2822Headers.RETURN_PATH,
128 (mail.getSender() == null ? "<>" : "<" + mail.getSender()
129 + ">"));
130 }
131
132 Enumeration headers;
133 InternetHeaders deliveredTo = new InternetHeaders();
134 if (deliveryHeader != null) {
135
136 headers = message
137 .getMatchingHeaders(new String[] { deliveryHeader });
138 while (headers.hasMoreElements()) {
139 Header header = (Header) headers.nextElement();
140 deliveredTo.addHeader(header.getName(), header.getValue());
141 }
142 }
143
144 for (Iterator i = recipients.iterator(); i.hasNext();) {
145 MailAddress recipient = (MailAddress) i.next();
146 try {
147 if (deliveryHeader != null) {
148
149 message.addHeader(deliveryHeader, recipient.toString());
150 }
151
152 storeMail(mail.getSender(), recipient, message);
153
154 if (deliveryHeader != null) {
155 if (i.hasNext()) {
156
157 message.removeHeader(deliveryHeader);
158 headers = deliveredTo.getAllHeaders();
159
160 while (headers.hasMoreElements()) {
161 Header header = (Header) headers.nextElement();
162 message.addHeader(header.getName(), header
163 .getValue());
164 }
165 }
166 }
167 } catch (Exception ex) {
168 getMailetContext().log("Error while storing mail.", ex);
169 errors.add(recipient);
170 }
171 }
172
173 if (!errors.isEmpty()) {
174
175
176
177
178
179
180
181 getMailetContext().sendMail(mail.getSender(), errors, mail.getMessage(),
182 Mail.ERROR);
183 }
184
185 mail.setState(Mail.GHOST);
186 }
187
188 /***
189 * Return a string describing this mailet.
190 *
191 * @return a string describing this mailet
192 */
193 public String getMailetInfo() {
194 return "ToMultiRepository Mailet";
195 }
196
197 /***
198 *
199 * @param sender
200 * @param recipient
201 * @param message
202 * @throws MessagingException
203 */
204 public void storeMail(MailAddress sender, MailAddress recipient,
205 MimeMessage message) throws MessagingException {
206 String username;
207 if (recipient == null) {
208 throw new IllegalArgumentException(
209 "Recipient for mail to be spooled cannot be null.");
210 }
211 if (message == null) {
212 throw new IllegalArgumentException(
213 "Mail message to be spooled cannot be null.");
214 }
215 username = recipient.getUser();
216
217 Collection recipients = new HashSet();
218 recipients.add(recipient);
219 MailImpl mail = new MailImpl(getId(), sender, recipients, message);
220 try {
221 MailRepository userInbox = getRepository(username);
222 if (userInbox == null) {
223 StringBuffer errorBuffer = new StringBuffer(128).append(
224 "The repository for user ").append(username).append(
225 " was not found on this server.");
226 throw new MessagingException(errorBuffer.toString());
227 }
228 userInbox.store(mail);
229 } finally {
230 mail.dispose();
231 }
232 }
233
234 /***
235 * Return a new mail id.
236 *
237 * @return a new mail id
238 */
239 public String getId() {
240 long localCount = -1;
241 synchronized (James.class) {
242 localCount = count++;
243 }
244 StringBuffer idBuffer = new StringBuffer(64).append("Mail").append(
245 System.currentTimeMillis()).append("-").append(localCount);
246 return idBuffer.toString();
247 }
248
249 /***
250 * @see org.apache.mailet.GenericMailet#init()
251 */
252 public void init() throws MessagingException {
253 super.init();
254 ServiceManager compMgr = (ServiceManager) getMailetContext()
255 .getAttribute(Constants.AVALON_COMPONENT_MANAGER);
256
257 try {
258
259 mailServer = (MailServer) compMgr.lookup(MailServer.ROLE);
260 } catch (ServiceException cnfe) {
261 log("Failed to retrieve MailServer component:" + cnfe.getMessage());
262 } catch (Exception e) {
263 log("Failed to retrieve MailServer component:" + e.getMessage());
264 }
265
266 try {
267
268 store = (Store) compMgr.lookup(Store.ROLE);
269 } catch (ServiceException cnfe) {
270 log("Failed to retrieve Store component:" + cnfe.getMessage());
271 } catch (Exception e) {
272 log("Failed to retrieve Store component:" + e.getMessage());
273 }
274
275 repositoryUrl = getInitParameter("repositoryUrl");
276 if (repositoryUrl != null) {
277 repositoryType = getInitParameter("repositoryType");
278 if (repositoryType == null)
279 repositoryType = "MAIL";
280 }
281
282 deliveryHeader = getInitParameter("addDeliveryHeader");
283 String resetReturnPathString = getInitParameter("resetReturnPath");
284 resetReturnPath = "true".equalsIgnoreCase(resetReturnPathString);
285 }
286
287 /***
288 * Get the user inbox: if the repositoryUrl is null then get the userinbox
289 * from the mailserver, otherwise lookup the store with the given
290 * repositoryurl/type
291 *
292 * @param userName
293 * @return
294 */
295 private MailRepository getRepository(String userName) {
296 MailRepository userInbox;
297 if (repositoryUrl == null) {
298 userInbox = mailServer.getUserInbox(userName);
299 } else {
300 StringBuffer destinationBuffer = new StringBuffer(192).append(
301 repositoryUrl).append(userName).append("/");
302 String destination = destinationBuffer.toString();
303 DefaultConfiguration mboxConf = new DefaultConfiguration(
304 "repository", "generated:ToMultiRepository.getUserInbox()");
305 mboxConf.setAttribute("destinationURL", destination);
306 mboxConf.setAttribute("type", repositoryType);
307 try {
308 userInbox = (MailRepository) store.select(mboxConf);
309 } catch (Exception e) {
310 log("Cannot open repository " + e);
311 userInbox = null;
312 }
313 }
314 return userInbox;
315 }
316
317 }