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, &regex_extension, &imap4flags_extension,
124 	&copy_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 	&notify_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, &reg) ) {
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