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 2007/09/13 22:28:32 UTC

svn commit: r575440 - in /james/jsieve/trunk: ./ src/main/java/org/apache/jsieve/mail/ src/main/java/org/apache/jsieve/parser/address/ src/main/java/org/apache/jsieve/samples/james/ src/main/java/org/apache/jsieve/tests/ src/main/java/org/apache/jsieve...

Author: rdonkin
Date: Thu Sep 13 13:28:31 2007
New Revision: 575440

URL: http://svn.apache.org/viewvc?rev=575440&view=rev
Log:
Support for matching headers containing more than one address. Resolves JSIEVE-6 (https://issues.apache.org/jira/browse/JSIEVE-6). JTree schema forked from Mime4J.

Added:
    james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/
    james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/AddressNode.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/BaseAddressListVisitor.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/SieveAddressBuilder.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/AbstractCompatatorTest.java
    james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressParseTest.java
    james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/MultipleToTest.java
    james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/OpenedAddress.java
    james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/
    james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/address/
    james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/address/SieveAddressBuilderTest.java
Modified:
    james/jsieve/trunk/build.xml
    james/jsieve/trunk/src/main/java/org/apache/jsieve/mail/MailAdapter.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/samples/james/SieveMailAdapter.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/Address.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/optional/Envelope.java
    james/jsieve/trunk/src/main/java/org/apache/jsieve/util/check/ScriptCheckMailAdapter.java
    james/jsieve/trunk/src/main/jjtree/AddressListParser.jjt
    james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressTest.java
    james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/utils/SieveMailAdapter.java

Modified: james/jsieve/trunk/build.xml
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/build.xml?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/build.xml (original)
+++ james/jsieve/trunk/build.xml Thu Sep 13 13:28:31 2007
@@ -131,14 +131,21 @@
         Generate JavaCC source inserting parse tree building actions 
         and the Java source for the parse classes.
         -->
-        <mkdir dir="${build.src}/org/apache/jsieve/parser/generated"/>
+        <mkdir dir="${build.src}/org/apache/jsieve/parser/generated/address"/>
         <java classname="jjtree" fork="yes" failonerror="true" dir="${build.src}">
             <arg line="${javacc.dir}/sieve.jjt"/>
             <classpath>
                 <pathelement location="${javacc.jar}"/>
                 <pathelement path="${java.class.path}" />
             </classpath>
-       </java>
+        </java>
+        <java classname="jjtree" fork="yes" failonerror="true" dir="${build.src}">
+             <arg line="${javacc.dir}/AddressListParser.jjt"/>
+             <classpath>
+                 <pathelement location="${javacc.jar}"/>
+                 <pathelement path="${java.class.path}" />
+             </classpath>
+        </java>   
 
        <!--
        Make the generated parse classes an extension of the relevant base node to add the 
@@ -159,6 +166,13 @@
                 <pathelement path="${java.class.path}" />
             </classpath>
        </java>
+        <java classname="javacc" fork="yes" failonerror="true" dir="${build.src}">
+            <arg line="-output_directory=${build.src}/org/apache/jsieve/parser/generated/address ${build.src}/AddressListParser.jj"/>
+            <classpath>
+                <pathelement location="${javacc.jar}"/>
+                <pathelement path="${java.class.path}" />
+            </classpath>
+       </java>   
     </target>
 
     <!--

Modified: james/jsieve/trunk/src/main/java/org/apache/jsieve/mail/MailAdapter.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/mail/MailAdapter.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/mail/MailAdapter.java (original)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/mail/MailAdapter.java Thu Sep 13 13:28:31 2007
@@ -23,6 +23,7 @@
 import java.util.List;
 import java.util.ListIterator;
 
+import org.apache.jsieve.InternetAddressException;
 import org.apache.jsieve.SieveException;
 
 /**
@@ -103,8 +104,6 @@
      */
     public void executeActions() throws SieveException;            
 
-
-
     /**
      * Method getSize answers the receiver's message size in octets.
      * @return int
@@ -128,4 +127,45 @@
      */
     public Object getContent() throws SieveMailException;
 
+    /**
+     * <p>Parses the named header value into individual addresses.</p>
+     * 
+     * <p>Headers should be matched in a way that ignores case and the 
+     * whitespace prefixes and suffixes of a header name when performing the
+     * match, as required by RFC 3028. Thus "From", "from ", " From" and " from "
+     * are considered equal.
+     * </p>
+     * 
+     * @param headerName name of the header whose value is to be split
+     * @return addresses listed in the given header not null, possibly empty
+     * @throws InternetAddressException when the header value is not an address
+     * or list of addresses. Implemetations may elect to support only
+     * standard headers known to containing one or more addresses rather 
+     * than parsing the value
+     * content
+     * @throws SieveMailException when the header value cannot be read
+     */
+    public Address[] parseAddresses(String headerName) throws SieveMailException, InternetAddressException;
+    
+    /**
+     * Contains address data required for SIEVE processing.
+     */
+    public interface Address {
+        
+        /**
+         * Gets the local part of the email address.
+         * Specified in 
+         * <a href='http://james.apache.org/server/rfclist/basic/rfc0822.txt'>RFC822</a>.
+         * @return local part, not null
+         */
+        public String getLocalPart();
+        
+        /**
+         * Gets the domain part of the email address.
+         * Specified in 
+         * <a href='http://james.apache.org/server/rfclist/basic/rfc0822.txt'>RFC822</a>.
+         * @return domain, not null
+         */
+        public String getDomain();
+    }
 }

