1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
10
#include "sieve-error.h"
11
#include "sieve-extensions.h"
14
* Forward declarations
17
static void sieve_extensions_init_registry(void);
18
static void sieve_extensions_deinit_registry(void);
20
static void sieve_extensions_init_capabilities(void);
21
static void sieve_extensions_deinit_capabilities(void);
24
* Pre-loaded 'extensions'
27
extern const struct sieve_extension comparator_extension;
28
extern const struct sieve_extension match_type_extension;
29
extern const struct sieve_extension address_part_extension;
31
const struct sieve_extension *sieve_preloaded_extensions[] = {
32
&comparator_extension, &match_type_extension, &address_part_extension
35
const unsigned int sieve_preloaded_extensions_count =
36
N_ELEMENTS(sieve_preloaded_extensions);
42
/* FIXME: This is stupid. Define a comparator-* extension and be done with it */
44
static const struct sieve_extension comparator_i_octet_extension = {
46
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
47
SIEVE_EXT_DEFINE_NO_OPERATIONS,
48
SIEVE_EXT_DEFINE_NO_OPERANDS
51
static const struct sieve_extension comparator_i_ascii_casemap_extension = {
52
"comparator-i;ascii-casemap",
53
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
54
SIEVE_EXT_DEFINE_NO_OPERATIONS,
55
SIEVE_EXT_DEFINE_NO_OPERANDS
62
extern const struct sieve_extension fileinto_extension;
63
extern const struct sieve_extension reject_extension;
64
extern const struct sieve_extension envelope_extension;
65
extern const struct sieve_extension encoded_character_extension;
68
* Native 'plugin' extensions
71
extern const struct sieve_extension vacation_extension;
72
extern const struct sieve_extension subaddress_extension;
73
extern const struct sieve_extension comparator_i_ascii_numeric_extension;
74
extern const struct sieve_extension relational_extension;
75
extern const struct sieve_extension regex_extension;
76
extern const struct sieve_extension imap4flags_extension;
77
extern const struct sieve_extension copy_extension;
78
extern const struct sieve_extension include_extension;
79
extern const struct sieve_extension body_extension;
80
extern const struct sieve_extension variables_extension;
81
extern const struct sieve_extension enotify_extension;
82
extern const struct sieve_extension environment_extension;
83
extern const struct sieve_extension mailbox_extension;
84
extern const struct sieve_extension date_extension;
87
* List of native extensions
90
const struct sieve_extension *sieve_core_extensions[] = {
91
/* Preloaded 'extensions' */
92
&comparator_extension, &match_type_extension, &address_part_extension,
94
/* Dummy extensions */
95
&comparator_i_octet_extension, &comparator_i_ascii_casemap_extension,
98
&fileinto_extension, &reject_extension, &envelope_extension,
99
&encoded_character_extension,
102
&vacation_extension, &subaddress_extension,
103
&comparator_i_ascii_numeric_extension,
104
&relational_extension, ®ex_extension, &imap4flags_extension,
105
©_extension, &include_extension, &body_extension,
106
&variables_extension, &enotify_extension, &environment_extension,
107
&mailbox_extension, &date_extension
110
const unsigned int sieve_core_extensions_count =
111
N_ELEMENTS(sieve_core_extensions);
114
* Deprecated extensions
117
extern const struct sieve_extension imapflags_extension;
118
extern const struct sieve_extension notify_extension;
120
const struct sieve_extension *sieve_deprecated_extensions[] = {
121
&imapflags_extension,
125
const unsigned int sieve_deprecated_extensions_count =
126
N_ELEMENTS(sieve_deprecated_extensions);
129
* Unfinished extensions
132
#ifdef HAVE_SIEVE_UNFINISHED
134
extern const struct sieve_extension ereject_extension;
136
const struct sieve_extension *sieve_unfinished_extensions[] = {
140
const unsigned int sieve_unfinished_extensions_count =
141
N_ELEMENTS(sieve_unfinished_extensions);
143
#endif /* HAVE_SIEVE_UNFINISHED */
146
* Extensions init/deinit
149
bool sieve_extensions_init(void)
153
sieve_extensions_init_registry();
154
sieve_extensions_init_capabilities();
156
/* Pre-load core extensions */
157
for ( i = 0; i < sieve_core_extensions_count; i++ ) {
158
(void)sieve_extension_register(sieve_core_extensions[i], TRUE);
161
/* Register deprecated extensions */
162
for ( i = 0; i < sieve_deprecated_extensions_count; i++ ) {
163
(void)sieve_extension_register(sieve_deprecated_extensions[i], FALSE);
166
#ifdef HAVE_SIEVE_UNFINISHED
167
/* Register unfinished extensions */
168
for ( i = 0; i < sieve_unfinished_extensions_count; i++ ) {
169
(void)sieve_extension_register(sieve_unfinished_extensions[i], FALSE);
173
/* More extensions can be added through plugins */
178
void sieve_extensions_deinit(void)
180
sieve_extensions_deinit_capabilities();
181
sieve_extensions_deinit_registry();
188
struct sieve_extension_registration {
189
const struct sieve_extension *extension;
195
static ARRAY_DEFINE(extensions, struct sieve_extension_registration);
196
static struct hash_table *extension_index;
198
static void sieve_extensions_init_registry(void)
200
i_array_init(&extensions, 30);
201
extension_index = hash_table_create
202
(default_pool, default_pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
205
static bool _sieve_extension_load
206
(const struct sieve_extension *extension)
208
/* Call load handler */
209
if ( extension->load != NULL && !extension->load() ) {
210
sieve_sys_error("failed to load '%s' extension support.",
218
static struct sieve_extension_registration *_sieve_extension_register
219
(const struct sieve_extension *extension, bool load)
221
struct sieve_extension_registration *ereg =
222
(struct sieve_extension_registration *)
223
hash_table_lookup(extension_index, extension->name);
225
/* Register extension if it is not registered already */
226
if ( ereg == NULL ) {
227
int ext_id = array_count(&extensions);
229
/* Add extension to the registry */
231
ereg = array_append_space(&extensions);
234
hash_table_insert(extension_index, (void *) extension->name, (void *) ereg);
237
/* Enable extension */
238
if ( extension->_id != NULL && load ) {
239
/* Make sure extension is enabled */
240
*(extension->_id) = ereg->id;
242
/* Call load handler if extension was not loaded already */
243
if ( !ereg->loaded ) {
244
if ( !_sieve_extension_load(extension) )
251
ereg->extension = extension;
256
int sieve_extension_register
257
(const struct sieve_extension *extension, bool load)
259
struct sieve_extension_registration *ereg;
261
/* Register the extension */
262
if ( (ereg=_sieve_extension_register(extension, load)) == NULL ) {
269
int sieve_extension_require(const struct sieve_extension *extension)
271
struct sieve_extension_registration *ereg;
273
/* Register (possibly unknown) extension */
274
if ( (ereg=_sieve_extension_register(extension, TRUE)) == NULL ) {
278
ereg->required = TRUE;
282
int sieve_extensions_get_count(void)
284
return array_count(&extensions);
287
const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id)
289
const struct sieve_extension_registration *ereg;
291
if ( ext_id < array_count(&extensions) ) {
292
ereg = array_idx(&extensions, ext_id);
294
if ( SIEVE_EXT_ENABLED(ereg->extension) )
295
return ereg->extension;
301
const struct sieve_extension *sieve_extension_get_by_name(const char *name)
303
struct sieve_extension_registration *ereg;
308
ereg = (struct sieve_extension_registration *)
309
hash_table_lookup(extension_index, name);
311
if ( ereg == NULL || !SIEVE_EXT_ENABLED(ereg->extension) )
314
return ereg->extension;
317
static inline bool _list_extension
318
(const struct sieve_extension_registration *ereg)
321
( SIEVE_EXT_ENABLED(ereg->extension) &&
322
*(ereg->extension->name) != '@' );
325
const char *sieve_extensions_get_string(void)
327
unsigned int i, ext_count;
328
const struct sieve_extension_registration *eregs;
329
string_t *extstr = t_str_new(256);
331
eregs = array_get(&extensions, &ext_count);
333
if ( ext_count > 0 ) {
336
/* Find first listable extension */
337
while ( i < ext_count && !_list_extension(&eregs[i]) )
340
if ( i < ext_count ) {
341
/* Add first to string */
342
str_append(extstr, eregs[i].extension->name);
346
for ( ; i < ext_count; i++ ) {
347
if ( _list_extension(&eregs[i]) ) {
348
str_append_c(extstr, ' ');
349
str_append(extstr, eregs[i].extension->name);
355
return str_c(extstr);
358
static void sieve_extension_enable(struct sieve_extension_registration *ereg)
360
if ( ereg->extension->_id != NULL ) {
361
*(ereg->extension->_id) = ereg->id;
363
if ( !ereg->loaded ) {
364
(void)_sieve_extension_load(ereg->extension);
371
static void sieve_extension_disable(struct sieve_extension_registration *ereg)
373
if ( ereg->extension->_id != NULL )
374
*(ereg->extension->_id) = -1;
377
void sieve_extensions_set_string(const char *ext_string)
379
ARRAY_DEFINE(enabled_extensions, const struct sieve_extension *);
380
ARRAY_DEFINE(disabled_extensions, const struct sieve_extension *);
381
const struct sieve_extension *const *ext_enabled;
382
const struct sieve_extension *const *ext_disabled;
383
struct sieve_extension_registration *eregs;
384
const char **ext_names;
385
unsigned int i, ext_count, ena_count, dis_count;
386
bool relative = FALSE;
388
if ( ext_string == NULL ) {
390
eregs = array_get_modifiable(&extensions, &ext_count);
392
for ( i = 0; i < ext_count; i++ )
393
sieve_extension_enable(&eregs[i]);
399
t_array_init(&enabled_extensions, array_count(&extensions));
400
t_array_init(&disabled_extensions, array_count(&extensions));
402
ext_names = t_strsplit_spaces(ext_string, " \t");
404
while ( *ext_names != NULL ) {
405
const char *name = *ext_names;
409
if ( *name != '\0' ) {
410
const struct sieve_extension_registration *ereg;
411
char op = '\0'; /* No add/remove operation */
413
if ( *name == '+' /* Add to existing config */
414
|| *name == '-' ) { /* Remove from existing config */
422
ereg = (const struct sieve_extension_registration *)
423
hash_table_lookup(extension_index, name);
425
if ( ereg == NULL ) {
427
"ignored unknown extension '%s' while configuring "
428
"available extensions", name);
433
array_append(&disabled_extensions, &ereg->extension, 1);
435
array_append(&enabled_extensions, &ereg->extension, 1);
439
eregs = array_get_modifiable(&extensions, &ext_count);
440
ext_enabled = array_get(&enabled_extensions, &ena_count);
441
ext_disabled = array_get(&disabled_extensions, &dis_count);
443
/* Set new extension status */
445
for ( i = 0; i < ext_count; i++ ) {
447
bool disabled = TRUE;
449
/* If extensions are specified relative to the default set,
450
* we first need to check which ones are disabled
454
/* Enable if core extension */
455
for ( j = 0; j < sieve_core_extensions_count; j++ ) {
456
if ( sieve_core_extensions[j] == eregs[i].extension ) {
462
/* Disable if explicitly disabled */
463
for ( j = 0; j < dis_count; j++ ) {
464
if ( ext_disabled[j] == eregs[i].extension ) {
471
/* Enable if listed with '+' or no prefix */
473
for ( j = 0; j < ena_count; j++ ) {
474
if ( ext_enabled[j] == eregs[i].extension ) {
480
/* Perform actual activation/deactivation */
482
if ( eregs[i].extension->_id != NULL &&
483
*(eregs[i].extension->name) != '@' ) {
484
if ( disabled && !eregs[i].required )
485
sieve_extension_disable(&eregs[i]);
487
sieve_extension_enable(&eregs[i]);
493
static void sieve_extensions_deinit_registry(void)
495
struct hash_iterate_context *itx =
496
hash_table_iterate_init(extension_index);
500
while ( hash_table_iterate(itx, &key, &value) ) {
501
struct sieve_extension_registration *ereg =
502
(struct sieve_extension_registration *) value;
503
const struct sieve_extension *ext = ereg->extension;
505
if ( ext->unload != NULL )
509
hash_table_iterate_deinit(&itx);
511
array_free(&extensions);
512
hash_table_destroy(&extension_index);
516
* Extension capabilities
519
static struct hash_table *capabilities_index;
521
static void sieve_extensions_init_capabilities(void)
523
capabilities_index = hash_table_create
524
(default_pool, default_pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
527
static void sieve_extensions_deinit_capabilities(void)
529
hash_table_destroy(&capabilities_index);
532
void sieve_extension_capabilities_register
533
(const struct sieve_extension_capabilities *cap)
536
(capabilities_index, (void *) cap->name, (void *) cap);
539
const char *sieve_extension_capabilities_get_string
540
(const char *cap_name)
542
const struct sieve_extension_capabilities *cap =
543
(const struct sieve_extension_capabilities *)
544
hash_table_lookup(capabilities_index, cap_name);
546
if ( cap == NULL || cap->get_string == NULL ||
547
!SIEVE_EXT_ENABLED(cap->extension) )
550
return cap->get_string();