From f985536f4ef1735c890541e2b35dd35cebdcdd2d Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Mon, 17 Aug 2015 23:41:05 +0200 Subject: [PATCH] lib-sieve: vnd.dovecot.environment extension: Forgot to add several files in previous commit. --- .../vnd.dovecot/environment/Makefile.am | 16 ++ .../environment/ext-vnd-environment-common.h | 40 ++++ .../environment/ext-vnd-environment-items.c | 66 ++++++ .../ext-vnd-environment-variables.c | 207 ++++++++++++++++++ .../environment/ext-vnd-environment.c | 102 +++++++++ .../vnd.dovecot/environment/basic.svtest | 19 ++ .../vnd.dovecot/environment/variables.svtest | 19 ++ 7 files changed, 469 insertions(+) create mode 100644 src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am create mode 100644 src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h create mode 100644 src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c create mode 100644 src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c create mode 100644 src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c create mode 100644 tests/extensions/vnd.dovecot/environment/basic.svtest create mode 100644 tests/extensions/vnd.dovecot/environment/variables.svtest diff --git a/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am b/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am new file mode 100644 index 000000000..5d4e43883 --- /dev/null +++ b/src/lib-sieve/plugins/vnd.dovecot/environment/Makefile.am @@ -0,0 +1,16 @@ +noinst_LTLIBRARIES = libsieve_ext_vnd_environment.la + +AM_CPPFLAGS = \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../../environment \ + -I$(srcdir)/../../variables \ + $(LIBDOVECOT_INCLUDE) + +libsieve_ext_vnd_environment_la_SOURCES = \ + ext-vnd-environment.c \ + ext-vnd-environment-items.c \ + ext-vnd-environment-variables.c + +noinst_HEADERS = + ext-vnd-environment-common.h + diff --git a/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h new file mode 100644 index 000000000..97b795e85 --- /dev/null +++ b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-common.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2002-2015 Pigeonhole authors, see the included COPYING file + */ + +#ifndef __EXT_VND_ENVIRONMENT_COMMON_H +#define __EXT_VND_ENVIRONMENT_COMMON_H + +#include "sieve-ext-environment.h" + +/* + * Extension + */ + +struct ext_vnd_environment_context { + const struct sieve_extension *env_ext; + const struct sieve_extension *var_ext; +}; + +const struct sieve_extension_def vnd_environment_extension; + +/* + * Operands + */ + +extern const struct sieve_operand_def environment_namespace_operand; + +/* + * Environment items + */ + +void ext_vnd_environment_items_register +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv); + +/* + * Variables + */ + +void ext_environment_variables_init +(const struct sieve_extension *this_ext, struct sieve_validator *valdtr); + +#endif diff --git a/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c new file mode 100644 index 000000000..eab13c3eb --- /dev/null +++ b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-items.c @@ -0,0 +1,66 @@ +/* Copyright (c) 2002-2015 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-address-parts.h" + +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-binary.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "ext-vnd-environment-common.h" + +/* + * Environment items + */ + +/* default_mailbox */ + +static const char *envit_default_mailbox_get_value +(const struct sieve_runtime_env *renv) +{ + i_assert(renv->scriptenv->default_mailbox != NULL); + return renv->scriptenv->default_mailbox; +} + +const struct sieve_environment_item default_mailbox_env_item = { + .name = "vnd.dovecot.default-mailbox", + .get_value = envit_default_mailbox_get_value +}; + +/* username */ + +static const char *envit_username_get_value +(const struct sieve_runtime_env *renv) +{ + return renv->svinst->username; +} + +const struct sieve_environment_item username_env_item = { + .name = "vnd.dovecot.username", + .get_value = envit_username_get_value +}; + +/* + * Register + */ + +void ext_vnd_environment_items_register +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv) +{ + struct ext_vnd_environment_context *ectx = + (struct ext_vnd_environment_context *) ext->context; + + sieve_environment_item_register + (ectx->env_ext, renv->interp, &default_mailbox_env_item); + sieve_environment_item_register + (ectx->env_ext, renv->interp, &username_env_item); +} diff --git a/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c new file mode 100644 index 000000000..4f7082676 --- /dev/null +++ b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment-variables.c @@ -0,0 +1,207 @@ +/* Copyright (c) 2015 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" + +#include "sieve-common.h" +#include "sieve-ast.h" +#include "sieve-binary.h" +#include "sieve-code.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "sieve-ext-variables.h" + +#include "ext-vnd-environment-common.h" + +static bool vnspc_vnd_environment_validate + (struct sieve_validator *valdtr, + const struct sieve_variables_namespace *nspc, + struct sieve_ast_argument *arg, struct sieve_command *cmd, + ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data, + bool assignment); +static bool vnspc_vnd_environment_generate + (const struct sieve_codegen_env *cgenv, + const struct sieve_variables_namespace *nspc, + struct sieve_ast_argument *arg, + struct sieve_command *cmd, void *var_data); +static bool vnspc_vnd_environment_dump_variable + (const struct sieve_dumptime_env *denv, + const struct sieve_variables_namespace *nspc, + const struct sieve_operand *oprnd, sieve_size_t *address); +static int vnspc_vnd_environment_read_variable + (const struct sieve_runtime_env *renv, + const struct sieve_variables_namespace *nspc, + const struct sieve_operand *oprnd, + sieve_size_t *address, string_t **str_r); + +static const struct sieve_variables_namespace_def +environment_namespace = { + SIEVE_OBJECT("env", &environment_namespace_operand, 0), + vnspc_vnd_environment_validate, + vnspc_vnd_environment_generate, + vnspc_vnd_environment_dump_variable, + vnspc_vnd_environment_read_variable +}; + +static bool vnspc_vnd_environment_validate +(struct sieve_validator *valdtr, + const struct sieve_variables_namespace *nspc ATTR_UNUSED, + struct sieve_ast_argument *arg, struct sieve_command *cmd ATTR_UNUSED, + ARRAY_TYPE(sieve_variable_name) *var_name, void **var_data, + bool assignment) +{ + struct sieve_ast *ast = arg->ast; + const struct sieve_variable_name *name_elements; + unsigned int i, count; + const char *variable; + string_t *name; + + /* Compose environment name from parsed variable name */ + name = t_str_new(64); + name_elements = array_get(var_name, &count); + i_assert(count > 1); + for (i = 1; i < count; i++) { + if ( name_elements[i].num_variable >= 0 ) { + sieve_argument_validate_error(valdtr, arg, + "vnd.dovecot.environment: invalid variable name within " + "env namespace `env.%d': " + "encountered numeric variable name", + name_elements[i].num_variable); + return FALSE; + } + if (str_len(name) > 0) + str_append_c(name, '.'); + str_append_str(name, name_elements[i].identifier); + } + + variable = str_c(name); + + if ( assignment ) { + sieve_argument_validate_error(valdtr, arg, + "vnd.dovecot.environment: cannot assign to environment " + "variable `env.%s'", variable); + return FALSE; + } + + *var_data = (void *) p_strdup(sieve_ast_pool(ast), variable); + return TRUE; +} + +static bool vnspc_vnd_environment_generate +(const struct sieve_codegen_env *cgenv, + const struct sieve_variables_namespace *nspc, + struct sieve_ast_argument *arg ATTR_UNUSED, + struct sieve_command *cmd ATTR_UNUSED, void *var_data) +{ + const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc); + const char *variable = (const char *) var_data; + struct ext_vnd_environment_context *ext_data; + + if ( this_ext == NULL ) + return FALSE; + + ext_data = (struct ext_vnd_environment_context *) this_ext->context; + + sieve_variables_opr_namespace_variable_emit + (cgenv->sblock, ext_data->var_ext, this_ext, &environment_namespace); + sieve_binary_emit_cstring(cgenv->sblock, variable); + + return TRUE; +} + +static bool vnspc_vnd_environment_dump_variable +(const struct sieve_dumptime_env *denv, + const struct sieve_variables_namespace *nspc ATTR_UNUSED, + const struct sieve_operand *oprnd, sieve_size_t *address) +{ + string_t *var_name; + + if ( !sieve_binary_read_string(denv->sblock, address, &var_name) ) + return FALSE; + + if ( oprnd->field_name != NULL ) + sieve_code_dumpf(denv, "%s: VAR ${env.%s}", + oprnd->field_name, str_c(var_name)); + else + sieve_code_dumpf(denv, "VAR ${env.%s}", + str_c(var_name)); + + return TRUE; +} + +static int vnspc_vnd_environment_read_variable +(const struct sieve_runtime_env *renv, + const struct sieve_variables_namespace *nspc, + const struct sieve_operand *oprnd, sieve_size_t *address, + string_t **str_r) +{ + const struct sieve_extension *this_ext = SIEVE_OBJECT_EXTENSION(nspc); + struct ext_vnd_environment_context *ectx = + (struct ext_vnd_environment_context *) this_ext->context; + string_t *var_name; + const char *ext_value; + + if ( !sieve_binary_read_string(renv->sblock, address, &var_name) ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "environment variable operand corrupt: invalid name"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if ( str_r != NULL ) { + const char *vname = str_c(var_name); + + ext_value = ext_environment_item_get_value + (ectx->env_ext, renv, vname); + + if ( ext_value == NULL && strchr(vname, '_') != NULL) { + char *p, *aname; + + /* Try again with '_' replaced with '-' */ + aname = t_strdup_noconst(vname); + for (p = aname; *p != '\0'; p++) { + if (*p == '_') + *p = '-'; + } + ext_value = ext_environment_item_get_value + (ectx->env_ext, renv, aname); + } + + if ( ext_value == NULL ) { + *str_r = t_str_new_const("", 0); + return SIEVE_EXEC_OK; + } + + *str_r = t_str_new_const(ext_value, strlen(ext_value)); + } + return SIEVE_EXEC_OK; +} + +/* + * Namespace registration + */ + +static const struct sieve_extension_objects environment_namespaces = + SIEVE_VARIABLES_DEFINE_NAMESPACE(environment_namespace); + +const struct sieve_operand_def environment_namespace_operand = { + "env-namespace", + &vnd_environment_extension, + 0, + &sieve_variables_namespace_operand_class, + &environment_namespaces +}; + +void ext_environment_variables_init +(const struct sieve_extension *this_ext, struct sieve_validator *valdtr) +{ + struct ext_vnd_environment_context *ext_data = + (struct ext_vnd_environment_context *) this_ext->context; + + sieve_variables_namespace_register + (ext_data->var_ext, valdtr, this_ext, &environment_namespace); +} diff --git a/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c new file mode 100644 index 000000000..849d7d7b6 --- /dev/null +++ b/src/lib-sieve/plugins/vnd.dovecot/environment/ext-vnd-environment.c @@ -0,0 +1,102 @@ +/* Copyright (c) 2002-2015 Pigeonhole authors, see the included COPYING file + */ + +/* Extension vnd.dovecot.environment + * --------------------------------- + * + * Authors: Stephan Bosch + * Specification: vendor-defined + * Implementation: preliminary + * Status: experimental + * + */ + +#include "lib.h" +#include "array.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-address-parts.h" + +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-binary.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "sieve-ext-variables.h" + +#include "ext-vnd-environment-common.h" + +/* + * Extension + */ + +static bool ext_vnd_environment_load + (const struct sieve_extension *ext, void **context); +static void ext_vnd_environment_unload + (const struct sieve_extension *ext); +static bool ext_vnd_environment_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); +static bool ext_vnd_environment_interpreter_load + (const struct sieve_extension *ext, const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_extension_def vnd_environment_extension = { + .name = "vnd.dovecot.environment", + .load = ext_vnd_environment_load, + .unload = ext_vnd_environment_unload, + .validator_load = ext_vnd_environment_validator_load, + .interpreter_load = ext_vnd_environment_interpreter_load, + SIEVE_EXT_DEFINE_OPERAND(environment_namespace_operand) +}; + +static bool ext_vnd_environment_load +(const struct sieve_extension *ext, void **context) +{ + struct ext_vnd_environment_context *ectx; + + if ( *context != NULL ) + ext_vnd_environment_unload(ext); + + ectx = i_new(struct ext_vnd_environment_context, 1); + ectx->env_ext = sieve_ext_environment_get_extension(ext->svinst); + ectx->var_ext = sieve_ext_variables_get_extension(ext->svinst); + *context = (void *) ectx; + + return TRUE; +} + +static void ext_vnd_environment_unload +(const struct sieve_extension *ext) +{ + struct ext_vnd_environment_context *ectx = + (struct ext_vnd_environment_context *) ext->context; + + i_free(ectx); +} + +/* + * Validator + */ + +static bool ext_vnd_environment_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + ext_environment_variables_init(ext, valdtr); + return TRUE; +} + +/* + * Interpreter + */ + +static bool ext_vnd_environment_interpreter_load +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv, + sieve_size_t *address ATTR_UNUSED) +{ + ext_vnd_environment_items_register(ext, renv); + return TRUE; +} diff --git a/tests/extensions/vnd.dovecot/environment/basic.svtest b/tests/extensions/vnd.dovecot/environment/basic.svtest new file mode 100644 index 000000000..a966d8954 --- /dev/null +++ b/tests/extensions/vnd.dovecot/environment/basic.svtest @@ -0,0 +1,19 @@ +require "vnd.dovecot.testsuite"; +require "environment"; +require "vnd.dovecot.environment"; +require "variables"; + +test "default-mailbox" { + if not environment :is "vnd.dovecot.default-mailbox" "INBOX" { + if environment :matches "vnd.dovecot.default-mailbox" "*" { set "env" "${1}"; } + + test_fail "vnd.dovecot.default-mailbox environment returned invalid value(1): `${env}'"; + } +} + +test "username" { + if not environment :contains "vnd.dovecot.username" "" { + test_fail "vnd.dovecot.username environment does not exist"; + } +} + diff --git a/tests/extensions/vnd.dovecot/environment/variables.svtest b/tests/extensions/vnd.dovecot/environment/variables.svtest new file mode 100644 index 000000000..7339bba57 --- /dev/null +++ b/tests/extensions/vnd.dovecot/environment/variables.svtest @@ -0,0 +1,19 @@ +require "vnd.dovecot.testsuite"; +require "environment"; +require "vnd.dovecot.environment"; +require "variables"; +require "relational"; + +test "default_mailbox" { + if not string "${env.vnd.dovecot.default_mailbox}" "INBOX" { + test_fail "The env.vnd.dovecot.default_mailbox variable returned invalid value: `${env.vnd.dovecot.default_mailbox}'"; + } +} + +test "username" { + set :length "userlen" "${env.vnd.dovecot.username}"; + if not string :value "ge" "${userlen}" "1" { + test_fail "The env.vnd.dovecot.username variable is empty or does not exist"; + } +} + -- GitLab