Added: james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/AddressNode.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/AddressNode.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/AddressNode.java (added)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/AddressNode.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,30 @@
+/****************************************************************
+ * 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.parser.address;
+
+import org.apache.jsieve.parser.generated.address.Token;
+
+public class AddressNode {
+
+    public Token firstToken = null;
+
+    public Token lastToken = null;
+
+}

Added: james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/BaseAddressListVisitor.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/BaseAddressListVisitor.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/BaseAddressListVisitor.java (added)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/BaseAddressListVisitor.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,89 @@
+/****************************************************************
+ * 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.parser.address;
+
+import org.apache.jsieve.parser.generated.address.ASTaddr_spec;
+import org.apache.jsieve.parser.generated.address.ASTaddress;
+import org.apache.jsieve.parser.generated.address.ASTaddress_list;
+import org.apache.jsieve.parser.generated.address.ASTangle_addr;
+import org.apache.jsieve.parser.generated.address.ASTdomain;
+import org.apache.jsieve.parser.generated.address.ASTgroup_body;
+import org.apache.jsieve.parser.generated.address.ASTlocal_part;
+import org.apache.jsieve.parser.generated.address.ASTmailbox;
+import org.apache.jsieve.parser.generated.address.ASTname_addr;
+import org.apache.jsieve.parser.generated.address.ASTphrase;
+import org.apache.jsieve.parser.generated.address.ASTroute;
+import org.apache.jsieve.parser.generated.address.AddressListParserVisitor;
+import org.apache.jsieve.parser.generated.address.SimpleNode;
+
+/**
+ * Do nothing implementation suitablae for subclassing.
+ */
+public abstract class BaseAddressListVisitor implements
+        AddressListParserVisitor {
+
+    public Object visit(SimpleNode node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTaddress_list node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTaddress node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTmailbox node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTname_addr node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTgroup_body node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTangle_addr node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTroute node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTphrase node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTaddr_spec node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTlocal_part node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+
+    public Object visit(ASTdomain node, Object data) {
+        return node.childrenAccept(this, data);
+    }
+}

Added: james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/SieveAddressBuilder.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/SieveAddressBuilder.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/SieveAddressBuilder.java (added)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/parser/address/SieveAddressBuilder.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,206 @@
+/****************************************************************
+ * 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.parser.address;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.mail.Header;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+
+import org.apache.jsieve.mail.MailAdapter;
+import org.apache.jsieve.mail.SieveMailException;
+import org.apache.jsieve.mail.MailAdapter.Address;
+import org.apache.jsieve.parser.generated.address.ASTaddr_spec;
+import org.apache.jsieve.parser.generated.address.ASTaddress_list;
+import org.apache.jsieve.parser.generated.address.ASTdomain;
+import org.apache.jsieve.parser.generated.address.ASTlocal_part;
+import org.apache.jsieve.parser.generated.address.AddressListParser;
+import org.apache.jsieve.parser.generated.address.ParseException;
+import org.apache.jsieve.parser.generated.address.Token;
+
+/**
+ * Builds {@link MailAdapter.Address}'s from address lists. Note that
+ * implementators of {@link MailAdapter} are recommended to use a fully featured
+ * and maintained parser such as <a href='http://james.apache.org/mime4j'>Apache
+ * Mime4J</a>. This implementation is based on Mime4J code but is intended only
+ * for internal and demonstration purposes. It is not actively maintained.
+ */
+public class SieveAddressBuilder {
+
+    /**
+     * Parses the value from the given message into addresses.
+     * @param headerName header name, to be matched case insensitively
+     * @param message <code>Message</code>, not null
+     * @return <code>Address</code> array, not null possibly empty
+     * @throws SieveMailException
+     */
+    public static Address[] parseAddresses(final String headerName, final Message message) throws SieveMailException {
+        try {
+            final SieveAddressBuilder builder = new SieveAddressBuilder();
+
+            for (Enumeration en = message.getAllHeaders();en.hasMoreElements();) {
+                final Header header = (Header) en.nextElement();
+                final String name = header.getName();
+                if (name.trim().equalsIgnoreCase(headerName)) {
+                    builder.addAddresses(header.getValue());
+                }
+            }
+            
+            final Address[] results = builder.getAddresses();
+            return results;
+            
+        } catch (MessagingException ex) {
+            throw new SieveMailException(ex);
+        } catch (ParseException ex) {
+            throw new SieveMailException(ex);
+        }
+    }
+    
+    private static final Address[] EMPTY_ADDRESSES = {};
+
+    private final Collection addresses;
+    private final Worker worker;
+
+    public SieveAddressBuilder() {
+        addresses = Collections.synchronizedCollection(new ArrayList());
+        worker = new Worker();
+    }
+
+    /**
+     * Clears the addresses currently accumulated.
+     */
+    public void reset() {
+        addresses.clear();
+    }
+
+    /**
+     * Adds addresses in the given list.
+     * 
+     * @param addressList
+     *            RFC822 address list
+     * @throws ParseException 
+     */
+    public void addAddresses(String addressList) throws ParseException {
+        final StringReader reader = new StringReader(addressList);
+        worker.addAddressses(reader, addresses);    
+    }
+
+    /**
+     * Gets addresses currently accumulated by calls to
+     * {@link #addAddresses(String)} since the last call to {@link #reset}.
+     * 
+     * @return addresses, not null
+     */
+    public Address[] getAddresses() {
+        final Address[] results = (Address[]) addresses
+                .toArray(EMPTY_ADDRESSES);
+        return results;
+    }
+
+    /**
+     * Performs the actual work.
+     * Factored into an inner class so that the build interface is clean.
+     */
+    private final class Worker extends BaseAddressListVisitor {
+
+        public void addAddressses(final Reader reader, final Collection results) throws ParseException {
+            AddressListParser parser = new AddressListParser(reader);
+            ASTaddress_list root = parser.parse();
+            root.childrenAccept(this, results);
+        }
+
+        public Object visit(ASTaddr_spec node, Object data) {
+            final AddressBean address = new AddressBean();
+            node.childrenAccept(this, address);
+            if (data instanceof Collection) {
+                final Collection collection = (Collection) data;
+                collection.add(address);
+            }
+            return data;
+        }
+
+        public Object visit(final ASTdomain node, final Object data) {
+            if (data instanceof AddressBean) {
+                final AddressBean address = (AddressBean) data;
+                final String domain = contents(node);
+                address.setDomain(domain);
+            }
+            return data;
+        }
+
+        public Object visit(ASTlocal_part node, Object data) {
+            if (data instanceof AddressBean) {
+                final AddressBean address = (AddressBean) data;
+                final String localPart = contents(node);
+                address.setLocalPart(localPart);
+            }
+            return data;
+        }
+        
+        private String contents(AddressNode node) {
+            StringBuffer buffer = new StringBuffer(32);
+            Token last = node.lastToken;
+            Token next = node.firstToken;
+            while(next != last) {
+                buffer.append(next.image);
+                next = next.next;
+            }
+            buffer.append(last.image);
+            return buffer.toString();
+        }
+    }
+
+    /**
+     * Bean based address implementation.
+     */
+    private final class AddressBean implements Address {
+        private String localPart;
+
+        private String domain;
+
+        public AddressBean() {
+            localPart = "";
+            domain = "";
+        }
+
+        public String getDomain() {
+            return domain;
+        }
+
+        public void setDomain(String domain) {
+            this.domain = domain;
+        }
+
+        public String getLocalPart() {
+            return localPart;
+        }
+
+        public void setLocalPart(String localPart) {
+            this.localPart = localPart;
+        }
+    }
+}

Modified: james/jsieve/trunk/src/main/java/org/apache/jsieve/samples/james/SieveMailAdapter.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/samples/james/SieveMailAdapter.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/samples/james/SieveMailAdapter.java (original)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/samples/james/SieveMailAdapter.java Thu Sep 13 13:28:31 2007
@@ -38,6 +38,7 @@
 import org.apache.jsieve.mail.MailUtils;
 import org.apache.jsieve.mail.SieveMailException;
 import org.apache.jsieve.mail.optional.EnvelopeAccessors;
+import org.apache.jsieve.parser.address.SieveAddressBuilder;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailAddress;
 import org.apache.mailet.MailetContext;
@@ -370,5 +371,20 @@
                 + " Envelope To: "
                 + (null == getEnvelopeTo() ? "null" : getEnvelopeTo())
                 + " Message ID: " + (null == messageID ? "null" : messageID);
+    }
+    public Object getContent() throws SieveMailException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    public String getContentType() throws SieveMailException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+    public Address[] parseAddresses(String headerName) throws SieveMailException {
+        try {
+            return SieveAddressBuilder.parseAddresses(headerName, getMail().getMessage());
+        } catch (MessagingException e) {
+            throw new SieveMailException(e);
+        }
     }
 }

