View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.jsieve.tests;
21  
22  import java.util.ArrayList;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.ListIterator;
26  
27  import org.apache.jsieve.Arguments;
28  import org.apache.jsieve.SieveContext;
29  import org.apache.jsieve.StringListArgument;
30  import org.apache.jsieve.TagArgument;
31  import org.apache.jsieve.comparators.ComparatorNames;
32  import org.apache.jsieve.comparators.ComparatorUtils;
33  import org.apache.jsieve.comparators.MatchTypeTags;
34  import org.apache.jsieve.exception.SieveException;
35  import org.apache.jsieve.mail.MailAdapter;
36  
37  /**
38   * Class Header implements the Header Test as defined in RFC 3028, section 5.7.
39   */
40  public class Header extends AbstractTest implements ComparatorTags,
41          MatchTypeTags, ComparatorNames {
42  
43      /**
44       * Constructor for Header.
45       */
46      public Header() {
47          super();
48      }
49  
50      /**
51       * <p>
52       * From RFC 3028, Section 5.7...
53       * </p>
54       * <code>  
55       * Syntax: header [COMPARATOR] [MATCH-TYPE]
56       *       &lt;header-names: string-list&gt; &lt;key-list: string-list&gt;
57       * </code>
58       * <p>
59       * Note that the spec. then goes on to give an example where the order of
60       * the optional parts is different, so I guess that the order is optional
61       * too!
62       * </p>
63       * 
64       * @see org.apache.jsieve.tests.AbstractTest#executeBasic(MailAdapter,
65       *      Arguments, SieveContext)
66       */
67      protected boolean executeBasic(MailAdapter mail, Arguments arguments,
68              SieveContext context) throws SieveException {
69          String comparator = null;
70          String matchType = null;
71          List headerNames = null;
72          List keys = null;
73  
74          ListIterator argumentsIter = arguments.getArgumentList().listIterator();
75          boolean stop = false;
76  
77          // Tag processing
78          while (!stop && argumentsIter.hasNext()) {
79              Object argument = argumentsIter.next();
80              if (argument instanceof TagArgument) {
81                  String tag = ((TagArgument) argument).getTag();
82  
83                  if (null == comparator && tag.equals(COMPARATOR_TAG)) {
84                      // The next argument must be a stringlist
85                      if (argumentsIter.hasNext()) {
86                          argument = argumentsIter.next();
87                          if (argument instanceof StringListArgument) {
88                              List stringList = ((StringListArgument) argument)
89                                      .getList();
90                              if (stringList.size() != 1)
91                                  throw context.getCoordinate().syntaxException(
92                                          "Expecting exactly one String");
93                              comparator = (String) stringList.get(0);
94                          } else
95                              throw context.getCoordinate().syntaxException(
96                                      "Expecting a StringList");
97                      }
98                  }
99                  // [MATCH-TYPE]?
100                 else if (null == matchType
101                         && (tag.equals(IS_TAG) || tag.equals(CONTAINS_TAG) || tag
102                                 .equals(MATCHES_TAG)))
103                     matchType = tag;
104                 else
105                     throw context.getCoordinate().syntaxException(
106                             "Found unexpected TagArgument: \"" + tag + "\"");
107             } else {
108                 // Stop when a non-tag argument is encountered
109                 argumentsIter.previous();
110                 stop = true;
111             }
112         }
113 
114         // The next argument MUST be a string-list of header names
115         if (argumentsIter.hasNext()) {
116             Object argument = argumentsIter.next();
117             if (argument instanceof StringListArgument)
118                 headerNames = ((StringListArgument) argument).getList();
119         }
120         if (null == headerNames)
121             throw context.getCoordinate().syntaxException(
122                     "Expecting a StringListof header names");
123 
124         // The next argument MUST be a string-list of keys
125         if (argumentsIter.hasNext()) {
126             Object argument = argumentsIter.next();
127             if (argument instanceof StringListArgument)
128                 keys = ((StringListArgument) argument).getList();
129         }
130         if (null == keys)
131             throw context.getCoordinate().syntaxException(
132                     "Expecting a StringList of keys");
133 
134         if (argumentsIter.hasNext())
135             throw context.getCoordinate().syntaxException(
136                     "Found unexpected arguments");
137 
138         return match(mail, (comparator == null ? ASCII_CASEMAP_COMPARATOR
139                 : comparator), (matchType == null ? IS_TAG : matchType),
140                 headerNames, keys, context);
141     }
142 
143     /**
144      * Method match.
145      * 
146      * @param mail
147      * @param comparator
148      * @param matchType
149      * @param headerNames
150      * @param keys
151      * @param context
152      *            TODO
153      * @return boolean
154      * @throws SieveException
155      */
156     protected boolean match(MailAdapter mail, String comparator,
157             String matchType, List headerNames, List keys, SieveContext context)
158             throws SieveException {
159         // Iterate over the header names looking for a match
160         boolean isMatched = false;
161         Iterator headerNamesIter = headerNames.iterator();
162         while (!isMatched && headerNamesIter.hasNext()) {
163             isMatched = match(comparator, matchType, mail
164                     .getMatchingHeader((String) headerNamesIter.next()), keys,
165                     context);
166         }
167         return isMatched;
168     }
169 
170     /**
171      * Method match.
172      * 
173      * @param comparator
174      * @param matchType
175      * @param headerValues
176      * @param keys
177      * @param context
178      *            TODO
179      * @return boolean
180      * @throws SieveException
181      */
182     protected boolean match(String comparator, String matchType,
183             List headerValues, List keys, SieveContext context)
184             throws SieveException {
185         // Special case for empty values
186         // If the matchType is :contains
187         // add the headerValue of a null string
188         // else
189         // not matched
190         if (headerValues.isEmpty())
191             if (matchType.equals(CONTAINS_TAG)) {
192                 // header values may be immutable
193                 headerValues = new ArrayList(headerValues);
194                 headerValues.add("");
195             } else {
196                 return false;
197             }
198         // Iterate over the header values looking for a match
199         boolean isMatched = false;
200         Iterator headerValuesIter = headerValues.iterator();
201         while (!isMatched && headerValuesIter.hasNext()) {
202             isMatched = match(comparator, matchType, (String) headerValuesIter
203                     .next(), keys, context);
204         }
205         return isMatched;
206     }
207 
208     /**
209      * Method match.
210      * 
211      * @param comparator
212      * @param matchType
213      * @param headerValue
214      * @param keys
215      * @param context
216      *            TODO
217      * @return boolean
218      * @throws SieveException
219      */
220     protected boolean match(String comparator, String matchType,
221             String headerValue, List keys, SieveContext context)
222             throws SieveException {
223         // Iterate over the keys looking for a match
224         boolean isMatched = false;
225         Iterator keysIter = keys.iterator();
226         while (!isMatched && keysIter.hasNext()) {
227             final String nextKey = (String) keysIter.next();
228             isMatched = ComparatorUtils.match(comparator, matchType,
229                     headerValue, nextKey, context);
230         }
231         return isMatched;
232     }
233 
234     /**
235      * @see org.apache.jsieve.tests.AbstractTest#validateArguments(Arguments,
236      *      SieveContext)
237      */
238     protected void validateArguments(Arguments arguments, SieveContext context)
239             throws SieveException {
240         if (arguments.hasTests())
241             throw context.getCoordinate().syntaxException(
242                     "Found unexpected tests");
243     }
244 
245 }