Author: btellier
Date: Wed Nov 25 16:02:07 2015
New Revision: 1716453

URL: http://svn.apache.org/viewvc?rev=1716453&view=rev
Log:
PROTOCOLS-68 Add a ManageSieve mailet

Added:
    
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/
    
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
    
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/transcode/
    
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/transcode/MessageToCoreToMessage.java
    
james/project/trunk/server/mailet/mailets/src/main/resources/managesieve.help.txt
    
james/project/trunk/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/
    
james/project/trunk/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
    
james/project/trunk/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/MockMail.java
    
james/project/trunk/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/MockMailetConfig.java
    
james/project/trunk/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/MockMailetContext.java
Modified:
    james/project/trunk/server/container/cassandra-guice/pom.xml
    
james/project/trunk/server/container/cassandra-guice/src/test/resources/mailetcontainer.xml
    james/project/trunk/server/mailet/mailets/pom.xml
    james/project/trunk/server/pom.xml

Modified: james/project/trunk/server/container/cassandra-guice/pom.xml
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/container/cassandra-guice/pom.xml?rev=1716453&r1=1716452&r2=1716453&view=diff
==============================================================================
--- james/project/trunk/server/container/cassandra-guice/pom.xml (original)
+++ james/project/trunk/server/container/cassandra-guice/pom.xml Wed Nov 25 
16:02:07 2015
@@ -218,14 +218,6 @@
                 </dependency>
                 <dependency>
                     <groupId>${project.groupId}</groupId>
-                    <artifactId>apache-jsieve-manager-jsieve</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>${project.groupId}</groupId>
-                    <artifactId>apache-jsieve-manager-mailet</artifactId>
-                </dependency>
-                <dependency>
-                    <groupId>${project.groupId}</groupId>
                     <artifactId>apache-mailet-standard</artifactId>
                 </dependency>
                 <dependency>
@@ -338,6 +330,10 @@
                     <artifactId>protocols-imap</artifactId>
                 </dependency>
                 <dependency>
+                    <groupId>org.apache.james.protocols</groupId>
+                    <artifactId>protocols-managesieve</artifactId>
+                </dependency>
+                <dependency>
                     <groupId>com.fasterxml.jackson.core</groupId>
                     <artifactId>jackson-databind</artifactId>
                     <version>2.3.3</version>

Modified: 
james/project/trunk/server/container/cassandra-guice/src/test/resources/mailetcontainer.xml
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/container/cassandra-guice/src/test/resources/mailetcontainer.xml?rev=1716453&r1=1716452&r2=1716453&view=diff
==============================================================================
--- 
james/project/trunk/server/container/cassandra-guice/src/test/resources/mailetcontainer.xml
 (original)
+++ 
james/project/trunk/server/container/cassandra-guice/src/test/resources/mailetcontainer.xml
 Wed Nov 25 16:02:07 2015
@@ -153,7 +153,7 @@
             <mailet match="All" class="SetMailAttribute">
                 
<org.apache.james.SMTPAuthUser>true</org.apache.james.SMTPAuthUser>
             </mailet>
-            <mailet match="All" 
class="org.apache.james.managesieve.mailet.ManageSieveMailet">
+            <mailet match="All" 
class="org.apache.james.transport.mailets.managesieve.ManageSieveMailet">
                 
<helpURL>file:/root/james-server-app-3.0.0-beta5-SNAPSHOT/conf/managesieve.help.txt</helpURL>
             </mailet>
             <mailet match="All" class="Null"/>

Modified: james/project/trunk/server/mailet/mailets/pom.xml
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/mailet/mailets/pom.xml?rev=1716453&r1=1716452&r2=1716453&view=diff
==============================================================================
--- james/project/trunk/server/mailet/mailets/pom.xml (original)
+++ james/project/trunk/server/mailet/mailets/pom.xml Wed Nov 25 16:02:07 2015
@@ -83,6 +83,16 @@
             <!--             </exclusions> -->
         </dependency>
         <dependency>
+            <groupId>org.apache.james.protocols</groupId>
+            <artifactId>protocols-managesieve</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.james.protocols</groupId>
+            <artifactId>protocols-managesieve</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.james</groupId>
             <artifactId>apache-mailet-api</artifactId>
             <scope>compile</scope>

Added: 
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java?rev=1716453&view=auto
==============================================================================
--- 
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
 (added)
+++ 
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
 Wed Nov 25 16:02:07 2015
