1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "str.h"
6 #include "mempool.h"
7 #include "hash.h"
8 #include "array.h"
9
10 #include "sieve-common.h"
11 #include "sieve-error.h"
12 #include "sieve-settings.h"
13 #include "sieve-extensions.h"
14
15 /*
16 * Forward declarations
17 */
18
19 static void sieve_extension_registry_init(struct sieve_instance *svinst);
20 static void sieve_extension_registry_deinit(struct sieve_instance *svinst);
21
22 static void sieve_capability_registry_init(struct sieve_instance *svinst);
23 static void sieve_capability_registry_deinit(struct sieve_instance *svinst);
24
25 static struct sieve_extension *_sieve_extension_register
26 (struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
27 bool load, bool required);
28
29 /*
30 * Instance global context
31 */
32
33 struct sieve_extension_registry {
34 ARRAY(struct sieve_extension *) extensions;
35 HASH_TABLE(const char *, struct sieve_extension *) extension_index;
36 HASH_TABLE(const char *, struct sieve_capability_registration *) capabilities_index;
37
38 /* Core language 'extensions' */
39 const struct sieve_extension *comparator_extension;
40 const struct sieve_extension *match_type_extension;
41 const struct sieve_extension *address_part_extension;
42
43 /* Preloaded extensions */
44 ARRAY(const struct sieve_extension *) preloaded_extensions;
45 };
46
47 /*
48 * Pre-loaded 'extensions'
49 */
50
51 extern const struct sieve_extension_def comparator_extension;
52 extern const struct sieve_extension_def match_type_extension;
53 extern const struct sieve_extension_def address_part_extension;
54
55 /*
56 * Dummy extensions
57 */
58
59 /* FIXME: This is stupid. Define a comparator-* extension and be done with it */
60
61 const struct sieve_extension_def comparator_i_octet_extension = {
62 .name = "comparator-i;octet",
63 };
64
65 const struct sieve_extension_def comparator_i_ascii_casemap_extension = {
66 .name = "comparator-i;ascii-casemap",
67 };
68
69 /*
70 * List of native extensions
71 */
72
73 /* Dummy extensions */
74
75 extern const struct sieve_extension_def comparator_i_octet_extension;
76 extern const struct sieve_extension_def comparator_i_ascii_casemap_extension;
77
78 const struct sieve_extension_def *sieve_dummy_extensions[] = {
79 &comparator_i_octet_extension, &comparator_i_ascii_casemap_extension
80 };
81
82 const unsigned int sieve_dummy_extensions_count =
83 N_ELEMENTS(sieve_dummy_extensions);
84
85 /* Core */
86
87 extern const struct sieve_extension_def fileinto_extension;
88 extern const struct sieve_extension_def reject_extension;
89 extern const struct sieve_extension_def envelope_extension;
90 extern const struct sieve_extension_def encoded_character_extension;
91
92 extern const struct sieve_extension_def vacation_extension;
93 extern const struct sieve_extension_def subaddress_extension;
94 extern const struct sieve_extension_def comparator_i_ascii_numeric_extension;
95 extern const struct sieve_extension_def relational_extension;
96 extern const struct sieve_extension_def regex_extension;
97 extern const struct sieve_extension_def imap4flags_extension;
98 extern const struct sieve_extension_def copy_extension;
99 extern const struct sieve_extension_def include_extension;
100 extern const struct sieve_extension_def body_extension;
101 extern const struct sieve_extension_def variables_extension;
102 extern const struct sieve_extension_def enotify_extension;
103 extern const struct sieve_extension_def environment_extension;
104 extern const struct sieve_extension_def mailbox_extension;
105 extern const struct sieve_extension_def date_extension;
106 extern const struct sieve_extension_def index_extension;
107 extern const struct sieve_extension_def ihave_extension;
108 extern const struct sieve_extension_def duplicate_extension;
109 extern const struct sieve_extension_def mime_extension;
110 extern const struct sieve_extension_def foreverypart_extension;
111 extern const struct sieve_extension_def extracttext_extension;
112 extern const struct sieve_extension_def mboxmetadata_extension;
113 extern const struct sieve_extension_def servermetadata_extension;
114
115 const struct sieve_extension_def *sieve_core_extensions[] = {
116 /* Core extensions */
117 &fileinto_extension, &reject_extension, &envelope_extension,
118 &encoded_character_extension,
119
120 /* 'Plugins' */
121 &vacation_extension, &subaddress_extension,
122 &comparator_i_ascii_numeric_extension,
123 &relational_extension, ®ex_extension, &imap4flags_extension,
124 ©_extension, &include_extension, &body_extension,
125 &variables_extension, &enotify_extension, &environment_extension,
126 &mailbox_extension, &date_extension, &index_extension, &ihave_extension,
127 &duplicate_extension, &mime_extension, &foreverypart_extension,
128 &extracttext_extension
129 };
130
131 const unsigned int sieve_core_extensions_count =
132 N_ELEMENTS(sieve_core_extensions);
133
134 /* Extra;
135 * These are not enabled by default, e.g. because explicit configuration is
136 * necessary to make these useful.
137 */
138
139 extern const struct sieve_extension_def vacation_seconds_extension;
140 extern const struct sieve_extension_def spamtest_extension;
141 extern const struct sieve_extension_def spamtestplus_extension;
142 extern const struct sieve_extension_def virustest_extension;
143 extern const struct sieve_extension_def editheader_extension;
144 extern const struct sieve_extension_def special_use_extension;
145
146 extern const struct sieve_extension_def vnd_debug_extension;
147 extern const struct sieve_extension_def vnd_environment_extension;
148 extern const struct sieve_extension_def vnd_report_extension;
149
150 const struct sieve_extension_def *sieve_extra_extensions[] = {
151 &vacation_seconds_extension, &spamtest_extension, &spamtestplus_extension,
152 &virustest_extension, &editheader_extension,
153 &mboxmetadata_extension, &servermetadata_extension,
154 &special_use_extension,
155
156 /* vnd.dovecot. */
157 &vnd_debug_extension, &vnd_environment_extension, &vnd_report_extension
158 };
159
160 const unsigned int sieve_extra_extensions_count =
161 N_ELEMENTS(sieve_extra_extensions);
162
163 /*
164 * Deprecated extensions
165 */
166
167 extern const struct sieve_extension_def imapflags_extension;
168 extern const struct sieve_extension_def notify_extension;
169 extern const struct sieve_extension_def vnd_duplicate_extension;
170
171 const struct sieve_extension_def *sieve_deprecated_extensions[] = {
172 &imapflags_extension,
173 ¬ify_extension,
174 &vnd_duplicate_extension
175 };
176
177 const unsigned int sieve_deprecated_extensions_count =
178 N_ELEMENTS(sieve_deprecated_extensions);
179
180 /*
181 * Unfinished extensions
182 */
183
184 #ifdef HAVE_SIEVE_UNFINISHED
185
186 extern const struct sieve_extension_def ereject_extension;
187
188 const struct sieve_extension_def *sieve_unfinished_extensions[] = {
189 &ereject_extension
190 };
191
192 const unsigned int sieve_unfinished_extensions_count =
193 N_ELEMENTS(sieve_unfinished_extensions);
194
195 #endif /* HAVE_SIEVE_UNFINISHED */
196
197 /*
198 * Extensions init/deinit
199 */
200
sieve_extensions_init(struct sieve_instance * svinst)201 bool sieve_extensions_init(struct sieve_instance *svinst)
202 {
203 unsigned int i;
204 struct sieve_extension_registry *ext_reg =
205 p_new(svinst->pool, struct sieve_extension_registry, 1);
206 struct sieve_extension *ext;
207
208 svinst->ext_reg = ext_reg;
209
210 sieve_extension_registry_init(svinst);
211 sieve_capability_registry_init(svinst);
212
213 /* Preloaded 'extensions' */
214 ext_reg->comparator_extension =
215 sieve_extension_register(svinst, &comparator_extension, TRUE);
216 ext_reg->match_type_extension =
217 sieve_extension_register(svinst, &match_type_extension, TRUE);
218 ext_reg->address_part_extension =
219 sieve_extension_register(svinst, &address_part_extension, TRUE);
220
221 p_array_init(&ext_reg->preloaded_extensions, svinst->pool, 5);
222 array_append(&ext_reg->preloaded_extensions,
223 &ext_reg->comparator_extension, 1);
224 array_append(&ext_reg->preloaded_extensions,
225 &ext_reg->match_type_extension, 1);
226 array_append(&ext_reg->preloaded_extensions,
227 &ext_reg->address_part_extension, 1);
228
229 /* Pre-load dummy extensions */
230 for ( i = 0; i < sieve_dummy_extensions_count; i++ ) {
231 if ( (ext=_sieve_extension_register
232 (svinst, sieve_dummy_extensions[i], TRUE, FALSE)) == NULL )
233 return FALSE;
234
235 ext->dummy = TRUE;
236 }
237
238 /* Pre-load core extensions */
239 for ( i = 0; i < sieve_core_extensions_count; i++ ) {
240 if ( sieve_extension_register
241 (svinst, sieve_core_extensions[i], TRUE) == NULL )
242 return FALSE;
243 }
244
245 /* Pre-load extra extensions */
246 for ( i = 0; i < sieve_extra_extensions_count; i++ ) {
247 if ( sieve_extension_register
248 (svinst, sieve_extra_extensions[i], FALSE) == NULL )
249 return FALSE;
250 }
251
252 /* Register deprecated extensions */
253 for ( i = 0; i < sieve_deprecated_extensions_count; i++ ) {
254 if ( sieve_extension_register
255 (svinst, sieve_deprecated_extensions[i], FALSE) == NULL )
256 return FALSE;
257 }
258
259 #ifdef HAVE_SIEVE_UNFINISHED
260 /* Register unfinished extensions */
261 for ( i = 0; i < sieve_unfinished_extensions_count; i++ ) {
262 if ( sieve_extension_register
263 (svinst, sieve_unfinished_extensions[i], FALSE) == NULL )
264 return FALSE;
265 }
266 #endif
267
268 /* More extensions can be added through plugins */
269
270 return TRUE;
271 }
272
sieve_extensions_configure(struct sieve_instance * svinst)273 void sieve_extensions_configure(struct sieve_instance *svinst)
274 {
275 const char *extensions;
276
277 /* Apply sieve_extensions configuration */
278
279 if ( (extensions=sieve_setting_get
280 (svinst, "sieve_extensions")) != NULL )
281 sieve_extensions_set_string(svinst, extensions, FALSE, FALSE);
282
283 /* Apply sieve_global_extensions configuration */
284
285 if ( (extensions=sieve_setting_get
286 (svinst, "sieve_global_extensions")) != NULL )
287 sieve_extensions_set_string(svinst, extensions, TRUE, FALSE);
288
289 /* Apply sieve_implicit_extensions configuration */
290
291 if ( (extensions=sieve_setting_get
292 (svinst, "sieve_implicit_extensions")) != NULL )
293 sieve_extensions_set_string(svinst, extensions, FALSE, TRUE);
294 }
295
sieve_extensions_deinit(struct sieve_instance * svinst)296 void sieve_extensions_deinit(struct sieve_instance *svinst)
297 {
298 sieve_extension_registry_deinit(svinst);
299 sieve_capability_registry_deinit(svinst);
300 }
301
302 /*
303 * Pre-loaded extensions
304 */
305
sieve_extensions_get_preloaded(struct sieve_instance * svinst,unsigned int * count_r)306 const struct sieve_extension *const *sieve_extensions_get_preloaded
307 (struct sieve_instance *svinst, unsigned int *count_r)
308 {
309 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
310
311 return array_get(&ext_reg->preloaded_extensions, count_r);
312 }
313
314 /*
315 * Extension registry
316 */
317
_sieve_extension_load(struct sieve_extension * ext)318 static bool _sieve_extension_load(struct sieve_extension *ext)
319 {
320 /* Call load handler */
321 if ( ext->def != NULL && ext->def->load != NULL &&
322 !ext->def->load(ext, &ext->context) ) {
323 e_error(ext->svinst->event,
324 "failed to load '%s' extension support.",
325 ext->def->name);
326 return FALSE;
327 }
328
329 return TRUE;
330 }
331
_sieve_extension_unload(struct sieve_extension * ext)332 static void _sieve_extension_unload(struct sieve_extension *ext)
333 {
334 /* Call unload handler */
335 if ( ext->def != NULL && ext->def->unload != NULL )
336 ext->def->unload(ext);
337 ext->context = NULL;
338 }
339
sieve_extension_registry_init(struct sieve_instance * svinst)340 static void sieve_extension_registry_init(struct sieve_instance *svinst)
341 {
342 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
343
344 p_array_init(&ext_reg->extensions, svinst->pool, 50);
345 hash_table_create
346 (&ext_reg->extension_index, default_pool, 0, str_hash, strcmp);
347 }
348
sieve_extension_registry_deinit(struct sieve_instance * svinst)349 static void sieve_extension_registry_deinit(struct sieve_instance *svinst)
350 {
351 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
352 struct sieve_extension * const *exts;
353 unsigned int i, ext_count;
354
355 if ( !hash_table_is_created(ext_reg->extension_index) ) return;
356
357 exts = array_get_modifiable(&ext_reg->extensions, &ext_count);
358 for ( i = 0; i < ext_count; i++ ) {
359 _sieve_extension_unload(exts[i]);
360 }
361
362 hash_table_destroy(&ext_reg->extension_index);
363 }
364
sieve_extension_reload(const struct sieve_extension * ext)365 bool sieve_extension_reload(const struct sieve_extension *ext)
366 {
367 struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
368 struct sieve_extension * const *mod_ext;
369 int ext_id = ext->id;
370
371 /* Let's not just cast the 'const' away */
372 if ( ext_id >= 0 && ext_id < (int) array_count(&ext_reg->extensions) ) {
373 mod_ext = array_idx(&ext_reg->extensions, ext_id);
374
375 return _sieve_extension_load(*mod_ext);
376 }
377
378 return FALSE;
379 }
380
sieve_extension_lookup(struct sieve_instance * svinst,const char * name)381 static struct sieve_extension *sieve_extension_lookup
382 (struct sieve_instance *svinst, const char *name)
383 {
384 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
385
386 return hash_table_lookup(ext_reg->extension_index, name);
387 }
388
sieve_extension_alloc(struct sieve_instance * svinst,const struct sieve_extension_def * extdef)389 static struct sieve_extension *sieve_extension_alloc
390 (struct sieve_instance *svinst,
391 const struct sieve_extension_def *extdef)
392 {
393 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
394 struct sieve_extension *ext, **extr;
395 int ext_id;
396
397 ext_id = (int)array_count(&ext_reg->extensions);
398
399 /* Add extension to the registry */
400 extr = array_append_space(&ext_reg->extensions);
401 *extr = ext = p_new(svinst->pool, struct sieve_extension, 1);
402 ext->id = ext_id;
403 ext->def = extdef;
404 ext->svinst = svinst;
405 return ext;
406 }
407
_sieve_extension_register(struct sieve_instance * svinst,const struct sieve_extension_def * extdef,bool load,bool required)408 static struct sieve_extension *_sieve_extension_register
409 (struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
410 bool load, bool required)
411 {
412 struct sieve_extension *ext;
413
414 ext = sieve_extension_lookup(svinst, extdef->name);
415
416 /* Register extension if it is not registered already */
417 if ( ext == NULL ) {
418 ext = sieve_extension_alloc(svinst, extdef);
419 hash_table_insert
420 (svinst->ext_reg->extension_index, extdef->name, ext);
421
422 } else if ( ext->overridden ) {
423 /* Create a dummy */
424 ext = sieve_extension_alloc(svinst, extdef);
425
426 } else {
427 /* Re-register it if it were previously unregistered
428 * (not going to happen)
429 */
430 i_assert( ext->def == NULL || ext->def == extdef );
431 ext->def = extdef;
432 }
433
434 /* Enable extension */
435 if ( load || required ) {
436 ext->enabled = ( ext->enabled || load );
437
438 /* Call load handler if extension was not loaded already */
439 if ( !ext->loaded ) {
440 if ( !_sieve_extension_load(ext) )
441 return NULL;
442 }
443
444 ext->loaded = TRUE;
445 }
446
447 ext->required = ( ext->required || required );
448
449 return ext;
450 }
451
sieve_extension_register(struct sieve_instance * svinst,const struct sieve_extension_def * extdef,bool load)452 const struct sieve_extension *sieve_extension_register
453 (struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
454 bool load)
455 {
456 return _sieve_extension_register(svinst, extdef, load, FALSE);
457 }
458
sieve_extension_unregister(const struct sieve_extension * ext)459 void sieve_extension_unregister(const struct sieve_extension *ext)
460 {
461 struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
462 struct sieve_extension * const *mod_ext;
463 int ext_id = ext->id;
464
465 if ( ext_id >= 0 && ext_id < (int) array_count(&ext_reg->extensions) ) {
466 mod_ext = array_idx(&ext_reg->extensions, ext_id);
467
468 sieve_extension_capabilities_unregister(*mod_ext);
469 _sieve_extension_unload(*mod_ext);
470 (*mod_ext)->loaded = FALSE;
471 (*mod_ext)->enabled = FALSE;
472 (*mod_ext)->def = NULL;
473 }
474 }
475
sieve_extension_replace(struct sieve_instance * svinst,const struct sieve_extension_def * extdef,bool load)476 const struct sieve_extension *sieve_extension_replace
477 (struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
478 bool load)
479 {
480 struct sieve_extension *ext;
481
482 ext = sieve_extension_lookup(svinst, extdef->name);
483 if (ext != NULL)
484 sieve_extension_unregister(ext);
485 return sieve_extension_register(svinst, extdef, load);
486 }
487
sieve_extension_require(struct sieve_instance * svinst,const struct sieve_extension_def * extdef,bool load)488 const struct sieve_extension *sieve_extension_require
489 (struct sieve_instance *svinst, const struct sieve_extension_def *extdef,
490 bool load)
491 {
492 return _sieve_extension_register(svinst, extdef, load, TRUE);
493 }
494
sieve_extension_override(struct sieve_instance * svinst,const char * name,const struct sieve_extension * ext)495 void sieve_extension_override
496 (struct sieve_instance *svinst, const char *name,
497 const struct sieve_extension *ext)
498 {
499 struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
500 struct sieve_extension * const *mod_ext;
501 struct sieve_extension *old_ext;
502
503 old_ext = sieve_extension_lookup(svinst, name);
504 if (old_ext == ext)
505 return;
506 i_assert( old_ext == NULL || !old_ext->overridden );
507
508 i_assert( ext->id >= 0 &&
509 ext->id < (int) array_count(&ext_reg->extensions) );
510 mod_ext = array_idx(&ext_reg->extensions, ext->id);
511
512 hash_table_update
513 (ext_reg->extension_index, name, *mod_ext);
514 if ( old_ext != NULL )
515 old_ext->overridden = TRUE;
516 }
517
sieve_extensions_get_count(struct sieve_instance * svinst)518 unsigned int sieve_extensions_get_count(struct sieve_instance *svinst)
519 {
520 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
521
522 return array_count(&ext_reg->extensions);
523 }
524
525 const struct sieve_extension *const *
sieve_extensions_get_all(struct sieve_instance * svinst,unsigned int * count_r)526 sieve_extensions_get_all(struct sieve_instance *svinst,
527 unsigned int *count_r)
528 {
529 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
530
531 return (const struct sieve_extension *const *)
532 array_get(&ext_reg->extensions, count_r);
533 }
534
sieve_extension_get_by_id(struct sieve_instance * svinst,unsigned int ext_id)535 const struct sieve_extension *sieve_extension_get_by_id
536 (struct sieve_instance *svinst, unsigned int ext_id)
537 {
538 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
539 struct sieve_extension * const *ext;
540
541 if ( ext_id < array_count(&ext_reg->extensions) ) {
542 ext = array_idx(&ext_reg->extensions, ext_id);
543
544 if ( (*ext)->def != NULL && ((*ext)->enabled || (*ext)->required) )
545 return *ext;
546 }
547
548 return NULL;
549 }
550
sieve_extension_get_by_name(struct sieve_instance * svinst,const char * name)551 const struct sieve_extension *sieve_extension_get_by_name
552 (struct sieve_instance *svinst, const char *name)
553 {
554 const struct sieve_extension *ext;
555
556 if ( *name == '@' )
557 return NULL;
558
559 if ( strlen(name) > 128 )
560 return NULL;
561
562 ext = sieve_extension_lookup(svinst, name);
563 if ( ext == NULL || ext->def == NULL || (!ext->enabled && !ext->required))
564 return NULL;
565
566 return ext;
567 }
568
_sieve_extension_listable(const struct sieve_extension * ext)569 static inline bool _sieve_extension_listable(const struct sieve_extension *ext)
570 {
571 return ( ext->enabled && ext->def != NULL && *(ext->def->name) != '@'
572 && !ext->dummy && !ext->global && !ext->overridden);
573 }
574
sieve_extensions_get_string(struct sieve_instance * svinst)575 const char *sieve_extensions_get_string(struct sieve_instance *svinst)
576 {
577 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
578 string_t *extstr = t_str_new(256);
579 struct sieve_extension * const *exts;
580 unsigned int i, ext_count;
581
582 exts = array_get(&ext_reg->extensions, &ext_count);
583
584 if ( ext_count > 0 ) {
585 i = 0;
586
587 /* Find first listable extension */
588 while ( i < ext_count && !_sieve_extension_listable(exts[i]) )
589 i++;
590
591 if ( i < ext_count ) {
592 /* Add first to string */
593 str_append(extstr, exts[i]->def->name);
594 i++;
595
596 /* Add others */
597 for ( ; i < ext_count; i++ ) {
598 if ( _sieve_extension_listable(exts[i]) ) {
599 str_append_c(extstr, ' ');
600 str_append(extstr, exts[i]->def->name);
601 }
602 }
603 }
604 }
605
606 return str_c(extstr);
607 }
608
sieve_extension_set_enabled(struct sieve_extension * ext,bool enabled)609 static void sieve_extension_set_enabled
610 (struct sieve_extension *ext, bool enabled)
611 {
612 if ( enabled ) {
613 ext->enabled = TRUE;
614
615 if ( !ext->loaded ) {
616 (void)_sieve_extension_load(ext);
617 }
618
619 ext->loaded = TRUE;
620 } else {
621 ext->enabled = FALSE;
622 }
623 }
624
sieve_extension_set_global(struct sieve_extension * ext,bool enabled)625 static void sieve_extension_set_global
626 (struct sieve_extension *ext, bool enabled)
627 {
628 if ( enabled ) {
629 sieve_extension_set_enabled(ext, TRUE);
630 ext->global = TRUE;
631 } else {
632 ext->global = FALSE;
633 }
634 }
635
sieve_extension_set_implicit(struct sieve_extension * ext,bool enabled)636 static void sieve_extension_set_implicit
637 (struct sieve_extension *ext, bool enabled)
638 {
639 if ( enabled ) {
640 sieve_extension_set_enabled(ext, TRUE);
641 ext->implicit = TRUE;
642 } else {
643 ext->implicit = FALSE;
644 }
645 }
646
sieve_extensions_set_string(struct sieve_instance * svinst,const char * ext_string,bool global,bool implicit)647 void sieve_extensions_set_string
648 (struct sieve_instance *svinst, const char *ext_string,
649 bool global, bool implicit)
650 {
651 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
652 ARRAY(const struct sieve_extension *) enabled_extensions;
653 ARRAY(const struct sieve_extension *) disabled_extensions;
654 const struct sieve_extension *const *ext_enabled;
655 const struct sieve_extension *const *ext_disabled;
656 struct sieve_extension **exts;
657 const char **ext_names;
658 unsigned int i, ext_count, ena_count, dis_count;
659 bool relative = FALSE;
660
661 if ( ext_string == NULL ) {
662 if ( global || implicit ) return;
663
664 /* Enable all */
665 exts = array_get_modifiable(&ext_reg->extensions, &ext_count);
666
667 for ( i = 0; i < ext_count; i++ )
668 sieve_extension_set_enabled(exts[i], TRUE);
669
670 return;
671 }
672
673 T_BEGIN {
674 t_array_init(&enabled_extensions, array_count(&ext_reg->extensions));
675 t_array_init(&disabled_extensions, array_count(&ext_reg->extensions));
676
677 ext_names = t_strsplit_spaces(ext_string, " \t");
678
679 while ( *ext_names != NULL ) {
680 const char *name = *ext_names;
681
682 ext_names++;
683
684 if ( *name != '\0' ) {
685 const struct sieve_extension *ext;
686 char op = '\0'; /* No add/remove operation */
687
688 if ( *name == '+' /* Add to existing config */
689 || *name == '-' ) { /* Remove from existing config */
690 op = *name++;
691 relative = TRUE;
692 }
693
694 if ( *name == '@' )
695 ext = NULL;
696 else
697 ext = hash_table_lookup(ext_reg->extension_index, name);
698
699 if ( ext == NULL || ext->def == NULL ) {
700 e_warning(svinst->event,
701 "ignored unknown extension '%s' while configuring "
702 "available extensions", name);
703 continue;
704 }
705
706 if ( op == '-' )
707 array_append(&disabled_extensions, &ext, 1);
708 else
709 array_append(&enabled_extensions, &ext, 1);
710 }
711 }
712
713 exts = array_get_modifiable(&ext_reg->extensions, &ext_count);
714 ext_enabled = array_get(&enabled_extensions, &ena_count);
715 ext_disabled = array_get(&disabled_extensions, &dis_count);
716
717 /* Set new extension status */
718
719 for ( i = 0; i < ext_count; i++ ) {
720 unsigned int j;
721 bool enabled = FALSE;
722
723 if ( exts[i]->id < 0 || exts[i]->def == NULL ||
724 *(exts[i]->def->name) == '@' ) {
725 continue;
726 }
727
728 /* If extensions are specified relative to the default set,
729 * we first need to check which ones are disabled
730 */
731
732 if ( relative ) {
733 if ( global )
734 enabled = exts[i]->global;
735 else if ( implicit )
736 enabled = exts[i]->implicit;
737 else
738 enabled = exts[i]->enabled;
739
740 if ( enabled ) {
741 /* Disable if explicitly disabled */
742 for ( j = 0; j < dis_count; j++ ) {
743 if ( ext_disabled[j]->def == exts[i]->def ) {
744 enabled = FALSE;
745 break;
746 }
747 }
748 }
749 }
750
751 /* Enable if listed with '+' or no prefix */
752
753 for ( j = 0; j < ena_count; j++ ) {
754 if ( ext_enabled[j]->def == exts[i]->def ) {
755 enabled = TRUE;
756 break;
757 }
758 }
759
760 /* Perform actual activation/deactivation */
761 if ( global ) {
762 sieve_extension_set_global(exts[i], enabled);
763 } else if ( implicit ) {
764 sieve_extension_set_implicit(exts[i], enabled);
765 } else {
766 sieve_extension_set_enabled(exts[i], enabled);
767 }
768 }
769 } T_END;
770 }
771
sieve_get_match_type_extension(struct sieve_instance * svinst)772 const struct sieve_extension *sieve_get_match_type_extension
773 (struct sieve_instance *svinst)
774 {
775 return svinst->ext_reg->match_type_extension;
776 }
777
sieve_get_comparator_extension(struct sieve_instance * svinst)778 const struct sieve_extension *sieve_get_comparator_extension
779 (struct sieve_instance *svinst)
780 {
781 return svinst->ext_reg->comparator_extension;
782 }
783
sieve_get_address_part_extension(struct sieve_instance * svinst)784 const struct sieve_extension *sieve_get_address_part_extension
785 (struct sieve_instance *svinst)
786 {
787 return svinst->ext_reg->address_part_extension;
788 }
789
sieve_enable_debug_extension(struct sieve_instance * svinst)790 void sieve_enable_debug_extension(struct sieve_instance *svinst)
791 {
792 (void) sieve_extension_register(svinst, &vnd_debug_extension, TRUE);
793 }
794
795 /*
796 * Extension capabilities
797 */
798
799 struct sieve_capability_registration {
800 const struct sieve_extension *ext;
801 const struct sieve_extension_capabilities *capabilities;
802 };
803
sieve_capability_registry_init(struct sieve_instance * svinst)804 void sieve_capability_registry_init(struct sieve_instance *svinst)
805 {
806 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
807
808 hash_table_create
809 (&ext_reg->capabilities_index, default_pool, 0, str_hash, strcmp);
810 }
811
sieve_capability_registry_deinit(struct sieve_instance * svinst)812 void sieve_capability_registry_deinit(struct sieve_instance *svinst)
813 {
814 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
815
816 if ( !hash_table_is_created(ext_reg->capabilities_index) ) return;
817
818 hash_table_destroy(&svinst->ext_reg->capabilities_index);
819 }
820
sieve_extension_capabilities_register(const struct sieve_extension * ext,const struct sieve_extension_capabilities * cap)821 void sieve_extension_capabilities_register
822 (const struct sieve_extension *ext,
823 const struct sieve_extension_capabilities *cap)
824 {
825 struct sieve_instance *svinst = ext->svinst;
826 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
827 struct sieve_capability_registration *reg;
828
829 reg = hash_table_lookup(ext_reg->capabilities_index, cap->name);
830 if (reg != NULL) {
831 /* Already registered */
832 return;
833 }
834
835 reg = p_new(svinst->pool, struct sieve_capability_registration, 1);
836 reg->ext = ext;
837 reg->capabilities = cap;
838
839 hash_table_insert(ext_reg->capabilities_index, cap->name, reg);
840 }
841
sieve_extension_capabilities_unregister(const struct sieve_extension * ext)842 void sieve_extension_capabilities_unregister
843 (const struct sieve_extension *ext)
844 {
845 struct sieve_extension_registry *ext_reg = ext->svinst->ext_reg;
846 struct hash_iterate_context *hictx;
847 const char *name;
848 struct sieve_capability_registration *reg;
849
850 hictx = hash_table_iterate_init(ext_reg->capabilities_index);
851 while ( hash_table_iterate(hictx, ext_reg->capabilities_index, &name, ®) ) {
852 if ( reg->ext == ext )
853 hash_table_remove(ext_reg->capabilities_index, name);
854 }
855 hash_table_iterate_deinit(&hictx);
856 }
857
sieve_extension_capabilities_get_string(struct sieve_instance * svinst,const char * cap_name)858 const char *sieve_extension_capabilities_get_string
859 (struct sieve_instance *svinst, const char *cap_name)
860 {
861 struct sieve_extension_registry *ext_reg = svinst->ext_reg;
862 const struct sieve_capability_registration *cap_reg =
863 hash_table_lookup(ext_reg->capabilities_index, cap_name);
864 const struct sieve_extension_capabilities *cap;
865
866 if ( cap_reg == NULL || cap_reg->capabilities == NULL )
867 return NULL;
868
869 cap = cap_reg->capabilities;
870
871 if ( cap->get_string == NULL || !cap_reg->ext->enabled )
872 return NULL;
873
874 return cap->get_string(cap_reg->ext);
875 }
876
877
878
879
880