Skip to content

Commit 6b4b013

Browse files
jonathantanmygitster
authored andcommitted
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 <[email protected]> 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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9c5681d commit 6b4b013

12 files changed

+125
-4
lines changed

mailinfo.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,21 @@ static int check_header(struct mailinfo *mi,
500500
return ret;
501501
}
502502

503+
/*
504+
* Returns 1 if the given line or any line beginning with the given line is an
505+
* in-body header (that is, check_header will succeed when passed
506+
* mi->s_hdr_data).
507+
*/
508+
static int is_inbody_header(const struct mailinfo *mi,
509+
const struct strbuf *line)
510+
{
511+
int i;
512+
for (i = 0; header[i]; i++)
513+
if (!mi->s_hdr_data[i] && cmp_header(line, header[i]))
514+
return 1;
515+
return 0;
516+
}
517+
503518
static void decode_transfer_encoding(struct mailinfo *mi, struct strbuf *line)
504519
{
505520
struct strbuf *ret;
@@ -609,8 +624,33 @@ static int is_scissors_line(const char *line)
609624
gap * 2 < perforation);
610625
}
611626

627+
static void flush_inbody_header_accum(struct mailinfo *mi)
628+
{
629+
if (!mi->inbody_header_accum.len)
630+
return;
631+
assert(check_header(mi, &mi->inbody_header_accum, mi->s_hdr_data, 0));
632+
strbuf_reset(&mi->inbody_header_accum);
633+
}
634+
612635
static int check_inbody_header(struct mailinfo *mi, const struct strbuf *line)
613636
{
637+
if (mi->inbody_header_accum.len &&
638+
(line->buf[0] == ' ' || line->buf[0] == '\t')) {
639+
if (mi->use_scissors && is_scissors_line(line->buf)) {
640+
/*
641+
* This is a scissors line; do not consider this line
642+
* as a header continuation line.
643+
*/
644+
flush_inbody_header_accum(mi);
645+
return 0;
646+
}
647+
strbuf_strip_suffix(&mi->inbody_header_accum, "\n");
648+
strbuf_addbuf(&mi->inbody_header_accum, line);
649+
return 1;
650+
}
651+
652+
flush_inbody_header_accum(mi);
653+
614654
if (starts_with(line->buf, ">From") && isspace(line->buf[5]))
615655
return is_format_patch_separator(line->buf + 1, line->len - 1);
616656
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)
622662
}
623663
return 0;
624664
}
625-
return check_header(mi, line, mi->s_hdr_data, 0);
665+
if (is_inbody_header(mi, line)) {
666+
strbuf_addbuf(&mi->inbody_header_accum, line);
667+
return 1;
668+
}
669+
return 0;
626670
}
627671

628672
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)
888932
break;
889933
} while (!strbuf_getwholeline(line, mi->input, '\n'));
890934

935+
flush_inbody_header_accum(mi);
936+
891937
handle_body_out:
892938
strbuf_release(&prev);
893939
}
@@ -1003,6 +1049,7 @@ void setup_mailinfo(struct mailinfo *mi)
10031049
strbuf_init(&mi->email, 0);
10041050
strbuf_init(&mi->charset, 0);
10051051
strbuf_init(&mi->log_message, 0);
1052+
strbuf_init(&mi->inbody_header_accum, 0);
10061053
mi->header_stage = 1;
10071054
mi->use_inbody_headers = 1;
10081055
mi->content_top = mi->content;
@@ -1016,6 +1063,7 @@ void clear_mailinfo(struct mailinfo *mi)
10161063
strbuf_release(&mi->name);
10171064
strbuf_release(&mi->email);
10181065
strbuf_release(&mi->charset);
1066+
strbuf_release(&mi->inbody_header_accum);
10191067
free(mi->message_id);
10201068

10211069
for (i = 0; mi->p_hdr_data[i]; i++)

mailinfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct mailinfo {
2727
int patch_lines;
2828
int filter_stage; /* still reading log or are we copying patch? */
2929
int header_stage; /* still checking in-body headers? */
30+
struct strbuf inbody_header_accum;
3031
struct strbuf **p_hdr_data;
3132
struct strbuf **s_hdr_data;
3233

t/t4150-am.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,4 +977,27 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
977977
test_cmp msg out
978978
'
979979

980+
test_expect_success 'am works with multi-line in-body headers' '
981+
FORTY="String that has a length of more than forty characters" &&
982+
LONG="$FORTY $FORTY" &&
983+
rm -fr .git/rebase-apply &&
984+
git checkout -f first &&
985+
echo one >> file &&
986+
git commit -am "$LONG" --author="$LONG <[email protected]>" &&
987+
git format-patch --stdout -1 >patch &&
988+
# bump from, date, and subject down to in-body header
989+
perl -lpe "
990+
if (/^From:/) {
991+
print \"From: x <x\@example.com>\";
992+
print \"Date: Sat, 1 Jan 2000 00:00:00 +0000\";
993+
print \"Subject: x\n\";
994+
}
995+
" patch >msg &&
996+
git checkout HEAD^ &&
997+
git am msg &&
998+
# Ensure that the author and full message are present
999+
git cat-file commit HEAD | grep "^author.*[email protected]" &&
1000+
git cat-file commit HEAD | grep "^$LONG"
1001+
'
1002+
9801003
test_done

t/t5100-mailinfo.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ test_expect_success 'split sample box' \
1111
'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last &&
1212
last=$(cat last) &&
1313
echo total is $last &&
14-
test $(cat last) = 17'
14+
test $(cat last) = 18'
1515

1616
check_mailinfo () {
1717
mail=$1 opt=$2

t/t5100/info0018

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Author: Another Thor
2+
3+
Subject: This one contains a tab and a space
4+
Date: Fri, 9 Jun 2006 00:44:16 -0700
5+

t/t5100/info0018--no-inbody-headers

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Author: A U Thor
2+
3+
Subject: check multiline inbody headers
4+
Date: Fri, 9 Jun 2006 00:44:16 -0700
5+

t/t5100/msg0015

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
- a list
2-
- of stuff

t/t5100/msg0018

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
a commit message
2+

t/t5100/msg0018--no-inbody-headers

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
From: Another Thor
2+
3+
Subject: This one contains
4+
a tab
5+
and a space
6+
7+
a commit message
8+

t/t5100/patch0018

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
diff --git a/foo b/foo
2+
index e69de29..d95f3ad 100644
3+
--- a/foo
4+
+++ b/foo
5+
@@ -0,0 +1 @@
6+
+content

0 commit comments

Comments
 (0)