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 package org.apache.jsieve.mailet;
20
21 import javax.mail.MessagingException;
22 import javax.mail.internet.MimeMessage;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.jsieve.mail.Action;
26 import org.apache.jsieve.mail.ActionFileInto;
27 import org.apache.mailet.Mail;
28 import org.apache.mailet.MailAddress;
29
30 /**
31 * Performs the filing of a mail into a specified destination.
32 * <h4>Thread Safety</h4>
33 * <p>An instance maybe safe accessed concurrently by multiple threads.</p>
34 */
35 public class FileIntoAction implements MailAction {
36
37 private static final char HIERARCHY_DELIMITER = '.';
38
39 public void execute(Action action, Mail mail, ActionContext context) throws MessagingException {
40 if (action instanceof ActionFileInto) {
41 final ActionFileInto fileIntoAction = (ActionFileInto) action;
42 execute(fileIntoAction, mail, context);
43 }
44 }
45
46 /**
47 * <p>
48 * Executes the passed ActionFileInto.
49 * </p>
50 *
51 * <p>
52 * This implementation accepts any destination with the root of <code>INBOX</code>.
53 * </p>
54 *
55 * <p>
56 * As the current POP3 server does not support sub-folders, the mail is
57 * stored in the INBOX for the recipient of the mail and the full intended
58 * destination added as a prefix to the message's subject.
59 * </p>
60 *
61 * <p>
62 * When IMAP support is added to James, it will be possible to support
63 * sub-folders of <code>INBOX</code> fully.
64 * </p>
65 *
66 * @param anAction
67 * @param aMail
68 * @param context not null
69 * @throws MessagingException
70 */
71 @SuppressWarnings("deprecation")
72 public void execute(ActionFileInto anAction, Mail aMail, final ActionContext context) throws MessagingException
73 {
74 String destinationMailbox = anAction.getDestination();
75 MailAddress recipient;
76 boolean delivered = false;
77 try
78 {
79 recipient = ActionUtils.getSoleRecipient(aMail);
80 MimeMessage localMessage = createMimeMessage(aMail, recipient);
81
82 if (!(destinationMailbox.length() > 0
83 && destinationMailbox.charAt(0) == HIERARCHY_DELIMITER)) {
84 destinationMailbox = HIERARCHY_DELIMITER + destinationMailbox;
85 }
86
87 final String mailbox = destinationMailbox.replace(HIERARCHY_DELIMITER, '/');
88 final String host;
89 if (mailbox.charAt(0) == '/') {
90 host = "@localhost";
91 } else {
92 host = "@localhost/";
93 }
94 final String url = "mailbox://" + recipient.getUser() + host + mailbox;
95 //TODO: copying this message so many times seems a waste
96 context.post(url, localMessage);
97 delivered = true;
98 }
99 catch (MessagingException ex)
100 {
101 final Log log = context.getLog();
102 if (log.isDebugEnabled()) {
103 log.debug("Error while storing mail into. "+destinationMailbox, ex);
104 }
105 throw ex;
106 }
107 finally
108 {
109 // Ensure the mail is always ghosted
110 aMail.setState(Mail.GHOST);
111 }
112 if (delivered)
113 {
114 final Log log = context.getLog();
115 if (log.isDebugEnabled()) {
116 log.debug("Filed Message ID: "
117 + aMail.getMessage().getMessageID()
118 + " into destination: \""
119 + destinationMailbox + "\"");
120 }
121 }
122 }
123
124 private static MimeMessage createMimeMessage(Mail aMail, MailAddress recipient) throws MessagingException {
125 // Adapted from LocalDelivery Mailet
126 // Add qmail's de facto standard Delivered-To header
127 MimeMessage localMessage = new MimeMessage(aMail.getMessage())
128 {
129 protected void updateHeaders() throws MessagingException
130 {
131 if (getMessageID() == null)
132 super.updateHeaders();
133 else
134 modified = false;
135 }
136 };
137 localMessage.addHeader("Delivered-To", recipient.toString());
138
139 localMessage.saveChanges();
140 return localMessage;
141 }
142 }