diff --git a/src/lib-sieve/plugins/notify/Makefile.am b/src/lib-sieve/plugins/notify/Makefile.am index 26e00b129b05a7350ea3cb805a291f6723b910ca..2b4f711bd6583a438fdb8ffff0614b389fe3f3bf 100644 --- a/src/lib-sieve/plugins/notify/Makefile.am +++ b/src/lib-sieve/plugins/notify/Makefile.am @@ -14,6 +14,7 @@ commands = \ libsieve_ext_notify_la_SOURCES = \ ext-notify.c \ + ext-notify-common.c \ $(commands) noinst_HEADERS = \ diff --git a/src/lib-sieve/plugins/notify/cmd-denotify.c b/src/lib-sieve/plugins/notify/cmd-denotify.c index 7f6f33bb5ef31e8a214003ed86b7aeaea507b9e9..dbc72b22e60b9e8f10a74c61c66d244a87fbbb8e 100644 --- a/src/lib-sieve/plugins/notify/cmd-denotify.c +++ b/src/lib-sieve/plugins/notify/cmd-denotify.c @@ -6,7 +6,10 @@ #include "sieve-common.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-actions.h" #include "sieve-validator.h" #include "sieve-generator.h" @@ -16,46 +19,287 @@ #include "ext-notify-common.h" -/* Denotify command (NOT IMPLEMENTED) +/* + * Denotify command (NOT IMPLEMENTED) * * Syntax: * denotify [MATCH-TYPE string] [<":low" / ":normal" / ":high">] */ -static bool cmd_denotify_pre_validate - (struct sieve_validator *valdtr, struct sieve_command_context *cmd); +static bool cmd_denotify_registered + (struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg); +static bool cmd_denotify_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx); const struct sieve_command cmd_denotify = { "denotify", SCT_COMMAND, 0, 0, FALSE, FALSE, + cmd_denotify_registered, + NULL, + NULL, + cmd_denotify_generate, + NULL +}; + +/* + * Tagged arguments + */ + +/* Forward declarations */ + +static bool tag_match_type_is_instance_of + (struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg); +static bool tag_match_type_validate + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd); + +/* Argument object */ + +const struct sieve_argument denotify_match_tag = { + "MATCH-TYPE-STRING", + tag_match_type_is_instance_of, NULL, - cmd_denotify_pre_validate, - NULL, NULL, NULL + tag_match_type_validate, + NULL, NULL +}; + +/* 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_operation *op ATTR_UNUSED, + const struct sieve_dumptime_env *denv, sieve_size_t *address); + const struct sieve_operation denotify_operation = { "DENOTIFY", ¬ify_extension, EXT_NOTIFY_OPERATION_DENOTIFY, - NULL, NULL + cmd_denotify_operation_dump, + NULL }; /* - * Command validation + * Tag validation */ -static bool cmd_denotify_pre_validate -(struct sieve_validator *valdtr, struct sieve_command_context *cmd) +static bool tag_match_type_is_instance_of +(struct sieve_validator *valdtr, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg) { - sieve_command_validate_error(valdtr, cmd, - "the denotify command cannot be used " - "(the deprecated notify extension is not fully implemented)"); - return FALSE; + return match_type_tag.is_instance_of(valdtr, cmd, arg); } +static bool tag_match_type_validate +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + struct sieve_ast_argument *tag = *arg; + + 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 paramterer, 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; + + if ( !sieve_match_type_validate + (valdtr, cmd, *arg, &is_match_type, &i_octet_comparator) ) + return FALSE; + + tag->argument = &match_type_tag; + + (*arg)->arg_id_code = OPT_MATCH_KEY; + + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +/* + * Command registration + */ + +static bool cmd_denotify_registered +(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag + (valdtr, cmd_reg, &denotify_match_tag, OPT_MATCH_TYPE); + + ext_notify_register_importance_tags(valdtr, cmd_reg, OPT_IMPORTANCE); + + return TRUE; +} + +/* + * Code generation + */ + +static bool cmd_denotify_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command_context *ctx) +{ + sieve_operation_emit_code(cgenv->sbin, &denotify_operation); + + /* Emit source line */ + sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(ctx)); + + /* Generate arguments */ + return sieve_generate_arguments(cgenv, ctx, NULL); +} + +/* + * Code dump + */ + +static bool cmd_denotify_operation_dump +(const struct sieve_operation *op ATTR_UNUSED, + const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + int opt_code = 1; + + sieve_code_dumpf(denv, "%s", op->mnemonic); + sieve_code_descend(denv); + + /* Source line */ + if ( !sieve_code_source_line_dump(denv, address) ) + return FALSE; + + /* Dump optional operands */ + if ( sieve_operand_optional_present(denv->sbin, address) ) { + while ( opt_code != 0 ) { + sieve_code_mark(denv); + + if ( !sieve_operand_optional_read(denv->sbin, address, &opt_code) ) + return FALSE; + + switch ( opt_code ) { + case 0: + break; + case OPT_MATCH_KEY: + if ( !sieve_opr_string_dump(denv, address, "key-string") ) + return FALSE; + break; + case OPT_MATCH_TYPE: + if ( !sieve_opr_match_type_dump(denv, address) ) + return FALSE; + break; + case OPT_IMPORTANCE: + if ( !sieve_opr_number_dump(denv, address, "importance") ) + return FALSE; + break; + default: + return FALSE; + } + } + } + + return TRUE; +} + +/* + * Code execution + */ + +static int cmd_notify_operation_execute +(const struct sieve_operation *op ATTR_UNUSED, + const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + struct ext_notify_action *act; + pool_t pool; + int opt_code = 1; + sieve_number_t importance = 1; + const struct sieve_match_type *match_type = NULL; + string_t *match_key = NULL; + unsigned int source_line; + + /* + * Read operands + */ + + /* Source line */ + if ( !sieve_code_source_line_read(renv, address, &source_line) ) { + sieve_runtime_trace_error(renv, "invalid source line"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + /* Optional operands */ + if ( sieve_operand_optional_present(renv->sbin, address) ) { + while ( opt_code != 0 ) { + if ( !sieve_operand_optional_read(renv->sbin, address, &opt_code) ) { + sieve_runtime_trace_error(renv, "invalid optional operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + switch ( opt_code ) { + case 0: + break; + case OPT_MATCH_TYPE: + if ( (match_type = sieve_opr_match_type_read(renv, address)) == NULL ) { + sieve_runtime_trace_error(renv, "invalid match type operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + break; + case OPT_MATCH_KEY: + if ( !sieve_opr_string_read(renv, address, &match_key) ) { + sieve_runtime_trace_error(renv, "invalid from operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + break; + case OPT_IMPORTANCE: + if ( !sieve_opr_number_read(renv, address, &importance) ) { + sieve_runtime_trace_error(renv, "invalid importance operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + /* Enforce 0 < importance < 4 (just to be sure) */ + if ( importance < 1 ) + importance = 1; + else if ( importance > 3 ) + importance = 3; + break; + default: + sieve_runtime_trace_error(renv, "unknown optional operand: %d", + opt_code); + return SIEVE_EXEC_BIN_CORRUPT; + } + } + } + + /* + * Perform operation + */ + + sieve_runtime_trace(renv, "DENOTIFY action"); + + return SIEVE_EXEC_OK; +} + + diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c index 39f55e57f851ec13df3d8ea4a541e79ba2ce37fe..39b7afa5fd6de23c032b5d9fc47b4252752d234f 100644 --- a/src/lib-sieve/plugins/notify/cmd-notify.c +++ b/src/lib-sieve/plugins/notify/cmd-notify.c @@ -72,9 +72,6 @@ static bool cmd_notify_validate_string_tag static bool cmd_notify_validate_stringlist_tag (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, struct sieve_command_context *cmd); -static bool cmd_notify_validate_importance_tag - (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, - struct sieve_command_context *cmd); /* Argument objects */ @@ -106,27 +103,6 @@ static const struct sieve_argument notify_message_tag = { NULL, NULL }; -static const struct sieve_argument notify_low_tag = { - "low", - NULL, NULL, - cmd_notify_validate_importance_tag, - NULL, NULL -}; - -static const struct sieve_argument notify_normal_tag = { - "normal", - NULL, NULL, - cmd_notify_validate_importance_tag, - NULL, NULL -}; - -static const struct sieve_argument notify_high_tag = { - "high", - NULL, NULL, - cmd_notify_validate_importance_tag, - NULL, NULL -}; - /* * Notify operation */ @@ -213,11 +189,11 @@ static bool cmd_notify_validate_string_tag /* Detach the tag itself */ *arg = sieve_ast_arguments_detach(*arg, 1); - /* Check syntax: - * :id <string> - * :method <string> - * :message <string> - */ + /* Check syntax: + * :id <string> + * :method <string> + * :message <string> + */ if ( !sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, SAAT_STRING) ) return FALSE; @@ -269,27 +245,6 @@ static bool cmd_notify_validate_stringlist_tag return TRUE; } -static bool cmd_notify_validate_importance_tag -(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg, - struct sieve_command_context *cmd ATTR_UNUSED) -{ - struct sieve_ast_argument *tag = *arg; - - if ( tag->argument == ¬ify_low_tag ) - sieve_ast_argument_number_substitute(tag, 3); - else if ( tag->argument == ¬ify_normal_tag ) - sieve_ast_argument_number_substitute(tag, 2); - else - sieve_ast_argument_number_substitute(tag, 1); - - tag->argument = &number_argument; - - /* Skip parameter */ - *arg = sieve_ast_argument_next(*arg); - - return TRUE; -} - /* * Command registration */ @@ -306,12 +261,7 @@ static bool cmd_notify_registered sieve_validator_register_tag (valdtr, cmd_reg, ¬ify_options_tag, OPT_OPTIONS); - sieve_validator_register_tag - (valdtr, cmd_reg, ¬ify_low_tag, OPT_IMPORTANCE); - sieve_validator_register_tag - (valdtr, cmd_reg, ¬ify_normal_tag, OPT_IMPORTANCE); - sieve_validator_register_tag - (valdtr, cmd_reg, ¬ify_high_tag, OPT_IMPORTANCE); + ext_notify_register_importance_tags(valdtr, cmd_reg, OPT_IMPORTANCE); return TRUE; } @@ -473,14 +423,14 @@ static void cmd_notify_construct_message string_t *out_msg) { const struct sieve_message_data *msgdata = renv->msgdata; - const char *p; + const char *p; - if ( msg_format == NULL ) + if ( msg_format == NULL ) msg_format = "$from$: $subject$"; /* Scan message for substitutions */ p = msg_format; - while ( *p != '\0' ) { + while ( *p != '\0' ) { const char *const *header; if ( strncasecmp(p, "$from$", 6) == 0 ) { @@ -491,11 +441,10 @@ static void cmd_notify_construct_message str_append(out_msg, header[0]); } else if ( strncasecmp(p, "$env-from$", 10) == 0 ) { - const char *from = sieve_message_get_sender(renv->msgctx); p += 10; - if ( from != NULL ) - str_append(out_msg, from); + if ( msgdata->return_path != NULL ) + str_append(out_msg, msgdata->return_path); } else if ( strncasecmp(p, "$subject$", 9) == 0 ) { p += 9; @@ -510,7 +459,7 @@ static void cmd_notify_construct_message const char *begin = p; bool valid = TRUE; - p += 5; + p += 5; if ( *p == '[' ) { p += 1; @@ -835,8 +784,10 @@ static bool contains_8bit(const char *msg) } static bool act_notify_send -(const struct sieve_action_exec_env *aenv, const struct ext_notify_action *act) +(const struct sieve_action_exec_env *aenv, + const struct ext_notify_action *act) { + const struct sieve_message_data *msgdata = aenv->msgdata; const struct sieve_script_env *senv = aenv->scriptenv; const struct ext_notify_recipient *recipients; void *smtp_handle; @@ -948,7 +899,7 @@ static bool act_notify_commit if ( strcasecmp(*hdsp, "no") != 0 ) { sieve_result_log(aenv, "not sending notification for auto-submitted message from <%s>", - str_sanitize(sieve_message_get_sender(aenv->msgctx), 128)); + str_sanitize(msgdata->return_path, 128)); return TRUE; } hdsp++; diff --git a/src/lib-sieve/plugins/notify/ext-notify-common.c b/src/lib-sieve/plugins/notify/ext-notify-common.c new file mode 100644 index 0000000000000000000000000000000000000000..1c4f8de8348a9b13bb5b1649d0bea9a9c1665785 --- /dev/null +++ b/src/lib-sieve/plugins/notify/ext-notify-common.c @@ -0,0 +1,77 @@ +/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file + */ + +#include "lib.h" + +#include "sieve-common.h" +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-commands.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" + +/* + * Importance argument + */ + +static bool tag_importance_validate + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd); + +static const struct sieve_argument importance_low_tag = { + "low", + NULL, NULL, + tag_importance_validate, + NULL, NULL +}; + +static const struct sieve_argument importance_normal_tag = { + "normal", + NULL, NULL, + tag_importance_validate, + NULL, NULL +}; + +static const struct sieve_argument importance_high_tag = { + "high", + NULL, NULL, + tag_importance_validate, + NULL, NULL +}; + +static bool tag_importance_validate +(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd ATTR_UNUSED) +{ + struct sieve_ast_argument *tag = *arg; + + if ( tag->argument == &importance_low_tag ) + sieve_ast_argument_number_substitute(tag, 3); + else if ( tag->argument == &importance_normal_tag ) + sieve_ast_argument_number_substitute(tag, 2); + else + sieve_ast_argument_number_substitute(tag, 1); + + tag->argument = &number_argument; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +void ext_notify_register_importance_tags +(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg, + unsigned int id_code) +{ + sieve_validator_register_tag(valdtr, cmd_reg, &importance_low_tag, id_code); + sieve_validator_register_tag(valdtr, cmd_reg, &importance_normal_tag, id_code); + sieve_validator_register_tag(valdtr, cmd_reg, &importance_high_tag, id_code); +} + diff --git a/src/lib-sieve/plugins/notify/ext-notify-common.h b/src/lib-sieve/plugins/notify/ext-notify-common.h index 8f07f5397c941acda768ecb7b5dadb8997400c28..de00e3442a8d30f3085fb2e58c657c8937bdd3a2 100644 --- a/src/lib-sieve/plugins/notify/ext-notify-common.h +++ b/src/lib-sieve/plugins/notify/ext-notify-common.h @@ -17,6 +17,14 @@ extern const struct sieve_extension notify_extension; extern const struct sieve_command cmd_notify_old; extern const struct sieve_command cmd_denotify; +/* + * Arguments + */ + +void ext_notify_register_importance_tags + (struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg, + unsigned int id_code); + /* * Operations */ diff --git a/src/lib-sieve/plugins/notify/ext-notify.c b/src/lib-sieve/plugins/notify/ext-notify.c index 95c3bbabd1c0ed337dcff91dcffb1a12e9b15f9a..749062a3fad6a6f0278450a7a647f3993e5838b3 100644 --- a/src/lib-sieve/plugins/notify/ext-notify.c +++ b/src/lib-sieve/plugins/notify/ext-notify.c @@ -7,15 +7,13 @@ * Authors: Stephan Bosch * Specification: draft-ietf-sieve-notify-00.txt * Implementation: deprecated; provided for backwards compatibility - * denotify command is explicitly not supported. * Status: deprecated * */ /* FIXME: Currently the following CMUSieve features are not supported: * - * 1) The denotify command is not supported and causes a compile error when used. - * 2) The $text$ substitution is not available for the :message argument. + * (*) The $text$ substitution is not available for the :message argument. */ #include <stdio.h>