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 my ($class, $reason) = @_;
32 return bless \
$reason, shift;
36 die "Cannot use readline on FakeTerm: $$self";
43 git send-email' [<options>] <file|directory>
44 git send-email' [<options>] <format-patch options>
45 git send-email --dump-aliases
48 --from <str> * Email From:
49 --[no-]to <str> * Email To:
50 --[no-]cc <str> * Email Cc:
51 --[no-]bcc <str> * Email Bcc:
52 --subject <str> * Email "Subject:"
53 --reply-to <str> * Email "Reply-To:"
54 --in-reply-to <str> * Email "In-Reply-To:"
55 --[no-]xmailer * Add "X-Mailer:" header (default).
56 --[no-]annotate * Review each patch that will be sent in an editor.
57 --compose * Open an editor for introduction.
58 --compose-encoding <str> * Encoding to assume for introduction.
59 --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
60 --transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
63 --envelope-sender <str> * Email envelope sender.
64 --sendmail-cmd <str> * Command to run to send email.
65 --smtp-server <str:int> * Outgoing SMTP server to use. The port
66 is optional. Default 'localhost'.
67 --smtp-server-option <str> * Outgoing SMTP server option to use.
68 --smtp-server-port <int> * Outgoing SMTP server port.
69 --smtp-user <str> * Username for SMTP-AUTH.
70 --smtp-pass <str> * Password for SMTP-AUTH; not necessary.
71 --smtp-encryption <str> * tls or ssl; anything else disables.
72 --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
73 --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
74 Pass an empty string to disable certificate
76 --smtp-domain <str> * The domain name sent to HELO/EHLO handshake
77 --smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
78 "none" to disable authentication.
79 This setting forces to use one of the listed mechanisms.
80 --no-smtp-auth Disable SMTP authentication. Shorthand for
82 --smtp-debug <0|1> * Disable, enable Net::SMTP debug.
84 --batch-size <int> * send max <int> message per connection.
85 --relogin-delay <int> * delay <int> seconds between two successive login.
86 This option can only be used with --batch-size
89 --identity <str> * Use the sendemail.<id> options.
90 --to-cmd <str> * Email To: via `<str> \$patch_path`
91 --cc-cmd <str> * Email Cc: via `<str> \$patch_path`
92 --suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
93 --[no-]cc-cover * Email Cc: addresses in the cover letter.
94 --[no-]to-cover * Email To: addresses in the cover letter.
95 --[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on.
96 --[no-]suppress-from * Send to self. Default off.
97 --[no-]chain-reply-to * Chain In-Reply-To: fields. Default off.
98 --[no-]thread * Use In-Reply-To: field. Default on.
101 --confirm <str> * Confirm recipients before sending;
102 auto, cc, compose, always, or never.
103 --quiet * Output one line of info per email.
104 --dry-run * Don't actually send the emails.
105 --[no-]validate * Perform patch sanity checks. Default on.
106 --[no-]format-patch * understand any non optional arguments as
107 `git format-patch` ones.
108 --force * Send even if safety checks would prevent it.
111 --dump-aliases * Dump configured aliases and exit.
119 grep !$seen{$_}++, @_;
122 sub completion_helper
{
123 my ($original_opts) = @_;
124 my %not_for_completion = (
125 "git-completion-helper" => undef,
128 my @send_email_opts = ();
130 foreach my $key (keys %$original_opts) {
131 unless (exists $not_for_completion{$key}) {
134 if ($key =~ /[:=][si]$/) {
135 $key =~ s/[:=][si]$//;
136 push (@send_email_opts, "--$_=") foreach (split (/\|/, $key));
138 push (@send_email_opts, "--$_") foreach (split (/\|/, $key));
143 my @format_patch_opts = split(/ /, Git
::command
('format-patch', '--git-completion-helper'));
144 my @opts = (@send_email_opts, @format_patch_opts);
145 @opts = uniq
(grep !/^$/, @opts);
146 # There's an implicit '\n' here already, no need to add an explicit one.
151 # most mail servers generate the Date: header, but not all...
152 sub format_2822_time
{
154 my @localtm = localtime($time);
155 my @gmttm = gmtime($time);
156 my $localmin = $localtm[1] + $localtm[2] * 60;
157 my $gmtmin = $gmttm[1] + $gmttm[2] * 60;
158 if ($localtm[0] != $gmttm[0]) {
159 die __
("local zone differs from GMT by a non-minute interval\n");
161 if ((($gmttm[6] + 1) % 7) == $localtm[6]) {
163 } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {
165 } elsif ($gmttm[6] != $localtm[6]) {
166 die __
("local time offset greater than or equal to 24 hours\n");
168 my $offset = $localmin - $gmtmin;
169 my $offhour = $offset / 60;
170 my $offmin = abs($offset % 60);
171 if (abs($offhour) >= 24) {
172 die __
("local time offset greater than or equal to 24 hours\n");
175 return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d",
176 qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]],
178 qw(Jan Feb Mar Apr May Jun
179 Jul Aug Sep Oct Nov Dec)[$localtm[4]],
184 ($offset >= 0) ?
'+' : '-',
194 # Regexes for RFC 2047 productions.
195 my $re_token = qr/[^][()<>@,;:\\"\/?
.= \000-\037\177-\377]+/;
196 my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
197 my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
199 # Variables we fill in automatically, or via prompting:
200 my (@to,@cc,@xh,$envelope_sender,
201 $initial_in_reply_to,$reply_to,$initial_subject,@files,
202 $author,$sender,$smtp_authpass,$annotate,$compose,$time);
203 # Things we either get from config, *or* are overridden on the
205 my ($no_cc, $no_to, $no_bcc, $no_identity);
206 my (@config_to, @getopt_to);
207 my (@config_cc, @getopt_cc);
208 my (@config_bcc, @getopt_bcc);
211 #$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
213 my $repo = eval { Git
->repository() };
214 my @repo = $repo ?
($repo) : ();
216 # Behavior modification variables
217 my ($quiet, $dry_run) = (0, 0);
219 my $compose_filename;
221 my $dump_aliases = 0;
223 # Handle interactive edition of files.
228 my ($args, $msg) = @_;
230 my $signalled = $?
& 127;
231 my $exit_code = $?
>> 8;
232 return unless $signalled or $exit_code;
234 my @sprintf_args = ($args->[0], $exit_code);
236 # Quiet the 'redundant' warning category, except we
237 # need to support down to Perl 5.8, so we can't do a
238 # "no warnings 'redundant'", since that category was
239 # introduced in perl 5.22, and asking for it will die
242 return sprintf($msg, @sprintf_args);
244 return sprintf(__
("fatal: command '%s' died with exit code %d"),
249 my $msg = system_or_msg
(@_);
254 if (!defined($editor)) {
255 $editor = Git
::command_oneline
('var', 'GIT_EDITOR');
257 my $die_msg = __
("the editor exited uncleanly, aborting everything");
258 if (defined($multiedit) && !$multiedit) {
259 system_or_die
(['sh', '-c', $editor.' "$@"', $editor, $_], $die_msg) for @_;
261 system_or_die
(['sh', '-c', $editor.' "$@"', $editor, @_], $die_msg);
265 # Variables with corresponding config settings
266 my ($suppress_from, $signed_off_by_cc);
267 my ($cover_cc, $cover_to);
268 my ($to_cmd, $cc_cmd);
269 my ($smtp_server, $smtp_server_port, @smtp_server_options);
270 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
271 my ($batch_size, $relogin_delay);
272 my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
275 my ($auto_8bit_encoding);
276 my ($compose_encoding);
278 # Variables with corresponding config settings & hardcoded defaults
279 my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
281 my $chain_reply_to = 0;
284 my $target_xfer_encoding = 'auto';
285 my $forbid_sendmail_variables = 1;
287 my %config_bool_settings = (
288 "thread" => \
$thread,
289 "chainreplyto" => \
$chain_reply_to,
290 "suppressfrom" => \
$suppress_from,
291 "signedoffbycc" => \
$signed_off_by_cc,
292 "cccover" => \
$cover_cc,
293 "tocover" => \
$cover_to,
294 "signedoffcc" => \
$signed_off_by_cc,
295 "validate" => \
$validate,
296 "multiedit" => \
$multiedit,
297 "annotate" => \
$annotate,
298 "xmailer" => \
$use_xmailer,
299 "forbidsendmailvariables" => \
$forbid_sendmail_variables,
302 my %config_settings = (
303 "smtpencryption" => \
$smtp_encryption,
304 "smtpserver" => \
$smtp_server,
305 "smtpserverport" => \
$smtp_server_port,
306 "smtpserveroption" => \
@smtp_server_options,
307 "smtpuser" => \
$smtp_authuser,
308 "smtppass" => \
$smtp_authpass,
309 "smtpdomain" => \
$smtp_domain,
310 "smtpauth" => \
$smtp_auth,
311 "smtpbatchsize" => \
$batch_size,
312 "smtprelogindelay" => \
$relogin_delay,
317 "aliasfiletype" => \
$aliasfiletype,
318 "bcc" => \
@config_bcc,
319 "suppresscc" => \
@suppress_cc,
320 "envelopesender" => \
$envelope_sender,
321 "confirm" => \
$confirm,
323 "assume8bitencoding" => \
$auto_8bit_encoding,
324 "composeencoding" => \
$compose_encoding,
325 "transferencoding" => \
$target_xfer_encoding,
326 "sendmailcmd" => \
$sendmail_cmd,
329 my %config_path_settings = (
330 "aliasesfile" => \
@alias_files,
331 "smtpsslcertpath" => \
$smtp_ssl_cert_path,
334 # Handle Uncouth Termination
337 require Term
::ANSIColor
;
338 print Term
::ANSIColor
::color
("reset"), "\n";
340 # SMTP password masked
343 # tmp files from --compose
344 if (defined $compose_filename) {
345 if (-e
$compose_filename) {
346 printf __
("'%s' contains an intermediate version ".
347 "of the email you were composing.\n"),
350 if (-e
($compose_filename . ".final")) {
351 printf __
("'%s.final' contains the composed email.\n"),
359 $SIG{TERM
} = \
&signal_handler
;
360 $SIG{INT
} = \
&signal_handler
;
362 # Read our sendemail.* config
364 my ($known_keys, $configured, $prefix) = @_;
366 foreach my $setting (keys %config_bool_settings) {
367 my $target = $config_bool_settings{$setting};
368 my $key = "$prefix.$setting";
369 next unless exists $known_keys->{$key};
370 my $v = (@
{$known_keys->{$key}} == 1 &&
371 (defined $known_keys->{$key}->[0] &&
372 $known_keys->{$key}->[0] =~ /^(?:true|false)$/s))
373 ?
$known_keys->{$key}->[0] eq 'true'
374 : Git
::config_bool
(@repo, $key);
375 next unless defined $v;
376 next if $configured->{$setting}++;
380 foreach my $setting (keys %config_path_settings) {
381 my $target = $config_path_settings{$setting};
382 my $key = "$prefix.$setting";
383 next unless exists $known_keys->{$key};
384 if (ref($target) eq "ARRAY") {
385 my @values = Git
::config_path
(@repo, $key);
387 next if $configured->{$setting}++;
391 my $v = Git
::config_path
(@repo, "$prefix.$setting");
392 next unless defined $v;
393 next if $configured->{$setting}++;
398 foreach my $setting (keys %config_settings) {
399 my $target = $config_settings{$setting};
400 my $key = "$prefix.$setting";
401 next unless exists $known_keys->{$key};
402 if (ref($target) eq "ARRAY") {
403 my @values = @
{$known_keys->{$key}};
404 @values = grep { defined } @values;
405 next if $configured->{$setting}++;
409 my $v = $known_keys->{$key}->[-1];
410 next unless defined $v;
411 next if $configured->{$setting}++;
421 my $ret = Git
::command
(
428 # We must always return ($k, $v) here, since
429 # empty config values will be just "key\0",
430 # not "key\nvalue\0".
431 my ($k, $v) = split /\n/, $_, 2;
436 # If we have no keys we're OK, otherwise re-throw
437 die $@
if $@
->value != 1;
442 # Save ourselves a lot of work of shelling out to 'git config' (it
443 # parses 'bool' etc.) by only doing so for config keys that exist.
444 my %known_config_keys;
446 my @kv = config_regexp
("^sende?mail[.]");
447 while (my ($k, $v) = splice @kv, 0, 2) {
448 push @
{$known_config_keys{$k}} => $v;
452 # sendemail.identity yields to --identity. We must parse this
453 # special-case first before the rest of the config is read.
455 my $key = "sendemail.identity";
456 $identity = Git
::config
(@repo, $key) if exists $known_config_keys{$key};
458 my %identity_options = (
459 "identity=s" => \
$identity,
460 "no-identity" => \
$no_identity,
462 my $rc = GetOptions
(%identity_options);
464 undef $identity if $no_identity;
466 # Now we know enough to read the config
469 read_config
(\
%known_config_keys, \
%configured, "sendemail.$identity") if defined $identity;
470 read_config
(\
%known_config_keys, \
%configured, "sendemail");
473 # Begin by accumulating all the variables (defined above), that we will end up
474 # needing, first, from the command line:
477 my $git_completion_helper;
478 my %dump_aliases_options = (
480 "dump-aliases" => \
$dump_aliases,
482 $rc = GetOptions
(%dump_aliases_options);
484 die __
("--dump-aliases incompatible with other options\n")
485 if !$help and $dump_aliases and @ARGV;
487 "sender|from=s" => \
$sender,
488 "in-reply-to=s" => \
$initial_in_reply_to,
489 "reply-to=s" => \
$reply_to,
490 "subject=s" => \
$initial_subject,
491 "to=s" => \
@getopt_to,
492 "to-cmd=s" => \
$to_cmd,
494 "cc=s" => \
@getopt_cc,
496 "bcc=s" => \
@getopt_bcc,
497 "no-bcc" => \
$no_bcc,
498 "chain-reply-to!" => \
$chain_reply_to,
499 "no-chain-reply-to" => sub {$chain_reply_to = 0},
500 "sendmail-cmd=s" => \
$sendmail_cmd,
501 "smtp-server=s" => \
$smtp_server,
502 "smtp-server-option=s" => \
@smtp_server_options,
503 "smtp-server-port=s" => \
$smtp_server_port,
504 "smtp-user=s" => \
$smtp_authuser,
505 "smtp-pass:s" => \
$smtp_authpass,
506 "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
507 "smtp-encryption=s" => \
$smtp_encryption,
508 "smtp-ssl-cert-path=s" => \
$smtp_ssl_cert_path,
509 "smtp-debug:i" => \
$debug_net_smtp,
510 "smtp-domain:s" => \
$smtp_domain,
511 "smtp-auth=s" => \
$smtp_auth,
512 "no-smtp-auth" => sub {$smtp_auth = 'none'},
513 "annotate!" => \
$annotate,
514 "no-annotate" => sub {$annotate = 0},
515 "compose" => \
$compose,
517 "cc-cmd=s" => \
$cc_cmd,
518 "suppress-from!" => \
$suppress_from,
519 "no-suppress-from" => sub {$suppress_from = 0},
520 "suppress-cc=s" => \
@suppress_cc,
521 "signed-off-cc|signed-off-by-cc!" => \
$signed_off_by_cc,
522 "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
523 "cc-cover|cc-cover!" => \
$cover_cc,
524 "no-cc-cover" => sub {$cover_cc = 0},
525 "to-cover|to-cover!" => \
$cover_to,
526 "no-to-cover" => sub {$cover_to = 0},
527 "confirm=s" => \
$confirm,
528 "dry-run" => \
$dry_run,
529 "envelope-sender=s" => \
$envelope_sender,
530 "thread!" => \
$thread,
531 "no-thread" => sub {$thread = 0},
532 "validate!" => \
$validate,
533 "no-validate" => sub {$validate = 0},
534 "transfer-encoding=s" => \
$target_xfer_encoding,
535 "format-patch!" => \
$format_patch,
536 "no-format-patch" => sub {$format_patch = 0},
537 "8bit-encoding=s" => \
$auto_8bit_encoding,
538 "compose-encoding=s" => \
$compose_encoding,
540 "xmailer!" => \
$use_xmailer,
541 "no-xmailer" => sub {$use_xmailer = 0},
542 "batch-size=i" => \
$batch_size,
543 "relogin-delay=i" => \
$relogin_delay,
544 "git-completion-helper" => \
$git_completion_helper,
546 $rc = GetOptions
(%options);
548 # Munge any "either config or getopt, not both" variables
549 my @initial_to = @getopt_to ?
@getopt_to : ($no_to ?
() : @config_to);
550 my @initial_cc = @getopt_cc ?
@getopt_cc : ($no_cc ?
() : @config_cc);
551 my @initial_bcc = @getopt_bcc ?
@getopt_bcc : ($no_bcc ?
() : @config_bcc);
554 my %all_options = (%options, %dump_aliases_options, %identity_options);
555 completion_helper
(\
%all_options) if $git_completion_helper;
560 if ($forbid_sendmail_variables && grep { /^sendmail/s } keys %known_config_keys) {
561 die __
("fatal: found configuration options for 'sendmail'\n" .
562 "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
563 "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
566 die __
("Cannot run git format-patch from outside a repository\n")
567 if $format_patch and not $repo;
569 die __
("`batch-size` and `relogin` must be specified together " .
570 "(via command-line or configuration option)\n")
571 if defined $relogin_delay and not defined $batch_size;
573 # 'default' encryption is none -- this only prevents a warning
574 $smtp_encryption = '' unless (defined $smtp_encryption);
576 # Set CC suppressions
579 foreach my $entry (@suppress_cc) {
580 # Please update $__git_send_email_suppresscc_options
581 # in git-completion.bash when you add new options.
582 die sprintf(__
("Unknown --suppress-cc field: '%s'\n"), $entry)
583 unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc|misc-by)$/;
584 $suppress_cc{$entry} = 1;
588 if ($suppress_cc{'all'}) {
589 foreach my $entry (qw
(cccmd cc author self sob body bodycc misc
-by
)) {
590 $suppress_cc{$entry} = 1;
592 delete $suppress_cc{'all'};
595 # If explicit old-style ones are specified, they trump --suppress-cc.
596 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
597 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
599 if ($suppress_cc{'body'}) {
600 foreach my $entry (qw
(sob bodycc misc
-by
)) {
601 $suppress_cc{$entry} = 1;
603 delete $suppress_cc{'body'};
606 # Set confirm's default value
607 my $confirm_unconfigured = !defined $confirm;
608 if ($confirm_unconfigured) {
609 $confirm = scalar %suppress_cc ?
'compose' : 'auto';
611 # Please update $__git_send_email_confirm_options in
612 # git-completion.bash when you add new options.
613 die sprintf(__
("Unknown --confirm setting: '%s'\n"), $confirm)
614 unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
616 # Debugging, print out the suppressions.
618 print "suppressions:\n";
619 foreach my $entry (keys %suppress_cc) {
620 printf " %-5s -> $suppress_cc{$entry}\n", $entry;
624 my ($repoauthor, $repocommitter);
627 my ($author, $committer);
630 return $cache{$what} if exists $cache{$what};
631 ($cache{$what}) = Git
::ident_person
(@repo, $what);
632 return $cache{$what};
634 $repoauthor = sub { $common->('author') };
635 $repocommitter = sub { $common->('committer') };
638 sub parse_address_line
{
639 require Git
::LoadCPAN
::Mail
::Address
;
640 return map { $_->format } Mail
::Address
->parse($_[0]);
644 require Text
::ParseWords
;
645 return Text
::ParseWords
::quotewords
('\s*,\s*', 1, @_);
650 sub parse_sendmail_alias
{
653 printf STDERR __
("warning: sendmail alias with quotes is not supported: %s\n"), $_;
654 } elsif (/:include:/) {
655 printf STDERR __
("warning: `:include:` not supported: %s\n"), $_;
657 printf STDERR __
("warning: `/file` or `|pipe` redirection not supported: %s\n"), $_;
658 } elsif (/^(\S+?)\s*:\s*(.+)$/) {
659 my ($alias, $addr) = ($1, $2);
660 $aliases{$alias} = [ split_addrs
($addr) ];
662 printf STDERR __
("warning: sendmail line is not recognized: %s\n"), $_;
666 sub parse_sendmail_aliases
{
671 next if /^\s*$/ || /^\s*#/;
672 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
673 parse_sendmail_alias
($s) if $s;
676 $s =~ s/\\$//; # silently tolerate stray '\' on last line
677 parse_sendmail_alias
($s) if $s;
681 # multiline formats can be supported in the future
682 mutt
=> sub { my $fh = shift; while (<$fh>) {
683 if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
684 my ($alias, $addr) = ($1, $2);
685 $addr =~ s/#.*$//; # mutt allows # comments
686 # commas delimit multiple addresses
687 my @addr = split_addrs
($addr);
689 # quotes may be escaped in the file,
690 # unescape them so we do not double-escape them later.
691 s/\\"/"/g foreach @addr;
692 $aliases{$alias} = \
@addr
694 mailrc
=> sub { my $fh = shift; while (<$fh>) {
695 if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
696 require Text
::ParseWords
;
697 # spaces delimit multiple addresses
698 $aliases{$1} = [ Text
::ParseWords
::quotewords
('\s+', 0, $2) ];
700 pine
=> sub { my $fh = shift; my $f='\t[^\t]*';
701 for (my $x = ''; defined($x); $x = $_) {
703 $x .= $1 while(defined($_ = <$fh>) && /^ +(.*)$/);
704 $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
705 $aliases{$1} = [ split_addrs
($2) ];
707 elm
=> sub { my $fh = shift;
709 if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
710 my ($alias, $addr) = ($1, $2);
711 $aliases{$alias} = [ split_addrs
($addr) ];
714 sendmail
=> \
&parse_sendmail_aliases
,
715 gnus
=> sub { my $fh = shift; while (<$fh>) {
716 if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
717 $aliases{$1} = [ $2 ];
719 # Please update _git_config() in git-completion.bash when you
723 if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
724 foreach my $file (@alias_files) {
725 open my $fh, '<', $file or die "opening $file: $!\n";
726 $parse_alias{$aliasfiletype}->($fh);
732 print "$_\n" for (sort keys %aliases);
736 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
737 # $f is a revision list specification to be passed to format-patch.
738 sub is_format_patch_arg
{
742 $repo->command('rev-parse', '--verify', '--quiet', $f);
743 if (defined($format_patch)) {
744 return $format_patch;
746 die sprintf(__
(<<EOF), $f, $f);
747 File '%s' exists but it could also be the range of commits
748 to produce patches for. Please disambiguate by...
750 * Saying "./%s" if you mean a file; or
751 * Giving --format-patch option if you mean a range.
753 } catch Git
::Error
::Command with
{
754 # Not a valid revision. Treat it as a filename.
759 # Now that all the defaults are set, process the rest of the command line
760 # arguments and collect up the files that need to be processed.
762 while (defined(my $f = shift @ARGV)) {
764 push @rev_list_opts, "--", @ARGV;
766 } elsif (-d
$f and !is_format_patch_arg
($f)) {
768 or die sprintf(__
("Failed to opendir %s: %s"), $f, $!);
771 push @files, grep { -f
$_ } map { File
::Spec
->catfile($f, $_) }
774 } elsif ((-f
$f or -p
$f) and !is_format_patch_arg
($f)) {
777 push @rev_list_opts, $f;
781 if (@rev_list_opts) {
782 die __
("Cannot run git format-patch from outside a repository\n")
785 push @files, $repo->command('format-patch', '-o', File
::Temp
::tempdir
(CLEANUP
=> 1), @rev_list_opts);
788 @files = handle_backup_files
(@files);
791 foreach my $f (@files) {
793 validate_patch
($f, $target_xfer_encoding);
800 print $_,"\n" for (@files);
803 print STDERR __
("\nNo patch files specified!\n\n");
807 sub get_patch_subject
{
809 open (my $fh, '<', $fn);
810 while (my $line = <$fh>) {
811 next unless ($line =~ /^Subject: (.*)$/);
816 die sprintf(__
("No subject line in %s?"), $fn);
820 # Note that this does not need to be secure, but we will make a small
821 # effort to have it be unique
823 $compose_filename = ($repo ?
824 File
::Temp
::tempfile
(".gitsendemail.msg.XXXXXX", DIR
=> $repo->repo_path()) :
825 File
::Temp
::tempfile
(".gitsendemail.msg.XXXXXX", DIR
=> "."))[1];
826 open my $c, ">", $compose_filename
827 or die sprintf(__
("Failed to open for writing %s: %s"), $compose_filename, $!);
830 my $tpl_sender = $sender || $repoauthor->() || $repocommitter->() || '';
831 my $tpl_subject = $initial_subject || '';
832 my $tpl_in_reply_to = $initial_in_reply_to || '';
833 my $tpl_reply_to = $reply_to || '';
835 print $c <<EOT1, Git::prefix_lines("GIT: ", __(<<EOT2)), <<EOT3;
836 From $tpl_sender # This line is ignored.
838 Lines beginning in "GIT:" will be removed.
839 Consider including an overall diffstat or table of contents
840 for the patch you are writing.
842 Clear the body content if you don't wish to send a summary.
845 Reply-To: $tpl_reply_to
846 Subject: $tpl_subject
847 In-Reply-To: $tpl_in_reply_to
851 print $c get_patch_subject($f);
856 do_edit($compose_filename, @files);
858 do_edit($compose_filename);
861 open $c, "<", $compose_filename
862 or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
864 if (!defined $compose_encoding) {
865 $compose_encoding = "UTF-8";
869 while (my $line = <$c>) {
870 next if $line =~ m/^GIT:/;
871 parse_header_line($line, \%parsed_email);
873 $parsed_email{'body'} = filter_body($c);
878 open my $c2, ">", $compose_filename . ".final"
879 or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
882 if ($parsed_email{'From'}) {
883 $sender = delete($parsed_email{'From'});
885 if ($parsed_email{'In-Reply-To'}) {
886 $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
888 if ($parsed_email{'Reply-To'}) {
889 $reply_to = delete($parsed_email{'Reply-To'});
891 if ($parsed_email{'Subject'}) {
892 $initial_subject = delete($parsed_email{'Subject'});
893 print $c2 "Subject: " .
894 quote_subject($initial_subject, $compose_encoding) .
898 if ($parsed_email{'MIME-Version'}) {
899 print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
900 "Content-Type: $parsed_email{'Content-Type'};\n",
901 "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
902 delete($parsed_email{'MIME-Version'});
903 delete($parsed_email{'Content-Type'});
904 delete($parsed_email{'Content-Transfer-Encoding'});
905 } elsif (file_has_nonascii($compose_filename)) {
906 my $content_type = (delete($parsed_email{'Content-Type'}) or
907 "text/plain; charset=$compose_encoding");
908 print $c2 "MIME-Version: 1.0\n",
909 "Content-Type: $content_type\n",
910 "Content-Transfer-Encoding: 8bit\n";
912 # Preserve unknown headers
913 foreach my $key (keys %parsed_email) {
914 next if $key eq 'body';
915 print $c2 "$key: $parsed_email{$key}";
918 if ($parsed_email{'body'}) {
919 print $c2 "\n$parsed_email{'body'}\n";
920 delete($parsed_email{'body'});
922 print __("Summary email is empty, skipping it\n");
928 } elsif ($annotate) {
934 require Term::ReadLine;
935 $ENV{"GIT_SEND_EMAIL_NOTTY"}
936 ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
937 : Term::ReadLine->new('git-send-email');
940 $term = FakeTerm->new("$@: going non-interactive");
946 my ($prompt, %arg) = @_;
947 my $valid_re = $arg{valid_re};
948 my $default = $arg{default};
949 my $confirm_only = $arg{confirm_only};
953 return defined $default ? $default : undef
954 unless defined $term->IN and defined fileno($term->IN) and
955 defined $term->OUT and defined fileno($term->OUT);
957 $resp = $term->readline($prompt);
958 if (!defined $resp) { # EOF
960 return defined $default ? $default : undef;
962 if ($resp eq '' and defined $default) {
965 if (!defined $valid_re or $resp =~ /$valid_re/) {
969 my $yesno = $term->readline(
970 # TRANSLATORS: please keep [y/N] as is.
971 sprintf(__("Are you sure you want to use <%s> [y/N]? "), $resp));
972 if (defined $yesno && $yesno =~ /y/i) {
980 sub parse_header_line {
982 my $parsed_line = shift;
983 my $addr_pat = join "|", qw(To Cc Bcc);
985 foreach (split(/\n/, $lines)) {
986 if (/^($addr_pat):\s*(.+)$/i) {
987 $parsed_line->{$1} = [ parse_address_line
($2) ];
988 } elsif (/^([^:]*):\s*(.+)\s*$/i) {
989 $parsed_line->{$1} = $2;
997 while (my $body_line = <$c>) {
998 if ($body_line !~ m/^GIT:/) {
1006 my %broken_encoding;
1008 sub file_declares_8bit_cte
{
1010 open (my $fh, '<', $fn);
1011 while (my $line = <$fh>) {
1012 last if ($line =~ /^$/);
1013 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
1019 foreach my $f (@files) {
1020 next unless (body_or_subject_has_nonascii
($f)
1021 && !file_declares_8bit_cte
($f));
1022 $broken_encoding{$f} = 1;
1025 if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
1026 print __
("The following files are 8bit, but do not declare " .
1027 "a Content-Transfer-Encoding.\n");
1028 foreach my $f (sort keys %broken_encoding) {
1031 $auto_8bit_encoding = ask
(__
("Which 8bit encoding should I declare [UTF-8]? "),
1032 valid_re
=> qr/.{4}/, confirm_only
=> 1,
1033 default => "UTF-8");
1037 for my $f (@files) {
1038 if (get_patch_subject
($f) =~ /\Q*** SUBJECT HERE ***\E/) {
1039 die sprintf(__
("Refusing to send because the patch\n\t%s\n"
1040 . "has the template subject '*** SUBJECT HERE ***'. "
1041 . "Pass --force if you really want to send.\n"), $f);
1046 if (defined $sender) {
1047 $sender =~ s/^\s+|\s+$//g;
1048 ($sender) = expand_aliases
($sender);
1050 $sender = $repoauthor->() || $repocommitter->() || '';
1053 # $sender could be an already sanitized address
1054 # (e.g. sendemail.from could be manually sanitized by user).
1055 # But it's a no-op to run sanitize_address on an already sanitized address.
1056 $sender = sanitize_address
($sender);
1058 my $to_whom = __
("To whom should the emails be sent (if anyone)?");
1060 if (!@initial_to && !defined $to_cmd) {
1061 my $to = ask
("$to_whom ",
1063 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
1064 push @initial_to, parse_address_line
($to) if defined $to; # sanitized/validated later
1068 sub expand_aliases
{
1069 return map { expand_one_alias
($_) } @_;
1072 my %EXPANDED_ALIASES;
1073 sub expand_one_alias
{
1075 if ($EXPANDED_ALIASES{$alias}) {
1076 die sprintf(__
("fatal: alias '%s' expands to itself\n"), $alias);
1078 local $EXPANDED_ALIASES{$alias} = 1;
1079 return $aliases{$alias} ? expand_aliases
(@
{$aliases{$alias}}) : $alias;
1082 @initial_to = process_address_list
(@initial_to);
1083 @initial_cc = process_address_list
(@initial_cc);
1084 @initial_bcc = process_address_list
(@initial_bcc);
1086 if ($thread && !defined $initial_in_reply_to && $prompting) {
1087 $initial_in_reply_to = ask
(
1088 __
("Message-ID to be used as In-Reply-To for the first email (if any)? "),
1090 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
1092 if (defined $initial_in_reply_to) {
1093 $initial_in_reply_to =~ s/^\s*<?//;
1094 $initial_in_reply_to =~ s/>?\s*$//;
1095 $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
1098 if (defined $reply_to) {
1099 $reply_to =~ s/^\s+|\s+$//g;
1100 ($reply_to) = expand_aliases
($reply_to);
1101 $reply_to = sanitize_address
($reply_to);
1104 if (!defined $sendmail_cmd && !defined $smtp_server) {
1105 my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
1106 push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH
};
1107 foreach (@sendmail_paths) {
1114 if (!defined $sendmail_cmd) {
1115 $smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*
1119 if ($compose && $compose > 0) {
1120 @files = ($compose_filename . ".final", @files);
1123 # Variables we set as part of the loop over files
1124 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
1125 $needs_confirm, $message_num, $ask_default);
1127 sub extract_valid_address
{
1128 my $address = shift;
1129 my $local_part_regexp = qr/[^<>"\s@]+/;
1130 my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
1132 # check for a local address:
1133 return $address if ($address =~ /^($local_part_regexp)$/);
1135 $address =~ s/^\s*<(.*)>\s*$/$1/;
1136 my $have_email_valid = eval { require Email
::Valid
; 1 };
1137 if ($have_email_valid) {
1138 return scalar Email
::Valid
->address($address);
1141 # less robust/correct than the monster regexp in Email::Valid,
1142 # but still does a 99% job, and one less dependency
1143 return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
1147 sub extract_valid_address_or_die
{
1148 my $address = shift;
1149 $address = extract_valid_address
($address);
1150 die sprintf(__
("error: unable to extract a valid address from: %s\n"), $address)
1155 sub validate_address
{
1156 my $address = shift;
1157 while (!extract_valid_address
($address)) {
1158 printf STDERR __
("error: unable to extract a valid address from: %s\n"), $address;
1159 # TRANSLATORS: Make sure to include [q] [d] [e] in your
1160 # translation. The program will only accept English input
1162 $_ = ask
(__
("What to do with this address? ([q]uit|[d]rop|[e]dit): "),
1163 valid_re
=> qr/^(?:quit|q|drop|d|edit|e)/i,
1168 cleanup_compose_files
();
1171 $address = ask
("$to_whom ",
1173 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
1178 sub validate_address_list
{
1179 return (grep { defined $_ }
1180 map { validate_address
($_) } @_);
1183 # Usually don't need to change anything below here.
1185 # we make a "fake" message id by taking the current number
1186 # of seconds since the beginning of Unix time and tacking on
1187 # a random number to the end, in case we are called quicker than
1188 # 1 second since the last time we were called.
1190 # We'll setup a template for the message id, using the "from" address:
1192 my ($message_id_stamp, $message_id_serial);
1193 sub make_message_id
{
1195 if (!defined $message_id_stamp) {
1197 $message_id_stamp = POSIX
::strftime
("%Y%m%d%H%M%S.$$", gmtime(time));
1198 $message_id_serial = 0;
1200 $message_id_serial++;
1201 $uniq = "$message_id_stamp-$message_id_serial";
1204 for ($sender, $repocommitter->(), $repoauthor->()) {
1205 $du_part = extract_valid_address
(sanitize_address
($_));
1206 last if (defined $du_part and $du_part ne '');
1208 if (not defined $du_part or $du_part eq '') {
1209 require Sys
::Hostname
;
1210 $du_part = 'user@' . Sys
::Hostname
::hostname
();
1212 my $message_id_template = "<%s-%s>";
1213 $message_id = sprintf($message_id_template, $uniq, $du_part);
1214 #print "new message id = $message_id\n"; # Was useful for debugging
1219 $time = time - scalar $#files;
1221 sub unquote_rfc2047
{
1224 my $sep = qr/[ \t]+/;
1225 s
{$re_encoded_word(?
:$sep$re_encoded_word)*}{
1226 my @words = split $sep, $&;
1228 m/$re_encoded_word/;
1232 if ($encoding eq 'q' || $encoding eq 'Q') {
1235 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1237 # other encodings not supported yet
1242 return wantarray ?
($_, $charset) : $_;
1247 my $encoding = shift || 'UTF-8';
1248 s/([^-a-zA-Z0-9!*+\/])/sprintf
("=%02X", ord($1))/eg
;
1249 s/(.*)/=\?$encoding\?q\?$1\?=/;
1253 sub is_rfc2047_quoted
{
1256 $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1259 sub subject_needs_rfc2047_quoting
{
1262 return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1266 local $subject = shift;
1267 my $encoding = shift || 'UTF-8';
1269 if (subject_needs_rfc2047_quoting
($subject)) {
1270 return quote_rfc2047
($subject, $encoding);
1275 # use the simplest quoting being able to handle the recipient
1276 sub sanitize_address
{
1277 my ($recipient) = @_;
1279 # remove garbage after email address
1280 $recipient =~ s/(.*>).*$/$1/;
1282 my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
1284 if (not $recipient_name) {
1288 # if recipient_name is already quoted, do nothing
1289 if (is_rfc2047_quoted
($recipient_name)) {
1293 # remove non-escaped quotes
1294 $recipient_name =~ s/(^|[^\\])"/$1/g;
1296 # rfc2047 is needed if a non-ascii char is included
1297 if ($recipient_name =~ /[^[:ascii:]]/) {
1298 $recipient_name = quote_rfc2047
($recipient_name);
1301 # double quotes are needed if specials or CTLs are included
1302 elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
1303 $recipient_name =~ s/([\\\r])/\\$1/g;
1304 $recipient_name = qq["$recipient_name"];
1307 return "$recipient_name $recipient_addr";
1311 sub strip_garbage_one_address
{
1314 if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1315 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1316 # Foo Bar <foobar@example.com> [possibly garbage here]
1319 if ($addr =~ /^(<[^>]*>).*/) {
1320 # <foo@example.com> [possibly garbage here]
1321 # if garbage contains other addresses, they are ignored.
1324 if ($addr =~ /^([^"#,\s]*)/) {
1325 # address without quoting: remove anything after the address
1331 sub sanitize_address_list
{
1332 return (map { sanitize_address
($_) } @_);
1335 sub process_address_list
{
1336 my @addr_list = map { parse_address_line
($_) } @_;
1337 @addr_list = expand_aliases
(@addr_list);
1338 @addr_list = sanitize_address_list
(@addr_list);
1339 @addr_list = validate_address_list
(@addr_list);
1343 # Returns the local Fully Qualified Domain Name (FQDN) if available.
1345 # Tightly configured MTAa require that a caller sends a real DNS
1346 # domain name that corresponds the IP address in the HELO/EHLO
1347 # handshake. This is used to verify the connection and prevent
1348 # spammers from trying to hide their identity. If the DNS and IP don't
1349 # match, the receiving MTA may deny the connection.
1351 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
1353 # Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
1354 # Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
1356 # This maildomain*() code is based on ideas in Perl library Test::Reporter
1357 # /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
1361 return defined $domain && !($^O
eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1364 sub maildomain_net
{
1367 require Net
::Domain
;
1368 my $domain = Net
::Domain
::domainname
();
1369 $maildomain = $domain if valid_fqdn
($domain);
1374 sub maildomain_mta
{
1377 for my $host (qw(mailhost localhost)) {
1379 my $smtp = Net
::SMTP
->new($host);
1380 if (defined $smtp) {
1381 my $domain = $smtp->domain;
1384 $maildomain = $domain if valid_fqdn
($domain);
1386 last if $maildomain;
1394 return maildomain_net
() || maildomain_mta
() || 'localhost.localdomain';
1397 sub smtp_host_string
{
1398 if (defined $smtp_server_port) {
1399 return "$smtp_server:$smtp_server_port";
1401 return $smtp_server;
1405 # Returns 1 if authentication succeeded or was not necessary
1406 # (smtp_user was not specified), and 0 otherwise.
1408 sub smtp_auth_maybe
{
1409 if (!defined $smtp_authuser || $auth || (defined $smtp_auth && $smtp_auth eq "none")) {
1413 # Workaround AUTH PLAIN/LOGIN interaction defect
1414 # with Authen::SASL::Cyrus
1416 require Authen
::SASL
;
1417 Authen
::SASL
->import(qw(Perl));
1420 # Check mechanism naming as defined in:
1421 # https://tools.ietf.org/html/rfc4422#page-8
1422 if ($smtp_auth && $smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
1423 die "invalid smtp auth: '${smtp_auth}'";
1426 # TODO: Authentication may fail not because credentials were
1427 # invalid but due to other reasons, in which we should not
1428 # reject credentials.
1429 $auth = Git
::credential
({
1430 'protocol' => 'smtp',
1431 'host' => smtp_host_string
(),
1432 'username' => $smtp_authuser,
1433 # if there's no password, "git credential fill" will
1434 # give us one, otherwise it'll just pass this one.
1435 'password' => $smtp_authpass
1440 my $sasl = Authen
::SASL
->new(
1441 mechanism
=> $smtp_auth,
1443 user
=> $cred->{'username'},
1444 pass
=> $cred->{'password'},
1445 authname
=> $cred->{'username'},
1449 return !!$smtp->auth($sasl);
1452 return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
1458 sub ssl_verify_params
{
1460 require IO
::Socket
::SSL
;
1461 IO
::Socket
::SSL
->import(qw
/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1464 print STDERR
"Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1468 if (!defined $smtp_ssl_cert_path) {
1469 # use the OpenSSL defaults
1470 return (SSL_verify_mode
=> SSL_VERIFY_PEER
());
1473 if ($smtp_ssl_cert_path eq "") {
1474 return (SSL_verify_mode
=> SSL_VERIFY_NONE
());
1475 } elsif (-d
$smtp_ssl_cert_path) {
1476 return (SSL_verify_mode
=> SSL_VERIFY_PEER
(),
1477 SSL_ca_path
=> $smtp_ssl_cert_path);
1478 } elsif (-f
$smtp_ssl_cert_path) {
1479 return (SSL_verify_mode
=> SSL_VERIFY_PEER
(),
1480 SSL_ca_file
=> $smtp_ssl_cert_path);
1482 die sprintf(__
("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1486 sub file_name_is_absolute
{
1489 # msys does not grok DOS drive-prefixes
1490 if ($^O
eq 'msys') {
1491 return ($path =~ m
#^/# || $path =~ m#^[a-zA-Z]\:#)
1494 require File
::Spec
::Functions
;
1495 return File
::Spec
::Functions
::file_name_is_absolute
($path);
1498 # Prepares the email, then asks the user what to do.
1500 # If the user chooses to send the email, it's sent and 1 is returned.
1501 # If the user chooses not to send the email, 0 is returned.
1502 # If the user decides they want to make further edits, -1 is returned and the
1503 # caller is expected to call send_message again after the edits are performed.
1505 # If an error occurs sending the email, this just dies.
1508 my @recipients = unique_email_list
(@to);
1509 @cc = (grep { my $cc = extract_valid_address_or_die
($_);
1510 not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
1513 my $to = join (",\n\t", @recipients);
1514 @recipients = unique_email_list
(@recipients,@cc,@initial_bcc);
1515 @recipients = (map { extract_valid_address_or_die
($_) } @recipients);
1516 my $date = format_2822_time
($time++);
1517 my $gitversion = '@@GIT_VERSION@@';
1518 if ($gitversion =~ m/..GIT_VERSION../) {
1519 $gitversion = Git
::version
();
1522 my $cc = join(",\n\t", unique_email_list
(@cc));
1525 $ccline = "\nCc: $cc";
1527 make_message_id
() unless defined($message_id);
1529 my $header = "From: $sender
1533 Message-Id: $message_id
1536 $header .= "X-Mailer: git-send-email $gitversion\n";
1540 $header .= "In-Reply-To: $in_reply_to\n";
1541 $header .= "References: $references\n";
1544 $header .= "Reply-To: $reply_to\n";
1547 $header .= join("\n", @xh) . "\n";
1550 my @sendmail_parameters = ('-i', @recipients);
1551 my $raw_from = $sender;
1552 if (defined $envelope_sender && $envelope_sender ne "auto") {
1553 $raw_from = $envelope_sender;
1555 $raw_from = extract_valid_address
($raw_from);
1556 unshift (@sendmail_parameters,
1557 '-f', $raw_from) if(defined $envelope_sender);
1559 if ($needs_confirm && !$dry_run) {
1560 print "\n$header\n";
1561 if ($needs_confirm eq "inform") {
1562 $confirm_unconfigured = 0; # squelch this message for the rest of this run
1563 $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation
1565 The Cc list above has been expanded by additional
1566 addresses found in the patch commit message. By default
1567 send-email prompts before sending whenever this occurs.
1568 This behavior is controlled by the sendemail.confirm
1569 configuration setting.
1571 For additional information, run 'git send-email --help'.
1572 To retain the current behavior, but squelch this message,
1573 run 'git config --global sendemail.confirm auto'.
1577 # TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
1578 # translation. The program will only accept English input
1580 $_ = ask
(__
("Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "),
1581 valid_re
=> qr/^(?:yes|y|no|n|edit|e|quit|q|all|a)/i,
1582 default => $ask_default);
1583 die __
("Send this email reply required") unless defined $_;
1589 cleanup_compose_files
();
1596 unshift (@sendmail_parameters, @smtp_server_options);
1599 # We don't want to send the email.
1600 } elsif (defined $sendmail_cmd || file_name_is_absolute
($smtp_server)) {
1601 my $pid = open my $sm, '|-';
1602 defined $pid or die $!;
1604 if (defined $sendmail_cmd) {
1605 exec ("sh", "-c", "$sendmail_cmd \"\$@\"", "-", @sendmail_parameters)
1608 exec ($smtp_server, @sendmail_parameters)
1612 print $sm "$header\n$message";
1613 close $sm or die $!;
1616 if (!defined $smtp_server) {
1617 die __
("The required SMTP server is not properly defined.")
1621 my $use_net_smtp_ssl = version
->parse($Net::SMTP
::VERSION
) < version
->parse("2.34");
1622 $smtp_domain ||= maildomain
();
1624 if ($smtp_encryption eq 'ssl') {
1625 $smtp_server_port ||= 465; # ssmtp
1626 require IO
::Socket
::SSL
;
1628 # Suppress "variable accessed once" warning.
1631 $IO::Socket
::SSL
::DEBUG
= 1;
1634 # Net::SMTP::SSL->new() does not forward any SSL options
1635 IO
::Socket
::SSL
::set_client_defaults
(
1636 ssl_verify_params
());
1638 if ($use_net_smtp_ssl) {
1639 require Net
::SMTP
::SSL
;
1640 $smtp ||= Net
::SMTP
::SSL
->new($smtp_server,
1641 Hello
=> $smtp_domain,
1642 Port
=> $smtp_server_port,
1643 Debug
=> $debug_net_smtp);
1646 $smtp ||= Net
::SMTP
->new($smtp_server,
1647 Hello
=> $smtp_domain,
1648 Port
=> $smtp_server_port,
1649 Debug
=> $debug_net_smtp,
1654 $smtp_server_port ||= 25;
1655 $smtp ||= Net
::SMTP
->new($smtp_server,
1656 Hello
=> $smtp_domain,
1657 Debug
=> $debug_net_smtp,
1658 Port
=> $smtp_server_port);
1659 if ($smtp_encryption eq 'tls' && $smtp) {
1660 if ($use_net_smtp_ssl) {
1661 $smtp->command('STARTTLS');
1663 if ($smtp->code != 220) {
1664 die sprintf(__
("Server does not support STARTTLS! %s"), $smtp->message);
1666 require Net
::SMTP
::SSL
;
1667 $smtp = Net
::SMTP
::SSL
->start_SSL($smtp,
1668 ssl_verify_params
())
1669 or die sprintf(__
("STARTTLS failed! %s"), IO
::Socket
::SSL
::errstr
());
1672 $smtp->starttls(ssl_verify_params
())
1673 or die sprintf(__
("STARTTLS failed! %s"), IO
::Socket
::SSL
::errstr
());
1675 # Send EHLO again to receive fresh
1676 # supported commands
1677 $smtp->hello($smtp_domain);
1682 die __
("Unable to initialize SMTP properly. Check config and use --smtp-debug."),
1683 " VALUES: server=$smtp_server ",
1684 "encryption=$smtp_encryption ",
1685 "hello=$smtp_domain",
1686 defined $smtp_server_port ?
" port=$smtp_server_port" : "";
1689 smtp_auth_maybe
or die $smtp->message;
1691 $smtp->mail( $raw_from ) or die $smtp->message;
1692 $smtp->to( @recipients ) or die $smtp->message;
1693 $smtp->data or die $smtp->message;
1694 $smtp->datasend("$header\n") or die $smtp->message;
1695 my @lines = split /^/, $message;
1696 foreach my $line (@lines) {
1697 $smtp->datasend("$line") or die $smtp->message;
1699 $smtp->dataend() or die $smtp->message;
1700 $smtp->code =~ /250|200/ or die sprintf(__
("Failed to send %s\n"), $subject).$smtp->message;
1703 printf($dry_run ? __
("Dry-Sent %s\n") : __
("Sent %s\n"), $subject);
1705 print($dry_run ? __
("Dry-OK. Log says:\n") : __
("OK. Log says:\n"));
1706 if (!defined $sendmail_cmd && !file_name_is_absolute
($smtp_server)) {
1707 print "Server: $smtp_server\n";
1708 print "MAIL FROM:<$raw_from>\n";
1709 foreach my $entry (@recipients) {
1710 print "RCPT TO:<$entry>\n";
1714 if (defined $sendmail_cmd) {
1715 $sm = $sendmail_cmd;
1720 print "Sendmail: $sm ".join(' ',@sendmail_parameters)."\n";
1722 print $header, "\n";
1724 print __
("Result: "), $smtp->code, ' ',
1725 ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
1727 print __
("Result: OK\n");
1734 $in_reply_to = $initial_in_reply_to;
1735 $references = $initial_in_reply_to || '';
1738 # Prepares the email, prompts the user, sends it out
1739 # Returns 0 if an edit was done and the function should be called again, or 1
1744 open my $fh, "<", $t or die sprintf(__
("can't open file %s"), $t);
1747 my $sauthor = undef;
1748 my $author_encoding;
1749 my $has_content_type;
1752 my $has_mime_version;
1756 my $input_format = undef;
1758 $subject = $initial_subject;
1761 # First unfold multiline header fields
1764 if (/^\s+\S/ and @header) {
1765 chomp($header[$#header]);
1767 $header[$#header] .= $_;
1772 # Now parse the header
1775 $input_format = 'mbox';
1779 if (!defined $input_format && /^[-A-Za-z]+:\s/) {
1780 $input_format = 'mbox';
1783 if (defined $input_format && $input_format eq 'mbox') {
1784 if (/^Subject:\s+(.*)$/i) {
1787 elsif (/^From:\s+(.*)$/i) {
1788 ($author, $author_encoding) = unquote_rfc2047
($1);
1789 $sauthor = sanitize_address
($author);
1790 next if $suppress_cc{'author'};
1791 next if $suppress_cc{'self'} and $sauthor eq $sender;
1792 printf(__
("(mbox) Adding cc: %s from line '%s'\n"),
1793 $1, $_) unless $quiet;
1796 elsif (/^To:\s+(.*)$/i) {
1797 foreach my $addr (parse_address_line
($1)) {
1798 printf(__
("(mbox) Adding to: %s from line '%s'\n"),
1799 $addr, $_) unless $quiet;
1803 elsif (/^Cc:\s+(.*)$/i) {
1804 foreach my $addr (parse_address_line
($1)) {
1805 my $qaddr = unquote_rfc2047
($addr);
1806 my $saddr = sanitize_address
($qaddr);
1807 if ($saddr eq $sender) {
1808 next if ($suppress_cc{'self'});
1810 next if ($suppress_cc{'cc'});
1812 printf(__
("(mbox) Adding cc: %s from line '%s'\n"),
1813 $addr, $_) unless $quiet;
1817 elsif (/^Content-type:/i) {
1818 $has_content_type = 1;
1819 if (/charset="?([^ "]+)/) {
1820 $body_encoding = $1;
1824 elsif (/^MIME-Version/i) {
1825 $has_mime_version = 1;
1828 elsif (/^Message-Id: (.*)/i) {
1831 elsif (/^Content-Transfer-Encoding: (.*)/i) {
1832 $xfer_encoding = $1 if not defined $xfer_encoding;
1834 elsif (/^In-Reply-To: (.*)/i) {
1835 if (!$initial_in_reply_to || $thread) {
1839 elsif (/^References: (.*)/i) {
1840 if (!$initial_in_reply_to || $thread) {
1844 elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1848 # In the traditional
1849 # "send lots of email" format,
1852 # So let's support that, too.
1853 $input_format = 'lots';
1854 if (@cc == 0 && !$suppress_cc{'cc'}) {
1855 printf(__
("(non-mbox) Adding cc: %s from line '%s'\n"),
1856 $_, $_) unless $quiet;
1858 } elsif (!defined $subject) {
1863 # Now parse the message body
1866 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1868 my ($what, $c) = ($1, $2);
1869 # strip garbage for the address we'll use:
1870 $c = strip_garbage_one_address
($c);
1871 # sanitize a bit more to decide whether to suppress the address:
1872 my $sc = sanitize_address
($c);
1873 if ($sc eq $sender) {
1874 next if ($suppress_cc{'self'});
1876 if ($what =~ /^Signed-off-by$/i) {
1877 next if $suppress_cc{'sob'};
1878 } elsif ($what =~ /-by$/i) {
1879 next if $suppress_cc{'misc-by'};
1880 } elsif ($what =~ /Cc/i) {
1881 next if $suppress_cc{'bodycc'};
1884 if ($c !~ /.+@.+|<.+>/) {
1885 printf("(body) Ignoring %s from line '%s'\n",
1886 $what, $_) unless $quiet;
1890 printf(__
("(body) Adding cc: %s from line '%s'\n"),
1891 $c, $_) unless $quiet;
1896 push @to, recipients_cmd
("to-cmd", "to", $to_cmd, $t)
1898 push @cc, recipients_cmd
("cc-cmd", "cc", $cc_cmd, $t)
1899 if defined $cc_cmd && !$suppress_cc{'cccmd'};
1901 if ($broken_encoding{$t} && !$has_content_type) {
1902 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1903 $has_content_type = 1;
1904 push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
1905 $body_encoding = $auto_8bit_encoding;
1908 if ($broken_encoding{$t} && !is_rfc2047_quoted
($subject)) {
1909 $subject = quote_subject
($subject, $auto_8bit_encoding);
1912 if (defined $sauthor and $sauthor ne $sender) {
1913 $message = "From: $author\n\n$message";
1914 if (defined $author_encoding) {
1915 if ($has_content_type) {
1916 if ($body_encoding eq $author_encoding) {
1917 # ok, we already have the right encoding
1920 # uh oh, we should re-encode
1924 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1925 $has_content_type = 1;
1927 "Content-Type: text/plain; charset=$author_encoding";
1931 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1932 ($message, $xfer_encoding) = apply_transfer_encoding
(
1933 $message, $xfer_encoding, $target_xfer_encoding);
1934 push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1935 unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1938 $confirm eq "always" or
1939 ($confirm =~ /^(?:auto|cc)$/ && @cc) or
1940 ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
1941 $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
1943 @to = process_address_list
(@to);
1944 @cc = process_address_list
(@cc);
1946 @to = (@initial_to, @to);
1947 @cc = (@initial_cc, @cc);
1949 if ($message_num == 1) {
1950 if (defined $cover_cc and $cover_cc) {
1953 if (defined $cover_to and $cover_to) {
1958 my $message_was_sent = send_message
();
1959 if ($message_was_sent == -1) {
1964 # set up for the next message
1966 if ($message_was_sent &&
1967 ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
1968 $message_num == 1)) {
1969 $in_reply_to = $message_id;
1970 if (length $references > 0) {
1971 $references .= "\n $message_id";
1973 $references = "$message_id";
1976 } elsif (!defined $initial_in_reply_to) {
1977 # --thread and --in-reply-to manage the "In-Reply-To" header and by
1978 # extension the "References" header. If these commands are not used, reset
1979 # the header values to their defaults.
1980 $in_reply_to = undef;
1983 $message_id = undef;
1985 if (defined $batch_size && $num_sent == $batch_size) {
1987 $smtp->quit if defined $smtp;
1990 sleep($relogin_delay) if defined $relogin_delay;
1996 foreach my $t (@files) {
1997 while (!process_file
($t)) {
1998 # user edited the file
2002 # Execute a command (e.g. $to_cmd) to get a list of email addresses
2003 # and return a results array
2004 sub recipients_cmd
{
2005 my ($prefix, $what, $cmd, $file) = @_;
2008 open my $fh, "-|", "$cmd \Q$file\E"
2009 or die sprintf(__
("(%s) Could not execute '%s'"), $prefix, $cmd);
2010 while (my $address = <$fh>) {
2011 $address =~ s/^\s*//g;
2012 $address =~ s/\s*$//g;
2013 $address = sanitize_address
($address);
2014 next if ($address eq $sender and $suppress_cc{'self'});
2015 push @addresses, $address;
2016 printf(__
("(%s) Adding %s: %s from: '%s'\n"),
2017 $prefix, $what, $address, $cmd) unless $quiet;
2020 or die sprintf(__
("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
2024 cleanup_compose_files
();
2026 sub cleanup_compose_files
{
2027 unlink($compose_filename, $compose_filename . ".final") if $compose;
2030 $smtp->quit if $smtp;
2032 sub apply_transfer_encoding
{
2033 my $message = shift;
2037 return ($message, $to) if ($from eq $to and $from ne '7bit');
2039 require MIME
::QuotedPrint
;
2040 require MIME
::Base64
;
2042 $message = MIME
::QuotedPrint
::decode
($message)
2043 if ($from eq 'quoted-printable');
2044 $message = MIME
::Base64
::decode
($message)
2045 if ($from eq 'base64');
2047 $to = ($message =~ /(?:.{999,}|\r)/) ?
'quoted-printable' : '8bit'
2050 die __
("cannot send message as 7bit")
2051 if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
2052 return ($message, $to)
2053 if ($to eq '7bit' or $to eq '8bit');
2054 return (MIME
::QuotedPrint
::encode
($message, "\n", 0), $to)
2055 if ($to eq 'quoted-printable');
2056 return (MIME
::Base64
::encode
($message, "\n"), $to)
2057 if ($to eq 'base64');
2058 die __
("invalid transfer encoding");
2061 sub unique_email_list
{
2065 foreach my $entry (@_) {
2066 my $clean = extract_valid_address_or_die
($entry);
2067 $seen{$clean} ||= 0;
2068 next if $seen{$clean}++;
2069 push @emails, $entry;
2074 sub validate_patch
{
2075 my ($fn, $xfer_encoding) = @_;
2078 my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
2080 my $validate_hook = File
::Spec
->catfile($hooks_path,
2081 'sendemail-validate');
2083 if (-x
$validate_hook) {
2085 my $target = Cwd
::abs_path
($fn);
2086 # The hook needs a correct cwd and GIT_DIR.
2087 my $cwd_save = Cwd
::getcwd
();
2088 chdir($repo->wc_path() or $repo->repo_path())
2089 or die("chdir: $!");
2090 local $ENV{"GIT_DIR"} = $repo->repo_path();
2091 $hook_error = system_or_msg
([$validate_hook, $target]);
2092 chdir($cwd_save) or die("chdir: $!");
2095 die sprintf(__
("fatal: %s: rejected by sendemail-validate hook\n" .
2097 "warning: no patches were sent\n"), $fn, $hook_error);
2101 # Any long lines will be automatically fixed if we use a suitable transfer
2103 unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
2104 open(my $fh, '<', $fn)
2105 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2106 while (my $line = <$fh>) {
2107 if (length($line) > 998) {
2108 die sprintf(__
("fatal: %s:%d is longer than 998 characters\n" .
2109 "warning: no patches were sent\n"), $fn, $.);
2117 my ($last, $lastlen, $file, $known_suffix) = @_;
2118 my ($suffix, $skip);
2121 if (defined $last &&
2122 ($lastlen < length($file)) &&
2123 (substr($file, 0, $lastlen) eq $last) &&
2124 ($suffix = substr($file, $lastlen)) !~ /^[a-z0-9]/i) {
2125 if (defined $known_suffix && $suffix eq $known_suffix) {
2126 printf(__
("Skipping %s with backup suffix '%s'.\n"), $file, $known_suffix);
2129 # TRANSLATORS: please keep "[y|N]" as is.
2130 my $answer = ask
(sprintf(__
("Do you really want to send %s? [y|N]: "), $file),
2131 valid_re
=> qr/^(?:y|n)/i,
2133 $skip = ($answer ne 'y');
2135 $known_suffix = $suffix;
2139 return ($skip, $known_suffix);
2142 sub handle_backup_files
{
2144 my ($last, $lastlen, $known_suffix, $skip, @result);
2145 for my $file (@file) {
2146 ($skip, $known_suffix) = handle_backup
($last, $lastlen,
2147 $file, $known_suffix);
2148 push @result, $file unless $skip;
2150 $lastlen = length($file);
2155 sub file_has_nonascii
{
2157 open(my $fh, '<', $fn)
2158 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2159 while (my $line = <$fh>) {
2160 return 1 if $line =~ /[^[:ascii:]]/;
2165 sub body_or_subject_has_nonascii
{
2167 open(my $fh, '<', $fn)
2168 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2169 while (my $line = <$fh>) {
2170 last if $line =~ /^$/;
2171 return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
2173 while (my $line = <$fh>) {
2174 return 1 if $line =~ /[^[:ascii:]]/;