Merge branch 'pb/send-email-te'

"git send-email" learned "--transfer-encoding" option to force
a non-fault Content-Transfer-Encoding header (e.g. base64).

* pb/send-email-te:
  git-send-email: add --transfer-encoding option
  git-send-email: delay creation of MIME headers
This commit is contained in:
Junio C Hamano 2014-12-22 12:26:53 -08:00
commit 2374f1dfd1
5 changed files with 227 additions and 6 deletions

View File

@ -2318,6 +2318,7 @@ sendemail.smtpserverport::
sendemail.smtpserveroption:: sendemail.smtpserveroption::
sendemail.smtpuser:: sendemail.smtpuser::
sendemail.thread:: sendemail.thread::
sendemail.transferencoding::
sendemail.validate:: sendemail.validate::
See linkgit:git-send-email[1] for description. See linkgit:git-send-email[1] for description.

View File

@ -131,6 +131,16 @@ Note that no attempts whatsoever are made to validate the encoding.
Specify encoding of compose message. Default is the value of the Specify encoding of compose message. Default is the value of the
'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed. 'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
--transfer-encoding=(7bit|8bit|quoted-printable|base64)::
Specify the transfer encoding to be used to send the message over SMTP.
7bit will fail upon encountering a non-ASCII message. quoted-printable
can be useful when the repository contains files that contain carriage
returns, but makes the raw patch email file (as saved from a MUA) much
harder to inspect manually. base64 is even more fool proof, but also
even more opaque. Default is the value of the 'sendemail.transferEncoding'
configuration value; if that is unspecified, git will use 8bit and not
add a Content-Transfer-Encoding header.
Sending Sending
~~~~~~~ ~~~~~~~

View File

@ -1875,6 +1875,10 @@ _git_config ()
__gitcomp "$__git_send_email_suppresscc_options" __gitcomp "$__git_send_email_suppresscc_options"
return return
;; ;;
sendemail.transferencoding)
__gitcomp "7bit 8bit quoted-printable base64"
return
;;
--get|--get-all|--unset|--unset-all) --get|--get-all|--unset|--unset-all)
__gitcomp_nl "$(__git_config_get_set_variables)" __gitcomp_nl "$(__git_config_get_set_variables)"
return return

View File

