diff --git a/Makefile.am b/Makefile.am index ca86a326e6e7e5c1ac85d78ff76b2d8430c6d592..8f05f1a8463f2005dea8390110a721ae66c56c1c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,7 @@ test_cases = \ tests/extensions/include/errors.svtest \ tests/extensions/imapflags/basic.svtest \ tests/extensions/imapflags/hasflag.svtest \ + tests/extensions/imapflags/execute.svtest \ tests/extensions/body/basic.svtest \ tests/extensions/body/match-values.svtest \ tests/extensions/regex/basic.svtest \ diff --git a/TODO b/TODO index 14d62bdb87892640d942c2fb08e303d63831902a..1745b4462c5681c9e609e4bcc968613998402d6d 100644 --- a/TODO +++ b/TODO @@ -2,9 +2,6 @@ Next (in order of descending priority/precedence): * Fix standards compliance issues: - Body: contains various bugs that need to be resolved for standards compliance. - - Imapflags: when keep/fileinto is used multiple times in a script and - duplicate message elimination is performed, the last flag list value - MUST win. - 'If an address is not syntactically valid, then it will not be matched by tests specifying ":localpart" or ":domain"'. - Vacation: If the Sieve variables extension is used, the arguments diff --git a/src/lib-sieve/cmd-keep.c b/src/lib-sieve/cmd-keep.c index 537ce6f6a33f83e1d0e2202475c7dbf97004dae8..88dc8f3d13d62c7544d0892cbc7065ec169328f3 100644 --- a/src/lib-sieve/cmd-keep.c +++ b/src/lib-sieve/cmd-keep.c @@ -66,7 +66,8 @@ static bool cmd_keep_generate /* Emit line number */ sieve_code_source_line_emit(cgenv->sbin, sieve_command_source_line(ctx)); - return TRUE; + /* Generate arguments */ + return sieve_generate_arguments(cgenv, ctx, NULL); } /* diff --git a/src/lib-sieve/plugins/copy/ext-copy.c b/src/lib-sieve/plugins/copy/ext-copy.c index ba90cbc4475efd6810343ceb73d3086d57a0bf54..2548c8aa7d14fe29b2c3126c5068a7cea78a28bd 100644 --- a/src/lib-sieve/plugins/copy/ext-copy.c +++ b/src/lib-sieve/plugins/copy/ext-copy.c @@ -84,7 +84,7 @@ static bool seff_copy_post_commit const struct sieve_side_effect copy_side_effect = { SIEVE_OBJECT("copy", ©_side_effect_operand, 0), &act_store, - NULL, NULL, + NULL, NULL, NULL, seff_copy_print, NULL, NULL, seff_copy_post_commit, diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c index a8b9abeee0b042588fbec51fadbdea792ececebd..5eac559634a86d072e3f9e3d094742bdb878818a 100644 --- a/src/lib-sieve/plugins/imapflags/tag-flags.c +++ b/src/lib-sieve/plugins/imapflags/tag-flags.c @@ -49,6 +49,10 @@ 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, + void **old_context, void *new_context); static void seff_flags_print (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_result_print_env *rpenv, void *se_context, bool *keep); @@ -63,6 +67,7 @@ const struct sieve_side_effect flags_side_effect = { seff_flags_dump_context, seff_flags_read_context, + seff_flags_merge, seff_flags_print, seff_flags_pre_execute, NULL, NULL, NULL @@ -260,6 +265,19 @@ static struct seff_flags_context *seff_flags_get_implicit_context return ctx; } +/* Result verification */ + +static int seff_flags_merge +(const struct sieve_runtime_env *renv ATTR_UNUSED, + const struct sieve_action *action ATTR_UNUSED, + const struct sieve_side_effect *seffect ATTR_UNUSED, + void **old_context, void *new_context) +{ + *old_context = new_context; + + return 1; +} + /* Result printing */ static void seff_flags_print diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h index f845f14b0d503d5656fa3caf3e6b77683af64bd1..915aca84290d1118306ede69af330e8625011d4a 100644 --- a/src/lib-sieve/sieve-actions.h +++ b/src/lib-sieve/sieve-actions.h @@ -82,8 +82,9 @@ struct sieve_side_effect { struct sieve_object object; /* The action it is supposed to link to */ - const struct sieve_action *to_action; + const struct sieve_action *to_action; + /* Context coding */ bool (*dump_context) @@ -96,8 +97,11 @@ struct sieve_side_effect { /* Result verification */ - /* ... */ - + int (*merge) + (const struct sieve_runtime_env *renv, const struct sieve_action *action, + const struct sieve_side_effect *seffect, + void **old_context, void *new_context); + /* Result printing */ void (*print) diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c index 937ea5652425faf40eeddba23ebe2b3fc8dec395..afac539c9f8cfdc6a4df506b2fc9ffcc9cece5b5 100644 --- a/src/lib-sieve/sieve-generator.c +++ b/src/lib-sieve/sieve-generator.c @@ -272,6 +272,10 @@ bool sieve_generate_arguments arg = sieve_ast_argument_next(arg); } + + /* Mark end of optional list if it is still open */ + if ( state == ARG_OPTIONAL ) + sieve_binary_emit_byte(cgenv->sbin, 0); if ( last_arg != NULL ) *last_arg = arg; diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index e778286393919609e39357b4a942242926d33cfb..c2c1f902981a12979edff7fb2e57f9c35a970a44 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -225,6 +225,87 @@ void sieve_result_add_implicit_side_effect sieve_side_effects_list_add(actctx->seffects, seffect, context); } +static int sieve_result_side_effects_merge +(const struct sieve_runtime_env *renv, const struct sieve_action *action, + struct sieve_side_effects_list *old_seffects, + struct sieve_side_effects_list *new_seffects) +{ + int ret; + struct sieve_result_side_effect *rsef, *nrsef; + + /* Allow side-effects to merge with existing copy */ + + /* Merge existing side effects */ + rsef = old_seffects != NULL ? old_seffects->first_effect : NULL; + while ( rsef != NULL ) { + const struct sieve_side_effect *seffect = rsef->seffect; + bool found = FALSE; + + if ( seffect->merge != NULL ) { + + /* Try to find it among the new */ + nrsef = new_seffects != NULL ? new_seffects->first_effect : NULL; + while ( nrsef != NULL ) { + if ( nrsef->seffect == seffect ) { + if ( seffect->merge + (renv, action, seffect, &rsef->context, nrsef->context) < 0 ) + return -1; + + found = TRUE; + break; + } + + nrsef = nrsef->next; + } + + /* Not found? */ + if ( !found && seffect->merge + (renv, action, seffect, &rsef->context, NULL) < 0 ) + return -1; + } + + rsef = rsef->next; + } + + /* Merge new Side effects */ + nrsef = new_seffects != NULL ? new_seffects->first_effect : NULL; + while ( nrsef != NULL ) { + const struct sieve_side_effect *seffect = nrsef->seffect; + bool found = FALSE; + + if ( seffect->merge != NULL ) { + + /* Try to find it in among the exising */ + rsef = old_seffects != NULL ? old_seffects->first_effect : NULL; + while ( rsef != NULL ) { + if ( rsef->seffect == seffect ) { + found = TRUE; + break; + } + rsef = rsef->next; + } + + /* Not found? */ + if ( !found ) { + void *new_context = NULL; + + if ( (ret=seffect->merge + (renv, action, seffect, &new_context, nrsef->context)) < 0 ) + return -1; + + if ( ret != 0 ) { + /* Add side effect */ + sieve_side_effects_list_add(new_seffects, seffect, new_context); + } + } + } + + nrsef = nrsef->next; + } + + return 1; +} + int sieve_result_add_action (const struct sieve_runtime_env *renv, const struct sieve_action *action, struct sieve_side_effects_list *seffects, @@ -249,10 +330,15 @@ int sieve_result_add_action if ( action->check_duplicate != NULL ) { if ( (ret=action->check_duplicate (renv, action, context, raction->context, - location, raction->location)) != 0 ) + location, raction->location)) < 0 ) return ret; - } else - return 1; + + /* Duplicate */ + if ( ret == 1 ) { + return sieve_result_side_effects_merge + (renv, action, raction->seffects, seffects); + } + } } else { /* Check conflict */ if ( action->check_conflict != NULL && @@ -270,14 +356,15 @@ int sieve_result_add_action /* Check policy limit on total number of actions */ if ( sieve_max_actions > 0 && result->action_count >= sieve_max_actions ) { - sieve_runtime_error(renv, location, "total number of actions exceeds policy limit"); + sieve_runtime_error(renv, location, + "total number of actions exceeds policy limit"); return -1; } /* Check policy limit on number of this class of actions */ if ( instance_limit > 0 && instance_count >= instance_limit ) { - sieve_runtime_error(renv, location, "number of %s actions exceeds policy limit", - action->name); + sieve_runtime_error(renv, location, + "number of %s actions exceeds policy limit", action->name); return -1; }