1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "sieve-common.h"
5 #include "sieve-error.h"
6 #include "sieve-script.h"
7 #include "sieve-commands.h"
8 #include "sieve-actions.h"
9 #include "sieve-comparators.h"
10 #include "sieve-match-types.h"
11 #include "sieve-validator.h"
12 #include "sieve-generator.h"
13 #include "sieve-interpreter.h"
14 #include "sieve-code.h"
15 #include "sieve-binary.h"
16 #include "sieve-result.h"
17 #include "sieve-dump.h"
18 #include "sieve-match.h"
19
20 #include "testsuite-common.h"
21 #include "testsuite-result.h"
22
23 /*
24 * test_result_action command
25 *
26 * Syntax:
27 * test_result_action [MATCH-TYPE] [COMPARATOR] [:index number]
28 * <key-list: string-list>
29 */
30
31 static bool tst_test_result_action_registered
32 (struct sieve_validator *validator, const struct sieve_extension *ext,
33 struct sieve_command_registration *cmd_reg);
34 static bool tst_test_result_action_validate
35 (struct sieve_validator *validator, struct sieve_command *cmd);
36 static bool tst_test_result_action_generate
37 (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
38
39 const struct sieve_command_def tst_test_result_action = {
40 .identifier = "test_result_action",
41 .type = SCT_TEST,
42 .positional_args = 1,
43 .subtests = 0,
44 .block_allowed = FALSE,
45 .block_required = FALSE,
46 .registered = tst_test_result_action_registered,
47 .validate = tst_test_result_action_validate,
48 .generate = tst_test_result_action_generate
49 };
50
51 /*
52 * Operation
53 */
54
55 static bool tst_test_result_action_operation_dump
56 (const struct sieve_dumptime_env *denv, sieve_size_t *address);
57 static int tst_test_result_action_operation_execute
58 (const struct sieve_runtime_env *renv, sieve_size_t *address);
59
60 const struct sieve_operation_def test_result_action_operation = {
61 .mnemonic = "TEST_RESULT_ACTION",
62 .ext_def = &testsuite_extension,
63 .code = TESTSUITE_OPERATION_TEST_RESULT_ACTION,
64 .dump = tst_test_result_action_operation_dump,
65 .execute = tst_test_result_action_operation_execute
66 };
67
68 /*
69 * Tagged arguments
70 */
71
72 /* FIXME: merge this with the test_error version of this tag */
73
74 static bool tst_test_result_action_validate_index_tag
75 (struct sieve_validator *validator, struct sieve_ast_argument **arg,
76 struct sieve_command *cmd);
77
78 static const struct sieve_argument_def test_result_action_index_tag = {
79 .identifier = "index",
80 .validate = tst_test_result_action_validate_index_tag
81 };
82
83 enum tst_test_result_action_optional {
84 OPT_INDEX = SIEVE_MATCH_OPT_LAST,
85 };
86
87 /*
88 * Argument implementation
89 */
90
tst_test_result_action_validate_index_tag(struct sieve_validator * validator,struct sieve_ast_argument ** arg,struct sieve_command * cmd)91 static bool tst_test_result_action_validate_index_tag
92 (struct sieve_validator *validator, struct sieve_ast_argument **arg,
93 struct sieve_command *cmd)
94 {
95 struct sieve_ast_argument *tag = *arg;
96
97 /* Detach the tag itself */
98 *arg = sieve_ast_arguments_detach(*arg,1);
99
100 /* Check syntax:
101 * :index number
102 */
103 if ( !sieve_validate_tag_parameter
104 (validator, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) ) {
105 return FALSE;
106 }
107
108 /* Skip parameter */
109 *arg = sieve_ast_argument_next(*arg);
110 return TRUE;
111 }
112
113
114 /*
115 * Command registration
116 */
117
tst_test_result_action_registered(struct sieve_validator * validator,const struct sieve_extension * ext,struct sieve_command_registration * cmd_reg)118 static bool tst_test_result_action_registered
119 (struct sieve_validator *validator, const struct sieve_extension *ext,
120 struct sieve_command_registration *cmd_reg)
121 {
122 /* The order of these is not significant */
123 sieve_comparators_link_tag(validator, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
124 sieve_match_types_link_tags(validator, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
125
126 sieve_validator_register_tag
127 (validator, cmd_reg, ext, &test_result_action_index_tag, OPT_INDEX);
128
129 return TRUE;
130 }
131
132 /*
133 * Validation
134 */
135
tst_test_result_action_validate(struct sieve_validator * valdtr ATTR_UNUSED,struct sieve_command * tst)136 static bool tst_test_result_action_validate
137 (struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *tst)
138 {
139 struct sieve_ast_argument *arg = tst->first_positional;
140 struct sieve_comparator cmp_default =
141 SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
142 struct sieve_match_type mcht_default =
143 SIEVE_COMPARATOR_DEFAULT(is_match_type);
144
145 if ( !sieve_validate_positional_argument
146 (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
147 return FALSE;
148 }
149
150 if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
151 return FALSE;
152
153 /* Validate the key argument to a specified match type */
154 return sieve_match_type_validate
155 (valdtr, tst, arg, &mcht_default, &cmp_default);
156 }
157
158 /*
159 * Code generation
160 */
161
tst_test_result_action_generate(const struct sieve_codegen_env * cgenv,struct sieve_command * tst)162 static bool tst_test_result_action_generate
163 (const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
164 {
165 sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_action_operation);
166
167 /* Generate arguments */
168 return sieve_generate_arguments(cgenv, tst, NULL);
169 }
170
171 /*
172 * Code dump
173 */
174
tst_test_result_action_operation_dump(const struct sieve_dumptime_env * denv,sieve_size_t * address)175 static bool tst_test_result_action_operation_dump
176 (const struct sieve_dumptime_env *denv, sieve_size_t *address)
177 {
178 int opt_code = 0;
179
180 sieve_code_dumpf(denv, "TEST_RESULT_ACTION:");
181 sieve_code_descend(denv);
182
183 /* Handle any optional arguments */
184 for (;;) {
185 int opt;
186
187 if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code))
188 < 0 )
189 return FALSE;
190
191 if ( opt == 0 ) break;
192
193 if ( opt_code == OPT_INDEX ) {
194 if ( !sieve_opr_number_dump(denv, address, "index") )
195 return FALSE;
196 } else {
197 return FALSE;
198 }
199 }
200
201 return sieve_opr_stringlist_dump(denv, address, "key list");
202 }
203
204 /*
205 * Intepretation
206 */
207
tst_test_result_action_operation_execute(const struct sieve_runtime_env * renv,sieve_size_t * address)208 static int tst_test_result_action_operation_execute
209 (const struct sieve_runtime_env *renv, sieve_size_t *address)
210 {
211 int opt_code = 0;
212 struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
213 struct sieve_match_type mcht = SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
214 struct sieve_stringlist *value_list, *key_list;
215 int index = 0;
216 int match, ret;
217
218 /*
219 * Read operands
220 */
221
222 /* Read optional operands */
223 for (;;) {
224 sieve_number_t number;
225 int opt;
226
227 if ( (opt=sieve_match_opr_optional_read
228 (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
229 return ret;
230
231 if ( opt == 0 ) break;
232
233 if ( opt_code == OPT_INDEX ) {
234 if ( (ret=sieve_opr_number_read(renv, address, "index", &number)) <= 0 )
235 return ret;
236 index = (int) number;
237 } else {
238 sieve_runtime_trace_error(renv, "invalid optional operand");
239 return SIEVE_EXEC_BIN_CORRUPT;
240 }
241 }
242
243 /* Read key-list */
244 if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list))
245 <= 0 )
246 return ret;
247
248 /*
249 * Perform operation
250 */
251
252 sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
253 "testsuite: test_result_action test; match result name (index: %d)", index);
254
255 /* Create value stringlist */
256 value_list = testsuite_result_stringlist_create(renv, index);
257
258 /* Perform match */
259 if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
260 return ret;
261
262 /* Set test result for subsequent conditional jump */
263 sieve_interpreter_set_test_result(renv->interp, match > 0);
264 return SIEVE_EXEC_OK;
265 }
266
267
268
269