From 06b238a1c399b5d5a7ab0b7aecb65e4133c25332 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Mon, 22 Oct 2007 14:40:01 +0200 Subject: [PATCH] Changed (currently unused) sieve-address.c to use dovecot rfc822 parser. --- src/lib-sieve/sieve-address.c | 244 +++++++++++++++++++--------------- 1 file changed, 137 insertions(+), 107 deletions(-) diff --git a/src/lib-sieve/sieve-address.c b/src/lib-sieve/sieve-address.c index af21ce532..65b523db5 100644 --- a/src/lib-sieve/sieve-address.c +++ b/src/lib-sieve/sieve-address.c @@ -1,14 +1,16 @@ -#include <string.h> +#include "lib.h" +#include "str.h" +#include "message-parser.h" +#include "message-address.h" +#include "rfc822-parser.h" -//#include "sieve-address.h" +/* WARNING: This file contains code duplicated from dovecot/src/lib-mail/message-address.c */ /* FIXME: Currently accepts only c-strings and no \0 characters (not according to spec) */ #ifdef TEST #include <stdio.h> - -typedef enum { FALSE, TRUE } bool; #endif /* Sieve address as defined in RFC3028 [SIEVE] and RFC822 [IMAIL]: @@ -53,124 +55,152 @@ typedef enum { FALSE, TRUE } bool; * at-sign ("@") and exactly one SPACE between all other <word>s. */ -#define IS_CHAR(c) ( c <= 127 ) -#define IS_NOT_CTL(c) ( c > 31 && c < 127 ) -#define IS_SPACE(c) ( c == ' ' ) -#define IS_SPECIAL(c) ( strchr( "()<>@,;:\\\".[]", c) != NULL ) -#define IS_ATOM_CHAR(c) ( IS_NOT_CTL(c) && !IS_SPECIAL(c) && !IS_SPACE(c) ) -#define IS_QTEXT_CHAR(c) ( IS_CHAR(c) && c != '"' && c != '\\' && c != '\r' ) -#define IS_DTEXT_CHAR(c) ( IS_CHAR(c) && c != '[' && c != ']' && c != '\\' && c != '\r' ) - -/* Useful macro's to manipulate the pointer, also prevents reading beyond end of string */ -#define shift(p) { if (**p == '\0') return FALSE; else printf("%c\n", **p); (*p)++; } -#define cur(p) (**p) - -static bool parse_subdomain(const unsigned char **input) { - if ( cur(input) == '[' ) { - /* Parse quoted-string */ - shift(input); - while ( TRUE ) { - if ( cur(input) == '\\' ) { - shift(input); - shift(input); - } else if ( IS_DTEXT_CHAR(cur(input)) ) { - shift(input); - } else - break; - } - - if ( cur(input) != ']' ) return FALSE; - - shift(input); - return TRUE; - } else if ( IS_ATOM_CHAR(cur(input)) ) { - /* Parse atom */ - while ( IS_ATOM_CHAR(cur(input)) ) { - shift(input); - } - - return TRUE; - } +struct sieve_address_parser_context { + pool_t pool; + struct rfc822_parser_context parser; - return FALSE; + const char *name, *mailbox, *domain; + + string_t *str; +}; + +static int parse_local_part(struct sieve_address_parser_context *ctx) +{ + int ret; + + /* + local-part = dot-atom / quoted-string / obs-local-part + obs-local-part = word *("." word) + */ + if (ctx->parser.data == ctx->parser.end) + return 0; + + str_truncate(ctx->str, 0); + if (*ctx->parser.data == '"') + ret = rfc822_parse_quoted_string(&ctx->parser, ctx->str); + else + ret = rfc822_parse_dot_atom(&ctx->parser, ctx->str); + if (ret < 0) + return -1; + + ctx->mailbox = p_strdup(ctx->pool, str_c(ctx->str)); + return ret; +} + +static int parse_domain(struct sieve_address_parser_context *ctx) +{ + int ret; + + str_truncate(ctx->str, 0); + if ((ret = rfc822_parse_domain(&ctx->parser, ctx->str)) < 0) + return -1; + + ctx->domain = p_strdup(ctx->pool, str_c(ctx->str)); + return ret; } -static bool parse_word(const unsigned char **input) { - if ( cur(input) == '"' ) { - /* Parse quoted-string */ - shift(input); - while ( TRUE ) { - if ( cur(input) == '\\' ) { - shift(input); - shift(input); - } else if ( IS_QTEXT_CHAR(cur(input)) ) { - shift(input); - } else - break; - } - - if ( cur(input) != '"' ) return FALSE; - - shift(input); - return TRUE; - } else if ( IS_ATOM_CHAR(cur(input)) ) { - /* Parse atom */ - while ( IS_ATOM_CHAR(cur(input)) ) { - shift(input); - } +static int parse_angle_addr(struct sieve_address_parser_context *ctx) +{ + int ret; + + /* "<" local-part "@" domain ">" */ + i_assert(*ctx->parser.data == '<'); + ctx->parser.data++; + + if ((ret = rfc822_skip_lwsp(&ctx->parser)) <= 0) + return ret; + + if ((ret = parse_local_part(ctx)) <= 0) + return ret; - return TRUE; + if (*ctx->parser.data == '@') { + if ((ret = parse_domain(ctx)) <= 0) + return ret; } - - return FALSE; + + if (*ctx->parser.data != '>') + return -1; + ctx->parser.data++; + + return rfc822_skip_lwsp(&ctx->parser); } -bool sieve_address_validate(const unsigned char *address) +static int parse_name_addr(struct sieve_address_parser_context *ctx) { - /* Parse local part */ - if ( parse_word(&address) ) { - while ( cur(&address) == '.' ) { - shift(&address) - if ( !parse_word(&address) ) { - return FALSE; - } - } - } else return FALSE; - - if ( cur(&address) == '@' ) { - shift(&address); - - if ( parse_subdomain(&address) ) { - while ( cur(&address) == '.' ) { - shift(&address) - if ( !parse_subdomain(&address) ) { - return FALSE; - } - } - } else return FALSE; - - return TRUE; + /* phrase "<" addr-spec ">" ; name & addr-spec */ + str_truncate(ctx->str, 0); + if (rfc822_parse_phrase(&ctx->parser, ctx->str) <= 0 || + *ctx->parser.data != '<') + return -1; + + ctx->addr.name = p_strdup(ctx->pool, str_c(ctx->str)); + if (*ctx->addr.name == '\0') { + /* Cope with "<address>" without display name */ + ctx->addr.name = NULL; } - - return FALSE; + if (parse_angle_addr(ctx) < 0) { + /* broken */ + ctx->addr.domain = p_strdup(ctx->pool, "SYNTAX_ERROR"); + } + return ctx->parser.data != ctx->parser.end; } -#ifdef TEST /* TEST - gcc -DTEST -o test sieve-address.c */ +static int parse_addr_spec(struct message_address_parser_context *ctx) +{ + /* addr-spec = local-part "@" domain */ + int ret; -#include <stdio.h> -#include <stdlib.h> + str_truncate(ctx->parser.last_comment, 0); -int main(int argc, char **argv) { - if ( argc != 2 ) { - printf("Usage: test <address>\n"); - exit(1); + if ((ret = parse_local_part(ctx)) < 0) + return ret; + if (ret > 0 && *ctx->parser.data == '@') { + if ((ret = parse_domain(ctx)) < 0) + return ret; } - - if ( sieve_address_validate(argv[1]) ) - printf("Addres valid.\n"); - else - printf("Addres invalid.\n"); + + if (str_len(ctx->parser.last_comment) > 0) { + ctx->addr.name = + p_strdup(ctx->pool, str_c(ctx->parser.last_comment)); + } + return ret; } +static int sieve_address_parse(pool_t pool, const unsigned char *data, size_t size) +{ + struct sieve_address_parser_context ctx; + const unsigned char *start; + int ret; + + if (!pool->datastack_pool) + t_push(); + + memset(&ctx, 0, sizeof(ctx)); + + rfc822_parser_init(&ctx.parser, data, size, t_str_new(128)); + ctx.pool = pool; + ctx.str = t_str_new(128); + + rfc822_skip_lwsp(&ctx.parser); + if (ctx->parser.data == ctx->parser.end) + return 0; + + /* sieve-address = addr-spec ; simple address + * / phrase "<" addr-spec ">" ; name & addr-spec + */ + start = ctx->parser.data; + if ((ret = parse_name_addr(ctx)) < 0) { + /* nope, should be addr-spec */ + ctx->parser.data = start; + if ((ret = parse_addr_spec(ctx)) < 0) + return -1; + } + + if (!pool->datastack_pool + t_pop(); + return ret; +} + + #endif -- GitLab