diff options
Diffstat (limited to 'mailinfo.c')
-rw-r--r-- | mailinfo.c | 79 |
1 files changed, 48 insertions, 31 deletions
diff --git a/mailinfo.c b/mailinfo.c index b395adbdf2..5681d9130d 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -19,8 +19,7 @@ static void cleanup_space(struct strbuf *sb) static void get_sane_name(struct strbuf *out, struct strbuf *name, struct strbuf *email) { struct strbuf *src = name; - if (name->len < 3 || 60 < name->len || strchr(name->buf, '@') || - strchr(name->buf, '<') || strchr(name->buf, '>')) + if (name->len < 3 || 60 < name->len || strpbrk(name->buf, "@<>")) src = email; else if (name == out) return; @@ -254,7 +253,7 @@ static void handle_content_type(struct mailinfo *mi, struct strbuf *line) mi->delsp = has_attr_value(line->buf, "delsp=", "yes"); if (slurp_attr(line->buf, "boundary=", boundary)) { - strbuf_insert(boundary, 0, "--", 2); + strbuf_insertstr(boundary, 0, "--"); if (++mi->content_top >= &mi->content[MAX_BOUNDARIES]) { error("Too many boundaries to handle"); mi->input_error = -1; @@ -346,11 +345,17 @@ static const char *header[MAX_HDR_PARSED] = { "From","Subject","Date", }; -static inline int cmp_header(const struct strbuf *line, const char *hdr) +static inline int skip_header(const struct strbuf *line, const char *hdr, + const char **outval) { - int len = strlen(hdr); - return !strncasecmp(line->buf, hdr, len) && line->len > len && - line->buf[len] == ':' && isspace(line->buf[len + 1]); + const char *val; + if (!skip_iprefix(line->buf, hdr, &val) || + *val++ != ':') + return 0; + while (isspace(*val)) + val++; + *outval = val; + return 1; } static int is_format_patch_separator(const char *line, int len) @@ -442,19 +447,21 @@ static int convert_to_utf8(struct mailinfo *mi, struct strbuf *line, const char *charset) { char *out; + size_t out_len; if (!mi->metainfo_charset || !charset || !*charset) return 0; if (same_encoding(mi->metainfo_charset, charset)) return 0; - out = reencode_string(line->buf, mi->metainfo_charset, charset); + out = reencode_string_len(line->buf, line->len, + mi->metainfo_charset, charset, &out_len); if (!out) { mi->input_error = -1; return error("cannot convert from %s to %s", charset, mi->metainfo_charset); } - strbuf_attach(line, out, strlen(out), strlen(out)); + strbuf_attach(line, out, out_len, out_len); return 0; } @@ -543,22 +550,36 @@ release_return: mi->input_error = -1; } +/* + * Returns true if "line" contains a header matching "hdr", in which case "val" + * will contain the value of the header with any RFC2047 B and Q encoding + * unwrapped, and optionally normalize the meta information to utf8. + */ +static int parse_header(const struct strbuf *line, + const char *hdr, + struct mailinfo *mi, + struct strbuf *val) +{ + const char *val_str; + + if (!skip_header(line, hdr, &val_str)) + return 0; + strbuf_addstr(val, val_str); + decode_header(mi, val); + return 1; +} + static int check_header(struct mailinfo *mi, const struct strbuf *line, struct strbuf *hdr_data[], int overwrite) { - int i, ret = 0, len; + int i, ret = 0; struct strbuf sb = STRBUF_INIT; /* search for the interesting parts */ for (i = 0; header[i]; i++) { - int len = strlen(header[i]); - if ((!hdr_data[i] || overwrite) && cmp_header(line, header[i])) { - /* Unwrap inline B and Q encoding, and optionally - * normalize the meta information to utf8. - */ - strbuf_add(&sb, line->buf + len + 2, line->len - len - 2); - decode_header(mi, &sb); + if ((!hdr_data[i] || overwrite) && + parse_header(line, header[i], mi, &sb)) { handle_header(&hdr_data[i], &sb); ret = 1; goto check_header_out; @@ -566,27 +587,17 @@ static int check_header(struct mailinfo *mi, } /* Content stuff */ - if (cmp_header(line, "Content-Type")) { - len = strlen("Content-Type: "); - strbuf_add(&sb, line->buf + len, line->len - len); - decode_header(mi, &sb); - strbuf_insert(&sb, 0, "Content-Type: ", len); + if (parse_header(line, "Content-Type", mi, &sb)) { handle_content_type(mi, &sb); ret = 1; goto check_header_out; } - if (cmp_header(line, "Content-Transfer-Encoding")) { - len = strlen("Content-Transfer-Encoding: "); - strbuf_add(&sb, line->buf + len, line->len - len); - decode_header(mi, &sb); + if (parse_header(line, "Content-Transfer-Encoding", mi, &sb)) { handle_content_transfer_encoding(mi, &sb); ret = 1; goto check_header_out; } - if (cmp_header(line, "Message-Id")) { - len = strlen("Message-Id: "); - strbuf_add(&sb, line->buf + len, line->len - len); - decode_header(mi, &sb); + if (parse_header(line, "Message-Id", mi, &sb)) { if (mi->add_message_id) mi->message_id = strbuf_detach(&sb, NULL); ret = 1; @@ -607,8 +618,9 @@ static int is_inbody_header(const struct mailinfo *mi, const struct strbuf *line) { int i; + const char *val; for (i = 0; header[i]; i++) - if (!mi->s_hdr_data[i] && cmp_header(line, header[i])) + if (!mi->s_hdr_data[i] && skip_header(line, header[i], &val)) return 1; return 0; } @@ -1126,6 +1138,11 @@ static void handle_info(struct mailinfo *mi) else continue; + if (memchr(hdr->buf, '\0', hdr->len)) { + error("a NUL byte in '%s' is not allowed.", header[i]); + mi->input_error = -1; + } + if (!strcmp(header[i], "Subject")) { if (!mi->keep_subject) { cleanup_subject(mi, hdr); |