From: Pali Rohár Date: Sun, 5 Jun 2016 13:48:19 +0000 (+0200) Subject: lib-mail: message_address_write: Quote and escape strings if needed X-Git-Tag: 2.2.31.rc1~101 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e209e9d36e48fb1f0e294b216eb1ba6f8aafcb7;p=thirdparty%2Fdovecot%2Fcore.git lib-mail: message_address_write: Quote and escape strings if needed ATEXT characters must be properly quoted when are in phrase. Test case: { name = "test\"test", mailbox = "user", domain = "host" } converts to: "test\"test" --- diff --git a/src/lib-mail/message-address.c b/src/lib-mail/message-address.c index 69dc59e9db..4a63362169 100644 --- a/src/lib-mail/message-address.c +++ b/src/lib-mail/message-address.c @@ -2,6 +2,7 @@ #include "lib.h" #include "str.h" +#include "strescape.h" #include "message-parser.h" #include "message-address.h" #include "rfc822-parser.h" @@ -32,6 +33,49 @@ static void add_address(struct message_address_parser_context *ctx) ctx->last_addr = addr; } +/* quote with "" and escape all '\', '"' and "'" characters if need */ +static void str_append_maybe_escape(string_t *dest, const char *cstr, bool escape_dot) +{ + const char *p; + + /* see if we need to quote it */ + for (p = cstr; *p != '\0'; p++) { + if (!IS_ATEXT(*p) && (escape_dot || *p != '.')) + break; + } + + if (*p == '\0') { + str_append_data(dest, cstr, (size_t) (p - cstr)); + return; + } + + /* see if we need to escape it */ + for (p = cstr; *p != '\0'; p++) { + if (IS_ESCAPED_CHAR(*p)) + break; + } + + if (*p == '\0') { + /* only quote */ + str_append_c(dest, '"'); + str_append_data(dest, cstr, (size_t) (p - cstr)); + str_append_c(dest, '"'); + return; + } + + /* quote and escape */ + str_append_c(dest, '"'); + str_append_data(dest, cstr, (size_t) (p - cstr)); + + for (; *p != '\0'; p++) { + if (IS_ESCAPED_CHAR(*p)) + str_append_c(dest, '\\'); + str_append_c(dest, *p); + } + + str_append_c(dest, '"'); +} + static int parse_local_part(struct message_address_parser_context *ctx) { int ret; @@ -371,7 +415,14 @@ void message_address_write(string_t *str, const struct message_address *addr) /* beginning of group. mailbox is the group name, others are NULL. */ if (addr->mailbox != NULL && *addr->mailbox != '\0') { - str_append(str, addr->mailbox); + /* check for MIME encoded-word */ + if (strstr(addr->mailbox, "=?") != NULL) + /* MIME encoded-word MUST NOT appear within a 'quoted-string' + so escaping and quoting of phrase is not possible, instead + use obsolete RFC822 phrase syntax which allow spaces */ + str_append(str, addr->mailbox); + else + str_append_maybe_escape(str, addr->mailbox, TRUE); } else { /* empty group name needs to be quoted */ str_append(str, "\"\""); @@ -398,7 +449,7 @@ void message_address_write(string_t *str, const struct message_address *addr) /* no name and no route. use only mailbox@domain */ i_assert(addr->mailbox != NULL); - str_append(str, addr->mailbox); + str_append_maybe_escape(str, addr->mailbox, FALSE); str_append_c(str, '@'); str_append(str, addr->domain); } else { @@ -406,7 +457,14 @@ void message_address_write(string_t *str, const struct message_address *addr) i_assert(addr->mailbox != NULL); if (addr->name != NULL) { - str_append(str, addr->name); + /* check for MIME encoded-word */ + if (strstr(addr->name, "=?")) + /* MIME encoded-word MUST NOT appear within a 'quoted-string' + so escaping and quoting of phrase is not possible, instead + use obsolete RFC822 phrase syntax which allow spaces */ + str_append(str, addr->name); + else + str_append_maybe_escape(str, addr->name, TRUE); str_append_c(str, ' '); } str_append_c(str, '<'); @@ -414,7 +472,7 @@ void message_address_write(string_t *str, const struct message_address *addr) str_append(str, addr->route); str_append_c(str, ':'); } - str_append(str, addr->mailbox); + str_append_maybe_escape(str, addr->mailbox, FALSE); str_append_c(str, '@'); str_append(str, addr->domain); str_append_c(str, '>');