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>
---
 src/lib-mail/message-address.c |   66 +++++++++++++++++++++++++++++++++++++---
 1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/src/lib-mail/message-address.c b/src/lib-mail/message-address.c
index 54d4ee1..7d6356c 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;
@@ -369,7 +413,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, "=?"))
+                                               /* 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, "\"\"");
@@ -396,7 +447,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 {
@@ -404,7 +455,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, '<');
@@ -412,7 +470,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, '>');
-- 
1.7.9.5

Reply via email to