diff options
Diffstat (limited to 'git-send-email.perl')
-rwxr-xr-x | git-send-email.perl | 116 |
1 files changed, 86 insertions, 30 deletions
diff --git a/git-send-email.perl b/git-send-email.perl index 5bd689958e..435c7c9e26 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -25,10 +25,12 @@ use Getopt::Long; use Text::ParseWords; use Term::ANSIColor; use File::Temp qw/ tempdir tempfile /; -use File::Spec::Functions qw(catfile); -use Error qw(:try); +use File::Spec::Functions qw(catdir catfile); +use Git::Error qw(:try); +use Cwd qw(abs_path cwd); use Git; use Git::I18N; +use Git::Mail::Address; Getopt::Long::Configure qw/ pass_through /; @@ -154,7 +156,6 @@ sub format_2822_time { } my $have_email_valid = eval { require Email::Valid; 1 }; -my $have_mail_address = eval { require Mail::Address; 1 }; my $smtp; my $auth; my $num_sent = 0; @@ -493,11 +494,7 @@ my ($repoauthor, $repocommitter); ($repocommitter) = Git::ident_person(@repo, 'committer'); sub parse_address_line { - if ($have_mail_address) { - return map { $_->format } Mail::Address->parse($_[0]); - } else { - return Git::parse_mailboxes($_[0]); - } + return map { $_->format } Mail::Address->parse($_[0]); } sub split_addrs { @@ -893,7 +890,9 @@ if (defined $initial_reply_to) { } if (!defined $smtp_server) { - foreach (qw( /usr/sbin/sendmail /usr/lib/sendmail )) { + my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail ); + push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH}; + foreach (@sendmail_paths) { if (-x $_) { $smtp_server = $_; last; @@ -1092,6 +1091,26 @@ sub sanitize_address { } +sub strip_garbage_one_address { + my ($addr) = @_; + chomp $addr; + if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) { + # "Foo Bar" <foobar@example.com> [possibly garbage here] + # Foo Bar <foobar@example.com> [possibly garbage here] + return $1; + } + if ($addr =~ /^(<[^>]*>).*/) { + # <foo@example.com> [possibly garbage here] + # if garbage contains other addresses, they are ignored. + return $1; + } + if ($addr =~ /^([^"#,\s]*)/) { + # address without quoting: remove anything after the address + return $1; + } + return $addr; +} + sub sanitize_address_list { return (map { sanitize_address($_) } @_); } @@ -1367,10 +1386,12 @@ EOF die __("The required SMTP server is not properly defined.") } + require Net::SMTP; + my $use_net_smtp_ssl = version->parse($Net::SMTP::VERSION) < version->parse("2.34"); + $smtp_domain ||= maildomain(); + if ($smtp_encryption eq 'ssl') { $smtp_server_port ||= 465; # ssmtp - require Net::SMTP::SSL; - $smtp_domain ||= maildomain(); require IO::Socket::SSL; # Suppress "variable accessed once" warning. @@ -1382,34 +1403,48 @@ EOF # Net::SMTP::SSL->new() does not forward any SSL options IO::Socket::SSL::set_client_defaults( ssl_verify_params()); - $smtp ||= Net::SMTP::SSL->new($smtp_server, - Hello => $smtp_domain, - Port => $smtp_server_port, - Debug => $debug_net_smtp); + + if ($use_net_smtp_ssl) { + require Net::SMTP::SSL; + $smtp ||= Net::SMTP::SSL->new($smtp_server, + Hello => $smtp_domain, + Port => $smtp_server_port, + Debug => $debug_net_smtp); + } + else { + $smtp ||= Net::SMTP->new($smtp_server, + Hello => $smtp_domain, + Port => $smtp_server_port, + Debug => $debug_net_smtp, + SSL => 1); + } } else { - require Net::SMTP; - $smtp_domain ||= maildomain(); $smtp_server_port ||= 25; $smtp ||= Net::SMTP->new($smtp_server, Hello => $smtp_domain, 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) { + if ($use_net_smtp_ssl) { + $smtp->command('STARTTLS'); + $smtp->response(); + if ($smtp->code != 220) { + die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message); + } + require Net::SMTP::SSL; $smtp = Net::SMTP::SSL->start_SSL($smtp, ssl_verify_params()) - or die "STARTTLS failed! ".IO::Socket::SSL::errstr(); - $smtp_encryption = ''; - # Send EHLO again to receive fresh - # supported commands - $smtp->hello($smtp_domain); - } else { - die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message); + or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr()); + } + else { + $smtp->starttls(ssl_verify_params()) + or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr()); } + $smtp_encryption = ''; + # Send EHLO again to receive fresh + # supported commands + $smtp->hello($smtp_domain); } } @@ -1577,10 +1612,12 @@ foreach my $t (@files) { # Now parse the message body while(<$fh>) { $message .= $_; - if (/^(Signed-off-by|Cc): ([^>]*>?)/i) { + if (/^(Signed-off-by|Cc): (.*)/i) { chomp; my ($what, $c) = ($1, $2); - chomp $c; + # strip garbage for the address we'll use: + $c = strip_garbage_one_address($c); + # sanitize a bit more to decide whether to suppress the address: my $sc = sanitize_address($c); if ($sc eq $sender) { next if ($suppress_cc{'self'}); @@ -1759,6 +1796,25 @@ sub unique_email_list { sub validate_patch { my $fn = shift; + + if ($repo) { + my $validate_hook = catfile(catdir($repo->repo_path(), 'hooks'), + 'sendemail-validate'); + my $hook_error; + if (-x $validate_hook) { + my $target = abs_path($fn); + # The hook needs a correct cwd and GIT_DIR. + my $cwd_save = cwd(); + chdir($repo->wc_path() or $repo->repo_path()) + or die("chdir: $!"); + local $ENV{"GIT_DIR"} = $repo->repo_path(); + $hook_error = "rejected by sendemail-validate hook" + if system($validate_hook, $target); + chdir($cwd_save) or die("chdir: $!"); + } + return $hook_error if $hook_error; + } + open(my $fh, '<', $fn) or die sprintf(__("unable to open %s: %s\n"), $fn, $!); while (my $line = <$fh>) { |