1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
/* Copyright (c) 2002-2010 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"
/*
* Types
*/
typedef void (*sieve_plugin_load_func_t)
(struct sieve_instance *svinst, void **context);
typedef void (*sieve_plugin_unload_func_t)
(struct sieve_instance *svinst, void *context);
struct sieve_plugin {
struct module *module;
void *context;
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 *name)
{
struct module *module;
module = sieve_modules;
while ( module != NULL ) {
const char *mod_name;
size_t len;
/* 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_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(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];
sieve_plugin_load_func_t load_func;
/* Find the module */
module = sieve_plugin_module_find(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 = (sieve_plugin_load_func_t) module_get_symbol
(module, t_strdup_printf("%s_load", module->name));
if ( load_func != NULL ) {
load_func(svinst, &plugin->context);
}
/* 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->next != 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;
sieve_plugin_unload_func_t unload_func;
unload_func = (sieve_plugin_unload_func_t)module_get_symbol
(module, t_strdup_printf("%s_unload", module->name));
if ( unload_func != NULL ) {
unload_func(svinst, plugin->context);
}
plugin = plugin->next;
}
/* Physically unload modules */
i_assert(sieve_modules_refcount > 0);
if ( --sieve_modules_refcount != 0 )
return;
module_dir_unload(&sieve_modules);
}
|