@ -58,6 +58,7 @@ git send-email [options] <file | directory | rev-list options >
--compose * Open an editor for introduction. --compose * Open an editor for introduction.
--compose-encoding <str> * Encoding to assume for introduction. --compose-encoding <str> * Encoding to assume for introduction.
--8bit-encoding <str> * Encoding to assume 8bit mails if undeclared --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
--transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
Sending: Sending:
--envelope-sender <str> * Email envelope sender. --envelope-sender <str> * Email envelope sender.
@ -206,6 +207,7 @@ my ($validate, $confirm);
my (@suppress_cc); my (@suppress_cc);
my ($auto_8bit_encoding); my ($auto_8bit_encoding);
my ($compose_encoding); my ($compose_encoding);
my ($target_xfer_encoding);
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message() my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
@ -242,6 +244,7 @@ my %config_settings = (
"from" => \$sender, "from" => \$sender,
"assume8bitencoding" => \$auto_8bit_encoding, "assume8bitencoding" => \$auto_8bit_encoding,
"composeencoding" => \$compose_encoding, "composeencoding" => \$compose_encoding,
"transferencoding" => \$target_xfer_encoding,
); );
my %config_path_settings = ( my %config_path_settings = (
@ -314,6 +317,7 @@ my $rc = GetOptions("h" => \$help,
"envelope-sender=s" => \$envelope_sender, "envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread, "thread!" => \$thread,
"validate!" => \$validate, "validate!" => \$validate,
"transfer-encoding=s" => \$target_xfer_encoding,
"format-patch!" => \$format_patch, "format-patch!" => \$format_patch,
"8bit-encoding=s" => \$auto_8bit_encoding, "8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding, "compose-encoding=s" => \$compose_encoding,
@ -1324,6 +1328,8 @@ foreach my $t (@files) {
my $author_encoding; my $author_encoding;
my $has_content_type; my $has_content_type;
my $body_encoding; my $body_encoding;
my $xfer_encoding;
my $has_mime_version;
@to = (); @to = ();
@cc = (); @cc = ();
@xh = (); @xh = ();
@ -1394,9 +1400,16 @@ foreach my $t (@files) {
} }
push @xh, $_; push @xh, $_;
} }
elsif (/^MIME-Version/i) {
$has_mime_version = 1;
push @xh, $_;
}
elsif (/^Message-Id: (.*)/i) { elsif (/^Message-Id: (.*)/i) {
$message_id = $1; $message_id = $1;
} }
elsif (/^Content-Transfer-Encoding: (.*)/i) {
$xfer_encoding = $1 if not defined $xfer_encoding;
}
elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) { elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_; push @xh, $_;
} }
@ -1444,10 +1457,9 @@ foreach my $t (@files) {
if defined $cc_cmd && !$suppress_cc{'cccmd'}; if defined $cc_cmd && !$suppress_cc{'cccmd'};
if ($broken_encoding{$t} && !$has_content_type) { if ($broken_encoding{$t} && !$has_content_type) {
$xfer_encoding = '8bit' if not defined $xfer_encoding;
$has_content_type = 1; $has_content_type = 1;
push @xh, "MIME-Version: 1.0", push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
"Content-Type: text/plain; charset=$auto_8bit_encoding",
"Content-Transfer-Encoding: 8bit";
$body_encoding = $auto_8bit_encoding; $body_encoding = $auto_8bit_encoding;
} }
@ -1467,14 +1479,25 @@ foreach my $t (@files) {
} }
} }
else { else {
$xfer_encoding = '8bit' if not defined $xfer_encoding;
$has_content_type = 1; $has_content_type = 1;
push @xh, push @xh,
'MIME-Version: 1.0', "Content-Type: text/plain; charset=$author_encoding";
"Content-Type: text/plain; charset=$author_encoding",
'Content-Transfer-Encoding: 8bit';
} }
} }
} }
if (defined $target_xfer_encoding) {
$xfer_encoding = '8bit' if not defined $xfer_encoding;
$message = apply_transfer_encoding(
$message, $xfer_encoding, $target_xfer_encoding);
$xfer_encoding = $target_xfer_encoding;
}
if (defined $xfer_encoding) {
push @xh, "Content-Transfer-Encoding: $xfer_encoding";
}
if (defined $xfer_encoding or $has_content_type) {
unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
}
$needs_confirm = ( $needs_confirm = (
$confirm eq "always" or $confirm eq "always" or
@ -1543,6 +1566,32 @@ sub cleanup_compose_files {
$smtp->quit if $smtp; $smtp->quit if $smtp;
sub apply_transfer_encoding {
my $message = shift;
my $from = shift;
my $to = shift;
return $message if ($from eq $to and $from ne '7bit');
require MIME::QuotedPrint;
require MIME::Base64;
$message = MIME::QuotedPrint::decode($message)
if ($from eq 'quoted-printable');
$message = MIME::Base64::decode($message)
if ($from eq 'base64');
die "cannot send message as 7bit"
if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
return $message
if ($to eq '7bit' or $to eq '8bit');
return MIME::QuotedPrint::encode($message, "\n", 0)
if ($to eq 'quoted-printable');
return MIME::Base64::encode($message, "\n")
if ($to eq 'base64');
die "invalid transfer encoding";
}
sub unique_email_list { sub unique_email_list {
my %seen; my %seen;
my @emails; my @emails;

View File

@ -1298,6 +1298,163 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
test_cmp expected actual test_cmp expected actual
' '
test_expect_success $PREREQ 'setup expect' '
cat >email-using-8bit <<EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
Message-Id: <bogus-message-id@example.com>
From: A U Thor <author@example.com>
Date: Sat, 12 Jun 2010 15:53:58 +0200
Content-Type: text/plain; charset=UTF-8
Subject: Nothing to see here.
Dieser Betreff enthält auch einen Umlaut!
EOF
'
test_expect_success $PREREQ 'sendemail.transferencoding=7bit fails on 8bit data' '
clean_fake_sendmail &&
git config sendemail.transferEncoding 7bit &&
test_must_fail git send-email \
--transfer-encoding=7bit \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit \
2>errors >out &&
grep "cannot send message as 7bit" errors &&
test -z "$(ls msgtxt*)"
'
test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEncoding' '
clean_fake_sendmail &&
git config sendemail.transferEncoding 8bit
test_must_fail git send-email \
--transfer-encoding=7bit \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit \
2>errors >out &&
grep "cannot send message as 7bit" errors &&
test -z "$(ls msgtxt*)"
'
test_expect_success $PREREQ 'sendemail.transferencoding=8bit' '
clean_fake_sendmail &&
git send-email \
--transfer-encoding=8bit \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit \
2>errors >out &&
sed '1,/^$/d' msgtxt1 >actual &&
sed '1,/^$/d' email-using-8bit >expected &&
test_cmp expected actual
'
test_expect_success $PREREQ 'setup expect' '
cat >expected <<EOF
Dieser Betreff enth=C3=A4lt auch einen Umlaut!
EOF
'
test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printable' '
clean_fake_sendmail &&
git send-email \
--transfer-encoding=quoted-printable \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit \
2>errors >out &&
sed '1,/^$/d' msgtxt1 >actual &&
test_cmp expected actual
'
test_expect_success $PREREQ 'setup expect' '
cat >expected <<EOF
RGllc2VyIEJldHJlZmYgZW50aMOkbHQgYXVjaCBlaW5lbiBVbWxhdXQhCg==
EOF
'
test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
clean_fake_sendmail &&
git send-email \
--transfer-encoding=base64 \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-8bit \
2>errors >out &&
sed '1,/^$/d' msgtxt1 >actual &&
test_cmp expected actual
'
test_expect_success $PREREQ 'setup expect' '
cat >email-using-qp <<EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
Message-Id: <bogus-message-id@example.com>
From: A U Thor <author@example.com>
Date: Sat, 12 Jun 2010 15:53:58 +0200
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
Subject: Nothing to see here.
Dieser Betreff enth=C3=A4lt auch einen Umlaut!
EOF
'
test_expect_success $PREREQ 'convert from quoted-printable to base64' '
clean_fake_sendmail &&
git send-email \
--transfer-encoding=base64 \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-qp \
2>errors >out &&
sed '1,/^$/d' msgtxt1 >actual &&
test_cmp expected actual
'
test_expect_success $PREREQ 'setup expect' "
tr -d '\\015' | tr '%' '\\015' > email-using-crlf <<EOF
From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
Message-Id: <bogus-message-id@example.com>
From: A U Thor <author@example.com>
Date: Sat, 12 Jun 2010 15:53:58 +0200
Content-Type: text/plain; charset=UTF-8
Subject: Nothing to see here.
Look, I have a CRLF and an = sign!%
EOF
"
test_expect_success $PREREQ 'setup expect' '
cat >expected <<EOF
Look, I have a CRLF and an =3D sign!=0D
EOF
'
test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printable' '
clean_fake_sendmail &&
git send-email \
--transfer-encoding=quoted-printable \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-crlf \
2>errors >out &&
sed '1,/^$/d' msgtxt1 >actual &&
test_cmp expected actual
'
test_expect_success $PREREQ 'setup expect' '
cat >expected <<EOF
TG9vaywgSSBoYXZlIGEgQ1JMRiBhbmQgYW4gPSBzaWduIQ0K
EOF
'
test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '
clean_fake_sendmail &&
git send-email \
--transfer-encoding=base64 \
--smtp-server="$(pwd)/fake.sendmail" \
email-using-crlf \
2>errors >out &&
sed '1,/^$/d' msgtxt1 >actual &&
test_cmp expected actual
'
# Note that the patches in this test are deliberately out of order; we # Note that the patches in this test are deliberately out of order; we
# want to make sure it works even if the cover-letter is not in the # want to make sure it works even if the cover-letter is not in the
# first mail. # first mail.