diff --git a/src/lib-sieve/plugins/enotify/Makefile.am b/src/lib-sieve/plugins/enotify/Makefile.am index a32fb02d22651f55d108e208b4c8abce3ccac745..d73dd10527e8fbdee801a1eabe9358fff3175b59 100644 --- a/src/lib-sieve/plugins/enotify/Makefile.am +++ b/src/lib-sieve/plugins/enotify/Makefile.am @@ -23,11 +23,13 @@ notify_methods = \ libsieve_ext_enotify_la_SOURCES = \ ext-enotify.c \ + ext-enotify-common.c \ $(commands) \ $(tests) \ $(var_modifiers) \ $(notify_methods) noinst_HEADERS = \ + sieve-ext-enotify.h \ ext-enotify-common.h diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.c b/src/lib-sieve/plugins/enotify/ext-enotify-common.c new file mode 100644 index 0000000000000000000000000000000000000000..66c90a3e38f622e43e2434fdcf844e1320f32515 --- /dev/null +++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.c @@ -0,0 +1,26 @@ +#include "lib.h" + +#include "sieve-common.h" + +#include "ext-enotify-common.h" + +/* + * Notify capability + */ + +static const char *ext_notify_get_methods_string(void); + +const struct sieve_extension_capabilities notify_capabilities = { + "notify", + ext_notify_get_methods_string +}; + +/* + * Notify method registry + */ + +static const char *ext_notify_get_methods_string(void) +{ + return "mailto"; +} + diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.h b/src/lib-sieve/plugins/enotify/ext-enotify-common.h index 02a46d138d8115ba4f7f4b900c28c698eaac4dac..9e0e04112c7cfbb8e9ecd1c1ca3e53b97451f873 100644 --- a/src/lib-sieve/plugins/enotify/ext-enotify-common.h +++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.h @@ -6,11 +6,14 @@ #include "sieve-ext-variables.h" +#include "sieve-ext-enotify.h" + /* * Extension */ extern const struct sieve_extension enotify_extension; +extern const struct sieve_extension_capabilities notify_capabilities; /* * Commands diff --git a/src/lib-sieve/plugins/enotify/ext-enotify.c b/src/lib-sieve/plugins/enotify/ext-enotify.c index 5fea70eb4221559dab7e851b98c1adf355032c59..e3ee477198b413a1a864445bf32007cca15a13e4 100644 --- a/src/lib-sieve/plugins/enotify/ext-enotify.c +++ b/src/lib-sieve/plugins/enotify/ext-enotify.c @@ -61,6 +61,8 @@ static bool ext_enotify_load(int ext_id) { ext_my_id = ext_id; + sieve_extension_capabilities_register(¬ify_capabilities); + return TRUE; } diff --git a/src/lib-sieve/plugins/enotify/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/ntfy-mailto.c index 0c7cfcc4f7a28417da821c3148e808f04d1ae616..366c32b215e664ab91625d7b3286141b44aca8a5 100644 --- a/src/lib-sieve/plugins/enotify/ntfy-mailto.c +++ b/src/lib-sieve/plugins/enotify/ntfy-mailto.c @@ -35,6 +35,10 @@ static bool ntfy_mailto_parse_uri { *recipient_r = "stephan@rename-it.nl"; *headers = NULL; + + /* Scheme already parsed, starting parse after colon */ + + /* First parse e-mail address */ } /* diff --git a/src/lib-sieve/sieve-address.c b/src/lib-sieve/sieve-address.c index 7117952522cdf0b4c7cbee1f32592ca53c378fc7..5ec44ccc305fc957746cf6622cb16b7279d9499e 100644 --- a/src/lib-sieve/sieve-address.c +++ b/src/lib-sieve/sieve-address.c @@ -55,14 +55,19 @@ * Message address specification as allowed bij the RFC 5228 SIEVE * specification: * sieve-address = addr-spec ; simple address - * / phrase "<" addr-spec ">" ; name & addr-spec + * / phrase "<" addr-spec ">" ; name & addr-spec\ + * + * Which concisely is about equal to: + * sieve-address = mailbox */ + +/* + * Address parse context + */ struct sieve_message_address_parser { struct rfc822_parser_context parser; - string_t *address; - string_t *str; string_t *local_part; string_t *domain; @@ -70,6 +75,10 @@ struct sieve_message_address_parser { string_t *error; }; +/* + * Error handling + */ + static inline void sieve_address_error (struct sieve_message_address_parser *ctx, const char *fmt, ...) ATTR_FORMAT(2, 3); @@ -85,6 +94,14 @@ static inline void sieve_address_error va_end(args); } } + +/* + * Partial RFC 2822 address parser + * + * FIXME: lots of overlap with dovecot/src/lib-mail/message-parser.c + * --> this implementation adds textual error reporting + * MERGE! + */ static int parse_local_part(struct sieve_message_address_parser *ctx) { @@ -143,7 +160,7 @@ static int parse_addr_spec(struct sieve_message_address_parser *ctx) return -1; } -static int parse_name_addr(struct sieve_message_address_parser *ctx) +static int parse_mailbox(struct sieve_message_address_parser *ctx) { int ret; const unsigned char *start; @@ -188,14 +205,15 @@ static int parse_name_addr(struct sieve_message_address_parser *ctx) return ret; } -static bool parse_sieve_address(struct sieve_message_address_parser *ctx) +static bool parse_mailbox_address +(struct sieve_message_address_parser *ctx, const unsigned char *address, + unsigned int addr_size) { int ret; /* Initialize parser */ - rfc822_parser_init(&ctx->parser, str_data(ctx->address), str_len(ctx->address), - t_str_new(128)); + rfc822_parser_init(&ctx->parser, address, addr_size, NULL); /* Parse */ @@ -206,7 +224,7 @@ static bool parse_sieve_address(struct sieve_message_address_parser *ctx) return FALSE; } - if ((ret = parse_name_addr(ctx)) < 0) { + if ((ret = parse_mailbox(ctx)) < 0) { return FALSE; } @@ -215,6 +233,7 @@ static bool parse_sieve_address(struct sieve_message_address_parser *ctx) sieve_address_error(ctx, "missing domain"); return FALSE; } + if ( str_len(ctx->local_part) == 0 ) { sieve_address_error(ctx, "missing local part"); return FALSE; @@ -223,20 +242,48 @@ static bool parse_sieve_address(struct sieve_message_address_parser *ctx) return TRUE; } +bool sieve_validate_rfc2822_mailbox(const char *address, const char **error_r) +{ + struct sieve_message_address_parser ctx; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.local_part = t_str_new(128); + ctx.domain = t_str_new(128); + ctx.str = t_str_new(128); + ctx.error = t_str_new(128); + + if ( !parse_mailbox_address(&ctx, (const unsigned char *) address, + strlen(address)) ) { + if ( error_r != NULL ) + *error_r = str_c(ctx.error); + return FALSE; + } + + if ( error_r != NULL ) + *error_r = NULL; + + return TRUE; +} + + +/* + * Sieve address + */ + const char *sieve_address_normalize (string_t *address, const char **error_r) { struct sieve_message_address_parser ctx; memset(&ctx, 0, sizeof(ctx)); - ctx.address = address; ctx.local_part = t_str_new(128); ctx.domain = t_str_new(128); ctx.str = t_str_new(128); ctx.error = t_str_new(128); - if ( !parse_sieve_address(&ctx) ) + if ( !parse_mailbox_address(&ctx, str_data(address), str_len(address)) ) { *error_r = str_c(ctx.error); return NULL; @@ -254,12 +301,11 @@ bool sieve_address_validate struct sieve_message_address_parser ctx; memset(&ctx, 0, sizeof(ctx)); - ctx.address = address; ctx.local_part = ctx.domain = ctx.str = t_str_new(128); ctx.error = t_str_new(128); - if ( !parse_sieve_address(&ctx) ) + if ( !parse_mailbox_address(&ctx, str_data(address), str_len(address)) ) { *error_r = str_c(ctx.error); return FALSE; @@ -411,7 +457,7 @@ static int path_parse_domain int ret; /* Domain = (sub-domain 1*("." sub-domain)) / address-literal - * sub-domain = Let-dig [Ldh-str] + * sub-domain = Let-dig [Ldh-str] * Let-dig = ALPHA / DIGIT * Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig */ @@ -474,13 +520,13 @@ static int path_skip_source_route(struct sieve_envelope_address_parser *parser) for (;;) { if ( (ret=path_skip_white_space(parser)) <= 0 ) - return -1; + return -1; if ( (ret=path_parse_domain(parser, TRUE)) <= 0 ) - return -1; + return -1; if ( (ret=path_skip_white_space(parser)) <= 0 ) - return ret; + return ret; /* Next? */ if ( *parser->data != ',' ) @@ -488,7 +534,7 @@ static int path_skip_source_route(struct sieve_envelope_address_parser *parser) parser->data++; if ( (ret=path_skip_white_space(parser)) <= 0 ) - return -1; + return -1; if ( *parser->data != '@' ) return -1; @@ -517,7 +563,7 @@ static int path_parse_local_part(struct sieve_envelope_address_parser *parser) str_truncate(parser->str, 0); if ( *parser->data == '"' ) { str_append_c(parser->str, *parser->data); - parser->data++; + parser->data++; while ( parser->data < parser->end ) { if ( *parser->data == '\\' ) { @@ -544,12 +590,12 @@ static int path_parse_local_part(struct sieve_envelope_address_parser *parser) return -1; str_append_c(parser->str, *parser->data); - parser->data++; + parser->data++; if ( (ret=path_skip_white_space(parser)) < 0 ) return ret; - } else { - for (;;) { + } else { + for (;;) { if ( !IS_ATEXT(*parser->data) ) return -1; str_append_c(parser->str, *parser->data); @@ -610,9 +656,9 @@ static int path_parse(struct sieve_envelope_address_parser *parser) if ( (ret=path_skip_white_space(parser)) <= 0 ) return ret; - /* We allow angle brackets to be missing */ - if ( *parser->data == '<' ) { - parser->data++; + /* We allow angle brackets to be missing */ + if ( *parser->data == '<' ) { + parser->data++; brackets = TRUE; if ( (ret=path_skip_white_space(parser)) <= 0 ) diff --git a/src/lib-sieve/sieve-address.h b/src/lib-sieve/sieve-address.h index 2373d4284369570104917992d3fd8e7d303f2d52..e4a51148dc5ec2e3aceefc065c0b88b49576afeb 100644 --- a/src/lib-sieve/sieve-address.h +++ b/src/lib-sieve/sieve-address.h @@ -17,6 +17,8 @@ struct sieve_address { * RFC 2822 addresses */ +bool sieve_validate_rfc2822_mailbox(const char *address, const char **error_r); + const char *sieve_address_normalize (string_t *address, const char **error_r); bool sieve_address_validate diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c index ec57b738f7d99319400e4fb0cd9b9c9726482794..05d98e3617ee10e4b6bb17a7b8d9780ec3828df3 100644 --- a/src/lib-sieve/sieve-extensions.c +++ b/src/lib-sieve/sieve-extensions.c @@ -17,6 +17,9 @@ static void sieve_extensions_init_registry(void); static void sieve_extensions_deinit_registry(void); +static void sieve_extensions_init_capabilities(void); +static void sieve_extensions_deinit_capabilities(void); + /* * Pre-loaded 'extensions' */ @@ -122,6 +125,7 @@ bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED) unsigned int i; sieve_extensions_init_registry(); + sieve_extensions_init_capabilities(); /* Pre-load core extensions */ for ( i = 0; i < sieve_core_extensions_count; i++ ) { @@ -135,6 +139,7 @@ bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED) void sieve_extensions_deinit(void) { + sieve_extensions_deinit_capabilities(); sieve_extensions_deinit_registry(); } @@ -211,7 +216,7 @@ const struct sieve_extension *sieve_extension_get_by_name(const char *name) return ereg->extension; } -static bool _list_extension(const struct sieve_extension *ext) +static inline bool _list_extension(const struct sieve_extension *ext) { return ( ext->id != NULL && *ext->name != '@' ); } @@ -266,4 +271,43 @@ static void sieve_extensions_deinit_registry(void) hash_destroy(&extension_index); } +/* + * Extension capabilities + */ + +static struct hash_table *capabilities_index; + +static void sieve_extensions_init_capabilities(void) +{ + capabilities_index = hash_create + (default_pool, default_pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); +} + +static void sieve_extensions_deinit_capabilities(void) +{ + hash_destroy(&capabilities_index); +} + +void sieve_extension_capabilities_register + (const struct sieve_extension_capabilities *cap) +{ + hash_insert + (capabilities_index, (void *) cap->name, (void *) cap); +} + +const char *sieve_extension_capabilities_get_string + (const char *cap_name) +{ + const struct sieve_extension_capabilities *cap = + (const struct sieve_extension_capabilities *) + hash_lookup(capabilities_index, cap_name); + + if ( cap == NULL || cap->get_string == NULL ) + return NULL; + + return cap->get_string(); +} + + + diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h index 8f1738b38f36c5b0cc3a4afc75db9f54a0285961..9c24962457928f11d740d89ec1e9717c52609ed1 100644 --- a/src/lib-sieve/sieve-extensions.h +++ b/src/lib-sieve/sieve-extensions.h @@ -91,4 +91,19 @@ const struct sieve_extension *sieve_extension_get_by_name(const char *name); const char *sieve_extensions_get_string(void); +/* + * Capability registries + */ + +struct sieve_extension_capabilities { + const char *name; + + const char *(*get_string)(void); +}; + +void sieve_extension_capabilities_register + (const struct sieve_extension_capabilities *cap); +const char *sieve_extension_capabilities_get_string + (const char *cap_name); + #endif /* __SIEVE_EXTENSIONS_H */ diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 718cd09dc1d698a7053acff7cdc71c6a789b996f..760f6eb68d68d40de7427109d7eed113a4a8aba7 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -43,9 +43,12 @@ void sieve_deinit(void) sieve_extensions_deinit(); } -const char *sieve_get_capabilities(void) +const char *sieve_get_capabilities(const char *name) { - return sieve_extensions_get_string(); + if ( name == NULL || *name == '\0' ) + return sieve_extensions_get_string(); + + return sieve_extension_capabilities_get_string(name); } /* diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index 417393eacac14c6d2ff048f8c21b5ec39520d7c5..b4f110f7b20acde0ea92f7648ac1c72100728db4 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -31,7 +31,7 @@ void sieve_deinit(void); /* sieve_get_capabilities: * */ -const char *sieve_get_capabilities(void); +const char *sieve_get_capabilities(const char *name); /* * Script compilation