diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c index 1ecfa9f75680fdc68952dc1dafad3ded8544f1ff..79e6a40242e06c64031d83519f61f204d31a7bfd 100644 --- a/src/lib-sieve/sieve-address-parts.c +++ b/src/lib-sieve/sieve-address-parts.c @@ -27,9 +27,10 @@ */ static void opr_address_part_emit - (struct sieve_binary *sbin, struct sieve_address_part *addrp); + (struct sieve_binary *sbin, const struct sieve_address_part *addrp); static void opr_address_part_emit_ext - (struct sieve_binary *sbin, struct sieve_address_part *addrp, int ext_id); + (struct sieve_binary *sbin, const struct sieve_address_part *addrp, + int ext_id); /* * Address-part 'extension' @@ -193,43 +194,39 @@ struct sieve_operand address_part_operand = */ static bool tag_address_part_is_instance_of - (struct sieve_validator *validator, const char *tag) +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg) { - return sieve_address_part_find(validator, tag, NULL) != NULL; + int ext_id; + struct sieve_address_part_context *adpctx; + const struct sieve_address_part *addrp = sieve_address_part_find + (validator, sieve_ast_argument_tag(arg), &ext_id); + + if ( addrp == NULL ) return FALSE; + + adpctx = p_new(sieve_command_pool(cmd), struct sieve_address_part_context, 1); + adpctx->command_ctx = cmd; + adpctx->address_part = addrp; + adpctx->ext_id = ext_id; + + /* Store address-part in context */ + arg->context = (void *) adpctx; + + return TRUE; } static bool tag_address_part_validate - (struct sieve_validator *validator, - struct sieve_ast_argument **arg, - struct sieve_command_context *cmd) +(struct sieve_validator *validator ATTR_UNUSED, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd ATTR_UNUSED) { - int ext_id; - const struct sieve_address_part *addrp; - + /* FIXME: Currenly trivial, but might need to allow for further validation for + * future extensions. + */ + /* Syntax: * ":localpart" / ":domain" / ":all" (subject to extension) */ - /* Get address_part from registry */ - addrp = sieve_address_part_find - (validator, sieve_ast_argument_tag(*arg), &ext_id); - - /* In theory, addrp can never be NULL, because we must have found it earlier - * to get here. - */ - if ( addrp == NULL ) { - sieve_command_validate_error(validator, cmd, - "unknown address-part modifier '%s' " - "(this error should not occur and is probably a bug)", - sieve_ast_argument_strc(*arg)); - - return FALSE; - } - - /* Store address-part in context */ - (*arg)->context = (void *) addrp; - (*arg)->ext_id = ext_id; - /* Skip tag */ *arg = sieve_ast_argument_next(*arg); @@ -239,14 +236,14 @@ static bool tag_address_part_validate /* Code generation */ static void opr_address_part_emit - (struct sieve_binary *sbin, struct sieve_address_part *addrp) +(struct sieve_binary *sbin, const struct sieve_address_part *addrp) { (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_ADDRESS_PART); (void) sieve_binary_emit_byte(sbin, addrp->code); } static void opr_address_part_emit_ext - (struct sieve_binary *sbin, struct sieve_address_part *addrp, int ext_id) +(struct sieve_binary *sbin, const struct sieve_address_part *addrp, int ext_id) { unsigned char addrp_code = SIEVE_ADDRESS_PART_CUSTOM + sieve_binary_extension_get_index(sbin, ext_id); @@ -321,8 +318,9 @@ static bool tag_address_part_generate struct sieve_command_context *cmd ATTR_UNUSED) { struct sieve_binary *sbin = sieve_generator_get_binary(generator); - struct sieve_address_part *addrp = - (struct sieve_address_part *) arg->context; + struct sieve_address_part_context *adpctx = + (struct sieve_address_part_context *) arg->context; + const struct sieve_address_part *addrp = adpctx->address_part; if ( addrp->extension == NULL ) { if ( addrp->code < SIEVE_ADDRESS_PART_CUSTOM ) @@ -330,7 +328,7 @@ static bool tag_address_part_generate else return FALSE; } else { - opr_address_part_emit_ext(sbin, addrp, arg->ext_id); + opr_address_part_emit_ext(sbin, addrp, adpctx->ext_id); } return TRUE; diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h index 1049e608c62902d0db28b1bee19f847ab4eb0ea2..12368faf324439242f8563958e4b67613f9a4fd7 100644 --- a/src/lib-sieve/sieve-address-parts.h +++ b/src/lib-sieve/sieve-address-parts.h @@ -36,6 +36,13 @@ struct sieve_address_part_extension { (unsigned int code); }; +struct sieve_address_part_context { + struct sieve_command_context *command_ctx; + const struct sieve_address_part *address_part; + + int ext_id; +}; + void sieve_address_parts_link_tags (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, int id_code); diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index 101c9d6f9b9f15ebdb074a66a14f1c5f0171bfe5..1cbfcbefd2595024c92172bd6ccffcc2c5df2455 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -89,9 +89,6 @@ struct sieve_ast_argument { /* Context data associated with this ast element */ void *context; - - /* Indicates whether this argument is part of which extension */ - int ext_id; }; struct sieve_ast_list { diff --git a/src/lib-sieve/sieve-commands.c b/src/lib-sieve/sieve-commands.c index 675557c5fc561acde48e4d029f612337f08cf35d..0ab71477d0561a77f243218619bda5ba43987612 100644 --- a/src/lib-sieve/sieve-commands.c +++ b/src/lib-sieve/sieve-commands.c @@ -195,7 +195,8 @@ inline struct sieve_command_context *sieve_command_parent_context } struct sieve_command_context *sieve_command_context_create - (struct sieve_ast_node *cmd_node, const struct sieve_command *command) + (struct sieve_ast_node *cmd_node, const struct sieve_command *command, + struct sieve_command_registration *reg) { struct sieve_command_context *cmd; @@ -203,6 +204,7 @@ struct sieve_command_context *sieve_command_context_create cmd->ast_node = cmd_node; cmd->command = command; + cmd->cmd_reg = reg; cmd->block_exit_command = NULL; diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index bd86026b3f9e9bb44f6868b8e9323fc1d24969d8..36ce0b0ac569930052e3ae2b9171ad46795e8fbb 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -11,17 +11,20 @@ struct sieve_argument { const char *identifier; - bool (*is_instance_of)(struct sieve_validator *validator, const char *tag); + bool (*is_instance_of) + (struct sieve_validator *validator, struct sieve_command_context *cmdctx, + struct sieve_ast_argument *arg); bool (*validate) - (struct sieve_validator *validator, struct sieve_ast_argument **arg, - struct sieve_command_context *context); + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *context); bool (*validate_context) - (struct sieve_validator *validator, struct sieve_ast_argument *arg, - struct sieve_command_context *context); + (struct sieve_validator *validator, struct sieve_ast_argument *arg, + struct sieve_command_context *context); - bool (*generate)(struct sieve_generator *generator, struct sieve_ast_argument *arg, - struct sieve_command_context *context); + bool (*generate) + (struct sieve_generator *generator, struct sieve_ast_argument *arg, + struct sieve_command_context *context); }; extern const struct sieve_argument number_argument; @@ -62,7 +65,7 @@ struct sieve_command { struct sieve_command_context { const struct sieve_command *command; - /* The registration of this command in the validator */ + /* The registration of this command in the validator (sieve-validator.h) */ struct sieve_command_registration *cmd_reg; /* The ast node of this command */ @@ -79,7 +82,8 @@ struct sieve_command_context { }; struct sieve_command_context *sieve_command_context_create - (struct sieve_ast_node *cmd_node, const struct sieve_command *command); + (struct sieve_ast_node *cmd_node, const struct sieve_command *command, + struct sieve_command_registration *reg); const char *sieve_command_type_name(const struct sieve_command *command); diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c index 234d0916ad65ed655dc2d66580a2b45504b7c050..341196ac8e3dda3590ada78838edf0628b96e05c 100644 --- a/src/lib-sieve/sieve-comparators.c +++ b/src/lib-sieve/sieve-comparators.c @@ -26,9 +26,9 @@ extern const struct sieve_comparator *sieve_core_comparators[]; extern const unsigned int sieve_core_comparators_count; static void opr_comparator_emit - (struct sieve_binary *sbin, struct sieve_comparator *cmp); + (struct sieve_binary *sbin, const struct sieve_comparator *cmp); static void opr_comparator_emit_ext - (struct sieve_binary *sbin, struct sieve_comparator *cmp, int ext_id); + (struct sieve_binary *sbin, const struct sieve_comparator *cmp, int ext_id); static int cmp_i_octet_compare (const struct sieve_comparator *cmp, @@ -217,6 +217,7 @@ static bool tag_comparator_validate struct sieve_command_context *cmd) { int ext_id; + struct sieve_comparator_context *cmpctx; struct sieve_ast_argument *tag = *arg; const struct sieve_comparator *cmp; @@ -244,12 +245,19 @@ static bool tag_comparator_validate return FALSE; } - /* String argument not needed during code generation, so detach it from argument list */ + /* String argument not needed during code generation, so detach it from + * argument list + */ *arg = sieve_ast_arguments_detach(*arg, 1); + /* Create context */ + cmpctx = p_new(sieve_command_pool(cmd), struct sieve_comparator_context, 1); + cmpctx->command_ctx = cmd; + cmpctx->comparator = cmp; + cmpctx->ext_id = ext_id; + /* Store comparator in context */ - tag->context = (void *) cmp; - tag->ext_id = ext_id; + tag->context = (void *) cmpctx; return TRUE; } @@ -280,14 +288,14 @@ inline const struct sieve_comparator *sieve_comparator_tag_get /* Code generation */ static void opr_comparator_emit - (struct sieve_binary *sbin, struct sieve_comparator *cmp) + (struct sieve_binary *sbin, const struct sieve_comparator *cmp) { (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_COMPARATOR); (void) sieve_binary_emit_byte(sbin, cmp->code); } static void opr_comparator_emit_ext - (struct sieve_binary *sbin, struct sieve_comparator *cmp, int ext_id) + (struct sieve_binary *sbin, const struct sieve_comparator *cmp, int ext_id) { unsigned char cmp_code = SIEVE_COMPARATOR_CUSTOM + sieve_binary_extension_get_index(sbin, ext_id); @@ -361,7 +369,9 @@ static bool tag_comparator_generate struct sieve_command_context *cmd ATTR_UNUSED) { struct sieve_binary *sbin = sieve_generator_get_binary(generator); - struct sieve_comparator *cmp = (struct sieve_comparator *) arg->context; + struct sieve_comparator_context *cmpctx = + (struct sieve_comparator_context *) arg->context; + const struct sieve_comparator *cmp = cmpctx->comparator; if ( cmp->extension == NULL ) { if ( cmp->code < SIEVE_COMPARATOR_CUSTOM ) @@ -369,7 +379,7 @@ static bool tag_comparator_generate else return FALSE; } else { - opr_comparator_emit_ext(sbin, cmp, arg->ext_id); + opr_comparator_emit_ext(sbin, cmp, cmpctx->ext_id); } return TRUE; diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h index 340fc50cd197238f82ec00ea8593b1f288bf803a..61016ded7799299404edbd9865b7dae93fc63300 100644 --- a/src/lib-sieve/sieve-comparators.h +++ b/src/lib-sieve/sieve-comparators.h @@ -51,6 +51,13 @@ struct sieve_comparator_extension { (unsigned int code); }; +struct sieve_comparator_context { + struct sieve_command_context *command_ctx; + const struct sieve_comparator *comparator; + + int ext_id; +}; + extern const struct sieve_argument comparator_tag; void sieve_comparators_link_tag diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c index b2e013c43dd5410f1b64fb7fc393cca3342b14b7..967948309b66a0c499ce83abbc4215fb403d5f01 100644 --- a/src/lib-sieve/sieve-match-types.c +++ b/src/lib-sieve/sieve-match-types.c @@ -191,48 +191,39 @@ struct sieve_operand match_type_operand = */ static bool tag_match_type_is_instance_of - (struct sieve_validator *validator, const char *tag) -{ - return sieve_match_type_find(validator, tag, NULL) != NULL; -} - -static bool tag_match_type_validate - (struct sieve_validator *validator, - struct sieve_ast_argument **arg, - struct sieve_command_context *cmd) +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg) { int ext_id; struct sieve_match_type_context *mtctx; - const struct sieve_match_type *mtch; - - /* Syntax: - * ":is" / ":contains" / ":matches" (subject to extension) - */ - - /* Get match_type from registry */ - mtch = sieve_match_type_find - (validator, sieve_ast_argument_tag(*arg), &ext_id); - - /* In theory, mtch can never be NULL, because we must have found it earlier - * to get here. - */ - if ( mtch == NULL ) { - sieve_command_validate_error(validator, cmd, - "unknown match-type modifier '%s' " - "(this error should not occur and is probably a bug)", - sieve_ast_argument_strc(*arg)); - - return FALSE; - } - + const struct sieve_match_type *mtch = + sieve_match_type_find(validator, sieve_ast_argument_tag(arg), &ext_id); + + if ( mtch == NULL ) return FALSE; + /* Create context */ mtctx = p_new(sieve_command_pool(cmd), struct sieve_match_type_context, 1); mtctx->match_type = mtch; + mtctx->ext_id = ext_id; mtctx->command_ctx = cmd; - (*arg)->context = (void *) mtctx; - (*arg)->ext_id = ext_id; + arg->context = (void *) mtctx; + return TRUE; +} + +static bool tag_match_type_validate +(struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd ATTR_UNUSED) +{ + struct sieve_match_type_context *mtctx = + (struct sieve_match_type_context *) (*arg)->context; + const struct sieve_match_type *mtch = mtctx->match_type; + + /* Syntax: + * ":is" / ":contains" / ":matches" (subject to extension) + */ + /* Skip tag */ *arg = sieve_ast_argument_next(*arg); @@ -378,7 +369,7 @@ static bool tag_match_type_generate else return FALSE; } else { - opr_match_type_emit_ext(sbin, mtctx->match_type, arg->ext_id); + opr_match_type_emit_ext(sbin, mtctx->match_type, mtctx->ext_id); } return TRUE; diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h index df976a090c0b6b20e5563529c75e2fab5d9b45b7..810992897e137bdb316b3221cc8a22d6b0b4639e 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -64,6 +64,8 @@ struct sieve_match_type_context { struct sieve_command_context *command_ctx; const struct sieve_match_type *match_type; + int ext_id; + /* Context data could be used in the future to pass data between validator and * generator in match types that use extra parameters. Currently not * necessary, not even for the relational extension. diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index f73e590a951400bbf5f8633b13279a342a5c0fa1..6c70f2a90f509fabdeb9b95c1b2b1180b86a11b5 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -246,8 +246,8 @@ static void sieve_validator_register_unknown_command (void)_sieve_validator_register_command(validator, &unknown_command, command); } -static const struct sieve_command * - sieve_validator_find_command(struct sieve_validator *validator, const char *command) +const struct sieve_command *sieve_validator_find_command +(struct sieve_validator *validator, const char *command) { struct sieve_command_registration *record = sieve_validator_find_command_registration(validator, command); @@ -328,19 +328,22 @@ void sieve_validator_register_tag } static void sieve_validator_register_unknown_tag - (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, +(struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, const char *tag) { _sieve_validator_register_tag(validator, cmd_reg, &_unknown_tag, tag, 0); } static const struct sieve_argument *sieve_validator_find_tag - (struct sieve_validator *validator, - struct sieve_command_registration *cmd_reg, - const char *tag, unsigned int *id_code) +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg, unsigned int *id_code) { + const char *tag; unsigned int i; + struct sieve_command_registration *cmd_reg = cmd->cmd_reg; const struct sieve_tag_registration *reg; + + tag = sieve_ast_argument_tag(arg); *id_code = 0; @@ -360,7 +363,9 @@ static const struct sieve_argument *sieve_validator_find_tag struct sieve_tag_registration * const *reg = array_idx(&cmd_reg->instanced_tags, i); - if ( (*reg)->tag != NULL && (*reg)->tag->is_instance_of(validator, tag) ) { + if ( (*reg)->tag != NULL && + (*reg)->tag->is_instance_of(validator, cmd, arg) ) + { *id_code = (*reg)->id_code; return (*reg)->tag; } @@ -540,39 +545,19 @@ static bool sieve_validate_command_arguments int arg_count = cmd->command->positional_arguments; int real_count = 0; struct sieve_ast_argument *arg; - struct sieve_command_registration *cmd_reg = NULL; + struct sieve_command_registration *cmd_reg = cmd->cmd_reg; - /* Validate any tags that might be present */\ + /* Validate any tags that might be present */ arg = sieve_ast_argument_first(cmd->ast_node); - - /* Get the command registration to get access to its tag registry */ - if ( sieve_ast_argument_type(arg) == SAAT_TAG ) { - cmd_reg = sieve_validator_find_command_registration(validator, cmd->command->identifier); - if ( cmd_reg == NULL ) { - sieve_command_validate_error( - validator, cmd, - "!!BUG!!: the '%s' %s seemed to be known before, " - "but somehow its registration got lost", - cmd->command->identifier, sieve_command_type_name(cmd->command) - ); - i_error("BUG: the '%s' %s seemed to be known before, " - "but somehow its registration got lost", - cmd->command->identifier, sieve_command_type_name(cmd->command) - ); - return FALSE; - } - } - - /* Parse tagged and optional arguments */ + /* Visit tagged and optional arguments */ while ( sieve_ast_argument_type(arg) == SAAT_TAG ) { unsigned int id_code; struct sieve_ast_argument *tag_arg = arg; struct sieve_ast_argument *parg; const struct sieve_argument *tag = - sieve_validator_find_tag - (validator, cmd_reg, sieve_ast_argument_tag(arg), &id_code); + sieve_validator_find_tag(validator, cmd, arg, &id_code); if ( tag == NULL ) { sieve_command_validate_error(validator, cmd, @@ -765,13 +750,16 @@ static bool sieve_validate_command { enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node); bool result = TRUE; + struct sieve_command_registration *cmd_reg; const struct sieve_command *command; i_assert( ast_type == SAT_TEST || ast_type == SAT_COMMAND ); /* Verify the command specified by this node */ - command = sieve_validator_find_command(validator, cmd_node->identifier); + cmd_reg = sieve_validator_find_command_registration + (validator, cmd_node->identifier); + command = cmd_reg->command; if ( command != NULL ) { /* Identifier = "" when the command was previously marked as unknown */ @@ -788,7 +776,7 @@ static bool sieve_validate_command } struct sieve_command_context *ctx = - sieve_command_context_create(cmd_node, command); + sieve_command_context_create(cmd_node, command, cmd_reg); cmd_node->context = ctx; /* If pre-validation fails, don't bother to validate further diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h index fcf96d13ebaf34b482204a77862e357deb661265..c3f7d2f61e8df19aaa91ee402b6aac9af3fa2656 100644 --- a/src/lib-sieve/sieve-validator.h +++ b/src/lib-sieve/sieve-validator.h @@ -47,6 +47,9 @@ void sieve_validator_critical /* Command/Test registration */ void sieve_validator_register_command (struct sieve_validator *validator, const struct sieve_command *command); +const struct sieve_command *sieve_validator_find_command + (struct sieve_validator *validator, const char *command); + void sieve_validator_register_external_tag (struct sieve_validator *validator, const struct sieve_argument *tag, const char *command, int id_code);