]> asedeno.scripts.mit.edu Git - git.git/commitdiff
Merge branch 'sb/send-email-use-to-from-input'
authorJunio C Hamano <gitster@pobox.com>
Wed, 27 Oct 2010 05:02:03 +0000 (22:02 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 27 Oct 2010 05:02:03 +0000 (22:02 -0700)
* sb/send-email-use-to-from-input:
  send-email: Don't leak To: headers between patches
  send-email: Use To: headers in patch files

Conflicts:
git-send-email.perl

1  2 
git-send-email.perl
t/t9001-send-email.sh

diff --combined git-send-email.perl
index 196efcd5e42a0a61726f26d471cb88fed19aec13,7f9eacd16c0b195fab058dbe4215cf35b43d2465..f304ef913ecde17db0ad7ad4c57ad52028abc9a3
@@@ -1,4 -1,4 +1,4 @@@
 -#!/usr/bin/perl -w
 +#!/usr/bin/perl
  #
  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>
  # Copyright 2005 Ryan Anderson <ryan@michonline.com>
@@@ -16,7 -16,6 +16,7 @@@
  #    and second line is the subject of the message.
  #
  
 +use 5.008;
  use strict;
  use warnings;
  use Term::ReadLine;
@@@ -25,7 -24,6 +25,7 @@@ use Text::ParseWords
  use Data::Dumper;
  use Term::ANSIColor;
  use File::Temp qw/ tempdir tempfile /;
 +use File::Spec::Functions qw(catfile);
  use Error qw(:try);
  use Git;
  
@@@ -62,7 -60,6 +62,7 @@@ git send-email [options] <file | direct
      --envelope-sender       <str>  * Email envelope sender.
      --smtp-server       <str:int>  * Outgoing SMTP server to use. The port
                                       is optional. Default 'localhost'.
 +    --smtp-server-option    <str>  * Outgoing SMTP server option to use.
      --smtp-server-port      <int>  * Outgoing SMTP server port.
      --smtp-user             <str>  * Username for SMTP-AUTH.
      --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
@@@ -73,7 -70,6 +73,7 @@@
  
    Automating:
      --identity              <str>  * Use the sendemail.<id> options.
 +    --to-cmd                <str>  * Email To: via `<str> \$patch_path`
      --cc-cmd                <str>  * Email Cc: via `<str> \$patch_path`
      --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, all.
      --[no-]signed-off-by-cc        * Send to Signed-off-by: addresses. Default on.
@@@ -89,7 -85,6 +89,7 @@@
      --[no-]validate                * Perform patch sanity checks. Default on.
      --[no-]format-patch            * understand any non optional arguments as
                                       `git format-patch` ones.
 +    --force                        * Send even if safety checks would prevent it.
  
  EOT
        exit(1);
@@@ -143,7 -138,7 +143,7 @@@ sub unique_email_list(@)
  sub cleanup_compose_files();
  
  # Variables we fill in automatically, or via prompting:
- my (@to,$no_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
+ my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
        $initial_reply_to,$initial_subject,@files,
        $author,$sender,$smtp_authpass,$annotate,$compose,$time);
  
@@@ -167,7 -162,6 +167,7 @@@ if ($@) 
  my ($quiet, $dry_run) = (0, 0);
  my $format_patch;
  my $compose_filename;
 +my $force = 0;
  
  # Handle interactive edition of files.
  my $multiedit;
@@@ -193,11 -187,9 +193,11 @@@ sub do_edit 
  }
  
  # Variables with corresponding config settings
 -my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
 -my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
 -my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts, $smtp_domain);
 +my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc);
 +my ($to_cmd, $cc_cmd);
 +my ($smtp_server, $smtp_server_port, @smtp_server_options);
 +my ($smtp_authuser, $smtp_encryption);
 +my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
  my ($validate, $confirm);
  my (@suppress_cc);
  my ($auto_8bit_encoding);
