1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5
6 #include "sieve.h"
7 #include "sieve-code.h"
8 #include "sieve-commands.h"
9 #include "sieve-binary.h"
10 #include "sieve-generator.h"
11 #include "sieve-interpreter.h"
12 #include "sieve-dump.h"
13
14 #include "testsuite-common.h"
15 #include "testsuite-substitutions.h"
16
17 /*
18 * Forward declarations
19 */
20
21 void testsuite_opr_substitution_emit
22 (struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub,
23 const char *param);
24
25 /*
26 * Testsuite substitutions
27 */
28
29 /* FIXME: make this extendible */
30
31 enum {
32 TESTSUITE_SUBSTITUTION_FILE,
33 };
34
35 static const struct testsuite_substitution_def testsuite_file_substitution;
36
37 static const struct testsuite_substitution_def *substitutions[] = {
38 &testsuite_file_substitution,
39 };
40
41 static const unsigned int substitutions_count = N_ELEMENTS(substitutions);
42
43 static inline const struct testsuite_substitution_def *
testsuite_substitution_get(unsigned int code)44 testsuite_substitution_get
45 (unsigned int code)
46 {
47 if ( code >= substitutions_count )
48 return NULL;
49
50 return substitutions[code];
51 }
52
testsuite_substitution_create(struct sieve_ast * ast,const char * identifier)53 static const struct testsuite_substitution *testsuite_substitution_create
54 (struct sieve_ast *ast, const char *identifier)
55 {
56 unsigned int i;
57
58 for ( i = 0; i < substitutions_count; i++ ) {
59 if ( strcasecmp(substitutions[i]->obj_def.identifier, identifier) == 0 ) {
60 const struct testsuite_substitution_def *tsub_def = substitutions[i];
61 struct testsuite_substitution *tsub;
62
63 tsub = p_new(sieve_ast_pool(ast), struct testsuite_substitution, 1);
64 tsub->object.def = &tsub_def->obj_def;
65 tsub->object.ext = testsuite_ext;
66 tsub->def = tsub_def;
67
68 return tsub;
69 }
70 }
71
72 return NULL;
73 }
74
75 /*
76 * Substitution argument
77 */
78
79 static bool arg_testsuite_substitution_generate
80 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
81 struct sieve_command *context);
82
83 struct _testsuite_substitution_context {
84 const struct testsuite_substitution *tsub;
85 const char *param;
86 };
87
88 const struct sieve_argument_def testsuite_substitution_argument = {
89 .identifier = "@testsuite-substitution",
90 .generate = arg_testsuite_substitution_generate
91 };
92
testsuite_substitution_argument_create(struct sieve_validator * valdtr ATTR_UNUSED,struct sieve_ast * ast,unsigned int source_line,const char * substitution,const char * param)93 struct sieve_ast_argument *testsuite_substitution_argument_create
94 (struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast *ast,
95 unsigned int source_line, const char *substitution, const char *param)
96 {
97 const struct testsuite_substitution *tsub;
98 struct _testsuite_substitution_context *tsctx;
99 struct sieve_ast_argument *arg;
100 pool_t pool;
101
102 tsub = testsuite_substitution_create(ast, substitution);
103 if ( tsub == NULL )
104 return NULL;
105
106 arg = sieve_ast_argument_create(ast, source_line);
107 arg->type = SAAT_STRING;
108
109 pool = sieve_ast_pool(ast);
110 tsctx = p_new(pool, struct _testsuite_substitution_context, 1);
111 tsctx->tsub = tsub;
112 tsctx->param = p_strdup(pool, param);
113
114 arg->argument = sieve_argument_create
115 (ast, &testsuite_substitution_argument, testsuite_ext, 0);
116 arg->argument->data = (void *) tsctx;
117
118 return arg;
119 }
120
arg_testsuite_substitution_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * context ATTR_UNUSED)121 static bool arg_testsuite_substitution_generate
122 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
123 struct sieve_command *context ATTR_UNUSED)
124 {
125 struct _testsuite_substitution_context *tsctx =
126 (struct _testsuite_substitution_context *) arg->argument->data;
127
128 testsuite_opr_substitution_emit(cgenv->sblock, tsctx->tsub, tsctx->param);
129
130 return TRUE;
131 }
132
133 /*
134 * Substitution operand
135 */
136
137 static bool opr_substitution_dump
138 (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
139 sieve_size_t *address);
140 static int opr_substitution_read_value
141 (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd,
142 sieve_size_t *address, string_t **str);
143
144 const struct sieve_opr_string_interface testsuite_substitution_interface = {
145 opr_substitution_dump,
146 opr_substitution_read_value
147 };
148
149 const struct sieve_operand_def testsuite_substitution_operand = {
150 .name = "test-substitution",
151 .ext_def = &testsuite_extension,
152 .code = TESTSUITE_OPERAND_SUBSTITUTION,
153 .class = &string_class,
154 .interface = &testsuite_substitution_interface
155 };
156
testsuite_opr_substitution_emit(struct sieve_binary_block * sblock,const struct testsuite_substitution * tsub,const char * param)157 void testsuite_opr_substitution_emit
158 (struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub,
159 const char *param)
160 {
161 /* Default variable storage */
162 (void) sieve_operand_emit
163 (sblock, testsuite_ext, &testsuite_substitution_operand);
164 (void) sieve_binary_emit_unsigned(sblock, tsub->object.def->code);
165 (void) sieve_binary_emit_cstring(sblock, param);
166 }
167
opr_substitution_dump(const struct sieve_dumptime_env * denv,const struct sieve_operand * oprnd,sieve_size_t * address)168 static bool opr_substitution_dump
169 (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
170 sieve_size_t *address)
171 {
172 unsigned int code = 0;
173 const struct testsuite_substitution_def *tsub;
174 string_t *param;
175
176 if ( !sieve_binary_read_unsigned(denv->sblock, address, &code) )
177 return FALSE;
178
179 tsub = testsuite_substitution_get(code);
180 if ( tsub == NULL )
181 return FALSE;
182
183 if ( !sieve_binary_read_string(denv->sblock, address, ¶m) )
184 return FALSE;
185
186 if ( oprnd->field_name != NULL )
187 sieve_code_dumpf(denv, "%s: TEST_SUBS %%{%s:%s}",
188 oprnd->field_name, tsub->obj_def.identifier, str_c(param));
189 else
190 sieve_code_dumpf(denv, "TEST_SUBS %%{%s:%s}",
191 tsub->obj_def.identifier, str_c(param));
192 return TRUE;
193 }
194
opr_substitution_read_value(const struct sieve_runtime_env * renv,const struct sieve_operand * oprnd ATTR_UNUSED,sieve_size_t * address,string_t ** str_r)195 static int opr_substitution_read_value
196 (const struct sieve_runtime_env *renv,
197 const struct sieve_operand *oprnd ATTR_UNUSED, sieve_size_t *address,
198 string_t **str_r)
199 {
200 const struct testsuite_substitution_def *tsub;
201 unsigned int code = 0;
202 string_t *param;
203
204 if ( !sieve_binary_read_unsigned(renv->sblock, address, &code) )
205 return SIEVE_EXEC_BIN_CORRUPT;
206
207 tsub = testsuite_substitution_get(code);
208 if ( tsub == NULL )
209 return SIEVE_EXEC_FAILURE;
210
211 /* Parameter str can be NULL if we are requested to only skip and not
212 * actually read the argument.
213 */
214 if ( str_r == NULL ) {
215 if ( !sieve_binary_read_string(renv->sblock, address, NULL) )
216 return SIEVE_EXEC_BIN_CORRUPT;
217
218 return SIEVE_EXEC_OK;
219 }
220
221 if ( !sieve_binary_read_string(renv->sblock, address, ¶m) )
222 return SIEVE_EXEC_BIN_CORRUPT;
223
224 if ( !tsub->get_value(str_c(param), str_r) )
225 return SIEVE_EXEC_FAILURE;
226
227 return SIEVE_EXEC_OK;
228 }
229
230 /*
231 * Testsuite substitution definitions
232 */
233
234 static bool testsuite_file_substitution_get_value
235 (const char *param, string_t **result);
236
237 static const struct testsuite_substitution_def
238 testsuite_file_substitution = {
239 SIEVE_OBJECT("file",
240 &testsuite_substitution_operand,
241 TESTSUITE_SUBSTITUTION_FILE),
242 .get_value = testsuite_file_substitution_get_value
243 };
244
testsuite_file_substitution_get_value(const char * param,string_t ** result)245 static bool testsuite_file_substitution_get_value
246 (const char *param, string_t **result)
247 {
248 *result = t_str_new(256);
249
250 str_printfa(*result, "[FILE: %s]", param);
251 return TRUE;
252 }
253
254