Use "git merge" instead of "git pull ."
[gitweb.git] / git-send-email.perl
index bd13cc812d2a0115edcdd2c3ec146665ddfc5e29..2162478392728f156ba6c541cdc69447aa9b0119 100755 (executable)
@@ -69,6 +69,9 @@ sub usage {
     --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
     --smtp-encryption       <str>  * tls or ssl; anything else disables.
     --smtp-ssl                     * Deprecated. Use '--smtp-encryption ssl'.
+    --smtp-ssl-cert-path    <str>  * Path to ca-certificates (either directory or file).
+                                     Pass an empty string to disable certificate
+                                     verification.
     --smtp-domain           <str>  * The domain name sent to HELO/EHLO handshake
     --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.
 
@@ -194,7 +197,7 @@ sub do_edit {
 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 ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
 my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
 my ($validate, $confirm);
 my (@suppress_cc);
@@ -203,11 +206,9 @@ sub do_edit {
 
 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
@@ -222,6 +223,7 @@ sub do_edit {
     "smtpserveroption" => \@smtp_server_options,
     "smtpuser" => \$smtp_authuser,
     "smtppass" => \$smtp_authpass,
+    "smtpsslcertpath" => \$smtp_ssl_cert_path,
     "smtpdomain" => \$smtp_domain,
     "to" => \@initial_to,
     "tocmd" => \$to_cmd,
@@ -241,19 +243,6 @@ sub do_edit {
     "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 {
 
@@ -302,6 +291,7 @@ sub signal_handler {
                    "smtp-pass:s" => \$smtp_authpass,
                    "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
                    "smtp-encryption=s" => \$smtp_encryption,
+                   "smtp-ssl-cert-path" => \$smtp_ssl_cert_path,
                    "smtp-debug:i" => \$debug_net_smtp,
                    "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
@@ -760,6 +750,11 @@ sub file_declares_8bit_cte {
        $sender = $repoauthor || $repocommitter || '';
 }
 
+# $sender could be an already sanitized address
+# (e.g. sendemail.from could be manually sanitized by user).
+# But it's a no-op to run sanitize_address on an already sanitized address.
+$sender = sanitize_address($sender);
+
 my $prompting = 0;
 if (!@initial_to && !defined $to_cmd) {
        my $to = ask("Who should the emails be sent to (if any)? ",
@@ -1089,6 +1084,34 @@ sub smtp_auth_maybe {
        return $auth;
 }
 
+sub ssl_verify_params {
+       eval {
+               require IO::Socket::SSL;
+               IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
+       };
+       if ($@) {
+               print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
+               return;
+       }
+
+       if (!defined $smtp_ssl_cert_path) {
+               $smtp_ssl_cert_path = "/etc/ssl/certs";
+       }
+
+       if ($smtp_ssl_cert_path eq "") {
+               return (SSL_verify_mode => SSL_VERIFY_NONE());
+       } elsif (-d $smtp_ssl_cert_path) {
+               return (SSL_verify_mode => SSL_VERIFY_PEER(),
+                       SSL_ca_path => $smtp_ssl_cert_path);
+       } elsif (-f $smtp_ssl_cert_path) {
+               return (SSL_verify_mode => SSL_VERIFY_PEER(),
+                       SSL_ca_file => $smtp_ssl_cert_path);
+       } else {
+               print STDERR "Not using SSL_VERIFY_PEER because the CA path does not exist.\n";
+               return (SSL_verify_mode => SSL_VERIFY_NONE());
+       }
+}
+
 # Returns 1 if the message was sent, and 0 otherwise.
 # In actuality, the whole program dies when there
 # is an error sending a message.
@@ -1113,10 +1136,9 @@ sub send_message {
        if ($cc ne '') {
                $ccline = "\nCc: $cc";
        }
-       my $sanitized_sender = sanitize_address($sender);
        make_message_id() unless defined($message_id);
 
-       my $header = "From: $sanitized_sender
+       my $header = "From: $sender
 To: $to${ccline}
 Subject: $subject
 Date: $date
@@ -1133,7 +1155,7 @@ sub send_message {
        }
 
        my @sendmail_parameters = ('-i', @recipients);
-       my $raw_from = $sanitized_sender;
+       my $raw_from = $sender;
        if (defined $envelope_sender && $envelope_sender ne "auto") {
                $raw_from = $envelope_sender;
        }
@@ -1194,20 +1216,24 @@ sub send_message {
                        $smtp_domain ||= maildomain();
                        $smtp ||= Net::SMTP::SSL->new($smtp_server,
                                                      Hello => $smtp_domain,
-                                                     Port => $smtp_server_port);
+                                                     Port => $smtp_server_port,
+                                                     ssl_verify_params());
                }
                else {
                        require Net::SMTP;
                        $smtp_domain ||= maildomain();
-                       $smtp ||= Net::SMTP->new(smtp_host_string(),
+                       $smtp_server_port ||= 25;
+                       $smtp ||= Net::SMTP->new($smtp_server,
                                                 Hello => $smtp_domain,
-                                                Debug => $debug_net_smtp);
+                                                Debug => $debug_net_smtp,
+                                                Port => $smtp_server_port);
                        if ($smtp_encryption eq 'tls' && $smtp) {
                                require Net::SMTP::SSL;
                                $smtp->command('STARTTLS');
                                $smtp->response();
                                if ($smtp->code == 220) {
-                                       $smtp = Net::SMTP::SSL->start_SSL($smtp)
+                                       $smtp = Net::SMTP::SSL->start_SSL($smtp,
+                                                                         ssl_verify_params())
                                                or die "STARTTLS failed! ".$smtp->message;
                                        $smtp_encryption = '';
                                        # Send EHLO again to receive fresh
@@ -1270,6 +1296,7 @@ sub send_message {
        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;
@@ -1308,8 +1335,9 @@ sub send_message {
                        }
                        elsif (/^From:\s+(.*)$/i) {
                                ($author, $author_encoding) = unquote_rfc2047($1);
+                               $sauthor = sanitize_address($author);
                                next if $suppress_cc{'author'};
-                               next if $suppress_cc{'self'} and $author eq $sender;
+                               next if $suppress_cc{'self'} and $sauthor eq $sender;
                                printf("(mbox) Adding cc: %s from line '%s'\n",
                                        $1, $_) unless $quiet;
                                push @cc, $1;
@@ -1323,7 +1351,9 @@ sub send_message {
                        }
                        elsif (/^Cc:\s+(.*)$/i) {
                                foreach my $addr (parse_address_line($1)) {
-                                       if (unquote_rfc2047($addr) eq $sender) {
+                                       my $qaddr = unquote_rfc2047($addr);
+                                       my $saddr = sanitize_address($qaddr);
+                                       if ($saddr eq $sender) {
                                                next if ($suppress_cc{'self'});
                                        } else {
                                                next if ($suppress_cc{'cc'});
@@ -1370,7 +1400,8 @@ sub send_message {
                        chomp;
                        my ($what, $c) = ($1, $2);
                        chomp $c;
-                       if ($c eq $sender) {
+                       my $sc = sanitize_address($c);
+                       if ($sc eq $sender) {
                                next if ($suppress_cc{'self'});
                        } else {
                                next if $suppress_cc{'sob'} and $what =~ /Signed-off-by/i;
@@ -1400,7 +1431,7 @@ sub send_message {
                $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) {
@@ -1437,7 +1468,7 @@ sub send_message {
 
        # 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) {
@@ -1454,7 +1485,6 @@ sub send_message {
 sub recipients_cmd {
        my ($prefix, $what, $cmd, $file) = @_;
 
-       my $sanitized_sender = sanitize_address($sender);
        my @addresses = ();
        open my $fh, "-|", "$cmd \Q$file\E"
            or die "($prefix) Could not execute '$cmd'";
@@ -1462,7 +1492,7 @@ sub recipients_cmd {
                $address =~ s/^\s*//g;
                $address =~ s/\s*$//g;
                $address = sanitize_address($address);
-               next if ($address eq $sanitized_sender and $suppress_from);
+               next if ($address eq $sender and $suppress_cc{'self'});
                push @addresses, $address;
                printf("($prefix) Adding %s: %s from: '%s'\n",
                       $what, $address, $cmd) unless $quiet;