From: Junio C Hamano Date: Wed, 7 Jan 2015 21:06:47 +0000 (-0800) Subject: Merge branch 'rd/send-email-2047-fix' X-Git-Tag: v2.3.0-rc0~20 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/948e81408d29be0d39b55d5da41a6c7c9b93fbc0?ds=inline;hp=-c Merge branch 'rd/send-email-2047-fix' "git send-email" did not handle RFC 2047 encoded headers quite right. * rd/send-email-2047-fix: send-email: handle adjacent RFC 2047-encoded words properly send-email: align RFC 2047 decoding more closely with the spec --- 948e81408d29be0d39b55d5da41a6c7c9b93fbc0 diff --combined git-send-email.perl index 82c6feaa46,cd327d7043..58c8bc2a59 --- a/git-send-email.perl +++ b/git-send-email.perl @@@ -58,7 -58,6 +58,7 @@@ git send-email [options] * Encoding to assume for introduction. --8bit-encoding * Encoding to assume 8bit mails if undeclared + --transfer-encoding * Transfer encoding to use (quoted-printable, 8bit, base64) Sending: --envelope-sender * Email envelope sender. @@@ -81,8 -80,6 +81,8 @@@ --to-cmd * Email To: via ` \$patch_path` --cc-cmd * Email Cc: via ` \$patch_path` --suppress-cc * author, self, sob, cc, cccmd, body, bodycc, all. + --[no-]cc-cover * Email Cc: addresses in the cover letter. + --[no-]to-cover * Email To: addresses in the cover letter. --[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on. --[no-]suppress-from * Send to self. Default off. --[no-]chain-reply-to * Chain In-Reply-To: fields. Default off. @@@ -146,6 -143,11 +146,11 @@@ my $have_mail_address = eval { require my $smtp; my $auth; + # Regexes for RFC 2047 productions. + my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/; + my $re_encoded_text = qr/[^? \000-\037\177-\377]+/; + my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/; + # Variables we fill in automatically, or via prompting: my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh, $initial_reply_to,$initial_subject,@files, @@@ -198,7 -200,6 +203,7 @@@ sub do_edit # Variables with corresponding config settings my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc); +my ($cover_cc, $cover_to); my ($to_cmd, $cc_cmd); my ($smtp_server, $smtp_server_port, @smtp_server_options); my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); @@@ -207,7 -208,6 +212,7 @@@ my ($validate, $confirm) my (@suppress_cc); my ($auto_8bit_encoding); my ($compose_encoding); +my ($target_xfer_encoding); my ($debug_net_smtp) = 0; # Net::SMTP, see send_message() @@@ -216,8 -216,6 +221,8 @@@ my %config_bool_settings = "chainreplyto" => [\$chain_reply_to, 0], "suppressfrom" => [\$suppress_from, undef], "signedoffbycc" => [\$signed_off_by_cc, undef], + "cccover" => [\$cover_cc, undef], + "tocover" => [\$cover_to, undef], "signedoffcc" => [\$signed_off_by_cc, undef], # Deprecated "validate" => [\$validate, 1], "multiedit" => [\$multiedit, undef], @@@ -244,7 -242,6 +249,7 @@@ my %config_settings = "from" => \$sender, "assume8bitencoding" => \$auto_8bit_encoding, "composeencoding" => \$compose_encoding, + "transferencoding" => \$target_xfer_encoding, ); my %config_path_settings = ( @@@ -310,14 -307,11 +315,14 @@@ my $rc = GetOptions("h" => \$help "suppress-from!" => \$suppress_from, "suppress-cc=s" => \@suppress_cc, "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc, + "cc-cover|cc-cover!" => \$cover_cc, + "to-cover|to-cover!" => \$cover_to, "confirm=s" => \$confirm, "dry-run" => \$dry_run, "envelope-sender=s" => \$envelope_sender, "thread!" => \$thread, "validate!" => \$validate, + "transfer-encoding=s" => \$target_xfer_encoding, "format-patch!" => \$format_patch, "8bit-encoding=s" => \$auto_8bit_encoding, "compose-encoding=s" => \$compose_encoding, @@@ -917,15 -911,26 +922,26 @@@ $time = time - scalar $#files sub unquote_rfc2047 { local ($_) = @_; - my $encoding; - s{=\?([^?]+)\?q\?(.*?)\?=}{ - $encoding = $1; - my $e = $2; - $e =~ s/_/ /g; - $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg; - $e; + my $charset; + my $sep = qr/[ \t]+/; + s{$re_encoded_word(?:$sep$re_encoded_word)*}{ + my @words = split $sep, $&; + foreach (@words) { + m/$re_encoded_word/; + $charset = $1; + my $encoding = $2; + my $text = $3; + if ($encoding eq 'q' || $encoding eq 'Q') { + $_ = $text; + s/_/ /g; + s/=([0-9A-F]{2})/chr(hex($1))/egi; + } else { + # other encodings not supported yet + } + } + join '', @words; }eg; - return wantarray ? ($_, $encoding) : $_; + return wantarray ? ($_, $charset) : $_; } sub quote_rfc2047 { @@@ -938,10 -943,8 +954,8 @@@ sub is_rfc2047_quoted { my $s = shift; - my $token = qr/[^][()<>@,;:"\/?.= \000-\037\177-\377]+/; - my $encoded_text = qr/[!->@-~]+/; length($s) <= 75 && - $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o; + $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o; } sub subject_needs_rfc2047_quoting { @@@ -1124,18 -1127,6 +1138,18 @@@ sub ssl_verify_params } } +sub file_name_is_absolute { + my ($path) = @_; + + # msys does not grok DOS drive-prefixes + if ($^O eq 'msys') { + return ($path =~ m#^/# || $path =~ m#^[a-zA-Z]\:#) + } + + require File::Spec::Functions; + return File::Spec::Functions::file_name_is_absolute($path); +} + # Returns 1 if the message was sent, and 0 otherwise. # In actuality, the whole program dies when there # is an error sending a message. @@@ -1220,7 -1211,7 +1234,7 @@@ X-Mailer: git-send-email $gitversio if ($dry_run) { # We don't want to send the email. - } elsif ($smtp_server =~ m#^/#) { + } elsif (file_name_is_absolute($smtp_server)) { my $pid = open my $sm, '|-'; defined $pid or die $!; if (!$pid) { @@@ -1294,7 -1285,7 +1308,7 @@@ printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject); } else { print (($dry_run ? "Dry-" : "")."OK. Log says:\n"); - if ($smtp_server !~ m#^/#) { + if (!file_name_is_absolute($smtp_server)) { print "Server: $smtp_server\n"; print "MAIL FROM:<$raw_from>\n"; foreach my $entry (@recipients) { @@@ -1328,8 -1319,6 +1342,8 @@@ foreach my $t (@files) my $author_encoding; my $has_content_type; my $body_encoding; + my $xfer_encoding; + my $has_mime_version; @to = (); @cc = (); @xh = (); @@@ -1400,16 -1389,9 +1414,16 @@@ } push @xh, $_; } + elsif (/^MIME-Version/i) { + $has_mime_version = 1; + push @xh, $_; + } elsif (/^Message-Id: (.*)/i) { $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/) { push @xh, $_; } @@@ -1457,9 -1439,10 +1471,9 @@@ if defined $cc_cmd && !$suppress_cc{'cccmd'}; if ($broken_encoding{$t} && !$has_content_type) { + $xfer_encoding = '8bit' if not defined $xfer_encoding; $has_content_type = 1; - push @xh, "MIME-Version: 1.0", - "Content-Type: text/plain; charset=$auto_8bit_encoding", - "Content-Transfer-Encoding: 8bit"; + push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding"; $body_encoding = $auto_8bit_encoding; } @@@ -1479,25 -1462,14 +1493,25 @@@ } } else { + $xfer_encoding = '8bit' if not defined $xfer_encoding; $has_content_type = 1; push @xh, - 'MIME-Version: 1.0', - "Content-Type: text/plain; charset=$author_encoding", - 'Content-Transfer-Encoding: 8bit'; + "Content-Type: text/plain; charset=$author_encoding"; } } } + 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 = ( $confirm eq "always" or @@@ -1511,15 -1483,6 +1525,15 @@@ @to = (@initial_to, @to); @cc = (@initial_cc, @cc); + if ($message_num == 1) { + if (defined $cover_cc and $cover_cc) { + @initial_cc = @cc; + } + if (defined $cover_to and $cover_to) { + @initial_to = @to; + } + } + my $message_was_sent = send_message(); # set up for the next message @@@ -1566,32 -1529,6 +1580,32 @@@ sub cleanup_compose_files $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 { my %seen; my @emails; diff --combined t/t9001-send-email.sh index e37efef5ca,f933bc7ec7..a8773bdf37 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@@ -6,37 -6,35 +6,37 @@@ test_description='git send-email # May be altered later in the test PREREQ="PERL" -test_expect_success $PREREQ \ - 'prepare reference tree' \ - 'echo "1A quick brown fox jumps over the" >file && - echo "lazy dog" >>file && - git add file && - GIT_AUTHOR_NAME="A" git commit -a -m "Initial."' - -test_expect_success $PREREQ \ - 'Setup helper tool' \ - '(echo "#!$SHELL_PATH" - echo shift - echo output=1 - echo "while test -f commandline\$output; do output=\$((\$output+1)); done" - echo for a - echo do - echo " echo \"!\$a!\"" - echo "done >commandline\$output" - echo "cat > msgtxt\$output" - ) >fake.sendmail && - chmod +x ./fake.sendmail && - git add fake.sendmail && - GIT_AUTHOR_NAME="A" git commit -a -m "Second."' - -clean_fake_sendmail() { +test_expect_success $PREREQ 'prepare reference tree' ' + echo "1A quick brown fox jumps over the" >file && + echo "lazy dog" >>file && + git add file && + GIT_AUTHOR_NAME="A" git commit -a -m "Initial." +' + +test_expect_success $PREREQ 'Setup helper tool' ' + write_script fake.sendmail <<-\EOF && + shift + output=1 + while test -f commandline$output + do + output=$(($output+1)) + done + for a + do + echo "!$a!" + done >commandline$output + cat >"msgtxt$output" + EOF + git add fake.sendmail && + GIT_AUTHOR_NAME="A" git commit -a -m "Second." +' + +clean_fake_sendmail () { rm -f commandline* msgtxt* } test_expect_success $PREREQ 'Extract patches' ' - patches=`git format-patch -s --cc="One " --cc=two@example.com -n HEAD^1` + patches=`git format-patch -s --cc="One " --cc=two@example.com -n HEAD^1` ' # Test no confirm early to ensure remaining tests will not hang @@@ -49,9 -47,9 +49,9 @@@ test_no_confirm () --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $@ \ - $patches > stdout && + $patches >stdout && test_must_fail grep "Send this email" stdout && - > no_confirm_okay + >no_confirm_okay } # Exit immediately to prevent hang if a no-confirm test fails @@@ -84,61 -82,61 +84,61 @@@ test_expect_success $PREREQ 'No confir ' test_expect_success $PREREQ 'Send patches' ' - git send-email --suppress-cc=sob --from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + git send-email --suppress-cc=sob --from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<\EOF -!nobody@example.com! -!author@example.com! -!one@example.com! -!two@example.com! -EOF + cat >expected <<-\EOF + !nobody@example.com! + !author@example.com! + !one@example.com! + !two@example.com! + EOF ' -test_expect_success $PREREQ \ - 'Verify commandline' \ - 'test_cmp expected commandline1' +test_expect_success $PREREQ 'Verify commandline' ' + test_cmp expected commandline1 +' test_expect_success $PREREQ 'Send patches with --envelope-sender' ' - clean_fake_sendmail && - git send-email --envelope-sender="Patch Contributor " --suppress-cc=sob --from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + clean_fake_sendmail && + git send-email --envelope-sender="Patch Contributor " --suppress-cc=sob --from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<\EOF -!patch@example.com! -!-i! -!nobody@example.com! -!author@example.com! -!one@example.com! -!two@example.com! -EOF + cat >expected <<-\EOF + !patch@example.com! + !-i! + !nobody@example.com! + !author@example.com! + !one@example.com! + !two@example.com! + EOF ' -test_expect_success $PREREQ \ - 'Verify commandline' \ - 'test_cmp expected commandline1' +test_expect_success $PREREQ 'Verify commandline' ' + test_cmp expected commandline1 +' test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' ' - clean_fake_sendmail && - git send-email --envelope-sender=auto --suppress-cc=sob --from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors + clean_fake_sendmail && + git send-email --envelope-sender=auto --suppress-cc=sob --from="Example " --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <<\EOF -!nobody@example.com! -!-i! -!nobody@example.com! -!author@example.com! -!one@example.com! -!two@example.com! -EOF + cat >expected <<-\EOF + !nobody@example.com! + !-i! + !nobody@example.com! + !author@example.com! + !one@example.com! + !two@example.com! + EOF ' -test_expect_success $PREREQ \ - 'Verify commandline' \ - 'test_cmp expected commandline1' +test_expect_success $PREREQ 'Verify commandline' ' + test_cmp expected commandline1 +' test_expect_success $PREREQ 'setup expect' " cat >expected-show-all-headers <<\EOF @@@ -242,6 -240,13 +242,13 @@@ test_expect_success $PREREQ 'non-ascii 'non_ascii_self_suppressed' " + # This name is long enough to force format-patch to split it into multiple + # encoded-words, assuming it uses UTF-8 with the "Q" encoding. + test_expect_success $PREREQ 'long non-ascii self name is suppressed' " + test_suppress_self_quoted 'Ƒüñníęř €. Nâṁé' 'odd_?=mail@example.com' \ + 'long_non_ascii_self_suppressed' + " + test_expect_success $PREREQ 'sanitized self name is suppressed' " test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \ 'self_name_sanitized_suppressed' @@@ -309,9 -314,11 +316,9 @@@ test_expect_success $PREREQ 'tocmd work clean_fake_sendmail && cp $patches tocmd.patch && echo tocmd--tocmd@example.com >>tocmd.patch && - { - echo "#!$SHELL_PATH" - echo sed -n -e s/^tocmd--//p \"\$1\" - } > tocmd-sed && - chmod +x tocmd-sed && + write_script tocmd-sed <<-\EOF && + sed -n -e "s/^tocmd--//p" "$1" + EOF git send-email \ --from="Example " \ --to-cmd=./tocmd-sed \ @@@ -325,9 -332,11 +332,9 @@@ test_expect_success $PREREQ 'cccmd work clean_fake_sendmail && cp $patches cccmd.patch && echo "cccmd-- cccmd@example.com" >>cccmd.patch && - { - echo "#!$SHELL_PATH" - echo sed -n -e s/^cccmd--//p \"\$1\" - } > cccmd-sed && - chmod +x cccmd-sed && + write_script cccmd-sed <<-\EOF && + sed -n -e "s/^cccmd--//p" "$1" + EOF git send-email \ --from="Example " \ --to=nobody@example.com \ @@@ -365,7 -374,7 +372,7 @@@ test_expect_success $PREREQ 'Author Fro --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $patches && - sed "1,/^\$/d" < msgtxt1 > msgbody1 && + sed "1,/^\$/d" msgbody1 && grep "From: A " msgbody1 ' @@@ -376,7 -385,7 +383,7 @@@ test_expect_success $PREREQ 'Author Fro --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ $patches && - sed "1,/^\$/d" < msgtxt1 > msgbody1 && + sed "1,/^\$/d" msgbody1 && ! grep "From: A " msgbody1 ' @@@ -457,9 -466,10 +464,9 @@@ test_expect_success $PREREQ 'In-Reply-T ' test_expect_success $PREREQ 'setup fake editor' ' - (echo "#!$SHELL_PATH" && - echo "echo fake edit >>\"\$1\"" - ) >fake-editor && - chmod +x fake-editor + write_script fake-editor <<-\EOF + echo fake edit >>"$1" + EOF ' test_set_editor "$(pwd)/fake-editor" @@@ -595,9 -605,8 +602,9 @@@ EO " test_expect_success $PREREQ 'sendemail.cccmd' ' - echo echo cc-cmd@example.com > cccmd && - chmod +x cccmd && + write_script cccmd <<-\EOF && + echo cc-cmd@example.com + EOF git config sendemail.cccmd ./cccmd && test_suppression cccmd ' @@@ -790,7 -799,7 +797,7 @@@ test_confirm () --from="Example " \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - $@ $patches > stdout && + $@ $patches >stdout && grep "Send this email" stdout } @@@ -838,7 -847,7 +845,7 @@@ test_expect_success $PREREQ 'confirm de --from="Example " \ --to=nobody@example.com \ --smtp-server="$(pwd)/fake.sendmail" \ - outdir/*.patch < /dev/null + outdir/*.patch >\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose --subject foo \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose --subject foo \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1 ' test_expect_success $PREREQ '--compose respects user mime type' ' clean_fake_sendmail && - (echo "#!$SHELL_PATH" && - echo "(echo MIME-Version: 1.0" - echo " echo Content-Type: text/plain\\; charset=iso-8859-1" - echo " echo Content-Transfer-Encoding: 8bit" - echo " echo Subject: foo" - echo " echo " - echo " echo utf8 body: àéìöú) >\"\$1\"" - ) >fake-editor-utf8-mime && - chmod +x fake-editor-utf8-mime && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \ - git send-email \ - --compose --subject foo \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8-mime <<-\EOF && + cat >"$1" <<-\EOM + MIME-Version: 1.0 + Content-Type: text/plain; charset=iso-8859-1 + Content-Transfer-Encoding: 8bit + Subject: foo + + utf8 body: àéìöú + EOM + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \ + git send-email \ + --compose --subject foo \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 && ! grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1 @@@ -929,13 -938,13 +936,13 @@@ test_expect_success $PREREQ '--compose adds MIME for utf8 subject' ' clean_fake_sendmail && - GIT_EDITOR="\"$(pwd)/fake-editor\"" \ - git send-email \ - --compose --subject utf8-sübjëct \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + GIT_EDITOR="\"$(pwd)/fake-editor\"" \ + git send-email \ + --compose --subject utf8-sübjëct \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^fake edit" msgtxt1 && grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 ' @@@ -947,9 -956,9 +954,9 @@@ test_expect_success $PREREQ 'utf8 autho git commit --amend --author "Füñný Nâmé " && git format-patch --stdout -1 >funny_name.patch && git send-email --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - funny_name.patch && + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && grep "^From: Füñný Nâmé " msgtxt1 ' @@@ -960,9 -969,9 +967,9 @@@ test_expect_success $PREREQ 'utf8 sende git commit --amend --author "Füñný Nâmé " && git format-patch --stdout -1 >funny_name.patch && git send-email --from="Füñný Nâmé " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - funny_name.patch && + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && grep "^From: " msgtxt1 >msgfrom && test_line_count = 1 msgfrom ' @@@ -970,33 -979,35 +977,33 @@@ test_expect_success $PREREQ 'sendemail.composeencoding works' ' clean_fake_sendmail && git config sendemail.composeencoding iso-8859-1 && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose --subject foo \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose --subject foo \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 ' test_expect_success $PREREQ '--compose-encoding works' ' clean_fake_sendmail && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose-encoding iso-8859-1 \ - --compose --subject foo \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-1 \ + --compose --subject foo \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 ' @@@ -1004,37 -1015,38 +1011,37 @@@ test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' ' clean_fake_sendmail && git config sendemail.composeencoding iso-8859-1 && - (echo "#!$SHELL_PATH" && - echo "echo utf8 body: àéìöú >>\"\$1\"" - ) >fake-editor-utf8 && - chmod +x fake-editor-utf8 && - GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ - git send-email \ - --compose-encoding iso-8859-2 \ - --compose --subject foo \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + write_script fake-editor-utf8 <<-\EOF && + echo "utf8 body: àéìöú" >>"$1" + EOF + GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject foo \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^utf8 body" msgtxt1 && grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1 ' test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' ' clean_fake_sendmail && - GIT_EDITOR="\"$(pwd)/fake-editor\"" \ - git send-email \ - --compose-encoding iso-8859-2 \ - --compose --subject utf8-sübjëct \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - $patches && + GIT_EDITOR="\"$(pwd)/fake-editor\"" \ + git send-email \ + --compose-encoding iso-8859-2 \ + --compose --subject utf8-sübjëct \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches && grep "^fake edit" msgtxt1 && grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 ' test_expect_success $PREREQ 'detects ambiguous reference/file conflict' ' - echo master > master && + echo master >master && git add master && git commit -m"add master" && test_must_fail git send-email --dry-run master 2>errors && @@@ -1045,10 -1057,10 +1052,10 @@@ test_expect_success $PREREQ 'feed two f rm -fr outdir && git format-patch -2 -o outdir && git send-email \ - --dry-run \ - --from="Example " \ - --to=nobody@example.com \ - outdir/000?-*.patch 2>errors >out && + --dry-run \ + --from="Example " \ + --to=nobody@example.com \ + outdir/000?-*.patch 2>errors >out && grep "^Subject: " out >subjects && test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." && test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master" @@@ -1192,7 -1204,7 +1199,7 @@@ test_expect_success $PREREQ 'To header ' test_expect_success $PREREQ 'setup expect' ' -cat >email-using-8bit <email-using-8bit <<\EOF From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 Message-Id: From: author@example.com @@@ -1204,7 -1216,9 +1211,7 @@@ EO ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <expected ' test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' ' @@@ -1219,11 -1233,11 +1226,11 @@@ ' test_expect_success $PREREQ 'setup expect' ' -cat >content-type-decl <content-type-decl <<-\EOF + MIME-Version: 1.0 + Content-Type: text/plain; charset=UTF-8 + Content-Transfer-Encoding: 8bit + EOF ' test_expect_success $PREREQ 'asks about and fixes 8bit encodings' ' @@@ -1263,21 -1277,21 +1270,21 @@@ test_expect_success $PREREQ '--8bit-enc ' test_expect_success $PREREQ 'setup expect' ' -cat >email-using-8bit < -From: author@example.com -Date: Sat, 12 Jun 2010 15:53:58 +0200 -Subject: Dieser Betreff enthält auch einen Umlaut! - -Nothing to see here. -EOF + cat >email-using-8bit <<-\EOF + From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001 + Message-Id: + From: author@example.com + Date: Sat, 12 Jun 2010 15:53:58 +0200 + Subject: Dieser Betreff enthält auch einen Umlaut! + + Nothing to see here. + EOF ' test_expect_success $PREREQ 'setup expect' ' -cat >expected <expected <<-\EOF + Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?= + EOF ' test_expect_success $PREREQ '--8bit-encoding also treats subject' ' @@@ -1291,163 -1305,6 +1298,163 @@@ 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: + From: A U Thor + 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: + From: A U Thor + 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 < +From: A U Thor +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 # want to make sure it works even if the cover-letter is not in the # first mail. @@@ -1456,13 -1313,13 +1463,13 @@@ test_expect_success $PREREQ 'refusing t rm -fr outdir && git format-patch --cover-letter -2 -o outdir && test_must_fail git send-email \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0002-*.patch \ - outdir/0000-*.patch \ - outdir/0001-*.patch \ - 2>errors >out && + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0002-*.patch \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + 2>errors >out && grep "SUBJECT HERE" errors && test -z "$(ls msgtxt*)" ' @@@ -1472,74 -1329,29 +1479,74 @@@ test_expect_success $PREREQ '--force se rm -fr outdir && git format-patch --cover-letter -2 -o outdir && git send-email \ - --force \ - --from="Example " \ - --to=nobody@example.com \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0002-*.patch \ - outdir/0000-*.patch \ - outdir/0001-*.patch \ - 2>errors >out && + --force \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0002-*.patch \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + 2>errors >out && ! grep "SUBJECT HERE" errors && test -n "$(ls msgtxt*)" ' +test_cover_addresses () { + header="$1" + shift + clean_fake_sendmail && + rm -fr outdir && + git format-patch --cover-letter -2 -o outdir && + cover=`echo outdir/0000-*.patch` && + mv $cover cover-to-edit.patch && + perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" && + git send-email \ + --force \ + --from="Example " \ + --no-to --no-cc \ + "$@" \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0000-*.patch \ + outdir/0001-*.patch \ + outdir/0002-*.patch \ + 2>errors >out && + grep "^$header: extra@address.com" msgtxt1 >to1 && + grep "^$header: extra@address.com" msgtxt2 >to2 && + grep "^$header: extra@address.com" msgtxt3 >to3 && + test_line_count = 1 to1 && + test_line_count = 1 to2 && + test_line_count = 1 to3 +} + +test_expect_success $PREREQ 'to-cover adds To to all mail' ' + test_cover_addresses "To" --to-cover +' + +test_expect_success $PREREQ 'cc-cover adds Cc to all mail' ' + test_cover_addresses "Cc" --cc-cover +' + +test_expect_success $PREREQ 'tocover adds To to all mail' ' + test_config sendemail.tocover true && + test_cover_addresses "To" +' + +test_expect_success $PREREQ 'cccover adds Cc to all mail' ' + test_config sendemail.cccover true && + test_cover_addresses "Cc" +' + test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' ' clean_fake_sendmail && echo "alias sbd somebody@example.org" >.mailrc && git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" && git config sendemail.aliasfiletype mailrc && git send-email \ - --from="Example " \ - --to=sbd \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0001-*.patch \ - 2>errors >out && + --from="Example " \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && grep "^!somebody@example\.org!$" commandline1 ' @@@ -1549,11 -1361,11 +1556,11 @@@ test_expect_success $PREREQ 'sendemail. git config --replace-all sendemail.aliasesfile "~/.mailrc" && git config sendemail.aliasfiletype mailrc && git send-email \ - --from="Example " \ - --to=sbd \ - --smtp-server="$(pwd)/fake.sendmail" \ - outdir/0001-*.patch \ - 2>errors >out && + --from="Example " \ + --to=sbd \ + --smtp-server="$(pwd)/fake.sendmail" \ + outdir/0001-*.patch \ + 2>errors >out && grep "^!someone@example\.org!$" commandline1 '