summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c')
-rw-r--r--pigeonhole/src/lib-sieve/plugins/notify/cmd-denotify.c389
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 = &notify_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;
+}
+
+
+