/src/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "hash.h" |
5 | | |
6 | | #include "sieve-common.h" |
7 | | #include "sieve-extensions.h" |
8 | | #include "sieve-interpreter.h" |
9 | | |
10 | | #include "ext-environment-common.h" |
11 | | |
12 | | struct ext_environment_interpreter_context; |
13 | | |
14 | | /* |
15 | | * Core environment items |
16 | | */ |
17 | | |
18 | | static const struct sieve_environment_item_def *core_env_items[] = { |
19 | | &domain_env_item, |
20 | | &host_env_item, |
21 | | &location_env_item, |
22 | | &phase_env_item, |
23 | | &name_env_item, |
24 | | &version_env_item, |
25 | | }; |
26 | | |
27 | | static unsigned int core_env_items_count = N_ELEMENTS(core_env_items); |
28 | | |
29 | | static void |
30 | | sieve_environment_item_insert( |
31 | | struct ext_environment_interpreter_context *ctx, |
32 | | struct sieve_interpreter *interp, const struct sieve_extension *ext, |
33 | | const struct sieve_environment_item_def *item_def); |
34 | | |
35 | | /* |
36 | | * Validator context |
37 | | */ |
38 | | |
39 | | struct ext_environment_interpreter_context { |
40 | | HASH_TABLE(const char *, |
41 | | const struct sieve_environment_item *) name_items; |
42 | | ARRAY(const struct sieve_environment_item *) prefix_items; |
43 | | |
44 | | bool active:1; |
45 | | }; |
46 | | |
47 | | static void |
48 | | ext_environment_interpreter_extension_free(const struct sieve_extension *ext, |
49 | | struct sieve_interpreter *interp, |
50 | | void *context); |
51 | | |
52 | | struct sieve_interpreter_extension environment_interpreter_extension = { |
53 | | .ext_def = &environment_extension, |
54 | | .free = ext_environment_interpreter_extension_free, |
55 | | }; |
56 | | |
57 | | static struct ext_environment_interpreter_context * |
58 | | ext_environment_interpreter_context_create( |
59 | | const struct sieve_extension *this_ext, |
60 | | struct sieve_interpreter *interp) |
61 | 0 | { |
62 | 0 | pool_t pool = sieve_interpreter_pool(interp); |
63 | 0 | struct ext_environment_interpreter_context *ctx; |
64 | |
|
65 | 0 | ctx = p_new(pool, struct ext_environment_interpreter_context, 1); |
66 | |
|
67 | 0 | hash_table_create(&ctx->name_items, default_pool, 0, str_hash, strcmp); |
68 | 0 | i_array_init(&ctx->prefix_items, 16); |
69 | |
|
70 | 0 | sieve_interpreter_extension_register(interp, this_ext, |
71 | 0 | &environment_interpreter_extension, |
72 | 0 | ctx); |
73 | 0 | return ctx; |
74 | 0 | } |
75 | | |
76 | | static void |
77 | | ext_environment_interpreter_extension_free( |
78 | | const struct sieve_extension *ext ATTR_UNUSED, |
79 | | struct sieve_interpreter *interp ATTR_UNUSED, void *context) |
80 | 0 | { |
81 | 0 | struct ext_environment_interpreter_context *ctx = |
82 | 0 | (struct ext_environment_interpreter_context *)context; |
83 | |
|
84 | 0 | hash_table_destroy(&ctx->name_items); |
85 | 0 | array_free(&ctx->prefix_items); |
86 | 0 | } |
87 | | |
88 | | static struct ext_environment_interpreter_context * |
89 | | ext_environment_interpreter_context_get(const struct sieve_extension *this_ext, |
90 | | struct sieve_interpreter *interp) |
91 | 0 | { |
92 | 0 | struct ext_environment_interpreter_context *ctx = |
93 | 0 | (struct ext_environment_interpreter_context *) |
94 | 0 | sieve_interpreter_extension_get_context(interp, this_ext); |
95 | |
|
96 | 0 | if (ctx == NULL) { |
97 | 0 | ctx = ext_environment_interpreter_context_create( |
98 | 0 | this_ext, interp); |
99 | 0 | } |
100 | 0 | return ctx; |
101 | 0 | } |
102 | | |
103 | | void ext_environment_interpreter_init(const struct sieve_extension *this_ext, |
104 | | struct sieve_interpreter *interp) |
105 | 0 | { |
106 | 0 | struct ext_environment_interpreter_context *ctx; |
107 | 0 | unsigned int i; |
108 | | |
109 | | /* Create our context */ |
110 | 0 | ctx = ext_environment_interpreter_context_get(this_ext, interp); |
111 | |
|
112 | 0 | for (i = 0; i < core_env_items_count; i++) { |
113 | 0 | sieve_environment_item_insert(ctx, interp, this_ext, |
114 | 0 | core_env_items[i]); |
115 | 0 | } |
116 | |
|
117 | 0 | ctx->active = TRUE; |
118 | 0 | } |
119 | | |
120 | | bool sieve_ext_environment_is_active(const struct sieve_extension *env_ext, |
121 | | struct sieve_interpreter *interp) |
122 | 0 | { |
123 | 0 | struct ext_environment_interpreter_context *ctx = |
124 | 0 | ext_environment_interpreter_context_get(env_ext, interp); |
125 | |
|
126 | 0 | return (ctx != NULL && ctx->active); |
127 | 0 | } |
128 | | |
129 | | /* |
130 | | * Registration |
131 | | */ |
132 | | |
133 | | static void |
134 | | sieve_environment_item_insert( |
135 | | struct ext_environment_interpreter_context *ctx, |
136 | | struct sieve_interpreter *interp, const struct sieve_extension *ext, |
137 | | const struct sieve_environment_item_def *item_def) |
138 | 0 | { |
139 | 0 | pool_t pool = sieve_interpreter_pool(interp); |
140 | 0 | struct sieve_environment_item *item_mod; |
141 | |
|
142 | 0 | item_mod = p_new(pool, struct sieve_environment_item, 1); |
143 | 0 | item_mod->def = item_def; |
144 | 0 | item_mod->ext = ext; |
145 | |
|
146 | 0 | const struct sieve_environment_item *item = item_mod; |
147 | 0 | if (!item_def->prefix) |
148 | 0 | hash_table_insert(ctx->name_items, item_def->name, item); |
149 | 0 | else |
150 | 0 | array_append(&ctx->prefix_items, &item, 1); |
151 | 0 | } |
152 | | |
153 | | void sieve_environment_item_register( |
154 | | const struct sieve_extension *env_ext, struct sieve_interpreter *interp, |
155 | | const struct sieve_extension *ext, |
156 | | const struct sieve_environment_item_def *item_def) |
157 | 0 | { |
158 | 0 | struct ext_environment_interpreter_context *ctx; |
159 | |
|
160 | 0 | i_assert(sieve_extension_is(env_ext, environment_extension)); |
161 | 0 | ctx = ext_environment_interpreter_context_get(env_ext, interp); |
162 | |
|
163 | 0 | sieve_environment_item_insert(ctx, interp, ext, item_def); |
164 | 0 | } |
165 | | |
166 | | /* |
167 | | * Retrieval |
168 | | */ |
169 | | |
170 | | static const struct sieve_environment_item * |
171 | | ext_environment_item_lookup(struct ext_environment_interpreter_context *ctx, |
172 | | const char **_name) |
173 | 0 | { |
174 | 0 | const struct sieve_environment_item *item; |
175 | 0 | const char *suffix, *name = *_name; |
176 | |
|
177 | 0 | item = hash_table_lookup(ctx->name_items, name); |
178 | 0 | if (item != NULL) |
179 | 0 | return item; |
180 | | |
181 | 0 | array_foreach_elem(&ctx->prefix_items, item) { |
182 | 0 | i_assert(item->def->prefix); |
183 | | |
184 | 0 | if (str_begins(name, item->def->name, &suffix)) { |
185 | 0 | if (*suffix == '.') |
186 | 0 | ++suffix; |
187 | |
|
188 | 0 | *_name = suffix; |
189 | 0 | return item; |
190 | 0 | } |
191 | 0 | } |
192 | 0 | return NULL; |
193 | 0 | } |
194 | | |
195 | | const char * |
196 | | ext_environment_item_get_value(const struct sieve_extension *env_ext, |
197 | | const struct sieve_runtime_env *renv, |
198 | | const char *name) |
199 | 0 | { |
200 | 0 | struct ext_environment_interpreter_context *ctx; |
201 | 0 | const struct sieve_environment_item *item; |
202 | |
|
203 | 0 | i_assert(sieve_extension_is(env_ext, environment_extension)); |
204 | 0 | ctx = ext_environment_interpreter_context_get(env_ext, renv->interp); |
205 | |
|
206 | 0 | item = ext_environment_item_lookup(ctx, &name); |
207 | 0 | if (item == NULL) |
208 | 0 | return NULL; |
209 | | |
210 | 0 | i_assert(item->def != NULL); |
211 | 0 | if (item->def->value != NULL) |
212 | 0 | return item->def->value; |
213 | 0 | if (item->def->get_value != NULL) |
214 | 0 | return item->def->get_value(renv, item, name); |
215 | 0 | return NULL; |
216 | 0 | } |
217 | | |
218 | | /* |
219 | | * Default environment items |
220 | | */ |
221 | | |
222 | | /* "domain": |
223 | | |
224 | | The primary DNS domain associated with the Sieve execution context, usually |
225 | | but not always a proper suffix of the host name. |
226 | | */ |
227 | | |
228 | | static const char * |
229 | | envit_domain_get_value(const struct sieve_runtime_env *renv, |
230 | | const struct sieve_environment_item *item ATTR_UNUSED, |
231 | | const char *name ATTR_UNUSED) |
232 | 0 | { |
233 | 0 | const struct sieve_execute_env *eenv = renv->exec_env; |
234 | |
|
235 | 0 | return eenv->svinst->domainname; |
236 | 0 | } |
237 | | |
238 | | const struct sieve_environment_item_def domain_env_item = { |
239 | | .name = "domain", |
240 | | .get_value = envit_domain_get_value, |
241 | | }; |
242 | | |
243 | | /* "host": |
244 | | |
245 | | The fully-qualified domain name of the host where the Sieve script is |
246 | | executing. |
247 | | */ |
248 | | |
249 | | static const char * |
250 | | envit_host_get_value(const struct sieve_runtime_env *renv, |
251 | | const struct sieve_environment_item *item ATTR_UNUSED, |
252 | | const char *name ATTR_UNUSED) |
253 | 0 | { |
254 | 0 | const struct sieve_execute_env *eenv = renv->exec_env; |
255 | |
|
256 | 0 | return eenv->svinst->hostname; |
257 | 0 | } |
258 | | |
259 | | const struct sieve_environment_item_def host_env_item = { |
260 | | .name = "host", |
261 | | .get_value = envit_host_get_value, |
262 | | }; |
263 | | |
264 | | /* "location": |
265 | | |
266 | | Sieve evaluation can be performed at various different points as messages |
267 | | are processed. This item provides additional information about the type of |
268 | | service that is evaluating the script. Possible values are: |
269 | | "MTA" - the Sieve script is being evaluated by a Message Transfer Agent |
270 | | "MDA" - evaluation is being performed by a Mail Delivery Agent |
271 | | "MUA" - evaluation is being performed by a Mail User Agent (right...) |
272 | | "MS" - evaluation is being performed by a Message Store |
273 | | */ |
274 | | |
275 | | static const char * |
276 | | envit_location_get_value(const struct sieve_runtime_env *renv, |
277 | | const struct sieve_environment_item *item ATTR_UNUSED, |
278 | | const char *name ATTR_UNUSED) |
279 | 0 | { |
280 | 0 | const struct sieve_execute_env *eenv = renv->exec_env; |
281 | |
|
282 | 0 | switch (eenv->svinst->env_location ) { |
283 | 0 | case SIEVE_ENV_LOCATION_MDA: |
284 | 0 | return "MDA"; |
285 | 0 | case SIEVE_ENV_LOCATION_MTA: |
286 | 0 | return "MTA"; |
287 | 0 | case SIEVE_ENV_LOCATION_MS: |
288 | 0 | return "MS"; |
289 | 0 | default: |
290 | 0 | break; |
291 | 0 | } |
292 | 0 | return NULL; |
293 | 0 | } |
294 | | |
295 | | const struct sieve_environment_item_def location_env_item = { |
296 | | .name = "location", |
297 | | .get_value = envit_location_get_value |
298 | | }; |
299 | | |
300 | | /* "phase": |
301 | | |
302 | | The point relative to final delivery where the Sieve script is being |
303 | | evaluated. Possible values are "pre", "during", and "post", referring |
304 | | respectively to processing before, during, and after final delivery has |
305 | | taken place. |
306 | | */ |
307 | | |
308 | | static const char * |
309 | | envit_phase_get_value(const struct sieve_runtime_env *renv, |
310 | | const struct sieve_environment_item *item ATTR_UNUSED, |
311 | | const char *name ATTR_UNUSED) |
312 | 0 | { |
313 | 0 | const struct sieve_execute_env *eenv = renv->exec_env; |
314 | |
|
315 | 0 | switch (eenv->svinst->delivery_phase) { |
316 | 0 | case SIEVE_DELIVERY_PHASE_PRE: |
317 | 0 | return "pre"; |
318 | 0 | case SIEVE_DELIVERY_PHASE_DURING: |
319 | 0 | return "during"; |
320 | 0 | case SIEVE_DELIVERY_PHASE_POST: |
321 | 0 | return "post"; |
322 | 0 | default: |
323 | 0 | break; |
324 | 0 | } |
325 | 0 | return NULL; |
326 | 0 | } |
327 | | |
328 | | const struct sieve_environment_item_def phase_env_item = { |
329 | | .name = "phase", |
330 | | .get_value = envit_phase_get_value |
331 | | }; |
332 | | |
333 | | /* "name": |
334 | | |
335 | | The product name associated with the Sieve interpreter. |
336 | | */ |
337 | | |
338 | | const struct sieve_environment_item_def name_env_item = { |
339 | | .name = "name", |
340 | | .value = PIGEONHOLE_NAME" Sieve" |
341 | | }; |
342 | | |
343 | | /* "version": |
344 | | |
345 | | The product version associated with the Sieve interpreter. The meaning of the |
346 | | product version string is product-specific and should always be considered |
347 | | in the context of the product name given by the "name" item. |
348 | | */ |
349 | | |
350 | | const struct sieve_environment_item_def version_env_item = { |
351 | | .name = "version", |
352 | | .value = PIGEONHOLE_VERSION, |
353 | | }; |