@@@ -218,12 -210,10 +218,12 @@@ my %config_bool_settings = 
  my %config_settings = (
      "smtpserver" => \$smtp_server,
      "smtpserverport" => \$smtp_server_port,
 +    "smtpserveroption" => \@smtp_server_options,
      "smtpuser" => \$smtp_authuser,
      "smtppass" => \$smtp_authpass,
 -      "smtpdomain" => \$smtp_domain,
 +    "smtpdomain" => \$smtp_domain,
-     "to" => \@to,
+     "to" => \@initial_to,
 +    "tocmd" => \$to_cmd,
      "cc" => \@initial_cc,
      "cccmd" => \$cc_cmd,
      "aliasfiletype" => \$aliasfiletype,
@@@ -281,8 -271,7 +281,8 @@@ $SIG{INT}  = \&signal_handler
  my $rc = GetOptions("sender|from=s" => \$sender,
                      "in-reply-to=s" => \$initial_reply_to,
                    "subject=s" => \$initial_subject,
-                   "to=s" => \@to,
+                   "to=s" => \@initial_to,
 +                  "to-cmd=s" => \$to_cmd,
                    "no-to" => \$no_to,
                    "cc=s" => \@initial_cc,
                    "no-cc" => \$no_cc,
                    "no-bcc" => \$no_bcc,
                    "chain-reply-to!" => \$chain_reply_to,
                    "smtp-server=s" => \$smtp_server,
 +                  "smtp-server-option=s" => \@smtp_server_options,
                    "smtp-server-port=s" => \$smtp_server_port,
                    "smtp-user=s" => \$smtp_authuser,
                    "smtp-pass:s" => \$smtp_authpass,
                    "validate!" => \$validate,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
 +                  "force" => \$force,
         );
  
  unless ($rc) {
@@@ -422,7 -409,7 +422,7 @@@ my ($repoauthor, $repocommitter)
  
  # Verify the user input
  
- foreach my $entry (@to) {
+ foreach my $entry (@initial_to) {
        die "Comma in --to entry: $entry'\n" unless $entry !~ m/,/;
  }
  
@@@ -524,7 -511,7 +524,7 @@@ while (defined(my $f = shift @ARGV)) 
                opendir(DH,$f)
                        or die "Failed to opendir $f: $!";
  
 -              push @files, grep { -f $_ } map { +$f . "/" . $_ }
 +              push @files, grep { -f $_ } map { catfile($f, $_) }
                                sort readdir(DH);
                closedir(DH);
        } elsif ((-f $f or -p $f) and !check_file_rev_conflict($f)) {
@@@ -715,16 -702,6 +715,16 @@@ if (!defined $auto_8bit_encoding && sca
                                  default => "UTF-8");
  }
  
 +if (!$force) {
 +      for my $f (@files) {
 +              if (get_patch_subject($f) =~ /\*\*\* SUBJECT HERE \*\*\*/) {
 +                      die "Refusing to send because the patch\n\t$f\n"
 +                              . "has the template subject '*** SUBJECT HERE ***'. "
 +                              . "Pass --force if you really want to send.\n";
 +              }
 +      }
 +}
 +
  my $prompting = 0;
  if (!defined $sender) {
        $sender = $repoauthor || $repocommitter || '';
        $prompting++;
  }
  
- if (!@to && !defined $to_cmd) {
 -if (!@initial_to) {
++if (!@initial_to && !defined $to_cmd) {
        my $to = ask("Who should the emails be sent to? ");
-       push @to, parse_address_line($to) if defined $to; # sanitized/validated later
+       push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
        $prompting++;
  }
  
@@@ -754,8 -731,8 +754,8 @@@ sub expand_one_alias 
        return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
  }
  
- @to = expand_aliases(@to);
- @to = (map { sanitize_address($_) } @to);
+ @initial_to = expand_aliases(@initial_to);
+ @initial_to = (map { sanitize_address($_) } @initial_to);
  @initial_cc = expand_aliases(@initial_cc);
  @bcclist = expand_aliases(@bcclist);
  
@@@ -1038,8 -1015,6 +1038,8 @@@ X-Mailer: git-send-email $gitversio
                }
        }
  
 +      unshift (@sendmail_parameters, @smtp_server_options);
 +
        if ($dry_run) {
                # We don't want to send the email.
        } elsif ($smtp_server =~ m#^/#) {
@@@ -1161,6 -1136,7 +1161,7 @@@ foreach my $t (@files) 
        my $author_encoding;
        my $has_content_type;
        my $body_encoding;
+       @to = ();
        @cc = ();
        @xh = ();
        my $input_format = undef;
                                        $1, $_) unless $quiet;
                                push @cc, $1;
                        }
