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.comparators;
21
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24 import java.util.regex.PatternSyntaxException;
25
26 import org.apache.jsieve.SieveContext;
27 import org.apache.jsieve.exception.LookupException;
28 import org.apache.jsieve.exception.SieveException;
29 import org.apache.jsieve.exception.SievePatternException;
30
31 import static org.apache.jsieve.comparators.MatchTypeTags.*;
32
33 /**
34 * Class ComparatorUtils implements utility methods used by Comparators.
35 */
36 public class ComparatorUtils {
37
38 /**
39 * Constructor for ComparatorUtils.
40 */
41 private ComparatorUtils() {
42 super();
43 }
44
45 /**
46 * Method <code>match</code> answers a boolean indicating if the parameter
47 * <code>matchTarget</code> compares to parameter
48 * <code>matchArgument</code> is a match of <code>matchType</code> using
49 * the comparator <code>comparatorName</code>.
50 *
51 * @param comparatorName not null
52 * @param matchType not null
53 * @param matchTarget not null
54 * @param matchArgument not null
55 * @param context not null
56 * @return boolean
57 */
58 public static boolean match(String comparatorName, String matchType,
59 String matchTarget, String matchArgument, SieveContext context)
60 throws SieveException {
61 boolean isMatched = false;
62 if (matchType.equals(IS_TAG))
63 isMatched = is(comparatorName, matchTarget, matchArgument, context);
64 else if (matchType.equals(CONTAINS_TAG))
65 isMatched = contains(comparatorName, matchTarget, matchArgument,
66 context);
67 else if (matchType.equals(MATCHES_TAG))
68 isMatched = matches(comparatorName, matchTarget, matchArgument,
69 context);
70 return isMatched;
71 }
72
73 /**
74 * <p>
75 * Method <code>matches</code> answers a boolean indicating if the
76 * parameter <code>string</code> matches the glob pattern described by
77 * parameter <code>glob</code>.
78 *
79 * @param string
80 * @param glob
81 * @return boolean
82 * @throws SievePatternException
83 */
84 static public boolean matches(String string, String glob)
85 throws SievePatternException {
86 try {
87 String regex = sieveToJavaRegex(glob);
88 final Matcher matcher = Pattern.compile(regex).matcher(string);
89 return matcher.matches();
90 } catch (PatternSyntaxException e) {
91 throw new SievePatternException(e.getMessage());
92 }
93 }
94
95 /**
96 * <p>
97 * Method <code>contains</code> answers a boolean indicating if the
98 * parameter <code>container</code> contains the parameter
99 * <code>contents</code>.
100 * </p>
101 *
102 * @param container
103 * @param contents
104 * @return boolean
105 */
106 static public boolean contains(String container, String contents) {
107 return container.indexOf(contents) > -1;
108 }
109
110 /**
111 * <p>
112 * Method <code>equals</code> answers a boolean indicating if the
113 * parameter <code>string1</code> is equal to the parameter
114 * <code>string2</code>.
115 * </p>
116 *
117 * @param string1
118 * @param string2
119 * @return boolean
120 */
121 static public boolean equals(String string1, String string2) {
122 return string1.equals(string2);
123 }
124
125 /**
126 * Returns true if the char is a special char for regex
127 */
128 private static boolean isRegexSpecialChar(char ch) {
129 return (ch == '*' || ch == '?' || ch == '+' || ch == '[' || ch == ']'
130 || ch == '(' || ch == ')' || ch == '|' || ch == '^'
131 || ch == '$' || ch == '.' || ch == '{' || ch == '}' || ch == '\\');
132 }
133
134 /**
135 * Returns true if the char is a special char for sieve matching
136 */
137 private static boolean isSieveMatcherSpecialChar(char ch) {
138 return (ch == '*' || ch == '?' || ch == '\\');
139 }
140
141 /**
142 * Converts a Sieve pattern in a java regex pattern
143 */
144 public static String sieveToJavaRegex(String pattern) {
145 int ch;
146 StringBuffer buffer = new StringBuffer(2 * pattern.length());
147 boolean lastCharWasStar = false;
148 for (ch = 0; ch < pattern.length(); ch++) {
149 final char nextChar = pattern.charAt(ch);
150 switch (nextChar) {
151 case '*':
152 //
153 // Java Matcher has issues with repeated stars
154 //
155 if (!lastCharWasStar) {
156 buffer.append(".*");
157 }
158 break;
159 case '?':
160 buffer.append('.');
161 break;
162 case '\\':
163 buffer.append('\\');
164 if (ch == pattern.length() - 1)
165 buffer.append('\\');
166 else if (isSieveMatcherSpecialChar(pattern.charAt(ch + 1)))
167 buffer.append(pattern.charAt(++ch));
168 else
169 buffer.append('\\');
170 break;
171 default:
172 if (isRegexSpecialChar(nextChar))
173 buffer.append('\\');
174 buffer.append(nextChar);
175 break;
176 }
177 // Workaround for issue with Java Matcher
178 lastCharWasStar = '*' == nextChar;
179 }
180 return buffer.toString();
181 }
182
183 /**
184 * Method <code>contains<code> answers a boolean indicating if the parameter
185 * <code>container</code> contains the parameter <code>contents</code> using an
186 * instance of <code>comparatorName</code>.
187 * @param comparatorName not null
188 * @param container not null
189 * @param contents not null
190 * @param context not null
191 * @return boolean
192 */
193 public static boolean contains(String comparatorName, String container,
194 String contents, SieveContext context) throws SieveException {
195 Contains comparatorObj = context.getComparatorManager().getComparator(comparatorName);
196 return comparatorObj.contains(container, contents);
197 }
198
199 /**
200 * Method <code>is<code> answers a boolean indicating if the parameter
201 * <code>container</code> is equal to the parameter <code>contents</code> using
202 * an instance of <code>comparatorName</code>.
203 * @param comparatorName
204 * @param string1 not null
205 * @param string2 not null
206 * @param context not null
207 * @return boolean
208 */
209 public static boolean is(String comparatorName, String string1,
210 String string2, SieveContext context) throws LookupException {
211 Equals comparatorObj = context.getComparatorManager().getComparator(comparatorName);
212 return comparatorObj.equals(string1, string2);
213 }
214
215 /**
216 * Method <code>matches</code> answers a boolean indicating if the
217 * parameter
218 * <code>string/code> is matched by the patterm <code>glob</code> using an
219 * instance of <code>comparatorName</code>.
220 * @param comparatorName not null
221 * @param string not null
222 * @param glob not null
223 * @param context not null
224 * @return boolean
225 */
226 public static boolean matches(String comparatorName, String string,
227 String glob, SieveContext context) throws SieveException {
228 Matches comparatorObj = context.getComparatorManager().getComparator(comparatorName);
229 return comparatorObj.matches(string, glob);
230 }
231
232 }