diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c b/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c new file mode 100644 index 0000000..8769808 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c @@ -0,0 +1,389 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" + +#include "sieve-common.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-ast.h" +#include "sieve-commands.h" +#include "sieve-match-types.h" +#include "sieve-comparators.h" +#include "sieve-match.h" +#include "sieve-actions.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" +#include "sieve-result.h" + +#include "ext-notify-common.h" + +/* + * Denotify command + * + * Syntax: + * denotify [MATCH-TYPE string] [<":low" / ":normal" / ":high">] + */ + +static bool cmd_denotify_registered + (struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool cmd_denotify_pre_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); +static bool cmd_denotify_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); +static bool cmd_denotify_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd); + +const struct sieve_command_def cmd_denotify = { + .identifier = "denotify", + .type = SCT_COMMAND, + .positional_args = 0, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = cmd_denotify_registered, + .pre_validate = cmd_denotify_pre_validate, + .validate = cmd_denotify_validate, + .generate = cmd_denotify_generate +}; + +/* + * Tagged arguments + */ + +/* Forward declarations */ + +static bool tag_match_type_is_instance_of + (struct sieve_validator *validator, struct sieve_command *cmd, + const struct sieve_extension *ext, const char *identifier, void **data); +static bool tag_match_type_validate + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command *cmd); + +/* Argument object */ + +const struct sieve_argument_def denotify_match_tag = { + .identifier = "MATCH-TYPE-STRING", + .is_instance_of = tag_match_type_is_instance_of, + .validate = tag_match_type_validate +}; + +/* Codes for optional operands */ + +enum cmd_denotify_optional { + OPT_END, + OPT_IMPORTANCE, + OPT_MATCH_TYPE, + OPT_MATCH_KEY +}; + +/* + * Denotify operation + */ + +static bool cmd_denotify_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int cmd_denotify_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_operation_def denotify_operation = { + .mnemonic = "DENOTIFY", + .ext_def = ¬ify_extension, + .code = EXT_NOTIFY_OPERATION_DENOTIFY, + .dump = cmd_denotify_operation_dump, + .execute = cmd_denotify_operation_execute +}; + +/* + * Command validation context + */ + +struct cmd_denotify_context_data { + struct sieve_ast_argument *match_key_arg; +}; + +/* + * Tag validation + */ + +static bool tag_match_type_is_instance_of +(struct sieve_validator *valdtr, struct sieve_command *cmd, + const struct sieve_extension *ext, const char *identifier, void **data) +{ + return match_type_tag.is_instance_of(valdtr, cmd, ext, identifier, data); +} + +static bool tag_match_type_validate +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct cmd_denotify_context_data *cmd_data = + (struct cmd_denotify_context_data *) cmd->data; + struct sieve_ast_argument *tag = *arg; + + i_assert(tag != NULL); + + if ( !match_type_tag.validate(valdtr, arg, cmd) ) + return FALSE; + + if ( *arg == NULL ) { + sieve_argument_validate_error(valdtr, tag, + "the MATCH-TYPE argument (:%s) for the denotify command requires " + "an additional key-string parameter, but no more arguments were found", + sieve_ast_argument_tag(tag)); + return FALSE; + } + + if ( sieve_ast_argument_type(*arg) != SAAT_STRING ) + { + sieve_argument_validate_error(valdtr, *arg, + "the MATCH-TYPE argument (:%s) for the denotify command requires " + "an additional key-string parameter, but %s was found", + sieve_ast_argument_tag(tag), sieve_ast_argument_name(*arg)); + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, cmd, *arg, FALSE) ) + return FALSE; + + tag->argument->def = &match_type_tag; + tag->argument->ext = NULL; + + (*arg)->argument->id_code = OPT_MATCH_KEY; + cmd_data->match_key_arg = *arg; + + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +/* + * Command registration + */ + +static bool cmd_denotify_registered +(struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag + (valdtr, cmd_reg, ext, &denotify_match_tag, OPT_MATCH_TYPE); + + ext_notify_register_importance_tags(valdtr, cmd_reg, ext, OPT_IMPORTANCE); + + return TRUE; +} + +/* + * Command validation + */ + +static bool cmd_denotify_pre_validate +(struct sieve_validator *valdtr ATTR_UNUSED, + struct sieve_command *cmd) +{ + struct cmd_denotify_context_data *ctx_data; + + /* Assign context */ + ctx_data = p_new(sieve_command_pool(cmd), + struct cmd_denotify_context_data, 1); + cmd->data = (void *) ctx_data; + + return TRUE; +} + +static bool cmd_denotify_validate +(struct sieve_validator *valdtr, struct sieve_command *cmd) +{ + struct cmd_denotify_context_data *ctx_data = + (struct cmd_denotify_context_data *) cmd->data; + struct sieve_ast_argument *key_arg = ctx_data->match_key_arg; + const struct sieve_match_type mcht_default = + SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + const struct sieve_comparator cmp_default = + SIEVE_COMPARATOR_DEFAULT(i_octet_comparator); + + if ( key_arg != NULL ) { + if ( !sieve_match_type_validate + (valdtr, cmd, key_arg, &mcht_default, &cmp_default) ) + return FALSE; + } + + return TRUE; +} + +/* + * Code generation + */ + +static bool cmd_denotify_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, &denotify_operation); + + /* Generate arguments */ + return sieve_generate_arguments(cgenv, cmd, NULL); +} + +/* + * Code dump + */ + +static bool cmd_denotify_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + const struct sieve_operation *op = denv->oprtn; + int opt_code = 0; + + sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(op)); + sieve_code_descend(denv); + + for (;;) { + int opt; + bool opok = TRUE; + + if ( (opt=sieve_opr_optional_dump(denv, address, &opt_code)) < 0 ) + return FALSE; + + if ( opt == 0 ) break; + + switch ( opt_code ) { + case OPT_MATCH_KEY: + opok = sieve_opr_string_dump(denv, address, "key-string"); + break; + case OPT_MATCH_TYPE: + opok = sieve_opr_match_type_dump(denv, address); + break; + case OPT_IMPORTANCE: + opok = sieve_opr_number_dump(denv, address, "importance"); + break; + default: + return FALSE; + } + + if ( !opok ) return FALSE; + } + + return TRUE; +} + +/* + * Code execution + */ + +static int cmd_denotify_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + int opt_code = 0; + struct sieve_match_type mcht = + SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + const struct sieve_comparator cmp = + SIEVE_COMPARATOR_DEFAULT(i_octet_comparator); + struct sieve_stringlist *match_key = NULL; + sieve_number_t importance = 0; + struct sieve_match_context *mctx; + struct sieve_result_iterate_context *rictx; + const struct sieve_action *action; + int ret; + + /* + * Read operands + */ + + /* Optional operands */ + + for (;;) { + int opt; + + if ( (opt=sieve_opr_optional_read(renv, address, &opt_code)) < 0 ) + return SIEVE_EXEC_BIN_CORRUPT; + + if ( opt == 0 ) break; + + switch ( opt_code ) { + case OPT_MATCH_TYPE: + ret = sieve_opr_match_type_read(renv, address, &mcht); + break; + case OPT_MATCH_KEY: + ret = sieve_opr_stringlist_read(renv, address, "match key", &match_key); + break; + case OPT_IMPORTANCE: + ret = sieve_opr_number_read(renv, address, "importance", &importance); + break; + default: + sieve_runtime_trace_error(renv, "unknown optional operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if ( ret <= 0 ) return ret; + } + + /* + * Perform operation + */ + + /* Enforce 0 < importance < 4 (just to be sure) */ + + if ( importance < 1 ) + importance = 1; + else if ( importance > 3 ) + importance = 3; + + /* Trace */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "denotify action"); + + /* Either do string matching or just kill all notify actions */ + if ( match_key != NULL ) { + /* Initialize match */ + mctx = sieve_match_begin(renv, &mcht, &cmp); + + /* Iterate through all notify actions and delete those that match */ + rictx = sieve_result_iterate_init(renv->result); + + while ( (action=sieve_result_iterate_next(rictx, NULL)) != NULL ) { + if ( sieve_action_is(action, act_notify_old) ) { + struct ext_notify_action *nact = + (struct ext_notify_action *) action->context; + + if ( importance == 0 || nact->importance == importance ) { + int match; + + if ( (match=sieve_match_value + (mctx, nact->id, strlen(nact->id), match_key)) < 0 ) + break; + + if ( match > 0 ) + sieve_result_iterate_delete(rictx); + } + } + } + + /* Finish match */ + if ( sieve_match_end(&mctx, &ret) < 0 ) + return ret; + + } else { + /* Delete all notify actions */ + rictx = sieve_result_iterate_init(renv->result); + + while ( (action=sieve_result_iterate_next(rictx, NULL)) != NULL ) { + + if ( sieve_action_is(action, act_notify_old) ) { + struct ext_notify_action *nact = + (struct ext_notify_action *) action->context; + + if ( importance == 0 || nact->importance == importance ) + sieve_result_iterate_delete(rictx); + } + } + } + + return SIEVE_EXEC_OK; +} + + + |