diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c new file mode 100644 index 0000000..28d4251 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/environment/ext-environment-common.c @@ -0,0 +1,339 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "hash.h" + +#include "sieve-common.h" +#include "sieve-extensions.h" +#include "sieve-interpreter.h" + +#include "ext-environment-common.h" + +struct ext_environment_interpreter_context; + +/* + * Core environment items + */ + +static const struct sieve_environment_item *core_env_items[] = { + &domain_env_item, + &host_env_item, + &location_env_item, + &phase_env_item, + &name_env_item, + &version_env_item +}; + +static unsigned int core_env_items_count = N_ELEMENTS(core_env_items); + +static void +sieve_environment_item_insert(struct ext_environment_interpreter_context *ctx, + const struct sieve_environment_item *item); + +/* + * Validator context + */ + +struct ext_environment_interpreter_context { + HASH_TABLE(const char *, + const struct sieve_environment_item *) name_items; + ARRAY(const struct sieve_environment_item *) prefix_items; + + bool active:1; +}; + +static void +ext_environment_interpreter_extension_free(const struct sieve_extension *ext, + struct sieve_interpreter *interp, + void *context); + +struct sieve_interpreter_extension environment_interpreter_extension = { + .ext_def = &environment_extension, + .free = ext_environment_interpreter_extension_free, +}; + +static struct ext_environment_interpreter_context * +ext_environment_interpreter_context_create( + const struct sieve_extension *this_ext, + struct sieve_interpreter *interp) +{ + pool_t pool = sieve_interpreter_pool(interp); + struct ext_environment_interpreter_context *ctx; + + ctx = p_new(pool, struct ext_environment_interpreter_context, 1); + + hash_table_create(&ctx->name_items, default_pool, 0, str_hash, strcmp); + i_array_init(&ctx->prefix_items, 16); + + sieve_interpreter_extension_register(interp, this_ext, + &environment_interpreter_extension, + (void *)ctx); + return ctx; +} + +static void +ext_environment_interpreter_extension_free( + const struct sieve_extension *ext ATTR_UNUSED, + struct sieve_interpreter *interp ATTR_UNUSED, void *context) +{ + struct ext_environment_interpreter_context *ctx = + (struct ext_environment_interpreter_context *)context; + + hash_table_destroy(&ctx->name_items); + array_free(&ctx->prefix_items); +} + +static struct ext_environment_interpreter_context * +ext_environment_interpreter_context_get(const struct sieve_extension *this_ext, + struct sieve_interpreter *interp) +{ + struct ext_environment_interpreter_context *ctx = + (struct ext_environment_interpreter_context *) + sieve_interpreter_extension_get_context(interp, this_ext); + + if (ctx == NULL) { + ctx = ext_environment_interpreter_context_create( + this_ext, interp); + } + return ctx; +} + +void ext_environment_interpreter_init(const struct sieve_extension *this_ext, + struct sieve_interpreter *interp) +{ + struct ext_environment_interpreter_context *ctx; + unsigned int i; + + /* Create our context */ + ctx = ext_environment_interpreter_context_get(this_ext, interp); + + for (i = 0; i < core_env_items_count; i++) + sieve_environment_item_insert(ctx, core_env_items[i]); + + ctx->active = TRUE; +} + +bool sieve_ext_environment_is_active(const struct sieve_extension *env_ext, + struct sieve_interpreter *interp) +{ + struct ext_environment_interpreter_context *ctx = + ext_environment_interpreter_context_get(env_ext, interp); + + return (ctx != NULL && ctx->active); +} + +/* + * Registration + */ + +static void +sieve_environment_item_insert(struct ext_environment_interpreter_context *ctx, + const struct sieve_environment_item *item) +{ + if (!item->prefix) + hash_table_insert(ctx->name_items, item->name, item); + else + array_append(&ctx->prefix_items, &item, 1); +} + +void sieve_environment_item_register(const struct sieve_extension *env_ext, + struct sieve_interpreter *interp, + const struct sieve_environment_item *item) +{ + struct ext_environment_interpreter_context *ctx; + + i_assert(sieve_extension_is(env_ext, environment_extension)); + ctx = ext_environment_interpreter_context_get(env_ext, interp); + + sieve_environment_item_insert(ctx, item); +} + +/* + * Retrieval + */ + +static const struct sieve_environment_item * +ext_environment_item_lookup(struct ext_environment_interpreter_context *ctx, + const char **_name) +{ + const struct sieve_environment_item *item; + const char *name = *_name; + + item = hash_table_lookup(ctx->name_items, name); + if (item != NULL) + return item; + + array_foreach_elem(&ctx->prefix_items, item) { + size_t prefix_len; + + i_assert(item->prefix); + prefix_len = strlen(item->name); + + if (str_begins(name, item->name)) { + if (name[prefix_len] == '.') { + *_name = &name[prefix_len+1]; + return item; + } else if (name[prefix_len] == '\0') { + *_name = &name[prefix_len+1]; + return item; + } + } + } + return NULL; +} + +const char * +ext_environment_item_get_value(const struct sieve_extension *env_ext, + const struct sieve_runtime_env *renv, + const char *name) +{ + struct ext_environment_interpreter_context *ctx; + const struct sieve_environment_item *item; + + i_assert(sieve_extension_is(env_ext, environment_extension)); + ctx = ext_environment_interpreter_context_get(env_ext, renv->interp); + + item = ext_environment_item_lookup(ctx, &name); + if (item == NULL) + return NULL; + + if (item->value != NULL) + return item->value; + if (item->get_value != NULL) + return item->get_value(renv, name); + return NULL; +} + +/* + * Default environment items + */ + +/* "domain": + + The primary DNS domain associated with the Sieve execution context, usually + but not always a proper suffix of the host name. + */ + +static const char * +envit_domain_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + + return eenv->svinst->domainname; +} + +const struct sieve_environment_item domain_env_item = { + .name = "domain", + .get_value = envit_domain_get_value, +}; + +/* "host": + + The fully-qualified domain name of the host where the Sieve script is + executing. + */ + +static const char * +envit_host_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + + return eenv->svinst->hostname; +} + +const struct sieve_environment_item host_env_item = { + .name = "host", + .get_value = envit_host_get_value, +}; + +/* "location": + + Sieve evaluation can be performed at various different points as messages + are processed. This item provides additional information about the type of + service that is evaluating the script. Possible values are: + "MTA" - the Sieve script is being evaluated by a Message Transfer Agent + "MDA" - evaluation is being performed by a Mail Delivery Agent + "MUA" - evaluation is being performed by a Mail User Agent (right...) + "MS" - evaluation is being performed by a Message Store + */ + +static const char * +envit_location_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + + switch (eenv->svinst->env_location ) { + case SIEVE_ENV_LOCATION_MDA: + return "MDA"; + case SIEVE_ENV_LOCATION_MTA: + return "MTA"; + case SIEVE_ENV_LOCATION_MS: + return "MS"; + default: + break; + } + return NULL; +} + +const struct sieve_environment_item location_env_item = { + .name = "location", + .get_value = envit_location_get_value +}; + +/* "phase": + + The point relative to final delivery where the Sieve script is being + evaluated. Possible values are "pre", "during", and "post", referring + respectively to processing before, during, and after final delivery has + taken place. + */ + +static const char * +envit_phase_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + + switch (eenv->svinst->delivery_phase) { + case SIEVE_DELIVERY_PHASE_PRE: + return "pre"; + case SIEVE_DELIVERY_PHASE_DURING: + return "during"; + case SIEVE_DELIVERY_PHASE_POST: + return "post"; + default: + break; + } + return NULL; +} + +const struct sieve_environment_item phase_env_item = { + .name = "phase", + .get_value = envit_phase_get_value +}; + +/* "name": + + The product name associated with the Sieve interpreter. + */ + +const struct sieve_environment_item name_env_item = { + .name = "name", + .value = PIGEONHOLE_NAME" Sieve" +}; + +/* "version": + + The product version associated with the Sieve interpreter. The meaning of the + product version string is product-specific and should always be considered + in the context of the product name given by the "name" item. + */ + +const struct sieve_environment_item version_env_item = { + .name = "version", + .value = PIGEONHOLE_VERSION, +}; |