X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=lib-mime%2Frfc822.c;h=22e54a46c15b2ba80cab16ac050162c991d9db48;hp=708955bf8369865948aff0287e4170acef35e62b;hb=7a368b3670a90656b2e0e724ed3efd79221f3d31;hpb=ea267f0ef94406be54d11511b3492f71717481d2 diff --git a/lib-mime/rfc822.c b/lib-mime/rfc822.c index 708955b..22e54a4 100644 --- a/lib-mime/rfc822.c +++ b/lib-mime/rfc822.c @@ -84,45 +84,51 @@ address_t *address_list_dup(address_t *addr) } -static void rfc822_dequote_comment(char *s) -{ - char *w = s; +/****************************************************************************/ +/* Parsing functions */ +/****************************************************************************/ - 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; - } +typedef struct static_buf { + char buf[STRING]; + int len; +} static_buf; + +static inline void stbuf_append(static_buf *buf, int c) { + if (buf->len < ssizeof(buf->buf) - 1) { + buf->buf[buf->len++] = c; + buf->buf[buf->len] = '\0'; } - *w = 0; } +static inline void stbuf_append_sp(static_buf *buf) { + if (buf->len) + stbuf_append(buf, ' '); +} -/****************************************************************************/ -/* Parsing functions */ -/****************************************************************************/ - -struct rfc822_parse_ctx { - address_t *cur; +static char *rfc822_dequote_comment(static_buf *buf) +{ + char *res = p_new(char, buf->len + 1); + char *q = res; + char *p = buf->buf; + int i; - char comment[STRING]; - size_t commentlen; + for (i = 0; i < buf->len; i++) { + if (p[i] == '\"') + continue; - char phrase[STRING]; - size_t phraselen; -}; + if (p[i] == '\\') { + if (++i >= buf->len) /* should not happen */ + break; + } -#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) + *q++ = p[i]; + } + *q++ = '\0'; + return res; +} -static const char * -parse_comment(const char *s, char *comment, size_t *commentlen, - size_t commentmax) +static const char *parse_comment(const char *s, static_buf *buf) { int level = 1; @@ -146,70 +152,60 @@ parse_comment(const char *s, char *comment, size_t *commentlen, break; } - if (*commentlen < commentmax) - comment[(*commentlen)++] = *s; + stbuf_append(buf, *s); } return NULL; } -static const char * -parse_quote(const char *s, char *token, size_t *tokenlen, size_t tokenmax) +static const char *parse_quote(const char *s, static_buf *buf) { - if (*tokenlen < tokenmax) - token[(*tokenlen)++] = '"'; - for (; *s; s++) { - if (*tokenlen < tokenmax) - token[*tokenlen] = *s; - - if (*s == '"') { - (*tokenlen)++; + switch (*s) { + case '"': + stbuf_append(buf, *s); return s + 1; - } - if (*s == '\\') { + case '\\': if (!*++s) - break; + return NULL; + /* fallthrough */ - if (*tokenlen < tokenmax) - token[*tokenlen] = *s; + default: + stbuf_append(buf, *s); + break; } - (*tokenlen)++; } 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); +#define is_special(x) strchr(RFC822Specials,x) - if (*s == '"') - return parse_quote(s + 1, token, tokenlen, tokenmax); +static const char *next_phrase(const char *s, static_buf *buf) +{ + if (*s == '"') { + stbuf_append(buf, '"'); + return parse_quote(s + 1, buf); + } if (is_special(*s)) { - if (*tokenlen < tokenmax) - token[(*tokenlen)++] = *s; + stbuf_append(buf, *s); return s + 1; } while (*s) { if (ISSPACE(*s) || is_special(*s)) break; - if (*tokenlen < tokenmax) - token[(*tokenlen)++] = *s; - s++; + stbuf_append(buf, *s++); } + return s; } static const char * -parse_mailboxdomain(const char *s, const char *nonspecial, - char *mailbox, size_t *mailboxlen, size_t mailboxmax, - struct rfc822_parse_ctx *ctx) +parse_mailboxdomain(const char *s, const char *nonspecial, static_buf *mbox, + static_buf *comment) { while (*s) { s = skipspaces(s); @@ -218,11 +214,10 @@ parse_mailboxdomain(const char *s, const char *nonspecial, 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); + stbuf_append_sp(comment); + s = parse_comment(s + 1, comment); } else { - s = next_token(s, mailbox, mailboxlen, mailboxmax); + s = next_phrase(s, mbox); } if (!s) @@ -233,81 +228,68 @@ parse_mailboxdomain(const char *s, const char *nonspecial, } static const char * -parse_address(const char *s, struct rfc822_parse_ctx *ctx) +parse_address(const char *s, static_buf *comment, address_t *cur) { - char token[STRING]; - size_t tokenlen = 0; + static_buf token = {"", 0}; - s = parse_mailboxdomain(s, ".\"(\\", - token, &tokenlen, sizeof(token) - 1, ctx); + s = parse_mailboxdomain(s, ".\"(\\", &token, comment); if (!s) return NULL; if (*s == '@') { - if (tokenlen < sizeof(token) - 1) - token[tokenlen++] = '@'; - s = parse_mailboxdomain(s + 1, ".([]\\", - token, &tokenlen, sizeof(token) - 1, ctx); + stbuf_append(&token, '@'); + s = parse_mailboxdomain(s + 1, ".([]\\", &token, comment); if (!s) return NULL; } - terminate_buffer(token); - ctx->cur->mailbox = m_strdup(token); + cur->mailbox = p_dupstr(token.buf, token.len); - if (ctx->commentlen && !ctx->cur->personal) { - terminate_buffer(ctx->comment); - ctx->cur->personal = m_strdup(ctx->comment); + if (comment->len && !cur->personal) { + cur->personal = p_dupstr(comment->buf, comment->len); } return s; } -address_t **add_addrspec(address_t **last, struct rfc822_parse_ctx *ctx) +address_t **rfc822_eotoken(address_t **last, static_buf *phrase, static_buf *comment) { - const char *s; + if (phrase->len) { + const char *s; + address_t *cur = address_new(); + + s = parse_address(phrase->buf, comment, cur); + if (s && *s && *s != ',' && *s != ';') { + address_delete(&cur); + return last; + } - ctx->cur = address_new(); - s = parse_address(ctx->phrase, ctx); - if (s && *s && *s != ',' && *s != ';') { - address_delete(&ctx->cur); - return last; + *last = cur; + return &(*last)->next; } - fprintf(stderr, "ADD [%s]\n", ctx->cur->mailbox); - *last = ctx->cur; - return &(*last)->next; + return last; } address_t *rfc822_parse_adrlist(address_t *top, const char *s) { - struct rfc822_parse_ctx ctx = { NULL, "", 0, "", 0 }; - int ws_pending = 0; - address_t **last; + static_buf comment = {"", 0}; + static_buf phrase = {"", 0}; - last = address_list_last(&top); + address_t **last = address_list_last(&top); + int ws_pending = 0; 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; + address_t *cur; 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 (ws_pending) + stbuf_append_sp(&phrase); + s = next_phrase(s, &phrase); if (!s) { address_delete(&top); return NULL; @@ -315,70 +297,57 @@ address_t *rfc822_parse_adrlist(address_t *top, const char *s) 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); + stbuf_append_sp(&comment); + s = parse_comment(s + 1, &comment); if (!s) { - address_delete (&top); + 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); + + case '<': + cur = address_new(); + if (phrase.len) { + /* if we get something like "Michael R. Elkins" remove the quotes */ + cur->personal = rfc822_dequote_comment(&phrase); } + + s = parse_address(skipspaces(s + 1), &comment, cur); + if (!s || *s != '>' || !cur->mailbox) { + address_delete(&top); + address_delete(&cur); + return NULL; + } + + *last = cur; + last = &(*last)->next; + break; + + case ',': + last = rfc822_eotoken(last, &phrase, &comment); break; - case ':': - terminate_buffer(ctx.phrase); + case ':': /* group start */ *last = address_new(); - (*last)->mailbox = m_strdup(ctx.phrase); + (*last)->mailbox = p_dupstr(phrase.buf, phrase.len); (*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); - } - + last = rfc822_eotoken(last, &phrase, &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; + last = &(*last)->next; break; + + case '\0': + last = rfc822_eotoken(last, &phrase, &comment); + return top; } - ctx.commentlen = 0; - ctx.phraselen = 0; + comment.len = phrase.len = 0; s++; } @@ -390,185 +359,119 @@ address_t *rfc822_parse_adrlist(address_t *top, const char *s) /* Output functions */ /****************************************************************************/ -void -rfc822_cat(char *buf, size_t buflen, const char *value, const char *specials) +ssize_t +rfc822_strcpy(char *buf, ssize_t buflen, const char *p, 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--; + if (strpbrk(p, specials)) { + ssize_t pos = 0; + + buf[pos++] = '"'; + + while (*p && pos < buflen - 2) { + if (*p == '\\' || *p == '"') { + if (pos >= buflen - 4) + break; + buf[pos++] = '\\'; } - *pc++ = *value; - tmplen--; + + buf[pos++] = *p++; } - *pc++ = '"'; - *pc = 0; - m_strcpy(buf, buflen, tmp); + + buf[pos++] = '"'; + buf[pos] = '\0'; + return pos; } else { - m_strcpy(buf, buflen, value); + return m_strcpy(buf, buflen, p); } } -void rfc822_write_address_single(char *buf, size_t buflen, address_t * addr, - int display) +ssize_t rfc822_write_address_single(char *buf, ssize_t buflen, + address_t *addr, int display) { - size_t len; - char *pbuf = buf; - char *pc; + ssize_t pos = 0; if (!addr) - return; + return 0; 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) + pos = rfc822_strcpy(buf, buflen, addr->personal, RFC822Specials); + if (pos + 2 >= buflen) goto done; - *pbuf++ = ' '; - buflen--; - } - if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) { - if (!buflen) - goto done; - *pbuf++ = '<'; - buflen--; + buf[pos++] = ' '; + buf[pos++] = '<'; } 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; + if (!display) { + pos += m_strcpy(buf + pos, buflen - pos, addr->mailbox); + } else { + pos += m_strcpy(buf + pos, buflen - pos, mutt_addr_for_display(addr)); } - pbuf += len; - buflen -= len; - if (addr->personal || (addr->mailbox && *addr->mailbox == '@')) { - if (!buflen) + if (addr->personal) { + if (pos + 1 >= buflen) goto done; - *pbuf++ = '>'; - buflen--; + buf[pos++] = '>'; } if (addr->group) { - if (!buflen) + if (pos + 1 >= buflen) goto done; - *pbuf++ = ':'; - buflen--; - if (!buflen) - goto done; - *pbuf++ = ' '; - buflen--; + buf[pos++] = ':'; } - } - else { - if (!buflen) + } else { + if (pos + 1 >= buflen) goto done; - *pbuf++ = ';'; - buflen--; + buf[pos++] = ';'; } -done: + + done: /* no need to check for length here since we already save space at the beginning of this routine */ - *pbuf = 0; + buf[pos] = 0; + return pos; } /* note: it is assumed that `buf' is nul terminated! */ -void rfc822_write_address (char *buf, size_t buflen, address_t * addr, - int display) +ssize_t +rfc822_write_address(char *buf, ssize_t buflen, address_t *addr, int display) { - char *pbuf = buf; - size_t len = m_strlen(buf); + ssize_t pos; buflen--; /* save room for the terminal nul */ + pos = m_strnlen(buf, buflen); - if (len > 0) { - if (len > buflen) - return; /* safety check for bogus arguments */ - - pbuf += len; - buflen -= len; - if (!buflen) - goto done; - *pbuf++ = ','; - buflen--; - if (!buflen) + if (pos) { + if (pos + 2 >= 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; + buf[pos++] = ','; + buf[pos++] = ' '; + } + while (addr) { + pos += rfc822_write_address_single(buf + pos, buflen + 1 - pos, + addr, display); /* 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) + if (!addr->group && addr->next && addr->next->mailbox) { + if (pos + 2 >= buflen) goto done; - *pbuf++ = ','; - buflen--; if (!buflen) goto done; - *pbuf++ = ' '; - buflen--; + + buf[pos++] = ','; + buf[pos++] = ' '; } + + addr = addr->next; } -done: - *pbuf = 0; + + done: + buf[pos] = '\0'; + return pos; }