/src/pigeonhole/src/lib-sieve/sieve-binary.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str.h" |
5 | | #include "str-sanitize.h" |
6 | | #include "mempool.h" |
7 | | #include "buffer.h" |
8 | | #include "hash.h" |
9 | | #include "array.h" |
10 | | #include "ostream.h" |
11 | | #include "ioloop.h" |
12 | | #include "eacces-error.h" |
13 | | #include "safe-mkstemp.h" |
14 | | |
15 | | #include "sieve-error.h" |
16 | | #include "sieve-extensions.h" |
17 | | #include "sieve-code.h" |
18 | | #include "sieve-script.h" |
19 | | #include "sieve-script-private.h" |
20 | | #include "sieve-storage-private.h" |
21 | | #include "sieve-rusage.h" |
22 | | |
23 | | #include "sieve-binary-private.h" |
24 | | |
25 | | /* |
26 | | * Forward declarations |
27 | | */ |
28 | | |
29 | | static inline struct sieve_binary_extension_reg * |
30 | | sieve_binary_extension_get_reg(struct sieve_binary *sbin, |
31 | | const struct sieve_extension *ext, bool create); |
32 | | |
33 | | static inline int |
34 | | sieve_binary_extension_register(struct sieve_binary *sbin, |
35 | | const struct sieve_extension *ext, |
36 | | struct sieve_binary_extension_reg **reg); |
37 | | |
38 | | /* |
39 | | * Binary object |
40 | | */ |
41 | | |
42 | | void sieve_binary_update_event(struct sieve_binary *sbin, const char *new_path) |
43 | 0 | { |
44 | 0 | if (new_path != NULL) { |
45 | 0 | event_set_append_log_prefix( |
46 | 0 | sbin->event, t_strdup_printf("binary %s: ", new_path)); |
47 | 0 | } else if (sbin->path != NULL) { |
48 | 0 | event_set_append_log_prefix( |
49 | 0 | sbin->event, |
50 | 0 | t_strdup_printf("binary %s: ", sbin->path)); |
51 | 0 | } else if (sbin->script != NULL) { |
52 | 0 | event_set_append_log_prefix( |
53 | 0 | sbin->event, |
54 | 0 | t_strdup_printf("binary %s: ", |
55 | 0 | sieve_script_name(sbin->script))); |
56 | 0 | } else { |
57 | 0 | event_set_append_log_prefix(sbin->event, "binary: "); |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | | struct sieve_binary * |
62 | | sieve_binary_create(struct sieve_instance *svinst, struct sieve_script *script) |
63 | 0 | { |
64 | 0 | pool_t pool; |
65 | 0 | struct sieve_binary *sbin; |
66 | 0 | const struct sieve_extension *const *ext_preloaded; |
67 | 0 | unsigned int i, ext_count; |
68 | |
|
69 | 0 | pool = pool_alloconly_create("sieve_binary", 16384); |
70 | 0 | sbin = p_new(pool, struct sieve_binary, 1); |
71 | 0 | sbin->pool = pool; |
72 | 0 | sbin->refcount = 1; |
73 | 0 | sbin->svinst = svinst; |
74 | |
|
75 | 0 | sbin->header.version_major = SIEVE_BINARY_VERSION_MAJOR; |
76 | 0 | sbin->header.version_minor = SIEVE_BINARY_VERSION_MINOR; |
77 | |
|
78 | 0 | sbin->script = script; |
79 | 0 | if (script != NULL) |
80 | 0 | sieve_script_ref(script); |
81 | |
|
82 | 0 | sbin->event = event_create(svinst->event); |
83 | |
|
84 | 0 | ext_count = sieve_extensions_get_count(svinst); |
85 | |
|
86 | 0 | p_array_init(&sbin->linked_extensions, pool, ext_count); |
87 | 0 | p_array_init(&sbin->extensions, pool, ext_count); |
88 | 0 | p_array_init(&sbin->extension_index, pool, ext_count); |
89 | |
|
90 | 0 | p_array_init(&sbin->blocks, pool, 16); |
91 | | |
92 | | /* Pre-load core language features implemented as 'extensions' */ |
93 | 0 | ext_preloaded = sieve_extensions_get_preloaded(svinst, &ext_count); |
94 | 0 | for (i = 0; i < ext_count; i++) { |
95 | 0 | const struct sieve_extension_def *ext_def = ext_preloaded[i]->def; |
96 | |
|
97 | 0 | if (ext_def != NULL && ext_def->binary_load != NULL) |
98 | 0 | (void)ext_def->binary_load(ext_preloaded[i], sbin); |
99 | 0 | } |
100 | |
|
101 | 0 | return sbin; |
102 | 0 | } |
103 | | |
104 | | struct sieve_binary *sieve_binary_create_new(struct sieve_script *script) |
105 | 0 | { |
106 | 0 | struct sieve_binary *sbin = |
107 | 0 | sieve_binary_create(sieve_script_svinst(script), script); |
108 | 0 | struct sieve_binary_block *sblock; |
109 | 0 | unsigned int i; |
110 | |
|
111 | 0 | sieve_binary_update_event(sbin, NULL); |
112 | | |
113 | | /* Create script metadata block */ |
114 | 0 | sblock = sieve_binary_block_create(sbin); |
115 | 0 | sieve_script_binary_write_metadata(script, sblock); |
116 | | |
117 | | /* Create other system blocks */ |
118 | 0 | for (i = 1; i < SBIN_SYSBLOCK_LAST; i++) |
119 | 0 | (void)sieve_binary_block_create(sbin); |
120 | |
|
121 | 0 | return sbin; |
122 | 0 | } |
123 | | |
124 | | void sieve_binary_ref(struct sieve_binary *sbin) |
125 | 0 | { |
126 | 0 | sbin->refcount++; |
127 | 0 | } |
128 | | |
129 | | static inline void sieve_binary_extensions_free(struct sieve_binary *sbin) |
130 | 0 | { |
131 | 0 | struct sieve_binary_extension_reg *const *regs; |
132 | 0 | unsigned int ext_count, i; |
133 | | |
134 | | /* Cleanup binary extensions */ |
135 | 0 | regs = array_get(&sbin->extensions, &ext_count); |
136 | 0 | for (i = 0; i < ext_count; i++) { |
137 | 0 | const struct sieve_binary_extension *binext = regs[i]->binext; |
138 | |
|
139 | 0 | if (binext != NULL && binext->binary_free != NULL) { |
140 | 0 | binext->binary_free(regs[i]->extension, sbin, |
141 | 0 | regs[i]->context); |
142 | 0 | } |
143 | 0 | } |
144 | 0 | } |
145 | | |
146 | | static void sieve_binary_update_resource_usage(struct sieve_binary *sbin) |
147 | 0 | { |
148 | 0 | enum sieve_error error_code; |
149 | |
|
150 | 0 | if (sbin->rusage_updated) { |
151 | 0 | (void)sieve_binary_file_update_resource_usage( |
152 | 0 | sbin, &error_code); |
153 | 0 | } |
154 | 0 | sbin->rusage_updated = FALSE; |
155 | 0 | } |
156 | | |
157 | | void sieve_binary_unref(struct sieve_binary **_sbin) |
158 | 0 | { |
159 | 0 | struct sieve_binary *sbin = *_sbin; |
160 | |
|
161 | 0 | *_sbin = NULL; |
162 | 0 | if (sbin == NULL) |
163 | 0 | return; |
164 | | |
165 | 0 | i_assert(sbin->refcount > 0); |
166 | 0 | if (--sbin->refcount != 0) |
167 | 0 | return; |
168 | | |
169 | 0 | sieve_binary_file_close(&sbin->file); |
170 | 0 | sieve_binary_update_resource_usage(sbin); |
171 | 0 | sieve_binary_extensions_free(sbin); |
172 | |
|
173 | 0 | sieve_script_unref(&sbin->script); |
174 | |
|
175 | 0 | event_unref(&sbin->event); |
176 | 0 | pool_unref(&sbin->pool); |
177 | 0 | } |
178 | | |
179 | | void sieve_binary_close(struct sieve_binary **_sbin) |
180 | 0 | { |
181 | 0 | struct sieve_binary *sbin = *_sbin; |
182 | |
|
183 | 0 | *_sbin = NULL; |
184 | 0 | if (sbin == NULL) |
185 | 0 | return; |
186 | | |
187 | 0 | sieve_binary_file_close(&sbin->file); |
188 | 0 | sieve_binary_update_resource_usage(sbin); |
189 | 0 | sieve_binary_unref(&sbin); |
190 | 0 | } |
191 | | |
192 | | /* |
193 | | * Resource usage |
194 | | */ |
195 | | |
196 | | static struct sieve_storage * |
197 | | sieve_binary_get_user_storage(struct sieve_binary *sbin) |
198 | 0 | { |
199 | 0 | if (sbin->script == NULL) |
200 | 0 | return NULL; |
201 | 0 | if (sbin->script->storage == NULL) |
202 | 0 | return NULL; |
203 | 0 | if (sbin->script->storage->rusage_path == NULL) |
204 | 0 | return NULL; |
205 | 0 | return sbin->script->storage; |
206 | 0 | } |
207 | | |
208 | | void sieve_binary_apply_persisted_rusage(struct sieve_binary *sbin) |
209 | 0 | { |
210 | 0 | struct sieve_storage *storage = sieve_binary_get_user_storage(sbin); |
211 | 0 | struct sieve_resource_usage rusage; |
212 | |
|
213 | 0 | if (storage == NULL) |
214 | 0 | return; |
215 | 0 | if (sieve_rusage_storage_load(storage, &rusage) <= 0) |
216 | 0 | return; |
217 | | |
218 | 0 | sbin->persisted_rusage.cpu_time_msecs = rusage.cpu_time_msecs; |
219 | 0 | sbin->persisted_rusage.update_time = ioloop_time; |
220 | 0 | sieve_resource_usage_init(&sbin->rusage); |
221 | 0 | sbin->rusage_updated = FALSE; |
222 | 0 | } |
223 | | |
224 | | void sieve_binary_get_resource_usage(struct sieve_binary *sbin, |
225 | | struct sieve_resource_usage *rusage_r) |
226 | 0 | { |
227 | 0 | time_t update_time = sbin->persisted_rusage.update_time; |
228 | 0 | unsigned int timeout = sbin->svinst->set->resource_usage_timeout; |
229 | |
|
230 | 0 | if (update_time != 0 && (ioloop_time - update_time) > (time_t)timeout) |
231 | 0 | i_zero(&sbin->persisted_rusage); |
232 | |
|
233 | 0 | sieve_resource_usage_init(rusage_r); |
234 | 0 | rusage_r->cpu_time_msecs = sbin->persisted_rusage.cpu_time_msecs; |
235 | 0 | sieve_resource_usage_add(rusage_r, &sbin->rusage); |
236 | 0 | } |
237 | | |
238 | | bool sieve_binary_check_resource_usage(struct sieve_binary *sbin) |
239 | 0 | { |
240 | 0 | struct sieve_resource_usage rusage; |
241 | |
|
242 | 0 | sieve_binary_get_resource_usage(sbin, &rusage); |
243 | 0 | return !sieve_resource_usage_is_excessive(sbin->svinst, &rusage); |
244 | 0 | } |
245 | | |
246 | | bool sieve_binary_record_resource_usage( |
247 | | struct sieve_binary *sbin, const struct sieve_resource_usage *rusage) |
248 | 0 | { |
249 | 0 | struct sieve_resource_usage rusage_total; |
250 | 0 | struct sieve_script *script; |
251 | |
|
252 | 0 | if (sbin == NULL) |
253 | 0 | return TRUE; |
254 | 0 | if (!sieve_resource_usage_is_high(sbin->svinst, rusage)) |
255 | 0 | return TRUE; |
256 | | |
257 | 0 | sieve_resource_usage_add(&sbin->rusage, rusage); |
258 | 0 | sbin->rusage_updated = TRUE; |
259 | |
|
260 | 0 | sieve_binary_get_resource_usage(sbin, &rusage_total); |
261 | |
|
262 | 0 | e_debug(sbin->event, "Updated cumulative resource usage: %s", |
263 | 0 | sieve_resource_usage_get_summary(&rusage_total)); |
264 | |
|
265 | 0 | if (!sieve_resource_usage_is_excessive(sbin->svinst, &rusage_total)) |
266 | 0 | return TRUE; |
267 | | |
268 | | /* Cumulative resource usage is only tracked for personal scripts; |
269 | | all callers gate this on the user's own script. */ |
270 | 0 | script = sbin->script; |
271 | 0 | i_assert(script != NULL); |
272 | 0 | i_assert(sieve_storage_is_personal(script->storage)); |
273 | | |
274 | 0 | e_warning(sbin->event, |
275 | 0 | "Personal sieve processing disabled for script '%s': " |
276 | 0 | "cumulative resource usage limit exceeded (%s)", |
277 | 0 | sieve_script_label(script), |
278 | 0 | sieve_resource_usage_get_summary(&rusage_total)); |
279 | 0 | return FALSE; |
280 | 0 | } |
281 | | |
282 | | void sieve_binary_set_resource_usage(struct sieve_binary *sbin, |
283 | | const struct sieve_resource_usage *rusage) |
284 | 0 | { |
285 | 0 | i_zero(&sbin->persisted_rusage); |
286 | 0 | sbin->rusage = *rusage; |
287 | 0 | sbin->rusage_updated = TRUE; |
288 | |
|
289 | 0 | (void)sieve_binary_check_resource_usage(sbin); |
290 | 0 | } |
291 | | |
292 | | /* |
293 | | * Accessors |
294 | | */ |
295 | | |
296 | | pool_t sieve_binary_pool(struct sieve_binary *sbin) |
297 | 0 | { |
298 | 0 | return sbin->pool; |
299 | 0 | } |
300 | | |
301 | | struct sieve_script *sieve_binary_script(struct sieve_binary *sbin) |
302 | 0 | { |
303 | 0 | return sbin->script; |
304 | 0 | } |
305 | | |
306 | | const char *sieve_binary_path(struct sieve_binary *sbin) |
307 | 0 | { |
308 | 0 | return sbin->path; |
309 | 0 | } |
310 | | |
311 | | bool sieve_binary_saved(struct sieve_binary *sbin) |
312 | 0 | { |
313 | 0 | return (sbin->path != NULL); |
314 | 0 | } |
315 | | |
316 | | bool sieve_binary_loaded(struct sieve_binary *sbin) |
317 | 0 | { |
318 | 0 | return (sbin->file != NULL); |
319 | 0 | } |
320 | | |
321 | | const char *sieve_binary_source(struct sieve_binary *sbin) |
322 | 0 | { |
323 | 0 | if (sbin->script != NULL && (sbin->path == NULL || sbin->file == NULL)) |
324 | 0 | return sieve_script_label(sbin->script); |
325 | | |
326 | 0 | return sbin->path; |
327 | 0 | } |
328 | | |
329 | | struct sieve_instance *sieve_binary_svinst(struct sieve_binary *sbin) |
330 | 0 | { |
331 | 0 | return sbin->svinst; |
332 | 0 | } |
333 | | |
334 | | time_t sieve_binary_mtime(struct sieve_binary *sbin) |
335 | 0 | { |
336 | 0 | i_assert(sbin->file != NULL); |
337 | 0 | return sbin->file->st.st_mtime; |
338 | 0 | } |
339 | | |
340 | | const struct stat *sieve_binary_stat(struct sieve_binary *sbin) |
341 | 0 | { |
342 | 0 | i_assert(sbin->file != NULL); |
343 | 0 | return &sbin->file->st; |
344 | 0 | } |
345 | | |
346 | | const char *sieve_binary_script_name(struct sieve_binary *sbin) |
347 | 0 | { |
348 | 0 | return (sbin->script == NULL ? |
349 | 0 | NULL : sieve_script_name(sbin->script)); |
350 | 0 | } |
351 | | |
352 | | const char *sieve_binary_script_location(struct sieve_binary *sbin) |
353 | 0 | { |
354 | 0 | return (sbin->script == NULL ? |
355 | 0 | NULL : sieve_script_label(sbin->script)); |
356 | 0 | } |
357 | | |
358 | | /* |
359 | | * Utility |
360 | | */ |
361 | | |
362 | | const char *sieve_binfile_from_name(const char *name) |
363 | 0 | { |
364 | 0 | return t_strconcat(name, "."SIEVE_BINARY_FILEEXT, NULL); |
365 | 0 | } |
366 | | |
367 | | /* |
368 | | * Block management |
369 | | */ |
370 | | |
371 | | unsigned int sieve_binary_block_count(struct sieve_binary *sbin) |
372 | 0 | { |
373 | 0 | return array_count(&sbin->blocks); |
374 | 0 | } |
375 | | |
376 | | struct sieve_binary_block *sieve_binary_block_create(struct sieve_binary *sbin) |
377 | 0 | { |
378 | 0 | unsigned int id = sieve_binary_block_count(sbin); |
379 | 0 | struct sieve_binary_block *sblock; |
380 | |
|
381 | 0 | sblock = p_new(sbin->pool, struct sieve_binary_block, 1); |
382 | 0 | sblock->data = buffer_create_dynamic(sbin->pool, 64); |
383 | 0 | sblock->sbin = sbin; |
384 | 0 | sblock->id = id; |
385 | |
|
386 | 0 | array_append(&sbin->blocks, &sblock, 1); |
387 | |
|
388 | 0 | return sblock; |
389 | 0 | } |
390 | | |
391 | | struct sieve_binary_block * |
392 | | sieve_binary_block_create_id(struct sieve_binary *sbin, unsigned int id) |
393 | 0 | { |
394 | 0 | struct sieve_binary_block *sblock; |
395 | |
|
396 | 0 | sblock = p_new(sbin->pool, struct sieve_binary_block, 1); |
397 | |
|
398 | 0 | array_idx_set(&sbin->blocks, id, &sblock); |
399 | 0 | sblock->data = NULL; |
400 | 0 | sblock->sbin = sbin; |
401 | 0 | sblock->id = id; |
402 | |
|
403 | 0 | return sblock; |
404 | 0 | } |
405 | | |
406 | | static bool sieve_binary_block_fetch(struct sieve_binary_block *sblock) |
407 | 0 | { |
408 | 0 | struct sieve_binary *sbin = sblock->sbin; |
409 | |
|
410 | 0 | if (sbin->file != NULL) { |
411 | | /* Try to acces the block in the binary on disk (apparently we |
412 | | were lazy) |
413 | | */ |
414 | 0 | if (!sieve_binary_load_block(sblock) || sblock->data == NULL) |
415 | 0 | return FALSE; |
416 | 0 | } else { |
417 | 0 | sblock->data = buffer_create_dynamic(sbin->pool, 64); |
418 | 0 | return TRUE; |
419 | 0 | } |
420 | | |
421 | 0 | return TRUE; |
422 | 0 | } |
423 | | |
424 | | struct sieve_binary_block * |
425 | | sieve_binary_block_get(struct sieve_binary *sbin, unsigned int id) |
426 | 0 | { |
427 | 0 | struct sieve_binary_block *sblock = sieve_binary_block_index(sbin, id); |
428 | |
|
429 | 0 | if (sblock == NULL) |
430 | 0 | return NULL; |
431 | | |
432 | 0 | if (sblock->data == NULL && !sieve_binary_block_fetch(sblock)) |
433 | 0 | return NULL; |
434 | | |
435 | 0 | return sblock; |
436 | 0 | } |
437 | | |
438 | | void sieve_binary_block_clear(struct sieve_binary_block *sblock) |
439 | 0 | { |
440 | 0 | buffer_set_used_size(sblock->data, 0); |
441 | 0 | } |
442 | | |
443 | | buffer_t *sieve_binary_block_get_buffer(struct sieve_binary_block *sblock) |
444 | 0 | { |
445 | 0 | if (sblock->data == NULL && !sieve_binary_block_fetch(sblock)) |
446 | 0 | return NULL; |
447 | | |
448 | 0 | return sblock->data; |
449 | 0 | } |
450 | | |
451 | | struct sieve_binary * |
452 | | sieve_binary_block_get_binary(const struct sieve_binary_block *sblock) |
453 | 0 | { |
454 | 0 | return sblock->sbin; |
455 | 0 | } |
456 | | |
457 | | unsigned int sieve_binary_block_get_id(const struct sieve_binary_block *sblock) |
458 | 0 | { |
459 | 0 | return sblock->id; |
460 | 0 | } |
461 | | |
462 | | size_t sieve_binary_block_get_size(const struct sieve_binary_block *sblock) |
463 | 0 | { |
464 | 0 | return _sieve_binary_block_get_size(sblock); |
465 | 0 | } |
466 | | |
467 | | /* |
468 | | * Up-to-date checking |
469 | | */ |
470 | | |
471 | | bool sieve_binary_up_to_date(struct sieve_binary *sbin, |
472 | | enum sieve_compile_flags cpflags) |
473 | 0 | { |
474 | 0 | struct sieve_binary_extension_reg *const *regs; |
475 | 0 | struct sieve_binary_block *sblock; |
476 | 0 | sieve_size_t offset = 0; |
477 | 0 | unsigned int ext_count, i; |
478 | 0 | int ret; |
479 | |
|
480 | 0 | i_assert(sbin->file != NULL); |
481 | | |
482 | 0 | sblock = sieve_binary_block_get(sbin, SBIN_SYSBLOCK_SCRIPT_DATA); |
483 | 0 | if (sblock == NULL || sbin->script == NULL) |
484 | 0 | return FALSE; |
485 | | |
486 | 0 | if ((ret = sieve_script_binary_read_metadata(sbin->script, sblock, |
487 | 0 | &offset)) <= 0) { |
488 | 0 | if (ret < 0) { |
489 | 0 | e_debug(sbin->event, "up-to-date: " |
490 | 0 | "failed to read script metadata from binary"); |
491 | 0 | } else { |
492 | 0 | e_debug(sbin->event, "up-to-date: " |
493 | 0 | "script metadata indicates that binary is not up-to-date"); |
494 | 0 | } |
495 | 0 | return FALSE; |
496 | 0 | } |
497 | | |
498 | 0 | regs = array_get(&sbin->extensions, &ext_count); |
499 | 0 | for (i = 0; i < ext_count; i++) { |
500 | 0 | const struct sieve_binary_extension *binext = regs[i]->binext; |
501 | |
|
502 | 0 | if (binext != NULL && binext->binary_up_to_date != NULL && |
503 | 0 | !binext->binary_up_to_date(regs[i]->extension, sbin, |
504 | 0 | regs[i]->context, cpflags)) { |
505 | 0 | e_debug(sbin->event, "up-to-date: " |
506 | 0 | "the %s extension indicates binary is not up-to-date", |
507 | 0 | sieve_extension_name(regs[i]->extension)); |
508 | 0 | return FALSE; |
509 | 0 | } |
510 | 0 | } |
511 | 0 | return TRUE; |
512 | 0 | } |
513 | | |
514 | | /* |
515 | | * Activate the binary (after code generation) |
516 | | */ |
517 | | |
518 | | void sieve_binary_activate(struct sieve_binary *sbin) |
519 | 0 | { |
520 | 0 | struct sieve_binary_extension_reg *const *regs; |
521 | 0 | unsigned int i, ext_count; |
522 | | |
523 | | /* Load other extensions into binary */ |
524 | 0 | regs = array_get(&sbin->linked_extensions, &ext_count); |
525 | 0 | for (i = 0; i < ext_count; i++) { |
526 | 0 | const struct sieve_extension *ext = regs[i]->extension; |
527 | |
|
528 | 0 | if (ext != NULL && ext->def != NULL && |
529 | 0 | ext->def->binary_load != NULL) |
530 | 0 | ext->def->binary_load(ext, sbin); |
531 | 0 | } |
532 | 0 | } |
533 | | |
534 | | /* |
535 | | * Extension handling |
536 | | */ |
537 | | |
538 | | void sieve_binary_extension_set_context(struct sieve_binary *sbin, |
539 | | const struct sieve_extension *ext, |
540 | | void *context) |
541 | 0 | { |
542 | 0 | struct sieve_binary_extension_reg *ereg = |
543 | 0 | sieve_binary_extension_get_reg(sbin, ext, TRUE); |
544 | |
|
545 | 0 | if (ereg != NULL) |
546 | 0 | ereg->context = context; |
547 | 0 | } |
548 | | |
549 | | const void * |
550 | | sieve_binary_extension_get_context(struct sieve_binary *sbin, |
551 | | const struct sieve_extension *ext) |
552 | 0 | { |
553 | 0 | struct sieve_binary_extension_reg *ereg = |
554 | 0 | sieve_binary_extension_get_reg(sbin, ext, TRUE); |
555 | |
|
556 | 0 | if (ereg != NULL) |
557 | 0 | return ereg->context; |
558 | | |
559 | 0 | return NULL; |
560 | 0 | } |
561 | | |
562 | | void sieve_binary_extension_set(struct sieve_binary *sbin, |
563 | | const struct sieve_extension *ext, |
564 | | const struct sieve_binary_extension *bext, |
565 | | void *context) |
566 | 0 | { |
567 | 0 | struct sieve_binary_extension_reg *ereg = |
568 | 0 | sieve_binary_extension_get_reg(sbin, ext, TRUE); |
569 | |
|
570 | 0 | if (ereg != NULL) { |
571 | 0 | ereg->binext = bext; |
572 | |
|
573 | 0 | if (context != NULL) |
574 | 0 | ereg->context = context; |
575 | 0 | } |
576 | 0 | } |
577 | | |
578 | | struct sieve_binary_block * |
579 | | sieve_binary_extension_create_block(struct sieve_binary *sbin, |
580 | | const struct sieve_extension *ext) |
581 | 0 | { |
582 | 0 | struct sieve_binary_block *sblock; |
583 | 0 | struct sieve_binary_extension_reg *ereg = |
584 | 0 | sieve_binary_extension_get_reg(sbin, ext, TRUE); |
585 | |
|
586 | 0 | i_assert(ereg != NULL); |
587 | | |
588 | 0 | sblock = sieve_binary_block_create(sbin); |
589 | |
|
590 | 0 | if (ereg->block_id < SBIN_SYSBLOCK_LAST) |
591 | 0 | ereg->block_id = sblock->id; |
592 | 0 | sblock->ext_index = ereg->index; |
593 | |
|
594 | 0 | return sblock; |
595 | 0 | } |
596 | | |
597 | | struct sieve_binary_block * |
598 | | sieve_binary_extension_get_block(struct sieve_binary *sbin, |
599 | | const struct sieve_extension *ext) |
600 | 0 | { |
601 | 0 | struct sieve_binary_extension_reg *ereg = |
602 | 0 | sieve_binary_extension_get_reg(sbin, ext, TRUE); |
603 | |
|
604 | 0 | i_assert(ereg != NULL); |
605 | | |
606 | 0 | if (ereg->block_id < SBIN_SYSBLOCK_LAST) |
607 | 0 | return NULL; |
608 | | |
609 | 0 | return sieve_binary_block_get(sbin, ereg->block_id); |
610 | 0 | } |
611 | | |
612 | | int sieve_binary_extension_link(struct sieve_binary *sbin, |
613 | | const struct sieve_extension *ext) |
614 | 0 | { |
615 | 0 | return sieve_binary_extension_register(sbin, ext, NULL); |
616 | 0 | } |
617 | | |
618 | | const struct sieve_extension * |
619 | | sieve_binary_extension_get_by_index(struct sieve_binary *sbin, int index) |
620 | 0 | { |
621 | 0 | struct sieve_binary_extension_reg *const *ereg; |
622 | |
|
623 | 0 | if (index < (int)array_count(&sbin->extensions)) { |
624 | 0 | ereg = array_idx(&sbin->extensions, (unsigned int)index); |
625 | |
|
626 | 0 | return (*ereg)->extension; |
627 | 0 | } |
628 | | |
629 | 0 | return NULL; |
630 | 0 | } |
631 | | |
632 | | int sieve_binary_extension_get_index(struct sieve_binary *sbin, |
633 | | const struct sieve_extension *ext) |
634 | 0 | { |
635 | 0 | struct sieve_binary_extension_reg *ereg = |
636 | 0 | sieve_binary_extension_get_reg(sbin, ext, FALSE); |
637 | |
|
638 | 0 | return (ereg == NULL ? -1 : ereg->index); |
639 | 0 | } |
640 | | |
641 | | int sieve_binary_extensions_count(struct sieve_binary *sbin) |
642 | 0 | { |
643 | 0 | return (int)array_count(&sbin->extensions); |
644 | 0 | } |