1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.jsieve.mailet;
21
22 import java.io.InputStream;
23 import java.util.Collection;
24 import java.util.Enumeration;
25 import java.util.Iterator;
26 import java.util.Vector;
27
28 import javax.mail.Header;
29 import javax.mail.MessagingException;
30 import javax.mail.internet.InternetHeaders;
31 import javax.mail.internet.MimeMessage;
32
33 import org.apache.commons.logging.Log;
34 import org.apache.jsieve.ConfigurationManager;
35 import org.apache.jsieve.SieveConfigurationException;
36 import org.apache.jsieve.SieveFactory;
37 import org.apache.mailet.Mail;
38 import org.apache.mailet.MailAddress;
39 import org.apache.mailet.MailetConfig;
40 import org.apache.mailet.MailetException;
41 import org.apache.mailet.base.GenericMailet;
42 import org.apache.mailet.base.RFC2822Headers;
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class SieveMailboxMailet extends GenericMailet {
57
58
59
60
61 private String deliveryHeader;
62
63
64
65
66 private boolean resetReturnPath;
67
68 private Poster poster;
69
70 private ResourceLocator locator;
71
72
73 private boolean verbose = false;
74
75 private boolean consume = true;
76
77 private boolean quiet = true;
78
79 private SieveFactory factory;
80
81 private ActionDispatcher actionDispatcher;
82
83 private Log log;
84
85
86
87
88 public SieveMailboxMailet() {}
89
90
91
92
93
94 public SieveMailboxMailet(Poster poster, ResourceLocator locator) {
95 this();
96 this.poster = poster;
97 this.locator = locator;
98 }
99
100
101 public ResourceLocator getLocator() {
102 return locator;
103 }
104
105
106
107
108
109 public void setLocator(ResourceLocator locator) {
110 this.locator = locator;
111 }
112
113 public Poster getPoster() {
114 return poster;
115 }
116
117
118
119
120
121 public void setPoster(Poster poster) {
122 this.poster = poster;
123 }
124
125
126
127
128
129 public boolean isConsume() {
130 return consume;
131 }
132
133
134
135
136
137
138 public void setConsume(boolean consume) {
139 this.consume = consume;
140 }
141
142
143
144
145
146
147 public boolean isVerbose() {
148 return verbose;
149 }
150
151
152
153
154
155
156
157
158
159 public void setVerbose(boolean verbose) {
160 this.verbose = verbose;
161 }
162
163
164
165
166
167 public boolean isQuiet() {
168 return quiet;
169 }
170
171
172
173
174
175
176 public void setQuiet(boolean quiet) {
177 this.quiet = quiet;
178 }
179
180
181
182
183
184
185 public boolean isInfoLoggingOn() {
186 return verbose || !quiet;
187 }
188
189 @Override
190 public void init(MailetConfig config) throws MessagingException {
191
192 super.init(config);
193
194 try {
195 final ConfigurationManager configurationManager = new ConfigurationManager();
196 final int logLevel;
197 if (verbose) {
198 logLevel = CommonsLoggingAdapter.TRACE;
199 } else if (quiet) {
200 logLevel = CommonsLoggingAdapter.FATAL;
201 } else {
202 logLevel = CommonsLoggingAdapter.WARN;
203 }
204 log = new CommonsLoggingAdapter(this, logLevel);
205 configurationManager.setLog(log);
206 factory = configurationManager.build();
207 } catch (SieveConfigurationException e) {
208 throw new MessagingException("Failed to load standard Sieve configuration.", e);
209 }
210 }
211
212
213
214
215
216
217
218
219
220
221 @SuppressWarnings("unchecked")
222 @Override
223 public void service(Mail mail) throws MessagingException {
224 Collection<MailAddress> recipients = mail.getRecipients();
225 Collection<MailAddress> errors = new Vector<MailAddress>();
226
227 MimeMessage message = null;
228 if (deliveryHeader != null || resetReturnPath) {
229 message = mail.getMessage();
230 }
231
232 if (resetReturnPath) {
233
234
235
236
237 message.setHeader(RFC2822Headers.RETURN_PATH,
238 (mail.getSender() == null ? "<>" : "<" + mail.getSender()
239 + ">"));
240 }
241
242 Enumeration headers;
243 InternetHeaders deliveredTo = new InternetHeaders();
244 if (deliveryHeader != null) {
245
246 headers = message
247 .getMatchingHeaders(new String[] { deliveryHeader });
248 while (headers.hasMoreElements()) {
249 Header header = (Header) headers.nextElement();
250 deliveredTo.addHeader(header.getName(), header.getValue());
251 }
252 }
253
254 for (Iterator<MailAddress> i = recipients.iterator(); i.hasNext();) {
255 MailAddress recipient = i.next();
256 try {
257 if (deliveryHeader != null) {
258
259 message.addHeader(deliveryHeader, recipient.toString());
260 }
261
262 storeMail(mail.getSender(), recipient, mail);
263
264 if (deliveryHeader != null) {
265 if (i.hasNext()) {
266
267 message.removeHeader(deliveryHeader);
268 headers = deliveredTo.getAllHeaders();
269
270 while (headers.hasMoreElements()) {
271 Header header = (Header) headers.nextElement();
272 message.addHeader(header.getName(), header
273 .getValue());
274 }
275 }
276 }
277 } catch (Exception ex) {
278 log("Error while storing mail.", ex);
279 errors.add(recipient);
280 }
281 }
282
283 if (!errors.isEmpty()) {
284
285
286
287
288
289
290
291 getMailetContext().sendMail(mail.getSender(), errors,
292 mail.getMessage(), Mail.ERROR);
293 }
294 if (consume) {
295
296 mail.setState(Mail.GHOST);
297 }
298 }
299
300
301
302
303
304
305 @Override
306 public String getMailetInfo() {
307 return "Sieve Mailbox Mailet";
308 }
309
310
311
312
313
314
315
316
317 @SuppressWarnings("deprecation")
318 public void storeMail(MailAddress sender, MailAddress recipient,
319 Mail mail) throws MessagingException {
320 String username;
321 if (recipient == null) {
322 throw new IllegalArgumentException(
323 "Recipient for mail to be spooled cannot be null.");
324 }
325 if (mail.getMessage() == null) {
326 throw new IllegalArgumentException(
327 "Mail message to be spooled cannot be null.");
328 }
329
330 username = recipient.getUser();
331
332 sieveMessage(username, mail);
333
334 }
335
336 void sieveMessage(String username, Mail aMail) throws MessagingException {
337
338 String relativeUri = "//" + username + "@" + "localhost/sieve";
339 try
340 {
341 final InputStream ins = locator.get(relativeUri);
342
343 SieveMailAdapter aMailAdapter = new SieveMailAdapter(aMail,
344 getMailetContext(), actionDispatcher, poster);
345 aMailAdapter.setLog(log);
346
347 if (verbose) {
348 log("Evaluating " + aMailAdapter.toString() + "against \""
349 + relativeUri + "\"");
350 }
351 factory.evaluate(aMailAdapter, factory.parse(ins));
352 }
353 catch (Exception ex)
354 {
355
356
357
358
359
360
361 if (isInfoLoggingOn()) {
362 log("Cannot evaluate Sieve script. Storing mail in user INBOX.", ex);
363 }
364 storeMessageInbox(username, aMail);
365 }
366 }
367
368 void storeMessageInbox(String username, Mail mail) throws MessagingException {
369 String url = "mailbox://" + username + "@localhost/";
370 poster.post(url, mail.getMessage());
371 }
372
373
374
375
376 @Override
377 public void init() throws MessagingException {
378 super.init();
379 if (poster == null || locator == null) {
380 throw new MailetException("Not initialised. Please ensure that the mailet container supports either" +
381 " setter or constructor injection");
382 }
383
384 this.deliveryHeader = getInitParameter("addDeliveryHeader");
385 this.resetReturnPath = getInitParameter("resetReturnPath", true);
386 this.consume = getInitParameter("consume", true);
387 this.verbose = getInitParameter("verbose", false);
388 this.quiet = getInitParameter("quiet", false);
389
390 actionDispatcher = new ActionDispatcher();
391 }
392 }