From 65920901094dbb9d0abd3da54d8910a9ec4b530d Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Thu, 31 Dec 2009 18:10:46 +0100 Subject: [PATCH] Further developed support for Sieve engine plugins. --- src/lib-sieve/Makefile.am | 2 + src/lib-sieve/sieve-common.h | 6 + src/lib-sieve/sieve-plugins.c | 210 ++++++++++++++++++++++++++++++++++ src/lib-sieve/sieve-plugins.h | 12 ++ src/lib-sieve/sieve.c | 79 +------------ 5 files changed, 232 insertions(+), 77 deletions(-) create mode 100644 src/lib-sieve/sieve-plugins.c create mode 100644 src/lib-sieve/sieve-plugins.h diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am index 6f66f428c..8d245ff11 100644 --- a/src/lib-sieve/Makefile.am +++ b/src/lib-sieve/Makefile.am @@ -98,6 +98,7 @@ libdovecot_sieve_la_SOURCES = \ sieve-code.c \ sieve-actions.c \ sieve-extensions.c \ + sieve-plugins.c \ $(comparators) \ $(match_types) \ $(tests) \ @@ -139,6 +140,7 @@ headers = \ sieve-code.h \ sieve-actions.h \ sieve-extensions.h \ + sieve-plugins.h \ sieve.h if INSTALL_HEADERS diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index 9c16ce7d1..cfbbd9be8 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -125,6 +125,9 @@ struct sieve_script; /* sieve-message.h */ struct sieve_message_context; +/* sieve-plugins.h */ +struct sieve_plugin; + /* sieve.c */ struct sieve_ast *sieve_parse (struct sieve_script *script, struct sieve_error_handler *ehandler); @@ -146,6 +149,9 @@ struct sieve_instance { /* Extension registry */ struct sieve_extension_registry *ext_reg; + /* Plugin modules */ + struct sieve_plugin *plugins; + /* Limits */ size_t max_script_size; unsigned int max_actions; diff --git a/src/lib-sieve/sieve-plugins.c b/src/lib-sieve/sieve-plugins.c new file mode 100644 index 000000000..6f6300322 --- /dev/null +++ b/src/lib-sieve/sieve-plugins.c @@ -0,0 +1,210 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "module-dir.h" + +#include "sieve-settings.h" +#include "sieve-extensions.h" + +#include "sieve-common.h" +#include "sieve-plugins.h" + +struct sieve_plugin { + struct module *module; + struct sieve_plugin *next; +}; + +/* + * Plugin support + */ + +static struct module *sieve_modules = NULL; +static int sieve_modules_refcount = 0; + +static struct module *sieve_plugin_module_find(const char *path, const char *name) +{ + struct module *module; + + module = sieve_modules; + while ( module != NULL ) { + const char *mod_path, *mod_name; + char *p; + size_t len; + + /* Strip module paths */ + + p = strrchr(module->path, '/'); + if ( p == NULL ) continue; + while ( p > module->path && *p == '/' ) p--; + mod_path = t_strdup_until(module->path, p+1); + + len = strlen(path); + if ( path[len-1] == '/' ) + path = t_strndup(path, len-1); + + /* Strip module names */ + + len = strlen(module->name); + if (len > 7 && strcmp(module->name + len - 7, "_plugin") == 0) + mod_name = t_strndup(module->name, len - 7); + else + mod_name = module->name; + + if ( strcmp(mod_path, path) == 0 && strcmp(mod_name, name) == 0 ) + return module; + + module = module->next; + } + + return NULL; +} + +void sieve_plugins_load(struct sieve_instance *svinst, const char *path, const char *plugins) +{ + struct module *module; + const char **module_names; + string_t *missing_modules; + unsigned int i; + + /* Determine what to load */ + + if ( path == NULL && plugins == NULL ) { + path = sieve_setting_get(svinst, "sieve_plugin_dir"); + plugins = sieve_setting_get(svinst, "sieve_plugins"); + } + + if ( plugins == NULL || *plugins == '\0' ) + return; + + if ( path == NULL || *path == '\0' ) + path = MODULEDIR"/sieve"; + + module_names = t_strsplit_spaces(plugins, ", "); + + for (i = 0; module_names[i] != NULL; i++) { + /* Allow giving the module names also in non-base form. */ + module_names[i] = module_file_get_name(module_names[i]); + } + + /* Load missing modules + * FIXME: Dovecot should provide this functionality (v2.0 does) + */ + + missing_modules = t_str_new(256); + + for (i = 0; module_names[i] != NULL; i++) { + const char *name = module_names[i]; + + if ( sieve_plugin_module_find(path, name) == NULL ) { + if ( i > 0 ) str_append_c(missing_modules, ' '); + + str_append(missing_modules, name); + } + } + + if ( str_len(missing_modules) > 0 ) { + struct module *new_modules = module_dir_load + (path, str_c(missing_modules), TRUE, SIEVE_VERSION); + + if ( sieve_modules == NULL ) { + /* No modules loaded yet */ + sieve_modules = new_modules; + } else { + /* Find the end of the list */ + module = sieve_modules; + while ( module != NULL && module->next != NULL ) + module = module->next; + + /* Add newly loaded modules */ + module->next = new_modules; + } + } + + /* Call plugin load functions for this Sieve instance */ + + if ( svinst->plugins == NULL ) { + sieve_modules_refcount++; + } + + for (i = 0; module_names[i] != NULL; i++) { + struct sieve_plugin *plugin; + const char *name = module_names[i]; + void (*load_func)(struct sieve_instance *svinst); + + /* Find the module */ + module = sieve_plugin_module_find(path, name); + i_assert(module != NULL); + + /* Check whether the plugin is already loaded in this instance */ + plugin = svinst->plugins; + while ( plugin != NULL ) { + if ( plugin->module == module ) + break; + plugin = plugin->next; + } + + /* Skip it if it is loaded already */ + if ( plugin != NULL ) + continue; + + /* Create plugin list item */ + plugin = p_new(svinst->pool, struct sieve_plugin, 1); + plugin->module = module; + + /* Call load function */ + load_func = module_get_symbol + (module, t_strdup_printf("%s_load", module->name)); + if ( load_func != NULL ) { + load_func(svinst); + } + + /* Add plugin to the instance */ + if ( svinst->plugins == NULL ) + svinst->plugins = plugin; + else { + struct sieve_plugin *plugin_last; + + plugin_last = svinst->plugins; + while ( plugin_last != NULL ) + plugin_last = plugin_last->next; + + plugin_last->next = plugin; + } + } +} + +void sieve_plugins_unload(struct sieve_instance *svinst) +{ + struct sieve_plugin *plugin; + + if ( svinst->plugins == NULL ) + return; + + /* Call plugin unload functions for this instance */ + + plugin = svinst->plugins; + while ( plugin != NULL ) { + struct module *module = plugin->module; + void (*unload_func)(struct sieve_instance *svinst); + + unload_func = module_get_symbol + (module, t_strdup_printf("%s_unload", module->name)); + if ( unload_func != NULL ) { + unload_func(svinst); + } + + plugin = plugin->next; + } + + /* Physically unload modules */ + + i_assert(sieve_modules_refcount > 0); + + if ( --sieve_modules_refcount != 0 ) + return; + + module_dir_unload(&sieve_modules); +} + diff --git a/src/lib-sieve/sieve-plugins.h b/src/lib-sieve/sieve-plugins.h new file mode 100644 index 000000000..2fd349dde --- /dev/null +++ b/src/lib-sieve/sieve-plugins.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#ifndef __SIEVE_PLUGINS_H +#define __SIEVE_PLUGINS_H + +#include "sieve-common.h" + +void sieve_plugins_load(struct sieve_instance *svinst, const char *path, const char *plugins); +void sieve_plugins_unload(struct sieve_instance *svinst); + +#endif /* __SIEVE_PLUGINS_H */ diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 00fdc4c93..32e58c7ef 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -6,11 +6,11 @@ #include "istream.h" #include "buffer.h" #include "eacces-error.h" -#include "module-dir.h" #include "sieve-limits.h" #include "sieve-settings.h" #include "sieve-extensions.h" +#include "sieve-plugins.h" #include "sieve-script.h" #include "sieve-ast.h" @@ -35,81 +35,6 @@ #include <stdio.h> #include <dirent.h> -/* - * Plugin support - */ - -static struct module *sieve_modules = NULL; -static int sieve_modules_refcount = 0; - -static void sieve_plugins_load(struct sieve_instance *svinst) -{ - struct module *module; - - /* Physically load modules */ - - /* FIXME: sieve plugins may/cannot differ between Sieve instances */ - - if ( sieve_modules == NULL ) { - const char *plugins = sieve_setting_get(svinst, "sieve_plugins"); - - if ( plugins != NULL && *plugins != '\0' ) { - const char *plugin_dir = sieve_setting_get(svinst, "sieve_plugin_dir"); - - if ( plugin_dir == NULL || *plugin_dir == '\0' ) - plugin_dir = MODULEDIR"/sieve"; - - sieve_modules = module_dir_load(plugin_dir, plugins, TRUE, SIEVE_VERSION); - } - } - - sieve_modules_refcount++; - - /* Call plugin load functions for this instance */ - - module = sieve_modules; - while ( module != NULL ) { - void (*load_func)(struct sieve_instance *svinst); - - load_func = module_get_symbol - (module, t_strdup_printf("%s_load", module->name)); - if ( load_func != NULL ) { - load_func(svinst); - } - - module = module->next; - } -} - -static void sieve_plugins_unload(struct sieve_instance *svinst) -{ - struct module *module; - - /* Call plugin unload functions for this instance */ - - module = sieve_modules; - while ( module != NULL ) { - void (*unload_func)(struct sieve_instance *svinst); - - unload_func = module_get_symbol - (module, t_strdup_printf("%s_unload", module->name)); - if ( unload_func != NULL ) { - unload_func(svinst); - } - - module = module->next; - } - - /* Physically unload modules */ - - i_assert(sieve_modules_refcount > 0); - - if ( --sieve_modules_refcount != 0 ) - return; - - module_dir_unload(&sieve_modules); -} - /* * Main Sieve library interface */ @@ -156,7 +81,7 @@ struct sieve_instance *sieve_init return NULL; } - sieve_plugins_load(svinst); + sieve_plugins_load(svinst, NULL, NULL); return svinst; } -- GitLab