diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/sieve-address-parts.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/sieve-address-parts.c | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/sieve-address-parts.c b/pigeonhole/src/lib-sieve/sieve-address-parts.c new file mode 100644 index 0000000..a856e20 --- /dev/null +++ b/pigeonhole/src/lib-sieve/sieve-address-parts.c @@ -0,0 +1,495 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "compat.h" +#include "mempool.h" +#include "hash.h" +#include "array.h" +#include "str-sanitize.h" + +#include "sieve-extensions.h" +#include "sieve-code.h" +#include "sieve-address.h" +#include "sieve-commands.h" +#include "sieve-binary.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" +#include "sieve-match.h" + +#include "sieve-address-parts.h" + +#include <string.h> + +/* + * Default address parts + */ + +const struct sieve_address_part_def *sieve_core_address_parts[] = { + &all_address_part, &local_address_part, &domain_address_part +}; + +const unsigned int sieve_core_address_parts_count = + N_ELEMENTS(sieve_core_address_parts); + +/* + * Address-part 'extension' + */ + +static bool addrp_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +const struct sieve_extension_def address_part_extension = { + .name = "@address-parts", + .validator_load = addrp_validator_load +}; + +/* + * Validator context: + * name-based address-part registry. + */ + +static struct sieve_validator_object_registry *_get_object_registry +(struct sieve_validator *valdtr) +{ + struct sieve_instance *svinst; + const struct sieve_extension *adrp_ext; + + svinst = sieve_validator_svinst(valdtr); + adrp_ext = sieve_get_address_part_extension(svinst); + return sieve_validator_object_registry_get(valdtr, adrp_ext); +} + +void sieve_address_part_register +(struct sieve_validator *valdtr, const struct sieve_extension *ext, + const struct sieve_address_part_def *addrp_def) +{ + struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); + + sieve_validator_object_registry_add(regs, ext, &addrp_def->obj_def); +} + +static bool sieve_address_part_exists +(struct sieve_validator *valdtr, const char *identifier) +{ + struct sieve_validator_object_registry *regs = _get_object_registry(valdtr); + + return sieve_validator_object_registry_find(regs, identifier, NULL); +} + +static const struct sieve_address_part *sieve_address_part_create_instance +(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_address_part *addrp; + + if ( !sieve_validator_object_registry_find(regs, identifier, &object) ) + return NULL; + + addrp = p_new(sieve_command_pool(cmd), struct sieve_address_part, 1); + addrp->object = object; + addrp->def = (const struct sieve_address_part_def *) object.def; + + return addrp; +} + +static bool addrp_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 address-parts */ + for ( i = 0; i < sieve_core_address_parts_count; i++ ) { + sieve_validator_object_registry_add + (regs, NULL, &(sieve_core_address_parts[i]->obj_def)); + } + + return TRUE; +} + +void sieve_address_parts_link_tags +(struct sieve_validator *valdtr, struct sieve_command_registration *cmd_reg, + int id_code) +{ + struct sieve_instance *svinst; + const struct sieve_extension *adrp_ext; + + svinst = sieve_validator_svinst(valdtr); + adrp_ext = sieve_get_address_part_extension(svinst); + + sieve_validator_register_tag + (valdtr, cmd_reg, adrp_ext, &address_part_tag, id_code); +} + +/* + * Address-part tagged argument + */ + +/* Forward declarations */ + +static bool tag_address_part_is_instance_of + (struct sieve_validator *valdtr, struct sieve_command *cmd, + const struct sieve_extension *ext, const char *identifier, void **data); +static bool tag_address_part_validate + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd); +static bool tag_address_part_generate + (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, + struct sieve_command *cmd); + +/* Argument object */ + +const struct sieve_argument_def address_part_tag = { + .identifier = "ADDRESS-PART", + .is_instance_of = tag_address_part_is_instance_of, + .validate = tag_address_part_validate, + .generate = tag_address_part_generate +}; + +/* Argument implementation */ + +static bool tag_address_part_is_instance_of +(struct sieve_validator *valdtr, struct sieve_command *cmd, + const struct sieve_extension *ext ATTR_UNUSED, const char *identifier, + void **data) +{ + const struct sieve_address_part *addrp; + + if ( data == NULL ) + return sieve_address_part_exists(valdtr, identifier); + + if ( (addrp=sieve_address_part_create_instance + (valdtr, cmd, identifier)) == NULL ) + return FALSE; + + *data = (void *) addrp; + return TRUE; +} + +static bool tag_address_part_validate +(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg, + struct sieve_command *cmd ATTR_UNUSED) +{ + /* NOTE: Currenly trivial, but might need to allow for further validation for + * future extensions. + */ + + /* Syntax: + * ":localpart" / ":domain" / ":all" (subject to extension) + */ + + /* Skip tag */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +static bool tag_address_part_generate +(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, + struct sieve_command *cmd ATTR_UNUSED) +{ + struct sieve_address_part *addrp = + (struct sieve_address_part *) arg->argument->data; + + sieve_opr_address_part_emit(cgenv->sblock, addrp); + + return TRUE; +} + +/* + * Address-part operand + */ + +const struct sieve_operand_class sieve_address_part_operand_class = + { "address part" }; + +static const struct sieve_extension_objects core_address_parts = + SIEVE_EXT_DEFINE_MATCH_TYPES(sieve_core_address_parts); + +const struct sieve_operand_def address_part_operand = { + .name = "address-part", + .code = SIEVE_OPERAND_ADDRESS_PART, + .class = &sieve_address_part_operand_class, + .interface = &core_address_parts +}; + +/* + * Address-part string list + */ + +static int sieve_address_part_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void sieve_address_part_stringlist_reset + (struct sieve_stringlist *_strlist); +static int sieve_address_part_stringlist_get_length + (struct sieve_stringlist *_strlist); +static void sieve_address_part_stringlist_set_trace +(struct sieve_stringlist *_strlist, bool trace); + +struct sieve_address_part_stringlist { + struct sieve_stringlist strlist; + + const struct sieve_address_part *addrp; + struct sieve_address_list *addresses; +}; + +struct sieve_stringlist *sieve_address_part_stringlist_create +(const struct sieve_runtime_env *renv, const struct sieve_address_part *addrp, + struct sieve_address_list *addresses) +{ + struct sieve_address_part_stringlist *strlist; + + strlist = t_new(struct sieve_address_part_stringlist, 1); + strlist->strlist.runenv = renv; + strlist->strlist.next_item = sieve_address_part_stringlist_next_item; + strlist->strlist.reset = sieve_address_part_stringlist_reset; + strlist->strlist.get_length = sieve_address_part_stringlist_get_length; + strlist->strlist.set_trace = sieve_address_part_stringlist_set_trace; + + strlist->addrp = addrp; + strlist->addresses = addresses; + + return &strlist->strlist; +} + +static int sieve_address_part_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + struct smtp_address item; + string_t *item_unparsed; + int ret; + + *str_r = NULL; + + while ( *str_r == NULL ) { + if ( (ret=sieve_address_list_next_item + (strlist->addresses, &item, &item_unparsed)) <= 0 ) + return ret; + + if ( item.localpart == NULL ) { + if ( item_unparsed != NULL ) { + if ( _strlist->trace ) { + sieve_runtime_trace(_strlist->runenv, 0, + "extracting `%s' part from non-address value `%s'", + sieve_address_part_name(strlist->addrp), + str_sanitize(str_c(item_unparsed), 80)); + } + + if ( str_len(item_unparsed) == 0 || + sieve_address_part_is(strlist->addrp, all_address_part) ) + *str_r = item_unparsed; + } + } else { + const struct sieve_address_part *addrp = strlist->addrp; + const char *part = NULL; + + if ( _strlist->trace ) { + sieve_runtime_trace(_strlist->runenv, 0, + "extracting `%s' part from address %s", + sieve_address_part_name(strlist->addrp), + smtp_address_encode_path(&item)); + } + + if ( addrp->def != NULL && addrp->def->extract_from != NULL ) + part = addrp->def->extract_from(addrp, &item); + + if ( part != NULL ) + *str_r = t_str_new_const(part, strlen(part)); + } + } + + return 1; +} + +static void sieve_address_part_stringlist_reset + (struct sieve_stringlist *_strlist) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + + sieve_address_list_reset(strlist->addresses); +} + +static int sieve_address_part_stringlist_get_length + (struct sieve_stringlist *_strlist) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + + return sieve_address_list_get_length(strlist->addresses); +} + +static void sieve_address_part_stringlist_set_trace +(struct sieve_stringlist *_strlist, bool trace) +{ + struct sieve_address_part_stringlist *strlist = + (struct sieve_address_part_stringlist *)_strlist; + + sieve_address_list_set_trace(strlist->addresses, trace); +} + +/* + * Default ADDRESS-PART, MATCH-TYPE, COMPARATOR access + */ + +int sieve_addrmatch_opr_optional_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address, + signed int *opt_code) +{ + signed int _opt_code = 0; + bool final = FALSE, opok = TRUE; + + if ( opt_code == NULL ) { + opt_code = &_opt_code; + final = TRUE; + } + + while ( opok ) { + int opt; + + if ( (opt=sieve_opr_optional_dump(denv, address, opt_code)) <= 0 ) + return opt; + + switch ( *opt_code ) { + case SIEVE_MATCH_OPT_COMPARATOR: + opok = sieve_opr_comparator_dump(denv, address); + break; + case SIEVE_MATCH_OPT_MATCH_TYPE: + opok = sieve_opr_match_type_dump(denv, address); + break; + case SIEVE_AM_OPT_ADDRESS_PART: + opok = sieve_opr_address_part_dump(denv, address); + break; + default: + return ( final ? -1 : 1 ); + } + } + + return -1; +} + +int sieve_addrmatch_opr_optional_read +(const struct sieve_runtime_env *renv, sieve_size_t *address, + signed int *opt_code, int *exec_status, struct sieve_address_part *addrp, + struct sieve_match_type *mtch, struct sieve_comparator *cmp) +{ + signed int _opt_code = 0; + bool final = FALSE; + int status = SIEVE_EXEC_OK; + + if ( opt_code == NULL ) { + opt_code = &_opt_code; + final = TRUE; + } + + if ( exec_status != NULL ) + *exec_status = SIEVE_EXEC_OK; + + while ( status == SIEVE_EXEC_OK ) { + int opt; + + if ( (opt=sieve_opr_optional_read(renv, address, opt_code)) <= 0 ){ + if ( opt < 0 && exec_status != NULL ) + *exec_status = SIEVE_EXEC_BIN_CORRUPT; + return opt; + } + + switch ( *opt_code ) { + case SIEVE_MATCH_OPT_COMPARATOR: + if (cmp == NULL) { + sieve_runtime_trace_error(renv, "unexpected comparator operand"); + if ( exec_status != NULL ) + *exec_status = SIEVE_EXEC_BIN_CORRUPT; + return -1; + } + status = sieve_opr_comparator_read(renv, address, cmp); + break; + case SIEVE_MATCH_OPT_MATCH_TYPE: + if (mtch == NULL) { + sieve_runtime_trace_error(renv, "unexpected match-type operand"); + if ( exec_status != NULL ) + *exec_status = SIEVE_EXEC_BIN_CORRUPT; + return -1; + } + status = sieve_opr_match_type_read(renv, address, mtch); + break; + case SIEVE_AM_OPT_ADDRESS_PART: + if (addrp == NULL) { + sieve_runtime_trace_error(renv, "unexpected address-part operand"); + if ( exec_status != NULL ) + *exec_status = SIEVE_EXEC_BIN_CORRUPT; + return -1; + } + status = sieve_opr_address_part_read(renv, address, addrp); + break; + default: + if ( final ) { + sieve_runtime_trace_error(renv, "invalid optional operand"); + if ( exec_status != NULL ) + *exec_status = SIEVE_EXEC_BIN_CORRUPT; + return -1; + } + return 1; + } + } + + if ( exec_status != NULL ) + *exec_status = status; + return -1; +} + +/* + * Core address-part modifiers + */ + +static const char *addrp_all_extract_from +(const struct sieve_address_part *addrp ATTR_UNUSED, + const struct smtp_address *address) +{ + if ( address->localpart == NULL ) + return NULL; + return smtp_address_encode(address); +} + +static const char *addrp_domain_extract_from +(const struct sieve_address_part *addrp ATTR_UNUSED, + const struct smtp_address *address) +{ + return address->domain; +} + +static const char *addrp_localpart_extract_from +(const struct sieve_address_part *addrp ATTR_UNUSED, + const struct smtp_address *address) +{ + return address->localpart; +} + +const struct sieve_address_part_def all_address_part = { + SIEVE_OBJECT("all", + &address_part_operand, SIEVE_ADDRESS_PART_ALL), + .extract_from = addrp_all_extract_from +}; + +const struct sieve_address_part_def local_address_part = { + SIEVE_OBJECT("localpart", + &address_part_operand, SIEVE_ADDRESS_PART_LOCAL), + .extract_from = addrp_localpart_extract_from +}; + +const struct sieve_address_part_def domain_address_part = { + SIEVE_OBJECT("domain", + &address_part_operand, SIEVE_ADDRESS_PART_DOMAIN), + .extract_from = addrp_domain_extract_from +}; + |