Added: james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/AbstractCompatatorTest.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/AbstractCompatatorTest.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/AbstractCompatatorTest.java (added)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/AbstractCompatatorTest.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,228 @@
+/****************************************************************
+ * 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.tests;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+
+import org.apache.jsieve.Arguments;
+import org.apache.jsieve.SieveContext;
+import org.apache.jsieve.SieveException;
+import org.apache.jsieve.StringListArgument;
+import org.apache.jsieve.SyntaxException;
+import org.apache.jsieve.TagArgument;
+import org.apache.jsieve.comparators.ComparatorNames;
+import org.apache.jsieve.mail.MailAdapter;
+import org.apache.jsieve.mail.SieveMailException;
+
+public abstract class AbstractCompatatorTest extends AbstractTest implements AddressPartTags, ComparatorTags, MatchTypeTags, ComparatorNames {
+
+    public AbstractCompatatorTest() {
+        super();
+    }
+
+    /**
+     * <p>From RFC 3028, Section 5.1... </p>
+     * <code>  
+     * Syntax: address [ADDRESS-PART] [COMPARATOR] [MATCH-TYPE]
+     *         &lt;header-list: string-list&gt; &lt;key-list: string-list&gt;
+     * </code>
+     * <p>Note that the spec. then goes on to give an example where the
+     * order of the optional parts is different, so I am assuming that the order of
+     * the optional parts is optional too!</p>
+     * 
+     * @see org.apache.jsieve.tests.AbstractTest#executeBasic(MailAdapter, Arguments, SieveContext)
+     */
+    protected boolean executeBasic(MailAdapter mail, Arguments arguments, SieveContext context) throws SieveException {
+        String addressPart = null;
+        String comparator = null;
+        String matchType = null;
+        List headerNames = null;
+        List keys = null;
+    
+        ListIterator argumentsIter = arguments.getArgumentList().listIterator();
+        boolean stop = false;
+    
+        // Tag processing
+        while (!stop && argumentsIter.hasNext())
+        {
+            Object argument = argumentsIter.next();
+            if (argument instanceof TagArgument)
+            {
+                String tag = ((TagArgument) argument).getTag();
+    
+                // [ADDRESS-PART]?
+                if (null == addressPart
+                    && (tag.equals(LOCALPART_TAG)
+                        || tag.equals(DOMAIN_TAG)
+                        || tag.equals(ALL_TAG)))
+                    addressPart = tag;
+                // [COMPARATOR]?    
+                else if (null == comparator && tag.equals(COMPARATOR_TAG))
+                {
+                    // The next argument must be a stringlist
+                    if (argumentsIter.hasNext())
+                    {
+                        argument = argumentsIter.next();
+                        if (argument instanceof StringListArgument)
+                        {
+                            List stringList =
+                                ((StringListArgument) argument).getList();
+                            if (stringList.size() != 1)
+                                throw new SyntaxException("Expecting exactly one String");
+                            comparator = (String) stringList.get(0);
+                        }
+                        else
+                            throw new SyntaxException("Expecting a StringList");
+                    }
+                }
+                // [MATCH-TYPE]?
+                else if (
+                    null == matchType
+                        && (tag.equals(IS_TAG)
+                            || tag.equals(CONTAINS_TAG)
+                            || tag.equals(MATCHES_TAG)))
+                    matchType = tag;
+                else
+                    throw context.getCoordinate().syntaxException("Found unexpected TagArgument");
+            }
+            else
+            {
+                // Stop when a non-tag argument is encountered
+                argumentsIter.previous();
+                stop = true;
+            }
+        }
+    
+        // The next argument MUST be a string-list of header names
+        if (argumentsIter.hasNext())
+        {
+            Object argument = argumentsIter.next();
+            if (argument instanceof StringListArgument)
+                headerNames = ((StringListArgument) argument).getList();
+        }
+        if (null == headerNames)
+            throw context.getCoordinate().syntaxException("Expecting a StringList of header names");
+    
+        // The next argument MUST be a string-list of keys
+        if (argumentsIter.hasNext())
+        {
+            Object argument = argumentsIter.next();
+            if (argument instanceof StringListArgument)
+                keys = ((StringListArgument) argument).getList();
+        }
+        else if (null == keys)
+            throw context.getCoordinate().syntaxException("Expecting a StringList of keys");
+    
+        if (argumentsIter.hasNext())
+            throw context.getCoordinate().syntaxException("Found unexpected arguments");
+    
+        return match(
+            mail,
+            (addressPart == null ? ALL_TAG : addressPart),
+            (comparator == null ? ASCII_CASEMAP_COMPARATOR : comparator),
+            (matchType == null ? IS_TAG : matchType),
+            headerNames,
+            keys);
+    }
+
+    /**
+     * Method match.
+     * @param mail
+     * @param addressPart
+     * @param comparator
+     * @param matchType
+     * @param headerNames
+     * @param keys
+     * @return boolean
+     * @throws SieveMailException
+     */
+    protected boolean match(MailAdapter mail, String addressPart, String comparator, String matchType, List headerNames, List keys) throws SieveException {
+        // Iterate over the header names looking for a match
+        boolean isMatched = false;
+        Iterator headerNamesIter = headerNames.iterator();
+        while (!isMatched && headerNamesIter.hasNext())
+        {
+            isMatched =
+                match(
+                    mail,
+                    addressPart,
+                    comparator,
+                    matchType,
+                    (String) headerNamesIter.next(),
+                    keys);
+        }
+        return isMatched;
+    }
+
+    /**
+     * Method match.
+     * @param mail
+     * @param addressPart
+     * @param comparator
+     * @param matchType
+     * @param headerName
+     * @param keys
+     * @return boolean
+     * @throws SieveMailException
+     */
+    protected boolean match(MailAdapter mail, String addressPart, String comparator, String matchType, String headerName, List keys) throws SieveException {
+        // Iterate over the keys looking for a match
+        boolean isMatched = false;
+        Iterator keysIter = keys.iterator();
+        while (!isMatched && keysIter.hasNext())
+        {
+            isMatched =
+                match(
+                    mail,
+                    addressPart,
+                    comparator,
+                    matchType,
+                    headerName,
+                    (String) keysIter.next());
+        }
+        return isMatched;
+    }
+
+    /**
+     * Method match.
+     * @param mail
+     * @param addressPart
+     * @param comparator
+     * @param matchType
+     * @param headerName
+     * @param key
+     * @return boolean
+     * @throws SieveMailException
+     */
+    protected abstract boolean match(MailAdapter mail, String addressPart, String comparator, 
+                String matchType, String headerName, String key) throws SieveException;
+
+    /**
+     * @see org.apache.jsieve.tests.AbstractTest#validateArguments(Arguments, SieveContext)
+     */
+    protected void validateArguments(Arguments arguments, SieveContext context) throws SieveException {
+        if (arguments.hasTests())
+            throw context.getCoordinate().syntaxException("Found unexpected tests");
+    }
+
+}

Modified: james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/Address.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/Address.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/Address.java (original)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/Address.java Thu Sep 13 13:28:31 2007
@@ -21,30 +21,22 @@
 package org.apache.jsieve.tests;
 
 import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
 
 import javax.mail.internet.AddressException;
 import javax.mail.internet.InternetAddress;
 
-import org.apache.jsieve.Arguments;
 import org.apache.jsieve.InternetAddressException;
-import org.apache.jsieve.SieveContext;
 import org.apache.jsieve.SieveException;
-import org.apache.jsieve.StringListArgument;
-import org.apache.jsieve.SyntaxException;
-import org.apache.jsieve.TagArgument;
-import org.apache.jsieve.comparators.ComparatorNames;
 import org.apache.jsieve.comparators.ComparatorUtils;
 import org.apache.jsieve.mail.MailAdapter;
 import org.apache.jsieve.mail.SieveMailException;
 
+
 /**
  * Class Address implements the Addresss Test as defined in RFC 3028, section 5.1.
  */
 public class Address
