simplify rfc822 parsing *A LOT*
authorPierre Habouzit <madcoder@debian.org>
Fri, 3 Nov 2006 02:26:43 +0000 (03:26 +0100)
committerPierre Habouzit <madcoder@debian.org>
Fri, 3 Nov 2006 02:26:43 +0000 (03:26 +0100)
Signed-off-by: Pierre Habouzit <madcoder@debian.org>
lib-mime/mime.h
lib-mime/rfc822.c

index 269b0d0..90f8c68 100644 (file)
@@ -90,16 +90,6 @@ extern const char *BodyEncodings[];
 /*                Standard for ARPA Internet Text Messages                  */
 /****************************************************************************/
 
-/* possible values for RFC822Error */
-enum {
-    ERR_MEMORY = 1,
-    ERR_MISMATCH_PAREN,
-    ERR_MISMATCH_QUOTE,
-    ERR_BAD_ROUTE,
-    ERR_BAD_ROUTE_ADDR,
-    ERR_BAD_ADDR_SPEC
-};
-
 typedef struct address_t {
     char *personal;               /* real name of address */
     char *mailbox;                /* mailbox and host address */
@@ -114,18 +104,18 @@ DO_NEW(address_t, address);
 DO_DELETE(address_t, address);
 DO_SLIST(address_t, address);
 
+
 address_t *address_dup(address_t *addr);
 address_t *address_list_dup(address_t *addr);
-
 void rfc822_qualify(address_t *, const char *);
 
 address_t *rfc822_parse_adrlist(address_t *, const char *s);
+
 void rfc822_write_address(char *, size_t, address_t *, int);
 void rfc822_write_address_single(char *, size_t, address_t *, int);
 void rfc822_cat(char *, size_t, const char *, const char *);
 
 extern int RFC822Error;
-extern const char *RFC822Errors[];
 extern const char RFC822Specials[];
 
 #define rfc822_error(x) RFC822Errors[x]
index e73b408..708955b 100644 (file)
@@ -37,6 +37,8 @@
 
 #include "mutt_idna.h"
 
+const char RFC822Specials[] = "@.,:;<>[]\\\"()";
+
 void address_wipe(address_t *addr)
 {
     p_delete(&addr->personal);
@@ -50,7 +52,7 @@ void rfc822_qualify(address_t *addr, const char *host)
     char *p;
 
     for (; addr; addr = addr->next) {
-        if (!addr->group && addr->mailbox && strchr(addr->mailbox, '@') == NULL) {
+        if (!addr->group && addr->mailbox && !strchr(addr->mailbox, '@')) {
             p = p_new(char, m_strlen(addr->mailbox) + m_strlen(host) + 2);
             sprintf(p, "%s@%s", addr->mailbox, host);        /* __SPRINTF_CHECKED__ */
             p_delete(&addr->mailbox);
@@ -81,586 +83,492 @@ address_t *address_list_dup(address_t *addr)
     return res;
 }
 
-#define terminate_string(a, b, c) do { if ((b) < (c)) a[(b)] = 0; else \
-       a[(c)] = 0; } while (0)
 
-#define terminate_buffer(a, b) terminate_string(a, b, sizeof (a) - 1)
+static void rfc822_dequote_comment(char *s)
+{
+    char *w = s;
+
+    for (; *s; s++) {
+        if (*s == '\\') {
+            /* if *++s is NUL that's an error, but we don't care */
+            *w++ = *++s;
+        } else
+        if (*s != '\"') {
+            *w++ = *s;
+        }
+    }
+    *w = 0;
+}
 
 
-const char RFC822Specials[] = "@.,:;<>[]\\\"()";
+/****************************************************************************/
+/* Parsing functions                                                        */
+/****************************************************************************/
 
-#define is_special(x) strchr(RFC822Specials,x)
+struct rfc822_parse_ctx {
+    address_t *cur;
 
-int RFC822Error = 0;
+    char comment[STRING];
+    size_t commentlen;
 
-/* these must defined in the same order as the numerated errors given in rfc822.h */
-const char *RFC822Errors[] = {
-  "out of memory",
-  "mismatched parenthesis",
-  "mismatched quotes",
-  "bad route in <>",
-  "bad address in <>",
-  "bad address spec"
+    char phrase[STRING];
+    size_t phraselen;
 };
 
-void rfc822_dequote_comment (char *s)
-{
-  char *w = s;
+#define is_special(x) strchr(RFC822Specials,x)
+#define terminate_string(a, b, c)  (a[MIN(b, c)] = 0)
+#define terminate_buffer(a)        terminate_string(a, a##len, sizeof (a) - 1)
 
-  for (; *s; s++) {
-    if (*s == '\\') {
-      if (!*++s)
-        break;                  /* error? */
-      *w++ = *s;
-    }
-    else if (*s != '\"') {
-      if (w != s)
-        *w = *s;
-      w++;
-    }
-  }
-  *w = 0;
-}
 
-static const char *parse_comment (const char *s,
-                                  char *comment, size_t * commentlen,
-                                  size_t commentmax)
+static const char *
+parse_comment(const char *s, char *comment, size_t *commentlen,
+              size_t commentmax)
 {
-  int level = 1;
+    int level = 1;
+
+    for (; *s; s++) {
+        switch (*s) {
+          case '(':
+            level++;
+            break;
+
+          case ')':
+            level--;
+            if (!level)
+                return s;
+            break;
+
+          case '\\':
+            s++; /* if *++s is NUL it will be an error anyway */
+            break;
+
+          default:
+            break;
+        }
 
-  while (*s && level) {
-    if (*s == '(')
-      level++;
-    else if (*s == ')') {
-      if (--level == 0) {
-        s++;
-        break;
-      }
+        if (*commentlen < commentmax)
+            comment[(*commentlen)++] = *s;
     }
-    else if (*s == '\\') {
-      if (!*++s)
-        break;
-    }
-    if (*commentlen < commentmax)
-      comment[(*commentlen)++] = *s;
-    s++;
-  }
-  if (level) {
-    RFC822Error = ERR_MISMATCH_PAREN;
+
     return NULL;
-  }
-  return s;
 }
 
-static const char *parse_quote (const char *s, char *token, size_t * tokenlen,
-                                size_t tokenmax)
+static const char *
+parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
 {
-  if (*tokenlen < tokenmax)
-    token[(*tokenlen)++] = '"';
-  while (*s) {
     if (*tokenlen < tokenmax)
-      token[*tokenlen] = *s;
-    if (*s == '"') {
-      (*tokenlen)++;
-      return (s + 1);
-    }
-    if (*s == '\\') {
-      if (!*++s)
-        break;
+        token[(*tokenlen)++] = '"';
+
+    for (; *s; s++) {
+        if (*tokenlen < tokenmax)
+            token[*tokenlen] = *s;
+
+        if (*s == '"') {
+            (*tokenlen)++;
+            return s + 1;
+        }
+
+        if (*s == '\\') {
+            if (!*++s)
+                break;
 
-      if (*tokenlen < tokenmax)
-        token[*tokenlen] = *s;
+            if (*tokenlen < tokenmax)
+                token[*tokenlen] = *s;
+        }
+        (*tokenlen)++;
     }
-    (*tokenlen)++;
-    s++;
-  }
-  RFC822Error = ERR_MISMATCH_QUOTE;
-  return NULL;
-}
 
-static const char *next_token (const char *s, char *token, size_t * tokenlen,
-                               size_t tokenmax)
-{
-  if (*s == '(')
-    return (parse_comment (s + 1, token, tokenlen, tokenmax));
-  if (*s == '"')
-    return (parse_quote (s + 1, token, tokenlen, tokenmax));
-  if (is_special (*s)) {
-    if (*tokenlen < tokenmax)
-      token[(*tokenlen)++] = *s;
-    return (s + 1);
-  }
-  while (*s) {
-    if (ISSPACE ((unsigned char) *s) || is_special (*s))
-      break;
-    if (*tokenlen < tokenmax)
-      token[(*tokenlen)++] = *s;
-    s++;
-  }
-  return s;
+    return NULL;
 }
 
-static const char *parse_mailboxdomain (const char *s, const char *nonspecial,
-                                        char *mailbox, size_t * mailboxlen,
-                                        size_t mailboxmax, char *comment,
-                                        size_t * commentlen,
-                                        size_t commentmax)
+static const char *
+next_token(const char *s, char *token, size_t *tokenlen, size_t tokenmax)
 {
-  const char *ps;
+    if (*s == '(')
+        return parse_comment(s + 1, token, tokenlen, tokenmax);
 
-  while (*s) {
-    s = vskipspaces(s);
-    if (strchr (nonspecial, *s) == NULL && is_special (*s))
-      return s;
+    if (*s == '"')
+        return parse_quote(s + 1, token, tokenlen, tokenmax);
 
-    if (*s == '(') {
-      if (*commentlen && *commentlen < commentmax)
-        comment[(*commentlen)++] = ' ';
-      ps = next_token (s, comment, commentlen, commentmax);
+    if (is_special(*s)) {
+        if (*tokenlen < tokenmax)
+            token[(*tokenlen)++] = *s;
+        return s + 1;
     }
-    else
-      ps = next_token (s, mailbox, mailboxlen, mailboxmax);
-    if (!ps)
-      return NULL;
-    s = ps;
-  }
-
-  return s;
+
+    while (*s) {
+        if (ISSPACE(*s) || is_special(*s))
+            break;
+        if (*tokenlen < tokenmax)
+            token[(*tokenlen)++] = *s;
+        s++;
+    }
+    return s;
 }
 
-static const char *parse_address (const char *s,
-                                  char *token, size_t * tokenlen,
-                                  size_t tokenmax, char *comment,
-                                  size_t * commentlen, size_t commentmax,
-                                  address_t * addr)
+static const char *
+parse_mailboxdomain(const char *s, const char *nonspecial,
+                    char *mailbox, size_t *mailboxlen, size_t mailboxmax,
+                    struct rfc822_parse_ctx *ctx)
 {
-  s = parse_mailboxdomain (s, ".\"(\\",
-                           token, tokenlen, tokenmax,
-                           comment, commentlen, commentmax);
-  if (!s)
-    return NULL;
-
-  if (*s == '@') {
-    if (*tokenlen < tokenmax)
-      token[(*tokenlen)++] = '@';
-    s = parse_mailboxdomain (s + 1, ".([]\\",
-                             token, tokenlen, tokenmax,
-                             comment, commentlen, commentmax);
-    if (!s)
-      return NULL;
-  }
-
-  terminate_string (token, *tokenlen, tokenmax);
-  addr->mailbox = m_strdup(token);
+    while (*s) {
+        s = skipspaces(s);
+
+        if (!strchr(nonspecial, *s) && is_special(*s))
+            return s;
+
+        if (*s == '(') {
+            if (ctx->commentlen && ctx->commentlen < sizeof(ctx->comment) - 1)
+                ctx->comment[ctx->commentlen++] = ' ';
+            s = next_token(s, ctx->comment, &ctx->commentlen, sizeof(ctx->comment) - 1);
+        } else {
+            s = next_token(s, mailbox, mailboxlen, mailboxmax);
+        }
 
-  if (*commentlen && !addr->personal) {
-    terminate_string (comment, *commentlen, commentmax);
-    addr->personal = m_strdup(comment);
-  }
+        if (!s)
+            return NULL;
+    }
 
-  return s;
+    return s;
 }
 
-static const char *parse_route_addr (const char *s,
-                                     char *comment, size_t * commentlen,
-                                     size_t commentmax, address_t * addr)
+static const char *
+parse_address(const char *s, struct rfc822_parse_ctx *ctx)
 {
-  char token[STRING];
-  size_t tokenlen = 0;
-
-  s = vskipspaces(s);
-
-  /* find the end of the route */
-  if (*s == '@') {
-    while (s && *s == '@') {
-      if (tokenlen < sizeof (token) - 1)
-        token[tokenlen++] = '@';
-      s = parse_mailboxdomain (s + 1, ",.\\[](", token,
-                               &tokenlen, sizeof (token) - 1,
-                               comment, commentlen, commentmax);
-    }
-    if (!s || *s != ':') {
-      RFC822Error = ERR_BAD_ROUTE;
-      return NULL;              /* invalid route */
-    }
+    char token[STRING];
+    size_t tokenlen = 0;
 
-    if (tokenlen < sizeof (token) - 1)
-      token[tokenlen++] = ':';
-    s++;
-  }
+    s = parse_mailboxdomain(s, ".\"(\\",
+                            token, &tokenlen, sizeof(token) - 1, ctx);
+    if (!s)
+        return NULL;
 
-  if ((s =
-       parse_address (s, token, &tokenlen, sizeof (token) - 1, comment,
-                      commentlen, commentmax, addr)) == NULL)
-    return NULL;
+    if (*s == '@') {
+        if (tokenlen < sizeof(token) - 1)
+            token[tokenlen++] = '@';
+        s = parse_mailboxdomain(s + 1, ".([]\\",
+                                token, &tokenlen, sizeof(token) - 1, ctx);
+        if (!s)
+            return NULL;
+    }
 
-  if (*s != '>') {
-    RFC822Error = ERR_BAD_ROUTE_ADDR;
-    return NULL;
-  }
+    terminate_buffer(token);
+    ctx->cur->mailbox = m_strdup(token);
 
-  if (!addr->mailbox)
-    addr->mailbox = m_strdup("@");
+    if (ctx->commentlen && !ctx->cur->personal) {
+        terminate_buffer(ctx->comment);
+        ctx->cur->personal = m_strdup(ctx->comment);
+    }
 
-  s++;
-  return s;
+    return s;
 }
 
-static const char *parse_addr_spec (const char *s,
-                                    char *comment, size_t * commentlen,
-                                    size_t commentmax, address_t * addr)
+address_t **add_addrspec(address_t **last, struct rfc822_parse_ctx *ctx)
 {
-  char token[STRING];
-  size_t tokenlen = 0;
-
-  s =
-    parse_address (s, token, &tokenlen, sizeof (token) - 1, comment,
-                   commentlen, commentmax, addr);
-  if (s && *s && *s != ',' && *s != ';') {
-    RFC822Error = ERR_BAD_ADDR_SPEC;
-    return NULL;
-  }
-  return s;
-}
+    const char *s;
 
-static void
-add_addrspec (address_t ** top, address_t ** last, const char *phrase,
-              char *comment, size_t * commentlen, size_t commentmax)
-{
-  address_t *cur = address_new ();
-
-  if (parse_addr_spec (phrase, comment, commentlen, commentmax, cur) == NULL) {
-    address_delete (&cur);
-    return;
-  }
-
-  if (*last)
-    (*last)->next = cur;
-  else
-    *top = cur;
-  *last = cur;
+    ctx->cur = address_new();
+    s = parse_address(ctx->phrase, ctx);
+    if (s && *s && *s != ',' && *s != ';') {
+        address_delete(&ctx->cur);
+        return last;
+    }
+
+    fprintf(stderr, "ADD [%s]\n", ctx->cur->mailbox);
+    *last = ctx->cur;
+    return &(*last)->next;
 }
 
-address_t *rfc822_parse_adrlist (address_t * top, const char *s)
+address_t *rfc822_parse_adrlist(address_t *top, const char *s)
 {
-  int ws_pending;
-  const char *begin, *ps;
-  char comment[STRING], phrase[STRING];
-  size_t phraselen = 0, commentlen = 0;
-  address_t *cur, *last = NULL;
-
-  RFC822Error = 0;
-
-  last = top;
-  while (last && last->next)
-    last = last->next;
-
-  ws_pending = isspace ((unsigned char) *s);
-
-  begin = s = vskipspaces(s);
-  while (*s) {
-    if (*s == ',') {
-      if (phraselen) {
-        terminate_buffer (phrase, phraselen);
-        add_addrspec (&top, &last, phrase, comment, &commentlen,
-                      sizeof (comment) - 1);
-      }
-      else if (commentlen && last && !last->personal) {
-        terminate_buffer (comment, commentlen);
-        last->personal = m_strdup(comment);
-      }
-
-      commentlen = 0;
-      phraselen = 0;
-      s++;
-      begin = vskipspaces(s);
-    }
-    else if (*s == '(') {
-      if (commentlen && commentlen < sizeof (comment) - 1)
-        comment[commentlen++] = ' ';
-      if ((ps =
-           next_token (s, comment, &commentlen,
-                       sizeof (comment) - 1)) == NULL) {
-        address_delete (&top);
-        return NULL;
-      }
-      s = ps;
-    }
-    else if (*s == ':') {
-      cur = address_new ();
-      terminate_buffer (phrase, phraselen);
-      cur->mailbox = m_strdup(phrase);
-      cur->group = 1;
-
-      if (last)
-        last->next = cur;
-      else
-        top = cur;
-      last = cur;
-
-      phraselen = 0;
-      commentlen = 0;
-      s++;
-      begin = vskipspaces(s);
-    }
-    else if (*s == ';') {
-      if (phraselen) {
-        terminate_buffer (phrase, phraselen);
-        add_addrspec (&top, &last, phrase, comment, &commentlen,
-                      sizeof (comment) - 1);
-      }
-      else if (commentlen && last && !last->personal) {
-        terminate_buffer (comment, commentlen);
-        last->personal = m_strdup(comment);
-      }
-
-      /* add group terminator */
-      cur = address_new ();
-      if (last) {
-        last->next = cur;
-        last = cur;
-      }
-
-      phraselen = 0;
-      commentlen = 0;
-      s++;
-      begin = vskipspaces(s);
-    }
-    else if (*s == '<') {
-      terminate_buffer (phrase, phraselen);
-      cur = address_new ();
-      if (phraselen) {
-        if (cur->personal)
-          p_delete(&cur->personal);
-        /* if we get something like "Michael R. Elkins" remove the quotes */
-        rfc822_dequote_comment (phrase);
-        cur->personal = m_strdup(phrase);
-      }
-      if ((ps =
-           parse_route_addr (s + 1, comment, &commentlen,
-                             sizeof (comment) - 1, cur)) == NULL) {
-        address_delete (&top);
-        address_delete (&cur);
-        return NULL;
-      }
-
-      if (last)
-        last->next = cur;
-      else
-        top = cur;
-      last = cur;
+    struct rfc822_parse_ctx ctx = { NULL, "", 0, "", 0 };
+    int ws_pending = 0;
+    address_t **last;
+
+    last = address_list_last(&top);
+
+    for (;;) {
+        ws_pending = ISSPACE(*s);
+        s = skipspaces(s);
+
+        switch (*s) {
+          case '\0':
+            if (ctx.phraselen) {
+                terminate_buffer(ctx.phrase);
+                terminate_buffer(ctx.comment);
+                last = add_addrspec(last, &ctx);
+            } else
+            if (ctx.commentlen && ctx.cur && !ctx.cur->personal) {
+                terminate_buffer(ctx.comment);
+                ctx.cur->personal = m_strdup(ctx.comment);
+            }
+            return top;
+
+          default:
+            if (ctx.phraselen && ctx.phraselen < sizeof(ctx.phrase) - 1 && ws_pending)
+                ctx.phrase[ctx.phraselen++] = ' ';
+            s = next_token(s, ctx.phrase, &ctx.phraselen, sizeof(ctx.phrase) - 1);
+            if (!s) {
+                address_delete(&top);
+                return NULL;
+            }
+            continue;
+
+          case '(':
+            if (ctx.commentlen && ctx.commentlen < sizeof(ctx.comment) - 1)
+                ctx.comment[ctx.commentlen++] = ' ';
+            s = next_token(s, ctx.comment, &ctx.commentlen, sizeof(ctx.comment) - 1);
+            if (!s) {
+                address_delete (&top);
+                return NULL;
+            }
+            continue;
+
+          case ',':
+            if (ctx.phraselen) {
+                terminate_buffer(ctx.phrase);
+                last = add_addrspec(last, &ctx);
+            } else
+            if (ctx.commentlen && ctx.cur && !ctx.cur->personal) {
+                terminate_buffer(ctx.comment);
+                ctx.cur->personal = m_strdup(ctx.comment);
+            }
+            break;
+
+          case ':':
+            terminate_buffer(ctx.phrase);
+            *last = address_new();
+            (*last)->mailbox = m_strdup(ctx.phrase);
+            (*last)->group = 1;
+            last = &(*last)->next;
+            break;
+
+          case ';':
+            if (ctx.phraselen) {
+                terminate_buffer(ctx.phrase);
+                last = add_addrspec(last, &ctx);
+            } else
+            if (ctx.commentlen && ctx.cur && !ctx.cur->personal) {
+                terminate_buffer(ctx.comment);
+                ctx.cur->personal = m_strdup(ctx.comment);
+            }
+
+            /* add group terminator */
+            *last = address_new();
+            return top;
+
+          case '<':
+            terminate_buffer(ctx.phrase);
+            ctx.cur = address_new ();
+            if (ctx.phraselen) {
+                /* if we get something like "Michael R. Elkins" remove the quotes */
+                rfc822_dequote_comment(ctx.phrase);
+                ctx.cur->personal = m_strdup(ctx.phrase);
+            }
+
+            s = parse_address(skipspaces(s + 1), &ctx);
+            if (!s || *s != '>' || !ctx.cur->mailbox) {
+                address_delete(&top);
+                address_delete(&ctx.cur);
+                return NULL;
+            }
+
+            *last = ctx.cur;
+            break;
+        }
 
-      phraselen = 0;
-      commentlen = 0;
-      s = ps;
-    }
-    else {
-      if (phraselen && phraselen < sizeof (phrase) - 1 && ws_pending)
-        phrase[phraselen++] = ' ';
-      if ((ps =
-           next_token (s, phrase, &phraselen, sizeof (phrase) - 1)) == NULL) {
-        address_delete (&top);
-        return NULL;
-      }
-      s = ps;
+        ctx.commentlen = 0;
+        ctx.phraselen = 0;
+        s++;
     }
-    ws_pending = isspace ((unsigned char) *s);
-    s = vskipspaces(s);
-  }
-
-  if (phraselen) {
-    terminate_buffer (phrase, phraselen);
-    terminate_buffer (comment, commentlen);
-    add_addrspec (&top, &last, phrase, comment, &commentlen,
-                  sizeof (comment) - 1);
-  }
-  else if (commentlen && last && !last->personal) {
-    terminate_buffer (comment, commentlen);
-    last->personal = m_strdup(comment);
-  }
-
-  return top;
+
+    return NULL;
 }
 
+
+/****************************************************************************/
+/* Output functions                                                         */
+/****************************************************************************/
+
 void
-rfc822_cat (char *buf, size_t buflen, const char *value, const char *specials)
+rfc822_cat(char *buf, size_t buflen, const char *value, const char *specials)
 {
-  if (strpbrk (value, specials)) {
-    char tmp[256], *pc = tmp;
-    size_t tmplen = sizeof (tmp) - 3;
-
-    *pc++ = '"';
-    for (; *value && tmplen > 1; value++) {
-      if (*value == '\\' || *value == '"') {
-        *pc++ = '\\';
-        tmplen--;
-      }
-      *pc++ = *value;
-      tmplen--;
+    if (strpbrk(value, specials)) {
+        char tmp[256], *pc = tmp;
+        size_t tmplen = sizeof (tmp) - 3;
+
+        *pc++ = '"';
+        for (; *value && tmplen > 1; value++) {
+            if (*value == '\\' || *value == '"') {
+                *pc++ = '\\';
+                tmplen--;
+            }
+            *pc++ = *value;
+            tmplen--;
+        }
+        *pc++ = '"';
+        *pc = 0;
+        m_strcpy(buf, buflen, tmp);
+    } else {
+        m_strcpy(buf, buflen, value);
     }
-    *pc++ = '"';
-    *pc = 0;
-    m_strcpy(buf, buflen, tmp);
-  }
-  else
-    m_strcpy(buf, buflen, value);
 }
 
-void rfc822_write_address_single (char *buf, size_t buflen, address_t * addr,
-                                  int display)
+void rfc822_write_address_single(char *buf, size_t buflen, address_t * addr,
+                                 int display)
 {
-  size_t len;
-  char *pbuf = buf;
-  char *pc;
-
-  if (!addr)
-    return;
-
-  buflen--;                     /* save room for the terminal nul */
-
-  if (addr->personal) {
-    if (strpbrk (addr->personal, RFC822Specials)) {
-      if (!buflen)
-        goto done;
-      *pbuf++ = '"';
-      buflen--;
-      for (pc = addr->personal; *pc && buflen > 0; pc++) {
-        if (*pc == '"' || *pc == '\\') {
-          if (!buflen)
-            goto done;
-          *pbuf++ = '\\';
-          buflen--;
+    size_t len;
+    char *pbuf = buf;
+    char *pc;
+
+    if (!addr)
+        return;
+
+    buflen--;                     /* save room for the terminal nul */
+
+    if (addr->personal) {
+        if (strpbrk (addr->personal, RFC822Specials)) {
+            if (!buflen)
+                goto done;
+            *pbuf++ = '"';
+            buflen--;
+            for (pc = addr->personal; *pc && buflen > 0; pc++) {
+                if (*pc == '"' || *pc == '\\') {
+                    if (!buflen)
+                        goto done;
+                    *pbuf++ = '\\';
+                    buflen--;
+                }
+                if (!buflen)
+                    goto done;
+                *pbuf++ = *pc;
+                buflen--;
+            }
+            if (!buflen)
+                goto done;
+            *pbuf++ = '"';
+            buflen--;
         }
+        else {
+            if (!buflen)
+                goto done;
+            m_strcpy(pbuf, buflen, addr->personal);
+            len = m_strlen(pbuf);
+            pbuf += len;
+            buflen -= len;
+        }
+
         if (!buflen)
-          goto done;
-        *pbuf++ = *pc;
+            goto done;
+        *pbuf++ = ' ';
         buflen--;
-      }
-      if (!buflen)
-        goto done;
-      *pbuf++ = '"';
-      buflen--;
-    }
-    else {
-      if (!buflen)
-        goto done;
-      m_strcpy(pbuf, buflen, addr->personal);
-      len = m_strlen(pbuf);
-      pbuf += len;
-      buflen -= len;
     }
 
-    if (!buflen)
-      goto done;
-    *pbuf++ = ' ';
-    buflen--;
-  }
-
-  if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) {
-    if (!buflen)
-      goto done;
-    *pbuf++ = '<';
-    buflen--;
-  }
-
-  if (addr->mailbox) {
-    if (!buflen)
-      goto done;
-    if (ascii_strcmp (addr->mailbox, "@") && !display) {
-      m_strcpy(pbuf, buflen, addr->mailbox);
-      len = m_strlen(pbuf);
-    }
-    else if (ascii_strcmp (addr->mailbox, "@") && display) {
-      m_strcpy(pbuf, buflen, mutt_addr_for_display(addr));
-      len = m_strlen(pbuf);
-    }
-    else {
-      *pbuf = '\0';
-      len = 0;
-    }
-    pbuf += len;
-    buflen -= len;
-
     if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) {
-      if (!buflen)
-        goto done;
-      *pbuf++ = '>';
-      buflen--;
+        if (!buflen)
+            goto done;
+        *pbuf++ = '<';
+        buflen--;
     }
 
-    if (addr->group) {
-      if (!buflen)
-        goto done;
-      *pbuf++ = ':';
-      buflen--;
-      if (!buflen)
-        goto done;
-      *pbuf++ = ' ';
-      buflen--;
+    if (addr->mailbox) {
+        if (!buflen)
+            goto done;
+        if (ascii_strcmp (addr->mailbox, "@") && !display) {
+            m_strcpy(pbuf, buflen, addr->mailbox);
+            len = m_strlen(pbuf);
+        }
+        else if (ascii_strcmp (addr->mailbox, "@") && display) {
+            m_strcpy(pbuf, buflen, mutt_addr_for_display(addr));
+            len = m_strlen(pbuf);
+        }
+        else {
+            *pbuf = '\0';
+            len = 0;
+        }
+        pbuf += len;
+        buflen -= len;
+
+        if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) {
+            if (!buflen)
+                goto done;
+            *pbuf++ = '>';
+            buflen--;
+        }
+
+        if (addr->group) {
+            if (!buflen)
+                goto done;
+            *pbuf++ = ':';
+            buflen--;
+            if (!buflen)
+                goto done;
+            *pbuf++ = ' ';
+            buflen--;
+        }
+    }
+    else {
+        if (!buflen)
+            goto done;
+        *pbuf++ = ';';
+        buflen--;
     }
-  }
-  else {
-    if (!buflen)
-      goto done;
-    *pbuf++ = ';';
-    buflen--;
-  }
 done:
-  /* no need to check for length here since we already save space at the
-     beginning of this routine */
-  *pbuf = 0;
+    /* no need to check for length here since we already save space at the
+       beginning of this routine */
+    *pbuf = 0;
 }
 
 /* note: it is assumed that `buf' is nul terminated! */
 void rfc822_write_address (char *buf, size_t buflen, address_t * addr,
                            int display)
 {
-  char *pbuf = buf;
-  size_t len = m_strlen(buf);
-
-  buflen--;                     /* save room for the terminal nul */
-
-  if (len > 0) {
-    if (len > buflen)
-      return;                   /* safety check for bogus arguments */
-
-    pbuf += len;
-    buflen -= len;
-    if (!buflen)
-      goto done;
-    *pbuf++ = ',';
-    buflen--;
-    if (!buflen)
-      goto done;
-    *pbuf++ = ' ';
-    buflen--;
-  }
-
-  for (; addr && buflen > 0; addr = addr->next) {
-    /* use buflen+1 here because we already saved space for the trailing
-       nul char, and the subroutine can make use of it */
-    rfc822_write_address_single (pbuf, buflen + 1, addr, display);
-
-    /* this should be safe since we always have at least 1 char passed into
-       the above call, which means `pbuf' should always be nul terminated */
-    len = m_strlen(pbuf);
-    pbuf += len;
-    buflen -= len;
-
-    /* if there is another address, and its not a group mailbox name or
-       group terminator, add a comma to separate the addresses */
-    if (addr->next && addr->next->mailbox && !addr->group) {
-      if (!buflen)
-        goto done;
-      *pbuf++ = ',';
-      buflen--;
-      if (!buflen)
-        goto done;
-      *pbuf++ = ' ';
-      buflen--;
+    char *pbuf = buf;
+    size_t len = m_strlen(buf);
+
+    buflen--;                     /* save room for the terminal nul */
+
+    if (len > 0) {
+        if (len > buflen)
+            return;                   /* safety check for bogus arguments */
+
+        pbuf += len;
+        buflen -= len;
+        if (!buflen)
+            goto done;
+        *pbuf++ = ',';
+        buflen--;
+        if (!buflen)
+            goto done;
+        *pbuf++ = ' ';
+        buflen--;
+    }
+
+    for (; addr && buflen > 0; addr = addr->next) {
+        /* use buflen+1 here because we already saved space for the trailing
+           nul char, and the subroutine can make use of it */
+        rfc822_write_address_single (pbuf, buflen + 1, addr, display);
+
+        /* this should be safe since we always have at least 1 char passed into
+           the above call, which means `pbuf' should always be nul terminated */
+        len = m_strlen(pbuf);
+        pbuf += len;
+        buflen -= len;
+
+        /* if there is another address, and its not a group mailbox name or
+           group terminator, add a comma to separate the addresses */
+        if (addr->next && addr->next->mailbox && !addr->group) {
+            if (!buflen)
+                goto done;
+            *pbuf++ = ',';
+            buflen--;
+            if (!buflen)
+                goto done;
+            *pbuf++ = ' ';
+            buflen--;
+        }
     }
-  }
 done:
-  *pbuf = 0;
+    *pbuf = 0;
 }