From 6bf4f1b4c9d78b2061bd5f3bf77bb21112b755be Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 14 Mar 2008 17:10:09 -0700 Subject: [PATCH] format-patch: generate MIME header as needed even when there is format.header Earlier, the callchain from pretty_print_commit() down to pp_title_line() had an unwarranted assumption that the presense of "after_subject" parameter, means the caller has already output MIME headers for attachments. The parameter's primary purpose is to give extra header lines the caller wants to place after pp_title_line() generates the "Subject: " line. This assumption does not hold when the user used the format.header configuration variable to pass extra headers, and caused a message with non-ASCII character to lack proper MIME headers (e.g. 8-bit CTE header). The earlier logic also failed to suppress duplicated MIME headers when "format-patch -s --attach" is asked for and the signer's name demanded 8-bit clean transport. This patch fixes the logic by introducing a separate need_8bit_cte parameter passed down the callchain. This can have one of these values: -1 : we've already done MIME crap and we do not want to add extra header to say this is 8bit in pp_title_line(); 0 : we haven't done MIME and we have not seen anything that is 8bit yet; 1 : we haven't done MIME and we have seen something that is 8bit; pp_title_line() must add MIME header. It adds two tests by Jeff King who independently diagnosed this issue. Signed-off-by: Junio C Hamano --- commit.h | 2 +- log-tree.c | 7 ++++++- pretty.c | 24 ++++++++++------------ t/t4021-format-patch-signer-mime.sh | 10 +++++++++- t/t4028-format-patch-mime-headers.sh | 30 ++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 16 deletions(-) create mode 100755 t/t4028-format-patch-mime-headers.sh diff --git a/commit.h b/commit.h index 10e2b5d4c..000528a67 100644 --- a/commit.h +++ b/commit.h @@ -70,7 +70,7 @@ extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*, struct strbuf *, int abbrev, const char *subject, const char *after_subject, enum date_mode, - int non_ascii_present); + int need_8bit_cte); /** Removes the first commit from a list sorted by date, and adds all * of its parents. diff --git a/log-tree.c b/log-tree.c index 1f3fcf16a..dd94f393a 100644 --- a/log-tree.c +++ b/log-tree.c @@ -146,6 +146,7 @@ void show_log(struct rev_info *opt, const char *sep) int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; const char *extra; const char *subject = NULL, *extra_headers = opt->extra_headers; + int need_8bit_cte = 0; opt->loginfo = NULL; if (!opt->verbose_header) { @@ -214,6 +215,8 @@ void show_log(struct rev_info *opt, const char *sep) if (opt->mime_boundary) { static char subject_buffer[1024]; static char buffer[1024]; + + need_8bit_cte = -1; /* never */ snprintf(subject_buffer, sizeof(subject_buffer) - 1, "%s" "MIME-Version: 1.0\n" @@ -282,9 +285,11 @@ void show_log(struct rev_info *opt, const char *sep) * And then the pretty-printed message itself */ strbuf_init(&msgbuf, 0); + if (need_8bit_cte >= 0) + need_8bit_cte = has_non_ascii(opt->add_signoff); pretty_print_commit(opt->commit_format, commit, &msgbuf, abbrev, subject, extra_headers, opt->date_mode, - has_non_ascii(opt->add_signoff)); + need_8bit_cte); if (opt->add_signoff) append_signoff(&msgbuf, opt->add_signoff); diff --git a/pretty.c b/pretty.c index b987ff245..0963bb08c 100644 --- a/pretty.c +++ b/pretty.c @@ -659,7 +659,7 @@ static void pp_title_line(enum cmit_fmt fmt, const char *subject, const char *after_subject, const char *encoding, - int plain_non_ascii) + int need_8bit_cte) { struct strbuf title; @@ -692,7 +692,7 @@ static void pp_title_line(enum cmit_fmt fmt, } strbuf_addch(sb, '\n'); - if (plain_non_ascii) { + if (need_8bit_cte > 0) { const char *header_fmt = "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=%s\n" @@ -741,9 +741,9 @@ static void pp_remainder(enum cmit_fmt fmt, } void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, - struct strbuf *sb, int abbrev, - const char *subject, const char *after_subject, - enum date_mode dmode, int plain_non_ascii) + struct strbuf *sb, int abbrev, + const char *subject, const char *after_subject, + enum date_mode dmode, int need_8bit_cte) { unsigned long beginning_of_body; int indent = 4; @@ -769,13 +769,11 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) indent = 0; - /* After-subject is used to pass in Content-Type: multipart - * MIME header; in that case we do not have to do the - * plaintext content type even if the commit message has - * non 7-bit ASCII character. Otherwise, check if we need - * to say this is not a 7-bit ASCII. + /* + * We need to check and emit Content-type: to mark it + * as 8-bit if we haven't done so. */ - if (fmt == CMIT_FMT_EMAIL && !after_subject) { + if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) { int i, ch, in_body; for (in_body = i = 0; (ch = msg[i]); i++) { @@ -788,7 +786,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, in_body = 1; } else if (non_ascii(ch)) { - plain_non_ascii = 1; + need_8bit_cte = 1; break; } } @@ -813,7 +811,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, /* These formats treat the title line specially. */ if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL) pp_title_line(fmt, &msg, sb, subject, - after_subject, encoding, plain_non_ascii); + after_subject, encoding, need_8bit_cte); beginning_of_body = sb->len; if (fmt != CMIT_FMT_ONELINE) diff --git a/t/t4021-format-patch-signer-mime.sh b/t/t4021-format-patch-signer-mime.sh index 67a70fada..ba43f1854 100755 --- a/t/t4021-format-patch-signer-mime.sh +++ b/t/t4021-format-patch-signer-mime.sh @@ -32,11 +32,19 @@ test_expect_success 'format with signoff without funny signer name' ' test_expect_success 'format with non ASCII signer name' ' - GIT_COMMITTER_NAME="$B$O$^$N(B $B$U$K$*$&(B" \ + GIT_COMMITTER_NAME="はまの ふにおう" \ git format-patch -s --stdout -1 >output && grep Content-Type output ' +test_expect_success 'attach and signoff do not duplicate mime headers' ' + + GIT_COMMITTER_NAME="はまの ふにおう" \ + git format-patch -s --stdout -1 --attach >output && + test `grep -ci ^MIME-Version: output` = 1 + +' + test_done diff --git a/t/t4028-format-patch-mime-headers.sh b/t/t4028-format-patch-mime-headers.sh new file mode 100755 index 000000000..204ba673c --- /dev/null +++ b/t/t4028-format-patch-mime-headers.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +test_description='format-patch mime headers and extra headers do not conflict' +. ./test-lib.sh + +test_expect_success 'create commit with utf-8 body' ' + echo content >file && + git add file && + git commit -m one && + echo more >>file && + git commit -a -m "two + + utf-8 body: ñ" +' + +test_expect_success 'patch has mime headers' ' + rm -f 0001-two.patch && + git format-patch HEAD^ && + grep -i "content-type: text/plain; charset=utf-8" 0001-two.patch +' + +test_expect_success 'patch has mime and extra headers' ' + rm -f 0001-two.patch && + git config format.headers "x-foo: bar" && + git format-patch HEAD^ && + grep -i "x-foo: bar" 0001-two.patch && + grep -i "content-type: text/plain; charset=utf-8" 0001-two.patch +' + +test_done -- 2.30.2