+                       elsif (/^To:\s+(.*)$/) {
+                               foreach my $addr (parse_address_line($1)) {
+                                       printf("(mbox) Adding to: %s from line '%s'\n",
+                                               $addr, $_) unless $quiet;
+                                       push @to, sanitize_address($addr);
+                               }
+                       }
                        elsif (/^Cc:\s+(.*)$/) {
                                foreach my $addr (parse_address_line($1)) {
                                        if (unquote_rfc2047($addr) eq $sender) {
        }
        close F;
  
 -      if (defined $cc_cmd && !$suppress_cc{'cccmd'}) {
 -              open(F, "$cc_cmd \Q$t\E |")
 -                      or die "(cc-cmd) Could not execute '$cc_cmd'";
 -              while(<F>) {
 -                      my $c = $_;
 -                      $c =~ s/^\s*//g;
 -                      $c =~ s/\n$//g;
 -                      next if ($c eq $sender and $suppress_from);
 -                      push @cc, $c;
 -                      printf("(cc-cmd) Adding cc: %s from: '%s'\n",
 -                              $c, $cc_cmd) unless $quiet;
 -              }
 -              close F
 -                      or die "(cc-cmd) failed to close pipe to '$cc_cmd'";
 -      }
 +      push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
 +              if defined $to_cmd;
 +      push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
 +              if defined $cc_cmd && !$suppress_cc{'cccmd'};
  
        if ($broken_encoding{$t} && !$has_content_type) {
                $has_content_type = 1;
                ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
        $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
  
+       @to = (@initial_to, @to);
        @cc = (@initial_cc, @cc);
  
        my $message_was_sent = send_message();
        $message_id = undef;
  }
  
 +# Execute a command (e.g. $to_cmd) to get a list of email addresses
 +# and return a results array
 +sub recipients_cmd {
 +      my ($prefix, $what, $cmd, $file) = @_;
 +
 +      my $sanitized_sender = sanitize_address($sender);
 +      my @addresses = ();
 +      open(F, "$cmd \Q$file\E |")
 +          or die "($prefix) Could not execute '$cmd'";
 +      while(<F>) {
 +              my $address = $_;
 +              $address =~ s/^\s*//g;
 +              $address =~ s/\s*$//g;
 +              $address = sanitize_address($address);
 +              next if ($address eq $sanitized_sender and $suppress_from);
 +              push @addresses, $address;
 +              printf("($prefix) Adding %s: %s from: '%s'\n",
 +                     $what, $address, $cmd) unless $quiet;
 +              }
 +      close F
 +          or die "($prefix) failed to close pipe to '$cmd'";
 +      return @addresses;
 +}
 +
  cleanup_compose_files();
  
  sub cleanup_compose_files() {
diff --combined t/t9001-send-email.sh
index ba11c00c74468f996ba718b2c07dd1852c21d30d,13d8d1a8b4f70fa7813c7aff42ca040b9da3c8bb..028758c6522f4b9668261bce5b7769da29c7812c
@@@ -201,24 -201,6 +201,24 @@@ test_expect_success $PREREQ 'Prompting 
                grep "^To: to@example.com\$" msgtxt1
  '
  
 +test_expect_success $PREREQ 'tocmd works' '
 +      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 &&
 +      git send-email \
 +              --from="Example <nobody@example.com>" \
 +              --to-cmd=./tocmd-sed \
 +              --smtp-server="$(pwd)/fake.sendmail" \
 +              tocmd.patch \
 +              &&
 +      grep "^To: tocmd@example.com" msgtxt1
 +'
 +
  test_expect_success $PREREQ 'cccmd works' '
        clean_fake_sendmail &&
        cp $patches cccmd.patch &&
@@@ -297,7 -279,7 +297,7 @@@ test_expect_success $PREREQ 'Invalid In
                --to=nobody@example.com \
                --in-reply-to=" " \
                --smtp-server="$(pwd)/fake.sendmail" \
 -              $patches
 +              $patches \
                2>errors
        ! grep "^In-Reply-To: < *>" msgtxt1
  '
@@@ -965,6 -947,45 +965,45 @@@ test_expect_success $PREREQ '--no-bcc o
        ! grep "RCPT TO:<other@ex.com>" stdout
  '
  
+ test_expect_success $PREREQ 'patches To headers are used by default' '
+       patch=`git format-patch -1 --to="bodies@example.com"` &&
+       test_when_finished "rm $patch" &&
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --smtp-server relay.example.com \
+               $patch >stdout &&
+       grep "RCPT TO:<bodies@example.com>" stdout
+ '
+ test_expect_success $PREREQ 'patches To headers are appended to' '
+       patch=`git format-patch -1 --to="bodies@example.com"` &&
+       test_when_finished "rm $patch" &&
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server relay.example.com \
+               $patch >stdout &&
+       grep "RCPT TO:<bodies@example.com>" stdout &&
+       grep "RCPT TO:<nobody@example.com>" stdout
+ '
+ test_expect_success $PREREQ 'To headers from files reset each patch' '
+       patch1=`git format-patch -1 --to="bodies@example.com"` &&
+       patch2=`git format-patch -1 --to="other@example.com" HEAD~` &&
+       test_when_finished "rm $patch1 && rm $patch2" &&
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to="nobody@example.com" \
+               --smtp-server relay.example.com \
+               $patch1 $patch2 >stdout &&
+       test $(grep -c "RCPT TO:<bodies@example.com>" stdout) = 1 &&
+       test $(grep -c "RCPT TO:<nobody@example.com>" stdout) = 2 &&
+       test $(grep -c "RCPT TO:<other@example.com>" stdout) = 1
+ '
  test_expect_success $PREREQ 'setup expect' '
  cat >email-using-8bit <<EOF
  From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
@@@ -1050,40 -1071,4 +1089,40 @@@ test_expect_success $PREREQ '--8bit-enc
        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.
 +test_expect_success 'refusing to send cover letter template' '
 +      clean_fake_sendmail &&
 +      rm -fr outdir &&
 +      git format-patch --cover-letter -2 -o outdir &&
 +      test_must_fail git send-email \
 +        --from="Example <nobody@example.com>" \
 +        --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*)"
 +'
 +
 +test_expect_success '--force sends cover letter template anyway' '
 +      clean_fake_sendmail &&
 +      rm -fr outdir &&
 +      git format-patch --cover-letter -2 -o outdir &&
 +      git send-email \
 +        --force \
 +        --from="Example <nobody@example.com>" \
 +        --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_done