Coverage Report

Created: 2026-06-15 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/sieve-plugins.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "str.h"
6
#include "settings-parser.h"
7
#include "module-dir.h"
8
#include "master-service.h"
9
10
#include "sieve-extensions.h"
11
12
#include "sieve-common.h"
13
#include "sieve-plugins.h"
14
15
/*
16
 * Types
17
 */
18
19
typedef int
20
(*sieve_plugin_load_func_t)(struct sieve_instance *svinst, void **context);
21
typedef void
22
(*sieve_plugin_unload_func_t)(struct sieve_instance *svinst, void *context);
23
24
struct sieve_plugin {
25
  struct module *module;
26
27
  void *context;
28
29
  struct sieve_plugin *next;
30
};
31
32
/*
33
 * Plugin support
34
 */
35
36
static struct module *sieve_modules = NULL;
37
static int sieve_modules_refcount = 0;
38
39
static struct module *sieve_plugin_module_find(const char *name)
40
0
{
41
0
  struct module *module;
42
43
0
  module = sieve_modules;
44
0
  while (module != NULL) {
45
0
    const char *mod_name;
46
47
    /* Strip module names */
48
0
    mod_name = module_get_plugin_name(module);
49
0
    if (strcmp(mod_name, name) == 0)
50
0
      return module;
51
52
0
    module = module->next;
53
0
  }
54
0
  return NULL;
55
0
}
56
57
int sieve_plugins_load(struct sieve_instance *svinst, const char *path,
58
           const char *plugins)
59
0
{
60
0
  struct module *module;
61
0
  struct module_dir_load_settings mod_set;
62
0
  const char *const *module_names;
63
0
  unsigned int i;
64
65
  /* Determine what to load */
66
67
0
  if (path == NULL && plugins == NULL) {
68
    /* From settings */
69
0
    module_names = settings_boollist_get(&svinst->set->plugins);
70
0
    path = svinst->set->plugin_dir;
71
0
  } else {
72
    /* From function parameters */
73
0
    const char **module_names_mod;
74
75
0
    if (plugins == NULL || *plugins == '\0')
76
0
      return 0;
77
0
    module_names_mod = t_strsplit_spaces(plugins, ", ");
78
79
0
    if (path == NULL || *path == '\0')
80
0
      path = sieve_default_settings.plugin_dir;
81
82
0
    for (i = 0; module_names_mod[i] != NULL; i++) {
83
      /* Allow giving the module names also in non-base form.
84
       */
85
0
      module_names_mod[i] =
86
0
        module_file_get_name(module_names_mod[i]);
87
0
    }
88
0
    module_names = module_names_mod;
89
0
  }
90
91
0
  if (module_names == NULL || *module_names == NULL)
92
0
    return 0;
93
94
0
  i_zero(&mod_set);
95
0
  mod_set.abi_version = PIGEONHOLE_ABI_VERSION;
96
0
  mod_set.binary_name = master_service_get_name(master_service);
97
0
  mod_set.setting_name = "sieve_plugins";
98
0
  mod_set.require_init_funcs = TRUE;
99
0
  mod_set.debug = svinst->debug;
100
101
  /* Load missing plugin modules */
102
103
0
  sieve_modules = module_dir_load_missing(sieve_modules, path,
104
0
            module_names, &mod_set);
105
106
  /* Call plugin load functions for this Sieve instance */
107
108
0
  if (svinst->plugins == NULL)
109
0
    sieve_modules_refcount++;
110
111
0
  for (i = 0; module_names[i] != NULL; i++) {
112
0
    struct sieve_plugin *plugin;
113
0
    const char *name = module_names[i];
114
0
    sieve_plugin_load_func_t load_func;
115
116
    /* Find the module */
117
0
    module = sieve_plugin_module_find(name);
118
0
    i_assert(module != NULL);
119
120
    /* Check whether the plugin is already loaded in this instance */
121
0
    plugin = svinst->plugins;
122
0
    while (plugin != NULL) {
123
0
      if (plugin->module == module)
124
0
        break;
125
0
      plugin = plugin->next;
126
0
    }
127
128
    /* Skip it if it is loaded already */
129
0
    if (plugin != NULL)
130
0
      continue;
131
132
    /* Create plugin list item */
133
0
    plugin = p_new(svinst->pool, struct sieve_plugin, 1);
134
0
    plugin->module = module;
135
136
    /* Call load function */
137
0
    load_func = (sieve_plugin_load_func_t)
138
0
      module_get_symbol(module,
139
0
        t_strdup_printf("%s_load", module->name));
140
0
    if (load_func != NULL &&
141
0
        load_func(svinst, &plugin->context) < 0)
142
0
      return -1;
143
144
    /* Add plugin to the instance */
145
0
    if (svinst->plugins == NULL)
146
0
      svinst->plugins = plugin;
147
0
    else {
148
0
      struct sieve_plugin *plugin_last;
149
150
0
      plugin_last = svinst->plugins;
151
0
      while ( plugin_last->next != NULL )
152
0
        plugin_last = plugin_last->next;
153
154
0
      plugin_last->next = plugin;
155
0
    }
156
0
  }
157
0
  return 0;
158
0
}
159
160
void sieve_plugins_unload(struct sieve_instance *svinst)
161
0
{
162
0
  struct sieve_plugin *plugin;
163
164
0
  if (svinst->plugins == NULL)
165
0
    return;
166
167
  /* Call plugin unload functions for this instance */
168
169
0
  plugin = svinst->plugins;
170
0
  while (plugin != NULL) {
171
0
    struct module *module = plugin->module;
172
0
    sieve_plugin_unload_func_t unload_func;
173
174
0
    unload_func = (sieve_plugin_unload_func_t)
175
0
      module_get_symbol(
176
0
        module,
177
0
        t_strdup_printf("%s_unload", module->name));
178
0
    if (unload_func != NULL)
179
0
      unload_func(svinst, plugin->context);
180
181
0
    plugin = plugin->next;
182
0
  }
183
184
  /* Physically unload modules */
185
186
0
  i_assert(sieve_modules_refcount > 0);
187
188
0
  if (--sieve_modules_refcount != 0)
189
0
    return;
190
191
0
  module_dir_unload(&sieve_modules);
192
0
}