Merge branch 'mt/send-email-cc-match-fix'
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Jun 2013 21:29:57 +0000 (14:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Jun 2013 21:29:57 +0000 (14:29 -0700)
Logic used by git-send-email to suppress cc mishandled names that
need RFC2047 quoting.

* mt/send-email-cc-match-fix:
send-email: sanitize author when writing From line
send-email: add test for duplicate utf8 name

1  2 
git-send-email.perl
t/t9001-send-email.sh
diff --combined git-send-email.perl
index 671762b93031e66cba2ca837ddf71ed765f7a204,548c75d69aa9214e336c9a916a810c46a6a1f678..ecbf56f693f7049fd87267ec1830f9020e60e720
@@@ -54,7 -54,7 +54,7 @@@ git send-email [options] <file | direct
      --[no-]bcc              <str>  * Email Bcc:
      --subject               <str>  * Email "Subject:"
      --in-reply-to           <str>  * Email "In-Reply-To:"
 -    --annotate                     * Review each patch that will be sent in an editor.
 +    --[no-]annotate                * Review each patch that will be sent in an editor.
      --compose                      * Open an editor for introduction.
      --compose-encoding      <str>  * Encoding to assume for introduction.
      --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
@@@ -203,15 -203,16 +203,15 @@@ my ($compose_encoding)
  
  my ($debug_net_smtp) = 0;             # Net::SMTP, see send_message()
  
 -my $not_set_by_user = "true but not set by the user";
 -
  my %config_bool_settings = (
      "thread" => [\$thread, 1],
 -    "chainreplyto" => [\$chain_reply_to, $not_set_by_user],
 +    "chainreplyto" => [\$chain_reply_to, 0],
      "suppressfrom" => [\$suppress_from, undef],
      "signedoffbycc" => [\$signed_off_by_cc, undef],
      "signedoffcc" => [\$signed_off_by_cc, undef],      # Deprecated
      "validate" => [\$validate, 1],
 -    "multiedit" => [\$multiedit, undef]
 +    "multiedit" => [\$multiedit, undef],
 +    "annotate" => [\$annotate, undef]
  );
  
  my %config_settings = (
@@@ -239,6 -240,19 +239,6 @@@ my %config_path_settings = 
      "aliasesfile" => \@alias_files,
  );
  
 -# Help users prepare for 1.7.0
 -sub chain_reply_to {
 -      if (defined $chain_reply_to &&
 -          $chain_reply_to eq $not_set_by_user) {
 -              print STDERR
 -                  "In git 1.7.0, the default has changed to --no-chain-reply-to\n" .
 -                  "Set sendemail.chainreplyto configuration variable to true if\n" .
 -                  "you want to keep --chain-reply-to as your default.\n";
 -              $chain_reply_to = 0;
 -      }
 -      return $chain_reply_to;
 -}
 -
  # Handle Uncouth Termination
  sub signal_handler {
  
@@@ -290,7 -304,7 +290,7 @@@ my $rc = GetOptions("h" => \$help
                    "smtp-debug:i" => \$debug_net_smtp,
                    "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
 -                  "annotate" => \$annotate,
 +                  "annotate!" => \$annotate,
                    "compose" => \$compose,
                    "quiet" => \$quiet,
                    "cc-cmd=s" => \$cc_cmd,
@@@ -1038,47 -1052,6 +1038,47 @@@ sub maildomain 
        return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
  }
  
 +sub smtp_host_string {
 +      if (defined $smtp_server_port) {
 +              return "$smtp_server:$smtp_server_port";
 +      } else {
 +              return $smtp_server;
 +      }
 +}
 +
 +# Returns 1 if authentication succeeded or was not necessary
 +# (smtp_user was not specified), and 0 otherwise.
 +
 +sub smtp_auth_maybe {
 +      if (!defined $smtp_authuser || $auth) {
 +              return 1;
 +      }
 +
 +      # Workaround AUTH PLAIN/LOGIN interaction defect
 +      # with Authen::SASL::Cyrus
 +      eval {
 +              require Authen::SASL;
 +              Authen::SASL->import(qw(Perl));
 +      };
 +
 +      # TODO: Authentication may fail not because credentials were
 +      # invalid but due to other reasons, in which we should not
 +      # reject credentials.
 +      $auth = Git::credential({
 +              'protocol' => 'smtp',
 +              'host' => smtp_host_string(),
 +              'username' => $smtp_authuser,
 +              # if there's no password, "git credential fill" will
 +              # give us one, otherwise it'll just pass this one.
 +              'password' => $smtp_authpass
 +      }, sub {
 +              my $cred = shift;
 +              return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
 +      });
 +
 +      return $auth;
 +}
 +
  # Returns 1 if the message was sent, and 0 otherwise.
  # In actuality, the whole program dies when there
  # is an error sending a message.
@@@ -1188,7 -1161,9 +1188,7 @@@ X-Mailer: git-send-email $gitversio
                else {
                        require Net::SMTP;
                        $smtp_domain ||= maildomain();
 -                      $smtp ||= Net::SMTP->new((defined $smtp_server_port)
 -                                               ? "$smtp_server:$smtp_server_port"
 -                                               : $smtp_server,
 +                      $smtp ||= Net::SMTP->new(smtp_host_string(),
                                                 Hello => $smtp_domain,
                                                 Debug => $debug_net_smtp);
                        if ($smtp_encryption eq 'tls' && $smtp) {
                            defined $smtp_server_port ? " port=$smtp_server_port" : "";
                }
  
 -              if (defined $smtp_authuser) {
 -                      # Workaround AUTH PLAIN/LOGIN interaction defect
 -                      # with Authen::SASL::Cyrus
 -                      eval {
 -                              require Authen::SASL;
 -                              Authen::SASL->import(qw(Perl));
 -                      };
 -
 -                      if (!defined $smtp_authpass) {
 -
 -                              system "stty -echo";
 -
 -                              do {
 -                                      print "Password: ";
 -                                      $_ = <STDIN>;
 -                                      print "\n";
 -                              } while (!defined $_);
 -
 -                              chomp($smtp_authpass = $_);
 -
 -                              system "stty echo";
 -                      }
 -
 -                      $auth ||= $smtp->auth( $smtp_authuser, $smtp_authpass ) or die $smtp->message;
 -              }
 +              smtp_auth_maybe or die $smtp->message;
  
                $smtp->mail( $raw_from ) or die $smtp->message;
                $smtp->to( @recipients ) or die $smtp->message;
@@@ -1259,6 -1258,7 +1259,7 @@@ foreach my $t (@files) 
        open my $fh, "<", $t or die "can't open file $t";
  
        my $author = undef;
+       my $sauthor = undef;
        my $author_encoding;
        my $has_content_type;
        my $body_encoding;
                        }
                        elsif (/^From:\s+(.*)$/i) {
                                ($author, $author_encoding) = unquote_rfc2047($1);
-                               my $sauthor = sanitize_address($author);
+                               $sauthor = sanitize_address($author);
                                next if $suppress_cc{'author'};
                                next if $suppress_cc{'self'} and $sauthor eq $sender;
                                printf("(mbox) Adding cc: %s from line '%s'\n",
                $subject = quote_subject($subject, $auto_8bit_encoding);
        }
  
-       if (defined $author and $author ne $sender) {
+       if (defined $sauthor and $sauthor ne $sender) {
                $message = "From: $author\n\n$message";
                if (defined $author_encoding) {
                        if ($has_content_type) {
  
        # set up for the next message
        if ($thread && $message_was_sent &&
 -              (chain_reply_to() || !defined $reply_to || length($reply_to) == 0 ||
 +              ($chain_reply_to || !defined $reply_to || length($reply_to) == 0 ||
                $message_num == 1)) {
                $reply_to = $message_id;
                if (length $references > 0) {
diff --combined t/t9001-send-email.sh
index 9f46f22ca87be40e217c2ffb199368f0afbf9548,d6f0271866173be0fdaf6d1308b1027e882f9b30..2813aa9a61dc52d6d72f684c51fe6894e623754d
@@@ -956,6 -956,20 +956,20 @@@ test_expect_success $PREREQ 'utf8 autho
        grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
  '
  
+ test_expect_success $PREREQ 'utf8 sender is not duplicated' '
+       clean_fake_sendmail &&
+       test_commit weird_sender &&
+       test_when_finished "git reset --hard HEAD^" &&
+       git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
+       git format-patch --stdout -1 >funny_name.patch &&
+       git send-email --from="Füñný Nâmé <odd_?=mail@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         funny_name.patch &&
+       grep "^From: " msgtxt1 >msgfrom &&
+       test_line_count = 1 msgfrom
+ '
  test_expect_success $PREREQ 'sendemail.composeencoding works' '
        clean_fake_sendmail &&
        git config sendemail.composeencoding iso-8859-1 &&
@@@ -1078,6 -1092,55 +1092,6 @@@ test_expect_success $PREREQ 'threading 
        grep "In-Reply-To: " stdout
  '
  
 -test_expect_success $PREREQ 'warning with an implicit --chain-reply-to' '
 -      git send-email \
 -      --dry-run \
 -      --from="Example <nobody@example.com>" \
 -      --to=nobody@example.com \
 -      outdir/000?-*.patch 2>errors >out &&
 -      grep "no-chain-reply-to" errors
 -'
 -
 -test_expect_success $PREREQ 'no warning with an explicit --chain-reply-to' '
 -      git send-email \
 -      --dry-run \
 -      --from="Example <nobody@example.com>" \
 -      --to=nobody@example.com \
 -      --chain-reply-to \
 -      outdir/000?-*.patch 2>errors >out &&
 -      ! grep "no-chain-reply-to" errors
 -'
 -
 -test_expect_success $PREREQ 'no warning with an explicit --no-chain-reply-to' '
 -      git send-email \
 -      --dry-run \
 -      --from="Example <nobody@example.com>" \
 -      --to=nobody@example.com \
 -      --nochain-reply-to \
 -      outdir/000?-*.patch 2>errors >out &&
 -      ! grep "no-chain-reply-to" errors
 -'
 -
 -test_expect_success $PREREQ 'no warning with sendemail.chainreplyto = false' '
 -      git config sendemail.chainreplyto false &&
 -      git send-email \
 -      --dry-run \
 -      --from="Example <nobody@example.com>" \
 -      --to=nobody@example.com \
 -      outdir/000?-*.patch 2>errors >out &&
 -      ! grep "no-chain-reply-to" errors
 -'
 -
 -test_expect_success $PREREQ 'no warning with sendemail.chainreplyto = true' '
 -      git config sendemail.chainreplyto true &&
 -      git send-email \
 -      --dry-run \
 -      --from="Example <nobody@example.com>" \
 -      --to=nobody@example.com \
 -      outdir/000?-*.patch 2>errors >out &&
 -      ! grep "no-chain-reply-to" errors
 -'
 -
  test_expect_success $PREREQ 'sendemail.to works' '
        git config --replace-all sendemail.to "Somebody <somebody@ex.com>" &&
        git send-email \