@@ -0,0 +1,270 @@
+/*
+ *   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.james.transport.mailets.managesieve;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Scanner;
+
+import javax.inject.Inject;
+import javax.mail.MessagingException;
+
+import org.apache.james.managesieve.api.SieveParser;
+import org.apache.james.managesieve.core.CoreProcessor;
+import org.apache.james.managesieve.transcode.LineToCore;
+import org.apache.james.managesieve.transcode.LineToCoreToLine;
+import org.apache.james.managesieve.util.SettableSession;
+import org.apache.james.sieverepository.api.SieveRepository;
+import 
org.apache.james.transport.mailets.managesieve.transcode.MessageToCoreToMessage;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.GenericMailet;
+
+/**
+ * <code>ManageSieveMailet</code> interprets mail from a local sender as
+ * commands to manage Sieve scripts stored on the mail server. The commands are
+ * a subset of those defined by <a
+ * href=http://tools.ietf.org/html/rfc5804#section
+ * -2>http://tools.ietf.org/html/rfc5804#section-2 
"MessageToCoreToMessage"</a>.
+ * 
+ * <p>
+ * For each supported command and associated response, the format is the same 
as
+ * defined by RFC 5804, with the exception that when Sieve scripts are involved
+ * in the exchange they are attached to the mail with the MIME type of
+ * 'application/sieve' rather than being embedded in the command.
+ * 
+ * <p>
+ * The command is written in the subject header of a mail received by this
+ * mailet. Responses from this mailet are sent to the sender as mail with the
+ * message body containing the response.
+ * 
+ * <p>
+ * The following commands are supported:
+ * <ul>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.4>CAPABILITY</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.5>HAVESPACE</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.6>PUTSCRIPT</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.7>LISTSCRIPTS</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.8>SETACTIVE</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.9>GETSCRIPT</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.10>DELETESCRIPT</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.11>RENAMESCRIPT</a>
+ * <li><a href=http://tools.ietf.org/html/rfc5804#section-2.12>CHECKSCRIPT</a>
+ * </ul>
+ * 
+ * <h2>An Important Note About Security</h2>
+ * <p>
+ * The mail server on which this mailet is deployed MUST robustly authenticate
+ * the sender, who MUST be local.
+ * <p>
+ * Sieve provides powerful email processing capabilities that if hijacked can
+ * expose the mail of individuals and organisations to intruders.
+ */
+public class ManageSieveMailet extends GenericMailet implements 
MessageToCoreToMessage.HelpProvider {
+
+    private class MailSession extends SettableSession {
+
+        public MailSession() {
+            super();
+        }
+
+        /**
+         * @param mail
+         *            the mail to set
+         */
+        public void setMail(Mail mail) {
+            setUser(getUser(mail.getSender()));
+            setAuthentication(null != 
mail.getAttribute(SMTP_AUTH_USER_ATTRIBUTE_NAME));
+        }
+
+        protected String getUser(MailAddress addr) {
+            return addr.getLocalPart() + '@' + (null == addr.getDomain() ? 
"localhost" : addr.getDomain());
+        }
+
+    }
+
+    public final static String SMTP_AUTH_USER_ATTRIBUTE_NAME = 
"org.apache.james.SMTPAuthUser";
+
+    private MailSession _session = null;
+
+    // Injected
+    private SieveRepository _sieveRepository = null;
+
+    // Injected
+    private SieveParser _sieveParser = null;
+
+    private MessageToCoreToMessage _transcoder = null;
+    
+    private URL _helpURL = null;
+    
+    private String _help = null;
+    
+    private boolean _cache = true;
+
+    /**
+     * Creates a new instance of ManageSieveMailet.
+     * 
+     */
+    public ManageSieveMailet() {
+        super();
+    }
+    
+    /**
+     * Creates a new instance of ManageSieveMailet.
+     *
+     * @param sieveRepository
+     * @param sieveParser
+     */
+    public ManageSieveMailet(SieveRepository sieveRepository, SieveParser 
sieveParser)
+    {
+        this();
+        setSieveRepository(sieveRepository);
+        setSieveParser(sieveParser);
+    }
+     
+    /**
+     * @see GenericMailet#init()
+     */
+    @Override
+    public void init() throws MessagingException {
+        super.init();
+        // Validate resources
+        if (null == _sieveParser)
+        {
+            throw new MessagingException("Missing resource \"sieveparser\"");
+        }
+        if (null == _sieveRepository)
+        {
+            throw new MessagingException("Missing resource 
\"sieverepository\"");
+        }
+        
+        setHelpURL(getInitParameter("helpURL"));
+        _cache = getInitParameter("cache", true);
+        _session = new MailSession();
+        _transcoder = new MessageToCoreToMessage(new LineToCoreToLine(new 
LineToCore(new CoreProcessor(_session,
+                _sieveRepository, _sieveParser))), this);
+    }
+    
+    protected void setHelpURL(String helpURL) throws MessagingException
+    {
+        try
+        {
+            _helpURL = new URL(helpURL);
+        }
+        catch (MalformedURLException ex)
+        {
+            throw new MessagingException("Invalid helpURL", ex);
+        }
+    } 
+
+    /**
+     * @see GenericMailet#service(Mail)
+     */
+    @Override
+    public void service(Mail mail) throws MessagingException {
+
+        // Sanity checks
+        if (null == mail.getSender()) {
+            getMailetContext().log("ERROR: Sender is null");
+            return;
+        }
+
+        if 
(!getMailetContext().isLocalServer(mail.getSender().getDomain().toLowerCase())) 
{
+            getMailetContext().log("ERROR: Sender not local");
+            return;
+        }
+
+        // Update the Session for the current mail and execute
+        _session.setMail(mail);
+        getMailetContext().sendMail(_transcoder.execute(mail.getMessage()));
+        mail.setState(Mail.GHOST);
+        
+        // And tidy up
+        clearCaches();
+    }
+    
+    protected void clearCaches()
+    {
+        if (!_cache)
+        {
+            _help = null;
+        }
+    }
+
+    public String getHelp() throws MessagingException {
+        if (null == _help)
+        {
+            _help = computeHelp();
+        }
+        return _help;
+    }
+    
+    protected String computeHelp() throws MessagingException
+    {
+        InputStream stream = null;
+        String help = null;
+        try {
+            stream = _helpURL.openStream();
+            help = new Scanner(stream, "UTF-8").useDelimiter("\\A").next();
+        } catch (IOException ex) {
+            throw new MessagingException("Unable to access help URL: " + 
_helpURL.toExternalForm(), ex);
+        }
+        finally
+        {
+            if (null != stream)
+            {
+                try {
+                    stream.close();
+                } catch (IOException ex) {
+                    // no op
+                }
+            }
+        }
+        return help;
+    }
+
+    /**
+     */
+    @Inject
+    public void setSieveRepository(SieveRepository repository) {
+        _sieveRepository = repository;
+    }
+
+    /**
+     * @param sieveParser
+     *            the sieveParser to set
+     */
+    @Inject
+    public void setSieveParser(SieveParser sieveParser) {
+        _sieveParser = sieveParser;
+    }
+
+    /**
+     * @see GenericMailet#getMailetInfo()
+     */
+    @Override
+    public String getMailetInfo() {
+        return getClass().getName();
+    }
+
+}

