]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: message_address_parse() - Handle invalid standalone phrases better
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 7 Jun 2017 12:33:42 +0000 (15:33 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 12 Jun 2017 14:05:32 +0000 (17:05 +0300)
We'll treat "local-part" (without quotes) as a mailbox even without
@domain, but if it continues with anything or if it's a quoted-string,
we'll treat it as a display-name instead.

This is probably better than just converting everything to display-name,
since there are likely to exist headers like "To: localuser"

src/lib-mail/message-address.c
src/lib-mail/test-message-address.c

index ce1f30575d42007eb96aebdc36edd927d9be2280..c24564665c4d9ee0846a5536289ac49ffc4c584b 100644 (file)
@@ -209,10 +209,13 @@ static int parse_name_addr(struct message_address_parser_context *ctx)
 static int parse_addr_spec(struct message_address_parser_context *ctx)
 {
        /* addr-spec       = local-part "@" domain */
-       int ret, ret2;
+       int ret, ret2 = -2;
+
+       i_assert(ctx->parser.data != ctx->parser.end);
 
        str_truncate(ctx->parser.last_comment, 0);
 
+       bool quoted_string = *ctx->parser.data == '"';
        ret = parse_local_part(ctx);
        if (ret <= 0) {
                /* end of input or parsing local-part failed */
@@ -226,6 +229,24 @@ static int parse_addr_spec(struct message_address_parser_context *ctx)
 
        if (str_len(ctx->parser.last_comment) > 0)
                ctx->addr.name = p_strdup(ctx->pool, str_c(ctx->parser.last_comment));
+       else if (ret2 == -2) {
+               /* So far we've read user without @domain and without
+                  (Display Name). We'll assume that a single "user" (already
+                  read into addr.mailbox) is a mailbox, but if it's followed
+                  by anything else it's a display-name. */
+               str_append_c(ctx->str, ' ');
+               size_t orig_str_len = str_len(ctx->str);
+               (void)rfc822_parse_phrase(&ctx->parser, ctx->str);
+               if (str_len(ctx->str) != orig_str_len) {
+                       ctx->addr.mailbox = NULL;
+                       ctx->addr.name = p_strdup(ctx->pool, str_c(ctx->str));
+               } else {
+                       if (!quoted_string)
+                               ctx->addr.domain = "";
+               }
+               ctx->addr.invalid_syntax = TRUE;
+               ret = -1;
+       }
        return ret;
 }
 
index fbc9acdeadfa9d4b801d40081ab53df6ca6b07c4..cfc5ea0942970e1633c179197ff7b2cd81b5901a 100644 (file)
@@ -49,9 +49,23 @@ static void test_message_address(void)
                  { NULL, NULL, NULL, "user\"name", "domain", FALSE } },
                { "\"\"@domain", "<\"\"@domain>",
                  { NULL, NULL, NULL, "", "domain", FALSE } },
+               { "user", "<user>",
+                 { NULL, NULL, NULL, "user", "", TRUE } },
                { "@domain", "<\"\"@domain>",
                  { NULL, NULL, NULL, "", "domain", TRUE } },
 
+               /* Display Name -> Display Name */
+               { "Display Name", "\"Display Name\"",
+                 { NULL, "Display Name", NULL, "", "", TRUE } },
+               { "\"Display Name\"", "\"Display Name\"",
+                 { NULL, "Display Name", NULL, "", "", TRUE } },
+               { "Display \"Name\"", "\"Display Name\"",
+                 { NULL, "Display Name", NULL, "", "", TRUE } },
+               { "\"Display\" \"Name\"", "\"Display Name\"",
+                 { NULL, "Display Name", NULL, "", "", TRUE } },
+               { "\"\"", "",
+                 { NULL, "", NULL, "", "", TRUE } },
+
                /* <user@domain> -> <user@domain> */
                { "<user@domain>", NULL,
                  { NULL, NULL, NULL, "user", "domain", FALSE } },
@@ -65,6 +79,8 @@ static void test_message_address(void)
                  { NULL, NULL, NULL, "user\"name", "domain", FALSE } },
                { "<\"\"@domain>", NULL,
                  { NULL, NULL, NULL, "", "domain", FALSE } },
+               { "<user>", NULL,
+                 { NULL, NULL, NULL, "user", "", TRUE } },
                { "<@route>", "<@route:\"\">",
                  { NULL, NULL, "@route", "", "", TRUE } },
 
@@ -79,6 +95,8 @@ static void test_message_address(void)
                  { NULL, "Display Name", NULL, "user", "", TRUE } },
                { "@domain (Display Name)", "\"Display Name\" <\"\"@domain>",
                  { NULL, "Display Name", NULL, "", "domain", TRUE } },
+               { "user@domain ()", "<user@domain>",
+                 { NULL, NULL, NULL, "user", "domain", FALSE } },
 
                /* Display Name <user@domain> -> "Display Name" <user@domain> */
                { "DisplayName <user@domain>", NULL,
@@ -91,6 +109,8 @@ static void test_message_address(void)
                  { NULL, "Display\"Name", NULL, "user", "domain", FALSE } },
                { "Display Name <user>", "\"Display Name\" <user>",
                  { NULL, "Display Name", NULL, "user", "", TRUE } },
+               { "\"\" <user@domain>", "<user@domain>",
+                 { NULL, NULL, NULL, "user", "domain", FALSE } },
 
                /* <@route:user@domain> -> <@route:user@domain> */
                { "<@route:user@domain>", NULL,