diff --git a/TODO b/TODO index e565a06260449c720d154fc22f1d2b7c94f89681..5f835262073ff15d333ef6f4f87da20cba7ea319 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ Next (in order of descending priority/precedence): * Review sieve-address parsing implementation for past-end checks * Improve handling of old/corrupt binaries. -* Move to 1.2 and start using mailbox_keyword_is_valid() and new const str. +* Move to 1.2 and start using and new const str. * Resolve problems in variables extension: scope uses hash the wrong way and extension ids are emitted directly. diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c index 575d02eeb9e00f7f3eee790ba5920fb4fe144fce..90d6ceddf86f35d8d073964415a865ec7c76c682 100644 --- a/src/lib-sieve/cmd-redirect.c +++ b/src/lib-sieve/cmd-redirect.c @@ -118,7 +118,7 @@ static bool cmd_redirect_validate /* We can only assess the validity of the outgoing address when it is * a string literal. For runtime-generated strings this needs to be - * done at runtime + * done at runtime (FIXME!) */ if ( sieve_argument_is_string_literal(arg) ) { string_t *address = sieve_ast_argument_str(arg); diff --git a/src/lib-sieve/plugins/imapflags/cmd-addflag.c b/src/lib-sieve/plugins/imapflags/cmd-addflag.c index 17c11aa02e8cbda99e1fd34d6b09662bd67c3168..d65fa1b7e35a46dc42a046f964f854c3c427031b 100644 --- a/src/lib-sieve/plugins/imapflags/cmd-addflag.c +++ b/src/lib-sieve/plugins/imapflags/cmd-addflag.c @@ -75,13 +75,9 @@ static bool cmd_addflag_operation_execute sieve_runtime_trace(renv, "ADDFLAG command"); - t_push(); - if ( !ext_imapflags_command_operands_read - (renv, address, &flag_list, &storage, &var_index) ) { - t_pop(); + (renv, address, &flag_list, &storage, &var_index) ) return FALSE; - } /* Iterate through all added flags */ while ( (result=sieve_coded_stringlist_next_item(flag_list, &flag_item)) && @@ -89,7 +85,5 @@ static bool cmd_addflag_operation_execute ext_imapflags_add_flags(renv, storage, var_index, flag_item); } - t_pop(); - return result; } diff --git a/src/lib-sieve/plugins/imapflags/cmd-removeflag.c b/src/lib-sieve/plugins/imapflags/cmd-removeflag.c index 1ccb4846d594e74393193e38471cd2b08203426e..c2cce08396411a6147f795687e8cfd5ef3dc5b25 100644 --- a/src/lib-sieve/plugins/imapflags/cmd-removeflag.c +++ b/src/lib-sieve/plugins/imapflags/cmd-removeflag.c @@ -76,21 +76,15 @@ static bool cmd_removeflag_operation_execute sieve_runtime_trace(renv, "REMOVEFLAG command"); - t_push(); - if ( !ext_imapflags_command_operands_read - (renv, address, &flag_list, &storage, &var_index) ) { - t_pop(); + (renv, address, &flag_list, &storage, &var_index) ) return FALSE; - } /* Iterate through all flags to remove */ while ( (result=sieve_coded_stringlist_next_item(flag_list, &flag_item)) && flag_item != NULL ) { ext_imapflags_remove_flags(renv, storage, var_index, flag_item); } - - t_pop(); return result; } diff --git a/src/lib-sieve/plugins/imapflags/cmd-setflag.c b/src/lib-sieve/plugins/imapflags/cmd-setflag.c index 74e03c6b86ae93d5d9bc9da793b648436d2ea5a6..2d166e974eb581c35d82659efefa3b4984ec6afd 100644 --- a/src/lib-sieve/plugins/imapflags/cmd-setflag.c +++ b/src/lib-sieve/plugins/imapflags/cmd-setflag.c @@ -74,13 +74,9 @@ static bool cmd_setflag_operation_execute sieve_runtime_trace(renv, "SETFLAG command"); - t_push(); - if ( !ext_imapflags_command_operands_read - (renv, address, &flag_list, &storage, &var_index) ) { - t_pop(); + (renv, address, &flag_list, &storage, &var_index) ) return FALSE; - } /* Iterate through all flags to set */ while ( (result=sieve_coded_stringlist_next_item(flag_list, &flag_item)) && @@ -88,8 +84,6 @@ static bool cmd_setflag_operation_execute ext_imapflags_set_flags(renv, storage, var_index, flag_item); } - t_pop(); - return result; } diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c index 3ebe325201b5d9978486032a7439a800c533000b..f8454f2ce6f187e3f423b51c5a2a5a9d83f9fa7d 100644 --- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c +++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c @@ -18,6 +18,12 @@ extern const struct sieve_argument tag_flags; extern const struct sieve_argument tag_flags_implicit; +/* + * Forward declarations + */ + +static bool flag_is_valid(const char *flag); + /* Common functions */ bool ext_imapflags_command_validate @@ -77,7 +83,7 @@ bool ext_imapflags_command_validate sieve_ast_argument_type(arg2) != SAAT_STRING_LIST ) { sieve_command_validate_error(validator, cmd, - "the %s %s command expects a string list (list of flags) as " + "the %s %s expects a string list (list of flags) as " "second argument when two arguments are specified, " "but %s was found", cmd->command->identifier, sieve_command_type_name(cmd->command), @@ -87,7 +93,28 @@ bool ext_imapflags_command_validate } else arg2 = arg; - return sieve_validator_argument_activate(validator, cmd, arg2, FALSE); + if ( !sieve_validator_argument_activate(validator, cmd, arg2, FALSE) ) + return FALSE; + + if ( cmd->command != &tst_hasflag && sieve_argument_is_string_literal(arg2) ) { + struct ext_imapflags_iter fiter; + const char *flag; + + /* Warn the user about validity of verifiable flags */ + ext_imapflags_iter_init(&fiter, sieve_ast_argument_str(arg)); + + while ( (flag=ext_imapflags_iter_get_flag(&fiter)) != NULL ) { + if ( !flag_is_valid(flag) ) { + sieve_command_validate_warning(validator, cmd, + "IMAP flag '%s' specified for the %s command is invalid " + "and will be ignored (only first invalid is reported)", + flag, cmd->command->identifier); + break; + } + } + } + + return TRUE; } bool ext_imapflags_command_operands_dump @@ -231,7 +258,13 @@ static bool flag_is_valid(const char *flag) return FALSE; } } else { - /* Custom keyword: currently nothing to validate */ + /* Custom keyword: + * + * The validity of the keyword cannot be validated until the + * target mailbox for the message is known. Meaning that the + * verfication of keyword can only be performed when the + * action side effect is about to be executed. + */ } return TRUE; diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h index 7be3b498dea2fc0fa1c23c442be41e2e854f49b9..3df0f58c02657363ccceaa278f65a7ff11596601 100644 --- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h +++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h @@ -18,6 +18,14 @@ enum ext_imapflags_opcode { EXT_IMAPFLAGS_OPERATION_HASFLAG }; +/* Commands */ + +extern const struct sieve_command cmd_setflag; +extern const struct sieve_command cmd_addflag; +extern const struct sieve_command cmd_removeflag; + +extern const struct sieve_command tst_hasflag; + bool ext_imapflags_command_validate (struct sieve_validator *validator, struct sieve_command_context *cmd); diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags.c b/src/lib-sieve/plugins/imapflags/ext-imapflags.c index 3a785f4281814e8b65c8ebf60074217afd13250a..c09afcafd5dfdcdb0b2aae4c13541b23bf0015ec 100644 --- a/src/lib-sieve/plugins/imapflags/ext-imapflags.c +++ b/src/lib-sieve/plugins/imapflags/ext-imapflags.c @@ -32,14 +32,6 @@ static bool ext_imapflags_validator_load(struct sieve_validator *valdtr); static bool ext_imapflags_runtime_load (const struct sieve_runtime_env *renv); -/* Commands */ - -extern const struct sieve_command cmd_setflag; -extern const struct sieve_command cmd_addflag; -extern const struct sieve_command cmd_removeflag; - -extern const struct sieve_command tst_hasflag; - /* Operations */ extern const struct sieve_operation setflag_operation; diff --git a/src/lib-sieve/plugins/imapflags/imapflags-errors.sieve b/src/lib-sieve/plugins/imapflags/imapflags-errors.sieve index c3fae9ac12ad97443807b47b5355c2b25c47636e..02400c919aee15c72fc19bc68a886b1000bcf472 100644 --- a/src/lib-sieve/plugins/imapflags/imapflags-errors.sieve +++ b/src/lib-sieve/plugins/imapflags/imapflags-errors.sieve @@ -1,4 +1,4 @@ -require "imapflags"; +require "imap4flags"; require "fileinto"; setflag; @@ -16,3 +16,5 @@ if hasflag 3 { if hasflag "flagvar" ["$MDNRequired", "\\Seen"] { removeflag "$MDNRequired"; } + +removeflag "\\frop"; diff --git a/src/lib-sieve/plugins/imapflags/imapflags.sieve b/src/lib-sieve/plugins/imapflags/imapflags.sieve index 53c0fdc18e9a6eefa38e4b7bf70c6fc86a2a4220..2503134b6a41f75358c9d96143166be3921845ad 100644 --- a/src/lib-sieve/plugins/imapflags/imapflags.sieve +++ b/src/lib-sieve/plugins/imapflags/imapflags.sieve @@ -25,4 +25,4 @@ if hasflag :count "ge" :comparator "i;ascii-numeric" "2" { fileinto "imap-twoflags"; } -fileinto :flags "MDNRequired \\Draft" "INBOX"; +fileinto :flags "MDNRequired \\Draft 3[\"]\\4" "INBOX"; diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c index 2b867fe2e00c494907998e7e2d23c6d76a3f78a4..e05fa43531b28a9e4bfe1157dc0e75c608533667 100644 --- a/src/lib-sieve/plugins/imapflags/tag-flags.c +++ b/src/lib-sieve/plugins/imapflags/tag-flags.c @@ -13,6 +13,8 @@ #include "ext-imapflags-common.h" +#include <ctype.h> + static bool tag_flags_validate (struct sieve_validator *validator, struct sieve_ast_argument **arg, struct sieve_command_context *cmd); @@ -274,7 +276,7 @@ static void seff_flags_print str_printfa(flags, " %s", *keyword); } - sieve_result_seffect_printf(rpenv, "add flags:%s", str_c(flags)); + sieve_result_seffect_printf(rpenv, "add IMAP flags:%s", str_c(flags)); } T_END; } } @@ -296,12 +298,32 @@ static bool seff_flags_pre_execute /* Assign mail keywords for subsequent mailbox_copy() */ if ( array_count(&ctx->keywords) > 0 ) { + unsigned int i; + if ( !array_is_created(&trans->keywords) ) { pool_t pool = sieve_result_pool(aenv->result); p_array_init(&trans->keywords, pool, 2); } - array_append_array(&trans->keywords, &ctx->keywords); + for ( i = 0; i < array_count(&ctx->keywords); i++ ) { + const char *const *keyword = array_idx(&ctx->keywords, i); + const char *kw_error; + + if ( trans->box != NULL && + mailbox_keyword_is_valid(trans->box, *keyword, &kw_error) ) + array_append(&trans->keywords, keyword, 1); + else { + char *error = ""; + if ( kw_error != NULL && *kw_error != '\0' ) { + error = t_strdup_noconst(kw_error); + error[0] = i_tolower(error[0]); + } + + sieve_result_warning(aenv, + "specified IMAP keyword '%s' is invalid (ignored): %s", + *keyword, error); + } + } } /* Assign mail flags for subsequent mailbox_copy() */ diff --git a/src/lib-sieve/plugins/imapflags/tst-hasflag.c b/src/lib-sieve/plugins/imapflags/tst-hasflag.c index d221bcf4145de050dd5f4afe18e7ab337fddfb66..9f1d55ee1fd41ba7cf3e70f66292e28a3169c760 100644 --- a/src/lib-sieve/plugins/imapflags/tst-hasflag.c +++ b/src/lib-sieve/plugins/imapflags/tst-hasflag.c @@ -188,14 +188,9 @@ static bool tst_hasflag_operation_execute } } - t_push(); - if ( !ext_imapflags_command_operands_read - (renv, address, &flag_list, &storage, &var_index) ) { - t_pop(); + (renv, address, &flag_list, &storage, &var_index) ) return FALSE; - } - matched = FALSE; mctx = sieve_match_begin(renv->interp, mtch, cmp, flag_list); @@ -209,8 +204,6 @@ static bool tst_hasflag_operation_execute matched = sieve_match_end(mctx) || matched; - t_pop(); - sieve_interpreter_set_test_result(renv->interp, matched); return TRUE; diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index 7e5b2ab2de138bfc71c5378d560b8fe17802920f..cb27d82c8ad6fdebc0a739ac7aae4a6ad27d8151 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -94,6 +94,8 @@ const char *sieve_command_type_name(const struct sieve_command *command); #define sieve_command_validate_error(validator, context, ...) \ sieve_validator_error(validator, (context)->ast_node, __VA_ARGS__) +#define sieve_command_validate_warning(validator, context, ...) \ + sieve_validator_warning(validator, (context)->ast_node, __VA_ARGS__) #define sieve_command_validate_critical(validator, context, ...) \ sieve_validator_critical(validator, (context)->ast_node, __VA_ARGS__) diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index 8382c4cdedefe68b03cbc60b31bdc7b6c393f074..c44c31ca5967e16d564ff6b06012071353f95b7e 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -157,6 +157,16 @@ void sieve_result_error va_end(args); } +void sieve_result_warning + (const struct sieve_action_exec_env *aenv, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + sieve_vwarning(aenv->result->ehandler, _get_location(aenv), fmt, args); + va_end(args); +} + void sieve_result_log (const struct sieve_action_exec_env *aenv, const char *fmt, ...) { diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h index 79f016e3e92c1d7fd0ad207cb9ae3085fa835751..e7860ab69d18a701db72c1b3f6c151dc6698f26b 100644 --- a/src/lib-sieve/sieve-result.h +++ b/src/lib-sieve/sieve-result.h @@ -40,6 +40,9 @@ bool sieve_result_print(struct sieve_result *result, struct ostream *stream); void sieve_result_log (const struct sieve_action_exec_env *aenv, const char *fmt, ...) ATTR_FORMAT(2, 3); +void sieve_result_warning + (const struct sieve_action_exec_env *aenv, const char *fmt, ...) + ATTR_FORMAT(2, 3); void sieve_result_error (const struct sieve_action_exec_env *aenv, const char *fmt, ...) ATTR_FORMAT(2, 3);