Added: 
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/transcode/MessageToCoreToMessage.java
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/transcode/MessageToCoreToMessage.java?rev=1716453&view=auto
==============================================================================
--- 
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/transcode/MessageToCoreToMessage.java
 (added)
+++ 
james/project/trunk/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/transcode/MessageToCoreToMessage.java
 Wed Nov 25 16:02:07 2015
@@ -0,0 +1,407 @@
+/*
+ *   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.james.transport.mailets.managesieve.transcode;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+import javax.activation.DataHandler;
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.util.ByteArrayDataSource;
+
+import org.apache.james.managesieve.transcode.LineToCoreToLine;
+import org.apache.james.managesieve.util.ParserUtils;
+
+/**
+ * <code>MessageToCoreToMessage</code>
+ */
+public class MessageToCoreToMessage {
+    
+    public interface HelpProvider {
+        abstract public String getHelp() throws MessagingException;
+    }   
+    
+    protected static String getScript(MimeMessage message) throws IOException, 
MessagingException {
+        String result = null;
+        if (message.getContentType().startsWith("multipart/")) {
+            MimeMultipart parts = (MimeMultipart) message.getContent();
+            boolean found = false;
+            // Find the first part with any of:
+            // - an attachment type of "application/sieve"
+            // - a file suffix of ".siv"
+            // - a file suffix of ".sieve"
+            for (int i = 0; !found && i < parts.getCount(); i++) {
+                MimeBodyPart part = (MimeBodyPart) parts.getBodyPart(i);
+                found = part.isMimeType("application/sieve");
+                if (!found) {
+                    String fileName = null == part.getFileName() ? null : 
part.getFileName()
+                            .toLowerCase();
+                    found = null != fileName
+                            && (fileName.endsWith(".siv") || 
fileName.endsWith(".sieve"));
+                }
+                if (found) {
+                    Object content = part.getContent();
+                    if (content instanceof String) {
+                        return (String) part.getContent();
+                    }
+                    InputStream is = (InputStream) part.getContent();
+                    Scanner scanner = null;
+                    try {
+                        scanner = new Scanner(is, "UTF-8").useDelimiter("\\A");
+                        if (scanner.hasNext()) {
+                            result = scanner.next();
+                        }
+                    } finally {
+                        if (null != scanner) {
+                            scanner.close();
+                        }
+                    }
+                }
+            }
+        }
+        if (null == result)
+        {
+            throw new MessagingException("Script part not found in this 
message");
+        }
+        return result;
+    }
+
+    protected static MimeBodyPart toPart(String name, String content) throws 
MessagingException,
+            IOException {
+        MimeBodyPart scriptPart = new MimeBodyPart();
+        scriptPart.setDataHandler(
+                new DataHandler(
+                        new ByteArrayDataSource(
+                                content,
+                                "application/sieve; charset=UTF-8")
+                          ));
+        scriptPart.setDisposition(MimeBodyPart.ATTACHMENT);
+        scriptPart.setFileName(name);
+        return scriptPart;
+    }
+
+    protected static MimeBodyPart toPart(String message) throws 
MessagingException {
+        MimeBodyPart part = new MimeBodyPart();
+        part.setText(message);
+        part.setDisposition(MimeBodyPart.INLINE);
+        return part;
+    }
+    
+    private interface Executable {
+        public MimeMultipart execute(String operands, MimeMessage message)
+                throws MessagingException;
+    }
+
+    private Map<String, Executable> _commands = null;
+    
+    private LineToCoreToLine _adapter = null;
+    
+    private HelpProvider _helpProvider = null;
+    
+    private MessageToCoreToMessage()
+    {
+        super();
+        _commands = computeCommands();
+    }
+    
+    public MessageToCoreToMessage(LineToCoreToLine adapter, HelpProvider 
helpProvider)
+    {
+        this();
+        _adapter = adapter;
+        _helpProvider = helpProvider;
+    }
+    
+    public MimeMessage execute(MimeMessage message) throws MessagingException {
+        // Extract the command and operands from the subject
+        String subject = null == message.getSubject() ? "" : 
message.getSubject();
+        String[] args = subject.split(" ", 2);
+        // If there are no arguments, reply with help
+        String command = 0 == args.length ? "HELP" : args[0].toUpperCase();
+        Executable executable = null;
+        // If the command isn't supported, reply with help
+        if (null == (executable = _commands.get(command))) {
+            executable = _commands.get("HELP");
+        }
+        // Execute the resultant command...
+        MimeMultipart content = executable.execute(args.length > 1 ? args[1] : 
"", message);
+        // ...and wrap it in a MimeMessage
+        MimeMessage reply = (MimeMessage) message.reply(false);
+        reply.setContent(content);
+        if (null == message.getAllRecipients() || 0 >= 
message.getAllRecipients().length) {
+            throw new MessagingException("Message has no recipients");
+        } else {
+            Address from = message.getAllRecipients()[0];
+            reply.setFrom(from);
+        }
+        reply.saveChanges();
+        return reply;
+    }
+    
+    protected Map<String, Executable> computeCommands() {
+        Map<String, Executable> commands = new HashMap<String, Executable>();
+        commands.put("HELP", new Executable() {
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return help(operands, message);
+            }
+        });
+        commands.put("CAPABILITY", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return capability(operands, message);
+            }
+        });
+        commands.put("CHECKSCRIPT", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return checkScript(operands, message);
+            }
+        });
+        commands.put("DELETESCRIPT", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return deleteScript(operands, message);
+            }
+        });
+        commands.put("GETSCRIPT", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return getScript(operands, message);
+            }
+        });
+        commands.put("HAVESPACE", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return haveSpace(operands, message);
+            }
+        });
+        commands.put("LISTSCRIPTS", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return listScripts(operands, message);
+            }
+        });
+        commands.put("PUTSCRIPT", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return putScript(operands, message);
+            }
+        });
+        commands.put("RENAMESCRIPT", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return renameScript(operands, message);
+            }
+        });
+        commands.put("SETACTIVE", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return setActive(operands, message);
+            }
+        });
+        commands.put("GETACTIVE", new Executable() {
+
+            public MimeMultipart execute(String operands, MimeMessage message)
+                    throws MessagingException {
+                return getActive(operands, message);
+            }
+        });
+
+        return commands;
+    }
+
+    protected MimeMultipart help(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_helpProvider.getHelp()));
+        return multipart;
+    }
+
+    protected MimeMultipart capability(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_adapter.capability(operands)));
+        return multipart;
+    }
+
+    protected MimeMultipart checkScript(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        String result = null;
+        Scanner scanner = new Scanner(operands).useDelimiter("\\A");
+        if (scanner.hasNext()) {
+            result = "NO \"Too many arguments: " + scanner.next() + "\"";
+        } else {
+            try {
+                String content = getScript(message);
+                result = _adapter.checkScript(content);
+            } catch (MessagingException ex) {
+                result = "NO \"" + ex.getMessage() + "\"";
+            } catch (IOException ex) {
+                result = "NO \"Failed to read script part\"";
+            }
+        }
+        multipart.addBodyPart(toPart(result));
+        return multipart;
+    }
+
+    protected MimeMultipart deleteScript(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_adapter.deleteScript(operands)));
+        return multipart;
+    }
+
+    protected MimeMultipart getScript(String operands, MimeMessage message)
+                throws MessagingException {
+        String result = _adapter.getScript(operands);
+        // Everything but the last line is the script
+        // The last line is the response
+        String response = null;
+        String script = null;
+        int endOfScript = result.lastIndexOf("\r\n");
+        if (endOfScript > 0) {
+            script = result.substring(0, endOfScript);
+            response = result.substring(endOfScript + "\r\n".length());
+        } else {
+            response = result;
+        }
+
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(response));
+        if (null != script) {
+            try {
+                multipart.addBodyPart(toPart(ParserUtils.unquote(ParserUtils
+                            .getScriptName(operands)), script));
+            } catch (IOException ex) {
+                throw new MessagingException("Failed to add script part", ex);
+            }
+        }
+        return multipart;
+    }
+
+    protected MimeMultipart haveSpace(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_adapter.haveSpace(operands)));
+        return multipart;
+    }
+
+    protected MimeMultipart listScripts(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_adapter.listScripts(operands)));
+        return multipart;
+    }
+
+    protected MimeMultipart putScript(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        String result = null;
+        String scriptName = ParserUtils.getScriptName(operands);
+        if (null == scriptName || scriptName.isEmpty()) {
+            result = "NO \"Missing argument: script name\"";
+        } else {
+            Scanner scanner = new 
Scanner(operands.substring(scriptName.length()).trim())
+                    .useDelimiter("\\A");
+            if (scanner.hasNext()) {
+                result = "NO \"Too many arguments: " + scanner.next() + "\"";
+            } else {
+                StringBuilder builder = new StringBuilder(scriptName);
+                String content = null;
+                try {
+                    content = getScript(message);
+                } catch (MessagingException ex) {
+                    result = "NO \"" + ex.getMessage() + "\"";
+                } catch (IOException ex) {
+                    result = "NO \"Failed to read script part\"";
+                }
+                if (null != content) {
+                    builder
+                            .append(' ')
+                            .append(content);
+                }
+                result = _adapter.putScript(builder.toString().trim());
+            }
+        }
+        multipart.addBodyPart(toPart(result));
+        return multipart;
+    }
+
+    protected MimeMultipart renameScript(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_adapter.renameScript(operands)));
+        return multipart;
+    }
+
+    protected MimeMultipart setActive(String operands, MimeMessage message)
+                throws MessagingException {
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(_adapter.setActive(operands)));
+        return multipart;
+    }
+
+    protected MimeMultipart getActive(String operands, MimeMessage message)
+            throws MessagingException {
+        String result = _adapter.getActive(operands);
+        _adapter.getActive(operands);
+        // Everything but the last line is the script
+        // The last line is the response
+        String response = null;
+        String script = null;
+        int endOfScript = result.lastIndexOf("\r\n");
+        if (endOfScript > 0) {
+            script = result.substring(0, endOfScript);
+            response = result.substring(endOfScript + "\r\n".length());
+        } else {
+            response = result;
+        }
+
+        MimeMultipart multipart = new MimeMultipart();
+        multipart.addBodyPart(toPart(response));
+        if (null != script) {
+            try {
+                multipart.addBodyPart(toPart("active", script));
+            } catch (IOException ex) {
+                throw new MessagingException("Failed to add script part", ex);
+            }
+        }
+        return multipart;
+    }
+
+}

