~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101901

« back to all changes in this revision

Viewing changes to libsieve/src/lib-sieve/sieve-extensions.c

  • Committer: Chuck Short
  • Date: 2010-01-21 20:21:25 UTC
  • mfrom: (4.1.11 squeeze)
  • Revision ID: zulcss@ubuntu.com-20100121202125-pme73o491kfwj5nc
* Merge from debian testing, remaining changes:
  + Add new binary pkg dovecot-postfix that integrates postfix and dovecot
    automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restriction
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
  + debian/dovecot-postfix.dirs: create backup directory for postfix's config
    configuration
  + restart postfix and dovecot.
  + debian/dovecot-postfix.postrm:
    - remove all dovecot related configuration from postfix.
    - restart postfix and dovecot.
  + debian/dovecot-common.init:
    - check if /etc/dovecot/dovecot-postfix.conf exists and use it
      as the configuration file if so.
  + debian/patches/warning-ubuntu-postfix.dpatch
    - add warning about dovecot-postfix.conf in dovecot default
      configuration file
  + debian/patches/dovecot-postfix.conf.diff:
    - Ubuntu server custom changes to the default dovecot configuration for
      better interfation with postfix.
    - enable sieve plugin.
    - Ubuntu server custom changes to the default dovecot configuration for
      better integration with postfix:
      - enable imap, pop3, imaps, pop3s and managesieve by default.
      - enable dovecot LDA (deliver).
      - enable SASL auth socket in postfix private directory
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules: install profile.
     - debian/control: suggest ufw.
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). (LP: #254721)
   + debian/control: Update Vcs-* headers.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
* New upstream release.
* debian/patches/gold-fix.patch: Removed. Fixed upstream.
* Moved libexec to lib corrections in dovecot-managesieve.patch and
  dovecot-managesieve-dist.patch to dovecot-example.patch
* debian/patches/dovecot-mboxlocking.patch: Regenerated to avoid FTBFS
  when quilt isn't installed.
* debian/patches/quota-mountpoint.patch: Removed. Not needed anymore.
* debian/patches/dovecot-quota.patch: Removed. Quotas aren't properly
  enabled unless mail_plugins = quota imap_quota.
* debian/patches/gold-fix.patch: Fixed configure script to build even
  with binutils-gold or --no-add-needed linker flag (Closes: #554306)
* debian/dovecot-common.init: fixed LSB headers. Thanks to Pascal Volk.
  (Closes: #558040)
* debian/changelog: added CVE references to previous changelog entry.
* debian/rules: checked up the build system. It's not fragile anymore.
  (Closes: 493803)
* debian/dovecot-common.postinst: Now invoking dpkg-reconfigure
  on dovecot-common is enough to generate new certificates
  if the previous ones were removed. (Closes: #545582)
* debian/rules: No longer install convert-tool in /usr/bin.
  It isn't an user utility and it should stay in /usr/lib/dovecot
  like all other similar tool.
* New upstream release. (Closes: #557601)
* [SECURITY] Fixes local information disclosure and denial of service.
  (see: http://www.dovecot.org/list/dovecot-news/2009-November/000143.html
  and CVE-2009-3897)
* Added myself to uploaders.
* Switched to the new source format "3.0 (quilt)":
  - removed dpatch from build-depends
  - removed debian/README.source because now we use only standard
    dpkg features
  - regenerated all patches
* Prepared to switch to multi-origin source:
  - recreated dovecot-libsieve.patch and dovecot-managesieve-dist.patch
    starting from the upstream tarball
  - removed all autotools related build-depends and build-conflict
  - renamed dovecot-libsieve and dovecot-managesieve directories
    to libsieve and managesieve.
* debian/rules: Moved the configuration of libsieve and managesieve from
  the build phase to the configuration phase
* Added dovecot-dbg package  with debugging symbols.  Thanks Stephan Bosch.
  (Closes: #554710)
* Fixed some stray libexec'isms in the default configuration.
* New upstream release.
* debian/dovecot-common.init:
  - use $CONF when starting the daemon. (Closes: #549944)
  - always output start/stop messages. (Closes: #523810)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2002-2009 Dovecot Sieve 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-error.h"
 
11
#include "sieve-extensions.h"
 
12
 
 
13
/*
 
14
 * Forward declarations 
 
15
 */
 
16
 
 
17
static void sieve_extensions_init_registry(void);
 
18
static void sieve_extensions_deinit_registry(void);
 
19
 
 
20
static void sieve_extensions_init_capabilities(void);
 
21
static void sieve_extensions_deinit_capabilities(void);
 
22
 
 
23
/* 
 
24
 * Pre-loaded 'extensions' 
 
25
 */
 
26
 
 
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;
 
30
 
 
31
const struct sieve_extension *sieve_preloaded_extensions[] = {
 
32
        &comparator_extension, &match_type_extension, &address_part_extension
 
33
};
 
34
 
 
35
const unsigned int sieve_preloaded_extensions_count = 
 
36
        N_ELEMENTS(sieve_preloaded_extensions);
 
37
 
 
38
/* 
 
39
 * Dummy extensions 
 
40
 */
 
41
 
 
42
/* FIXME: This is stupid. Define a comparator-* extension and be done with it */
 
43
 
 
44
static const struct sieve_extension comparator_i_octet_extension = {
 
45
        "comparator-i;octet", 
 
46
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
47
        SIEVE_EXT_DEFINE_NO_OPERATIONS, 
 
48
        SIEVE_EXT_DEFINE_NO_OPERANDS
 
49
};
 
50
 
 
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
 
56
};
 
57
 
 
58
/* 
 
59
 * Core extensions 
 
60
 */
 
61
 
 
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;
 
66
 
 
67
/* 
 
68
 * Native 'plugin' extensions 
 
69
 */
 
70
 
 
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;
 
85
 
 
86
/*
 
87
 * List of native extensions
 
88
 */
 
89
 
 
90
const struct sieve_extension *sieve_core_extensions[] = {
 
91
        /* Preloaded 'extensions' */
 
92
        &comparator_extension, &match_type_extension, &address_part_extension,
 
93
        
 
94
        /* Dummy extensions */ 
 
95
        &comparator_i_octet_extension, &comparator_i_ascii_casemap_extension, 
 
96
        
 
97
        /* Core extensions */
 
98
        &fileinto_extension, &reject_extension, &envelope_extension, 
 
99
        &encoded_character_extension,
 
100
        
 
101
        /* 'Plugins' */
 
102
        &vacation_extension, &subaddress_extension, 
 
103
        &comparator_i_ascii_numeric_extension, 
 
104
        &relational_extension, &regex_extension, &imap4flags_extension,
 
105
        &copy_extension, &include_extension, &body_extension,
 
106
        &variables_extension, &enotify_extension, &environment_extension,
 
107
        &mailbox_extension, &date_extension
 
108
};
 
109
 
 
110
const unsigned int sieve_core_extensions_count =
 
111
        N_ELEMENTS(sieve_core_extensions);
 
112
 
 
113
/*
 
114
 * Deprecated extensions
 
115
 */
 
116
 
 
117
extern const struct sieve_extension imapflags_extension;
 
118
extern const struct sieve_extension notify_extension;
 
119
 
 
120
const struct sieve_extension *sieve_deprecated_extensions[] = {
 
121
        &imapflags_extension,
 
122
        &notify_extension
 
123
};
 
124
 
 
125
const unsigned int sieve_deprecated_extensions_count =
 
126
        N_ELEMENTS(sieve_deprecated_extensions);
 
127
 
 
128
/*
 
129
 * Unfinished extensions
 
130
 */
 
131
 
 
132
#ifdef HAVE_SIEVE_UNFINISHED
 
133
 
 
134
extern const struct sieve_extension ereject_extension;
 
135
 
 
136
const struct sieve_extension *sieve_unfinished_extensions[] = {
 
137
        &ereject_extension,
 
138
};
 
139
 
 
140
const unsigned int sieve_unfinished_extensions_count =
 
141
        N_ELEMENTS(sieve_unfinished_extensions);
 
142
 
 
143
#endif /* HAVE_SIEVE_UNFINISHED */
 
144
 
 
145
/* 
 
146
 * Extensions init/deinit
 
147
 */
 
148
 
 
149
bool sieve_extensions_init(void) 
 
150
{
 
151
        unsigned int i;
 
152
        
 
153
        sieve_extensions_init_registry();
 
154
        sieve_extensions_init_capabilities();
 
155
        
 
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);
 
159
        }
 
160
 
 
161
        /* Register deprecated extensions */
 
162
        for ( i = 0; i < sieve_deprecated_extensions_count; i++ ) {
 
163
                (void)sieve_extension_register(sieve_deprecated_extensions[i], FALSE);
 
164
        }
 
165
 
 
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);
 
170
        }
 
171
#endif
 
172
 
 
173
        /* More extensions can be added through plugins */
 
174
        
 
175
        return TRUE;
 
176
}
 
177
 
 
178
void sieve_extensions_deinit(void)
 
179
{       
 
180
        sieve_extensions_deinit_capabilities();
 
181
        sieve_extensions_deinit_registry();
 
182
}
 
183
 
 
184
/* 
 
185
 * Extension registry
 
186
 */
 
187
 
 
188
struct sieve_extension_registration {
 
189
        const struct sieve_extension *extension;
 
190
        int id;
 
191
        bool required;
 
192
        bool loaded;
 
193
};
 
194
 
 
195
static ARRAY_DEFINE(extensions, struct sieve_extension_registration); 
 
196
static struct hash_table *extension_index; 
 
197
 
 
198
static void sieve_extensions_init_registry(void)
 
199
{       
 
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);
 
203
}
 
204
 
 
205
static bool _sieve_extension_load
 
206
(const struct sieve_extension *extension)
 
207
{
 
208
        /* Call load handler */
 
209
        if ( extension->load != NULL && !extension->load() ) {
 
210
                sieve_sys_error("failed to load '%s' extension support.", 
 
211
                        extension->name);
 
212
                return FALSE;
 
213
        }
 
214
 
 
215
        return TRUE;
 
216
}
 
217
 
 
218
static struct sieve_extension_registration *_sieve_extension_register
 
219
(const struct sieve_extension *extension, bool load)
 
220
{
 
221
        struct sieve_extension_registration *ereg = 
 
222
                (struct sieve_extension_registration *) 
 
223
                hash_table_lookup(extension_index, extension->name);
 
224
 
 
225
        /* Register extension if it is not registered already */
 
226
        if ( ereg == NULL ) {
 
227
                int ext_id = array_count(&extensions);
 
228
 
 
229
                /* Add extension to the registry */
 
230
 
 
231
                ereg = array_append_space(&extensions);
 
232
                ereg->id = ext_id;
 
233
 
 
234
                hash_table_insert(extension_index, (void *) extension->name, (void *) ereg);
 
235
        }
 
236
 
 
237
        /* Enable extension */
 
238
        if ( extension->_id != NULL && load ) {
 
239
                /* Make sure extension is enabled */
 
240
                *(extension->_id) = ereg->id;
 
241
 
 
242
                /* Call load handler if extension was not loaded already */
 
243
                if ( !ereg->loaded ) {
 
244
                        if ( !_sieve_extension_load(extension) )
 
245
                                return NULL;
 
246
                }
 
247
 
 
248
                ereg->loaded = TRUE;
 
249
        }
 
250
 
 
251
        ereg->extension = extension;
 
252
 
 
253
        return ereg;
 
254
}
 
255
 
 
256
int sieve_extension_register
 
257
(const struct sieve_extension *extension, bool load) 
 
258
{
 
259
        struct sieve_extension_registration *ereg;
 
260
 
 
261
        /* Register the extension */
 
262
        if ( (ereg=_sieve_extension_register(extension, load)) == NULL ) {
 
263
                return -1;
 
264
        }
 
265
 
 
266
        return ereg->id;
 
267
}
 
268
 
 
269
int sieve_extension_require(const struct sieve_extension *extension)
 
270
{
 
271
        struct sieve_extension_registration *ereg;
 
272
 
 
273
        /* Register (possibly unknown) extension */
 
274
    if ( (ereg=_sieve_extension_register(extension, TRUE)) == NULL ) {
 
275
        return -1;
 
276
    }
 
277
 
 
278
        ereg->required = TRUE;
 
279
        return ereg->id;
 
280
}
 
281
 
 
282
int sieve_extensions_get_count(void)
 
283
{
 
284
        return array_count(&extensions);
 
285
}
 
286
 
 
287
const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id) 
 
288
{
 
289
        const struct sieve_extension_registration *ereg;
 
290
        
 
291
        if ( ext_id < array_count(&extensions) ) {
 
292
                ereg = array_idx(&extensions, ext_id);
 
293
 
 
294
                if ( SIEVE_EXT_ENABLED(ereg->extension) )
 
295
                        return ereg->extension;
 
296
        }
 
297
        
 
298
        return NULL;
 
299
}
 
300
 
 
301
const struct sieve_extension *sieve_extension_get_by_name(const char *name) 
 
302
{
 
303
        struct sieve_extension_registration *ereg;
 
304
        
 
305
        if ( *name == '@' )
 
306
                return NULL;    
 
307
                
 
308
        ereg = (struct sieve_extension_registration *) 
 
309
                hash_table_lookup(extension_index, name);
 
310
 
 
311
        if ( ereg == NULL || !SIEVE_EXT_ENABLED(ereg->extension) )
 
312
                return NULL;
 
313
                
 
314
        return ereg->extension;
 
315
}
 
316
 
 
317
static inline bool _list_extension
 
318
        (const struct sieve_extension_registration *ereg)
 
319
{
 
320
        return 
 
321
                ( SIEVE_EXT_ENABLED(ereg->extension) && 
 
322
                        *(ereg->extension->name) != '@' );
 
323
}
 
324
 
 
325
const char *sieve_extensions_get_string(void)
 
326
{
 
327
        unsigned int i, ext_count;
 
328
        const struct sieve_extension_registration *eregs;
 
329
        string_t *extstr = t_str_new(256);
 
330
 
 
331
        eregs = array_get(&extensions, &ext_count);
 
332
 
 
333
        if ( ext_count > 0 ) {
 
334
                i = 0;
 
335
                
 
336
                /* Find first listable extension */
 
337
                while ( i < ext_count && !_list_extension(&eregs[i]) )
 
338
                        i++;
 
339
 
 
340
                if ( i < ext_count ) {
 
341
                        /* Add first to string */
 
342
                        str_append(extstr, eregs[i].extension->name);
 
343
                        i++;     
 
344
 
 
345
                        /* Add others */
 
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);
 
350
                                }
 
351
                        }
 
352
                }
 
