1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "unichar.h"
6 #include "str-sanitize.h"
7
8 #include "sieve-common.h"
9 #include "sieve-commands.h"
10 #include "sieve-code.h"
11 #include "sieve-binary.h"
12 #include "sieve-validator.h"
13 #include "sieve-generator.h"
14 #include "sieve-runtime.h"
15
16 #include "ext-variables-common.h"
17 #include "ext-variables-limits.h"
18 #include "ext-variables-modifiers.h"
19
20 #include <ctype.h>
21
22 /*
23 * Core modifiers
24 */
25
26 extern const struct sieve_variables_modifier_def lower_modifier;
27 extern const struct sieve_variables_modifier_def upper_modifier;
28 extern const struct sieve_variables_modifier_def lowerfirst_modifier;
29 extern const struct sieve_variables_modifier_def upperfirst_modifier;
30 extern const struct sieve_variables_modifier_def quotewildcard_modifier;
31 extern const struct sieve_variables_modifier_def length_modifier;
32
33 enum ext_variables_modifier_code {
34 EXT_VARIABLES_MODIFIER_LOWER,
35 EXT_VARIABLES_MODIFIER_UPPER,
36 EXT_VARIABLES_MODIFIER_LOWERFIRST,
37 EXT_VARIABLES_MODIFIER_UPPERFIRST,
38 EXT_VARIABLES_MODIFIER_QUOTEWILDCARD,
39 EXT_VARIABLES_MODIFIER_LENGTH
40 };
41
42 const struct sieve_variables_modifier_def *ext_variables_core_modifiers[] = {
43 &lower_modifier,
44 &upper_modifier,
45 &lowerfirst_modifier,
46 &upperfirst_modifier,
47 "ewildcard_modifier,
48 &length_modifier
49 };
50
51 const unsigned int ext_variables_core_modifiers_count =
52 N_ELEMENTS(ext_variables_core_modifiers);
53
54 #define ext_variables_modifier_name(modf) \
55 (modf)->object->def->name
56 #define ext_variables_modifiers_equal(modf1, modf2) \
57 ( (modf1)->def == (modf2)->def )
58 #define ext_variables_modifiers_equal_precedence(modf1, modf2) \
59 ( (modf1)->def->precedence == (modf2)->def->precendence )
60
61 /*
62 * Modifier registry
63 */
64
sieve_variables_modifier_register(const struct sieve_extension * var_ext,struct sieve_validator * valdtr,const struct sieve_extension * ext,const struct sieve_variables_modifier_def * smodf_def)65 void sieve_variables_modifier_register
66 (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
67 const struct sieve_extension *ext,
68 const struct sieve_variables_modifier_def *smodf_def)
69 {
70 struct ext_variables_validator_context *ctx =
71 ext_variables_validator_context_get(var_ext, valdtr);
72
73 sieve_validator_object_registry_add(ctx->modifiers, ext, &smodf_def->obj_def);
74 }
75
ext_variables_modifier_exists(const struct sieve_extension * var_ext,struct sieve_validator * valdtr,const char * identifier)76 bool ext_variables_modifier_exists
77 (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
78 const char *identifier)
79 {
80 struct ext_variables_validator_context *ctx =
81 ext_variables_validator_context_get(var_ext, valdtr);
82
83 return sieve_validator_object_registry_find(ctx->modifiers, identifier, NULL);
84 }
85
ext_variables_modifier_create_instance(const struct sieve_extension * var_ext,struct sieve_validator * valdtr,struct sieve_command * cmd,const char * identifier)86 const struct sieve_variables_modifier *ext_variables_modifier_create_instance
87 (const struct sieve_extension *var_ext, struct sieve_validator *valdtr,
88 struct sieve_command *cmd, const char *identifier)
89 {
90 struct ext_variables_validator_context *ctx =
91 ext_variables_validator_context_get(var_ext, valdtr);
92 struct sieve_object object;
93 struct sieve_variables_modifier *modf;
94 pool_t pool;
95
96 if ( !sieve_validator_object_registry_find
97 (ctx->modifiers, identifier, &object) )
98 return NULL;
99
100 pool = sieve_command_pool(cmd);
101 modf = p_new(pool, struct sieve_variables_modifier, 1);
102 modf->object = object;
103 modf->var_ext = var_ext;
104 modf->def = (const struct sieve_variables_modifier_def *) object.def;
105
106 return modf;
107 }
108
ext_variables_register_core_modifiers(const struct sieve_extension * ext,struct ext_variables_validator_context * ctx)109 void ext_variables_register_core_modifiers
110 (const struct sieve_extension *ext, struct ext_variables_validator_context *ctx)
111 {
112 unsigned int i;
113
114 /* Register core modifiers*/
115 for ( i = 0; i < ext_variables_core_modifiers_count; i++ ) {
116 sieve_validator_object_registry_add
117 (ctx->modifiers, ext, &(ext_variables_core_modifiers[i]->obj_def));
118 }
119 }
120
121 /*
122 * Core modifiers
123 */
124
125 /* Forward declarations */
126
127 static bool
128 mod_lower_modify(const struct sieve_variables_modifier *modf,
129 string_t *in, string_t **result);
130 static bool
131 mod_upper_modify(const struct sieve_variables_modifier *modf,
132 string_t *in, string_t **result);
133 static bool
134 mod_lowerfirst_modify(const struct sieve_variables_modifier *modf,
135 string_t *in, string_t **result);
136 static bool
137 mod_upperfirst_modify(const struct sieve_variables_modifier *modf,
138 string_t *in, string_t **result);
139 static bool
140 mod_length_modify(const struct sieve_variables_modifier *modf,
141 string_t *in, string_t **result);
142 static bool
143 mod_quotewildcard_modify(const struct sieve_variables_modifier *modf,
144 string_t *in, string_t **result);
145
146 /* Modifier objects */
147
148 const struct sieve_variables_modifier_def lower_modifier = {
149 SIEVE_OBJECT("lower", &modifier_operand, EXT_VARIABLES_MODIFIER_LOWER),
150 40,
151 mod_lower_modify
152 };
153
154 const struct sieve_variables_modifier_def upper_modifier = {
155 SIEVE_OBJECT("upper", &modifier_operand, EXT_VARIABLES_MODIFIER_UPPER),
156 40,
157 mod_upper_modify
158 };
159
160 const struct sieve_variables_modifier_def lowerfirst_modifier = {
161 SIEVE_OBJECT
162 ("lowerfirst", &modifier_operand, EXT_VARIABLES_MODIFIER_LOWERFIRST),
163 30,
164 mod_lowerfirst_modify
165 };
166
167 const struct sieve_variables_modifier_def upperfirst_modifier = {
168 SIEVE_OBJECT
169 ("upperfirst", &modifier_operand, EXT_VARIABLES_MODIFIER_UPPERFIRST),
170 30,
171 mod_upperfirst_modify
172 };
173
174 const struct sieve_variables_modifier_def quotewildcard_modifier = {
175 SIEVE_OBJECT
176 ("quotewildcard", &modifier_operand, EXT_VARIABLES_MODIFIER_QUOTEWILDCARD),
177 20,
178 mod_quotewildcard_modify
179 };
180
181 const struct sieve_variables_modifier_def length_modifier = {
182 SIEVE_OBJECT("length", &modifier_operand, EXT_VARIABLES_MODIFIER_LENGTH),
183 10,
184 mod_length_modify
185 };
186
187 /* Modifier implementations */
188
189 static bool
mod_upperfirst_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)190 mod_upperfirst_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
191 string_t *in, string_t **result)
192 {
193 char *content;
194
195 if ( str_len(in) == 0 ) {
196 *result = in;
197 return TRUE;
198 }
199
200 *result = t_str_new(str_len(in));
201 str_append_str(*result, in);
202
203 content = str_c_modifiable(*result);
204 content[0] = i_toupper(content[0]);
205
206 return TRUE;
207 }
208
209 static bool
mod_lowerfirst_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)210 mod_lowerfirst_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
211 string_t *in, string_t **result)
212 {
213 char *content;
214
215 if ( str_len(in) == 0 ) {
216 *result = in;
217 return TRUE;
218 }
219
220 *result = t_str_new(str_len(in));
221 str_append_str(*result, in);
222
223 content = str_c_modifiable(*result);
224 content[0] = i_tolower(content[0]);
225
226 return TRUE;
227 }
228
229 static bool
mod_upper_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)230 mod_upper_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
231 string_t *in, string_t **result)
232 {
233 char *content;
234
235 if ( str_len(in) == 0 ) {
236 *result = in;
237 return TRUE;
238 }
239
240 *result = t_str_new(str_len(in));
241 str_append_str(*result, in);
242
243 content = str_c_modifiable(*result);
244 (void)str_ucase(content);
245
246 return TRUE;
247 }
248
249 static bool
mod_lower_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)250 mod_lower_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
251 string_t *in, string_t **result)
252 {
253 char *content;
254
255 if ( str_len(in) == 0 ) {
256 *result = in;
257 return TRUE;
258 }
259
260 *result = t_str_new(str_len(in));
261 str_append_str(*result, in);
262
263 content = str_c_modifiable(*result);
264 (void)str_lcase(content);
265
266 return TRUE;
267 }
268
269 static bool
mod_length_modify(const struct sieve_variables_modifier * modf ATTR_UNUSED,string_t * in,string_t ** result)270 mod_length_modify(const struct sieve_variables_modifier *modf ATTR_UNUSED,
271 string_t *in, string_t **result)
272 {
273 *result = t_str_new(64);
274 str_printfa(*result, "%llu", (unsigned long long)
275 uni_utf8_strlen_n(str_data(in), str_len(in)));
276 return TRUE;
277 }
278
279 static bool
mod_quotewildcard_modify(const struct sieve_variables_modifier * modf,string_t * in,string_t ** result)280 mod_quotewildcard_modify(const struct sieve_variables_modifier *modf,
281 string_t *in, string_t **result)
282 {
283 size_t max_var_size =
284 sieve_variables_get_max_variable_size(modf->var_ext);
285 const unsigned char *p, *poff, *pend;
286 size_t new_size;
287
288 if ( str_len(in) == 0 ) {
289 /* empty string */
290 *result = in;
291 return TRUE;
292 }
293
294 /* allocate new string */
295 new_size = str_len(in) + 16;
296 if (new_size > max_var_size)
297 new_size = max_var_size;
298 *result = t_str_new(new_size + 1);
299
300 /* escape string */
301 p = str_data(in);
302 pend = p + str_len(in);
303 poff = p;
304 while (p < pend) {
305 unsigned int n = uni_utf8_char_bytes((char)*p);
306
307 if (n == 1 && (*p == '*' || *p == '?' || *p == '\\')) {
308 str_append_data(*result, poff, p - poff);
309 poff = p;
310
311 if (str_len(*result) + 2 > max_var_size)
312 break;
313
314 str_append_c(*result, '\\');
315 } else if ((str_len(*result) + (p - poff) + n) > max_var_size) {
316 break;
317 }
318 if (p + n > pend) {
319 p = pend;
320 break;
321 }
322 p += n;
323 }
324
325 str_append_data(*result, poff, p - poff);
326
327 return TRUE;
328 }
329
330 /*
331 * Modifier argument
332 */
333
334 /* [MODIFIER]:
335 * ":lower" / ":upper" / ":lowerfirst" / ":upperfirst" /
336 * ":quotewildcard" / ":length"
337 */
338
339 /* Forward declarations */
340
341 static bool tag_modifier_is_instance_of
342 (struct sieve_validator *valdtr, struct sieve_command *cmd,
343 const struct sieve_extension *ext, const char *identifier, void **context);
344
345 /* Modifier tag object */
346
347 static const struct sieve_argument_def modifier_tag = {
348 .identifier = "MODIFIER",
349 .flags = SIEVE_ARGUMENT_FLAG_MULTIPLE,
350 .is_instance_of = tag_modifier_is_instance_of
351 };
352
353 /* Modifier tag implementation */
354
tag_modifier_is_instance_of(struct sieve_validator * valdtr,struct sieve_command * cmd,const struct sieve_extension * ext,const char * identifier,void ** data)355 static bool tag_modifier_is_instance_of
356 (struct sieve_validator *valdtr, struct sieve_command *cmd,
357 const struct sieve_extension *ext, const char *identifier, void **data)
358 {
359 const struct sieve_variables_modifier *modf;
360
361 if ( data == NULL ) {
362 return ext_variables_modifier_exists(ext, valdtr, identifier);
363 }
364
365 if ( (modf=ext_variables_modifier_create_instance
366 (ext, valdtr, cmd, identifier)) == NULL )
367 return FALSE;
368
369 *data = (void *) modf;
370
371 return TRUE;
372 }
373
374 /* Registration */
375
sieve_variables_modifiers_link_tag(struct sieve_validator * valdtr,const struct sieve_extension * var_ext,struct sieve_command_registration * cmd_reg)376 void sieve_variables_modifiers_link_tag
377 (struct sieve_validator *valdtr, const struct sieve_extension *var_ext,
378 struct sieve_command_registration *cmd_reg)
379 {
380 sieve_validator_register_tag(valdtr, cmd_reg, var_ext, &modifier_tag, 0);
381 }
382
383 /* Validation */
384
sieve_variables_modifiers_validate(struct sieve_validator * valdtr,struct sieve_command * cmd,ARRAY_TYPE (sieve_variables_modifier)* modifiers)385 bool sieve_variables_modifiers_validate
386 (struct sieve_validator *valdtr, struct sieve_command *cmd,
387 ARRAY_TYPE(sieve_variables_modifier) *modifiers)
388 {
389 struct sieve_ast_argument *arg;
390
391 arg = sieve_command_first_argument(cmd);
392 while ( arg != NULL && arg != cmd->first_positional ) {
393 const struct sieve_variables_modifier *modfs;
394 const struct sieve_variables_modifier *modf;
395 unsigned int i, modf_count;
396 bool inserted;
397
398 if ( !sieve_argument_is(arg, modifier_tag) ) {
399 arg = sieve_ast_argument_next(arg);
400 continue;
401 }
402 modf = (const struct sieve_variables_modifier *)
403 arg->argument->data;
404
405 inserted = FALSE;
406 modfs = array_get(modifiers, &modf_count);
407 for ( i = 0; i < modf_count && !inserted; i++ ) {
408
409 if ( modfs[i].def->precedence == modf->def->precedence ) {
410 sieve_argument_validate_error(valdtr, arg,
411 "modifiers :%s and :%s specified for the set command conflict "
412 "having equal precedence",
413 modfs[i].def->obj_def.identifier, modf->def->obj_def.identifier);
414 return FALSE;
415 }
416
417 if ( modfs[i].def->precedence < modf->def->precedence ) {
418 array_insert(modifiers, i, modf, 1);
419 inserted = TRUE;
420 }
421 }
422
423 if ( !inserted )
424 array_append(modifiers, modf, 1);
425
426 /* Added to modifier list;
427 self-destruct to prevent implicit code generation */
428 arg = sieve_ast_arguments_detach(arg, 1);
429 }
430 return TRUE;
431 }
432
sieve_variables_modifiers_generate(const struct sieve_codegen_env * cgenv,ARRAY_TYPE (sieve_variables_modifier)* modifiers)433 bool sieve_variables_modifiers_generate
434 (const struct sieve_codegen_env *cgenv,
435 ARRAY_TYPE(sieve_variables_modifier) *modifiers)
436 {
437 struct sieve_binary_block *sblock = cgenv->sblock;
438 const struct sieve_variables_modifier *modfs;
439 unsigned int i, modf_count;
440
441 sieve_binary_emit_byte(sblock, array_count(modifiers));
442
443 modfs = array_get(modifiers, &modf_count);
444 for ( i = 0; i < modf_count; i++ ) {
445 ext_variables_opr_modifier_emit(sblock,
446 modfs[i].object.ext, modfs[i].def);
447 }
448 return TRUE;
449 }
450
451 /*
452 * Modifier coding
453 */
454
455 const struct sieve_operand_class sieve_variables_modifier_operand_class =
456 { "modifier" };
457
458 static const struct sieve_extension_objects core_modifiers =
459 SIEVE_VARIABLES_DEFINE_MODIFIERS(ext_variables_core_modifiers);
460
461 const struct sieve_operand_def modifier_operand = {
462 .name = "modifier",
463 .ext_def = &variables_extension,
464 .code = EXT_VARIABLES_OPERAND_MODIFIER,
465 .class = &sieve_variables_modifier_operand_class,
466 .interface = &core_modifiers
467 };
468
sieve_variables_modifiers_code_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address)469 bool sieve_variables_modifiers_code_dump
470 (const struct sieve_dumptime_env *denv, sieve_size_t *address)
471 {
472 unsigned int mdfs, i;
473
474 /* Read the number of applied modifiers we need to read */
475 if ( !sieve_binary_read_byte(denv->sblock, address, &mdfs) )
476 return FALSE;
477
478 /* Print all modifiers (sorted during code generation already) */
479 for ( i = 0; i < mdfs; i++ ) {
480 if ( !ext_variables_opr_modifier_dump(denv, address) )
481 return FALSE;
482 }
483 return TRUE;
484 }
485
sieve_variables_modifiers_code_read(const struct sieve_runtime_env * renv,const struct sieve_extension * var_ext,sieve_size_t * address,ARRAY_TYPE (sieve_variables_modifier)* modifiers)486 int sieve_variables_modifiers_code_read(
487 const struct sieve_runtime_env *renv,
488 const struct sieve_extension *var_ext, sieve_size_t *address,
489 ARRAY_TYPE(sieve_variables_modifier) *modifiers)
490 {
491 unsigned int lprec, mdfs, i;
492
493 if ( !sieve_binary_read_byte(renv->sblock, address, &mdfs) ) {
494 sieve_runtime_trace_error(renv, "invalid modifier count");
495 return SIEVE_EXEC_BIN_CORRUPT;
496 }
497
498 t_array_init(modifiers, mdfs);
499
500 lprec = (unsigned int)-1;
501 for ( i = 0; i < mdfs; i++ ) {
502 struct sieve_variables_modifier modf;
503
504 if ( !ext_variables_opr_modifier_read(renv, var_ext,
505 address, &modf) )
506 return SIEVE_EXEC_BIN_CORRUPT;
507 if ( modf.def != NULL ) {
508 if ( modf.def->precedence >= lprec ) {
509 sieve_runtime_trace_error(renv,
510 "unsorted modifier precedence");
511 return SIEVE_EXEC_BIN_CORRUPT;
512 }
513 lprec = modf.def->precedence;
514 }
515
516 array_append(modifiers, &modf, 1);
517 }
518
519 return SIEVE_EXEC_OK;
520 }
521
522 /*
523 * Modifier application
524 */
525
sieve_variables_modifiers_apply(const struct sieve_runtime_env * renv,const struct sieve_extension * var_ext,ARRAY_TYPE (sieve_variables_modifier)* modifiers,string_t ** value)526 int sieve_variables_modifiers_apply
527 (const struct sieve_runtime_env *renv,
528 const struct sieve_extension *var_ext,
529 ARRAY_TYPE(sieve_variables_modifier) *modifiers,
530 string_t **value)
531 {
532 const struct ext_variables_config *config =
533 ext_variables_get_config(var_ext);
534 const struct sieve_variables_modifier *modfs;
535 unsigned int i, modf_count;
536
537 /* Hold value within limits */
538 if ( str_len(*value) > config->max_variable_size ) {
539 /* assume variable originates from code, so copy it first */
540 string_t *new_value = t_str_new(config->max_variable_size+3);
541 str_append_str(new_value, *value);
542 *value = new_value;
543 str_truncate_utf8(*value, config->max_variable_size);
544 }
545
546 if ( !array_is_created(modifiers) )
547 return SIEVE_EXEC_OK;
548
549 modfs = array_get(modifiers, &modf_count);
550 if ( modf_count == 0 )
551 return SIEVE_EXEC_OK;
552
553 for ( i = 0; i < modf_count; i++ ) {
554 string_t *new_value;
555 const struct sieve_variables_modifier *modf = &modfs[i];
556
557 if ( modf->def != NULL && modf->def->modify != NULL ) {
558 if ( !modf->def->modify(modf, *value, &new_value) )
559 return SIEVE_EXEC_FAILURE;
560
561 *value = new_value;
562 if ( *value == NULL )
563 return SIEVE_EXEC_FAILURE;
564
565 sieve_runtime_trace_here
566 (renv, SIEVE_TRLVL_COMMANDS,
567 "modify :%s \"%s\" => \"%s\"",
568 sieve_variables_modifier_name(modf),
569 str_sanitize(str_c(*value), 256),
570 str_sanitize(str_c(new_value), 256));
571
572 /* Hold value within limits */
573 if ( str_len(*value) > config->max_variable_size )
574 str_truncate_utf8(*value, config->max_variable_size);
575 }
576 }
577 return SIEVE_EXEC_OK;
578 }
579