diff options
author | Jonathan Tan <jonathantanmy@google.com> | 2016-09-20 10:17:53 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2016-09-21 10:23:11 -0700 |
commit | 6b4b013f1884a3b5e67877d65a9f1da598ab4a6f (patch) | |
tree | 3076091dfce8fc0c844c9bbea2825ba25780902b /mailinfo.c | |
parent | 9c5681da88825c4320d3f7142ed320e6984c2377 (diff) | |
download | git-6b4b013f1884a3b5e67877d65a9f1da598ab4a6f.tar.gz |
mailinfo: handle in-body header continuations
Mailinfo currently handles multi-line headers, but it does not handle
multi-line in-body headers. Teach it to handle such headers, for
example, for this input:
From: author <author@example.com>
Date: Fri, 9 Jun 2006 00:44:16 -0700
Subject: a very long
broken line
Subject: another very long
broken line
interpret the in-body subject to be "another very long broken line"
instead of "another very long".
An existing test (t/t5100/msg0015) has an indented line immediately
after an in-body header - it has been modified to reflect the new
functionality.
Signed-off-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'mailinfo.c')
-rw-r--r-- | mailinfo.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/mailinfo.c b/mailinfo.c index 69391aaca1..2275b285f0 100644 --- a/mailinfo.c +++ b/mailinfo.c @@ -500,6 +500,21 @@ check_header_out: return ret; } +/* + * Returns 1 if the given line or any line beginning with the given line is an + * in-body header (that is, check_header will succeed when passed + * mi->s_hdr_data). + */ +static int is_inbody_header(const struct mailinfo *mi, + const struct strbuf *line) +{ + int i; + for (i = 0; header[i]; i++) + if (!mi->s_hdr_data[i] && cmp_header(line, header[i])) + return 1; + return 0; +} + static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line) { struct strbuf *ret; @@ -609,8 +624,33 @@ static int is_scissors_line(const char *line) gap * 2 < perforation); } +static void flush_inbody_header_accum(struct mailinfo *mi) +{ + if (!mi->inbody_header_accum.len) + return; + assert(check_header(mi, &mi->inbody_header_accum, mi->s_hdr_data, 0)); + strbuf_reset(&mi->inbody_header_accum); +} + static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line) { + if (mi->inbody_header_accum.len && + (line->buf[0] == ' ' || line->buf[0] == '\t')) { + if (mi->use_scissors && is_scissors_line(line->buf)) { + /* + * This is a scissors line; do not consider this line + * as a header continuation line. + */ + flush_inbody_header_accum(mi); + return 0; + } + strbuf_strip_suffix(&mi->inbody_header_accum, "\n"); + strbuf_addbuf(&mi->inbody_header_accum, line); + return 1; + } + + flush_inbody_header_accum(mi); + if (starts_with(line->buf, ">From") && isspace(line->buf[5])) return is_format_patch_separator(line->buf + 1, line->len - 1); if (starts_with(line->buf, "[PATCH]") && isspace(line->buf[7])) { @@ -622,7 +662,11 @@ static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line) } return 0; } - return check_header(mi, line, mi->s_hdr_data, 0); + if (is_inbody_header(mi, line)) { + strbuf_addbuf(&mi->inbody_header_accum, line); + return 1; + } + return 0; } static int handle_commit_msg(struct mailinfo *mi, struct strbuf *line) @@ -888,6 +932,8 @@ static void handle_body(struct mailinfo *mi, struct strbuf *line) break; } while (!strbuf_getwholeline(line, mi->input, '\n')); + flush_inbody_header_accum(mi); + handle_body_out: strbuf_release(&prev); } @@ -1003,6 +1049,7 @@ void setup_mailinfo(struct mailinfo *mi) strbuf_init(&mi->email, 0); strbuf_init(&mi->charset, 0); strbuf_init(&mi->log_message, 0); + strbuf_init(&mi->inbody_header_accum, 0); mi->header_stage = 1; mi->use_inbody_headers = 1; mi->content_top = mi->content; @@ -1016,6 +1063,7 @@ void clear_mailinfo(struct mailinfo *mi) strbuf_release(&mi->name); strbuf_release(&mi->email); strbuf_release(&mi->charset); + strbuf_release(&mi->inbody_header_accum); free(mi->message_id); for (i = 0; mi->p_hdr_data[i]; i++) |