Added support for :regex matching type.
Showing
1 changed file
with
169 additions
and
25 deletions
... | @@ -103,45 +103,189 @@ sieve_comparator_lookup (const char *name, int matchtype) | ... | @@ -103,45 +103,189 @@ sieve_comparator_lookup (const char *name, int matchtype) |
103 | return NULL; | 103 | return NULL; |
104 | } | 104 | } |
105 | 105 | ||
106 | static int | ||
107 | _find_comparator (void *item, void *data) | ||
108 | { | ||
109 | sieve_runtime_tag_t *tag = item; | ||
110 | |||
111 | if (strcmp (tag->tag, "comparator") == 0) | ||
112 | { | ||
113 | *(sieve_comparator_t*)data = tag->arg->v.ptr; | ||
114 | return 1; | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
106 | sieve_comparator_t | 119 | sieve_comparator_t |
107 | sieve_get_comparator (list_t tags) | 120 | sieve_get_comparator (list_t tags) |
108 | { | 121 | { |
122 | sieve_comparator_t comp = NULL; | ||
123 | |||
124 | list_do (tags, _find_comparator, &comp); | ||
125 | return comp ? comp : sieve_comparator_lookup ("i;ascii-casemap", | ||
126 | MU_SIEVE_MATCH_IS); | ||
127 | } | ||
128 | |||
129 | /* Compile time support */ | ||
130 | |||
131 | struct regex_data { | ||
132 | int flags; | ||
133 | list_t list; | ||
134 | }; | ||
135 | |||
136 | static int | ||
137 | _regex_compile (void *item, void *data) | ||
138 | { | ||
139 | struct regex_data *rd = data; | ||
140 | int rc; | ||
141 | regex_t *preg = sieve_palloc (&sieve_machine->memory_pool, sizeof (*preg)); | ||
142 | |||
143 | rc = regcomp (preg, (char*)item, rd->flags); | ||
144 | if (rc) | ||
145 | { | ||
146 | size_t size = regerror (rc, preg, NULL, 0); | ||
147 | char *errbuf = malloc (size + 1); | ||
148 | if (errbuf) | ||
149 | { | ||
150 | regerror (rc, preg, errbuf, size); | ||
151 | sieve_compile_error (sieve_filename, sieve_line_num, | ||
152 | "regex error: %s", errbuf); | ||
153 | free (errbuf); | ||
154 | } | ||
155 | else | ||
156 | sieve_compile_error (sieve_filename, sieve_line_num, | ||
157 | "regex error"); | ||
158 | return rc; | ||
159 | } | ||
160 | |||
161 | list_append (rd->list, preg); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int | ||
167 | _free_regex (void *item, void *unused) | ||
168 | { | ||
169 | regfree ((regex_t*)item); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static void | ||
174 | _free_reglist (void *data) | ||
175 | { | ||
176 | list_t list = data; | ||
177 | list_do (list, _free_regex, NULL); | ||
178 | list_destroy (&list); | ||
179 | } | ||
180 | |||
181 | int | ||
182 | sieve_match_part_checker (const char *name, list_t tags, list_t args) | ||
183 | { | ||
109 | iterator_t itr; | 184 | iterator_t itr; |
110 | char *compname = "i;ascii-casemap"; | 185 | sieve_runtime_tag_t *match = NULL; |
111 | int matchtype = MU_SIEVE_MATCH_IS; | 186 | sieve_runtime_tag_t *comp = NULL; |
187 | sieve_comparator_t compfun; | ||
188 | char *compname; | ||
189 | |||
190 | int matchtype; | ||
191 | int err = 0; | ||
112 | 192 | ||
113 | if (!tags || iterator_create (&itr, tags)) | 193 | if (!tags || iterator_create (&itr, tags)) |
114 | return NULL; | 194 | return 0; |
115 | 195 | ||
116 | for (iterator_first (itr); !iterator_is_done (itr); iterator_next (itr)) | 196 | for (iterator_first (itr); !err && !iterator_is_done (itr); |
197 | iterator_next (itr)) | ||
117 | { | 198 | { |
118 | sieve_runtime_tag_t *t; | 199 | sieve_runtime_tag_t *t; |
119 | iterator_current (itr, (void **)&t); | 200 | iterator_current (itr, (void **)&t); |
120 | switch (t->tag) | 201 | |
202 | if (strcmp (t->tag, "is") == 0 | ||
203 | || strcmp (t->tag, "contains") == 0 | ||
204 | || strcmp (t->tag, "matches") == 0 | ||
205 | || strcmp (t->tag, "regex") == 0) | ||
121 | { | 206 | { |
122 | case TAG_COMPARATOR: | 207 | if (match) |
123 | compname = t->arg->v.string; | 208 | err = 1; |
124 | break; | 209 | else |
125 | 210 | match = t; | |
126 | case TAG_IS: | ||
127 | matchtype = MU_SIEVE_MATCH_IS; | ||
128 | break; | ||
129 | |||
130 | case TAG_CONTAINS: | ||
131 | matchtype = MU_SIEVE_MATCH_CONTAINS; | ||
132 | break; | ||
133 | |||
134 | case TAG_MATCHES: | ||
135 | matchtype = MU_SIEVE_MATCH_MATCHES; | ||
136 | break; | ||
137 | |||
138 | case TAG_REGEX: | ||
139 | matchtype = MU_SIEVE_MATCH_REGEX; | ||
140 | break; | ||
141 | } | 211 | } |
212 | else if (strcmp (t->tag, "comparator") == 0) | ||
213 | comp = t; | ||
142 | } | 214 | } |
215 | |||
143 | iterator_destroy (&itr); | 216 | iterator_destroy (&itr); |
144 | return sieve_comparator_lookup (compname, matchtype); | 217 | |
218 | if (err) | ||
219 | { | ||
220 | sieve_compile_error (sieve_filename, sieve_line_num, | ||
221 | "match type specified twice in call to `%s'", | ||
222 | name); | ||
223 | return 1; | ||
224 | } | ||
225 | |||
226 | if (!match || strcmp (match->tag, "is") == 0) | ||
227 | matchtype = MU_SIEVE_MATCH_IS; | ||
228 | else if (strcmp (match->tag, "contains") == 0) | ||
229 | matchtype = MU_SIEVE_MATCH_CONTAINS; | ||
230 | else if (strcmp (match->tag, "matches") == 0) | ||
231 | matchtype = MU_SIEVE_MATCH_MATCHES; | ||
232 | else if (strcmp (match->tag, "regex") == 0) | ||
233 | matchtype = MU_SIEVE_MATCH_REGEX; | ||
234 | |||
235 | if (match) | ||
236 | list_remove (tags, match); | ||
237 | |||
238 | compname = comp ? comp->arg->v.string : "i;ascii-casemap"; | ||
239 | compfun = sieve_comparator_lookup (compname, matchtype); | ||
240 | if (!compfun) | ||
241 | { | ||
242 | sieve_compile_error (sieve_filename, sieve_line_num, | ||
243 | "comparator `%s' is incompatible with match type `%s' in call to `%s'", | ||
244 | compname, match ? match->tag : "is", name); | ||
245 | return 1; | ||
246 | } | ||
247 | |||
248 | if (comp) | ||
249 | { | ||
250 | sieve_pfree (&sieve_machine->memory_pool, comp->arg); | ||
251 | } | ||
252 | else | ||
253 | { | ||
254 | comp = sieve_palloc (&sieve_machine->memory_pool, | ||
255 | sizeof (*comp)); | ||
256 | comp->tag = "comparator"; | ||
257 | list_append (tags, comp); | ||
258 | } | ||
259 | comp->arg = sieve_value_create (SVT_POINTER, compfun); | ||
260 | |||
261 | if (matchtype == MU_SIEVE_MATCH_REGEX) | ||
262 | { | ||
263 | /* To speed up things, compile all patterns at once. | ||
264 | Notice that it is supposed that patterns are in arg 2 */ | ||
265 | sieve_value_t *val, *newval; | ||
266 | struct regex_data rd; | ||
267 | int rc; | ||
268 | |||
269 | if (list_get (args, 1, (void**)&val)) | ||
270 | return 0; | ||
271 | |||
272 | if (strcmp (compname, "i;ascii-casemap") == 0) | ||
273 | rd.flags = REG_ICASE; | ||
274 | else | ||
275 | rd.flags = 0; | ||
276 | |||
277 | list_create (&rd.list); | ||
278 | |||
279 | rc = sieve_vlist_do (val, _regex_compile, &rd); | ||
280 | |||
281 | sieve_machine_add_destructor (sieve_machine, _free_reglist, rd.list); | ||
282 | |||
283 | if (rc) | ||
284 | return rc; | ||
285 | newval = sieve_value_create (SVT_STRING_LIST, rd.list); | ||
286 | list_replace (args, val, newval); | ||
287 | } | ||
288 | return 0; | ||
145 | } | 289 | } |
146 | 290 | ||
147 | /* Particular comparators */ | 291 | /* Particular comparators */ | ... | ... |
-
Please register or sign in to post a comment