Mercurial > dovecot > core-2.2
changeset 22158:862126b86ef1
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" <user@host>
author | Pali Rohár <pali.rohar@gmail.com> |
---|---|
date | Sun, 05 Jun 2016 15:48:19 +0200 |
parents | 19734488e58a |
children | 4d0360081722 |
files | src/lib-mail/message-address.c |
diffstat | 1 files changed, 62 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-mail/message-address.c Sun Jun 05 15:48:18 2016 +0200 +++ b/src/lib-mail/message-address.c Sun Jun 05 15:48:19 2016 +0200 @@ -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 @@ 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 @@ /* 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 @@ /* 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 @@ 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 @@ 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, '>');