send-email: ask about and declare 8bit mails
git-send-email passes on an 8bit mail as-is even if it does not declare a content-type. Because the user can edit email between format-patch and send-email, such invalid mails are unfortunately not very hard to come by. Make git-send-email stop and ask about the encoding to use if it encounters any such mail. Also provide a configuration setting to permanently configure an encoding. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Thomas Rast committed
Jun 17, 2010 at 22:10 UTC
3cae7e5b2b9c73aca6a7729bc34c1ce6638fa43a
3 files changed
+146
Documentation/git-send-email.txt
+9
@@ -101,6 +101,15 @@ See the CONFIGURATION section for 'sendemail.multiedit'.
101
+
102
The --to option must be repeated for each user you want on the to list.
103
104
+--8bit-encoding=<encoding>::
105
+ When encountering a non-ASCII message or subject that does not
106
+ declare its encoding, add headers/quoting to indicate it is
107
+ encoded in <encoding>. Default is the value of the
108
+ 'sendemail.assume8bitEncoding'; if that is unspecified, this
109
+ will be prompted for if any non-ASCII files are encountered.
110
++
111
+Note that no attempts whatsoever are made to validate the encoding.
112
+
113
114
Sending
115
~~~~~~~
git-send-email.perl
+60
@@ -54,6 +54,7 @@ git send-email [options] <file | directory | rev-list options >
54
--in-reply-to <str> * Email "In-Reply-To:"
55
--annotate * Review each patch that will be sent in an editor.
56
--compose * Open an editor for introduction.
57
+ --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
58
59
Sending:
60
--envelope-sender <str> * Email envelope sender.
@@ -193,6 +194,7 @@ my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
194
my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
195
my ($validate, $confirm);
196
my (@suppress_cc);
197
+my ($auto_8bit_encoding);
198
199
my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
200
@@ -223,6 +225,7 @@ my %config_settings = (
225
"multiedit" => \$multiedit,
226
"confirm" => \$confirm,
227
"from" => \$sender,
228
+ "assume8bitencoding" => \$auto_8bit_encoding,
229
);
230
231
# Help users prepare for 1.7.0
@@ -298,6 +301,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
301
"thread!" => \$thread,
302
"validate!" => \$validate,
303
"format-patch!" => \$format_patch,
304
+ "8bit-encoding=s" => \$auto_8bit_encoding,
305
);
306
307
unless ($rc) {
@@ -670,6 +674,35 @@ sub ask {
674
return undef;
675
}
676
677
+my %broken_encoding;
678
+
679
+sub file_declares_8bit_cte($) {
680
+ my $fn = shift;
681
+ open (my $fh, '<', $fn);
682
+ while (my $line = <$fh>) {
683
+ last if ($line =~ /^$/);
684
+ return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
685
+ }
686
+ close $fh;
687
+ return 0;
688
+}
689
+
690
+foreach my $f (@files) {
691
+ next unless (body_or_subject_has_nonascii($f)
692
+ && !file_declares_8bit_cte($f));
693
+ $broken_encoding{$f} = 1;
694
+}
695
+
696
+if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
697
+ print "The following files are 8bit, but do not declare " .
698
+ "a Content-Transfer-Encoding.\n";
699
+ foreach my $f (sort keys %broken_encoding) {
700
+ print " $f\n";
701
+ }
702
+ $auto_8bit_encoding = ask("Which 8bit encoding should I declare [UTF-8]? ",
703
+ default => "UTF-8");
704
+}
705
+
706
my $prompting = 0;
707
if (!defined $sender) {
708
$sender = $repoauthor || $repocommitter || '';
@@ -1225,6 +1258,18 @@ foreach my $t (@files) {
1258
or die "(cc-cmd) failed to close pipe to '$cc_cmd'";
1259
}
1260
1261
+ if ($broken_encoding{$t} && !$has_content_type) {
1262
+ $has_content_type = 1;
1263
+ push @xh, "MIME-Version: 1.0",
1264
+ "Content-Type: text/plain; charset=$auto_8bit_encoding",
1265
+ "Content-Transfer-Encoding: 8bit";
1266
+ $body_encoding = $auto_8bit_encoding;
1267
+ }
1268
+
1269
+ if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) {
1270
+ $subject = quote_rfc2047($subject, $auto_8bit_encoding);
1271
+ }
1272
+
1273
if (defined $author and $author ne $sender) {
1274
$message = "From: $author\n\n$message";
1275
if (defined $author_encoding) {
@@ -1237,6 +1282,7 @@ foreach my $t (@files) {
1282
}
1283
}
1284
else {
1285
+ $has_content_type = 1;
1286
push @xh,
1287
'MIME-Version: 1.0',
1288
"Content-Type: text/plain; charset=$author_encoding",
@@ -1314,3 +1360,17 @@ sub file_has_nonascii {
1360
}
1361
return 0;
1362
}
1363
+
1364
+sub body_or_subject_has_nonascii {
1365
+ my $fn = shift;
1366
+ open(my $fh, '<', $fn)
1367
+ or die "unable to open $fn: $!\n";
1368
+ while (my $line = <$fh>) {
1369
+ last if $line =~ /^$/;
1370
+ return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
1371
+ }
1372
+ while (my $line = <$fh>) {
1373
+ return 1 if $line =~ /[^[:ascii:]]/;
1374
+ }
1375
+ return 0;
1376
+}
t/t9001-send-email.sh
+77
@@ -918,4 +918,81 @@ test_expect_success '--no-bcc overrides sendemail.bcc' '
918
! grep "RCPT TO:<other@ex.com>" stdout
919
'
920
921
+cat >email-using-8bit <<EOF
922
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
923
+Message-Id: <bogus-message-id@example.com>
924
+From: author@example.com
925
+Date: Sat, 12 Jun 2010 15:53:58 +0200
926
+Subject: subject goes here
927
+
928
+Dieser deutsche Text enthält einen Umlaut!
929
+EOF
930
+
931
+cat >content-type-decl <<EOF
932
+MIME-Version: 1.0
933
+Content-Type: text/plain; charset=UTF-8
934
+Content-Transfer-Encoding: 8bit
935
+EOF
936
+
937
+test_expect_success 'asks about and fixes 8bit encodings' '
938
+ clean_fake_sendmail &&
939
+ echo |
940
+ git send-email --from=author@example.com --to=nobody@example.com \
941
+ --smtp-server="$(pwd)/fake.sendmail" \
942
+ email-using-8bit >stdout &&
943
+ grep "do not declare a Content-Transfer-Encoding" stdout &&
944
+ grep email-using-8bit stdout &&
945
+ grep "Which 8bit encoding" stdout &&
946
+ grep "Content\\|MIME" msgtxt1 >actual &&
947
+ test_cmp actual content-type-decl
948
+'
949
+
950
+test_expect_success 'sendemail.8bitEncoding works' '
951
+ clean_fake_sendmail &&
952
+ git config sendemail.assume8bitEncoding UTF-8 &&
953
+ echo bogus |
954
+ git send-email --from=author@example.com --to=nobody@example.com \
955
+ --smtp-server="$(pwd)/fake.sendmail" \
956
+ email-using-8bit >stdout &&
957
+ grep "Content\\|MIME" msgtxt1 >actual &&
958
+ test_cmp actual content-type-decl
959
+'
960
+
961
+test_expect_success '--8bit-encoding overrides sendemail.8bitEncoding' '
962
+ clean_fake_sendmail &&
963
+ git config sendemail.assume8bitEncoding "bogus too" &&
964
+ echo bogus |
965
+ git send-email --from=author@example.com --to=nobody@example.com \
966
+ --smtp-server="$(pwd)/fake.sendmail" \
967
+ --8bit-encoding=UTF-8 \
968
+ email-using-8bit >stdout &&
969
+ grep "Content\\|MIME" msgtxt1 >actual &&
970
+ test_cmp actual content-type-decl
971
+'
972
+
973
+cat >email-using-8bit <<EOF
974
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
975
+Message-Id: <bogus-message-id@example.com>
976
+From: author@example.com
977
+Date: Sat, 12 Jun 2010 15:53:58 +0200
978
+Subject: Dieser Betreff enthält auch einen Umlaut!
979
+
980
+Nothing to see here.
981
+EOF
982
+
983
+cat >expected <<EOF
984
+Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
985
+EOF
986
+
987
+test_expect_success '--8bit-encoding also treats subject' '
988
+ clean_fake_sendmail &&
989
+ echo bogus |
990
+ git send-email --from=author@example.com --to=nobody@example.com \
991
+ --smtp-server="$(pwd)/fake.sendmail" \
992
+ --8bit-encoding=UTF-8 \
993
+ email-using-8bit >stdout &&
994
+ grep "Subject" msgtxt1 >actual &&
995
+ test_cmp expected actual
996
+'
997
+
998
test_done