/src/pigeonhole/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c
Line | Count | Source |
1 | | /* Copyright (c) 2015-2018 Pigeonhole authors, see the included COPYING file |
2 | | */ |
3 | | |
4 | | #include "lib.h" |
5 | | #include "str.h" |
6 | | |
7 | | #include "sieve-common.h" |
8 | | #include "sieve-ast.h" |
9 | | #include "sieve-binary.h" |
10 | | #include "sieve-code.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-vnd-environment-common.h" |
20 | | |
21 | | static bool |
22 | | vnspc_vnd_environment_validate(struct sieve_validator *valdtr, |
23 | | const struct sieve_variables_namespace *nspc, |
24 | | struct sieve_ast_argument *arg, |
25 | | struct sieve_command *cmd, |
26 | | ARRAY_TYPE(sieve_variable_name) *var_name, |
27 | | void **var_data, bool assignment); |
28 | | static bool |
29 | | vnspc_vnd_environment_generate(const struct sieve_codegen_env *cgenv, |
30 | | const struct sieve_variables_namespace *nspc, |
31 | | struct sieve_ast_argument *arg, |
32 | | struct sieve_command *cmd, void *var_data); |
33 | | static bool |
34 | | vnspc_vnd_environment_dump_variable( |
35 | | const struct sieve_dumptime_env *denv, |
36 | | const struct sieve_variables_namespace *nspc, |
37 | | const struct sieve_operand *oprnd, sieve_size_t *address); |
38 | | static int |
39 | | vnspc_vnd_environment_read_variable( |
40 | | const struct sieve_runtime_env *renv, |
41 | | const struct sieve_variables_namespace *nspc, |
42 | | const struct sieve_operand *oprnd, |
43 | | sieve_size_t *address, string_t **str_r); |
44 | | |
45 | | static const struct sieve_variables_namespace_def |
46 | | environment_namespace = { |
47 | | SIEVE_OBJECT("env", &environment_namespace_operand, 0), |
48 | | .validate = vnspc_vnd_environment_validate, |
49 | | .generate = vnspc_vnd_environment_generate, |
50 | | .dump_variable = vnspc_vnd_environment_dump_variable, |
51 | | .read_variable = vnspc_vnd_environment_read_variable, |
52 | | }; |
53 | | |
54 | | static bool |
55 | | vnspc_vnd_environment_validate( |
56 | | struct sieve_validator *valdtr, |
57 | | const struct sieve_variables_namespace *nspc ATTR_UNUSED, |
58 | | struct sieve_ast_argument *arg, struct sieve_command *cmd ATTR_UNUSED, |
59 | | ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data, |
60 | | bool assignment) |
61 | 0 | { |
62 | 0 | struct sieve_ast *ast = arg->ast; |
63 | 0 | const struct sieve_variable_name *name_elements; |
64 | 0 | unsigned int i, count; |
65 | 0 | const char *variable; |
66 | 0 | string_t *name; |
67 | | |
68 | | /* Compose environment name from parsed variable name */ |
69 | 0 | name = t_str_new(64); |
70 | 0 | name_elements = array_get(var_name, &count); |
71 | 0 | i_assert(count > 1); |
72 | 0 | for (i = 1; i < count; i++) { |
73 | 0 | if (name_elements[i].num_variable >= 0) { |
74 | 0 | sieve_argument_validate_error( |
75 | 0 | valdtr, arg, "vnd.dovecot.environment: " |
76 | 0 | "invalid variable name within env namespace 'env.%d': " |
77 | 0 | "encountered numeric variable name", |
78 | 0 | name_elements[i].num_variable); |
79 | 0 | return FALSE; |
80 | 0 | } |
81 | 0 | if (str_len(name) > 0) |
82 | 0 | str_append_c(name, '.'); |
83 | 0 | str_append_str(name, name_elements[i].identifier); |
84 | 0 | } |
85 | | |
86 | 0 | variable = str_c(name); |
87 | |
|
88 | 0 | if (assignment) { |
89 | 0 | sieve_argument_validate_error( |
90 | 0 | valdtr, arg, "vnd.dovecot.environment: " |
91 | 0 | "cannot assign to environment variable 'env.%s'", |
92 | 0 | variable); |
93 | 0 | return FALSE; |
94 | 0 | } |
95 | | |
96 | 0 | *var_data = p_strdup(sieve_ast_pool(ast), variable); |
97 | 0 | return TRUE; |
98 | 0 | } |
99 | | |
100 | | static bool |
101 | | vnspc_vnd_environment_generate(const struct sieve_codegen_env *cgenv, |
102 | | const struct sieve_variables_namespace *nspc, |
103 | | struct sieve_ast_argument *arg ATTR_UNUSED, |
104 | | struct sieve_command *cmd ATTR_UNUSED, |
105 | | void *var_data) |
106 | 0 | { |
107 | 0 | const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc); |
108 | 0 | const char *variable = (const char *) var_data; |
109 | 0 | struct ext_vnd_environment_context *extctx; |
110 | |
|
111 | 0 | if (this_ext == NULL) |
112 | 0 | return FALSE; |
113 | | |
114 | 0 | extctx = (struct ext_vnd_environment_context *)this_ext->context; |
115 | |
|
116 | 0 | sieve_variables_opr_namespace_variable_emit( |
117 | 0 | cgenv->sblock, extctx->var_ext, this_ext, |
118 | 0 | &environment_namespace); |
119 | 0 | sieve_binary_emit_cstring(cgenv->sblock, variable); |
120 | 0 | return TRUE; |
121 | 0 | } |
122 | | |
123 | | static bool |
124 | | vnspc_vnd_environment_dump_variable( |
125 | | const struct sieve_dumptime_env *denv, |
126 | | const struct sieve_variables_namespace *nspc ATTR_UNUSED, |
127 | | const struct sieve_operand *oprnd, sieve_size_t *address) |
128 | 0 | { |
129 | 0 | string_t *var_name; |
130 | |
|
131 | 0 | if (!sieve_binary_read_string(denv->sblock, address, &var_name)) |
132 | 0 | return FALSE; |
133 | | |
134 | 0 | if (oprnd->field_name != NULL) { |
135 | 0 | sieve_code_dumpf(denv, "%s: VAR ${env.%s}", |
136 | 0 | oprnd->field_name, str_c(var_name)); |
137 | 0 | } else { |
138 | 0 | sieve_code_dumpf(denv, "VAR ${env.%s}", str_c(var_name)); |
139 | 0 | } |
140 | 0 | return TRUE; |
141 | 0 | } |
142 | | |
143 | | static int |
144 | | vnspc_vnd_environment_read_variable( |
145 | | const struct sieve_runtime_env *renv, |
146 | | const struct sieve_variables_namespace *nspc, |
147 | | const struct sieve_operand *oprnd, sieve_size_t *address, |
148 | | string_t **str_r) |
149 | 0 | { |
150 | 0 | const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc); |
151 | 0 | struct ext_vnd_environment_context *extctx = this_ext->context; |
152 | 0 | string_t *var_name; |
153 | 0 | const char *ext_value; |
154 | |
|
155 | 0 | if (!sieve_binary_read_string(renv->sblock, address, &var_name)) { |
156 | 0 | sieve_runtime_trace_operand_error( |
157 | 0 | renv, oprnd, "environment variable operand corrupt: " |
158 | 0 | "invalid name"); |
159 | 0 | return SIEVE_EXEC_BIN_CORRUPT; |
160 | 0 | } |
161 | | |
162 | 0 | if (str_r != NULL) { |
163 | 0 | const char *vname = str_c(var_name); |
164 | |
|
165 | 0 | ext_value = ext_environment_item_get_value(extctx->env_ext, |
166 | 0 | renv, vname); |
167 | 0 | if (ext_value == NULL && strchr(vname, '_') != NULL) { |
168 | 0 | char *p, *aname; |
169 | | |
170 | | /* Try again with '_' replaced with '-' */ |
171 | 0 | aname = t_strdup_noconst(vname); |
172 | 0 | for (p = aname; *p != '\0'; p++) { |
173 | 0 | if (*p == '_') |
174 | 0 | *p = '-'; |
175 | 0 | } |
176 | 0 | ext_value = ext_environment_item_get_value( |
177 | 0 | extctx->env_ext, renv, aname); |
178 | 0 | } |
179 | |
|
180 | 0 | if (ext_value == NULL) { |
181 | 0 | *str_r = t_str_new_const("", 0); |
182 | 0 | return SIEVE_EXEC_OK; |
183 | 0 | } |
184 | | |
185 | 0 | *str_r = t_str_new_const(ext_value, strlen(ext_value)); |
186 | 0 | } |
187 | 0 | return SIEVE_EXEC_OK; |
188 | 0 | } |
189 | | |
190 | | /* |
191 | | * Namespace registration |
192 | | */ |
193 | | |
194 | | static const struct sieve_extension_objects environment_namespaces = |
195 | | SIEVE_VARIABLES_DEFINE_NAMESPACE(environment_namespace); |
196 | | |
197 | | const struct sieve_operand_def environment_namespace_operand = { |
198 | | .name = "env-namespace", |
199 | | .ext_def = &vnd_environment_extension, |
200 | | .class = &sieve_variables_namespace_operand_class, |
201 | | .interface = &environment_namespaces, |
202 | | }; |
203 | | |
204 | | void ext_environment_variables_init(const struct sieve_extension *this_ext, |
205 | | struct sieve_validator *valdtr) |
206 | 0 | { |
207 | 0 | struct ext_vnd_environment_context *extctx = this_ext->context; |
208 | |
|
209 | 0 | sieve_variables_namespace_register(extctx->var_ext, valdtr, this_ext, |
210 | 0 | &environment_namespace); |
211 | 0 | } |