View Javadoc

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 }