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