Merge branch 'ab/require-perl-5.8'
[gitweb.git] / git-send-email.perl
index d10d869912c187868018e5a7b9d97bad51073b64..196efcd5e42a0a61726f26d471cb88fed19aec13 100755 (executable)
@@ -25,6 +25,7 @@
 use Data::Dumper;
 use Term::ANSIColor;
 use File::Temp qw/ tempdir tempfile /;
+use File::Spec::Functions qw(catfile);
 use Error qw(:try);
 use Git;
 
@@ -61,6 +62,7 @@ sub usage {
     --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.
@@ -71,6 +73,7 @@ sub usage {
 
   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.
@@ -86,6 +89,7 @@ sub usage {
     --[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);
@@ -163,6 +167,7 @@ sub format_2822_time {
 my ($quiet, $dry_run) = (0, 0);
 my $format_patch;
 my $compose_filename;
+my $force = 0;
 
 # Handle interactive edition of files.
 my $multiedit;
@@ -188,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);
@@ -211,10 +218,12 @@ sub do_edit {
 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,
+    "tocmd" => \$to_cmd,
     "cc" => \@initial_cc,
     "cccmd" => \$cc_cmd,
     "aliasfiletype" => \$aliasfiletype,
@@ -273,6 +282,7 @@ sub signal_handler {
                     "in-reply-to=s" => \$initial_reply_to,
                    "subject=s" => \$initial_subject,
                    "to=s" => \@to,
+                   "to-cmd=s" => \$to_cmd,
                    "no-to" => \$no_to,
                    "cc=s" => \@initial_cc,
                    "no-cc" => \$no_cc,
@@ -280,6 +290,7 @@ sub signal_handler {
                    "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,
@@ -302,6 +313,7 @@ sub signal_handler {
                    "validate!" => \$validate,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
+                   "force" => \$force,
         );
 
 unless ($rc) {
@@ -512,7 +524,7 @@ ($)
                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)) {
@@ -703,6 +715,16 @@ ($)
                                  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 || '';
@@ -712,7 +734,7 @@ ($)
        $prompting++;
 }
 
-if (!@to) {
+if (!@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
        $prompting++;
@@ -896,7 +918,7 @@ sub sanitize_address {
 
 sub valid_fqdn {
        my $domain = shift;
-       return !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
+       return defined $domain && !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
 }
 
 sub maildomain_net {
@@ -1016,6 +1038,8 @@ sub send_message {
                }
        }
 
+       unshift (@sendmail_parameters, @smtp_server_options);
+
        if ($dry_run) {
                # We don't want to send the email.
        } elsif ($smtp_server =~ m#^/#) {
@@ -1239,21 +1263,10 @@ sub send_message {
        }
        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;
@@ -1311,6 +1324,30 @@ sub 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() {