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