summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c')
-rw-r--r--pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c b/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c
new file mode 100644
index 0000000..abaa7ae
--- /dev/null
+++ b/pigeonhole/src/lib-sieve/plugins/subaddress/ext-subaddress.c
@@ -0,0 +1,191 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+/* Extension subaddress
+ * --------------------
+ *
+ * Author: Stephan Bosch
+ * Specification: RFC 3598
+ * Implementation: full
+ * Status: testing
+ *
+ */
+
+#include "sieve-common.h"
+
+#include "sieve-settings.h"
+#include "sieve-code.h"
+#include "sieve-address.h"
+#include "sieve-extensions.h"
+#include "sieve-commands.h"
+#include "sieve-address-parts.h"
+#include "sieve-validator.h"
+#include "sieve-generator.h"
+#include "sieve-interpreter.h"
+
+#include <string.h>
+
+/*
+ * Configuration
+ */
+
+#define SUBADDRESS_DEFAULT_DELIM "+"
+
+struct ext_subaddress_config {
+ char *delimiter;
+};
+
+/*
+ * Forward declarations
+ */
+
+const struct sieve_address_part_def user_address_part;
+const struct sieve_address_part_def detail_address_part;
+
+static struct sieve_operand_def subaddress_operand;
+
+/*
+ * Extension
+ */
+
+static bool ext_subaddress_load
+ (const struct sieve_extension *ext, void **context);
+static void ext_subaddress_unload
+ (const struct sieve_extension *ext);
+static bool ext_subaddress_validator_load
+ (const struct sieve_extension *ext, struct sieve_validator *validator);
+
+const struct sieve_extension_def subaddress_extension = {
+ .name = "subaddress",
+ .load = ext_subaddress_load,
+ .unload = ext_subaddress_unload,
+ .validator_load = ext_subaddress_validator_load,
+ SIEVE_EXT_DEFINE_OPERAND(subaddress_operand)
+};
+
+static bool ext_subaddress_load
+(const struct sieve_extension *ext, void **context)
+{
+ struct ext_subaddress_config *config;
+ const char *delim;
+
+ if ( *context != NULL ) {
+ ext_subaddress_unload(ext);
+ }
+
+ delim = sieve_setting_get(ext->svinst, "recipient_delimiter");
+
+ if ( delim == NULL )
+ delim = SUBADDRESS_DEFAULT_DELIM;
+
+ config = i_new(struct ext_subaddress_config, 1);
+ config->delimiter = i_strdup(delim);
+
+ *context = (void *) config;
+
+ return TRUE;
+}
+
+static void ext_subaddress_unload
+(const struct sieve_extension *ext)
+{
+ struct ext_subaddress_config *config =
+ (struct ext_subaddress_config *) ext->context;
+
+ i_free(config->delimiter);
+ i_free(config);
+}
+
+static bool ext_subaddress_validator_load
+(const struct sieve_extension *ext, struct sieve_validator *validator)
+{
+ sieve_address_part_register(validator, ext, &user_address_part);
+ sieve_address_part_register(validator, ext, &detail_address_part);
+
+ return TRUE;
+}
+
+/*
+ * Address parts
+ */
+
+enum ext_subaddress_address_part {
+ SUBADDRESS_USER,
+ SUBADDRESS_DETAIL
+};
+
+/* Forward declarations */
+
+static const char *subaddress_user_extract_from
+ (const struct sieve_address_part *addrp, const struct smtp_address *address);
+static const char *subaddress_detail_extract_from
+ (const struct sieve_address_part *addrp, const struct smtp_address *address);
+
+/* Address part objects */
+
+const struct sieve_address_part_def user_address_part = {
+ SIEVE_OBJECT("user",
+ &subaddress_operand, SUBADDRESS_USER),
+ subaddress_user_extract_from
+};
+
+const struct sieve_address_part_def detail_address_part = {
+ SIEVE_OBJECT("detail",
+ &subaddress_operand, SUBADDRESS_DETAIL),
+ .extract_from = subaddress_detail_extract_from
+};
+
+/* Address part implementation */
+
+static const char *subaddress_user_extract_from
+(const struct sieve_address_part *addrp, const struct smtp_address *address)
+{
+ struct ext_subaddress_config *config =
+ (struct ext_subaddress_config *) addrp->object.ext->context;
+ const char *delim;
+ size_t idx;
+
+ idx = strcspn(address->localpart, config->delimiter);
+ delim = address->localpart[idx] != '\0' ? address->localpart + idx : NULL;
+
+ if ( delim == NULL ) return address->localpart;
+
+ return t_strdup_until(address->localpart, delim);
+}
+
+static const char *subaddress_detail_extract_from
+(const struct sieve_address_part *addrp, const struct smtp_address *address)
+{
+ struct ext_subaddress_config *config =
+ (struct ext_subaddress_config *) addrp->object.ext->context;
+ const char *delim;
+ size_t idx;
+
+ idx = strcspn(address->localpart, config->delimiter);
+ delim = address->localpart[idx] != '\0' ? address->localpart + idx + 1: NULL;
+
+ /* Just to be sure */
+ if ( delim == NULL ||
+ delim > (address->localpart + strlen(address->localpart)) )
+ return NULL;
+ return delim;
+}
+
+/*
+ * Operand
+ */
+
+const struct sieve_address_part_def *ext_subaddress_parts[] = {
+ &user_address_part, &detail_address_part
+};
+
+static const struct sieve_extension_objects ext_address_parts =
+ SIEVE_EXT_DEFINE_ADDRESS_PARTS(ext_subaddress_parts);
+
+static struct sieve_operand_def subaddress_operand = {
+ .name = "address-part",
+ .ext_def = &subaddress_extension,
+ .class = &sieve_address_part_operand_class,
+ .interface = &ext_address_parts
+};
+