/src/pigeonhole/src/lib-sieve/plugins/ihave/ext-ihave-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 | | |
6 | | #include "sieve-common.h" |
7 | | #include "sieve-extensions.h" |
8 | | #include "sieve-error.h" |
9 | | #include "sieve-script.h" |
10 | | #include "sieve-binary.h" |
11 | | #include "sieve-generator.h" |
12 | | #include "sieve-interpreter.h" |
13 | | #include "sieve-dump.h" |
14 | | |
15 | | #include "ext-ihave-common.h" |
16 | | #include "ext-ihave-binary.h" |
17 | | |
18 | | /* |
19 | | * Forward declarations |
20 | | */ |
21 | | |
22 | | static bool |
23 | | ext_ihave_binary_pre_save(const struct sieve_extension *ext, |
24 | | struct sieve_binary *sbin, void *context, |
25 | | enum sieve_error *error_code_r); |
26 | | static bool |
27 | | ext_ihave_binary_open(const struct sieve_extension *ext, |
28 | | struct sieve_binary *sbin, void *context); |
29 | | static bool |
30 | | ext_ihave_binary_up_to_date(const struct sieve_extension *ext, |
31 | | struct sieve_binary *sbin, void *context, |
32 | | enum sieve_compile_flags cpflags); |
33 | | |
34 | | /* |
35 | | * Binary include extension |
36 | | */ |
37 | | |
38 | | const struct sieve_binary_extension ihave_binary_ext = { |
39 | | .extension = &ihave_extension, |
40 | | .binary_pre_save = ext_ihave_binary_pre_save, |
41 | | .binary_open = ext_ihave_binary_open, |
42 | | .binary_up_to_date = ext_ihave_binary_up_to_date, |
43 | | }; |
44 | | |
45 | | /* |
46 | | * Binary context management |
47 | | */ |
48 | | |
49 | | struct ext_ihave_binary_context { |
50 | | struct sieve_binary *binary; |
51 | | struct sieve_binary_block *block; |
52 | | |
53 | | ARRAY(const char *) missing_extensions; |
54 | | }; |
55 | | |
56 | | static struct ext_ihave_binary_context * |
57 | | ext_ihave_binary_create_context(const struct sieve_extension *this_ext, |
58 | | struct sieve_binary *sbin) |
59 | 0 | { |
60 | 0 | pool_t pool = sieve_binary_pool(sbin); |
61 | 0 | struct ext_ihave_binary_context *ctx = |
62 | 0 | p_new(pool, struct ext_ihave_binary_context, 1); |
63 | |
|
64 | 0 | ctx->binary = sbin; |
65 | 0 | p_array_init(&ctx->missing_extensions, pool, 64); |
66 | |
|
67 | 0 | sieve_binary_extension_set(sbin, this_ext, &ihave_binary_ext, ctx); |
68 | 0 | return ctx; |
69 | 0 | } |
70 | | |
71 | | struct ext_ihave_binary_context * |
72 | | ext_ihave_binary_get_context(const struct sieve_extension *this_ext, |
73 | | struct sieve_binary *sbin) |
74 | 0 | { |
75 | 0 | struct ext_ihave_binary_context *ctx = |
76 | 0 | (struct ext_ihave_binary_context *) |
77 | 0 | sieve_binary_extension_get_context(sbin, this_ext); |
78 | |
|
79 | 0 | if (ctx == NULL) |
80 | 0 | ctx = ext_ihave_binary_create_context(this_ext, sbin); |
81 | 0 | return ctx; |
82 | 0 | } |
83 | | |
84 | | struct ext_ihave_binary_context * |
85 | | ext_ihave_binary_init(const struct sieve_extension *this_ext, |
86 | | struct sieve_binary *sbin, struct sieve_ast *ast) |
87 | 0 | { |
88 | 0 | struct ext_ihave_ast_context *ast_ctx = |
89 | 0 | ext_ihave_get_ast_context(this_ext, ast); |
90 | 0 | struct ext_ihave_binary_context *binctx; |
91 | 0 | const char *const *exts; |
92 | 0 | unsigned int i, count; |
93 | |
|
94 | 0 | binctx = ext_ihave_binary_get_context(this_ext, sbin); |
95 | |
|
96 | 0 | exts = array_get(&ast_ctx->missing_extensions, &count); |
97 | 0 | if (count > 0) { |
98 | 0 | pool_t pool = sieve_binary_pool(sbin); |
99 | |
|
100 | 0 | if (binctx->block == NULL) { |
101 | 0 | binctx->block = sieve_binary_extension_create_block( |
102 | 0 | sbin, this_ext); |
103 | 0 | } |
104 | |
|
105 | 0 | for (i = 0; i < count; i++) { |
106 | 0 | const char *ext_name = p_strdup(pool, exts[i]); |
107 | |
|
108 | 0 | array_append(&binctx->missing_extensions, &ext_name, 1); |
109 | 0 | } |
110 | 0 | } |
111 | |
|
112 | 0 | return binctx; |
113 | 0 | } |
114 | | |
115 | | /* |
116 | | * Binary extension |
117 | | */ |
118 | | |
119 | | static bool |
120 | | ext_ihave_binary_pre_save(const struct sieve_extension *ext, |
121 | | struct sieve_binary *sbin, void *context, |
122 | | enum sieve_error *error_code_r ATTR_UNUSED) |
123 | 0 | { |
124 | 0 | struct ext_ihave_binary_context *binctx = |
125 | 0 | (struct ext_ihave_binary_context *)context; |
126 | 0 | const char *const *exts; |
127 | 0 | unsigned int count, i; |
128 | |
|
129 | 0 | exts = array_get(&binctx->missing_extensions, &count); |
130 | |
|
131 | 0 | if (binctx->block != NULL) |
132 | 0 | sieve_binary_block_clear(binctx->block); |
133 | |
|
134 | 0 | if (count > 0) { |
135 | 0 | if (binctx->block == NULL) { |
136 | 0 | binctx->block = |
137 | 0 | sieve_binary_extension_create_block(sbin, ext); |
138 | 0 | } |
139 | |
|
140 | 0 | sieve_binary_emit_unsigned(binctx->block, count); |
141 | |
|
142 | 0 | for (i = 0; i < count; i++) |
143 | 0 | sieve_binary_emit_cstring(binctx->block, exts[i]); |
144 | 0 | } |
145 | 0 | return TRUE; |
146 | 0 | } |
147 | | |
148 | | static bool |
149 | | ext_ihave_binary_open(const struct sieve_extension *ext, |
150 | | struct sieve_binary *sbin, void *context) |
151 | 0 | { |
152 | 0 | struct sieve_instance *svinst = ext->svinst; |
153 | 0 | struct ext_ihave_binary_context *binctx = |
154 | 0 | (struct ext_ihave_binary_context *)context; |
155 | 0 | struct sieve_binary_block *sblock; |
156 | 0 | unsigned int i, count, block_id; |
157 | 0 | sieve_size_t offset; |
158 | |
|
159 | 0 | sblock = sieve_binary_extension_get_block(sbin, ext); |
160 | |
|
161 | 0 | if (sblock != NULL) { |
162 | 0 | binctx->block = sblock; |
163 | 0 | block_id = sieve_binary_block_get_id(sblock); |
164 | |
|
165 | 0 | offset = 0; |
166 | | |
167 | | /* Read number of missing extensions to read subsequently */ |
168 | 0 | if (!sieve_binary_read_unsigned(sblock, &offset, &count)) { |
169 | 0 | e_error(svinst->event, "ihave: " |
170 | 0 | "failed to read missing extension count " |
171 | 0 | "from block %d of binary %s", |
172 | 0 | block_id, sieve_binary_path(sbin)); |
173 | 0 | return FALSE; |
174 | 0 | } |
175 | | |
176 | | /* Read dependencies */ |
177 | 0 | for (i = 0; i < count; i++) { |
178 | 0 | string_t *ext_name; |
179 | 0 | const char *name; |
180 | |
|
181 | 0 | if (!sieve_binary_read_string(sblock, &offset, |
182 | 0 | &ext_name)) { |
183 | | /* Binary is corrupt, recompile */ |
184 | 0 | e_error(svinst->event, "ihave: " |
185 | 0 | "failed to read missing extension name " |
186 | 0 | "from block %d of binary %s", |
187 | 0 | block_id, sieve_binary_path(sbin)); |
188 | 0 | return FALSE; |
189 | 0 | } |
190 | | |
191 | 0 | name = str_c(ext_name); |
192 | 0 | array_append(&binctx->missing_extensions, &name, 1); |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | 0 | return TRUE; |
197 | 0 | } |
198 | | |
199 | | static bool |
200 | | ext_ihave_binary_up_to_date(const struct sieve_extension *ext, |
201 | | struct sieve_binary *sbin ATTR_UNUSED, |
202 | | void *context, enum sieve_compile_flags cpflags) |
203 | 0 | { |
204 | 0 | struct ext_ihave_binary_context *binctx = |
205 | 0 | (struct ext_ihave_binary_context *)context; |
206 | 0 | const struct sieve_extension *mext; |
207 | 0 | const char *const *mexts; |
208 | 0 | unsigned int count, i; |
209 | |
|
210 | 0 | mexts = array_get(&binctx->missing_extensions, &count); |
211 | 0 | for (i = 0; i < count; i++) { |
212 | 0 | mext = sieve_extension_get_by_name(ext->svinst, mexts[i]); |
213 | 0 | if (mext != NULL && |
214 | 0 | ((cpflags & SIEVE_COMPILE_FLAG_NOGLOBAL) == 0 || |
215 | 0 | !mext->global)) |
216 | 0 | return FALSE; |
217 | 0 | } |
218 | 0 | return TRUE; |
219 | 0 | } |
220 | | |
221 | | /* |
222 | | * Main extension interface |
223 | | */ |
224 | | |
225 | | bool ext_ihave_binary_load(const struct sieve_extension *ext, |
226 | | struct sieve_binary *sbin) |
227 | 0 | { |
228 | 0 | (void)ext_ihave_binary_get_context(ext, sbin); |
229 | |
|
230 | 0 | return TRUE; |
231 | 0 | } |
232 | | |
233 | | bool ext_ihave_binary_dump(const struct sieve_extension *ext, |
234 | | struct sieve_dumptime_env *denv) |
235 | 0 | { |
236 | 0 | struct sieve_binary *sbin = denv->sbin; |
237 | 0 | struct ext_ihave_binary_context *binctx = |
238 | 0 | ext_ihave_binary_get_context(ext, sbin); |
239 | 0 | const char *const *exts; |
240 | 0 | unsigned int count, i; |
241 | |
|
242 | 0 | exts = array_get(&binctx->missing_extensions, &count); |
243 | |
|
244 | 0 | if (count > 0) { |
245 | 0 | sieve_binary_dump_sectionf( |
246 | 0 | denv, "Extensions missing at compile (block: %d)", |
247 | 0 | sieve_binary_block_get_id(binctx->block)); |
248 | |
|
249 | 0 | for (i = 0; i < count; i++) |
250 | 0 | sieve_binary_dumpf(denv, " - %s\n", exts[i]); |
251 | 0 | } |
252 | |
|
253 | 0 | return TRUE; |
254 | 0 | } |