changeset 22175:755d206606df

lib-mail: message_address_parse() - Handle invalid standalone phrases better 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"
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Wed, 07 Jun 2017 15:33:42 +0300
parents 935729d0802e
children fc301d74f851
files src/lib-mail/message-address.c src/lib-mail/test-message-address.c
diffstat 2 files changed, 42 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-mail/message-address.c	Wed Jun 07 15:22:22 2017 +0300
+++ b/src/lib-mail/message-address.c	Wed Jun 07 15:33:42 2017 +0300
@@ -209,10 +209,13 @@
 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 @@
 
 	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;
 }
 
--- a/src/lib-mail/test-message-address.c	Wed Jun 07 15:22:22 2017 +0300
+++ b/src/lib-mail/test-message-address.c	Wed Jun 07 15:33:42 2017 +0300
@@ -49,9 +49,23 @@
 		  { 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 @@
 		  { 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 @@
 		  { 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 @@
 		  { 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,