diff --git a/src/lib-sieve/plugins/variables/Makefile.am b/src/lib-sieve/plugins/variables/Makefile.am index 592a8eb63c5e2f03b71ff99fce2fe538174657be..f3457b79972de3706f231d95babf43d3a33658d3 100644 --- a/src/lib-sieve/plugins/variables/Makefile.am +++ b/src/lib-sieve/plugins/variables/Makefile.am @@ -7,6 +7,19 @@ AM_CPPFLAGS = \ -I$(dovecot_incdir)/src/lib-mail \ -I$(dovecot_incdir)/src/lib-storage +cmds = \ + cmd-set.c + +tsts = \ + tst-string.c + libsieve_ext_variables_la_SOURCES = \ + ext-variables-common.c \ + $(cmds) \ + $(tsts) \ ext-variables.c +noinst_HEADERS = \ + ext-variables-common.h + + diff --git a/src/lib-sieve/plugins/variables/cmd-set.c b/src/lib-sieve/plugins/variables/cmd-set.c new file mode 100644 index 0000000000000000000000000000000000000000..b05747b269c0eafb2d42f63b756d4d236ffb3417 --- /dev/null +++ b/src/lib-sieve/plugins/variables/cmd-set.c @@ -0,0 +1,217 @@ +#include "lib.h" + +#include "sieve-common.h" + +#include "sieve-code.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-code-dumper.h" + +#include "ext-variables-common.h" + +/* Forward declarations */ + +static bool opc_set_dump + (const struct sieve_opcode *opcode, + const struct sieve_dumptime_env *denv, sieve_size_t *address); +static bool opc_set_execute + (const struct sieve_opcode *opcode, + const struct sieve_runtime_env *renv, sieve_size_t *address); + +static bool cmd_set_registered + (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); +static bool cmd_set_validate + (struct sieve_validator *validator, struct sieve_command_context *cmd); +static bool cmd_set_generate + (struct sieve_generator *generator, struct sieve_command_context *ctx); + +/* Set command + * + * Syntax: + * set [MODIFIER] <name: string> <value: string> + */ +const struct sieve_command cmd_set = { + "set", + SCT_COMMAND, + 2, 0, FALSE, FALSE, + cmd_set_registered, + NULL, + cmd_set_validate, + cmd_set_generate, + NULL +}; + +/* set opcode */ +const struct sieve_opcode cmd_set_opcode = { + "SET", + SIEVE_OPCODE_CUSTOM, + &variables_extension, + EXT_VARIABLES_OPCODE_SET, + opc_set_dump, + opc_set_execute +}; + +/* Tag validation */ + +/* [MODIFIER]: + * ":lower" / ":upper" / ":lowerfirst" / ":upperfirst" / + * ":quotewildcard" / ":length" + * + * FIXME: Provide support to add further modifiers (as needed by notify) + */ + +static bool tag_modifier_is_instance_of + (struct sieve_validator *validator, const char *tag) +{ + return ext_variables_set_modifier_find(validator, tag) != NULL; +} + +static bool tag_modifier_validate +(struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + struct sieve_ast_argument *tag = *arg; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +static bool tag_modifier_generate +(struct sieve_generator *generator, struct sieve_ast_argument *arg, + struct sieve_command_context *cmd ATTR_UNUSED) +{ + return TRUE; +} + +const struct sieve_argument modifier_tag = { + "MODIFIER", + tag_modifier_is_instance_of, + tag_modifier_validate, + NULL, + tag_modifier_generate +}; + +/* Pre-defined modifiers */ + +const struct ext_variables_set_modifier lower_modifier = { + "lower", + EXT_VARIABLES_SET_MODIFIER_LOWER, + 40 +}; + +const struct ext_variables_set_modifier upper_modifier = { + "upper", + EXT_VARIABLES_SET_MODIFIER_UPPER, + 40 +}; + +const struct ext_variables_set_modifier lowerfirst_modifier = { + "lowerfirst", + EXT_VARIABLES_SET_MODIFIER_LOWERFIRST, + 30 +}; + +const struct ext_variables_set_modifier upperfirst_modifier = { + "upperfirst", + EXT_VARIABLES_SET_MODIFIER_UPPERFIRST, + 30 +}; + +const struct ext_variables_set_modifier quotewildcard_modifier = { + "quotewildcard", + EXT_VARIABLES_SET_MODIFIER_QUOTEWILDCARD, + 20 +}; + +const struct ext_variables_set_modifier length_modifier = { + "length", + EXT_VARIABLES_SET_MODIFIER_LENGTH, + 10 +}; + +/* Command registration */ + +static bool cmd_set_registered + (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag(validator, cmd_reg, &modifier_tag, 0); + + return TRUE; +} + +/* Command validation */ + +static bool cmd_set_validate(struct sieve_validator *validator, + struct sieve_command_context *cmd) +{ + struct sieve_ast_argument *arg = cmd->first_positional; + + if ( !sieve_validate_positional_argument + (validator, cmd, arg, "name", 1, SAAT_STRING) ) { + return FALSE; + } + sieve_validator_argument_activate(validator, cmd, arg, TRUE); + + arg = sieve_ast_argument_next(arg); + + if ( !sieve_validate_positional_argument + (validator, cmd, arg, "value", 2, SAAT_STRING) ) { + return FALSE; + } + sieve_validator_argument_activate(validator, cmd, arg, TRUE); + + return TRUE; +} + +/* + * Generation + */ + +static bool cmd_set_generate + (struct sieve_generator *generator, struct sieve_command_context *ctx) +{ + sieve_generator_emit_opcode_ext + (generator, &cmd_set_opcode, ext_variables_my_id); + + /* Generate arguments */ + if ( !sieve_generate_arguments(generator, ctx, NULL) ) + return FALSE; + + return TRUE; +} + +/* + * Code dump + */ + +static bool opc_set_dump +(const struct sieve_opcode *opcode ATTR_UNUSED, + const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + sieve_code_dumpf(denv, "SET"); + sieve_code_descend(denv); + + return + sieve_opr_string_dump(denv, address) && + sieve_opr_string_dump(denv, address); +} + +/* + * Code execution + */ + +static bool opc_set_execute +(const struct sieve_opcode *opcode ATTR_UNUSED, + const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + return TRUE; +} + + + + + diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.c b/src/lib-sieve/plugins/variables/ext-variables-common.c new file mode 100644 index 0000000000000000000000000000000000000000..932e7631905c0112ac17acdcadca7d68cf2bf448 --- /dev/null +++ b/src/lib-sieve/plugins/variables/ext-variables-common.c @@ -0,0 +1,81 @@ +#include "lib.h" +#include "hash.h" + +#include "sieve-common.h" +#include "sieve-validator.h" + +#include "ext-variables-common.h" + +/* Forward declarations */ + +extern const struct ext_variables_set_modifier lower_modifier; +extern const struct ext_variables_set_modifier upper_modifier; +extern const struct ext_variables_set_modifier lowerfirst_modifier; +extern const struct ext_variables_set_modifier upperfirst_modifier; +extern const struct ext_variables_set_modifier quotewildcard_modifier; +extern const struct ext_variables_set_modifier length_modifier; + +const struct ext_variables_set_modifier *default_set_modifiers[] = { + &lower_modifier, &upper_modifier, &lowerfirst_modifier, &upperfirst_modifier, + "ewildcard_modifier, &length_modifier +}; + +const unsigned int default_set_modifiers_count = + N_ELEMENTS(default_set_modifiers); + +/* Validator context */ + +struct ext_variables_validator_context { + struct hash_table *set_modifiers; +}; + +static struct ext_variables_validator_context * +ext_variables_validator_context_create(struct sieve_validator *validator) +{ + pool_t pool = sieve_validator_pool(validator); + struct ext_variables_validator_context *ctx; + + ctx = p_new(pool, struct ext_variables_validator_context, 1); + ctx->set_modifiers = hash_create + (pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); + + sieve_validator_extension_set_context + (validator, ext_variables_my_id, (void *) ctx); + + return ctx; +} + +void ext_variables_validator_initialize(struct sieve_validator *validator) +{ + unsigned int i; + struct ext_variables_validator_context *ctx; + + /* Create our context */ + ctx = ext_variables_validator_context_create(validator); + + for ( i = 0; i < default_set_modifiers_count; i++ ) { + const struct ext_variables_set_modifier *mod = default_set_modifiers[i]; + + hash_insert(ctx->set_modifiers, (void *) mod->identifier, (void *) mod); + } +} + +static inline struct ext_variables_validator_context * +ext_variables_validator_context_get(struct sieve_validator *validator) +{ + return (struct ext_variables_validator_context *) + sieve_validator_extension_get_context(validator, ext_variables_my_id); +} + +/* Set modifier registration */ + +const struct ext_variables_set_modifier *ext_variables_set_modifier_find +(struct sieve_validator *validator, const char *identifier) +{ + struct ext_variables_validator_context *ctx = + ext_variables_validator_context_get(validator); + + return (const struct ext_variables_set_modifier *) + hash_lookup(ctx->set_modifiers, identifier); +} + diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.h b/src/lib-sieve/plugins/variables/ext-variables-common.h new file mode 100644 index 0000000000000000000000000000000000000000..b86c242ada1508214980fc03e75e32f242aa3fa8 --- /dev/null +++ b/src/lib-sieve/plugins/variables/ext-variables-common.h @@ -0,0 +1,40 @@ +#ifndef __EXT_VARIABLES_COMMON_H +#define __EXT_VARIABLES_COMMON_H + +#include "sieve-common.h" + +extern int ext_variables_my_id; + +extern struct sieve_extension variables_extension; + +enum ext_variables_opcode { + EXT_VARIABLES_OPCODE_SET, + EXT_VARIABLES_OPCODE_STRING +}; + +/* Extension */ + +void ext_variables_validator_initialize(struct sieve_validator *validator); + +/* Set modifiers */ + +enum ext_variables_set_modifier_code { + EXT_VARIABLES_SET_MODIFIER_LOWER, + EXT_VARIABLES_SET_MODIFIER_UPPER, + EXT_VARIABLES_SET_MODIFIER_LOWERFIRST, + EXT_VARIABLES_SET_MODIFIER_UPPERFIRST, + EXT_VARIABLES_SET_MODIFIER_QUOTEWILDCARD, + EXT_VARIABLES_SET_MODIFIER_LENGTH +}; + +struct ext_variables_set_modifier { + const char *identifier; + int code; + + unsigned int precedence; +}; + +const struct ext_variables_set_modifier *ext_variables_set_modifier_find + (struct sieve_validator *validator, const char *identifier); + +#endif /* __EXT_VARIABLES_COMMON_H */ diff --git a/src/lib-sieve/plugins/variables/ext-variables.c b/src/lib-sieve/plugins/variables/ext-variables.c index 9ce50ea54177a618ee8c9bf86fc0960840c2067c..d836a82fbfa6a580a3841d6f575bc0f58c5e384d 100644 --- a/src/lib-sieve/plugins/variables/ext-variables.c +++ b/src/lib-sieve/plugins/variables/ext-variables.c @@ -15,6 +15,8 @@ #include "sieve-commands.h" #include "sieve-validator.h" +#include "ext-variables-common.h" + #include <ctype.h> /* Forward declarations */ @@ -22,22 +24,36 @@ static bool ext_variables_load(int ext_id); static bool ext_variables_validator_load(struct sieve_validator *validator); +/* Commands */ + +extern const struct sieve_command cmd_set; +extern const struct sieve_command tst_string; + +/* Opcodes */ + +extern const struct sieve_opcode cmd_set_opcode; +extern const struct sieve_opcode tst_string_opcode; + +const struct sieve_opcode *ext_variables_opcodes[] = { + &cmd_set_opcode, &tst_string_opcode +}; + /* Extension definitions */ -static int ext_my_id; +int ext_variables_my_id; struct sieve_extension variables_extension = { "variables", ext_variables_load, ext_variables_validator_load, NULL, NULL, NULL, - SIEVE_EXT_DEFINE_NO_OPCODES, + SIEVE_EXT_DEFINE_OPCODES(ext_variables_opcodes), NULL }; static bool ext_variables_load(int ext_id) { - ext_my_id = ext_id; + ext_variables_my_id = ext_id; return TRUE; } @@ -142,7 +158,13 @@ static bool arg_variable_string_validate static bool ext_variables_validator_load (struct sieve_validator *validator ATTR_UNUSED) { - sieve_validator_argument_override(validator, SAT_VAR_STRING, - &variable_string_argument); + /*sieve_validator_argument_override(validator, SAT_VAR_STRING, + &variable_string_argument);*/ + + sieve_validator_register_command(validator, &cmd_set); + sieve_validator_register_command(validator, &tst_string); + + ext_variables_validator_initialize(validator); + return TRUE; } diff --git a/src/lib-sieve/plugins/variables/tst-string.c b/src/lib-sieve/plugins/variables/tst-string.c new file mode 100644 index 0000000000000000000000000000000000000000..23e01d6190d0b9f780bde310a926755646e64f82 --- /dev/null +++ b/src/lib-sieve/plugins/variables/tst-string.c @@ -0,0 +1,237 @@ +#include <stdio.h> + +#include "sieve-commands.h" +#include "sieve-commands-private.h" +#include "sieve-code.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-code-dumper.h" + +#include "ext-variables-common.h" + +/* String test + * + * Syntax: + * string [COMPARATOR] [MATCH-TYPE] + * <source: string-list> <key-list: string-list> + */ + +static bool tst_string_registered + (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg); +static bool tst_string_validate + (struct sieve_validator *validator, struct sieve_command_context *tst); +static bool tst_string_generate + (struct sieve_generator *generator, struct sieve_command_context *ctx); + +const struct sieve_command tst_string = { + "string", + SCT_TEST, + 2, 0, FALSE, FALSE, + tst_string_registered, + NULL, + tst_string_validate, + tst_string_generate, + NULL +}; + +/* Opcode */ + +static bool tst_string_opcode_dump + (const struct sieve_opcode *opcode, + const struct sieve_dumptime_env *denv, sieve_size_t *address); +static bool tst_string_opcode_execute + (const struct sieve_opcode *opcode, + const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_opcode tst_string_opcode = { + "string", + SIEVE_OPCODE_CUSTOM, + &variables_extension, + EXT_VARIABLES_OPCODE_STRING, + tst_string_opcode_dump, + tst_string_opcode_execute +}; + +/* Optional arguments */ + +enum tst_string_optional { + OPT_END, + OPT_COMPARATOR, + OPT_MATCH_TYPE +}; + +/* Test registration */ + +static bool tst_string_registered + (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg) +{ + /* The order of these is not significant */ + sieve_comparators_link_tag(validator, cmd_reg, OPT_COMPARATOR); + sieve_match_types_link_tags(validator, cmd_reg, OPT_MATCH_TYPE); + + return TRUE; +} + +/* Test validation */ + +static bool tst_string_validate + (struct sieve_validator *validator, struct sieve_command_context *tst) +{ + struct sieve_ast_argument *arg = tst->first_positional; + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "source", 1, SAAT_STRING_LIST) ) { + return FALSE; + } + sieve_validator_argument_activate(validator, tst, arg, FALSE); + + arg = sieve_ast_argument_next(arg); + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { + return FALSE; + } + sieve_validator_argument_activate(validator, tst, arg, FALSE); + + /* Validate the key argument to a specified match type */ + sieve_match_type_validate(validator, tst, arg); + + return TRUE; +} + +/* Test generation */ + +static bool tst_string_generate + (struct sieve_generator *generator, struct sieve_command_context *ctx) +{ + sieve_generator_emit_opcode(generator, &tst_string_opcode); + + /* Generate arguments */ + if ( !sieve_generate_arguments(generator, ctx, NULL) ) + return FALSE; + + return TRUE; +} + +/* Code dump */ + +static bool tst_string_opcode_dump +(const struct sieve_opcode *opcode ATTR_UNUSED, + const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + int opt_code = 1; + + sieve_code_dumpf(denv, "STRING-TEST"); + sieve_code_descend(denv); + + /* Handle any optional arguments */ + if ( sieve_operand_optional_present(denv->sbin, address) ) { + while ( opt_code != 0 ) { + if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) + return FALSE; + + switch ( opt_code ) { + case 0: + break; + case OPT_COMPARATOR: + sieve_opr_comparator_dump(denv, address); + break; + case OPT_MATCH_TYPE: + sieve_opr_match_type_dump(denv, address); + break; + default: + return FALSE; + } + } + } + + return + sieve_opr_stringlist_dump(denv, address) && + sieve_opr_stringlist_dump(denv, address); +} + +/* Code execution */ + +static bool tst_string_opcode_execute +(const struct sieve_opcode *opcode ATTR_UNUSED, + const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + bool result = TRUE; + int opt_code = 1; + const struct sieve_comparator *cmp = &i_octet_comparator; + const struct sieve_match_type *mtch = &is_match_type; + struct sieve_match_context *mctx; + struct sieve_coded_stringlist *source; + struct sieve_coded_stringlist *key_list; + string_t *src_item; + bool matched; + + printf("?? STRING\n"); + + /* Handle any optional arguments */ + if ( sieve_operand_optional_present(renv->sbin, address) ) { + while ( opt_code != 0 ) { + if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) + return FALSE; + + switch ( opt_code ) { + case 0: + break; + case OPT_COMPARATOR: + cmp = sieve_opr_comparator_read(renv->sbin, address); + break; + case OPT_MATCH_TYPE: + mtch = sieve_opr_match_type_read(renv->sbin, address); + break; + default: + return FALSE; + } + } + } + + t_push(); + + /* Read string-list */ + if ( (source=sieve_opr_stringlist_read(renv->sbin, address)) == NULL ) { + t_pop(); + return FALSE; + } + + /* Read key-list */ + if ( (key_list=sieve_opr_stringlist_read(renv->sbin, address)) == NULL ) { + t_pop(); + return FALSE; + } + + mctx = sieve_match_begin(mtch, cmp, key_list); + + /* Iterate through all requested strings to match */ + src_item = NULL; + matched = FALSE; + while ( !matched && + (result=sieve_coded_stringlist_next_item(source, &src_item)) + && src_item != NULL ) { + + /* + if ( mail_get_strings_utf8(renv->msgdata->mail, str_c(hdr_item), &strings) >= 0 ) { + + int i; + for ( i = 0; !matched && strings[i] != NULL; i++ ) { + if ( sieve_match_value(mctx, strings[i], strlen(strings[i])) ) + matched = TRUE; + } + }*/ + } + + matched = sieve_match_end(mctx) || matched; + + t_pop(); + + if ( result ) + sieve_interpreter_set_test_result(renv->interp, matched); + + return result; +} diff --git a/src/lib-sieve/plugins/variables/variables.sieve b/src/lib-sieve/plugins/variables/variables.sieve index 43681b5c9becf81046c6897742619ed69567d192..498c48ae7cc92183594f60686ca1e4badc73af85 100644 --- a/src/lib-sieve/plugins/variables/variables.sieve +++ b/src/lib-sieve/plugins/variables/variables.sieve @@ -1,3 +1,4 @@ require "variables"; - +set :upper "foo" "foosome"; +set :lower "bar" "bareable";