From e34883258326119f41961dac357059227ab1f9d3 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Wed, 12 Nov 2008 17:05:48 +0100 Subject: [PATCH] Imap4flags: fixed bug in the handling of the internal variable. Previously the final value of internal variable was for every store action that didn't specify a :flags argument explicitly. This results in out-of order assignment/removal of flags, e.g. also the flags assigned keep actions that were executed before the addflag/setflag command were modified. --- .../plugins/imapflags/ext-imapflags-common.c | 7 +- src/lib-sieve/plugins/imapflags/tag-flags.c | 160 ++++++++++++------ src/lib-sieve/sieve-code.c | 24 ++- src/lib-sieve/sieve-code.h | 11 ++ src/lib-sieve/sieve-validator.c | 22 +-- 5 files changed, 159 insertions(+), 65 deletions(-) diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c index cfb76cbce..1fbc05c6d 100644 --- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c +++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c @@ -227,7 +227,12 @@ void ext_imapflags_attach_flags_tag */ /* Tag specified by user */ - sieve_validator_register_external_tag(valdtr, &tag_flags, command, -1); + sieve_validator_register_external_tag + (valdtr, &tag_flags, command, -1); + + /* Implicit tag if none is specified */ + sieve_validator_register_persistent_tag + (valdtr, &tag_flags_implicit, command); } /* diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c index db8cab61e..a77bdfd51 100644 --- a/src/lib-sieve/plugins/imapflags/tag-flags.c +++ b/src/lib-sieve/plugins/imapflags/tag-flags.c @@ -14,6 +14,7 @@ #include "sieve-generator.h" #include "sieve-interpreter.h" #include "sieve-actions.h" +#include "sieve-dump.h" #include "ext-imapflags-common.h" @@ -26,6 +27,8 @@ static bool tag_flags_validate (struct sieve_validator *validator, struct sieve_ast_argument **arg, struct sieve_command_context *cmd); +static bool tag_flags_validate_persistent + (struct sieve_validator *validator, struct sieve_command_context *cmd); static bool tag_flags_generate (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, struct sieve_command_context *cmd); @@ -38,6 +41,14 @@ const struct sieve_argument tag_flags = { tag_flags_generate }; +const struct sieve_argument tag_flags_implicit = { + "flags-implicit", + NULL, + tag_flags_validate_persistent, + NULL, NULL, + tag_flags_generate +}; + /* * Side effect */ @@ -49,6 +60,7 @@ static bool seff_flags_read_context (const struct sieve_side_effect *seffect, const struct sieve_runtime_env *renv, sieve_size_t *address, void **se_context); + static int seff_flags_merge (const struct sieve_runtime_env *renv, const struct sieve_action *action, const struct sieve_side_effect *seffect, @@ -92,6 +104,16 @@ const struct sieve_operand flags_side_effect_operand = { * Tag validation */ +static bool tag_flags_validate_persistent +(struct sieve_validator *validator ATTR_UNUSED, struct sieve_command_context *cmd) +{ + if ( sieve_command_find_argument(cmd, &tag_flags) == NULL ) { + sieve_command_add_dynamic_tag(cmd, &tag_flags_implicit, -1); + } + + return TRUE; +} + static bool tag_flags_validate (struct sieve_validator *validator, struct sieve_ast_argument **arg, struct sieve_command_context *cmd) @@ -132,13 +154,24 @@ static bool tag_flags_generate } sieve_opr_side_effect_emit(cgenv->sbin, &flags_side_effect); - - param = arg->parameters; - /* Call the generation function for the argument */ - if ( param->argument != NULL && param->argument->generate != NULL && - !param->argument->generate(cgenv, param, cmd) ) - return FALSE; + if ( arg->argument == &tag_flags ) { + /* Explicit :flags tag */ + param = arg->parameters; + + /* Call the generation function for the argument */ + if ( param->argument != NULL && param->argument->generate != NULL && + !param->argument->generate(cgenv, param, cmd) ) + return FALSE; + + } else if ( arg->argument == &tag_flags_implicit ) { + /* Implicit flags */ + sieve_opr_omitted_emit(cgenv->sbin); + + } else { + /* Something else?! */ + i_unreached(); + } return TRUE; } @@ -160,7 +193,57 @@ static bool seff_flags_dump_context (const struct sieve_side_effect *seffect ATTR_UNUSED, const struct sieve_dumptime_env *denv, sieve_size_t *address) { - return sieve_opr_stringlist_dump(denv, address, "flags"); + const struct sieve_operand *operand; + + operand = sieve_operand_read(denv->sbin, address); + + if ( sieve_operand_is_omitted(operand) ) { + sieve_code_dumpf(denv, "flags: INTERNAL"); + return TRUE; + } + + return sieve_opr_stringlist_dump_data(denv, operand, address, + "flags"); +} + +static struct seff_flags_context *seff_flags_get_implicit_context +(struct sieve_result *result) +{ + pool_t pool = sieve_result_pool(result); + struct seff_flags_context *ctx; + const char *flag; + struct ext_imapflags_iter flit; + + ctx = p_new(pool, struct seff_flags_context, 1); + p_array_init(&ctx->keywords, pool, 2); + + t_push(); + + /* Unpack */ + ext_imapflags_get_implicit_flags_init(&flit, result); + while ( (flag=ext_imapflags_iter_get_flag(&flit)) != NULL ) { + if (flag != NULL && *flag != '\\') { + /* keyword */ + const char *keyword = p_strdup(pool, flag); + array_append(&ctx->keywords, &keyword, 1); + } else { + /* system flag */ + if (flag == NULL || strcasecmp(flag, "\\flagged") == 0) + ctx->flags |= MAIL_FLAGGED; + else if (strcasecmp(flag, "\\answered") == 0) + ctx->flags |= MAIL_ANSWERED; + else if (strcasecmp(flag, "\\deleted") == 0) + ctx->flags |= MAIL_DELETED; + else if (strcasecmp(flag, "\\seen") == 0) + ctx->flags |= MAIL_SEEN; + else if (strcasecmp(flag, "\\draft") == 0) + ctx->flags |= MAIL_DRAFT; + } + } + + t_pop(); + + return ctx; } static bool seff_flags_read_context @@ -169,6 +252,8 @@ static bool seff_flags_read_context void **se_context) { bool result = TRUE; + sieve_size_t op_address = *address; + const struct sieve_operand *operand; pool_t pool = sieve_result_pool(renv->result); struct seff_flags_context *ctx; string_t *flags_item; @@ -178,9 +263,28 @@ static bool seff_flags_read_context p_array_init(&ctx->keywords, pool, 2); t_push(); + + /* Check whether explicit flag list operand is present */ + operand = sieve_operand_read(renv->sbin, address); + + if ( operand == NULL ) { + sieve_runtime_trace_error(renv, "invalid operand"); + t_pop(); + return FALSE; + } + + if ( sieve_operand_is_omitted(operand) ) { + /* Flag list is omitted, use current value of internal + * variable to construct side effect context. + */ + *se_context = seff_flags_get_implicit_context(renv->result); + t_pop(); + return TRUE; + } /* Read flag-list */ - if ( (flag_list=sieve_opr_stringlist_read(renv, address)) == NULL ) { + if ( (flag_list=sieve_opr_stringlist_read_data + (renv, operand, op_address, address)) == NULL ) { t_pop(); return FALSE; } @@ -225,46 +329,6 @@ static bool seff_flags_read_context return result; } -static struct seff_flags_context *seff_flags_get_implicit_context -(struct sieve_result *result) -{ - pool_t pool = sieve_result_pool(result); - struct seff_flags_context *ctx; - const char *flag; - struct ext_imapflags_iter flit; - - ctx = p_new(pool, struct seff_flags_context, 1); - p_array_init(&ctx->keywords, pool, 2); - - t_push(); - - /* Unpack */ - ext_imapflags_get_implicit_flags_init(&flit, result); - while ( (flag=ext_imapflags_iter_get_flag(&flit)) != NULL ) { - if (flag != NULL && *flag != '\\') { - /* keyword */ - const char *keyword = p_strdup(pool, flag); - array_append(&ctx->keywords, &keyword, 1); - } else { - /* system flag */ - if (flag == NULL || strcasecmp(flag, "\\flagged") == 0) - ctx->flags |= MAIL_FLAGGED; - else if (strcasecmp(flag, "\\answered") == 0) - ctx->flags |= MAIL_ANSWERED; - else if (strcasecmp(flag, "\\deleted") == 0) - ctx->flags |= MAIL_DELETED; - else if (strcasecmp(flag, "\\seen") == 0) - ctx->flags |= MAIL_SEEN; - else if (strcasecmp(flag, "\\draft") == 0) - ctx->flags |= MAIL_DRAFT; - } - } - - t_pop(); - - return ctx; -} - /* Result verification */ static int seff_flags_merge diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c index 7155f987b..11334944f 100644 --- a/src/lib-sieve/sieve-code.c +++ b/src/lib-sieve/sieve-code.c @@ -190,16 +190,12 @@ bool sieve_code_source_line_read * Core operands */ -const struct sieve_operand number_operand; -const struct sieve_operand string_operand; -const struct sieve_operand stringlist_operand; - extern const struct sieve_operand comparator_operand; extern const struct sieve_operand match_type_operand; extern const struct sieve_operand address_part_operand; const struct sieve_operand *sieve_operands[] = { - NULL, /* SIEVE_OPERAND_OPTIONAL */ + &omitted_operand, /* SIEVE_OPERAND_OPTIONAL */ &number_operand, &string_operand, &stringlist_operand, @@ -278,6 +274,17 @@ bool sieve_operand_optional_read /* * Operand definitions */ + +/* Omitted */ + +const struct sieve_operand_class omitted_class = + { "OMITTED" }; + +const struct sieve_operand omitted_operand = { + "@OMITTED", + NULL, SIEVE_OPERAND_OPTIONAL, + &omitted_class, NULL +}; /* Number */ @@ -352,6 +359,13 @@ const struct sieve_operand stringlist_operand = { /* * Operand implementations */ + +/* Omitted */ + +void sieve_opr_omitted_emit(struct sieve_binary *sbin) +{ + (void) sieve_operand_emit_code(sbin, &omitted_operand); +} /* Number */ diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h index 9f1be317b..8fb2aa901 100644 --- a/src/lib-sieve/sieve-code.h +++ b/src/lib-sieve/sieve-code.h @@ -98,6 +98,7 @@ const struct sieve_operand_class stringlist_class; /* Operand objects */ +extern const struct sieve_operand omitted_operand; extern const struct sieve_operand number_operand; extern const struct sieve_operand string_operand; extern const struct sieve_operand stringlist_operand; @@ -137,6 +138,16 @@ struct sieve_opr_stringlist_interface { * Core operand functions */ +/* Omitted */ + +void sieve_opr_omitted_emit(struct sieve_binary *sbin); + +static inline bool sieve_operand_is_omitted +(const struct sieve_operand *operand) +{ + return ( operand != NULL && operand == &omitted_operand ); +} + /* Number */ void sieve_opr_number_emit(struct sieve_binary *sbin, sieve_number_t number); diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 3a70e7cd0..0406373f2 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -830,19 +830,19 @@ static bool sieve_validate_command_arguments } /* Call initial validation for persistent arguments */ - if ( array_is_created(&cmd_reg->persistent_tags) ) { - unsigned int i; + if ( array_is_created(&cmd_reg->persistent_tags) ) { + unsigned int i; - for ( i = 0; i < array_count(&cmd_reg->persistent_tags); i++ ) { - struct sieve_tag_registration * const *reg = - array_idx(&cmd_reg->persistent_tags, i); + for ( i = 0; i < array_count(&cmd_reg->persistent_tags); i++ ) { + struct sieve_tag_registration * const *reg = + array_idx(&cmd_reg->persistent_tags, i); const struct sieve_argument *tag = (*reg)->tag; - - if ( tag != NULL && tag->validate_persistent != NULL ) { /* To be sure */ - if ( !tag->validate_persistent(validator, cmd) ) - return FALSE; - } - } + + if ( tag != NULL && tag->validate_persistent != NULL ) { /* To be sure */ + if ( !tag->validate_persistent(validator, cmd) ) + return FALSE; + } + } } return TRUE; -- GitLab