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