diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/sieve-comparators.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/sieve-comparators.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/sieve-comparators.c b/pigeonhole/src/lib-sieve/sieve-comparators.c new file mode 100644 index 0000000..56c33ab --- /dev/null +++ b/pigeonhole/src/lib-sieve/sieve-comparators.c @@ -0,0 +1,260 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str-sanitize.h" +#include "hash.h" +#include "array.h" + +#include "sieve-extensions.h" +#include "sieve-code.h" +#include "sieve-commands.h" +#include "sieve-binary.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "sieve-comparators.h" + +#include <string.h> +#include <stdio.h> + +/* + * Core comparators + */ + +const struct sieve_comparator_def *sieve_core_comparators[] = { + &i_octet_comparator, &i_ascii_casemap_comparator +}; + +const unsigned int sieve_core_comparators_count = + N_ELEMENTS(sieve_core_comparators); + +/* + * Comparator 'extension' + */ + +static bool cmp_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +const struct sieve_extension_def comparator_extension = { + .name = "@comparators", + .validator_load = cmp_validator_load +}; + +/* + * Validator context: + * name-based comparator registry. + */ + +static struct sieve_validator_object_registry *_get_object_registry +(struct sieve_validator *valdtr) +{ + struct sieve_instance *svinst; + const struct sieve_extension *mcht_ext; + + svinst = sieve_validator_svinst(valdtr); + mcht_ext = sieve_get_comparator_extension(svinst); + return sieve_validator_object_registry_get(valdtr, mcht_ext); +} + +void sieve_comparator_register +(struct sieve_validator *valdtr, const struct sieve_extension *ext, + const struct sieve_comparator_def *cmp) +{ + struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); + + sieve_validator_object_registry_add(regs, ext, &cmp->obj_def); +} + +static struct sieve_comparator *sieve_comparator_create +(struct sieve_validator *valdtr, struct sieve_command *cmd, + const char *identifier) +{ + struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); + struct sieve_object object; + struct sieve_comparator *cmp; + + if ( !sieve_validator_object_registry_find(regs, identifier, &object) ) + return NULL; + + cmp = p_new(sieve_command_pool(cmd), struct sieve_comparator, 1); + cmp->object = object; + cmp->def = (const struct sieve_comparator_def *) object.def; + + return cmp; +} + +bool cmp_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + struct sieve_validator_object_registry *regs = + sieve_validator_object_registry_init(valdtr, ext); + unsigned int i; + + /* Register core comparators */ + for ( i = 0; i < sieve_core_comparators_count; i++ ) { + sieve_validator_object_registry_add + (regs, NULL, &(sieve_core_comparators[i]->obj_def)); + } + + return TRUE; +} + +/* + * Comparator tagged argument + */ + +/* Forward declarations */ + +static bool tag_comparator_validate + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd); +static bool tag_comparator_generate + (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, + struct sieve_command *cmd); + +/* Argument object */ + +const struct sieve_argument_def comparator_tag = { + .identifier = "comparator", + .validate = tag_comparator_validate, + .generate = tag_comparator_generate +}; + +/* Argument implementation */ + +static bool tag_comparator_validate +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + const struct sieve_comparator *cmp; + + /* Skip tag */ + *arg = sieve_ast_argument_next(*arg); + + /* Check syntax: + * ":comparator" <comparator-name: string> + */ + if ( !sieve_validate_tag_parameter + (valdtr, cmd, tag, *arg, NULL, 0, SAAT_STRING, FALSE) ) { + return FALSE; + } + + /* FIXME: We can currently only handle string literal argument, so + * variables are not allowed. + */ + if ( !sieve_argument_is_string_literal(*arg) ) { + sieve_argument_validate_error(valdtr, *arg, + "this Sieve implementation currently only supports " + "a literal string argument for the :comparator tag"); + return FALSE; + } + + /* Get comparator from registry */ + cmp = sieve_comparator_create(valdtr, cmd, sieve_ast_argument_strc(*arg)); + + if ( cmp == NULL ) { + sieve_argument_validate_error(valdtr, *arg, + "unknown comparator '%s'", + str_sanitize(sieve_ast_argument_strc(*arg),80)); + + return FALSE; + } + + /* String argument not needed during code generation, so detach it from + * argument list + */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + /* Store comparator in context */ + tag->argument->data = (void *) cmp; + + return TRUE; +} + +static bool tag_comparator_generate +(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, + struct sieve_command *cmd ATTR_UNUSED) +{ + const struct sieve_comparator *cmp = + (const struct sieve_comparator *) arg->argument->data; + + sieve_opr_comparator_emit(cgenv->sblock, cmp); + + return TRUE; +} + +/* Functions to enable and evaluate comparator tag for commands */ + +void sieve_comparators_link_tag +(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg, + int id_code) +{ + struct sieve_instance *svinst; + const struct sieve_extension *mcht_ext; + + svinst = sieve_validator_svinst(valdtr); + mcht_ext = sieve_get_comparator_extension(svinst); + + sieve_validator_register_tag + (valdtr, cmd_reg, mcht_ext, &comparator_tag, id_code); +} + +bool sieve_comparator_tag_is +(struct sieve_ast_argument *tag, const struct sieve_comparator_def *cmp_def) +{ + const struct sieve_comparator *cmp; + + if ( !sieve_argument_is(tag, comparator_tag) ) + return FALSE; + + cmp = (const struct sieve_comparator *) tag->argument->data; + + return ( cmp->def == cmp_def ); +} + +const struct sieve_comparator *sieve_comparator_tag_get +(struct sieve_ast_argument *tag) +{ + if ( !sieve_argument_is(tag, comparator_tag) ) + return NULL; + + + return (const struct sieve_comparator *) tag->argument->data; +} + +/* + * Comparator coding + */ + +const struct sieve_operand_class sieve_comparator_operand_class = + { "comparator" }; + +static const struct sieve_extension_objects core_comparators = + SIEVE_EXT_DEFINE_COMPARATORS(sieve_core_comparators); + +const struct sieve_operand_def comparator_operand = { + .name = "comparator", + .code = SIEVE_OPERAND_COMPARATOR, + .class = &sieve_comparator_operand_class, + .interface = &core_comparators +}; + +/* + * Trivial/Common comparator method implementations + */ + +bool sieve_comparator_octet_skip + (const struct sieve_comparator *cmp ATTR_UNUSED, + const char **val, const char *val_end) +{ + if ( *val < val_end ) { + (*val)++; + return TRUE; + } + + return FALSE; +} |