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