/src/pigeonhole/src/testsuite/testsuite-arguments.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str.h" |
5 | | #include "str-sanitize.h" |
6 | | #include "array.h" |
7 | | |
8 | | #include "sieve-common.h" |
9 | | #include "sieve-ast.h" |
10 | | #include "sieve-commands.h" |
11 | | #include "sieve-code.h" |
12 | | #include "sieve-validator.h" |
13 | | #include "sieve-generator.h" |
14 | | #include "sieve-dump.h" |
15 | | |
16 | | #include "testsuite-common.h" |
17 | | #include "testsuite-substitutions.h" |
18 | | #include "testsuite-arguments.h" |
19 | | |
20 | | #include <ctype.h> |
21 | | |
22 | | /* |
23 | | * Testsuite string argument |
24 | | */ |
25 | | |
26 | | static bool |
27 | | arg_testsuite_string_validate(struct sieve_validator *validator, |
28 | | struct sieve_ast_argument **arg, |
29 | | struct sieve_command *context); |
30 | | |
31 | | const struct sieve_argument_def testsuite_string_argument = { |
32 | | .identifier = "@testsuite-string", |
33 | | .validate = arg_testsuite_string_validate, |
34 | | .generate = sieve_arg_catenated_string_generate, |
35 | | }; |
36 | | |
37 | | static bool |
38 | | arg_testsuite_string_validate(struct sieve_validator *valdtr, |
39 | | struct sieve_ast_argument **arg, |
40 | | struct sieve_command *cmd) |
41 | 0 | { |
42 | 0 | enum { ST_NONE, ST_OPEN, ST_SUBSTITUTION, ST_PARAM, ST_CLOSE } state = |
43 | 0 | ST_NONE; |
44 | 0 | pool_t pool = sieve_ast_pool((*arg)->ast); |
45 | 0 | struct sieve_arg_catenated_string *catstr = NULL; |
46 | 0 | string_t *str = sieve_ast_argument_str(*arg); |
47 | 0 | const char *p, *strstart, *substart = NULL; |
48 | 0 | const char *strval = (const char *) str_data(str); |
49 | 0 | const char *strend = strval + str_len(str); |
50 | 0 | bool result = TRUE; |
51 | 0 | string_t *subs_name = t_str_new(256); |
52 | 0 | string_t *subs_param = t_str_new(256); |
53 | |
|
54 | 0 | T_BEGIN { |
55 | | /* Initialize substitution structure */ |
56 | |
|
57 | 0 | p = strval; |
58 | 0 | strstart = p; |
59 | 0 | while (result && p < strend) { |
60 | 0 | switch (state) { |
61 | | /* Nothing found yet */ |
62 | 0 | case ST_NONE: |
63 | 0 | if (*p == '%') { |
64 | 0 | substart = p; |
65 | 0 | state = ST_OPEN; |
66 | 0 | str_truncate(subs_name, 0); |
67 | 0 | str_truncate(subs_param, 0); |
68 | 0 | } |
69 | 0 | p++; |
70 | 0 | break; |
71 | | /* Got '%' */ |
72 | 0 | case ST_OPEN: |
73 | 0 | if (*p == '{') { |
74 | 0 | state = ST_SUBSTITUTION; |
75 | 0 | p++; |
76 | 0 | } else |
77 | 0 | state = ST_NONE; |
78 | 0 | break; |
79 | | |
80 | | /* Got '%{' */ |
81 | 0 | case ST_SUBSTITUTION: |
82 | 0 | state = ST_PARAM; |
83 | |
|
84 | 0 | while (*p != '}' && *p != ':') { |
85 | 0 | if (!i_isalnum(*p)) { |
86 | 0 | state = ST_NONE; |
87 | 0 | break; |
88 | 0 | } |
89 | 0 | str_append_c(subs_name, *p); |
90 | 0 | p++; |
91 | 0 | } |
92 | 0 | break; |
93 | | /* Got '%{name' */ |
94 | 0 | case ST_PARAM: |
95 | 0 | if (*p == ':') { |
96 | 0 | p++; |
97 | 0 | while (*p != '}') { |
98 | 0 | str_append_c(subs_param, *p); |
99 | 0 | p++; |
100 | 0 | } |
101 | 0 | } |
102 | 0 | state = ST_CLOSE; |
103 | 0 | break; |
104 | | /* Finished parsing param, expecting '}' */ |
105 | 0 | case ST_CLOSE: |
106 | 0 | if (*p == '}') { |
107 | 0 | struct sieve_ast_argument *strarg; |
108 | | |
109 | | /* We now know that the substitution is valid */ |
110 | |
|
111 | 0 | if (catstr == NULL) |
112 | 0 | catstr = sieve_arg_catenated_string_create(*arg); |
113 | | |
114 | | /* Add the substring that is before the substitution to the |
115 | | variable-string AST. |
116 | | */ |
117 | 0 | if (substart > strstart) { |
118 | 0 | string_t *newstr = str_new(pool, substart - strstart); |
119 | 0 | str_append_data(newstr, strstart, substart - strstart); |
120 | |
|
121 | 0 | strarg = sieve_ast_argument_string_create_raw( |
122 | 0 | (*arg)->ast, newstr, (*arg)->source_line); |
123 | 0 | sieve_arg_catenated_string_add_element(catstr, strarg); |
124 | | |
125 | | /* Give other substitution extensions a chance to do |
126 | | their work */ |
127 | 0 | if (!sieve_validator_argument_activate_super( |
128 | 0 | valdtr, cmd, strarg, FALSE)) { |
129 | 0 | result = FALSE; |
130 | 0 | break; |
131 | 0 | } |
132 | 0 | } |
133 | | |
134 | 0 | strarg = testsuite_substitution_argument_create( |
135 | 0 | valdtr, (*arg)->ast, (*arg)->source_line, |
136 | 0 | str_c(subs_name), str_c(subs_param)); |
137 | 0 | if (strarg != NULL) |
138 | 0 | sieve_arg_catenated_string_add_element(catstr, strarg); |
139 | 0 | else { |
140 | 0 | sieve_argument_validate_error( |
141 | 0 | valdtr, *arg, |
142 | 0 | "unknown testsuite substitution type '%s'", |
143 | 0 | str_c(subs_name)); |
144 | 0 | } |
145 | |
|
146 | 0 | strstart = p + 1; |
147 | 0 | substart = strstart; |
148 | 0 | p++; |
149 | 0 | } |
150 | | |
151 | | /* Finished, reset for the next substitution */ |
152 | 0 | state = ST_NONE; |
153 | 0 | } |
154 | 0 | } |
155 | 0 | } T_END; |
156 | | |
157 | | /* Bail out early if substitution is invalid */ |
158 | 0 | if (!result) |
159 | 0 | return FALSE; |
160 | | |
161 | | /* Check whether any substitutions were found */ |
162 | 0 | if (catstr == NULL) { |
163 | | /* No substitutions in this string, pass it on to any other |
164 | | substution extension. |
165 | | */ |
166 | 0 | return sieve_validator_argument_activate_super( |
167 | 0 | valdtr, cmd, *arg, TRUE); |
168 | 0 | } |
169 | | |
170 | | /* Add the final substring that comes after the last substitution to the |
171 | | variable-string AST. |
172 | | */ |
173 | 0 | if (strend > strstart) { |
174 | 0 | struct sieve_ast_argument *strarg; |
175 | 0 | string_t *newstr = str_new(pool, strend - strstart); |
176 | 0 | str_append_data(newstr, strstart, strend - strstart); |
177 | |
|
178 | 0 | strarg = sieve_ast_argument_string_create_raw( |
179 | 0 | (*arg)->ast, newstr, (*arg)->source_line); |
180 | 0 | sieve_arg_catenated_string_add_element(catstr, strarg); |
181 | | |
182 | | /* Give other substitution extensions a chance to do their work. |
183 | | */ |
184 | 0 | if (!sieve_validator_argument_activate_super(valdtr, cmd, |
185 | 0 | strarg, FALSE)) |
186 | 0 | return FALSE; |
187 | 0 | } |
188 | 0 | return TRUE; |
189 | 0 | } |