3 # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>
4 # Copyright 2005 Ryan Anderson <ryan@michonline.com>
8 # Ported to support git "mbox" format files by Ryan Anderson <ryan@michonline.com>
10 # Sends a collection of emails to the given email addresses, disturbingly fast.
12 # Supports two formats:
13 # 1. mbox format files (ignoring most headers and MIME formatting - this is designed for sending patches)
14 # 2. The original format support by Greg's script:
15 # first line of the message is who to CC,
16 # and second line is the subject of the message.
21 use warnings
$ENV{GIT_PERL_FATAL_WARNINGS
} ?
qw(FATAL all) : ();
23 use Git
::LoadCPAN
::Error
qw(:try);
27 Getopt
::Long
::Configure qw
/ pass_through /;
31 git send-email [<options>] <file|directory>
32 git send-email [<options>] <format-patch options>
33 git send-email --dump-aliases
36 --from <str> * Email From:
37 --[no-]to <str> * Email To:
38 --[no-]cc <str> * Email Cc:
39 --[no-]bcc <str> * Email Bcc:
40 --subject <str> * Email "Subject:"
41 --reply-to <str> * Email "Reply-To:"
42 --in-reply-to <str> * Email "In-Reply-To:"
43 --[no-]xmailer * Add "X-Mailer:" header (default).
44 --[no-]annotate * Review each patch that will be sent in an editor.
45 --compose * Open an editor for introduction.
46 --compose-encoding <str> * Encoding to assume for introduction.
47 --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
48 --transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
51 --envelope-sender <str> * Email envelope sender.
52 --sendmail-cmd <str> * Command to run to send email.
53 --smtp-server <str:int> * Outgoing SMTP server to use. The port
54 is optional. Default 'localhost'.
55 --smtp-server-option <str> * Outgoing SMTP server option to use.
56 --smtp-server-port <int> * Outgoing SMTP server port.
57 --smtp-user <str> * Username for SMTP-AUTH.
58 --smtp-pass <str> * Password for SMTP-AUTH; not necessary.
59 --smtp-encryption <str> * tls or ssl; anything else disables.
60 --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
61 --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
62 Pass an empty string to disable certificate
64 --smtp-domain <str> * The domain name sent to HELO/EHLO handshake
65 --smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
66 "none" to disable authentication.
67 This setting forces to use one of the listed mechanisms.
68 --no-smtp-auth Disable SMTP authentication. Shorthand for
70 --smtp-debug <0|1> * Disable, enable Net::SMTP debug.
72 --batch-size <int> * send max <int> message per connection.
73 --relogin-delay <int> * delay <int> seconds between two successive login.
74 This option can only be used with --batch-size
77 --identity <str> * Use the sendemail.<id> options.
78 --to-cmd <str> * Email To: via `<str> \$patch_path`.
79 --cc-cmd <str> * Email Cc: via `<str> \$patch_path`.
80 --header-cmd <str> * Add headers via `<str> \$patch_path`.
81 --no-header-cmd * Disable any header command in use.
82 --suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
83 --[no-]cc-cover * Email Cc: addresses in the cover letter.
84 --[no-]to-cover * Email To: addresses in the cover letter.
85 --[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on.
86 --[no-]suppress-from * Send to self. Default off.
87 --[no-]chain-reply-to * Chain In-Reply-To: fields. Default off.
88 --[no-]thread * Use In-Reply-To: field. Default on.
91 --confirm <str> * Confirm recipients before sending;
92 auto, cc, compose, always, or never.
93 --quiet * Output one line of info per email.
94 --dry-run * Don't actually send the emails.
95 --[no-]validate * Perform patch sanity checks. Default on.
96 --[no-]format-patch * understand any non optional arguments as
97 `git format-patch` ones.
98 --force * Send even if safety checks would prevent it.
101 --dump-aliases * Dump configured aliases and exit.
109 grep !$seen{$_}++, @_;
112 sub completion_helper
{
113 my ($original_opts) = @_;
114 my %not_for_completion = (
115 "git-completion-helper" => undef,
118 my @send_email_opts = ();
120 foreach my $key (keys %$original_opts) {
121 unless (exists $not_for_completion{$key}) {
122 my $negatable = ($key =~ s/!$//);
124 if ($key =~ /[:=][si]$/) {
125 $key =~ s/[:=][si]$//;
126 push (@send_email_opts, "--$_=") foreach (split (/\|/, $key));
128 push (@send_email_opts, "--$_") foreach (split (/\|/, $key));
130 push (@send_email_opts, "--no-$_") foreach (split (/\|/, $key));
136 my @format_patch_opts = split(/ /, Git
::command
('format-patch', '--git-completion-helper'));
137 my @opts = (@send_email_opts, @format_patch_opts);
138 @opts = uniq
(grep !/^$/, @opts);
139 # There's an implicit '\n' here already, no need to add an explicit one.
144 # most mail servers generate the Date: header, but not all...
145 sub format_2822_time
{
147 my @localtm = localtime($time);
148 my @gmttm = gmtime($time);
149 my $localmin = $localtm[1] + $localtm[2] * 60;
150 my $gmtmin = $gmttm[1] + $gmttm[2] * 60;
151 if ($localtm[0] != $gmttm[0]) {
152 die __
("local zone differs from GMT by a non-minute interval\n");
154 if ((($gmttm[6] + 1) % 7) == $localtm[6]) {
156 } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {
158 } elsif ($gmttm[6] != $localtm[6]) {
159 die __
("local time offset greater than or equal to 24 hours\n");
161 my $offset = $localmin - $gmtmin;
162 my $offhour = $offset / 60;
163 my $offmin = abs($offset % 60);
164 if (abs($offhour) >= 24) {
165 die __
("local time offset greater than or equal to 24 hours\n");
168 return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d",
169 qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]],
171 qw(Jan Feb Mar Apr May Jun
172 Jul Aug Sep Oct Nov Dec)[$localtm[4]],
177 ($offset >= 0) ?
'+' : '-',
187 # Regexes for RFC 2047 productions.
188 my $re_token = qr/[^][()<>@,;:\\"\/?
.= \000-\037\177-\377]+/;
189 my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
190 my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
192 # Variables we fill in automatically, or via prompting:
193 my (@to,@cc,@xh,$envelope_sender,
194 $initial_in_reply_to,$reply_to,$initial_subject,@files,
195 $author,$sender,$smtp_authpass,$annotate,$compose,$time);
196 # Things we either get from config, *or* are overridden on the
198 my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);
199 my (@config_to, @getopt_to);
200 my (@config_cc, @getopt_cc);
201 my (@config_bcc, @getopt_bcc);
204 #$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
206 my $repo = eval { Git
->repository() };
207 my @repo = $repo ?
($repo) : ();
209 # Behavior modification variables
210 my ($quiet, $dry_run) = (0, 0);
212 my $compose_filename;
214 my $dump_aliases = 0;
216 # Variables to prevent short format-patch options from being captured
217 # as abbreviated send-email options
220 # Handle interactive edition of files.
225 my ($args, $msg, $cmd_name) = @_;
227 my $signalled = $?
& 127;
228 my $exit_code = $?
>> 8;
229 return unless $signalled or $exit_code;
231 my @sprintf_args = ($cmd_name ?
$cmd_name : $args->[0], $exit_code);
233 # Quiet the 'redundant' warning category, except we
234 # need to support down to Perl 5.8.1, so we can't do a
235 # "no warnings 'redundant'", since that category was
236 # introduced in perl 5.22, and asking for it will die
239 return sprintf($msg, @sprintf_args);
241 return sprintf(__
("fatal: command '%s' died with exit code %d"),
246 my $msg = system_or_msg
(@_);
251 if (!defined($editor)) {
252 $editor = Git
::command_oneline
('var', 'GIT_EDITOR');
254 my $die_msg = __
("the editor exited uncleanly, aborting everything");
255 if (defined($multiedit) && !$multiedit) {
256 system_or_die
(['sh', '-c', $editor.' "$@"', $editor, $_], $die_msg) for @_;
258 system_or_die
(['sh', '-c', $editor.' "$@"', $editor, @_], $die_msg);
262 # Variables with corresponding config settings
263 my ($suppress_from, $signed_off_by_cc);
264 my ($cover_cc, $cover_to);
265 my ($to_cmd, $cc_cmd, $header_cmd);
266 my ($smtp_server, $smtp_server_port, @smtp_server_options);
267 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
268 my ($batch_size, $relogin_delay);
269 my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
272 my ($auto_8bit_encoding);
273 my ($compose_encoding);
275 # Variables with corresponding config settings & hardcoded defaults
276 my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
278 my $chain_reply_to = 0;
281 my $target_xfer_encoding = 'auto';
282 my $forbid_sendmail_variables = 1;
284 my %config_bool_settings = (
285 "thread" => \
$thread,
286 "chainreplyto" => \
$chain_reply_to,
287 "suppressfrom" => \
$suppress_from,
288 "signedoffbycc" => \
$signed_off_by_cc,
289 "cccover" => \
$cover_cc,
290 "tocover" => \
$cover_to,
291 "signedoffcc" => \
$signed_off_by_cc,
292 "validate" => \
$validate,
293 "multiedit" => \
$multiedit,
294 "annotate" => \
$annotate,
295 "xmailer" => \
$use_xmailer,
296 "forbidsendmailvariables" => \
$forbid_sendmail_variables,
299 my %config_settings = (
300 "smtpencryption" => \
$smtp_encryption,
301 "smtpserver" => \
$smtp_server,
302 "smtpserverport" => \
$smtp_server_port,
303 "smtpserveroption" => \
@smtp_server_options,
304 "smtpuser" => \
$smtp_authuser,
305 "smtppass" => \
$smtp_authpass,
306 "smtpdomain" => \
$smtp_domain,
307 "smtpauth" => \
$smtp_auth,
308 "smtpbatchsize" => \
$batch_size,
309 "smtprelogindelay" => \
$relogin_delay,
314 "headercmd" => \
$header_cmd,
315 "aliasfiletype" => \
$aliasfiletype,
316 "bcc" => \
@config_bcc,
317 "suppresscc" => \
@suppress_cc,
318 "envelopesender" => \
$envelope_sender,
319 "confirm" => \
$confirm,
321 "assume8bitencoding" => \
$auto_8bit_encoding,
322 "composeencoding" => \
$compose_encoding,
323 "transferencoding" => \
$target_xfer_encoding,
324 "sendmailcmd" => \
$sendmail_cmd,
327 my %config_path_settings = (
328 "aliasesfile" => \
@alias_files,
329 "smtpsslcertpath" => \
$smtp_ssl_cert_path,
332 # Handle Uncouth Termination
335 require Term
::ANSIColor
;
336 print Term
::ANSIColor
::color
("reset"), "\n";
338 # SMTP password masked
341 # tmp files from --compose
342 if (defined $compose_filename) {
343 if (-e
$compose_filename) {
344 printf __
("'%s' contains an intermediate version ".
345 "of the email you were composing.\n"),
348 if (-e
($compose_filename . ".final")) {
349 printf __
("'%s.final' contains the composed email.\n"),
357 $SIG{TERM
} = \
&signal_handler
;
358 $SIG{INT
} = \
&signal_handler
;
360 # Read our sendemail.* config
362 my ($known_keys, $configured, $prefix) = @_;
364 foreach my $setting (keys %config_bool_settings) {
365 my $target = $config_bool_settings{$setting};
366 my $key = "$prefix.$setting";
367 next unless exists $known_keys->{$key};
368 my $v = (@
{$known_keys->{$key}} == 1 &&
369 (defined $known_keys->{$key}->[0] &&
370 $known_keys->{$key}->[0] =~ /^(?:true|false)$/s))
371 ?
$known_keys->{$key}->[0] eq 'true'
372 : Git
::config_bool
(@repo, $key);
373 next unless defined $v;
374 next if $configured->{$setting}++;
378 foreach my $setting (keys %config_path_settings) {
379 my $target = $config_path_settings{$setting};
380 my $key = "$prefix.$setting";
381 next unless exists $known_keys->{$key};
382 if (ref($target) eq "ARRAY") {
383 my @values = Git
::config_path
(@repo, $key);
385 next if $configured->{$setting}++;
389 my $v = Git
::config_path
(@repo, "$prefix.$setting");
390 next unless defined $v;
391 next if $configured->{$setting}++;
396 foreach my $setting (keys %config_settings) {
397 my $target = $config_settings{$setting};
398 my $key = "$prefix.$setting";
399 next unless exists $known_keys->{$key};
400 if (ref($target) eq "ARRAY") {
401 my @values = @
{$known_keys->{$key}};
402 @values = grep { defined } @values;
403 next if $configured->{$setting}++;
407 my $v = $known_keys->{$key}->[-1];
408 next unless defined $v;
409 next if $configured->{$setting}++;
419 my $ret = Git
::command
(
426 # We must always return ($k, $v) here, since
427 # empty config values will be just "key\0",
428 # not "key\nvalue\0".
429 my ($k, $v) = split /\n/, $_, 2;
434 # If we have no keys we're OK, otherwise re-throw
435 die $@
if $@
->value != 1;
440 # Save ourselves a lot of work of shelling out to 'git config' (it
441 # parses 'bool' etc.) by only doing so for config keys that exist.
442 my %known_config_keys;
444 my @kv = config_regexp
("^sende?mail[.]");
445 while (my ($k, $v) = splice @kv, 0, 2) {
446 push @
{$known_config_keys{$k}} => $v;
450 # sendemail.identity yields to --identity. We must parse this
451 # special-case first before the rest of the config is read.
453 my $key = "sendemail.identity";
454 $identity = Git
::config
(@repo, $key) if exists $known_config_keys{$key};
456 my %identity_options = (
457 "identity=s" => \
$identity,
458 "no-identity" => \
$no_identity,
460 my $rc = GetOptions
(%identity_options);
462 undef $identity if $no_identity;
464 # Now we know enough to read the config
467 read_config
(\
%known_config_keys, \
%configured, "sendemail.$identity") if defined $identity;
468 read_config
(\
%known_config_keys, \
%configured, "sendemail");
471 # Begin by accumulating all the variables (defined above), that we will end up
472 # needing, first, from the command line:
475 my $git_completion_helper;
476 my %dump_aliases_options = (
478 "dump-aliases" => \
$dump_aliases,
480 $rc = GetOptions
(%dump_aliases_options);
482 die __
("--dump-aliases incompatible with other options\n")
483 if !$help and $dump_aliases and @ARGV;
485 "sender|from=s" => \
$sender,
486 "in-reply-to=s" => \
$initial_in_reply_to,
487 "reply-to=s" => \
$reply_to,
488 "subject=s" => \
$initial_subject,
489 "to=s" => \
@getopt_to,
490 "to-cmd=s" => \
$to_cmd,
492 "cc=s" => \
@getopt_cc,
494 "bcc=s" => \
@getopt_bcc,
495 "no-bcc" => \
$no_bcc,
496 "chain-reply-to!" => \
$chain_reply_to,
497 "sendmail-cmd=s" => \
$sendmail_cmd,
498 "smtp-server=s" => \
$smtp_server,
499 "smtp-server-option=s" => \
@smtp_server_options,
500 "smtp-server-port=s" => \
$smtp_server_port,
501 "smtp-user=s" => \
$smtp_authuser,
502 "smtp-pass:s" => \
$smtp_authpass,
503 "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
504 "smtp-encryption=s" => \
$smtp_encryption,
505 "smtp-ssl-cert-path=s" => \
$smtp_ssl_cert_path,
506 "smtp-debug:i" => \
$debug_net_smtp,
507 "smtp-domain:s" => \
$smtp_domain,
508 "smtp-auth=s" => \
$smtp_auth,
509 "no-smtp-auth" => sub {$smtp_auth = 'none'},
510 "annotate!" => \
$annotate,
511 "compose" => \
$compose,
513 "cc-cmd=s" => \
$cc_cmd,
514 "header-cmd=s" => \
$header_cmd,
515 "no-header-cmd" => \
$no_header_cmd,
516 "suppress-from!" => \
$suppress_from,
517 "suppress-cc=s" => \
@suppress_cc,
518 "signed-off-cc|signed-off-by-cc!" => \
$signed_off_by_cc,
519 "cc-cover!" => \
$cover_cc,
520 "to-cover!" => \
$cover_to,
521 "confirm=s" => \
$confirm,
522 "dry-run" => \
$dry_run,
523 "envelope-sender=s" => \
$envelope_sender,
524 "thread!" => \
$thread,
525 "validate!" => \
$validate,
526 "transfer-encoding=s" => \
$target_xfer_encoding,
527 "format-patch!" => \
$format_patch,
528 "8bit-encoding=s" => \
$auto_8bit_encoding,
529 "compose-encoding=s" => \
$compose_encoding,
531 "xmailer!" => \
$use_xmailer,
532 "batch-size=i" => \
$batch_size,
533 "relogin-delay=i" => \
$relogin_delay,
534 "git-completion-helper" => \
$git_completion_helper,
535 "v=s" => \
$reroll_count,
537 $rc = GetOptions
(%options);
539 # Munge any "either config or getopt, not both" variables
540 my @initial_to = @getopt_to ?
@getopt_to : ($no_to ?
() : @config_to);
541 my @initial_cc = @getopt_cc ?
@getopt_cc : ($no_cc ?
() : @config_cc);
542 my @initial_bcc = @getopt_bcc ?
@getopt_bcc : ($no_bcc ?
() : @config_bcc);
545 my %all_options = (%options, %dump_aliases_options, %identity_options);
546 completion_helper
(\
%all_options) if $git_completion_helper;
551 if ($forbid_sendmail_variables && grep { /^sendmail/s } keys %known_config_keys) {
552 die __
("fatal: found configuration options for 'sendmail'\n" .
553 "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
554 "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
557 die __
("Cannot run git format-patch from outside a repository\n")
558 if $format_patch and not $repo;
560 die __
("`batch-size` and `relogin` must be specified together " .
561 "(via command-line or configuration option)\n")
562 if defined $relogin_delay and not defined $batch_size;
564 # 'default' encryption is none -- this only prevents a warning
565 $smtp_encryption = '' unless (defined $smtp_encryption);
567 # Set CC suppressions
570 foreach my $entry (@suppress_cc) {
571 # Please update $__git_send_email_suppresscc_options
572 # in git-completion.bash when you add new options.
573 die sprintf(__
("Unknown --suppress-cc field: '%s'\n"), $entry)
574 unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc|misc-by)$/;
575 $suppress_cc{$entry} = 1;
579 if ($suppress_cc{'all'}) {
580 foreach my $entry (qw
(cccmd cc author self sob body bodycc misc
-by
)) {
581 $suppress_cc{$entry} = 1;
583 delete $suppress_cc{'all'};
586 # If explicit old-style ones are specified, they trump --suppress-cc.
587 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
588 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
590 if ($suppress_cc{'body'}) {
591 foreach my $entry (qw
(sob bodycc misc
-by
)) {
592 $suppress_cc{$entry} = 1;
594 delete $suppress_cc{'body'};
597 # Set confirm's default value
598 my $confirm_unconfigured = !defined $confirm;
599 if ($confirm_unconfigured) {
600 $confirm = scalar %suppress_cc ?
'compose' : 'auto';
602 # Please update $__git_send_email_confirm_options in
603 # git-completion.bash when you add new options.
604 die sprintf(__
("Unknown --confirm setting: '%s'\n"), $confirm)
605 unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
607 # Debugging, print out the suppressions.
609 print "suppressions:\n";
610 foreach my $entry (keys %suppress_cc) {
611 printf " %-5s -> $suppress_cc{$entry}\n", $entry;
615 my ($repoauthor, $repocommitter);
618 my ($author, $committer);
621 return $cache{$what} if exists $cache{$what};
622 ($cache{$what}) = Git
::ident_person
(@repo, $what);
623 return $cache{$what};
625 $repoauthor = sub { $common->('author') };
626 $repocommitter = sub { $common->('committer') };
629 sub parse_address_line
{
630 require Git
::LoadCPAN
::Mail
::Address
;
631 return map { $_->format } Mail
::Address
->parse($_[0]);
635 require Text
::ParseWords
;
636 return Text
::ParseWords
::quotewords
('\s*,\s*', 1, @_);
641 sub parse_sendmail_alias
{
644 printf STDERR __
("warning: sendmail alias with quotes is not supported: %s\n"), $_;
645 } elsif (/:include:/) {
646 printf STDERR __
("warning: `:include:` not supported: %s\n"), $_;
648 printf STDERR __
("warning: `/file` or `|pipe` redirection not supported: %s\n"), $_;
649 } elsif (/^(\S+?)\s*:\s*(.+)$/) {
650 my ($alias, $addr) = ($1, $2);
651 $aliases{$alias} = [ split_addrs
($addr) ];
653 printf STDERR __
("warning: sendmail line is not recognized: %s\n"), $_;
657 sub parse_sendmail_aliases
{
662 next if /^\s*$/ || /^\s*#/;
663 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
664 parse_sendmail_alias
($s) if $s;
667 $s =~ s/\\$//; # silently tolerate stray '\' on last line
668 parse_sendmail_alias
($s) if $s;
672 # multiline formats can be supported in the future
673 mutt
=> sub { my $fh = shift; while (<$fh>) {
674 if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
675 my ($alias, $addr) = ($1, $2);
676 $addr =~ s/#.*$//; # mutt allows # comments
677 # commas delimit multiple addresses
678 my @addr = split_addrs
($addr);
680 # quotes may be escaped in the file,
681 # unescape them so we do not double-escape them later.
682 s/\\"/"/g foreach @addr;
683 $aliases{$alias} = \
@addr
685 mailrc
=> sub { my $fh = shift; while (<$fh>) {
686 if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
687 require Text
::ParseWords
;
688 # spaces delimit multiple addresses
689 $aliases{$1} = [ Text
::ParseWords
::quotewords
('\s+', 0, $2) ];
691 pine
=> sub { my $fh = shift; my $f='\t[^\t]*';
692 for (my $x = ''; defined($x); $x = $_) {
694 $x .= $1 while(defined($_ = <$fh>) && /^ +(.*)$/);
695 $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
696 $aliases{$1} = [ split_addrs
($2) ];
698 elm
=> sub { my $fh = shift;
700 if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
701 my ($alias, $addr) = ($1, $2);
702 $aliases{$alias} = [ split_addrs
($addr) ];
705 sendmail
=> \
&parse_sendmail_aliases
,
706 gnus
=> sub { my $fh = shift; while (<$fh>) {
707 if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
708 $aliases{$1} = [ $2 ];
710 # Please update _git_config() in git-completion.bash when you
714 if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
715 foreach my $file (@alias_files) {
716 open my $fh, '<', $file or die "opening $file: $!\n";
717 $parse_alias{$aliasfiletype}->($fh);
723 print "$_\n" for (sort keys %aliases);
727 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
728 # $f is a revision list specification to be passed to format-patch.
729 sub is_format_patch_arg
{
733 $repo->command('rev-parse', '--verify', '--quiet', $f);
734 if (defined($format_patch)) {
735 return $format_patch;
737 die sprintf(__
(<<EOF), $f, $f);
738 File '%s' exists but it could also be the range of commits
739 to produce patches for. Please disambiguate by...
741 * Saying "./%s" if you mean a file; or
742 * Giving --format-patch option if you mean a range.
744 } catch Git
::Error
::Command with
{
745 # Not a valid revision. Treat it as a filename.
750 # Now that all the defaults are set, process the rest of the command line
751 # arguments and collect up the files that need to be processed.
753 while (defined(my $f = shift @ARGV)) {
755 push @rev_list_opts, "--", @ARGV;
757 } elsif (-d
$f and !is_format_patch_arg
($f)) {
759 or die sprintf(__
("Failed to opendir %s: %s"), $f, $!);
762 push @files, grep { -f
$_ } map { File
::Spec
->catfile($f, $_) }
765 } elsif ((-f
$f or -p
$f) and !is_format_patch_arg
($f)) {
768 push @rev_list_opts, $f;
772 if (@rev_list_opts) {
773 die __
("Cannot run git format-patch from outside a repository\n")
776 push @files, $repo->command('format-patch', '-o', File
::Temp
::tempdir
(CLEANUP
=> 1),
777 defined $reroll_count ?
('-v', $reroll_count) : (),
781 if (defined $sender) {
782 $sender =~ s/^\s+|\s+$//g;
783 ($sender) = expand_aliases
($sender);
785 $sender = $repoauthor->() || $repocommitter->() || '';
788 # $sender could be an already sanitized address
789 # (e.g. sendemail.from could be manually sanitized by user).
790 # But it's a no-op to run sanitize_address on an already sanitized address.
791 $sender = sanitize_address
($sender);
793 $time = time - scalar $#files;
795 @files = handle_backup_files
(@files);
799 print $_,"\n" for (@files);
802 print STDERR __
("\nNo patch files specified!\n\n");
806 sub get_patch_subject
{
808 open (my $fh, '<', $fn);
809 while (my $line = <$fh>) {
810 next unless ($line =~ /^Subject: (.*)$/);
815 die sprintf(__
("No subject line in %s?"), $fn);
819 # Note that this does not need to be secure, but we will make a small
820 # effort to have it be unique
822 $compose_filename = ($repo ?
823 File
::Temp
::tempfile
(".gitsendemail.msg.XXXXXX", DIR
=> $repo->repo_path()) :
824 File
::Temp
::tempfile
(".gitsendemail.msg.XXXXXX", DIR
=> "."))[1];
825 open my $c, ">", $compose_filename
826 or die sprintf(__
("Failed to open for writing %s: %s"), $compose_filename, $!);
829 my $tpl_sender = $sender || $repoauthor->() || $repocommitter->() || '';
830 my $tpl_subject = $initial_subject || '';
831 my $tpl_in_reply_to = $initial_in_reply_to || '';
832 my $tpl_reply_to = $reply_to || '';
833 my $tpl_to = join(',', @initial_to);
834 my $tpl_cc = join(',', @initial_cc);
835 my $tpl_bcc = join(', ', @initial_bcc);
837 print $c <<EOT1, Git::prefix_lines("GIT: ", __(<<EOT2)), <<EOT3;
838 From $tpl_sender # This line is ignored.
840 Lines beginning in "GIT:" will be removed.
841 Consider including an overall diffstat or table of contents
842 for the patch you are writing.
844 Clear the body content if you don't wish to send a summary.
850 Reply-To: $tpl_reply_to
851 Subject: $tpl_subject
852 In-Reply-To: $tpl_in_reply_to
856 print $c get_patch_subject($f);
861 do_edit($compose_filename, @files);
863 do_edit($compose_filename);
866 open my $c2, ">", $compose_filename . ".final"
867 or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
869 open $c, "<", $compose_filename
870 or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
872 my $need_8bit_cte = file_has_nonascii($compose_filename);
874 my $summary_empty = 1;
875 if (!defined $compose_encoding) {
876 $compose_encoding = "UTF-8";
881 $summary_empty = 0 unless (/^\n$/);
884 if ($need_8bit_cte) {
885 print $c2 "MIME-Version: 1.0\n",
886 "Content-Type: text/plain; ",
887 "charset=$compose_encoding\n",
888 "Content-Transfer-Encoding: 8bit\n";
890 } elsif (/^MIME-Version:/i) {
892 } elsif (/^Subject:\s*(.+)\s*$/i) {
893 $initial_subject = $1;
894 my $subject = $initial_subject;
896 quote_subject($subject, $compose_encoding) .
898 } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
899 $initial_in_reply_to = $1;
901 } elsif (/^Reply-To:\s*(.+)\s*$/i) {
903 } elsif (/^From:\s*(.+)\s*$/i) {
906 } elsif (/^To:\s*(.+)\s*$/i) {
907 @initial_to = parse_address_line($1);
909 } elsif (/^Cc:\s*(.+)\s*$/i) {
910 @initial_cc = parse_address_line($1);
913 @initial_bcc = parse_address_line($1);
921 if ($summary_empty) {
922 print __("Summary email is empty, skipping it\n");
925 } elsif ($annotate) {
930 # Only instantiate one $term per program run, since some
931 # Term::ReadLine providers refuse to create a second instance.
934 require Term::ReadLine;
935 if (!defined $term) {
936 $term = $ENV{"GIT_SEND_EMAIL_NOTTY"}
937 ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
938 : Term::ReadLine->new('git-send-email');
945 my ($prompt, %arg) = @_;
946 my $valid_re = $arg{valid_re};
947 my $default = $arg{default};
948 my $confirm_only = $arg{confirm_only};
952 return defined $default ? $default : undef
953 unless defined $term->IN and defined fileno($term->IN) and
954 defined $term->OUT and defined fileno($term->OUT);
956 $resp = $term->readline($prompt);
957 if (!defined $resp) { # EOF
959 return defined $default ? $default : undef;
961 if ($resp eq '' and defined $default) {
964 if (!defined $valid_re or $resp =~ /$valid_re/) {
968 my $yesno = $term->readline(
969 # TRANSLATORS: please keep [y/N] as is.
970 sprintf(__("Are you sure you want to use <%s> [y/N]? "), $resp));
971 if (defined $yesno && $yesno =~ /y/i) {
981 sub file_declares_8bit_cte {
983 open (my $fh, '<', $fn);
984 while (my $line = <$fh>) {
985 last if ($line =~ /^$/);
986 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
992 foreach my $f (@files) {
993 next unless (body_or_subject_has_nonascii($f)
994 && !file_declares_8bit_cte($f));
995 $broken_encoding{$f} = 1;
998 if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
999 print __("The following files are 8bit, but do not declare " .
1000 "a Content-Transfer-Encoding.\n");
1001 foreach my $f (sort keys %broken_encoding) {
1004 $auto_8bit_encoding = ask(__("Which 8bit encoding should I declare [UTF-8]? "),
1005 valid_re => qr/.{4}/, confirm_only => 1,
1006 default => "UTF-8");
1010 for my $f (@files) {
1011 if (get_patch_subject($f) =~ /\Q*** SUBJECT HERE ***\E/) {
1012 die sprintf(__("Refusing to send because the patch\n\t%s\n"
1013 . "has the template subject '*** SUBJECT HERE ***'. "
1014 . "Pass --force if you really want to send.\n"), $f);
1019 my $to_whom = __("To whom should the emails be sent (if anyone)?");
1021 if (!@initial_to && !defined $to_cmd) {
1022 my $to = ask("$to_whom ",
1024 valid_re => qr/\@.*\./, confirm_only => 1);
1025 push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
1029 sub expand_aliases {
1030 return map { expand_one_alias($_) } @_;
1033 my %EXPANDED_ALIASES;
1034 sub expand_one_alias {
1036 if ($EXPANDED_ALIASES{$alias}) {
1037 die sprintf(__("fatal: alias '%s' expands to itself\n"), $alias);
1039 local $EXPANDED_ALIASES{$alias} = 1;
1040 return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
1043 @initial_to = process_address_list(@initial_to);
1044 @initial_cc = process_address_list(@initial_cc);
1045 @initial_bcc = process_address_list(@initial_bcc);
1047 if ($thread && !defined $initial_in_reply_to && $prompting) {
1048 $initial_in_reply_to = ask(
1049 __("Message-ID to be used as In-Reply-To for the first email (if any)? "),
1051 valid_re => qr/\@.*\./, confirm_only => 1);
1053 if (defined $initial_in_reply_to) {
1054 $initial_in_reply_to =~ s/^\s*<?//;
1055 $initial_in_reply_to =~ s/>?\s*$//;
1056 $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
1059 if (defined $reply_to) {
1060 $reply_to =~ s/^\s+|\s+$//g;
1061 ($reply_to) = expand_aliases($reply_to);
1062 $reply_to = sanitize_address($reply_to);
1065 if (!defined $sendmail_cmd && !defined $smtp_server) {
1066 my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
1067 push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH
};
1068 foreach (@sendmail_paths) {
1075 if (!defined $sendmail_cmd) {
1076 $smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*
1080 if ($compose && $compose > 0) {
1081 @files = ($compose_filename . ".final", @files);
1084 # Variables we set as part of the loop over files
1085 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
1086 $needs_confirm, $message_num, $ask_default);
1088 sub extract_valid_address
{
1089 my $address = shift;
1090 my $local_part_regexp = qr/[^<>"\s@]+/;
1091 my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
1093 # check for a local address:
1094 return $address if ($address =~ /^($local_part_regexp)$/);
1096 $address =~ s/^\s*<(.*)>\s*$/$1/;
1097 my $have_email_valid = eval { require Email
::Valid
; 1 };
1098 if ($have_email_valid) {
1099 return scalar Email
::Valid
->address($address);
1102 # less robust/correct than the monster regexp in Email::Valid,
1103 # but still does a 99% job, and one less dependency
1104 return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
1108 sub extract_valid_address_or_die
{
1109 my $address = shift;
1110 my $valid_address = extract_valid_address
($address);
1111 die sprintf(__
("error: unable to extract a valid address from: %s\n"), $address)
1113 return $valid_address;
1116 sub validate_address
{
1117 my $address = shift;
1118 while (!extract_valid_address
($address)) {
1119 printf STDERR __
("error: unable to extract a valid address from: %s\n"), $address;
1120 # TRANSLATORS: Make sure to include [q] [d] [e] in your
1121 # translation. The program will only accept English input
1123 $_ = ask
(__
("What to do with this address? ([q]uit|[d]rop|[e]dit): "),
1124 valid_re
=> qr/^(?:quit|q|drop|d|edit|e)/i,
1129 cleanup_compose_files
();
1132 $address = ask
("$to_whom ",
1134 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
1139 sub validate_address_list
{
1140 return (grep { defined $_ }
1141 map { validate_address
($_) } @_);
1144 # Usually don't need to change anything below here.
1146 # we make a "fake" message id by taking the current number
1147 # of seconds since the beginning of Unix time and tacking on
1148 # a random number to the end, in case we are called quicker than
1149 # 1 second since the last time we were called.
1151 # We'll setup a template for the message id, using the "from" address:
1153 my ($message_id_stamp, $message_id_serial);
1154 sub make_message_id
{
1156 if (!defined $message_id_stamp) {
1158 $message_id_stamp = POSIX
::strftime
("%Y%m%d%H%M%S.$$", gmtime(time));
1159 $message_id_serial = 0;
1161 $message_id_serial++;
1162 $uniq = "$message_id_stamp-$message_id_serial";
1165 for ($sender, $repocommitter->(), $repoauthor->()) {
1166 $du_part = extract_valid_address
(sanitize_address
($_));
1167 last if (defined $du_part and $du_part ne '');
1169 if (not defined $du_part or $du_part eq '') {
1170 require Sys
::Hostname
;
1171 $du_part = 'user@' . Sys
::Hostname
::hostname
();
1173 my $message_id_template = "<%s-%s>";
1174 $message_id = sprintf($message_id_template, $uniq, $du_part);
1175 #print "new message id = $message_id\n"; # Was useful for debugging
1178 sub unquote_rfc2047
{
1181 my $sep = qr/[ \t]+/;
1182 s
{$re_encoded_word(?
:$sep$re_encoded_word)*}{
1183 my @words = split $sep, $&;
1185 m/$re_encoded_word/;
1189 if ($encoding eq 'q' || $encoding eq 'Q') {
1192 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1194 # other encodings not supported yet
1199 return wantarray ?
($_, $charset) : $_;
1204 my $encoding = shift || 'UTF-8';
1205 s/([^-a-zA-Z0-9!*+\/])/sprintf
("=%02X", ord($1))/eg
;
1206 s/(.*)/=\?$encoding\?q\?$1\?=/;
1210 sub is_rfc2047_quoted
{
1213 $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1216 sub subject_needs_rfc2047_quoting
{
1219 return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1223 local $subject = shift;
1224 my $encoding = shift || 'UTF-8';
1226 if (subject_needs_rfc2047_quoting
($subject)) {
1227 return quote_rfc2047
($subject, $encoding);
1232 # use the simplest quoting being able to handle the recipient
1233 sub sanitize_address
{
1234 my ($recipient) = @_;
1236 # remove garbage after email address
1237 $recipient =~ s/(.*>).*$/$1/;
1239 my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
1241 if (not $recipient_name) {
1245 # if recipient_name is already quoted, do nothing
1246 if (is_rfc2047_quoted
($recipient_name)) {
1250 # remove non-escaped quotes
1251 $recipient_name =~ s/(^|[^\\])"/$1/g;
1253 # rfc2047 is needed if a non-ascii char is included
1254 if ($recipient_name =~ /[^[:ascii:]]/) {
1255 $recipient_name = quote_rfc2047
($recipient_name);
1258 # double quotes are needed if specials or CTLs are included
1259 elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
1260 $recipient_name =~ s/([\\\r])/\\$1/g;
1261 $recipient_name = qq["$recipient_name"];
1264 return "$recipient_name $recipient_addr";
1268 sub strip_garbage_one_address
{
1271 if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1272 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1273 # Foo Bar <foobar@example.com> [possibly garbage here]
1276 if ($addr =~ /^(<[^>]*>).*/) {
1277 # <foo@example.com> [possibly garbage here]
1278 # if garbage contains other addresses, they are ignored.
1281 if ($addr =~ /^([^"#,\s]*)/) {
1282 # address without quoting: remove anything after the address
1288 sub sanitize_address_list
{
1289 return (map { sanitize_address
($_) } @_);
1292 sub process_address_list
{
1293 my @addr_list = map { parse_address_line
($_) } @_;
1294 @addr_list = expand_aliases
(@addr_list);
1295 @addr_list = sanitize_address_list
(@addr_list);
1296 @addr_list = validate_address_list
(@addr_list);
1300 # Returns the local Fully Qualified Domain Name (FQDN) if available.
1302 # Tightly configured MTAa require that a caller sends a real DNS
1303 # domain name that corresponds the IP address in the HELO/EHLO
1304 # handshake. This is used to verify the connection and prevent
1305 # spammers from trying to hide their identity. If the DNS and IP don't
1306 # match, the receiving MTA may deny the connection.
1308 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
1310 # Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
1311 # Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
1313 # This maildomain*() code is based on ideas in Perl library Test::Reporter
1314 # /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
1318 return defined $domain && !($^O
eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1321 sub maildomain_net
{
1324 require Net
::Domain
;
1325 my $domain = Net
::Domain
::domainname
();
1326 $maildomain = $domain if valid_fqdn
($domain);
1331 sub maildomain_mta
{
1334 for my $host (qw(mailhost localhost)) {
1336 my $smtp = Net
::SMTP
->new($host);
1337 if (defined $smtp) {
1338 my $domain = $smtp->domain;
1341 $maildomain = $domain if valid_fqdn
($domain);
1343 last if $maildomain;
1351 return maildomain_net
() || maildomain_mta
() || 'localhost.localdomain';
1354 sub smtp_host_string
{
1355 if (defined $smtp_server_port) {
1356 return "$smtp_server:$smtp_server_port";
1358 return $smtp_server;
1362 # Returns 1 if authentication succeeded or was not necessary
1363 # (smtp_user was not specified), and 0 otherwise.
1365 sub smtp_auth_maybe
{
1366 if (!defined $smtp_authuser || $auth || (defined $smtp_auth && $smtp_auth eq "none")) {
1370 # Workaround AUTH PLAIN/LOGIN interaction defect
1371 # with Authen::SASL::Cyrus
1373 require Authen
::SASL
;
1374 Authen
::SASL
->import(qw(Perl));
1377 # Check mechanism naming as defined in:
1378 # https://tools.ietf.org/html/rfc4422#page-8
1379 if ($smtp_auth && $smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
1380 die "invalid smtp auth: '${smtp_auth}'";
1383 # TODO: Authentication may fail not because credentials were
1384 # invalid but due to other reasons, in which we should not
1385 # reject credentials.
1386 $auth = Git
::credential
({
1387 'protocol' => 'smtp',
1388 'host' => smtp_host_string
(),
1389 'username' => $smtp_authuser,
1390 # if there's no password, "git credential fill" will
1391 # give us one, otherwise it'll just pass this one.
1392 'password' => $smtp_authpass
1397 my $sasl = Authen
::SASL
->new(
1398 mechanism
=> $smtp_auth,
1400 user
=> $cred->{'username'},
1401 pass
=> $cred->{'password'},
1402 authname
=> $cred->{'username'},
1406 return !!$smtp->auth($sasl);
1409 return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
1415 sub ssl_verify_params
{
1417 require IO
::Socket
::SSL
;
1418 IO
::Socket
::SSL
->import(qw
/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1421 print STDERR
"Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1425 if (!defined $smtp_ssl_cert_path) {
1426 # use the OpenSSL defaults
1427 return (SSL_verify_mode
=> SSL_VERIFY_PEER
());
1430 if ($smtp_ssl_cert_path eq "") {
1431 return (SSL_verify_mode
=> SSL_VERIFY_NONE
());
1432 } elsif (-d
$smtp_ssl_cert_path) {
1433 return (SSL_verify_mode
=> SSL_VERIFY_PEER
(),
1434 SSL_ca_path
=> $smtp_ssl_cert_path);
1435 } elsif (-f
$smtp_ssl_cert_path) {
1436 return (SSL_verify_mode
=> SSL_VERIFY_PEER
(),
1437 SSL_ca_file
=> $smtp_ssl_cert_path);
1439 die sprintf(__
("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1443 sub file_name_is_absolute
{
1446 # msys does not grok DOS drive-prefixes
1447 if ($^O
eq 'msys') {
1448 return ($path =~ m
#^/# || $path =~ m#^[a-zA-Z]\:#)
1451 require File
::Spec
::Functions
;
1452 return File
::Spec
::Functions
::file_name_is_absolute
($path);
1456 my @recipients = unique_email_list
(@to);
1457 @cc = (grep { my $cc = extract_valid_address_or_die
($_);
1458 not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
1461 my $to = join (",\n\t", @recipients);
1462 @recipients = unique_email_list
(@recipients,@cc,@initial_bcc);
1463 @recipients = (map { extract_valid_address_or_die
($_) } @recipients);
1464 my $date = format_2822_time
($time++);
1465 my $gitversion = '@@GIT_VERSION@@';
1466 if ($gitversion =~ m/..GIT_VERSION../) {
1467 $gitversion = Git
::version
();
1470 my $cc = join(",\n\t", unique_email_list
(@cc));
1473 $ccline = "\nCc: $cc";
1475 make_message_id
() unless defined($message_id);
1477 my $header = "From: $sender
1481 Message-ID: $message_id
1484 $header .= "X-Mailer: git-send-email $gitversion\n";
1488 $header .= "In-Reply-To: $in_reply_to\n";
1489 $header .= "References: $references\n";
1492 $header .= "Reply-To: $reply_to\n";
1495 $header .= join("\n", @xh) . "\n";
1497 my $recipients_ref = \
@recipients;
1498 return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
1501 # Prepares the email, then asks the user what to do.
1503 # If the user chooses to send the email, it's sent and 1 is returned.
1504 # If the user chooses not to send the email, 0 is returned.
1505 # If the user decides they want to make further edits, -1 is returned and the
1506 # caller is expected to call send_message again after the edits are performed.
1508 # If an error occurs sending the email, this just dies.
1511 my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header
();
1512 my @recipients = @
$recipients_ref;
1514 my @sendmail_parameters = ('-i', @recipients);
1515 my $raw_from = $sender;
1516 if (defined $envelope_sender && $envelope_sender ne "auto") {
1517 $raw_from = $envelope_sender;
1519 $raw_from = extract_valid_address
($raw_from);
1520 unshift (@sendmail_parameters,
1521 '-f', $raw_from) if(defined $envelope_sender);
1523 if ($needs_confirm && !$dry_run) {
1524 print "\n$header\n";
1525 if ($needs_confirm eq "inform") {
1526 $confirm_unconfigured = 0; # squelch this message for the rest of this run
1527 $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation
1529 The Cc list above has been expanded by additional
1530 addresses found in the patch commit message. By default
1531 send-email prompts before sending whenever this occurs.
1532 This behavior is controlled by the sendemail.confirm
1533 configuration setting.
1535 For additional information, run 'git send-email --help'.
1536 To retain the current behavior, but squelch this message,
1537 run 'git config --global sendemail.confirm auto'.
1541 # TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
1542 # translation. The program will only accept English input
1544 $_ = ask
(__
("Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "),
1545 valid_re
=> qr/^(?:yes|y|no|n|edit|e|quit|q|all|a)/i,
1546 default => $ask_default);
1547 die __
("Send this email reply required") unless defined $_;
1553 cleanup_compose_files
();
1560 unshift (@sendmail_parameters, @smtp_server_options);
1563 # We don't want to send the email.
1564 } elsif (defined $sendmail_cmd || file_name_is_absolute
($smtp_server)) {
1565 my $pid = open my $sm, '|-';
1566 defined $pid or die $!;
1568 if (defined $sendmail_cmd) {
1569 exec ("sh", "-c", "$sendmail_cmd \"\$@\"", "-", @sendmail_parameters)
1572 exec ($smtp_server, @sendmail_parameters)
1576 print $sm "$header\n$message";
1577 close $sm or die $!;
1580 if (!defined $smtp_server) {
1581 die __
("The required SMTP server is not properly defined.")
1585 my $use_net_smtp_ssl = version
->parse($Net::SMTP
::VERSION
) < version
->parse("2.34");
1586 $smtp_domain ||= maildomain
();
1588 if ($smtp_encryption eq 'ssl') {
1589 $smtp_server_port ||= 465; # ssmtp
1590 require IO
::Socket
::SSL
;
1592 # Suppress "variable accessed once" warning.
1595 $IO::Socket
::SSL
::DEBUG
= 1;
1598 # Net::SMTP::SSL->new() does not forward any SSL options
1599 IO
::Socket
::SSL
::set_client_defaults
(
1600 ssl_verify_params
());
1602 if ($use_net_smtp_ssl) {
1603 require Net
::SMTP
::SSL
;
1604 $smtp ||= Net
::SMTP
::SSL
->new($smtp_server,
1605 Hello
=> $smtp_domain,
1606 Port
=> $smtp_server_port,
1607 Debug
=> $debug_net_smtp);
1610 $smtp ||= Net
::SMTP
->new($smtp_server,
1611 Hello
=> $smtp_domain,
1612 Port
=> $smtp_server_port,
1613 Debug
=> $debug_net_smtp,
1618 $smtp_server_port ||= 25;
1619 $smtp ||= Net
::SMTP
->new($smtp_server,
1620 Hello
=> $smtp_domain,
1621 Debug
=> $debug_net_smtp,
1622 Port
=> $smtp_server_port);
1623 if ($smtp_encryption eq 'tls' && $smtp) {
1624 if ($use_net_smtp_ssl) {
1625 $smtp->command('STARTTLS');
1627 if ($smtp->code != 220) {
1628 die sprintf(__
("Server does not support STARTTLS! %s"), $smtp->message);
1630 require Net
::SMTP
::SSL
;
1631 $smtp = Net
::SMTP
::SSL
->start_SSL($smtp,
1632 ssl_verify_params
())
1633 or die sprintf(__
("STARTTLS failed! %s"), IO
::Socket
::SSL
::errstr
());
1636 $smtp->starttls(ssl_verify_params
())
1637 or die sprintf(__
("STARTTLS failed! %s"), IO
::Socket
::SSL
::errstr
());
1639 # Send EHLO again to receive fresh
1640 # supported commands
1641 $smtp->hello($smtp_domain);
1646 die __
("Unable to initialize SMTP properly. Check config and use --smtp-debug."),
1647 " VALUES: server=$smtp_server ",
1648 "encryption=$smtp_encryption ",
1649 "hello=$smtp_domain",
1650 defined $smtp_server_port ?
" port=$smtp_server_port" : "";
1653 smtp_auth_maybe
or die $smtp->message;
1655 $smtp->mail( $raw_from ) or die $smtp->message;
1656 $smtp->to( @recipients ) or die $smtp->message;
1657 $smtp->data or die $smtp->message;
1658 $smtp->datasend("$header\n") or die $smtp->message;
1659 my @lines = split /^/, $message;
1660 foreach my $line (@lines) {
1661 $smtp->datasend("$line") or die $smtp->message;
1663 $smtp->dataend() or die $smtp->message;
1664 $smtp->code =~ /250|200/ or die sprintf(__
("Failed to send %s\n"), $subject).$smtp->message;
1667 printf($dry_run ? __
("Dry-Sent %s") : __
("Sent %s"), $subject);
1670 print($dry_run ? __
("Dry-OK. Log says:") : __
("OK. Log says:"));
1672 if (!defined $sendmail_cmd && !file_name_is_absolute
($smtp_server)) {
1673 print "Server: $smtp_server\n";
1674 print "MAIL FROM:<$raw_from>\n";
1675 foreach my $entry (@recipients) {
1676 print "RCPT TO:<$entry>\n";
1680 if (defined $sendmail_cmd) {
1681 $sm = $sendmail_cmd;
1686 print "Sendmail: $sm ".join(' ',@sendmail_parameters)."\n";
1688 print $header, "\n";
1690 print __
("Result: "), $smtp->code, ' ',
1691 ($smtp->message =~ /\n([^\n]+\n)$/s);
1693 print __
("Result: OK");
1701 sub pre_process_file
{
1702 my ($t, $quiet) = @_;
1704 open my $fh, "<", $t or die sprintf(__
("can't open file %s"), $t);
1707 my $sauthor = undef;
1708 my $author_encoding;
1709 my $has_content_type;
1712 my $has_mime_version;
1716 my $input_format = undef;
1718 $subject = $initial_subject;
1722 # Retrieve and unfold header fields.
1723 my @header_lines = ();
1726 push(@header_lines, $_);
1728 @header = unfold_headers
(@header_lines);
1729 # Add computed headers, if applicable.
1730 unless ($no_header_cmd || ! $header_cmd) {
1731 push @header, invoke_header_cmd
($header_cmd, $t);
1733 # Now parse the header
1736 $input_format = 'mbox';
1740 if (!defined $input_format && /^[-A-Za-z]+:\s/) {
1741 $input_format = 'mbox';
1744 if (defined $input_format && $input_format eq 'mbox') {
1745 if (/^Subject:\s+(.*)$/i) {
1748 elsif (/^From:\s+(.*)$/i) {
1749 ($author, $author_encoding) = unquote_rfc2047
($1);
1750 $sauthor = sanitize_address
($author);
1751 next if $suppress_cc{'author'};
1752 next if $suppress_cc{'self'} and $sauthor eq $sender;
1753 printf(__
("(mbox) Adding cc: %s from line '%s'\n"),
1754 $1, $_) unless $quiet;
1757 elsif (/^To:\s+(.*)$/i) {
1758 foreach my $addr (parse_address_line
($1)) {
1759 printf(__
("(mbox) Adding to: %s from line '%s'\n"),
1760 $addr, $_) unless $quiet;
1764 elsif (/^Cc:\s+(.*)$/i) {
1765 foreach my $addr (parse_address_line
($1)) {
1766 my $qaddr = unquote_rfc2047
($addr);
1767 my $saddr = sanitize_address
($qaddr);
1768 if ($saddr eq $sender) {
1769 next if ($suppress_cc{'self'});
1771 next if ($suppress_cc{'cc'});
1773 printf(__
("(mbox) Adding cc: %s from line '%s'\n"),
1774 $addr, $_) unless $quiet;
1778 elsif (/^Content-type:/i) {
1779 $has_content_type = 1;
1780 if (/charset="?([^ "]+)/) {
1781 $body_encoding = $1;
1785 elsif (/^MIME-Version/i) {
1786 $has_mime_version = 1;
1789 elsif (/^Message-ID: (.*)/i) {
1792 elsif (/^Content-Transfer-Encoding: (.*)/i) {
1793 $xfer_encoding = $1 if not defined $xfer_encoding;
1795 elsif (/^In-Reply-To: (.*)/i) {
1796 if (!$initial_in_reply_to || $thread) {
1800 elsif (/^References: (.*)/i) {
1801 if (!$initial_in_reply_to || $thread) {
1805 elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1809 # In the traditional
1810 # "send lots of email" format,
1813 # So let's support that, too.
1814 $input_format = 'lots';
1815 if (@cc == 0 && !$suppress_cc{'cc'}) {
1816 printf(__
("(non-mbox) Adding cc: %s from line '%s'\n"),
1817 $_, $_) unless $quiet;
1819 } elsif (!defined $subject) {
1824 # Now parse the message body
1827 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1829 my ($what, $c) = ($1, $2);
1830 # strip garbage for the address we'll use:
1831 $c = strip_garbage_one_address
($c);
1832 # sanitize a bit more to decide whether to suppress the address:
1833 my $sc = sanitize_address
($c);
1834 if ($sc eq $sender) {
1835 next if ($suppress_cc{'self'});
1837 if ($what =~ /^Signed-off-by$/i) {
1838 next if $suppress_cc{'sob'};
1839 } elsif ($what =~ /-by$/i) {
1840 next if $suppress_cc{'misc-by'};
1841 } elsif ($what =~ /Cc/i) {
1842 next if $suppress_cc{'bodycc'};
1845 if ($c !~ /.+@.+|<.+>/) {
1846 printf("(body) Ignoring %s from line '%s'\n",
1847 $what, $_) unless $quiet;
1851 printf(__
("(body) Adding cc: %s from line '%s'\n"),
1852 $sc, $_) unless $quiet;
1857 push @to, recipients_cmd
("to-cmd", "to", $to_cmd, $t, $quiet)
1859 push @cc, recipients_cmd
("cc-cmd", "cc", $cc_cmd, $t, $quiet)
1860 if defined $cc_cmd && !$suppress_cc{'cccmd'};
1862 if ($broken_encoding{$t} && !$has_content_type) {
1863 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1864 $has_content_type = 1;
1865 push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
1866 $body_encoding = $auto_8bit_encoding;
1869 if ($broken_encoding{$t} && !is_rfc2047_quoted
($subject)) {
1870 $subject = quote_subject
($subject, $auto_8bit_encoding);
1873 if (defined $sauthor and $sauthor ne $sender) {
1874 $message = "From: $author\n\n$message";
1875 if (defined $author_encoding) {
1876 if ($has_content_type) {
1877 if ($body_encoding eq $author_encoding) {
1878 # ok, we already have the right encoding
1881 # uh oh, we should re-encode
1885 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1886 $has_content_type = 1;
1888 "Content-Type: text/plain; charset=$author_encoding";
1892 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1893 ($message, $xfer_encoding) = apply_transfer_encoding
(
1894 $message, $xfer_encoding, $target_xfer_encoding);
1895 push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1896 unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1899 $confirm eq "always" or
1900 ($confirm =~ /^(?:auto|cc)$/ && @cc) or
1901 ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
1902 $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
1904 @to = process_address_list
(@to);
1905 @cc = process_address_list
(@cc);
1907 @to = (@initial_to, @to);
1908 @cc = (@initial_cc, @cc);
1910 if ($message_num == 1) {
1911 if (defined $cover_cc and $cover_cc) {
1914 if (defined $cover_to and $cover_to) {
1920 # Prepares the email, prompts the user, and sends it out
1921 # Returns 0 if an edit was done and the function should be called again, or 1
1922 # on the email being successfully sent out.
1926 pre_process_file
($t, $quiet);
1928 my $message_was_sent = send_message
();
1929 if ($message_was_sent == -1) {
1934 # set up for the next message
1936 if ($message_was_sent &&
1937 ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
1938 $message_num == 1)) {
1939 $in_reply_to = $message_id;
1940 if (length $references > 0) {
1941 $references .= "\n $message_id";
1943 $references = "$message_id";
1946 } elsif (!defined $initial_in_reply_to) {
1947 # --thread and --in-reply-to manage the "In-Reply-To" header and by
1948 # extension the "References" header. If these commands are not used, reset
1949 # the header values to their defaults.
1950 $in_reply_to = undef;
1953 $message_id = undef;
1955 if (defined $batch_size && $num_sent == $batch_size) {
1957 $smtp->quit if defined $smtp;
1960 sleep($relogin_delay) if defined $relogin_delay;
1966 sub initialize_modified_loop_vars
{
1967 $in_reply_to = $initial_in_reply_to;
1968 $references = $initial_in_reply_to || '';
1973 # FIFOs can only be read once, exclude them from validation.
1974 my @real_files = ();
1975 foreach my $f (@files) {
1977 push(@real_files, $f);
1981 # Run the loop once again to avoid gaps in the counter due to FIFO
1982 # arguments provided by the user.
1984 my $num_files = scalar @real_files;
1985 $ENV{GIT_SENDEMAIL_FILE_TOTAL
} = "$num_files";
1986 initialize_modified_loop_vars
();
1987 foreach my $r (@real_files) {
1988 $ENV{GIT_SENDEMAIL_FILE_COUNTER
} = "$num";
1989 pre_process_file
($r, 1);
1990 validate_patch
($r, $target_xfer_encoding);
1993 delete $ENV{GIT_SENDEMAIL_FILE_COUNTER
};
1994 delete $ENV{GIT_SENDEMAIL_FILE_TOTAL
};
1997 initialize_modified_loop_vars
();
1998 foreach my $t (@files) {
1999 while (!process_file
($t)) {
2000 # user edited the file
2004 # Execute a command and return its output lines as an array. Blank
2005 # lines which do not appear at the end of the output are reported as
2008 my ($prefix, $cmd, $file) = @_;
2010 my $seen_blank_line = 0;
2011 open my $fh, "-|", "$cmd \Q$file\E"
2012 or die sprintf(__
("(%s) Could not execute '%s'"), $prefix, $cmd);
2013 while (my $line = <$fh>) {
2014 die sprintf(__
("(%s) Malformed output from '%s'"), $prefix, $cmd)
2015 if $seen_blank_line;
2016 if ($line =~ /^$/) {
2017 $seen_blank_line = $line =~ /^$/;
2023 or die sprintf(__
("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
2027 # Process headers lines, unfolding multiline headers as defined by RFC
2029 sub unfold_headers
{
2033 if (/^\s+\S/ and @headers) {
2034 chomp($headers[$#headers]);
2036 $headers[$#headers] .= $_;
2044 # Invoke the provided CMD with FILE as an argument, which should
2045 # output RFC 2822 email headers. Fold multiline headers and return the
2046 # headers as an array.
2047 sub invoke_header_cmd
{
2048 my ($cmd, $file) = @_;
2049 my @lines = execute_cmd
("header-cmd", $header_cmd, $file);
2050 return unfold_headers
(@lines);
2053 # Execute a command (e.g. $to_cmd) to get a list of email addresses
2054 # and return a results array
2055 sub recipients_cmd
{
2056 my ($prefix, $what, $cmd, $file, $quiet) = @_;
2060 @lines = execute_cmd
($prefix, $cmd, $file);
2061 for my $address (@lines) {
2062 $address =~ s/^\s*//g;
2063 $address =~ s/\s*$//g;
2064 $address = sanitize_address
($address);
2065 next if ($address eq $sender and $suppress_cc{'self'});
2066 push @addresses, $address;
2067 printf(__
("(%s) Adding %s: %s from: '%s'\n"),
2068 $prefix, $what, $address, $cmd) unless $quiet;
2073 cleanup_compose_files
();
2075 sub cleanup_compose_files
{
2076 unlink($compose_filename, $compose_filename . ".final") if $compose;
2079 $smtp->quit if $smtp;
2081 sub apply_transfer_encoding
{
2082 my $message = shift;
2086 return ($message, $to) if ($from eq $to and $from ne '7bit');
2088 require MIME
::QuotedPrint
;
2089 require MIME
::Base64
;
2091 $message = MIME
::QuotedPrint
::decode
($message)
2092 if ($from eq 'quoted-printable');
2093 $message = MIME
::Base64
::decode
($message)
2094 if ($from eq 'base64');
2096 $to = ($message =~ /(?:.{999,}|\r)/) ?
'quoted-printable' : '8bit'
2099 die __
("cannot send message as 7bit")
2100 if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
2101 return ($message, $to)
2102 if ($to eq '7bit' or $to eq '8bit');
2103 return (MIME
::QuotedPrint
::encode
($message, "\n", 0), $to)
2104 if ($to eq 'quoted-printable');
2105 return (MIME
::Base64
::encode
($message, "\n"), $to)
2106 if ($to eq 'base64');
2107 die __
("invalid transfer encoding");
2110 sub unique_email_list
{
2114 foreach my $entry (@_) {
2115 my $clean = extract_valid_address_or_die
($entry);
2116 $seen{$clean} ||= 0;
2117 next if $seen{$clean}++;
2118 push @emails, $entry;
2123 sub validate_patch
{
2124 my ($fn, $xfer_encoding) = @_;
2127 my $hook_name = 'sendemail-validate';
2128 my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
2130 my $validate_hook = File
::Spec
->catfile($hooks_path, $hook_name);
2132 if (-x
$validate_hook) {
2134 my $target = Cwd
::abs_path
($fn);
2135 # The hook needs a correct cwd and GIT_DIR.
2136 my $cwd_save = Cwd
::getcwd
();
2137 chdir($repo->wc_path() or $repo->repo_path())
2138 or die("chdir: $!");
2139 local $ENV{"GIT_DIR"} = $repo->repo_path();
2141 my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header
();
2144 my ($header_filehandle, $header_filename) = File
::Temp
::tempfile
(
2145 TEMPLATE
=> ".gitsendemail.header.XXXXXX",
2146 DIR
=> $repo->repo_path(),
2149 print $header_filehandle $header;
2151 my @cmd = ("git", "hook", "run", "--ignore-missing",
2153 my @cmd_msg = (@cmd, "<patch>", "<header>");
2154 my @cmd_run = (@cmd, $target, $header_filename);
2155 $hook_error = system_or_msg
(\
@cmd_run, undef, "@cmd_msg");
2156 chdir($cwd_save) or die("chdir: $!");
2159 $hook_error = sprintf(
2160 __
("fatal: %s: rejected by %s hook\n%s\nwarning: no patches were sent\n"),
2161 $fn, $hook_name, $hook_error);
2166 # Any long lines will be automatically fixed if we use a suitable transfer
2168 unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
2169 open(my $fh, '<', $fn)
2170 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2171 while (my $line = <$fh>) {
2172 if (length($line) > 998) {
2173 die sprintf(__
("fatal: %s:%d is longer than 998 characters\n" .
2174 "warning: no patches were sent\n"), $fn, $.);
2182 my ($last, $lastlen, $file, $known_suffix) = @_;
2183 my ($suffix, $skip);
2186 if (defined $last &&
2187 ($lastlen < length($file)) &&
2188 (substr($file, 0, $lastlen) eq $last) &&
2189 ($suffix = substr($file, $lastlen)) !~ /^[a-z0-9]/i) {
2190 if (defined $known_suffix && $suffix eq $known_suffix) {
2191 printf(__
("Skipping %s with backup suffix '%s'.\n"), $file, $known_suffix);
2194 # TRANSLATORS: please keep "[y|N]" as is.
2195 my $answer = ask
(sprintf(__
("Do you really want to send %s? [y|N]: "), $file),
2196 valid_re
=> qr/^(?:y|n)/i,
2198 $skip = ($answer ne 'y');
2200 $known_suffix = $suffix;
2204 return ($skip, $known_suffix);
2207 sub handle_backup_files
{
2209 my ($last, $lastlen, $known_suffix, $skip, @result);
2210 for my $file (@file) {
2211 ($skip, $known_suffix) = handle_backup
($last, $lastlen,
2212 $file, $known_suffix);
2213 push @result, $file unless $skip;
2215 $lastlen = length($file);
2220 sub file_has_nonascii
{
2222 open(my $fh, '<', $fn)
2223 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2224 while (my $line = <$fh>) {
2225 return 1 if $line =~ /[^[:ascii:]]/;
2230 sub body_or_subject_has_nonascii
{
2232 open(my $fh, '<', $fn)
2233 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2234 while (my $line = <$fh>) {
2235 last if $line =~ /^$/;
2236 return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
2238 while (my $line = <$fh>) {
2239 return 1 if $line =~ /[^[:ascii:]]/;