-    extends AbstractTest
-    implements AddressPartTags, ComparatorTags, MatchTypeTags, ComparatorNames
+    extends AbstractCompatatorTest
 {
     /**
      * Constructor for Address.
@@ -54,235 +46,33 @@
         super();
     }
 
-    /**
-     * <p>From RFC 3028, Section 5.1... </p>
-     * <code>  
-     * Syntax: address [ADDRESS-PART] [COMPARATOR] [MATCH-TYPE]
-     *         &lt;header-list: string-list&gt; &lt;key-list: string-list&gt;
-     * </code>
-     * <p>Note that the spec. then goes on to give an example where the
-     * order of the optional parts is different, so I am assuming that the order of
-     * the optional parts is optional too!</p>
-     * 
-     * @see org.apache.jsieve.tests.AbstractTest#executeBasic(MailAdapter, Arguments, SieveContext)
-     */
-    protected boolean executeBasic(MailAdapter mail, Arguments arguments, SieveContext context)
-        throws SieveException
-    {
-        String addressPart = null;
-        String comparator = null;
-        String matchType = null;
-        List headerNames = null;
-        List keys = null;
-
-        ListIterator argumentsIter = arguments.getArgumentList().listIterator();
-        boolean stop = false;
-
-        // Tag processing
-        while (!stop && argumentsIter.hasNext())
-        {
-            Object argument = argumentsIter.next();
-            if (argument instanceof TagArgument)
-            {
-                String tag = ((TagArgument) argument).getTag();
-
-                // [ADDRESS-PART]?
-                if (null == addressPart
-                    && (tag.equals(LOCALPART_TAG)
-                        || tag.equals(DOMAIN_TAG)
-                        || tag.equals(ALL_TAG)))
-                    addressPart = tag;
-                // [COMPARATOR]?    
-                else if (null == comparator && tag.equals(COMPARATOR_TAG))
-                {
-                    // The next argument must be a stringlist
-                    if (argumentsIter.hasNext())
-                    {
-                        argument = argumentsIter.next();
-                        if (argument instanceof StringListArgument)
-                        {
-                            List stringList =
-                                ((StringListArgument) argument).getList();
-                            if (stringList.size() != 1)
-                                throw new SyntaxException("Expecting exactly one String");
-                            comparator = (String) stringList.get(0);
-                        }
-                        else
-                            throw new SyntaxException("Expecting a StringList");
-                    }
-                }
-                // [MATCH-TYPE]?
-                else if (
-                    null == matchType
-                        && (tag.equals(IS_TAG)
-                            || tag.equals(CONTAINS_TAG)
-                            || tag.equals(MATCHES_TAG)))
-                    matchType = tag;
-                else
-                    throw context.getCoordinate().syntaxException("Found unexpected TagArgument");
-            }
-            else
-            {
-                // Stop when a non-tag argument is encountered
-                argumentsIter.previous();
-                stop = true;
-            }
-        }
-
-        // The next argument MUST be a string-list of header names
-        if (argumentsIter.hasNext())
-        {
-            Object argument = argumentsIter.next();
-            if (argument instanceof StringListArgument)
-                headerNames = ((StringListArgument) argument).getList();
-        }
-        if (null == headerNames)
-            throw context.getCoordinate().syntaxException("Expecting a StringList of header names");
-
-        // The next argument MUST be a string-list of keys
-        if (argumentsIter.hasNext())
-        {
-            Object argument = argumentsIter.next();
-            if (argument instanceof StringListArgument)
-                keys = ((StringListArgument) argument).getList();
-        }
-        else if (null == keys)
-            throw context.getCoordinate().syntaxException("Expecting a StringList of keys");
-
-        if (argumentsIter.hasNext())
-            throw context.getCoordinate().syntaxException("Found unexpected arguments");
-
-        return match(
-            mail,
-            (addressPart == null ? ALL_TAG : addressPart),
-            (comparator == null ? ASCII_CASEMAP_COMPARATOR : comparator),
-            (matchType == null ? IS_TAG : matchType),
-            headerNames,
-            keys);
-    }
-
-    /**
-     * Method match.
-     * @param mail
-     * @param addressPart
-     * @param comparator
-     * @param matchType
-     * @param headerNames
-     * @param keys
-     * @return boolean
-     * @throws SieveMailException
-     */
-    protected boolean match(
-        MailAdapter mail,
-        String addressPart,
-        String comparator,
-        String matchType,
-        List headerNames,
-        List keys)
-        throws SieveException
-    {
-        // Iterate over the header names looking for a match
-        boolean isMatched = false;
-        Iterator headerNamesIter = headerNames.iterator();
-        while (!isMatched && headerNamesIter.hasNext())
-        {
-            isMatched =
-                match(
-                    mail,
-                    addressPart,
-                    comparator,
-                    matchType,
-                    (String) headerNamesIter.next(),
-                    keys);
-        }
-        return isMatched;
-    }
-
-    /**
-     * Method match.
-     * @param mail
-     * @param addressPart
-     * @param comparator
-     * @param matchType
-     * @param headerName
-     * @param keys
-     * @return boolean
-     * @throws SieveMailException
-     */
-    protected boolean match(
-        MailAdapter mail,
-        String addressPart,
-        String comparator,
-        String matchType,
-        String headerName,
-        List keys)
-        throws SieveException
+    protected boolean match(MailAdapter mail, String addressPart, String comparator, String matchType, String headerName, String key) throws SieveException 
     {
-        // Iterate over the keys looking for a match
+        final MailAdapter.Address[] addresses =
+            getMatchingValues(mail, headerName);
+        final int length = addresses.length;
+        int i=0;
         boolean isMatched = false;
-        Iterator keysIter = keys.iterator();
-        while (!isMatched && keysIter.hasNext())
+        while (!isMatched && i<length)
         {
             isMatched =
                 match(
-                    mail,
-                    addressPart,
-                    comparator,
-                    matchType,
-                    headerName,
-                    (String) keysIter.next());
+                        addressPart,
+                        comparator,
+                        matchType,
+                        addresses[i++],
+                        key);
         }
         return isMatched;
     }
 
-    /**
-     * Method match.
-     * @param mail
-     * @param addressPart
-     * @param comparator
-     * @param matchType
-     * @param headerName
-     * @param key
-     * @return boolean
-     * @throws SieveMailException
-     */
-    protected boolean match(
-        MailAdapter mail,
-        String addressPart,
-        String comparator,
-        String matchType,
-        String headerName,
-        String key)
-        throws SieveException
+    private MailAdapter.Address[] getMatchingValues(MailAdapter mail,
+            String valueName) throws SieveMailException,
+            InternetAddressException 
     {
-        Iterator headerValuesIter =
-            getMatchingValues(mail, headerName).iterator();
-        boolean isMatched = false;
-        while (!isMatched && headerValuesIter.hasNext())
-        {
-            isMatched =
-                match(
-                    addressPart,
-                    comparator,
-                    matchType,
-                    ((String) headerValuesIter.next()),
-                    key);
-        }
-        return isMatched;
+        return mail.parseAddresses(valueName);
     }
 
-    /**
-     * Method getMatchingValues.
-     * @param mail
-     * @param valueName
-     * @return List
-     * @throws SieveMailException
-     */
-    protected List getMatchingValues(MailAdapter mail, String valueName)
-        throws SieveMailException
-    {
-        return mail.getMatchingHeader(valueName);
-    }
 
     /**
      * Method match.
@@ -294,66 +84,35 @@
      * @return boolean
      * @throws SieveMailException
      */
-    protected boolean match(
-        String addressPart,
-        String comparator,
-        String matchType,
-        String headerValue,
-        String key)
-        throws SieveException
+    protected boolean match(String addressPart, String comparator, String matchType, 
+            MailAdapter.Address address, String key) throws SieveException 
     {
-        // Attempt to create a new InternetAddress object from the headerValue
-        // If this fails, the header either is not intended to contain a valid
-        // Internet Address or is corrupt. Either way, its an Exception!
-        String address = null;
-        try
-        {
-            // address is a simple address; user@domain or user
-            address = new InternetAddress(headerValue).getAddress();
-        }
-        catch (AddressException e)
-        {
-            throw new InternetAddressException(e.getMessage());
-        }
+        final String localPart = address.getLocalPart();
+        final String domain = address.getDomain();
 
         // Extract the part of the address we are matching on       
-        String matchAddress = null;
+        final String matchAddress;
         if (addressPart.equals(":all"))
-            matchAddress = address;
+            matchAddress = localPart + "@" + domain;
         else
         {
-            int localStart = 0;
-            int localEnd = 0;
-            int domainStart = 0;
-            int domainEnd = address.length();
-            int splitIndex = address.indexOf('@');
-            // If there is no domain part (-1), treat it as an empty String
-            if (splitIndex == -1)
-            {
-                localEnd = domainEnd;
-                domainStart = domainEnd;
-            }
-            else
-            {
-                localEnd = splitIndex;
-                domainStart = splitIndex + 1;
-            }
             matchAddress =
                 (addressPart.equals(LOCALPART_TAG)
-                    ? address.substring(localStart, localEnd)
-                    : address.substring(domainStart, domainEnd));
+                    ? localPart
+                    : domain.toLowerCase());
         }