Added: 
james/project/trunk/server/mailet/mailets/src/main/resources/managesieve.help.txt
URL: 
http://svn.apache.org/viewvc/james/project/trunk/server/mailet/mailets/src/main/resources/managesieve.help.txt?rev=1716453&view=auto
==============================================================================
--- 
james/project/trunk/server/mailet/mailets/src/main/resources/managesieve.help.txt
 (added)
+++ 
james/project/trunk/server/mailet/mailets/src/main/resources/managesieve.help.txt
 Wed Nov 25 16:02:07 2015
@@ -0,0 +1,112 @@
+managesieve implements the commands defined by RFC 5804 
((http://tools.ietf.org/html/rfc5804) to manage sieve scripts via mail 
messages. A mail is sent to the managesieve user with the command and 
parameters in the subject header. Sieve scripts are exchanged as mail 
attachments.
+
+Consult your mail administrator for the name of the managesieve user 
configured for your installation.
+
+Users MUST be SMTP authenticated to execute all except the CAPABILITY and HELP 
commands (see note (1) below).
+
+Commands are executed and answered within the namespace of the sending user as 
denoted by the sender header of the mail. Thus, a command such as LISTSCRIPTS 
lists the scripts within namespace of the user identified by the sender header.
+
+The supported commands are summarised in "Command Summary" below. Generally 
the responses are self describing. For full details see RFC 5804 - Commands 
(http://tools.ietf.org/html/rfc5804#section-2).
+
+In these descriptions the following keywords apply:
+
+- sieve-name
+    The name of a sieve script enclosed in parentheses, eg: "my script". An 
empty name is not allowed.
+- active-sieve-name
+    As sieve-name, except an empty name, eg: "", is allowed.
+- old-sieve-name
+    As sieve-name
+- new-sieve-name
+    As sieve-name    
+- sieve-script
+    A mail attachment recognised as a sieve script. This is the first 
attachment in a mail satisfying any of these characteristics:
+        - A MIME type of "application/sieve"
+        - A filename with the suffix ".sieve"
+        - A filename with the suffix ".siv"
+    Returned sieve-scripts always have the MIME type of "application/sieve"
+
+Command Summary
+---------------
+
+CAPABILITY
+    Subject:
+        CAPABILITY
+    Attachments: 
+        none
+Answers the capabilities of the underlying sieve inplementation.
+
+CHECKSCRIPT
+    Subject:
+        CHECKSCRIPT
+    Attachments: 
+        sieve-script
+Verifies the attached sieve-script without storing it on the server.
+
+DELETESCRIPT
+    Subject: 
+        DELETESCRIPT sieve-name
+    Attachments: 
+        none
+Deletes the named sieve script.
+
+GETACTIVE
+    Subject: 
+        GETACTIVE
+    Attachments: 
+        none
+Answers the active sieve script as an attachment.
+
+GETSCRIPT
+    Subject: 
+        GETSCRIPT sieve-name
+    Attachments: 
+        none
+Answers the named sieve script as an attachment.
+
+HAVESPACE
+    Subject: 
+        HAVESPACE sieve-name number
+    Attachments: 
+        none
+Answers OK if there is available space to store a script with the given name 
of the given size, else NO.
+
+HELP
+    Subject: 
+        HELP
+    Attachments: 
+        none
+Answers this text.
+
+LISTSCRIPTS
+    Subject: 
+        LISTSCRIPTS
+    Attachments: 
+        none
+Answers a list of the sieve scripts stored on the server, indicating which, if 
any, is the active script.
+
+PUTSCRIPT
+    Subject: 
+        PUTSCRIPT sieve-name
+    Attachments: 
+        sieve-script
+Verifies the attached sieve-script and if there are no errors stores it on the 
server using the given name.
+
+RENAMESCRIPT
+    Subject: 
+        RENAMESCRIPT old-sieve-name new-sieve-name
+    Attachments: 
+        none
+Renames the script stored on the server named old-sieve-name to new-sieve-name.
+
+SETACTIVE
+    Subject: 
+        SETACTIVE active-sieve-name
+    Attachments: 
+        none
+Sets the active script on the server to the given name. Use an empty string, 
"", to deactivate all scripts.
+
+Notes
+-----
+1) Some mail servers optionally allow configurations that enable local clients 
to post without SMTP authentication, such configurations will fail as 
managesieve requires SMTP authentication in all circumstances. To repeat, users 
MUST be SMTP authenticated to execute all except the CAPABILITY and HELP 
commands.
+
+



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

Reply via email to