You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rd...@apache.org on 2008/12/23 23:33:48 UTC

svn commit: r729150 - /james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/

Author: rdonkin
Date: Tue Dec 23 14:33:48 2008
New Revision: 729150

URL: http://svn.apache.org/viewvc?rev=729150&view=rev
Log:
Revise dispatch in favour of a system that uses interfaces (rather than reflection). Introduced ActionContext to group minor parameters together.

Added:
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionContext.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionUtils.java
      - copied, changed from r729074, james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/Actions.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/FileIntoAction.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/KeepAction.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/MailAction.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RedirectAction.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RejectAction.java
Removed:
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/Actions.java
Modified:
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionDispatcher.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailAdapter.java
    james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailboxMailet.java

Added: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionContext.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionContext.java?rev=729150&view=auto
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionContext.java (added)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionContext.java Tue Dec 23 14:33:48 2008
@@ -0,0 +1,65 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.jsieve.mailet;
+
+import java.util.Collection;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.commons.logging.Log;
+import org.apache.mailet.MailAddress;
+
+/**
+ * Provides context for action execution.
+ */
+public interface ActionContext {
+    
+    /**
+     * Gets the log.
+     * @return not null
+     */
+    public Log getLog();
+    
+    /**
+     * Experimental mail delivery. 
+     * POST verb indicate that mail should be attached to the collection
+     * indicated by the given URI.
+     * 
+     * @param uri indicates the destination to which the mail to added. ATM 
+     * the value should be mailbox://<user>@localhost/<mailbox-path>
+     * @param mail not null
+     */
+    public void post(String uri, MimeMessage mail) throws MessagingException;
+
+    /**
+     * Posts the given mail.
+     * @param sender possibly null
+     * @param recipients not null
+     * @param mail not null
+     * @throws MessagingException when mail cannot be posted
+     */
+    public void post(MailAddress sender, Collection recipients, MimeMessage mail) throws MessagingException;
+
+    /**
+     * Gets name (including version) of this server.
+     * @return not nul
+     */
+    public String getServerInfo();
+}

Modified: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionDispatcher.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionDispatcher.java?rev=729150&r1=729149&r2=729150&view=diff
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionDispatcher.java (original)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionDispatcher.java Tue Dec 23 14:33:48 2008
@@ -19,8 +19,6 @@
 
 package org.apache.jsieve.mailet;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -32,19 +30,18 @@
 import org.apache.jsieve.mail.ActionRedirect;
 import org.apache.jsieve.mail.ActionReject;
 import org.apache.mailet.Mail;