353
        }
 
354
 
 
355
        return str_c(extstr);
 
356
}
 
357
 
 
358
static void sieve_extension_enable(struct sieve_extension_registration *ereg)
 
359
{
 
360
        if ( ereg->extension->_id != NULL ) {
 
361
                *(ereg->extension->_id) = ereg->id;
 
362
        
 
363
                if ( !ereg->loaded ) {
 
364
                        (void)_sieve_extension_load(ereg->extension);
 
365
                }
 
366
        }
 
367
 
 
368
        ereg->loaded = TRUE;
 
369
}
 
370
 
 
371
static void sieve_extension_disable(struct sieve_extension_registration *ereg)
 
372
{
 
373
        if ( ereg->extension->_id != NULL )
 
374
                *(ereg->extension->_id) = -1;   
 
375
}
 
376
 
 
377
void sieve_extensions_set_string(const char *ext_string)
 
378
{
 
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;
 
387
 
 
388
        if ( ext_string == NULL ) {
 
389
                /* Enable all */
 
390
                eregs = array_get_modifiable(&extensions, &ext_count);
 
391
                
 
392
                for ( i = 0; i < ext_count; i++ )
 
393
                        sieve_extension_enable(&eregs[i]);
 
394
 
 
395
                return; 
 
396
        }
 
397
 
 
398
        T_BEGIN {
 
399
                t_array_init(&enabled_extensions, array_count(&extensions));
 
400
                t_array_init(&disabled_extensions, array_count(&extensions));
 
401
 
 
402
                ext_names = t_strsplit_spaces(ext_string, " \t");
 
403
 
 
404
                while ( *ext_names != NULL ) {
 
405
                        const char *name = *ext_names;
 
406
 
 
407
                        ext_names++;
 
408
 
 
409
                        if ( *name != '\0' ) {
 
410
                                const struct sieve_extension_registration *ereg;
 
411
                                char op = '\0'; /* No add/remove operation */
 
412
        
 
413
                                if ( *name == '+'               /* Add to existing config */
 
414
                                        || *name == '-' ) {     /* Remove from existing config */
 
415
                                        op = *name++;
 
416
                                        relative = TRUE;
 
417
                                }
 
418
 
 
419
                                if ( *name == '@' )
 
420
                                        ereg = NULL;
 
421
                                else
 
422
                                        ereg = (const struct sieve_extension_registration *) 
 
423
                                                hash_table_lookup(extension_index, name);
 
424
        
 
425
                                if ( ereg == NULL ) {
 
426
                                        sieve_sys_warning(
 
427
                                                "ignored unknown extension '%s' while configuring "
 
428
                                                "available extensions", name);
 
429
                                        continue;
 
430
                                }
 
431
 
 
432
                                if ( op == '-' )
 
433
                                        array_append(&disabled_extensions, &ereg->extension, 1);
 
434
                                else
 
435
                                        array_append(&enabled_extensions, &ereg->extension, 1);
 
436
                        }
 
437
                }
 
438
 
 
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);
 
442
 
 
443
                /* Set new extension status */
 
444
 
 
445
                for ( i = 0; i < ext_count; i++ ) {
 
446
                        unsigned int j;
 
447
                        bool disabled = TRUE;
 
448
 
 
449
                        /* If extensions are specified relative to the default set,
 
450
                         * we first need to check which ones are disabled 
 
451
                         */
 
452
 
 
453
                        if ( relative ) {
 
454
                                /* Enable if core extension */
 
455
                                for ( j = 0; j < sieve_core_extensions_count; j++ ) {
 
456
                                        if ( sieve_core_extensions[j] == eregs[i].extension ) {
 
457
                                                disabled = FALSE;
 
458
                                                break;
 
459
                                        }
 
460
                        }
 
461
 
 
462
                                /* Disable if explicitly disabled */
 
463
                                for ( j = 0; j < dis_count; j++ ) {
 
464
                                        if ( ext_disabled[j] == eregs[i].extension ) {
 
465
                                                disabled = TRUE;
 
466
                                                break;
 
467
                                        }
 
468
                                }
 
469
                        } 
 
470
 
 
471
                        /* Enable if listed with '+' or no prefix */
 
472
        
 
473
                        for ( j = 0; j < ena_count; j++ ) {
 
474
                                if ( ext_enabled[j] == eregs[i].extension ) {
 
475
                                        disabled = FALSE;
 
476
                                        break;
 
477
                                }               
 
478
                        }
 
479
 
 
480
                        /* Perform actual activation/deactivation */
 
481
 
 
482
                        if ( eregs[i].extension->_id != NULL && 
 
483
                                *(eregs[i].extension->name) != '@' ) {
 
484
                                if ( disabled && !eregs[i].required )
 
485
                                        sieve_extension_disable(&eregs[i]);
 
486
                                else
 
487
                                        sieve_extension_enable(&eregs[i]);
 
488
                        }
 
489
                }
 
490
        } T_END;
 
