diff --git a/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c b/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c index 561fea8e1fa220f580289ba0bdaf73d45a546df7..334bc62a95faf7bd01c038d105af0c069d4ff88a 100644 --- a/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c +++ b/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c @@ -2,10 +2,10 @@ */ /* FIXME: URI syntax conforms to something somewhere in between RFC 2368 and - * draft-duerst-mailto-bis-05.txt. Should fully migrate to new specification - * when it matures. This requires modifications to the address parser (no - * whitespace allowed within the address itself) and UTF-8 support will be - * required in the URL. + draft-duerst-mailto-bis-05.txt. Should fully migrate to new + specification when it matures. This requires modifications to the + address parser (no whitespace allowed within the address itself) and + UTF-8 support will be required in the URL. */ #include "lib.h" @@ -71,37 +71,39 @@ uri_mailto_log(struct uri_mailto_parser *parser, enum log_type log_type, * Reserved and unique headers */ -static inline bool uri_mailto_header_is_reserved -(struct uri_mailto_parser *parser, const char *field_name) +static inline bool +uri_mailto_header_is_reserved(struct uri_mailto_parser *parser, + const char *field_name) { const char **hdr = parser->reserved_headers; - if ( hdr == NULL ) return FALSE; + if (hdr == NULL) + return FALSE; /* Check whether it is reserved */ - while ( *hdr != NULL ) { - if ( strcasecmp(field_name, *hdr) == 0 ) + while (*hdr != NULL) { + if (strcasecmp(field_name, *hdr) == 0) return TRUE; hdr++; } - return FALSE; } -static inline bool uri_mailto_header_is_unique -(struct uri_mailto_parser *parser, const char *field_name) +static inline bool +uri_mailto_header_is_unique(struct uri_mailto_parser *parser, + const char *field_name) { const char **hdr = parser->unique_headers; - if ( hdr == NULL ) return FALSE; + if (hdr == NULL) + return FALSE; /* Check whether it is supposed to be unique */ - while ( *hdr != NULL ) { - if ( strcasecmp(field_name, *hdr) == 0 ) + while (*hdr != NULL) { + if (strcasecmp(field_name, *hdr) == 0) return TRUE; hdr++; } - return FALSE; } @@ -139,18 +141,15 @@ static inline bool _is_qchar(unsigned char c) static inline int _decode_hex_digit(unsigned char digit) { - switch ( digit ) { + switch (digit) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return (int) digit - '0'; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return (int) digit - 'a' + 0x0a; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': return (int) digit - 'A' + 0x0A; } - return -1; } @@ -158,22 +157,22 @@ static bool _parse_hex_value(const char **in, char *out) { int value, digit; - if ( (digit=_decode_hex_digit((unsigned char) **in)) < 0 ) + if ((digit = _decode_hex_digit((unsigned char)**in)) < 0) return FALSE; value = digit << 4; (*in)++; - if ( (digit=_decode_hex_digit((unsigned char) **in)) < 0 ) + if ((digit = _decode_hex_digit((unsigned char)**in)) < 0) return FALSE; value |= digit; (*in)++; - if ( value == 0 ) + if (value == 0) return FALSE; - *out = (char) value; + *out = (char)value; return TRUE; } @@ -181,8 +180,9 @@ static bool _parse_hex_value(const char **in, char *out) * URI recipient parsing */ -static bool uri_mailto_add_valid_recipient -(struct uri_mailto_parser *parser, string_t *recipient, bool cc) +static bool +uri_mailto_add_valid_recipient(struct uri_mailto_parser *parser, + string_t *recipient, bool cc) { struct uri_mailto *uri = parser->uri; struct uri_mailto_recipient *new_recipient; @@ -192,35 +192,41 @@ static bool uri_mailto_add_valid_recipient const struct smtp_address *address; /* Verify recipient */ - if ( (address=sieve_address_parse_str - (recipient, &error)) == NULL ) { + if ((address = sieve_address_parse_str(recipient, &error)) == NULL) { uri_mailto_error(parser, "invalid recipient '%s': %s", - str_sanitize(str_c(recipient), 80), error); + str_sanitize(str_c(recipient), 80), error); return FALSE; } /* Add recipient to the uri */ - if ( uri != NULL ) { + if (uri != NULL) { /* Get current recipients */ rcpts = array_get_modifiable(&uri->recipients, &count); /* Enforce limits */ - if ( parser->max_recipients > 0 && (int)count >= parser->max_recipients ) { - if ( (int)count == parser->max_recipients) { - uri_mailto_warning(parser, + if (parser->max_recipients > 0 && + (int)count >= parser->max_recipients) { + if ((int)count == parser->max_recipients) { + uri_mailto_warning( + parser, "more than the maximum %u recipients specified; " - "rest is discarded", parser->max_recipients); + "rest is discarded", + parser->max_recipients); } return TRUE; } /* Check for duplicate first */ - for ( i = 0; i < count; i++ ) { - if ( smtp_address_equals(rcpts[i].address, address) ) { - /* Upgrade existing Cc: recipient to a To: recipient if possible */ - rcpts[i].carbon_copy = ( rcpts[i].carbon_copy && cc ); - - uri_mailto_warning(parser, "ignored duplicate recipient '%s'", + for (i = 0; i < count; i++) { + if (smtp_address_equals(rcpts[i].address, address)) { + /* Upgrade existing Cc: recipient to a To: + recipient if possible */ + rcpts[i].carbon_copy = + (rcpts[i].carbon_copy && cc); + + uri_mailto_warning( + parser, + "ignored duplicate recipient '%s'", str_sanitize(str_c(recipient), 80)); return TRUE; } @@ -230,50 +236,55 @@ static bool uri_mailto_add_valid_recipient new_recipient = array_append_space(&uri->recipients); new_recipient->carbon_copy = cc; new_recipient->full = p_strdup(parser->pool, str_c(recipient)); - new_recipient->address = smtp_address_clone(parser->pool, address); + new_recipient->address = + smtp_address_clone(parser->pool, address); } return TRUE; } -static bool uri_mailto_parse_recipients -(struct uri_mailto_parser *parser, const char **uri_p) +static bool +uri_mailto_parse_recipients(struct uri_mailto_parser *parser, + const char **uri_p) { string_t *to = t_str_new(128); const char *p = *uri_p; - if ( *p == '\0' || *p == '?' ) + if (*p == '\0' || *p == '?') return TRUE; - while ( *p != '\0' && *p != '?' ) { - if ( *p == '%' ) { + while (*p != '\0' && *p != '?') { + if (*p == '%') { /* % encoded character */ char ch; p++; /* Parse 2-digit hex value */ - if ( !_parse_hex_value(&p, &ch) ) { + if (!_parse_hex_value(&p, &ch)) { uri_mailto_error(parser, "invalid %% encoding"); return FALSE; } /* Check for delimiter */ - if ( ch == ',' ) { + if (ch == ',') { /* Verify and add recipient */ - if ( !uri_mailto_add_valid_recipient(parser, to, FALSE) ) + if (!uri_mailto_add_valid_recipient( + parser, to, FALSE)) return FALSE; /* Reset for next recipient */ str_truncate(to, 0); - } else { + } else { /* Content character */ str_append_c(to, ch); } } else { - if ( *p == ':' || *p == ';' || *p == ',' || !_is_qchar(*p) ) { - uri_mailto_error - (parser, "invalid character '%c' in 'to' part", *p); + if (*p == ':' || *p == ';' || *p == ',' || + !_is_qchar(*p)) { + uri_mailto_error( + parser, + "invalid character '%c' in 'to' part", *p); return FALSE; } @@ -283,27 +294,28 @@ static bool uri_mailto_parse_recipients } } - i_assert( *p == '\0' || *p == '?' ); + i_assert(*p == '\0' || *p == '?'); /* Verify and add recipient */ - if ( !uri_mailto_add_valid_recipient(parser, to, FALSE) ) + if (!uri_mailto_add_valid_recipient(parser, to, FALSE)) return FALSE; *uri_p = p; return TRUE; } -static bool uri_mailto_parse_header_recipients -(struct uri_mailto_parser *parser, string_t *rcpt_header, bool cc) +static bool +uri_mailto_parse_header_recipients(struct uri_mailto_parser *parser, + string_t *rcpt_header, bool cc) { string_t *to = t_str_new(128); - const char *p = (const char *) str_data(rcpt_header); + const char *p = (const char *)str_data(rcpt_header); const char *pend = p + str_len(rcpt_header); - while ( p < pend ) { - if ( *p == ',' ) { + while (p < pend) { + if (*p == ',') { /* Verify and add recipient */ - if ( !uri_mailto_add_valid_recipient(parser, to, cc) ) + if (!uri_mailto_add_valid_recipient(parser, to, cc)) return FALSE; /* Reset for next recipient */ @@ -316,7 +328,7 @@ static bool uri_mailto_parse_header_recipients } /* Verify and add recipient */ - if ( !uri_mailto_add_valid_recipient(parser, to, cc) ) + if (!uri_mailto_add_valid_recipient(parser, to, cc)) return FALSE; return TRUE; @@ -324,80 +336,90 @@ static bool uri_mailto_parse_header_recipients /* URI header parsing */ -static bool uri_mailto_header_is_duplicate -(struct uri_mailto_parser *parser, const char *field_name) +static bool +uri_mailto_header_is_duplicate(struct uri_mailto_parser *parser, + const char *field_name) { struct uri_mailto *uri = parser->uri; - if ( uri == NULL ) return FALSE; + if (uri == NULL) + return FALSE; - if ( uri_mailto_header_is_unique(parser, field_name) ) { + if (uri_mailto_header_is_unique(parser, field_name)) { const struct uri_mailto_header_field *hdrs; unsigned int count, i; hdrs = array_get(&uri->headers, &count); - for ( i = 0; i < count; i++ ) { - if ( strcasecmp(hdrs[i].name, field_name) == 0 ) + for (i = 0; i < count; i++) { + if (strcasecmp(hdrs[i].name, field_name) == 0) return TRUE; } } - return FALSE; } -static bool uri_mailto_parse_headers -(struct uri_mailto_parser *parser, const char **uri_p) +static bool +uri_mailto_parse_headers(struct uri_mailto_parser *parser, const char **uri_p) { struct uri_mailto *uri = parser->uri; unsigned int header_count = 0; string_t *field = t_str_new(128); const char *p = *uri_p; - while ( *p != '\0' ) { + while (*p != '\0') { enum { _HNAME_IGNORED, _HNAME_GENERIC, _HNAME_TO, _HNAME_CC, _HNAME_SUBJECT, - _HNAME_BODY + _HNAME_BODY, } hname_type = _HNAME_GENERIC; struct uri_mailto_header_field *hdrf = NULL; const char *field_name; /* Parse field name */ - while ( *p != '\0' && *p != '=' ) { + while (*p != '\0' && *p != '=') { char ch = *p; p++; - if ( ch == '%' ) { + if (ch == '%') { /* Encoded, parse 2-digit hex value */ - if ( !_parse_hex_value(&p, &ch) ) { - uri_mailto_error(parser, "invalid %% encoding"); + if (!_parse_hex_value(&p, &ch)) { + uri_mailto_error(parser, + "invalid %% encoding"); return FALSE; } - } else if ( ch != '=' && !_is_qchar(ch) ) { - uri_mailto_error - (parser, "invalid character '%c' in header field name part", ch); + } else if (ch != '=' && !_is_qchar(ch)) { + uri_mailto_error( + parser, + "invalid character '%c' in header field name part", + ch); return FALSE; } str_append_c(field, ch); } - if ( *p != '\0' ) p++; + if (*p != '\0') + p++; /* Verify field name */ - if ( !rfc2822_header_field_name_verify(str_c(field), str_len(field)) ) { + if (!rfc2822_header_field_name_verify(str_c(field), + str_len(field))) { uri_mailto_error(parser, "invalid header field name"); return FALSE; } - if ( parser->max_headers > -1 && - (int)header_count >= parser->max_headers ) { - /* Refuse to accept more headers than allowed by policy */ - if ( (int)header_count == parser->max_headers ) { - uri_mailto_warning(parser, "more than the maximum %u headers specified; " - "rest is discarded", parser->max_headers); + if (parser->max_headers > -1 && + (int)header_count >= parser->max_headers) { + /* Refuse to accept more headers than allowed by policy + */ + if ((int)header_count == parser->max_headers) { + uri_mailto_warning( + parser, + "more than the maximum %u headers specified; " + "rest is discarded", + parser->max_headers); } hname_type = _HNAME_IGNORED; @@ -405,21 +427,22 @@ static bool uri_mailto_parse_headers /* Add new header field to array and assign its name */ field_name = str_c(field); - if ( strcasecmp(field_name, "to") == 0 ) + if (strcasecmp(field_name, "to") == 0) hname_type = _HNAME_TO; - else if ( strcasecmp(field_name, "cc") == 0 ) + else if (strcasecmp(field_name, "cc") == 0) hname_type = _HNAME_CC; - else if ( strcasecmp(field_name, "subject") == 0 ) + else if (strcasecmp(field_name, "subject") == 0) hname_type = _HNAME_SUBJECT; - else if ( strcasecmp(field_name, "body") == 0 ) + else if (strcasecmp(field_name, "body") == 0) hname_type = _HNAME_BODY; - else if ( !uri_mailto_header_is_reserved(parser, field_name) ) { - if ( uri != NULL ) { - if ( !uri_mailto_header_is_duplicate(parser, field_name) ) { + else if (!uri_mailto_header_is_reserved(parser, field_name)) { + if (uri != NULL) { + if (!uri_mailto_header_is_duplicate(parser, field_name)) { hdrf = array_append_space(&uri->headers); hdrf->name = p_strdup(parser->pool, field_name); } else { - uri_mailto_warning(parser, + uri_mailto_warning( + parser, "ignored duplicate for unique header field '%s'", str_sanitize(field_name, 32)); hname_type = _HNAME_IGNORED; @@ -428,7 +451,9 @@ static bool uri_mailto_parse_headers hname_type = _HNAME_IGNORED; } } else { - uri_mailto_warning(parser, "ignored reserved header field '%s'", + uri_mailto_warning( + parser, + "ignored reserved header field '%s'", str_sanitize(field_name, 32)); hname_type = _HNAME_IGNORED; } @@ -440,71 +465,85 @@ static bool uri_mailto_parse_headers str_truncate(field, 0); /* Parse field body */ - while ( *p != '\0' && *p != '&' ) { + while (*p != '\0' && *p != '&') { char ch = *p; p++; - if ( ch == '%' ) { + if (ch == '%') { /* Encoded, parse 2-digit hex value */ - if ( !_parse_hex_value(&p, &ch) ) { - uri_mailto_error(parser, "invalid %% encoding"); + if (!_parse_hex_value(&p, &ch)) { + uri_mailto_error(parser, + "invalid %% encoding"); return FALSE; } - } else if ( ch != '=' && !_is_qchar(ch) ) { - uri_mailto_error - (parser, "invalid character '%c' in header field value part", ch); + } else if (ch != '=' && !_is_qchar(ch)) { + uri_mailto_error( + parser, + "invalid character '%c' in header field value part", + ch); return FALSE; } str_append_c(field, ch); } - if ( *p != '\0' ) p++; + if (*p != '\0') + p++; /* Verify field body */ - if ( hname_type == _HNAME_BODY ) { + if (hname_type == _HNAME_BODY) { // FIXME: verify body ... } else { - if ( !rfc2822_header_field_body_verify - (str_c(field), str_len(field), FALSE, FALSE) ) { - uri_mailto_error(parser, "invalid header field body"); + if (!rfc2822_header_field_body_verify( + str_c(field), str_len(field), FALSE, FALSE)) { + uri_mailto_error(parser, + "invalid header field body"); return FALSE; } } /* Assign field body */ - switch ( hname_type ) { + switch (hname_type) { case _HNAME_IGNORED: break; case _HNAME_TO: /* Gracefully allow duplicate To fields */ - if ( !uri_mailto_parse_header_recipients(parser, field, FALSE) ) + if (!uri_mailto_parse_header_recipients( + parser, field, FALSE)) return FALSE; break; case _HNAME_CC: /* Gracefully allow duplicate Cc fields */ - if ( !uri_mailto_parse_header_recipients(parser, field, TRUE) ) + if (!uri_mailto_parse_header_recipients( + parser, field, TRUE)) return FALSE; break; case _HNAME_SUBJECT: - /* Igore duplicate subject field */ - if ( uri != NULL ) { - if ( uri->subject == NULL ) - uri->subject = p_strdup(parser->pool, str_c(field)); - else - uri_mailto_warning(parser, "ignored duplicate subject field"); + /* Ignore duplicate subject field */ + if (uri != NULL) { + if (uri->subject == NULL) { + uri->subject = + p_strdup(parser->pool, str_c(field)); + } else { + uri_mailto_warning( + parser, + "ignored duplicate subject field"); + } } break; case _HNAME_BODY: - /* Igore duplicate body field */ - if ( uri != NULL ) { - if ( uri->body == NULL ) - uri->body = p_strdup(parser->pool, str_c(field)); - else - uri_mailto_warning(parser, "ignored duplicate body field"); + /* Ignore duplicate body field */ + if (uri != NULL) { + if (uri->body == NULL) { + uri->body = p_strdup( + parser->pool, str_c(field)); + } else { + uri_mailto_warning( + parser, "ignored duplicate body field"); + } } break; case _HNAME_GENERIC: - if ( uri != NULL && hdrf != NULL ) + if (uri != NULL && hdrf != NULL) hdrf->body = p_strdup(parser->pool, str_c(field)); break; } @@ -514,14 +553,15 @@ static bool uri_mailto_parse_headers } /* Skip '&' */ - if ( *p != '\0' ) p++; + if (*p != '\0') + p++; *uri_p = p; return TRUE; } -static bool uri_mailto_parse_uri -(struct uri_mailto_parser *parser, const char *uri_body) +static bool +uri_mailto_parse_uri(struct uri_mailto_parser *parser, const char *uri_body) { const char *p = uri_body; @@ -547,22 +587,22 @@ static bool uri_mailto_parse_uri /* First extract to-part by searching for '?' and decoding % items */ - if ( !uri_mailto_parse_recipients(parser, &p) ) + if (!uri_mailto_parse_recipients(parser, &p)) return FALSE; - if ( *p == '\0' ) + if (*p == '\0') return TRUE; - i_assert( *p == '?' ); + i_assert(*p == '?'); p++; /* Extract hfield items */ - while ( *p != '\0' ) { - /* Extract hfield item by searching for '&' and decoding '%' items */ - if ( !uri_mailto_parse_headers(parser, &p) ) + while (*p != '\0') { + /* Extract hfield item by searching for '&' and decoding '%' + items */ + if (!uri_mailto_parse_headers(parser, &p)) return FALSE; } - return TRUE; } @@ -570,10 +610,10 @@ static bool uri_mailto_parse_uri * Validation */ -bool uri_mailto_validate -(const char *uri_body, const char **reserved_headers, - const char **unique_headers, int max_recipients, int max_headers, - const struct uri_mailto_log *log) +bool uri_mailto_validate(const char *uri_body, + const char **reserved_headers, + const char **unique_headers, int max_recipients, + int max_headers, const struct uri_mailto_log *log) { struct uri_mailto_parser parser; @@ -585,7 +625,7 @@ bool uri_mailto_validate parser.unique_headers = unique_headers; /* If no errors are reported, we don't need to record any data */ - if ( log != NULL ) { + if (log != NULL) { parser.pool = pool_datastack_create(); parser.uri = p_new(parser.pool, struct uri_mailto, 1); @@ -593,14 +633,16 @@ bool uri_mailto_validate p_array_init(&parser.uri->headers, parser.pool, max_headers); } - if ( !uri_mailto_parse_uri(&parser, uri_body) ) + if (!uri_mailto_parse_uri(&parser, uri_body)) return FALSE; - if ( log != NULL ) { - if ( array_count(&parser.uri->recipients) == 0 ) - uri_mailto_warning(&parser, "notification URI specifies no recipients"); + if (log != NULL) { + if (array_count(&parser.uri->recipients) == 0) { + uri_mailto_warning( + &parser, + "notification URI specifies no recipients"); + } } - return TRUE; } @@ -608,10 +650,11 @@ bool uri_mailto_validate * Parsing */ -struct uri_mailto *uri_mailto_parse -(const char *uri_body, pool_t pool, const char **reserved_headers, - const char **unique_headers, int max_recipients, int max_headers, - const struct uri_mailto_log *log) +struct uri_mailto * +uri_mailto_parse(const char *uri_body, pool_t pool, + const char **reserved_headers, const char **unique_headers, + int max_recipients, int max_headers, + const struct uri_mailto_log *log) { struct uri_mailto_parser parser; @@ -626,18 +669,15 @@ struct uri_mailto *uri_mailto_parse p_array_init(&parser.uri->recipients, pool, max_recipients); p_array_init(&parser.uri->headers, pool, max_headers); - if ( !uri_mailto_parse_uri(&parser, uri_body) ) + if (!uri_mailto_parse_uri(&parser, uri_body)) return NULL; - if ( log != NULL ) { - if ( array_count(&parser.uri->recipients) == 0 ) - uri_mailto_warning(&parser, "notification URI specifies no recipients"); + if (log != NULL) { + if (array_count(&parser.uri->recipients) == 0) { + uri_mailto_warning( + &parser, + "notification URI specifies no recipients"); + } } - return parser.uri; } - - - - -