/src/pigeonhole/src/testsuite/testsuite-objects.c
Line | Count | Source |
1 | | /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file |
2 | | */ |
3 | | |
4 | | #include "lib.h" |
5 | | #include "string.h" |
6 | | #include "ostream.h" |
7 | | #include "hash.h" |
8 | | #include "mail-storage.h" |
9 | | |
10 | | #include "sieve.h" |
11 | | #include "sieve-code.h" |
12 | | #include "sieve-commands.h" |
13 | | #include "sieve-extensions.h" |
14 | | #include "sieve-validator.h" |
15 | | #include "sieve-generator.h" |
16 | | #include "sieve-binary.h" |
17 | | #include "sieve-dump.h" |
18 | | |
19 | | #include "testsuite-common.h" |
20 | | #include "testsuite-objects.h" |
21 | | #include "testsuite-message.h" |
22 | | |
23 | | /* |
24 | | * Testsuite core objects |
25 | | */ |
26 | | |
27 | | enum testsuite_object_code { |
28 | | TESTSUITE_OBJECT_MESSAGE, |
29 | | TESTSUITE_OBJECT_ENVELOPE |
30 | | }; |
31 | | |
32 | | const struct testsuite_object_def *testsuite_core_objects[] = { |
33 | | &message_testsuite_object, |
34 | | &envelope_testsuite_object, |
35 | | }; |
36 | | |
37 | | const unsigned int testsuite_core_objects_count = |
38 | | N_ELEMENTS(testsuite_core_objects); |
39 | | |
40 | | /* |
41 | | * Testsuite object registry |
42 | | */ |
43 | | |
44 | | static inline struct sieve_validator_object_registry * |
45 | | _get_object_registry(struct sieve_validator *valdtr) |
46 | 0 | { |
47 | 0 | struct testsuite_validator_context *ctx = |
48 | 0 | testsuite_validator_context_get(valdtr); |
49 | |
|
50 | 0 | return ctx->object_registrations; |
51 | 0 | } |
52 | | |
53 | | void testsuite_object_register(struct sieve_validator *valdtr, |
54 | | const struct sieve_extension *ext, |
55 | | const struct testsuite_object_def *tobj_def) |
56 | 0 | { |
57 | 0 | struct sieve_validator_object_registry *regs = |
58 | 0 | _get_object_registry(valdtr); |
59 | |
|
60 | 0 | sieve_validator_object_registry_add(regs, ext, &tobj_def->obj_def); |
61 | 0 | } |
62 | | |
63 | | static const struct testsuite_object * |
64 | | testsuite_object_create(struct sieve_validator *valdtr, |
65 | | struct sieve_command *cmd, const char *identifier) |
66 | 0 | { |
67 | 0 | struct sieve_validator_object_registry *regs = |
68 | 0 | _get_object_registry(valdtr); |
69 | 0 | struct sieve_object object; |
70 | 0 | struct testsuite_object *tobj; |
71 | |
|
72 | 0 | if (!sieve_validator_object_registry_find(regs, identifier, &object)) |
73 | 0 | return NULL; |
74 | | |
75 | 0 | tobj = p_new(sieve_command_pool(cmd), struct testsuite_object, 1); |
76 | 0 | tobj->object = object; |
77 | 0 | tobj->def = (const struct testsuite_object_def *)object.def; |
78 | |
|
79 | 0 | return tobj; |
80 | 0 | } |
81 | | |
82 | | void testsuite_register_core_objects(struct testsuite_validator_context *ctx) |
83 | 0 | { |
84 | 0 | struct sieve_validator_object_registry *regs = |
85 | 0 | ctx->object_registrations; |
86 | 0 | unsigned int i; |
87 | | |
88 | | /* Register core testsuite objects */ |
89 | 0 | for (i = 0; i < testsuite_core_objects_count; i++) { |
90 | 0 | const struct testsuite_object_def *tobj_def = |
91 | 0 | testsuite_core_objects[i]; |
92 | |
|
93 | 0 | sieve_validator_object_registry_add( |
94 | 0 | regs, testsuite_ext, &tobj_def->obj_def); |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * Testsuite object code |
100 | | */ |
101 | | |
102 | | const struct sieve_operand_class sieve_testsuite_object_operand_class = |
103 | | { "testsuite object" }; |
104 | | |
105 | | static const struct sieve_extension_objects core_testsuite_objects = |
106 | | SIEVE_EXT_DEFINE_OBJECTS(testsuite_core_objects); |
107 | | |
108 | | const struct sieve_operand_def testsuite_object_operand = { |
109 | | .name = "testsuite-object", |
110 | | .ext_def = &testsuite_extension, |
111 | | .code = TESTSUITE_OPERAND_OBJECT, |
112 | | .class = &sieve_testsuite_object_operand_class, |
113 | | .interface = &core_testsuite_objects, |
114 | | }; |
115 | | |
116 | | static void |
117 | | testsuite_object_emit(struct sieve_binary_block *sblock, |
118 | | const struct testsuite_object *tobj, int member_id) |
119 | 0 | { |
120 | 0 | sieve_opr_object_emit(sblock, tobj->object.ext, tobj->object.def); |
121 | |
|
122 | 0 | if (tobj->def != NULL && tobj->def->get_member_id != NULL) |
123 | 0 | (void)sieve_binary_emit_byte(sblock, (unsigned char)member_id); |
124 | 0 | } |
125 | | |
126 | | bool testsuite_object_read(struct sieve_binary_block *sblock, |
127 | | sieve_size_t *address, struct testsuite_object *tobj) |
128 | 0 | { |
129 | 0 | struct sieve_operand oprnd; |
130 | |
|
131 | 0 | if (!sieve_operand_read(sblock, address, NULL, &oprnd)) |
132 | 0 | return FALSE; |
133 | | |
134 | 0 | if (!sieve_opr_object_read_data(sblock, &oprnd, |
135 | 0 | &sieve_testsuite_object_operand_class, |
136 | 0 | address, &tobj->object)) |
137 | 0 | return FALSE; |
138 | | |
139 | 0 | tobj->def = (const struct testsuite_object_def *)tobj->object.def; |
140 | 0 | i_assert(tobj->def != NULL); |
141 | 0 | return TRUE; |
142 | 0 | } |
143 | | |
144 | | bool testsuite_object_read_member(struct sieve_binary_block *sblock, |
145 | | sieve_size_t *address, |
146 | | struct testsuite_object *tobj, |
147 | | int *member_id_r) |
148 | 0 | { |
149 | 0 | if (!testsuite_object_read(sblock, address, tobj)) |
150 | 0 | return FALSE; |
151 | | |
152 | 0 | *member_id_r = -1; |
153 | 0 | if (tobj->def->get_member_id != NULL) { |
154 | 0 | if (!sieve_binary_read_code(sblock, address, member_id_r)) |
155 | 0 | return FALSE; |
156 | 0 | } |
157 | 0 | return TRUE; |
158 | 0 | } |
159 | | |
160 | | const char * |
161 | | testsuite_object_member_name(const struct testsuite_object *object, |
162 | | int member_id) |
163 | 0 | { |
164 | 0 | const struct testsuite_object_def *obj_def = object->def; |
165 | 0 | const char *member = NULL; |
166 | |
|
167 | 0 | if (obj_def->get_member_id != NULL) { |
168 | 0 | if (obj_def->get_member_name != NULL) |
169 | 0 | member = obj_def->get_member_name(member_id); |
170 | 0 | } else |
171 | 0 | return obj_def->obj_def.identifier; |
172 | | |
173 | 0 | if (member == NULL) { |
174 | 0 | return t_strdup_printf("%s.%d", obj_def->obj_def.identifier, |
175 | 0 | member_id); |
176 | 0 | } |
177 | 0 | return t_strdup_printf("%s.%s", obj_def->obj_def.identifier, member); |
178 | 0 | } |
179 | | |
180 | | bool testsuite_object_dump(const struct sieve_dumptime_env *denv, |
181 | | sieve_size_t *address) |
182 | 0 | { |
183 | 0 | struct testsuite_object object; |
184 | 0 | int member_id; |
185 | |
|
186 | 0 | sieve_code_mark(denv); |
187 | |
|
188 | 0 | if (!testsuite_object_read_member(denv->sblock, address, |
189 | 0 | &object, &member_id)) |
190 | 0 | return FALSE; |
191 | | |
192 | 0 | sieve_code_dumpf(denv, "%s: %s", |
193 | 0 | sieve_testsuite_object_operand_class.name, |
194 | 0 | testsuite_object_member_name(&object, member_id)); |
195 | 0 | return TRUE; |
196 | 0 | } |
197 | | |
198 | | /* |
199 | | * Testsuite object argument |
200 | | */ |
201 | | |
202 | | static bool |
203 | | arg_testsuite_object_generate(const struct sieve_codegen_env *cgenv, |
204 | | struct sieve_ast_argument *arg, |
205 | | struct sieve_command *cmd); |
206 | | |
207 | | const struct sieve_argument_def testsuite_object_argument = { |
208 | | .identifier = "testsuite-object", |
209 | | .generate = arg_testsuite_object_generate |
210 | | }; |
211 | | |
212 | | struct testsuite_object_argctx { |
213 | | const struct testsuite_object *object; |
214 | | int member; |
215 | | }; |
216 | | |
217 | | bool testsuite_object_argument_activate(struct sieve_validator *valdtr, |
218 | | struct sieve_ast_argument *arg, |
219 | | struct sieve_command *cmd) |
220 | 0 | { |
221 | 0 | const char *objname = sieve_ast_argument_strc(arg); |
222 | 0 | const struct testsuite_object *tobj; |
223 | 0 | int member_id; |
224 | 0 | const char *member; |
225 | 0 | struct testsuite_object_argctx *ctx; |
226 | | |
227 | | /* Parse the object specifier */ |
228 | |
|
229 | 0 | member = strchr(objname, '.'); |
230 | 0 | if (member != NULL) { |
231 | 0 | objname = t_strdup_until(objname, member); |
232 | 0 | member++; |
233 | 0 | } |
234 | | |
235 | | /* Find the object */ |
236 | |
|
237 | 0 | tobj = testsuite_object_create(valdtr, cmd, objname); |
238 | 0 | if (tobj == NULL) { |
239 | 0 | sieve_argument_validate_error(valdtr, arg, |
240 | 0 | "unknown testsuite object '%s'", |
241 | 0 | objname); |
242 | 0 | return FALSE; |
243 | 0 | } |
244 | | |
245 | | /* Find the object member */ |
246 | | |
247 | 0 | member_id = -1; |
248 | 0 | if (member != NULL) { |
249 | 0 | if (tobj->def == NULL || tobj->def->get_member_id == NULL || |
250 | 0 | (member_id = tobj->def->get_member_id(member)) == -1) { |
251 | 0 | sieve_argument_validate_error(valdtr, arg, |
252 | 0 | "member '%s' does not exist for testsuite object '%s'", |
253 | 0 | member, objname); |
254 | 0 | return FALSE; |
255 | 0 | } |
256 | 0 | } |
257 | | |
258 | | /* Assign argument context */ |
259 | | |
260 | 0 | ctx = p_new(sieve_command_pool(cmd), struct testsuite_object_argctx, 1); |
261 | 0 | ctx->object = tobj; |
262 | 0 | ctx->member = member_id; |
263 | |
|
264 | 0 | arg->argument = sieve_argument_create( |
265 | 0 | arg->ast, &testsuite_object_argument, testsuite_ext, 0); |
266 | 0 | arg->argument->data = ctx; |
267 | 0 | return TRUE; |
268 | 0 | } |
269 | | |
270 | | static bool |
271 | | arg_testsuite_object_generate(const struct sieve_codegen_env *cgenv, |
272 | | struct sieve_ast_argument *arg, |
273 | | struct sieve_command *cmd ATTR_UNUSED) |
274 | 0 | { |
275 | 0 | struct testsuite_object_argctx *ctx = |
276 | 0 | (struct testsuite_object_argctx *)arg->argument->data; |
277 | |
|
278 | 0 | testsuite_object_emit(cgenv->sblock, ctx->object, ctx->member); |
279 | 0 | return TRUE; |
280 | 0 | } |
281 | | |
282 | | /* |
283 | | * Testsuite core object implementation |
284 | | */ |
285 | | |
286 | | static bool tsto_message_set_member(const struct sieve_runtime_env *renv, |
287 | | int id, string_t *value); |
288 | | |
289 | | static int tsto_envelope_get_member_id(const char *identifier); |
290 | | static const char *tsto_envelope_get_member_name(int id); |
291 | | static bool tsto_envelope_set_member(const struct sieve_runtime_env *renv, |
292 | | int id, string_t *value); |
293 | | |
294 | | const struct testsuite_object_def message_testsuite_object = { |
295 | | SIEVE_OBJECT("message", &testsuite_object_operand, |
296 | | TESTSUITE_OBJECT_MESSAGE), |
297 | | .set_member = tsto_message_set_member, |
298 | | }; |
299 | | |
300 | | const struct testsuite_object_def envelope_testsuite_object = { |
301 | | SIEVE_OBJECT("envelope", &testsuite_object_operand, |
302 | | TESTSUITE_OBJECT_ENVELOPE), |
303 | | .get_member_id = tsto_envelope_get_member_id, |
304 | | .get_member_name = tsto_envelope_get_member_name, |
305 | | .set_member = tsto_envelope_set_member, |
306 | | }; |
307 | | |
308 | | enum testsuite_object_envelope_field { |
309 | | TESTSUITE_OBJECT_ENVELOPE_FROM, |
310 | | TESTSUITE_OBJECT_ENVELOPE_TO, |
311 | | TESTSUITE_OBJECT_ENVELOPE_ORIG_TO, |
312 | | TESTSUITE_OBJECT_ENVELOPE_AUTH_USER, |
313 | | }; |
314 | | |
315 | | static bool |
316 | | tsto_message_set_member(const struct sieve_runtime_env *renv, int id, |
317 | | string_t *value) |
318 | 0 | { |
319 | 0 | if (id != -1) |
320 | 0 | return FALSE; |
321 | | |
322 | 0 | testsuite_message_set_string(renv, value); |
323 | 0 | return TRUE; |
324 | 0 | } |
325 | | |
326 | | static int tsto_envelope_get_member_id(const char *identifier) |
327 | 0 | { |
328 | 0 | if (strcasecmp(identifier, "from") == 0) |
329 | 0 | return TESTSUITE_OBJECT_ENVELOPE_FROM; |
330 | 0 | if (strcasecmp(identifier, "to") == 0) |
331 | 0 | return TESTSUITE_OBJECT_ENVELOPE_TO; |
332 | 0 | if (strcasecmp(identifier, "orig_to") == 0) |
333 | 0 | return TESTSUITE_OBJECT_ENVELOPE_ORIG_TO; |
334 | 0 | if (strcasecmp(identifier, "auth") == 0) |
335 | 0 | return TESTSUITE_OBJECT_ENVELOPE_AUTH_USER; |
336 | 0 | return -1; |
337 | 0 | } |
338 | | |
339 | | static const char *tsto_envelope_get_member_name(int id) |
340 | 0 | { |
341 | 0 | switch (id) { |
342 | 0 | case TESTSUITE_OBJECT_ENVELOPE_FROM: |
343 | 0 | return "from"; |
344 | 0 | case TESTSUITE_OBJECT_ENVELOPE_TO: |
345 | 0 | return "to"; |
346 | 0 | case TESTSUITE_OBJECT_ENVELOPE_ORIG_TO: |
347 | 0 | return "orig_to"; |
348 | 0 | case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER: |
349 | 0 | return "auth"; |
350 | 0 | } |
351 | 0 | return NULL; |
352 | 0 | } |
353 | | |
354 | | static bool |
355 | | tsto_envelope_set_member(const struct sieve_runtime_env *renv, int id, |
356 | | string_t *value) |
357 | 0 | { |
358 | 0 | switch (id) { |
359 | 0 | case TESTSUITE_OBJECT_ENVELOPE_FROM: |
360 | 0 | testsuite_envelope_set_sender(renv, str_c(value)); |
361 | 0 | return TRUE; |
362 | 0 | case TESTSUITE_OBJECT_ENVELOPE_TO: |
363 | 0 | testsuite_envelope_set_recipient(renv, str_c(value)); |
364 | 0 | return TRUE; |
365 | 0 | case TESTSUITE_OBJECT_ENVELOPE_ORIG_TO: |
366 | 0 | testsuite_envelope_set_orig_recipient(renv, str_c(value)); |
367 | 0 | return TRUE; |
368 | 0 | case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER: |
369 | 0 | testsuite_envelope_set_auth_user(renv, str_c(value)); |
370 | 0 | return TRUE; |
371 | 0 | } |
372 | 0 | return FALSE; |
373 | 0 | } |