diff --git a/sieve/examples/vivil.sieve b/sieve/examples/vivil.sieve index 03f78b8ae4bce896ab2ac348251900e5212e3f16..bce750703b0755471fa9b1501e5112aa88213358 100644 --- a/sieve/examples/vivil.sieve +++ b/sieve/examples/vivil.sieve @@ -1,9 +1,10 @@ # Example Sieve Script # Author: Vivil # URL: http://wiki.fastmail.fm/index.php?title=Vivil +# Removed unused notify require # ************************************************************************* -require ["envelope", "fileinto", "reject", "notify", "vacation", "regex", "relational", +require ["envelope", "fileinto", "reject", "vacation", "regex", "relational", "comparator-i;ascii-numeric"]; diff --git a/sieve/tests/stop.sieve b/sieve/tests/stop.sieve new file mode 100644 index 0000000000000000000000000000000000000000..fe56f5ea1c5cd274b931aebbbf089c8cfdc00af4 --- /dev/null +++ b/sieve/tests/stop.sieve @@ -0,0 +1,10 @@ +require "fileinto"; + +if address :contains "from" "frop" { + fileinto "junk"; + stop; +} + +redirect "me@example.com"; + + diff --git a/src/lib-sieve/cmd-if.c b/src/lib-sieve/cmd-if.c index 9b196f829eaa35084b2a5b0776dbad34b066f4c8..6c09f0cae03e355bda92981c668ee78de5183d41 100644 --- a/src/lib-sieve/cmd-if.c +++ b/src/lib-sieve/cmd-if.c @@ -67,6 +67,7 @@ struct cmd_if_context_data { struct cmd_if_context_data *previous; struct cmd_if_context_data *next; + bool jump_generated; sieve_size_t exit_jump; }; @@ -80,6 +81,7 @@ static void cmd_if_initialize_context_data ctx_data->previous = previous; ctx_data->next = NULL; ctx_data->exit_jump = 0; + ctx_data->jump_generated = FALSE; if ( previous != NULL ) previous->next = ctx_data; @@ -131,7 +133,8 @@ static void cmd_if_resolve_exit_jumps struct cmd_if_context_data *if_ctx = ctx_data->previous; while ( if_ctx != NULL ) { - sieve_binary_resolve_offset(sbin, if_ctx->exit_jump); + if ( if_ctx->jump_generated ) + sieve_binary_resolve_offset(sbin, if_ctx->exit_jump); if_ctx = if_ctx->previous; } } @@ -156,9 +159,16 @@ static bool cmd_if_generate /* Are we the final command in this if-elsif-else structure? */ if ( ctx_data->next != NULL ) { - /* No, generate jump to end of if-elsif-else structure (resolved later) */ - sieve_operation_emit_code(sbin, SIEVE_OPCODE_JMP); - ctx_data->exit_jump = sieve_binary_emit_offset(sbin, 0); + /* No, generate jump to end of if-elsif-else structure (resolved later) + * This of course is not necessary if the {} block contains a command + * like stop at top level that unconditionally exits the block already + * anyway. + */ + if ( !sieve_command_block_exits_unconditionally(ctx) ) { + sieve_operation_emit_code(sbin, SIEVE_OPCODE_JMP); + ctx_data->exit_jump = sieve_binary_emit_offset(sbin, 0); + ctx_data->jump_generated = TRUE; + } } else { /* Yes, Resolve previous exit jumps to this point */ cmd_if_resolve_exit_jumps(sbin, ctx_data); diff --git a/src/lib-sieve/sieve-commands.c b/src/lib-sieve/sieve-commands.c index 9f063177eb32861af73c842d5904d8723398f11d..69eef6e01182ea05d4f0eeb5d8450143622b42f8 100644 --- a/src/lib-sieve/sieve-commands.c +++ b/src/lib-sieve/sieve-commands.c @@ -138,6 +138,9 @@ static const struct sieve_command tst_true = { static bool cmd_stop_generate (struct sieve_generator *generator, struct sieve_command_context *ctx ATTR_UNUSED); +static bool cmd_stop_validate + (struct sieve_validator *validator, struct sieve_command_context *ctx); + static bool cmd_keep_generate (struct sieve_generator *generator, struct sieve_command_context *ctx ATTR_UNUSED); @@ -149,7 +152,8 @@ static const struct sieve_command cmd_stop = { "stop", SCT_COMMAND, 0, 0, FALSE, FALSE, - NULL, NULL, NULL, + NULL, NULL, + cmd_stop_validate, cmd_stop_generate, NULL }; @@ -193,7 +197,7 @@ const unsigned int sieve_core_commands_count = N_ELEMENTS(sieve_core_commands); /* Command context */ -struct sieve_command_context *sieve_command_prev_context +inline struct sieve_command_context *sieve_command_prev_context (struct sieve_command_context *context) { struct sieve_ast_node *node = sieve_ast_node_prev(context->ast_node); @@ -205,6 +209,18 @@ struct sieve_command_context *sieve_command_prev_context return NULL; } +inline struct sieve_command_context *sieve_command_parent_context + (struct sieve_command_context *context) +{ + struct sieve_ast_node *node = sieve_ast_node_parent(context->ast_node); + + if ( node != NULL ) { + return node->context; + } + + return NULL; +} + struct sieve_command_context *sieve_command_context_create (struct sieve_ast_node *cmd_node, const struct sieve_command *command) { @@ -215,6 +231,8 @@ struct sieve_command_context *sieve_command_context_create cmd->ast_node = cmd_node; cmd->command = command; + cmd->block_exit_command = NULL; + return cmd; } @@ -229,8 +247,33 @@ const char *sieve_command_type_name(const struct sieve_command *command) { return "??COMMAND-TYPE??"; } +inline void sieve_command_exit_block_unconditionally + (struct sieve_command_context *cmd) +{ + struct sieve_command_context *parent = sieve_command_parent_context(cmd); + + /* Only the first unconditional exit is of importance */ + if ( parent != NULL && parent->block_exit_command == NULL ) + parent->block_exit_command = cmd; +} + +inline bool sieve_command_block_exits_unconditionally + (struct sieve_command_context *cmd) +{ + return ( cmd->block_exit_command != NULL ); +} + /* Code generation for trivial commands and tests */ +static bool cmd_stop_validate + (struct sieve_validator *validator ATTR_UNUSED, + struct sieve_command_context *ctx) +{ + sieve_command_exit_block_unconditionally(ctx); + + return TRUE; +} + static bool cmd_stop_generate (struct sieve_generator *generator, struct sieve_command_context *ctx ATTR_UNUSED) diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index bc41804e8bc97b024bdb09b51f6efd6ed9c8b1c4..a88a8ef23975a3613e59777791ec159be75946a7 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -70,9 +70,12 @@ struct sieve_command_context { /* The ast node of this command */ struct sieve_ast_node *ast_node; - /* First positional argument */ + /* First positional argument, found during argument validation */ struct sieve_ast_argument *first_positional; + /* The child ast node that unconditionally exits this command's block */ + struct sieve_command_context *block_exit_command; + /* Command-specific context data*/ void *data; }; @@ -95,7 +98,14 @@ const char *sieve_command_type_name(const struct sieve_command *command); #define sieve_command_is_first(context) \ ( sieve_ast_node_prev((context)->ast_node) == NULL ) -struct sieve_command_context *sieve_command_prev_context +inline struct sieve_command_context *sieve_command_prev_context (struct sieve_command_context *context); +inline struct sieve_command_context *sieve_command_parent_context + (struct sieve_command_context *context); + +inline void sieve_command_exit_block_unconditionally + (struct sieve_command_context *cmd); +inline bool sieve_command_block_exits_unconditionally + (struct sieve_command_context *cmd); #endif /* __SIEVE_COMMANDS_H */ diff --git a/src/lib-sieve/sieve-generator.c b/src/lib-sieve/sieve-generator.c index 180ed5b744a656e7ef3c392840d744323ba9b95c..d295bd132871aac84078d3e28d88edc2177e1c1a 100644 --- a/src/lib-sieve/sieve-generator.c +++ b/src/lib-sieve/sieve-generator.c @@ -186,7 +186,8 @@ bool sieve_generate_test return TRUE; } -static bool sieve_generate_command(struct sieve_generator *generator, struct sieve_ast_node *cmd_node) +static bool sieve_generate_command + (struct sieve_generator *generator, struct sieve_ast_node *cmd_node) { i_assert( cmd_node->context != NULL && cmd_node->context->command != NULL ); @@ -197,7 +198,8 @@ static bool sieve_generate_command(struct sieve_generator *generator, struct sie return TRUE; } -bool sieve_generate_block(struct sieve_generator *generator, struct sieve_ast_node *block) +bool sieve_generate_block + (struct sieve_generator *generator, struct sieve_ast_node *block) { struct sieve_ast_node *command; diff --git a/src/lib-sieve/sieve-generator.h b/src/lib-sieve/sieve-generator.h index 47606e85393fc4bcedf18d3065cf852ac74da6c0..217befe16b35d38ef7ee25d3d08bea9b72c99fe6 100644 --- a/src/lib-sieve/sieve-generator.h +++ b/src/lib-sieve/sieve-generator.h @@ -57,9 +57,11 @@ inline void sieve_generator_register_extension bool sieve_generate_arguments(struct sieve_generator *generator, struct sieve_command_context *cmd, struct sieve_ast_argument **arg); -bool sieve_generate_block(struct sieve_generator *generator, struct sieve_ast_node *block); -bool sieve_generate_test(struct sieve_generator *generator, struct sieve_ast_node *tst_node, - struct sieve_jumplist *jlist, bool jump_true); +bool sieve_generate_block + (struct sieve_generator *generator, struct sieve_ast_node *block); +bool sieve_generate_test + (struct sieve_generator *generator, struct sieve_ast_node *tst_node, + struct sieve_jumplist *jlist, bool jump_true); struct sieve_binary *sieve_generator_run(struct sieve_generator *genarator); #endif /* __SIEVE_GENERATOR_H */