491
}
 
492
 
 
493
static void sieve_extensions_deinit_registry(void) 
 
494
{
 
495
        struct hash_iterate_context *itx = 
 
496
                hash_table_iterate_init(extension_index);
 
497
        void *key; 
 
498
        void *value;
 
499
        
 
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;
 
504
                
 
505
                if ( ext->unload != NULL )
 
506
                        ext->unload();
 
507
        }
 
508
 
 
509
        hash_table_iterate_deinit(&itx);        
 
510
 
 
511
        array_free(&extensions);
 
512
        hash_table_destroy(&extension_index);
 
513
}
 
514
 
 
515
/*
 
516
 * Extension capabilities
 
517
 */
 
518
 
 
519
static struct hash_table *capabilities_index; 
 
520
 
 
521
static void sieve_extensions_init_capabilities(void)
 
522
{       
 
523
        capabilities_index = hash_table_create
 
524
                (default_pool, default_pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
 
525
}
 
526
 
 
527
static void sieve_extensions_deinit_capabilities(void) 
 
528
{
 
529
        hash_table_destroy(&capabilities_index);
 
530
}
 
531
 
 
532
void sieve_extension_capabilities_register
 
533
        (const struct sieve_extension_capabilities *cap) 
 
534
{       
 
535
        hash_table_insert
 
536
                (capabilities_index, (void *) cap->name, (void *) cap);
 
537
}
 
538
 
 
539
const char *sieve_extension_capabilities_get_string
 
540
        (const char *cap_name) 
 
541
{
 
542
  const struct sieve_extension_capabilities *cap = 
 
543
                (const struct sieve_extension_capabilities *) 
 
544
                        hash_table_lookup(capabilities_index, cap_name);
 
545
 
 
546
        if ( cap == NULL || cap->get_string == NULL || 
 
547
                !SIEVE_EXT_ENABLED(cap->extension) )
 
548
                return NULL;
 
549
                
 
550
        return cap->get_string();
 
551
}
 
552
 
 
553
 
 
554
 
 
555