From ea267f0ef94406be54d11511b3492f71717481d2 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 3 Nov 2006 03:26:43 +0100 Subject: [PATCH] simplify rfc822 parsing *A LOT* Signed-off-by: Pierre Habouzit --- lib-mime/mime.h | 14 +- lib-mime/rfc822.c | 922 +++++++++++++++++++++------------------------- 2 files changed, 417 insertions(+), 519 deletions(-) diff --git a/lib-mime/mime.h b/lib-mime/mime.h index 269b0d0..90f8c68 100644 --- a/lib-mime/mime.h +++ b/lib-mime/mime.h @@ -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] diff --git a/lib-mime/rfc822.c b/lib-mime/rfc822.c index e73b408..708955b 100644 --- a/lib-mime/rfc822.c +++ b/lib-mime/rfc822.c @@ -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; } -- 2.20.1