1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
8
#include "sieve-common.h"
9
#include "sieve-extensions.h"
11
#include "sieve-code.h"
12
#include "sieve-ast.h"
13
#include "sieve-commands.h"
14
#include "sieve-binary.h"
16
#include "sieve-validator.h"
17
#include "sieve-generator.h"
18
#include "sieve-interpreter.h"
19
#include "sieve-dump.h"
21
#include "ext-variables-common.h"
22
#include "ext-variables-modifiers.h"
28
* set [MODIFIER] <name: string> <value: string>
31
static bool cmd_set_registered
32
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg);
33
static bool cmd_set_pre_validate
34
(struct sieve_validator *validator, struct sieve_command_context *cmd);
35
static bool cmd_set_validate
36
(struct sieve_validator *validator, struct sieve_command_context *cmd);
37
static bool cmd_set_generate
38
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx);
40
const struct sieve_command cmd_set = {
55
static bool cmd_set_operation_dump
56
(const struct sieve_operation *op,
57
const struct sieve_dumptime_env *denv, sieve_size_t *address);
58
static int cmd_set_operation_execute
59
(const struct sieve_operation *op,
60
const struct sieve_runtime_env *renv, sieve_size_t *address);
62
const struct sieve_operation cmd_set_operation = {
65
EXT_VARIABLES_OPERATION_SET,
66
cmd_set_operation_dump,
67
cmd_set_operation_execute
74
struct cmd_set_context {
75
ARRAY_DEFINE(modifiers, const struct sieve_variables_modifier *);
82
* ":lower" / ":upper" / ":lowerfirst" / ":upperfirst" /
83
* ":quotewildcard" / ":length"
86
/* Forward declarations */
88
static bool tag_modifier_is_instance_of
89
(struct sieve_validator *validator, struct sieve_command_context *cmdctx,
90
struct sieve_ast_argument *arg);
91
static bool tag_modifier_validate
92
(struct sieve_validator *validator, struct sieve_ast_argument **arg,
93
struct sieve_command_context *cmd);
95
/* Modifier tag object */
97
const struct sieve_argument modifier_tag = {
99
tag_modifier_is_instance_of,
101
tag_modifier_validate,
105
/* Modifier tag implementation */
107
static bool tag_modifier_is_instance_of
108
(struct sieve_validator *validator ATTR_UNUSED,
109
struct sieve_command_context *cmdctx ATTR_UNUSED,
110
struct sieve_ast_argument *arg)
112
const struct sieve_variables_modifier *modf = ext_variables_modifier_find
113
(validator, sieve_ast_argument_tag(arg));
115
arg->context = (void *) modf;
117
return ( modf != NULL );
120
static bool tag_modifier_validate
121
(struct sieve_validator *validator, struct sieve_ast_argument **arg,
122
struct sieve_command_context *cmd)
126
const struct sieve_variables_modifier *modf =
127
(const struct sieve_variables_modifier *) (*arg)->context;
128
struct cmd_set_context *sctx = (struct cmd_set_context *) cmd->data;
131
for ( i = 0; i < array_count(&sctx->modifiers) && !inserted; i++ ) {
132
const struct sieve_variables_modifier * const *smdf =
133
array_idx(&sctx->modifiers, i);
135
if ( (*smdf)->precedence == modf->precedence ) {
136
sieve_argument_validate_error(validator, *arg,
137
"modifiers :%s and :%s specified for the set command conflict "
138
"having equal precedence",
139
(*smdf)->object.identifier, modf->object.identifier);
143
if ( (*smdf)->precedence < modf->precedence ) {
144
array_insert(&sctx->modifiers, i, &modf, 1);
150
array_append(&sctx->modifiers, &modf, 1);
152
/* Added to modifier list; self-destruct to prevent duplicate generation */
153
*arg = sieve_ast_arguments_detach(*arg, 1);
158
/* Command registration */
160
static bool cmd_set_registered
161
(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg)
163
sieve_validator_register_tag(validator, cmd_reg, &modifier_tag, 0);
172
static bool cmd_set_pre_validate
173
(struct sieve_validator *validator ATTR_UNUSED,
174
struct sieve_command_context *cmd)
176
pool_t pool = sieve_command_pool(cmd);
177
struct cmd_set_context *sctx = p_new(pool, struct cmd_set_context, 1);
179
/* Create an array for the sorted list of modifiers */
180
p_array_init(&sctx->modifiers, pool, 2);
182
cmd->data = (void *) sctx;
187
static bool cmd_set_validate(struct sieve_validator *validator,
188
struct sieve_command_context *cmd)
190
struct sieve_ast_argument *arg = cmd->first_positional;
192
if ( !sieve_validate_positional_argument
193
(validator, cmd, arg, "name", 1, SAAT_STRING) ) {
197
if ( !sieve_variable_argument_activate(validator, cmd, arg, TRUE) ) {
201
arg = sieve_ast_argument_next(arg);
203
if ( !sieve_validate_positional_argument
204
(validator, cmd, arg, "value", 2, SAAT_STRING) ) {
208
return sieve_validator_argument_activate(validator, cmd, arg, FALSE);
215
static bool cmd_set_generate
216
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx)
218
struct sieve_binary *sbin = cgenv->sbin;
219
struct cmd_set_context *sctx = (struct cmd_set_context *) ctx->data;
222
sieve_operation_emit_code(sbin, &cmd_set_operation);
224
/* Generate arguments */
225
if ( !sieve_generate_arguments(cgenv, ctx, NULL) )
228
/* Generate modifiers (already sorted during validation) */
229
sieve_binary_emit_byte(sbin, array_count(&sctx->modifiers));
230
for ( i = 0; i < array_count(&sctx->modifiers); i++ ) {
231
const struct sieve_variables_modifier * const * modf =
232
array_idx(&sctx->modifiers, i);
234
ext_variables_opr_modifier_emit(sbin, *modf);
244
static bool cmd_set_operation_dump
245
(const struct sieve_operation *op ATTR_UNUSED,
246
const struct sieve_dumptime_env *denv, sieve_size_t *address)
248
unsigned int mdfs, i;
250
sieve_code_dumpf(denv, "SET");
251
sieve_code_descend(denv);
253
/* Print both variable name and string value */
254
if ( !sieve_opr_string_dump(denv, address, "variable") ||
255
!sieve_opr_string_dump(denv, address, "value") )
258
/* Read the number of applied modifiers we need to read */
259
if ( !sieve_binary_read_byte(denv->sbin, address, &mdfs) )
262
/* Print all modifiers (sorted during code generation already) */
263
for ( i = 0; i < mdfs; i++ ) {
264
if ( !ext_variables_opr_modifier_dump(denv, address) )
275
static int cmd_set_operation_execute
276
(const struct sieve_operation *op ATTR_UNUSED,
277
const struct sieve_runtime_env *renv, sieve_size_t *address)
279
struct sieve_variable_storage *storage;
280
unsigned int var_index, mdfs, i;
282
int ret = SIEVE_EXEC_OK;
285
* Read the normal operands
288
/* Read the variable */
289
if ( !sieve_variable_operand_read
290
(renv, address, &storage, &var_index) ) {
291
sieve_runtime_trace_error(renv, "invalid variable operand");
292
return SIEVE_EXEC_BIN_CORRUPT;
295
/* Read the raw string value */
296
if ( !sieve_opr_string_read(renv, address, &value) ) {
297
sieve_runtime_trace_error(renv, "invalid string operand");
298
return SIEVE_EXEC_BIN_CORRUPT;
301
/* Read the number of modifiers used */
302
if ( !sieve_binary_read_byte(renv->sbin, address, &mdfs) ) {
303
sieve_runtime_trace_error(renv, "invalid modifier count");
304
return SIEVE_EXEC_BIN_CORRUPT;
308
* Determine and assign the value
311
sieve_runtime_trace(renv, "SET action");
313
/* Hold value within limits */
314
if ( str_len(value) > SIEVE_VARIABLES_MAX_VARIABLE_SIZE )
315
str_truncate(value, SIEVE_VARIABLES_MAX_VARIABLE_SIZE);
318
/* Apply modifiers if necessary (sorted during code generation already) */
319
if ( str_len(value) > 0 ) {
320
for ( i = 0; i < mdfs; i++ ) {
322
const struct sieve_variables_modifier *modf =
323
ext_variables_opr_modifier_read(renv, address);
325
if ( modf == NULL ) {
328
sieve_runtime_trace_error(renv, "invalid modifier operand");
329
ret = SIEVE_EXEC_BIN_CORRUPT;
333
if ( modf->modify != NULL ) {
334
if ( !modf->modify(value, &new_value) ) {
336
ret = SIEVE_EXEC_FAILURE;
344
/* Hold value within limits */
345
if ( str_len(value) > SIEVE_VARIABLES_MAX_VARIABLE_SIZE )
346
str_truncate(value, SIEVE_VARIABLES_MAX_VARIABLE_SIZE);
351
/* Actually assign the value if all is well */
352
if ( value != NULL ) {
353
if ( !sieve_variable_assign(storage, var_index, value) )
354
ret = SIEVE_EXEC_BIN_CORRUPT;
361
return ( value != NULL );