-import org.apache.mailet.MailetContext;
 
 /**
- * Singleton Class <code>ActionDispatcher</code> dynamically dispatches 
- * an Action depending on the type of Action received at runtime. 
+ * Dynamically dispatches an Action depending on the type of Action received at runtime. 
  */
 public class ActionDispatcher
 {   
     /**
      * A Map keyed by the type of Action. The values are the methods to invoke to 
      * handle the Action.
+     * <Action, MailAction>
      */ 
-    private Map fieldMethodMap;
+    private Map/*<Action, MailAction>*/ fieldMailActionMap;
 
     /**
      * Constructor for ActionDispatcher.
@@ -55,104 +52,50 @@
         super();
         setMethodMap(defaultMethodMap());
     }
-     
+
     /**
      * Method execute executes the passed Action by invoking the method mapped by the
      * receiver with a parameter of the EXACT type of Action.
-     * @param anAction
-     * @param aMail
-     * @param aMailetContext
-     * @throws NoSuchMethodException
-     * @throws IllegalAccessException
-     * @throws InvocationTargetException
+     * @param anAction not null
+     * @param aMail not null
+     * @param context not null
      * @throws MessagingException
      */
-    public void execute(
-        Action anAction,
-        Mail aMail,
-        MailetContext aMailetContext)
-        throws
-            NoSuchMethodException,
-            IllegalAccessException,
-            InvocationTargetException,
-            MessagingException
+    public void execute(final Action anAction, final Mail aMail, final ActionContext context) throws MessagingException
     {
-        Method actionMethod = (Method) getMethodMap().get(anAction.getClass());
-        if (null == actionMethod)
-            throw new NoSuchMethodException(
-                "Method accepting parameters ("
-                    + anAction.getClass().getName()
-                    + ", "
-                    + aMail.getClass().getName()
-                    + ", "
-                    + aMailetContext.getClass().getName()
-                    + ") not mapped.");
-        actionMethod.invoke(
-            null,
-            new Object[] { anAction, aMail, aMailetContext });
+        MailAction mailAction = (MailAction) getMethodMap().get(anAction.getClass());
+        mailAction.execute(anAction, aMail, context);
     }
-    
+
     /**
      * Returns the methodMap.
      * @return Map
      */
     public Map getMethodMap()
     {
-        return fieldMethodMap;
+        return fieldMailActionMap;
     }    
-    
+
     /**
      * Returns a new methodMap.
      * @return Map
      */
-    private Map defaultMethodMap() throws MessagingException
+    private Map defaultMethodMap()
     {
-        try {
-            Map methodNameMap = new HashMap();
-            methodNameMap.put(
-                ActionFileInto.class,
-                Actions.class.getMethod(
-                    "execute",
-                    new Class[] {
-                        ActionFileInto.class,
-                        Mail.class,
-                        MailetContext.class }));
-            methodNameMap.put(
-                ActionKeep.class,
-                Actions.class.getMethod(
-                    "execute",
-                    new Class[] {
-                        ActionKeep.class,
-                        Mail.class,
-                        MailetContext.class }));
-            methodNameMap.put(
-                ActionRedirect.class,
-                Actions.class.getMethod(
-                    "execute",
-                    new Class[] {
-                        ActionRedirect.class,
-                        Mail.class,
-                        MailetContext.class }));
-            methodNameMap.put(
-                ActionReject.class,
-                Actions.class.getMethod(
-                    "execute",
-                    new Class[] {
-                        ActionReject.class,
-                        Mail.class,
-                        MailetContext.class }));
-            return methodNameMap;
-        } catch (NoSuchMethodException e) {
-            throw new MessagingException("Require method missing from action.", e);
-        }
+        Map/*<Action, MailAction>*/ actionMap = new HashMap/*<Action, MailAction>*/(4);
+        actionMap.put(ActionFileInto.class, new FileIntoAction());
+        actionMap.put(ActionKeep.class, new KeepAction());
+        actionMap.put(ActionRedirect.class, new RedirectAction());
+        actionMap.put(ActionReject.class, new RejectAction());
+        return actionMap;
     }    
 
     /**
-     * Sets the methodMap.
-     * @param methodMap The methodMap to set
+     * Sets the mail action mail.
+     * @param mailActionMap <Action, MailAction> not null
      */
-    protected void setMethodMap(Map methodMap)
+    protected void setMethodMap(Map/*<Action, MailAction>*/  mailActionMap)
     {
-        fieldMethodMap = methodMap;
+        fieldMailActionMap = mailActionMap;
     }
 }

Copied: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionUtils.java (from r729074, james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/Actions.java)
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionUtils.java?p2=james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionUtils.java&p1=james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/Actions.java&r1=729074&r2=729150&rev=729150&view=diff
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/Actions.java (original)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/ActionUtils.java Tue Dec 23 14:33:48 2008
@@ -19,267 +19,18 @@
 
 package org.apache.jsieve.mailet;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Collection;
-
-import javax.mail.Address;
 import javax.mail.MessagingException;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
 
-import org.apache.mailet.base.mail.mdn.ActionModeAutomatic;
-import org.apache.mailet.base.mail.mdn.Disposition;
-import org.apache.mailet.base.mail.mdn.DispositionModifier;
-import org.apache.mailet.base.mail.mdn.MDNFactory;
-import org.apache.mailet.base.mail.mdn.ModifierError;
-import org.apache.mailet.base.mail.mdn.SendingModeAutomatic;
-import org.apache.mailet.base.mail.mdn.TypeDeleted;
-import org.apache.jsieve.mail.ActionFileInto;
-import org.apache.jsieve.mail.ActionKeep;
-import org.apache.jsieve.mail.ActionRedirect;
-import org.apache.jsieve.mail.ActionReject;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailAddress;
-import org.apache.mailet.MailetContext;
 
 /**
- * Singleton Class <code>Actions</code> implements <code>execute()</code>
- * methods for each of the supported Actions.
+ * Utility methods helpful for actions.
  */
