]> git.ipfire.org Git - thirdparty/git.git/blobdiff - git-send-email.perl
Merge branch 'sb/send-email-use-to-from-input'
[thirdparty/git.git] / git-send-email.perl
index e1f29a72a10ff68c972b439749535d251bfd311c..f304ef913ecde17db0ad7ad4c57ad52028abc9a3 100755 (executable)
@@ -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,6 +16,7 @@
 #    and second line is the subject of the message.
 #
 
+use 5.008;
 use strict;
 use warnings;
 use Term::ReadLine;
@@ -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;
 
@@ -60,6 +62,7 @@ git send-email [options] <file | directory | rev-list options >
     --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.
@@ -70,6 +73,7 @@ git send-email [options] <file | directory | rev-list options >
 
   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.
@@ -85,6 +89,7 @@ git send-email [options] <file | directory | rev-list options >
     --[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);
@@ -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);
 
@@ -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;
@@ -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);
@@ -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,
-    "to" => \@to,
+    "smtpdomain" => \$smtp_domain,
+    "to" => \@initial_to,
+    "tocmd" => \$to_cmd,
     "cc" => \@initial_cc,
     "cccmd" => \$cc_cmd,
     "aliasfiletype" => \$aliasfiletype,
@@ -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,
@@ -279,6 +290,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
                    "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,
@@ -301,6 +313,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
                    "validate!" => \$validate,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
+                   "force" => \$force,
         );
 
 unless ($rc) {
@@ -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/,/;
 }
 
@@ -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)) {
@@ -702,6 +715,16 @@ if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
                                  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 || '';
@@ -711,9 +734,9 @@ if (!defined $sender) {
        $prompting++;
 }
 
-if (!@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++;
 }
 
@@ -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);
 
@@ -1015,6 +1038,8 @@ X-Mailer: git-send-email $gitversion
                }
        }
 
+       unshift (@sendmail_parameters, @smtp_server_options);
+
        if ($dry_run) {
                # We don't want to send the email.
        } elsif ($smtp_server =~ m#^/#) {
@@ -1136,6 +1161,7 @@ foreach my $t (@files) {
        my $author_encoding;
        my $has_content_type;
        my $body_encoding;
+       @to = ();
        @cc = ();
        @xh = ();
        my $input_format = undef;
@@ -1176,6 +1202,13 @@ foreach my $t (@files) {
                                        $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) {
@@ -1238,21 +1271,10 @@ foreach my $t (@files) {
        }
        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;
@@ -1293,6 +1315,7 @@ foreach my $t (@files) {
                ($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();
@@ -1310,6 +1333,30 @@ foreach my $t (@files) {
        $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() {