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