sub usage {
print <<EOT;
git send-email [options] <file | directory | rev-list options >
+git send-email --dump-aliases
Composing:
--from <str> * Email From:
`git format-patch` ones.
--force * Send even if safety checks would prevent it.
+ Information:
+ --dump-aliases * Dump configured aliases and exit.
+
EOT
exit(1);
}
my $format_patch;
my $compose_filename;
my $force = 0;
+my $dump_aliases = 0;
# Handle interactive edition of files.
my $multiedit;
"smtpserveroption" => \@smtp_server_options,
"smtpuser" => \$smtp_authuser,
"smtppass" => \$smtp_authpass,
- "smtpsslcertpath" => \$smtp_ssl_cert_path,
"smtpdomain" => \$smtp_domain,
"smtpauth" => \$smtp_auth,
"to" => \@initial_to,
my %config_path_settings = (
"aliasesfile" => \@alias_files,
+ "smtpsslcertpath" => \$smtp_ssl_cert_path,
);
# Handle Uncouth Termination
my $help;
my $rc = GetOptions("h" => \$help,
+ "dump-aliases" => \$dump_aliases);
+usage() unless $rc;
+die "--dump-aliases incompatible with other options\n"
+ if !$help and $dump_aliases and @ARGV;
+$rc = GetOptions(
"sender|from=s" => \$sender,
"in-reply-to=s" => \$initial_reply_to,
"subject=s" => \$initial_subject,
($repoauthor) = Git::ident_person(@repo, 'author');
($repocommitter) = Git::ident_person(@repo, 'committer');
-# Verify the user input
-
-foreach my $entry (@initial_to) {
- die "Comma in --to entry: $entry'\n" unless $entry !~ m/,/;
-}
-
-foreach my $entry (@initial_cc) {
- die "Comma in --cc entry: $entry'\n" unless $entry !~ m/,/;
-}
-
-foreach my $entry (@bcclist) {
- die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/;
-}
-
sub parse_address_line {
if ($have_mail_address) {
return map { $_->format } Mail::Address->parse($_[0]);
} else {
- return split_addrs($_[0]);
+ return Git::parse_mailboxes($_[0]);
}
}
}
}
-($sender) = expand_aliases($sender) if defined $sender;
+if ($dump_aliases) {
+ print "$_\n" for (sort keys %aliases);
+ exit(0);
+}
# is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
# $f is a revision list specification to be passed to format-patch.
}
}
-if (!defined $sender) {
+if (defined $sender) {
+ $sender =~ s/^\s+|\s+$//g;
+ ($sender) = expand_aliases($sender);
+} else {
$sender = $repoauthor || $repocommitter || '';
}
return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
}
-@initial_to = expand_aliases(@initial_to);
-@initial_to = validate_address_list(sanitize_address_list(@initial_to));
-@initial_cc = expand_aliases(@initial_cc);
-@initial_cc = validate_address_list(sanitize_address_list(@initial_cc));
-@bcclist = expand_aliases(@bcclist);
-@bcclist = validate_address_list(sanitize_address_list(@bcclist));
+@initial_to = process_address_list(@initial_to);
+@initial_cc = process_address_list(@initial_cc);
+@bcclist = process_address_list(@bcclist);
if ($thread && !defined $initial_reply_to && $prompting) {
$initial_reply_to = ask(
return $recipient;
}
+ # remove non-escaped quotes
+ $recipient_name =~ s/(^|[^\\])"/$1/g;
+
# rfc2047 is needed if a non-ascii char is included
if ($recipient_name =~ /[^[:ascii:]]/) {
- $recipient_name =~ s/^"(.*)"$/$1/;
$recipient_name = quote_rfc2047($recipient_name);
}
# double quotes are needed if specials or CTLs are included
elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
- $recipient_name =~ s/(["\\\r])/\\$1/g;
+ $recipient_name =~ s/([\\\r])/\\$1/g;
$recipient_name = qq["$recipient_name"];
}
return (map { sanitize_address($_) } @_);
}
+sub process_address_list {
+ my @addr_list = map { parse_address_line($_) } @_;
+ @addr_list = expand_aliases(@addr_list);
+ @addr_list = sanitize_address_list(@addr_list);
+ @addr_list = validate_address_list(@addr_list);
+ return @addr_list;
+}
+
# Returns the local Fully Qualified Domain Name (FQDN) if available.
#
# Tightly configured MTAa require that a caller sends a real DNS
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());
+ die "CA path \"$smtp_ssl_cert_path\" does not exist";
}
}
require Net::SMTP::SSL;
$smtp_domain ||= maildomain();
require IO::Socket::SSL;
+
+ # Suppress "variable accessed once" warning.
+ {
+ no warnings 'once';
+ $IO::Socket::SSL::DEBUG = 1;
+ }
+
# Net::SMTP::SSL->new() does not forward any SSL options
IO::Socket::SSL::set_client_defaults(
ssl_verify_params());
$smtp->mail( $raw_from ) or die $smtp->message;
$smtp->to( @recipients ) or die $smtp->message;
$smtp->data or die $smtp->message;
- $smtp->datasend("$header\n$message") or die $smtp->message;
+ $smtp->datasend("$header\n") or die $smtp->message;
+ my @lines = split /^/, $message;
+ foreach my $line (@lines) {
+ $smtp->datasend("$line") or die $smtp->message;
+ }
$smtp->dataend() or die $smtp->message;
$smtp->code =~ /250|200/ or die "Failed to send $subject\n".$smtp->message;
}
($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
$needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
- @to = validate_address_list(sanitize_address_list(@to));
- @cc = validate_address_list(sanitize_address_list(@cc));
+ @to = process_address_list(@to);
+ @cc = process_address_list(@cc);
@to = (@initial_to, @to);
@cc = (@initial_cc, @cc);