-public class Actions
+public class ActionUtils
 {
-    private static final String INBOX = "INBOX";
-    private static final char HIERARCHY_DELIMITER = '.';
-    static private String fieldAttributePrefix;
-
-    /**
-     * Constructor for Actions.
-     */
-    private Actions()
-    {
-        super();
-    }
-
-    /**
-     * <p>
-     * Executes the passed ActionFileInto.
-     * </p>
-     * 
-     * <p>
-     * This implementation accepts any destination with the root of <code>INBOX</code>.
-     * </p>
-     * 
-     * <p>
-     * As the current POP3 server does not support sub-folders, the mail is
-     * stored in the INBOX for the recipient of the mail and the full intended
-     * destination added as a prefix to the message's subject.
-     * </p>
-     * 
-     * <p>
-     * When IMAP support is added to James, it will be possible to support
-     * sub-folders of <code>INBOX</code> fully.
-     * </p>
-     * 
-     * @param anAction
-     * @param aMail
-     * @param aMailetContext
-     * @param poster TODO
-     * @throws MessagingException
-     */
-    static public void execute(ActionFileInto anAction, Mail aMail,
-            MailetContext aMailetContext, Poster poster) throws MessagingException
-    {
-        String destinationMailbox = anAction.getDestination();
-        MailAddress recipient;
-        boolean delivered = false;
-        try
-        {
-            recipient = getSoleRecipient(aMail);
-            MimeMessage localMessage = createMimeMessage(aMail, recipient);
-            
-            if (!(destinationMailbox.length() > 0 
-                    && destinationMailbox.charAt(0) == HIERARCHY_DELIMITER)) {
-                destinationMailbox =  HIERARCHY_DELIMITER + destinationMailbox;
-            }
-            
-            final String url = "mailbox://" + recipient.getUser() + "@localhost/" + 
-                destinationMailbox.replace(HIERARCHY_DELIMITER, '/');
-            //TODO: copying this message so many times seems a waste
-            poster.post(url, localMessage);
-            delivered = true;
-        }
-        catch (MessagingException ex)
-        {
-            aMailetContext.log("Error while storing mail into. "+destinationMailbox, ex);
-            throw ex;
-        }
-        finally
-        {
-            // Ensure the mail is always ghosted
-            aMail.setState(Mail.GHOST);
-        }
-        if (delivered)
-        {
-            aMailetContext.log("Filed Message ID: "
-                    + aMail.getMessage().getMessageID()
-                    + " into destination: \""
-                    + destinationMailbox + "\"");
-        }
-    }
-
-    private static MimeMessage createMimeMessage(Mail aMail, MailAddress recipient) throws MessagingException {
-        // Adapted from LocalDelivery Mailet
-        // Add qmail's de facto standard Delivered-To header
-        MimeMessage localMessage = new MimeMessage(aMail.getMessage())
-        {
-            protected void updateHeaders() throws MessagingException
-            {
-                if (getMessageID() == null)
-                    super.updateHeaders();
-                else
-                    modified = false;
-            }
-        };
-        localMessage.addHeader("Delivered-To", recipient.toString());
-
-        localMessage.saveChanges();
-        return localMessage;
-    }
-
-    /**
-     * <p>
-     * Executes the passed ActionKeep.
-     * </p>
-     * 
-     * <p>
-     * In this implementation, "keep" is equivalent to "fileinto" with a
-     * destination of "INBOX".
-     * </p>
-     * 
-     * @param anAction
-     * @param aMail
-     * @param aMailetContext
-     * @throws MessagingException
-     */
-    public static void execute(ActionKeep anAction, Mail aMail,
-            MailetContext aMailetContext, Poster poster) throws MessagingException
-    {
-        final ActionFileInto action = new ActionFileInto(INBOX);
-        execute(action, aMail, aMailetContext, poster);
-    }
-
-    /**
-     * Method execute executes the passed ActionRedirect.
-     * 
-     * @param anAction
-     * @param aMail
-     * @param aMailetContext
-     * @throws MessagingException
-     */
-    public static void execute(ActionRedirect anAction, Mail aMail,
-            MailetContext aMailetContext) throws MessagingException
-    {
-        detectAndHandleLocalLooping(aMail, aMailetContext, "redirect");
-        Collection recipients = new ArrayList(1);
-        recipients.add(new InternetAddress(anAction.getAddress()));
-        aMailetContext.sendMail(aMail.getSender(), recipients, aMail
-                .getMessage());
-        aMail.setState(Mail.GHOST);
-        aMailetContext.log("Redirected Message ID: "
-                + aMail.getMessage().getMessageID() + " to \""
-                + anAction.getAddress() + "\"");
-    }
-
-    /**
-     * <p>
-     * Method execute executes the passed ActionReject. It sends an RFC 2098
-     * compliant reject MDN back to the sender.
-     * </p>
-     * <p>
-     * NOTE: The Mimecontent type should be 'report', but as we do not yet have
-     * a DataHandler for this yet, its currently 'text'!
-     * 
-     * @param anAction
-     * @param aMail
-     * @param aMailetContext
-     * @throws MessagingException
-     */
-    public static void execute(ActionReject anAction, Mail aMail,
-            MailetContext aMailetContext) throws MessagingException
-    {
-        detectAndHandleLocalLooping(aMail, aMailetContext, "reject");
-
-        // Create the MDN part
-        StringBuffer humanText = new StringBuffer(128);
-        humanText
-                .append("This message was refused by the recipient's mail filtering program.");
-        humanText.append("\r\n");
-        humanText.append("The reason given was:");
-        humanText.append("\r\n");
-        humanText.append("\r\n");
-        humanText.append(anAction.getMessage());
-
-        String reporting_UA_name = null;
-        try
-        {
-            reporting_UA_name = InetAddress.getLocalHost()
-                    .getCanonicalHostName();
-        }
-        catch (UnknownHostException ex)
-        {
-            reporting_UA_name = "localhost";
-        }
-
-        String reporting_UA_product = aMailetContext.getServerInfo();
-
-        String[] originalRecipients = aMail.getMessage().getHeader(
-                "Original-Recipient");
-        String original_recipient = null;
-        if (null != originalRecipients && originalRecipients.length > 0)
-        {
-            original_recipient = originalRecipients[0];
-        }
-
-        MailAddress soleRecipient = getSoleRecipient(aMail);
-        String final_recipient = soleRecipient.toString();
-
-        String original_message_id = aMail.getMessage().getMessageID();
-
-        DispositionModifier modifiers[] = {new ModifierError()};
-        Disposition disposition = new Disposition(new ActionModeAutomatic(),
-                new SendingModeAutomatic(), new TypeDeleted(), modifiers);
-
-        MimeMultipart multiPart = MDNFactory.create(humanText.toString(),
-                reporting_UA_name, reporting_UA_product, original_recipient,
-                final_recipient, original_message_id, disposition);
-
-        // Send the message
-        MimeMessage reply = (MimeMessage) aMail.getMessage().reply(false);
-        reply.setFrom(soleRecipient.toInternetAddress());
-        reply.setContent(multiPart);
-        reply.saveChanges();
-        Address[] recipientAddresses = reply.getAllRecipients();
-        if (null != recipientAddresses)
-        {
-            Collection recipients = new ArrayList(recipientAddresses.length);
-            for (int i = 0; i < recipientAddresses.length; i++)
-            {
-                recipients.add(new MailAddress(
-                        (InternetAddress) recipientAddresses[i]));
-            }
-            aMailetContext.sendMail(null, recipients, reply);
-        }
-        else
-        {
-            aMailetContext
-                    .log("Unable to send reject MDN. Could not determine the recipient.");
-        }
-        // Ghost the original mail
-        aMail.setState(Mail.GHOST);
-    }
+    
+    private final static String ATTRIBUTE_PREFIX = ActionUtils.class.getPackage().getName() + ".";
 
     /**
      * Answers the sole intended recipient for aMail.
@@ -288,13 +39,12 @@
      * @return String
      * @throws MessagingException
      */
-    protected static MailAddress getSoleRecipient(Mail aMail)
-            throws MessagingException
+    public static MailAddress getSoleRecipient(Mail aMail) throws MessagingException
     {
-          if (aMail.getRecipients() == null) {
-          throw new MessagingException("Invalid number of recipients - 0"
-              + ". Exactly 1 recipient is expected.");
-          } else if (1 != aMail.getRecipients().size())
+        if (aMail.getRecipients() == null) {
+            throw new MessagingException("Invalid number of recipients - 0"
+                    + ". Exactly 1 recipient is expected.");
+        } else if (1 != aMail.getRecipients().size())
             throw new MessagingException("Invalid number of recipients - "
                     + new Integer(aMail.getRecipients().size()).toString()
                     + ". Exactly 1 recipient is expected.");
@@ -302,84 +52,29 @@
     }
 
     /**
-     * Returns a lazy initialised attributePrefix.
-     * 
-     * @return String
-     */
-    protected static String getAttributePrefix()
-    {
-        String value = null;
-        if (null == (value = getAttributePrefixBasic()))
-        {
-            updateAttributePrefix();
-            return getAttributePrefix();
-        }
-        return value;
-    }
-
-    /**
-     * Returns the attributePrefix.
-     * 
-     * @return String
-     */
-    private static String getAttributePrefixBasic()
-    {
-        return fieldAttributePrefix;
-    }
-
-    /**
-     * Returns the computed attributePrefix.
-     * 
-     * @return String
-     */
-    protected static String computeAttributePrefix()
-    {
-        return Actions.class.getPackage().getName() + ".";
-    }
-
-    /**
-     * Sets the attributePrefix.
-     * 
-     * @param attributePrefix The attributePrefix to set
-     */
-    protected static void setAttributePrefix(String attributePrefix)
-    {
-        fieldAttributePrefix = attributePrefix;
-    }
-
-    /**
-     * Updates the attributePrefix.
-     */
-    protected static void updateAttributePrefix()
-    {
-        setAttributePrefix(computeAttributePrefix());
-    }
-
-    /**
      * Detect and handle locally looping mail. External loop detection is left
      * to the MTA.
      * 
      * @param aMail
-     * @param aMailetContext
+     * @param context not null
      * @param anAttributeSuffix
      * @throws MessagingException
      */
-    protected static void detectAndHandleLocalLooping(Mail aMail,
-            MailetContext aMailetContext, String anAttributeSuffix)
+    public static void detectAndHandleLocalLooping(Mail aMail, ActionContext context, String anAttributeSuffix)
             throws MessagingException
     {
         MailAddress thisRecipient = getSoleRecipient(aMail);
         MailAddress lastRecipient = (MailAddress) aMail
-                .getAttribute(getAttributePrefix() + anAttributeSuffix);
+                .getAttribute(ATTRIBUTE_PREFIX + anAttributeSuffix);
         if (null != lastRecipient && lastRecipient.equals(thisRecipient))
         {
             MessagingException ex = new MessagingException(
                     "This message is looping! Message ID: "
                             + aMail.getMessage().getMessageID());
-            aMailetContext.log(ex.getMessage(), ex);
+            context.getLog().warn(ex.getMessage(), ex);
             throw ex;
         }
-        aMail.setAttribute(getAttributePrefix() + anAttributeSuffix,
+        aMail.setAttribute(ATTRIBUTE_PREFIX + anAttributeSuffix,
                 thisRecipient);
     }
 }

Added: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/FileIntoAction.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/FileIntoAction.java?rev=729150&view=auto
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/FileIntoAction.java (added)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/FileIntoAction.java Tue Dec 23 14:33:48 2008
@@ -0,0 +1,130 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.jsieve.mailet;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.commons.logging.Log;
+import org.apache.jsieve.mail.Action;
+import org.apache.jsieve.mail.ActionFileInto;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+public class FileIntoAction implements MailAction {
+    
+    private static final char HIERARCHY_DELIMITER = '.';
+
+    public void execute(Action action, Mail mail, ActionContext context) throws MessagingException {
+        if (action instanceof ActionFileInto) {
+            final ActionFileInto fileIntoAction = (ActionFileInto) action;
+            execute(fileIntoAction, mail, context);
+        }
+    }
+
+    /**
+     * <p>
+     * Executes the passed ActionFileInto.
+     * </p>
+     * 
+     * <p>
+     * This implementation accepts any destination with the root of <code>INBOX</code>.
+     * </p>
+     * 
+     * <p>
+     * As the current POP3 server does not support sub-folders, the mail is
+     * stored in the INBOX for the recipient of the mail and the full intended
+     * destination added as a prefix to the message's subject.
+     * </p>
+     * 
+     * <p>
+     * When IMAP support is added to James, it will be possible to support
+     * sub-folders of <code>INBOX</code> fully.
+     * </p>
+     * 
+     * @param anAction
+     * @param aMail
+     * @param context not null
+     * @throws MessagingException
+     */
+    public void execute(ActionFileInto anAction, Mail aMail, final ActionContext context) throws MessagingException
+    {
+        String destinationMailbox = anAction.getDestination();
+        MailAddress recipient;
+        boolean delivered = false;
+        try
+        {
+            recipient = ActionUtils.getSoleRecipient(aMail);
+            MimeMessage localMessage = createMimeMessage(aMail, recipient);
+            
+            if (!(destinationMailbox.length() > 0 
+                    && destinationMailbox.charAt(0) == HIERARCHY_DELIMITER)) {
+                destinationMailbox =  HIERARCHY_DELIMITER + destinationMailbox;
+            }
+            
+            final String url = "mailbox://" + recipient.getUser() + "@localhost/" + 
+                destinationMailbox.replace(HIERARCHY_DELIMITER, '/');
+            //TODO: copying this message so many times seems a waste
+            context.post(url, localMessage);
+            delivered = true;
+        }
+        catch (MessagingException ex)
+        {
+            final Log log = context.getLog();
+            if (log.isDebugEnabled()) {
+                log.debug("Error while storing mail into. "+destinationMailbox, ex);
+            }
+            throw ex;
+        }
+        finally
+        {
+            // Ensure the mail is always ghosted
+            aMail.setState(Mail.GHOST);
+        }
+        if (delivered)
+        {
+            final Log log = context.getLog();
+            if (log.isDebugEnabled()) {
+                log.debug("Filed Message ID: "
+                    + aMail.getMessage().getMessageID()
+                    + " into destination: \""
+                    + destinationMailbox + "\"");
+            }
+        }
+    }
+    
+    private static MimeMessage createMimeMessage(Mail aMail, MailAddress recipient) throws MessagingException {
+        // Adapted from LocalDelivery Mailet
+        // Add qmail's de facto standard Delivered-To header
+        MimeMessage localMessage = new MimeMessage(aMail.getMessage())
+        {
+            protected void updateHeaders() throws MessagingException
+            {
+                if (getMessageID() == null)
+                    super.updateHeaders();
+                else
+                    modified = false;
+            }
+        };
+        localMessage.addHeader("Delivered-To", recipient.toString());
+
+        localMessage.saveChanges();
+        return localMessage;
+    }
+}

Added: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/KeepAction.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/KeepAction.java?rev=729150&view=auto
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/KeepAction.java (added)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/KeepAction.java Tue Dec 23 14:33:48 2008
@@ -0,0 +1,60 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.jsieve.mailet;
+
+import javax.mail.MessagingException;
+
+import org.apache.jsieve.mail.Action;
+import org.apache.jsieve.mail.ActionFileInto;
+import org.apache.jsieve.mail.ActionKeep;
+import org.apache.mailet.Mail;
+
+public class KeepAction extends FileIntoAction implements MailAction {
+    
+    private static final String INBOX = "INBOX";
+
+    public void execute(Action action, Mail mail, ActionContext context)
+            throws MessagingException {
+        if (action instanceof ActionKeep) {
+            final ActionKeep actionKeep = (ActionKeep) action;
+            execute(actionKeep, mail, context);
+        }
+    }
+
+    /**
+     * <p>
+     * Executes the passed ActionKeep.
+     * </p>
+     * 
+     * <p>
+     * In this implementation, "keep" is equivalent to "fileinto" with a
+     * destination of "INBOX".
+     * </p>
+     * 
+     * @param anAction not null
+     * @param aMail not null
+     * @param context not null
+     * @throws MessagingException
+     */
+    public void execute(ActionKeep anAction, Mail aMail, ActionContext context) throws MessagingException
+    {
+        final ActionFileInto action = new ActionFileInto(INBOX);
+        execute(action, aMail, context);
+    }
+}

Added: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/MailAction.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/MailAction.java?rev=729150&view=auto
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/MailAction.java (added)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/MailAction.java Tue Dec 23 14:33:48 2008
@@ -0,0 +1,39 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.jsieve.mailet;
+
+import javax.mail.MessagingException;
+
+import org.apache.jsieve.mail.Action;
+import org.apache.mailet.Mail;
+
+/**
+ * Executes a Sieve action.
+ */
+public interface MailAction {
+    
+    /**
+     * Executes the given action.
+     * @param action not null
+     * @param mail not null
+     * @param context not null
+     * @throws MessagingException when action cannot be executed
+     */
+    public void execute(final Action action, final Mail mail, final ActionContext context) throws MessagingException;
+}

Added: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RedirectAction.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RedirectAction.java?rev=729150&view=auto
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RedirectAction.java (added)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RedirectAction.java Tue Dec 23 14:33:48 2008
@@ -0,0 +1,67 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.jsieve.mailet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.commons.logging.Log;
+import org.apache.jsieve.mail.Action;
+import org.apache.jsieve.mail.ActionRedirect;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+public class RedirectAction implements MailAction {
+
+    public void execute(Action action, Mail mail, ActionContext context)
+            throws MessagingException {
+        if (action instanceof ActionRedirect) {
+            final ActionRedirect actionRedirect = (ActionRedirect) action;
+            execute(actionRedirect, mail, context);
+        }
+
+    }
+
+    /**
+     * Method execute executes the passed ActionRedirect.
+     * 
+     * @param anAction not nul
+     * @param aMail not null
+     * @param context not null
+     * @throws MessagingException
+     */
+    public void execute(ActionRedirect anAction, Mail aMail, ActionContext context) throws MessagingException
+    {
+        ActionUtils.detectAndHandleLocalLooping(aMail, context, "redirect");
+        Collection recipients = new ArrayList(1);
+        recipients.add(new InternetAddress(anAction.getAddress()));
+        MailAddress sender = aMail.getSender();
+        context.post(sender, recipients, aMail.getMessage());
+        aMail.setState(Mail.GHOST);
+        Log log = context.getLog();
+        if (log.isDebugEnabled()) {
+            log.debug("Redirected Message ID: "
+                + aMail.getMessage().getMessageID() + " to \""
+                + anAction.getAddress() + "\"");
+        }
+    }
+}

Added: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RejectAction.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RejectAction.java?rev=729150&view=auto
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RejectAction.java (added)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/RejectAction.java Tue Dec 23 14:33:48 2008
@@ -0,0 +1,141 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+package org.apache.jsieve.mailet;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.apache.jsieve.mail.Action;
+import org.apache.jsieve.mail.ActionReject;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.mail.mdn.ActionModeAutomatic;
+import org.apache.mailet.base.mail.mdn.Disposition;
+import org.apache.mailet.base.mail.mdn.DispositionModifier;
+import org.apache.mailet.base.mail.mdn.MDNFactory;
+import org.apache.mailet.base.mail.mdn.ModifierError;
+import org.apache.mailet.base.mail.mdn.SendingModeAutomatic;
+import org.apache.mailet.base.mail.mdn.TypeDeleted;
+
+public class RejectAction implements MailAction {
+
+    public void execute(Action action, Mail mail, ActionContext context)
+            throws MessagingException {
+        if (action instanceof ActionReject) {
+            final ActionReject actionReject = (ActionReject) action;
+            execute(actionReject, mail, context);
+        }
+
+    }
+
+    /**
+     * <p>
+     * Method execute executes the passed ActionReject. It sends an RFC 2098
+     * compliant reject MDN back to the sender.
+     * </p>
+     * <p>
+     * NOTE: The Mimecontent type should be 'report', but as we do not yet have
+     * a DataHandler for this yet, its currently 'text'!
+     * 
+     * @param anAction not null
+     * @param aMail not null
+     * @param context not null
+     * @throws MessagingException
+     */
+    public void execute(ActionReject anAction, Mail aMail, ActionContext context) throws MessagingException
+    {
+        ActionUtils.detectAndHandleLocalLooping(aMail, context, "reject");
+
+        // Create the MDN part
+        StringBuffer humanText = new StringBuffer(128);
+        humanText
+                .append("This message was refused by the recipient's mail filtering program.");
+        humanText.append("\r\n");
+        humanText.append("The reason given was:");
+        humanText.append("\r\n");
+        humanText.append("\r\n");
+        humanText.append(anAction.getMessage());
+
+        String reporting_UA_name = null;
+        try
+        {
+            reporting_UA_name = InetAddress.getLocalHost()
+                    .getCanonicalHostName();
+        }
+        catch (UnknownHostException ex)
+        {
+            reporting_UA_name = "localhost";
+        }
+
+        String reporting_UA_product = context.getServerInfo();
+
+        String[] originalRecipients = aMail.getMessage().getHeader(
+                "Original-Recipient");
+        String original_recipient = null;
+        if (null != originalRecipients && originalRecipients.length > 0)
+        {
+            original_recipient = originalRecipients[0];
+        }
+
+        MailAddress soleRecipient = ActionUtils.getSoleRecipient(aMail);
+        String final_recipient = soleRecipient.toString();
+
+        String original_message_id = aMail.getMessage().getMessageID();
+
+        DispositionModifier modifiers[] = {new ModifierError()};
+        Disposition disposition = new Disposition(new ActionModeAutomatic(),
+                new SendingModeAutomatic(), new TypeDeleted(), modifiers);
+
+        MimeMultipart multiPart = MDNFactory.create(humanText.toString(),
+                reporting_UA_name, reporting_UA_product, original_recipient,
+                final_recipient, original_message_id, disposition);
+
+        // Send the message
+        MimeMessage reply = (MimeMessage) aMail.getMessage().reply(false);
+        reply.setFrom(soleRecipient.toInternetAddress());
+        reply.setContent(multiPart);
+        reply.saveChanges();
+        Address[] recipientAddresses = reply.getAllRecipients();
+        if (null != recipientAddresses)
+        {
+            Collection recipients = new ArrayList(recipientAddresses.length);
+            for (int i = 0; i < recipientAddresses.length; i++)
+            {
+                recipients.add(new MailAddress(
+                        (InternetAddress) recipientAddresses[i]));
+            }
+            context.post(null, recipients, reply);
+        }
+        else
+        {
+            context.getLog().info("Unable to send reject MDN. Could not determine the recipient.");
+        }
+        // Ghost the original mail
+        aMail.setState(Mail.GHOST);
+    }
+
+}

Modified: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailAdapter.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailAdapter.java?rev=729150&r1=729149&r2=729150&view=diff
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailAdapter.java (original)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailAdapter.java Tue Dec 23 14:33:48 2008
@@ -19,9 +19,9 @@
 
 package org.apache.jsieve.mailet;
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -30,10 +30,13 @@
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
+
 import javax.mail.Header;
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.james.mime4j.field.address.AddressList;
 import org.apache.james.mime4j.field.address.Mailbox;
 import org.apache.james.mime4j.field.address.MailboxList;
@@ -54,8 +57,12 @@
  * for use in a Mailet environment.
  * </p>
  */
-public class SieveMailAdapter implements MailAdapter, EnvelopeAccessors
+public class SieveMailAdapter implements MailAdapter, EnvelopeAccessors, ActionContext
 {
+    private static final Log LOG = LogFactory.getLog(SieveMailAdapter.class);
+    
+    private Log log = LOG;
+    
     /**
      * The Mail being adapted.
      */
@@ -71,18 +78,27 @@
     
     private final ActionDispatcher dispatcher;
     
+    private final Poster poster;
+    
     /**
      * Constructor for SieveMailAdapter.
      * 
      * @param aMail
      * @param aMailetContext
      */
-    public SieveMailAdapter(final Mail aMail, final MailetContext aMailetContext, final ActionDispatcher dispatcher)
+    public SieveMailAdapter(final Mail aMail, final MailetContext aMailetContext, final ActionDispatcher dispatcher, final Poster poster)
     {
+        this.poster = poster;
         this.dispatcher = dispatcher;
         setMail(aMail);
         setMailetContext(aMailetContext);
     }
+    
+  
+    public void setLog(Log log) {
+        this.log = log;
+    }
+
     /**
      * Returns the message.
      * 
@@ -146,19 +162,7 @@
             getMailetContext().log("Executing action: " + action.toString());
             try
             {
-                dispatcher.execute(action, getMail(), getMailetContext());
-            }
-            catch (NoSuchMethodException e)
-            {
-                throw new SieveException(e);
-            }
-            catch (IllegalAccessException e)
-            {
-                throw new SieveException(e);
-            }
-            catch (InvocationTargetException e)
-            {
-                throw new SieveException(e);
+                dispatcher.execute(action, getMail(), this);
             }
             catch (MessagingException e)
             {
@@ -439,4 +443,19 @@
             return localPart;
         }
     }
+
+    public Log getLog() {
+        return log;
+    }
+    
+    public String getServerInfo() {
+        return getMailetContext().getServerInfo();
+    }
+    public void post(String uri, MimeMessage mail) throws MessagingException {
+        poster.post(uri, mail);
+    }
+    
+    public void post(MailAddress sender, Collection recipients, MimeMessage mail) throws MessagingException {
+        getMailetContext().sendMail(sender, recipients, mail);
+    }
 }

Modified: james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailboxMailet.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailboxMailet.java?rev=729150&r1=729149&r2=729150&view=diff
==============================================================================
--- james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailboxMailet.java (original)
+++ james/jsieve/trunk/mailet/src/main/java/org/apache/jsieve/mailet/SieveMailboxMailet.java Tue Dec 23 14:33:48 2008
@@ -30,10 +30,10 @@
 import javax.mail.internet.InternetHeaders;
 import javax.mail.internet.MimeMessage;
 
+import org.apache.commons.logging.Log;
 import org.apache.jsieve.ConfigurationManager;
 import org.apache.jsieve.SieveConfigurationException;
 import org.apache.jsieve.SieveFactory;
-import org.apache.jsieve.mail.MailAdapter;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailAddress;
 import org.apache.mailet.MailetConfig;
@@ -80,6 +80,8 @@
 
     private ActionDispatcher actionDispatcher;
 
+    private Log log;
+
     /**
      * For SDI
      */
@@ -199,7 +201,8 @@
             } else {
                 logLevel = CommonsLoggingAdapter.WARN;
             }
-            configurationManager.setLog(new CommonsLoggingAdapter(this, logLevel));
+            log = new CommonsLoggingAdapter(this, logLevel);
+            configurationManager.setLog(log);
             factory = configurationManager.build();
         } catch (SieveConfigurationException e) {
             throw new MessagingException("Failed to load standard Sieve configuration.", e);
@@ -333,8 +336,9 @@
         {
             final InputStream ins = locator.get(relativeUri);
             
-            MailAdapter aMailAdapter = new SieveMailAdapter(aMail,
-                    getMailetContext(), actionDispatcher);
+            SieveMailAdapter aMailAdapter = new SieveMailAdapter(aMail,
+                    getMailetContext(), actionDispatcher, poster);
+            aMailAdapter.setLog(log);
             // This logging operation is potentially costly
             if (verbose) {
                 log("Evaluating " + aMailAdapter.toString() + "against \""



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org