/src/pigeonhole/src/lib-sieve/plugins/include/ext-include-variables.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str-sanitize.h" |
5 | | |
6 | | #include "sieve-common.h" |
7 | | #include "sieve-error.h" |
8 | | #include "sieve-script.h" |
9 | | #include "sieve-ast.h" |
10 | | #include "sieve-binary.h" |
11 | | #include "sieve-commands.h" |
12 | | #include "sieve-validator.h" |
13 | | #include "sieve-generator.h" |
14 | | #include "sieve-interpreter.h" |
15 | | #include "sieve-dump.h" |
16 | | |
17 | | #include "sieve-ext-variables.h" |
18 | | |
19 | | #include "ext-include-common.h" |
20 | | #include "ext-include-binary.h" |
21 | | #include "ext-include-variables.h" |
22 | | |
23 | | /* |
24 | | * Variable import-export |
25 | | */ |
26 | | |
27 | | struct sieve_variable * |
28 | | ext_include_variable_import_global(struct sieve_validator *valdtr, |
29 | | struct sieve_command *cmd, |
30 | | const char *variable) |
31 | 0 | { |
32 | 0 | const struct sieve_extension *this_ext = cmd->ext; |
33 | 0 | struct sieve_ast *ast = cmd->ast_node->ast; |
34 | 0 | struct ext_include_ast_context *ctx = |
35 | 0 | ext_include_get_ast_context(this_ext, ast); |
36 | 0 | struct ext_include_context *extctx = ext_include_get_context(this_ext); |
37 | 0 | struct sieve_variable_scope *local_scope; |
38 | 0 | struct sieve_variable_scope *global_scope = ctx->global_vars; |
39 | 0 | struct sieve_variable *global_var = NULL, *local_var; |
40 | | |
41 | | /* Sanity safeguard */ |
42 | 0 | i_assert (ctx->global_vars != NULL); |
43 | | |
44 | 0 | if (!sieve_variable_identifier_is_valid(variable)) { |
45 | 0 | sieve_command_validate_error( |
46 | 0 | valdtr, cmd, "invalid variable identifier '%s'", |
47 | 0 | str_sanitize(variable,80)); |
48 | 0 | return NULL; |
49 | 0 | } |
50 | | |
51 | | /* Get/Declare the variable in the global scope */ |
52 | 0 | global_var = sieve_variable_scope_declare(global_scope, variable); |
53 | | |
54 | | /* Check whether scope is over its size limit */ |
55 | 0 | if (global_var == NULL) { |
56 | 0 | sieve_command_validate_error( |
57 | 0 | valdtr, cmd, |
58 | 0 | "declaration of new global variable '%s' exceeds the limit " |
59 | 0 | "(max variables: %u)", variable, |
60 | 0 | sieve_variables_get_max_scope_count(extctx->var_ext)); |
61 | 0 | return NULL; |
62 | 0 | } |
63 | | |
64 | | /* Import the global variable into the local script scope */ |
65 | 0 | local_scope = sieve_ext_variables_get_local_scope( |
66 | 0 | extctx->var_ext, valdtr); |
67 | |
|
68 | 0 | local_var = sieve_variable_scope_get_variable(local_scope, variable); |
69 | 0 | if (local_var != NULL && local_var->ext != this_ext) { |
70 | | /* FIXME: indicate location of conflicting set statement */ |
71 | 0 | sieve_command_validate_error( |
72 | 0 | valdtr, cmd, |
73 | 0 | "declaration of new global variable '%s' " |
74 | 0 | "conflicts with earlier local use", variable); |
75 | 0 | return NULL; |
76 | 0 | } |
77 | | |
78 | 0 | return sieve_variable_scope_import(local_scope, global_var); |
79 | 0 | } |
80 | | |
81 | | /* |
82 | | * Binary symbol table |
83 | | */ |
84 | | |
85 | | bool ext_include_variables_save(struct sieve_binary_block *sblock, |
86 | | struct sieve_variable_scope_binary *global_vars, |
87 | | enum sieve_error *error_code_r ATTR_UNUSED) |
88 | 0 | { |
89 | 0 | struct sieve_variable_scope *global_scope = |
90 | 0 | sieve_variable_scope_binary_get(global_vars); |
91 | 0 | unsigned int count = sieve_variable_scope_size(global_scope); |
92 | 0 | sieve_size_t jump; |
93 | |
|
94 | 0 | sieve_binary_emit_unsigned(sblock, count); |
95 | |
|
96 | 0 | jump = sieve_binary_emit_offset(sblock, 0); |
97 | |
|
98 | 0 | if (count > 0) { |
99 | 0 | unsigned int size, i; |
100 | 0 | struct sieve_variable *const *vars = |
101 | 0 | sieve_variable_scope_get_variables(global_scope, &size); |
102 | |
|
103 | 0 | for (i = 0; i < size; i++) { |
104 | 0 | sieve_binary_emit_cstring(sblock, vars[i]->identifier); |
105 | 0 | } |
106 | 0 | } |
107 | |
|
108 | 0 | sieve_binary_resolve_offset(sblock, jump); |
109 | |
|
110 | 0 | return TRUE; |
111 | 0 | } |
112 | | |
113 | | bool ext_include_variables_load( |
114 | | const struct sieve_extension *this_ext, |
115 | | struct sieve_binary_block *sblock, sieve_size_t *offset, |
116 | | struct sieve_variable_scope_binary **global_vars_r) |
117 | 0 | { |
118 | 0 | struct ext_include_context *extctx = ext_include_get_context(this_ext); |
119 | | |
120 | | /* Sanity assert */ |
121 | 0 | i_assert(*global_vars_r == NULL); |
122 | | |
123 | 0 | *global_vars_r = sieve_variable_scope_binary_read( |
124 | 0 | this_ext->svinst, extctx->var_ext, this_ext, sblock, offset); |
125 | |
|
126 | 0 | return (*global_vars_r != NULL); |
127 | 0 | } |
128 | | |
129 | | bool ext_include_variables_dump(struct sieve_dumptime_env *denv, |
130 | | struct sieve_variable_scope_binary *global_vars) |
131 | 0 | { |
132 | 0 | struct sieve_variable_scope *global_scope = |
133 | 0 | sieve_variable_scope_binary_get(global_vars); |
134 | 0 | unsigned int size; |
135 | 0 | struct sieve_variable *const *vars; |
136 | |
|
137 | 0 | i_assert(global_scope != NULL); |
138 | | |
139 | 0 | vars = sieve_variable_scope_get_variables(global_scope, &size); |
140 | |
|
141 | 0 | if (size > 0) { |
142 | 0 | unsigned int i; |
143 | |
|
144 | 0 | sieve_binary_dump_sectionf(denv, "Global variables"); |
145 | |
|
146 | 0 | for (i = 0; i < size; i++) { |
147 | 0 | sieve_binary_dumpf(denv, "%3d: '%s' \n", |
148 | 0 | i, vars[i]->identifier); |
149 | 0 | } |
150 | 0 | } |
151 | 0 | return TRUE; |
152 | 0 | } |
153 | | |
154 | | /* |
155 | | * Global variables namespace |
156 | | */ |
157 | | |
158 | | static bool |
159 | | vnspc_global_variables_validate(struct sieve_validator *valdtr, |
160 | | const struct sieve_variables_namespace *nspc, |
161 | | struct sieve_ast_argument *arg, |
162 | | struct sieve_command *cmd, |
163 | | ARRAY_TYPE(sieve_variable_name) *var_name, |
164 | | void **var_data, bool assignment); |
165 | | static bool |
166 | | vnspc_global_variables_generate(const struct sieve_codegen_env *cgenv, |
167 | | const struct sieve_variables_namespace *nspc, |
168 | | struct sieve_ast_argument *arg, |
169 | | struct sieve_command *cmd, void *var_data); |
170 | | |
171 | | static const struct sieve_variables_namespace_def |
172 | | global_variables_namespace = { |
173 | | SIEVE_OBJECT("global", NULL, 0), |
174 | | .validate = vnspc_global_variables_validate, |
175 | | .generate = vnspc_global_variables_generate |
176 | | }; |
177 | | |
178 | | static bool |
179 | | vnspc_global_variables_validate(struct sieve_validator *valdtr, |
180 | | const struct sieve_variables_namespace *nspc, |
181 | | struct sieve_ast_argument *arg, |
182 | | struct sieve_command *cmd ATTR_UNUSED, |
183 | | ARRAY_TYPE(sieve_variable_name) *var_name, |
184 | | void **var_data, bool assignment ATTR_UNUSED) |
185 | 0 | { |
186 | 0 | const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc); |
187 | 0 | struct sieve_ast *ast = arg->ast; |
188 | 0 | struct ext_include_context *extctx = ext_include_get_context(this_ext); |
189 | 0 | struct ext_include_ast_context *ctx = |
190 | 0 | ext_include_get_ast_context(this_ext, ast); |
191 | 0 | struct sieve_variable *var = NULL; |
192 | 0 | const struct sieve_variable_name *name_element; |
193 | 0 | const char *variable; |
194 | | |
195 | | /* Sanity safeguard */ |
196 | 0 | i_assert (ctx->global_vars != NULL); |
197 | | |
198 | | /* Check variable name */ |
199 | | |
200 | 0 | if (array_count(var_name) != 2) { |
201 | 0 | sieve_argument_validate_error( |
202 | 0 | valdtr, arg, |
203 | 0 | "invalid variable name within global namespace: " |
204 | 0 | "encountered sub-namespace"); |
205 | 0 | return FALSE; |
206 | 0 | } |
207 | | |
208 | 0 | name_element = array_idx(var_name, 1); |
209 | 0 | if (name_element->num_variable >= 0) { |
210 | 0 | sieve_argument_validate_error( |
211 | 0 | valdtr, arg, |
212 | 0 | "invalid variable name within global namespace: " |
213 | 0 | "encountered numeric variable name"); |
214 | 0 | return FALSE; |
215 | 0 | } |
216 | | |
217 | 0 | variable = str_c(name_element->identifier); |
218 | | |
219 | | /* Get/Declare the variable in the global scope */ |
220 | |
|
221 | 0 | var = sieve_variable_scope_declare(ctx->global_vars, variable); |
222 | 0 | if (var == NULL) { |
223 | 0 | sieve_argument_validate_error( |
224 | 0 | valdtr, arg, |
225 | 0 | "(implicit) declaration of new global variable '%s' " |
226 | 0 | "exceeds the limit (max variables: %u)", variable, |
227 | 0 | sieve_variables_get_max_scope_count(extctx->var_ext)); |
228 | 0 | return FALSE; |
229 | 0 | } |
230 | | |
231 | 0 | *var_data = var; |
232 | 0 | return TRUE; |
233 | 0 | } |
234 | | |
235 | | bool vnspc_global_variables_generate( |
236 | | const struct sieve_codegen_env *cgenv, |
237 | | const struct sieve_variables_namespace *nspc, |
238 | | struct sieve_ast_argument *arg ATTR_UNUSED, |
239 | | struct sieve_command *cmd ATTR_UNUSED, void *var_data) |
240 | 0 | { |
241 | 0 | const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc); |
242 | 0 | struct ext_include_context *extctx = ext_include_get_context(this_ext); |
243 | 0 | struct sieve_variable *var = (struct sieve_variable *)var_data; |
244 | |
|
245 | 0 | sieve_variables_opr_variable_emit(cgenv->sblock, extctx->var_ext, var); |
246 | 0 | return TRUE; |
247 | 0 | } |
248 | | |
249 | | void ext_include_variables_global_namespace_init( |
250 | | const struct sieve_extension *this_ext, struct sieve_validator *valdtr) |
251 | 0 | { |
252 | 0 | struct ext_include_context *extctx = ext_include_get_context(this_ext); |
253 | |
|
254 | 0 | sieve_variables_namespace_register(extctx->var_ext, valdtr, this_ext, |
255 | 0 | &global_variables_namespace); |
256 | 0 | } |