"bcc=s" => \@bcclist,
"no-bcc" => \$no_bcc,
"chain-reply-to!" => \$chain_reply_to,
+ "no-chain-reply-to" => sub {$chain_reply_to = 0},
"smtp-server=s" => \$smtp_server,
"smtp-server-option=s" => \@smtp_server_options,
"smtp-server-port=s" => \$smtp_server_port,
"smtp-domain:s" => \$smtp_domain,
"identity=s" => \$identity,
"annotate!" => \$annotate,
+ "no-annotate" => sub {$annotate = 0},
"compose" => \$compose,
"quiet" => \$quiet,
"cc-cmd=s" => \$cc_cmd,
"suppress-from!" => \$suppress_from,
+ "no-suppress-from" => sub {$suppress_from = 0},
"suppress-cc=s" => \@suppress_cc,
"signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
+ "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
"cc-cover|cc-cover!" => \$cover_cc,
+ "no-cc-cover" => sub {$cover_cc = 0},
"to-cover|to-cover!" => \$cover_to,
+ "no-to-cover" => sub {$cover_to = 0},
"confirm=s" => \$confirm,
"dry-run" => \$dry_run,
"envelope-sender=s" => \$envelope_sender,
"thread!" => \$thread,
+ "no-thread" => sub {$thread = 0},
"validate!" => \$validate,
+ "no-validate" => sub {$validate = 0},
"transfer-encoding=s" => \$target_xfer_encoding,
"format-patch!" => \$format_patch,
+ "no-format-patch" => sub {$format_patch = 0},
"8bit-encoding=s" => \$auto_8bit_encoding,
"compose-encoding=s" => \$compose_encoding,
"force" => \$force,
"xmailer!" => \$use_xmailer,
+ "no-xmailer" => sub {$use_xmailer = 0},
);
usage() if $help;
($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]);
}
}
}
my %aliases;
+
+sub parse_sendmail_alias {
+ local $_ = shift;
+ if (/"/) {
+ print STDERR "warning: sendmail alias with quotes is not supported: $_\n";
+ } elsif (/:include:/) {
+ print STDERR "warning: `:include:` not supported: $_\n";
+ } elsif (/[\/|]/) {
+ print STDERR "warning: `/file` or `|pipe` redirection not supported: $_\n";
+ } elsif (/^(\S+?)\s*:\s*(.+)$/) {
+ my ($alias, $addr) = ($1, $2);
+ $aliases{$alias} = [ split_addrs($addr) ];
+ } else {
+ print STDERR "warning: sendmail line is not recognized: $_\n";
+ }
+}
+
+sub parse_sendmail_aliases {
+ my $fh = shift;
+ my $s = '';
+ while (<$fh>) {
+ chomp;
+ next if /^\s*$/ || /^\s*#/;
+ $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
+ parse_sendmail_alias($s) if $s;
+ $s = $_;
+ }
+ $s =~ s/\\$//; # silently tolerate stray '\' on last line
+ parse_sendmail_alias($s) if $s;
+}
+
my %parse_alias = (
# multiline formats can be supported in the future
mutt => sub { my $fh = shift; while (<$fh>) {
$aliases{$alias} = [ split_addrs($addr) ];
}
} },
-
+ sendmail => \&parse_sendmail_aliases,
gnus => sub { my $fh = shift; while (<$fh>) {
if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
$aliases{$1} = [ $2 ];
}
}
-($sender) = expand_aliases($sender) if defined $sender;
-
# 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.
sub is_format_patch_arg {
}
}
-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
($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);