1
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
6
#include "sieve-common.h"
7
#include "sieve-code.h"
8
#include "sieve-commands.h"
9
#include "sieve-validator.h"
10
#include "sieve-generator.h"
11
#include "sieve-binary.h"
12
#include "sieve-interpreter.h"
13
#include "sieve-dump.h"
15
#include "sieve-ext-variables.h"
17
#include "ext-include-common.h"
18
#include "ext-include-binary.h"
19
#include "ext-include-variables.h"
25
static bool cmd_global_validate
26
(struct sieve_validator *validator, struct sieve_command_context *cmd);
27
static bool cmd_global_generate
28
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd);
30
const struct sieve_command cmd_global = {
48
const struct sieve_command cmd_import = {
63
const struct sieve_command cmd_export = {
77
static bool opc_global_dump
78
(const struct sieve_operation *op,
79
const struct sieve_dumptime_env *denv, sieve_size_t *address);
80
static int opc_global_execute
81
(const struct sieve_operation *op,
82
const struct sieve_runtime_env *renv, sieve_size_t *address);
84
/* Global operation */
86
const struct sieve_operation global_operation = {
89
EXT_INCLUDE_OPERATION_GLOBAL,
98
static bool cmd_global_validate
99
(struct sieve_validator *validator, struct sieve_command_context *cmd)
101
struct sieve_ast_argument *arg = cmd->first_positional;
102
struct sieve_command_context *prev_context =
103
sieve_command_prev_context(cmd);
105
/* Check valid command placement */
106
if ( !sieve_command_is_toplevel(cmd) ||
107
( !sieve_command_is_first(cmd) && prev_context != NULL &&
108
prev_context->command != &cmd_require ) ) {
110
if ( cmd->command == &cmd_global ) {
111
if ( prev_context->command != &cmd_global ) {
112
sieve_command_validate_error(validator, cmd,
113
"a global command can only be placed at top level "
114
"at the beginning of the file after any require or other global commands");
118
if ( prev_context->command != &cmd_import && prev_context->command != &cmd_export ) {
119
sieve_command_validate_error(validator, cmd,
120
"the DEPRICATED %s command can only be placed at top level "
121
"at the beginning of the file after any require or import/export commands",
122
cmd->command->identifier);
128
/* Check for use of variables extension */
129
if ( !sieve_ext_variables_is_active(validator) ) {
130
sieve_command_validate_error(validator, cmd,
131
"%s command requires that variables extension is active",
132
cmd->command->identifier);
136
/* Register global variable */
137
if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
139
const char *identifier = sieve_ast_argument_strc(arg);
140
struct sieve_variable *var;
142
if ( (var=ext_include_variable_import_global
143
(validator, cmd, identifier)) == NULL )
146
arg->context = (void *) var;
148
} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
150
struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
152
while ( stritem != NULL ) {
153
const char *identifier = sieve_ast_argument_strc(stritem);
154
struct sieve_variable *var;
156
if ( (var=ext_include_variable_import_global
157
(validator, cmd, identifier)) == NULL )
160
stritem->context = (void *) var;
162
stritem = sieve_ast_strlist_next(stritem);
166
sieve_argument_validate_error(validator, arg,
167
"the %s command accepts a single string or string list argument, "
168
"but %s was found", cmd->command->identifier,
169
sieve_ast_argument_name(arg));
173
/* Join global commands with predecessors if possible */
174
if ( prev_context->command == cmd->command ) {
175
/* Join this command's string list with the previous one */
176
prev_context->first_positional = sieve_ast_stringlist_join
177
(prev_context->first_positional, cmd->first_positional);
179
if ( prev_context->first_positional == NULL ) {
180
/* Not going to happen unless MAXINT stringlist items are specified */
181
sieve_command_validate_error(validator, cmd,
182
"compiler reached AST limit (script too complex)");
186
/* Detach this command node */
187
sieve_ast_node_detach(cmd->ast_node);
197
static bool cmd_global_generate
198
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd)
200
struct sieve_ast_argument *arg = cmd->first_positional;
202
sieve_operation_emit_code(cgenv->sbin, &global_operation);
204
if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
206
struct sieve_variable *var = (struct sieve_variable *) arg->context;
208
(void)sieve_binary_emit_unsigned(cgenv->sbin, 1);
209
(void)sieve_binary_emit_unsigned(cgenv->sbin, var->index);
211
} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
213
struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
215
(void)sieve_binary_emit_unsigned(cgenv->sbin, sieve_ast_strlist_count(arg));
217
while ( stritem != NULL ) {
218
struct sieve_variable *var = (struct sieve_variable *) stritem->context;
220
(void)sieve_binary_emit_unsigned(cgenv->sbin, var->index);
222
stritem = sieve_ast_strlist_next(stritem);
235
static bool opc_global_dump
236
(const struct sieve_operation *op ATTR_UNUSED,
237
const struct sieve_dumptime_env *denv, sieve_size_t *address)
239
unsigned int count, i, var_count;
240
struct sieve_variable_scope *scope;
241
struct sieve_variable * const *vars;
243
if ( !sieve_binary_read_unsigned(denv->sbin, address, &count) )
246
sieve_code_dumpf(denv, "GLOBAL (count: %u):", count);
248
scope = ext_include_binary_get_global_scope(denv->sbin);
249
vars = sieve_variable_scope_get_variables(scope, &var_count);
251
sieve_code_descend(denv);
253
for ( i = 0; i < count; i++ ) {
256
sieve_code_mark(denv);
257
if ( !sieve_binary_read_unsigned(denv->sbin, address, &index) ||
261
sieve_code_dumpf(denv, "VAR[%d]: '%s'", index, vars[index]->identifier);
271
static int opc_global_execute
272
(const struct sieve_operation *op ATTR_UNUSED,
273
const struct sieve_runtime_env *renv, sieve_size_t *address)
275
struct sieve_variable_scope *scope;
276
struct sieve_variable_storage *storage;
277
struct sieve_variable * const *vars;
278
unsigned int var_count, count, i;
280
if ( !sieve_binary_read_unsigned(renv->sbin, address, &count) ) {
281
sieve_runtime_trace_error(renv, "invalid count operand");
282
return SIEVE_EXEC_BIN_CORRUPT;
285
scope = ext_include_binary_get_global_scope(renv->sbin);
286
vars = sieve_variable_scope_get_variables(scope, &var_count);
287
storage = ext_include_interpreter_get_global_variables(renv->interp);
289
for ( i = 0; i < count; i++ ) {
292
if ( !sieve_binary_read_unsigned(renv->sbin, address, &index) ) {
293
sieve_runtime_trace_error(renv, "invalid global variable operand");
294
return SIEVE_EXEC_BIN_CORRUPT;
297
if ( index >= var_count ) {
298
sieve_runtime_trace_error(renv, "invalid global variable index (%u > %u)",
300
return SIEVE_EXEC_BIN_CORRUPT;
303
/* Make sure variable is initialized (export) */
304
(void)sieve_variable_get_modifiable(storage, index, NULL);
307
return SIEVE_EXEC_OK;