-
+    
         // domain matches MUST ignore case, others should not
         String matchKey = null;
         if (addressPart.equals(DOMAIN_TAG))
         {
             matchKey = key.toLowerCase();
-            matchAddress = matchAddress.toLowerCase();
         }
         else
+        {
             matchKey = key;
-
+        }
+    
         // Match using the specified comparator          
         return ComparatorUtils.match(
             comparator,
@@ -361,14 +120,4 @@
             matchAddress,
             matchKey);
     }
-
-    /**
-     * @see org.apache.jsieve.tests.AbstractTest#validateArguments(Arguments, SieveContext)
-     */
-    protected void validateArguments(Arguments arguments, SieveContext context) throws SieveException
-    {
-        if (arguments.hasTests())
-            throw context.getCoordinate().syntaxException("Found unexpected tests");
-    }
-
 }

Modified: james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/optional/Envelope.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/optional/Envelope.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/optional/Envelope.java (original)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/tests/optional/Envelope.java Thu Sep 13 13:28:31 2007
@@ -20,18 +20,26 @@
 
 package org.apache.jsieve.tests.optional;
 
+import java.util.Iterator;
 import java.util.List;
 
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.jsieve.InternetAddressException;
+import org.apache.jsieve.SieveException;
+import org.apache.jsieve.comparators.ComparatorUtils;
 import org.apache.jsieve.mail.MailAdapter;
 import org.apache.jsieve.mail.SieveMailException;
 import org.apache.jsieve.mail.optional.EnvelopeAccessors;
+import org.apache.jsieve.tests.AbstractCompatatorTest;
 import org.apache.jsieve.tests.Address;
 
 /**
  * Class Envelope implements the optional Envelope Test as defined in RFC 3028, 
  * section 5.4.
  */
