Commit 04a9780c 04a9780c45bef8366415d8c0f1a4f305468c85a3 by Sergey Poznyakoff

Added support for :regex matching type.

1 parent a5910b7b
...@@ -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 */
......