-public class Envelope extends Address
+public class Envelope extends AbstractCompatatorTest
 {
 
     /**
@@ -49,6 +57,94 @@
         throws SieveMailException
     {
         return ((EnvelopeAccessors) mail).getMatchingEnvelope(valueName);
+    }
+
+    /**
+     * Method match.
+     * @param addressPart
+     * @param comparator
+     * @param matchType
+     * @param headerValue
+     * @param key
+     * @return boolean
+     * @throws SieveMailException
+     */
+    protected boolean match(String addressPart, String comparator, String matchType, String headerValue, String key) throws SieveException {
+        // Attempt to create a new InternetAddress object from the headerValue
+        // If this fails, the header either is not intended to contain a valid
+        // Internet Address or is corrupt. Either way, its an Exception!
+        String address = null;
+        try
+        {
+            // address is a simple address; user@domain or user
+            address = new InternetAddress(headerValue).getAddress();
+        }
+        catch (AddressException e)
+        {
+            throw new InternetAddressException(e.getMessage());
+        }
+    
+        // Extract the part of the address we are matching on       
+        String matchAddress = null;
+        if (addressPart.equals(":all"))
+            matchAddress = address;
+        else
+        {
+            int localStart = 0;
+            int localEnd = 0;
+            int domainStart = 0;
+            int domainEnd = address.length();
+            int splitIndex = address.indexOf('@');
+            // If there is no domain part (-1), treat it as an empty String
+            if (splitIndex == -1)
+            {
+                localEnd = domainEnd;
+                domainStart = domainEnd;
+            }
+            else
+            {
+                localEnd = splitIndex;
+                domainStart = splitIndex + 1;
+            }
+            matchAddress =
+                (addressPart.equals(LOCALPART_TAG)
+                    ? address.substring(localStart, localEnd)
+                    : address.substring(domainStart, domainEnd));
+        }
+    
+        // domain matches MUST ignore case, others should not
+        String matchKey = null;
+        if (addressPart.equals(DOMAIN_TAG))
+        {
+            matchKey = key.toLowerCase();
+            matchAddress = matchAddress.toLowerCase();
+        }
+        else
+            matchKey = key;
+    
+        // Match using the specified comparator          
+        return ComparatorUtils.match(
+            comparator,
+            matchType,
+            matchAddress,
+            matchKey);
+    }
+
+    protected boolean match(MailAdapter mail, String addressPart, String comparator, String matchType, String headerName, String key) throws SieveException {
+        Iterator headerValuesIter =
+            getMatchingValues(mail, headerName).iterator();
+        boolean isMatched = false;
+        while (!isMatched && headerValuesIter.hasNext())
+        {
+            isMatched =
+                match(
+                    addressPart,
+                    comparator,
+                    matchType,
+                    ((String) headerValuesIter.next()),
+                    key);
+        }
+        return isMatched;
     }    
 
 

Modified: james/jsieve/trunk/src/main/java/org/apache/jsieve/util/check/ScriptCheckMailAdapter.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/java/org/apache/jsieve/util/check/ScriptCheckMailAdapter.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/main/java/org/apache/jsieve/util/check/ScriptCheckMailAdapter.java (original)
+++ james/jsieve/trunk/src/main/java/org/apache/jsieve/util/check/ScriptCheckMailAdapter.java Thu Sep 13 13:28:31 2007
@@ -37,6 +37,7 @@
 import org.apache.jsieve.mail.MailAdapter;
 import org.apache.jsieve.mail.MailUtils;
 import org.apache.jsieve.mail.SieveMailException;
+import org.apache.jsieve.parser.address.SieveAddressBuilder;
 
 /**
  * Checks script execution for an email.
@@ -268,6 +269,10 @@
             }
         }
         return result;
+    }
+
+    public Address[] parseAddresses(String headerName) throws SieveMailException {
+        return SieveAddressBuilder.parseAddresses(headerName, mail);
     }
 
 }

Modified: james/jsieve/trunk/src/main/jjtree/AddressListParser.jjt
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/main/jjtree/AddressListParser.jjt?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/main/jjtree/AddressListParser.jjt (original)
+++ james/jsieve/trunk/src/main/jjtree/AddressListParser.jjt Thu Sep 13 13:28:31 2007
@@ -1,332 +1,317 @@
-/****************************************************************
- * 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.                                           *
- ****************************************************************/
-
-
-/**
- * RFC2822 address list parser.
- *
- * Created 9/17/2004
- * by Joe Cheng <co...@joecheng.com>
- */
-
-options {
-	STATIC=false;
-	LOOKAHEAD=1;
-	VISITOR=true;
-	MULTI=true;
-	NODE_SCOPE_HOOK=true;
-	NODE_EXTENDS="org.apache.james.mime4j.field.address.parser.BaseNode"; 
-	//DEBUG_PARSER=true;
-	//DEBUG_TOKEN_MANAGER=true;
-}
-
-PARSER_BEGIN(AddressListParser)
-/****************************************************************
- * 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.mime4j.field.address.parser;
-
-public class AddressListParser {
-    public static void main(String args[]) throws ParseException {
-		while (true) {
-		    try {
-				AddressListParser parser = new AddressListParser(System.in);
-		    	parser.parseLine();
-		    	((SimpleNode)parser.jjtree.rootNode()).dump("> ");
-		    } catch (Exception x) {
-				x.printStackTrace();
-				return;
-		    }
-		}
-    }
-    
-    private static void log(String msg) {
-    	System.out.print(msg);
-    }
-    
-    public ASTaddress_list parse() throws ParseException {
-        try {
-    	    parseAll();
-    	    return (ASTaddress_list)jjtree.rootNode();
-    	} catch (TokenMgrError tme) {
-    	    throw new ParseException(tme.getMessage());
-    	}
-    }
-    
-    
-    void jjtreeOpenNodeScope(Node n) {
-    	((SimpleNode)n).firstToken = getToken(1);
-    }
-    
-    void jjtreeCloseNodeScope(Node n) {
-    	((SimpleNode)n).lastToken = getToken(0);
-    }
-}
-
-PARSER_END(AddressListParser)
-
-void parseLine() #void :
-{}
-{
-	address_list() ["\r"] "\n"
-}
-
-void parseAll() #void :
-{}
-{
-	address_list() <EOF>
-}
-
-void address_list() :
-{}
-{
-	[ address() ]
-	(
-		","
-		[ address() ]
-	)*
-}
-
-void address() :
-{}
-{
-	LOOKAHEAD(2147483647)
-	addr_spec()
-|	angle_addr()
-|	( phrase() (group_body() | angle_addr()) )
-}
-
-void mailbox() :
-{}
-{
-	LOOKAHEAD(2147483647)
-	addr_spec()
-|	angle_addr()
-|	name_addr()
-}
-
-void name_addr() :
-{}
-{
-	phrase() angle_addr()
-}
-
-void group_body() :
-{}
-{
-	":"
-	[ mailbox() ]
-	(
-		","
-		[ mailbox() ]
-	)*
-	";"
-}
-
-void angle_addr() :
-{}
-{
-	"<" [ route() ] addr_spec() ">"
-}
-
-void route() :
-{}
-{
-	"@" domain() ( (",")* "@" domain() )* ":"
-}
-
-void phrase() :
-{}
-{
-(	<DOTATOM>
-|	<QUOTEDSTRING>
-)+
-}
-
-void addr_spec() :
-{}
-{
-	( local_part() "@" domain() )
-}
-
-void local_part() :
-{ Token t; }
-{
-	( t=<DOTATOM> | t=<QUOTEDSTRING> )
-	(	[t="."]
-		{
-			if ( t.kind == AddressListParserConstants.QUOTEDSTRING || t.image.charAt(t.image.length() - 1) != '.')
-				throw new ParseException("Words in local part must be separated by '.'");
-		}
-		(	t=<DOTATOM> | t=<QUOTEDSTRING> )
-	)*
-}
-
-void domain() :
-{ Token t; }
-{
-	(	t=<DOTATOM>
-		(	[t="."]
-			{
-				if (t.image.charAt(t.image.length() - 1) != '.')
-					throw new ParseException("Atoms in domain names must be separated by '.'");
-			}
-			t=<DOTATOM>
-		)*
-	)
-|	<DOMAINLITERAL>
-}
-
-SPECIAL_TOKEN :
-{
- 	< WS: ( [" ", "\t"] )+ >
-}
-
-TOKEN :
-{
-	< #ALPHA: ["a" - "z", "A" - "Z"] >
-|	< #DIGIT: ["0" - "9"] >
-|	< #ATEXT: ( <ALPHA> | <DIGIT>
-			  | "!" | "#" | "$" | "%"
-			  | "&" | "'" | "*" | "+"
-			  | "-" | "/" | "=" | "?"
-			  | "^" | "_" | "`" | "{"
-			  | "|" | "}" | "~"
-			  )>
-|	< DOTATOM: <ATEXT> ( <ATEXT> | "." )* >
-}
-
-TOKEN_MGR_DECLS :
-{
-	// Keeps track of how many levels of comment nesting
-	// we've encountered.  This is only used when the 2nd
-	// level is reached, for example ((this)), not (this).
-	// This is because the outermost level must be treated
-	// specially anyway, because the outermost ")" has a 
-	// different token type than inner ")" instances.
-	static int commentNest;
-}
-
-MORE :
-{
-	// domain literal
-	"[" : INDOMAINLITERAL
-}
-
-<INDOMAINLITERAL>
-MORE :
-{
-	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-|	< ~["[", "]", "\\"] >
-}
-
-<INDOMAINLITERAL>
-TOKEN :
-{
-	< DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT
-}
-
-MORE :
-{
-	// starts a comment
-	"(" : INCOMMENT
-}
-
-<INCOMMENT>
-SKIP :
-{
-	// ends a comment
-	< COMMENT: ")" > : DEFAULT
-	// if this is ever changed to not be a SKIP, need
-	// to make sure matchedToken.token = token.toString()
-	// is called.
-}
-
-<INCOMMENT>
-MORE :
-{
-	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-|	"(" { commentNest = 1; } : NESTED_COMMENT
-|	< <ANY>>
-}
-
-<NESTED_COMMENT>
-MORE :
-{
-	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-|	"(" { ++commentNest; }
-|	")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
-|	< <ANY>>
-}
-
-
-// QUOTED STRINGS
-
-MORE :
-{
-	"\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING
-}
-
-<INQUOTEDSTRING>
-MORE :
-{
-	< <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-|	< (~["\"", "\\"])+ >
-}
-
-<INQUOTEDSTRING>
-TOKEN :
-{
-	< QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT
-}
-
-// GLOBALS
-
-<*>
-TOKEN :
-{
-	< #QUOTEDPAIR: "\\" <ANY> >
-|	< #ANY: ~[] >
-}
-
-// ERROR!
-/*
-
-<*>
-TOKEN :
-{
-	< UNEXPECTED_CHAR: <ANY> >
-}
-
-*/
\ No newline at end of file
+/****************************************************************
+ * 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.                                           *
+ ****************************************************************/
+
+
+/**
+ * RFC2822 address list parser.
+ *
+ * Created 9/17/2004
+ * by Joe Cheng <co...@joecheng.com>
+ */
+
+options {
+    STATIC=false;
+    LOOKAHEAD=1;
+    VISITOR=true;
+    MULTI=true;
+    NODE_SCOPE_HOOK=true;
+    NODE_EXTENDS="org.apache.jsieve.parser.address.AddressNode"; 
+    OUTPUT_DIRECTORY="./org/apache/jsieve/parser/generated/address";
+    //DEBUG_PARSER=true;
+    //DEBUG_TOKEN_MANAGER=true;
+}
+
+PARSER_BEGIN(AddressListParser)
+/****************************************************************
+ * 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.parser.generated.address;
+
+public class AddressListParser {    
+
+    public ASTaddress_list parse() throws ParseException {
+        try {
+            parseAll();
+            return (ASTaddress_list)jjtree.rootNode();
+        } catch (TokenMgrError tme) {
+            throw new ParseException(tme.getMessage());
+        }
+    }
+    
+    
+    void jjtreeOpenNodeScope(Node n) {
+        ((SimpleNode)n).firstToken = getToken(1);
+    }
+    
+    void jjtreeCloseNodeScope(Node n) {
+        ((SimpleNode)n).lastToken = getToken(0);
+    }
+}
+
+PARSER_END(AddressListParser)
+
+void parseLine() #void :
+{}
+{
+    address_list() ["\r"] "\n"
+}
+
+void parseAll() #void :
+{}
+{
+    address_list() <EOF>
+}
+
+void address_list() :
+{}
+{
+    [ address() ]
+    (
+        ","
+        [ address() ]
+    )*
+}
+
+void address() :
+{}
+{
+    LOOKAHEAD(2147483647)
+    addr_spec()
+|   angle_addr()
+|   ( phrase() (group_body() | angle_addr()) )
+}
+
+void mailbox() :
+{}
+{
+    LOOKAHEAD(2147483647)
+    addr_spec()
+|   angle_addr()
+|   name_addr()
+}
+
+void name_addr() :
+{}
+{
+    phrase() angle_addr()
+}
+
+void group_body() :
+{}
+{
+    ":"
+    [ mailbox() ]
+    (
+        ","
+        [ mailbox() ]
+    )*
+    ";"
+}
+
+void angle_addr() :
+{}
+{
+    "<" [ route() ] addr_spec() ">"
+}
+
+void route() :
+{}
+{
+    "@" domain() ( (",")* "@" domain() )* ":"
+}
+
+void phrase() :
+{}
+{
+(   <DOTATOM>
+|   <QUOTEDSTRING>
+)+
+}
+
+void addr_spec() :
+{}
+{
+    ( local_part() "@" domain() )
+}
+
+void local_part() :
+{ Token t; }
+{
+    ( t=<DOTATOM> | t=<QUOTEDSTRING> )
+    (   [t="."]
+        {
+            if ( t.kind == AddressListParserConstants.QUOTEDSTRING || t.image.charAt(t.image.length() - 1) != '.')
+                throw new ParseException("Words in local part must be separated by '.'");
+        }
+        (   t=<DOTATOM> | t=<QUOTEDSTRING> )
+    )*
+}
+
+void domain() :
+{ Token t; }
+{
+    (   t=<DOTATOM>
+        (   [t="."]
+            {
+                if (t.image.charAt(t.image.length() - 1) != '.')
+                    throw new ParseException("Atoms in domain names must be separated by '.'");
+            }
+            t=<DOTATOM>
+        )*
+    )
+|   <DOMAINLITERAL>
+}
+
+SPECIAL_TOKEN :
+{
+    < WS: ( [" ", "\t"] )+ >
+}
+
+TOKEN :
+{
+    < #ALPHA: ["a" - "z", "A" - "Z"] >
+|   < #DIGIT: ["0" - "9"] >
+|   < #ATEXT: ( <ALPHA> | <DIGIT>
+              | "!" | "#" | "$" | "%"
+              | "&" | "'" | "*" | "+"
+              | "-" | "/" | "=" | "?"
+              | "^" | "_" | "`" | "{"
+              | "|" | "}" | "~"
+              )>
+|   < DOTATOM: <ATEXT> ( <ATEXT> | "." )* >
+}
+
+TOKEN_MGR_DECLS :
+{
+    // Keeps track of how many levels of comment nesting
+    // we've encountered.  This is only used when the 2nd
+    // level is reached, for example ((this)), not (this).
+    // This is because the outermost level must be treated
+    // specially anyway, because the outermost ")" has a 
+    // different token type than inner ")" instances.
+    static int commentNest;
+}
+
+MORE :
+{
+    // domain literal
+    "[" : INDOMAINLITERAL
+}
+
+<INDOMAINLITERAL>
+MORE :
+{
+    < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|   < ~["[", "]", "\\"] >
+}
+
+<INDOMAINLITERAL>
+TOKEN :
+{
+    < DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT
+}
+
+MORE :
+{
+    // starts a comment
+    "(" : INCOMMENT
+}
+
+<INCOMMENT>
+SKIP :
+{
+    // ends a comment
+    < COMMENT: ")" > : DEFAULT
+    // if this is ever changed to not be a SKIP, need
+    // to make sure matchedToken.token = token.toString()
+    // is called.
+}
+
+<INCOMMENT>
+MORE :
+{
+    < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|   "(" { commentNest = 1; } : NESTED_COMMENT
+|   < <ANY>>
+}
+
+<NESTED_COMMENT>
+MORE :
+{
+    < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|   "(" { ++commentNest; }
+|   ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
+|   < <ANY>>
+}
+
+
+// QUOTED STRINGS
+
+MORE :
+{
+    "\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING
+}
+
+<INQUOTEDSTRING>
+MORE :
+{
+    < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
+|   < (~["\"", "\\"])+ >
+}
+
+<INQUOTEDSTRING>
+TOKEN :
+{
+    < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT
+}
+
+// GLOBALS
+
+<*>
+TOKEN :
+{
+    < #QUOTEDPAIR: "\\" <ANY> >
+|   < #ANY: ~[] >
+}
+
+// ERROR!
+/*
+
+<*>
+TOKEN :
+{
+    < UNEXPECTED_CHAR: <ANY> >
+}
+
+*/

Added: james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressParseTest.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressParseTest.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressParseTest.java (added)
+++ james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressParseTest.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,59 @@
+/****************************************************************
+ * 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.junit;
+
+import junit.framework.TestCase;
+
+import org.apache.jsieve.junit.utils.JUnitUtils;
+import org.apache.jsieve.junit.utils.SieveMailAdapter;
+
+public class AddressParseTest extends TestCase {
+    
+    private static final String MULTIPLE_ADDRESS_VALUES = 
+        "coyote@desert.example.org, bugs@example.org,  elmer@hunters.example.org";
+    
+    private static final String SOLO_ADDRESS_VALUES = 
+        "coyote@desert.example.org";    
+    
+    SieveMailAdapter mail;
+    OpenedAddress address;
+    
+    protected void setUp() throws Exception {
+        super.setUp();
+        mail = (SieveMailAdapter) JUnitUtils.createMail();
+        address = new OpenedAddress();
+    }
+
+    public void testSingleAddress() throws Exception {
+        mail.getMessage().addHeader("From", SOLO_ADDRESS_VALUES);
+        assertTrue(address.match(mail, ":all", "i;ascii-casemap", ":is", "from", "coyote@desert.example.org"));
+        assertFalse(address.match(mail, ":all", "i;ascii-casemap", ":is", "from","elmer@hunters.example.org"));
+        assertFalse(address.match(mail, ":all", "i;ascii-casemap", ":is", "from", "bugs@example.org"));
+        assertFalse(address.match(mail, ":all", "i;ascii-casemap", ":is", "from", "roadrunner@example.org"));
+    }
+
+    public void testMultipleAddresses() throws Exception {
+        mail.getMessage().addHeader("From", MULTIPLE_ADDRESS_VALUES);
+        assertTrue(address.match(mail, ":all", "i;ascii-casemap", ":is", "from", "coyote@desert.example.org"));
+        assertTrue(address.match(mail, ":all", "i;ascii-casemap", ":is", "from","elmer@hunters.example.org"));
+        assertTrue(address.match(mail, ":all", "i;ascii-casemap", ":is", "from", "bugs@example.org"));
+        assertFalse(address.match(mail, ":all", "i;ascii-casemap", ":is", "from", "roadrunner@example.org"));
+    }
+}

Modified: james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressTest.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressTest.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressTest.java (original)
+++ james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/AddressTest.java Thu Sep 13 13:28:31 2007
@@ -138,7 +138,7 @@
         try
         {
             SieveMailAdapter mail = (SieveMailAdapter) JUnitUtils.createMail();
-            mail.getMessage().addHeader("From ", "user@domain");            
+            mail.getMessage().addHeader("From ", "user@domain");
             JUnitUtils.interpret(mail, script);
         }
         catch (MessagingException e)

Added: james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/MultipleToTest.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/MultipleToTest.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/MultipleToTest.java (added)
+++ james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/MultipleToTest.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,90 @@
+/****************************************************************
+ * 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.junit;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringBufferInputStream;
+import java.io.StringReader;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.jsieve.util.check.ScriptChecker;
+
+public class MultipleToTest extends TestCase {
+    
+    private static final String SOLO_TO_EMAIL = 
+        "Date: Sun, 1 Apr 2007 1100:00:00 +0100 (BST)\r\f" +
+        "From: roadrunner@acme.example.com\r\f" +
+        "To: coyote@desert.example.org\r\f" +
+        "Subject: Who's The Fool?\r\f" +
+        "\r\f" +
+        "Beep-Beep\r\f"; 
+    
+    private static final String MULTIPLE_TO_EMAIL = 
+        "Date: Sun, 1 Apr 2007 1100:00:00 +0100 (BST)\r\f" +
+        "From: roadrunner@acme.example.com\r\f" +
+        "To: coyote@desert.example.org, bugs@example.org, " +
+        "    elmer@hunters.example.org,\r\f" +
+        "Subject: Who's The Fool?\r\f" +
+        "\r\f" +
+        "Beep-Beep\r\f"; 
+    
+    private static final String FILTER_SCRIPT = "require \"fileinto\";\r\f" +
+            "if address :is :all \"to\" \"coyote@desert.example.org\" {\r\f" +
+            "  fileinto \"coyote\";\r\f}\r\f" +
+            "if address :is :all \"to\" \"bugs@example.org\" {\r\f" +
+            "  fileinto \"bugs\";\r\f}\r\f" +
+            "if address :is :all \"to\" \"roadrunneracme.@example.org\" {\r\f" +
+            "  fileinto \"rr\";\r\f}\r\f" +
+            "if address :is :all \"to\" \"elmer@hunters.example.org\" {\r\f" +
+            "  fileinto \"elmer\";\r\f}\r\f";
+    
+    public void testSingleTo() throws Exception {
+        ScriptChecker checker = new ScriptChecker();
+        ScriptChecker.Results results = checker.check(toStream(SOLO_TO_EMAIL), toStream(FILTER_SCRIPT));
+        if (results.getException() != null) {
+            fail(results.getException().toString());
+        }
+        final List actionsExecuted = results.getActionsExecuted();
+        assertEquals(1, actionsExecuted.size());
+        assertTrue(results.isActionFileInto("coyote", 0));
+    }
+    
+    public void testMultipleTo() throws Exception {
+        ScriptChecker checker = new ScriptChecker();
+        ScriptChecker.Results results = checker.check(toStream(MULTIPLE_TO_EMAIL), toStream(FILTER_SCRIPT));
+        if (results.getException() != null) {
+            fail(results.getException().toString());
+        }
+        final List actionsExecuted = results.getActionsExecuted();
+        assertEquals(3, actionsExecuted.size());
+        assertTrue(results.isActionFileInto("coyote", 0));
+        assertTrue(results.isActionFileInto("bugs", 1));
+        assertTrue(results.isActionFileInto("elmer", 2));
+    }
+    
+    private InputStream toStream(String in) throws Exception {
+        byte[] bytes = in.getBytes("US-ASCII");
+        ByteArrayInputStream result = new ByteArrayInputStream(bytes);
+        return result;
+    }
+}

Added: james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/OpenedAddress.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/OpenedAddress.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/OpenedAddress.java (added)
+++ james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/OpenedAddress.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,32 @@
+/****************************************************************
+ * 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.junit;
+
+import org.apache.jsieve.SieveException;
+import org.apache.jsieve.mail.MailAdapter;
+import org.apache.jsieve.tests.Address;
+
+final class OpenedAddress extends Address {
+
+    protected boolean match(MailAdapter mail, String addressPart, String comparator, String matchType, String headerName, String key) throws SieveException {
+        return super.match(mail, addressPart, comparator, matchType, headerName, key);
+    }
+    
+}

Modified: james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/utils/SieveMailAdapter.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/utils/SieveMailAdapter.java?rev=575440&r1=575439&r2=575440&view=diff
==============================================================================
--- james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/utils/SieveMailAdapter.java (original)
+++ james/jsieve/trunk/src/test/java/org/apache/jsieve/junit/utils/SieveMailAdapter.java Thu Sep 13 13:28:31 2007
@@ -42,6 +42,8 @@
 import org.apache.jsieve.mail.MailAdapter;
 import org.apache.jsieve.mail.MailUtils;
 import org.apache.jsieve.mail.SieveMailException;
+import org.apache.jsieve.parser.address.SieveAddressBuilder;
+import org.apache.jsieve.parser.generated.address.ParseException;
 
 /**
  * <p>Class SieveMailAdapter implements a mock MailAdapter for testing purposes.</p>
@@ -277,6 +279,10 @@
         {
             throw new SieveMailException(ex);
         }
+    }
+
+    public Address[] parseAddresses(final String headerName) throws SieveMailException {
+         return SieveAddressBuilder.parseAddresses(headerName, getMessage());
     }
 
 

Added: james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/address/SieveAddressBuilderTest.java
URL: http://svn.apache.org/viewvc/james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/address/SieveAddressBuilderTest.java?rev=575440&view=auto
==============================================================================
--- james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/address/SieveAddressBuilderTest.java (added)
+++ james/jsieve/trunk/src/test/java/org/apache/jsieve/parser/address/SieveAddressBuilderTest.java Thu Sep 13 13:28:31 2007
@@ -0,0 +1,101 @@
+/****************************************************************
+ * 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.parser.address;
+
+import org.apache.jsieve.mail.MailAdapter.Address;
+import org.apache.jsieve.parser.generated.address.ParseException;
+
+import junit.framework.TestCase;
+
+public class SieveAddressBuilderTest extends TestCase {
+
+    public static final String DOMAIN = "example.org";
+    public static final String COYOTE = "coyote";
+    public static final String COYOTE_ADDRESS = COYOTE + "@" + DOMAIN;
+    public static final String ROADRUNNER = "roadrunner";
+    public static final String ROADRUNNER_ADDRESS = ROADRUNNER + "@" + DOMAIN;
+    public static final String BUGS = "bugs";
+    public static final String BUGS_ADDRESS = BUGS + "@" + DOMAIN;
+    public static final String HEROS = ROADRUNNER_ADDRESS + " , " + BUGS_ADDRESS;
+    
+    SieveAddressBuilder builder;
+    
+    protected void setUp() throws Exception {
+        super.setUp();
+        builder = new SieveAddressBuilder();
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testNotAddress() throws Exception {
+        try {
+            builder.addAddresses("What a load of rubbish - not an address in sight!");
+            fail("Parsing should fail when the input is not an address");
+        } catch (ParseException e) {
+            // expected
+        }
+    }
+
+    public void testAddAddresses() throws Exception {
+        assertNotNull(builder.getAddresses());
+        builder.addAddresses(COYOTE_ADDRESS);
+        Address[] addresses = builder.getAddresses();
+        assertNotNull(addresses);
+        assertEquals(1, addresses.length);
+        assertEquals(COYOTE, addresses[0].getLocalPart());
+        assertEquals(DOMAIN, addresses[0].getDomain());
+        builder.addAddresses(HEROS);
+        addresses = builder.getAddresses();
+        assertNotNull(addresses);
+        assertEquals(3, addresses.length);
+        assertEquals(COYOTE, addresses[0].getLocalPart());
+        assertEquals(DOMAIN, addresses[0].getDomain());
+        assertEquals(ROADRUNNER, addresses[1].getLocalPart());
+        assertEquals(DOMAIN, addresses[1].getDomain());
+        assertEquals(BUGS, addresses[2].getLocalPart());
+        assertEquals(DOMAIN, addresses[2].getDomain());
+    }
+
+    public void testReset() throws Exception {
+        assertNotNull(builder.getAddresses());
+        builder.addAddresses(COYOTE_ADDRESS);
+        Address[] addresses = builder.getAddresses();
+        assertNotNull(addresses);
+        assertEquals(1, addresses.length);
+        assertEquals(COYOTE, addresses[0].getLocalPart());
+        assertEquals(DOMAIN, addresses[0].getDomain());
+        addresses = builder.getAddresses();
+        assertNotNull(addresses);
+        assertEquals(1, addresses.length);
+        assertEquals(COYOTE, addresses[0].getLocalPart());
+        assertEquals(DOMAIN, addresses[0].getDomain());
+        builder.reset();
+        addresses = builder.getAddresses();
+        assertNotNull(addresses);
+        assertEquals(0, addresses.length);
+        builder.addAddresses(COYOTE_ADDRESS);
+        addresses = builder.getAddresses();
+        assertNotNull(addresses);
+        assertEquals(1, addresses.length);
+        assertEquals(COYOTE, addresses[0].getLocalPart());
+        assertEquals(DOMAIN, addresses[0].getDomain());
+    }
+}



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