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) : ();
22 use POSIX qw
/strftime/;
27 use File
::Temp qw
/ tempdir tempfile /;
28 use File
::Spec
::Functions
qw(catdir catfile);
29 use Git
::LoadCPAN
::Error
qw(:try);
30 use Cwd
qw(abs_path cwd);
35 use Git
::LoadCPAN
::Mail
::Address
;
37 Getopt
::Long
::Configure qw
/ pass_through /;
41 my ($class, $reason) = @_;
42 return bless \
$reason, shift;
46 die "Cannot use readline on FakeTerm: $$self";
53 git send-email [options] <file | directory | rev-list options >
54 git send-email --dump-aliases
57 --from <str> * Email From:
58 --[no-]to <str> * Email To:
59 --[no-]cc <str> * Email Cc:
60 --[no-]bcc <str> * Email Bcc:
61 --subject <str> * Email "Subject:"
62 --reply-to <str> * Email "Reply-To:"
63 --in-reply-to <str> * Email "In-Reply-To:"
64 --[no-]xmailer * Add "X-Mailer:" header (default).
65 --[no-]annotate * Review each patch that will be sent in an editor.
66 --compose * Open an editor for introduction.
67 --compose-encoding <str> * Encoding to assume for introduction.
68 --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
69 --transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
72 --envelope-sender <str> * Email envelope sender.
73 --smtp-server <str:int> * Outgoing SMTP server to use. The port
74 is optional. Default 'localhost'.
75 --smtp-server-option <str> * Outgoing SMTP server option to use.
76 --smtp-server-port <int> * Outgoing SMTP server port.
77 --smtp-user <str> * Username for SMTP-AUTH.
78 --smtp-pass <str> * Password for SMTP-AUTH; not necessary.
79 --smtp-encryption <str> * tls or ssl; anything else disables.
80 --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
81 --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
82 Pass an empty string to disable certificate
84 --smtp-domain <str> * The domain name sent to HELO/EHLO handshake
85 --smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
86 "none" to disable authentication.
87 This setting forces to use one of the listed mechanisms.
88 --no-smtp-auth Disable SMTP authentication. Shorthand for
90 --smtp-debug <0|1> * Disable, enable Net::SMTP debug.
92 --batch-size <int> * send max <int> message per connection.
93 --relogin-delay <int> * delay <int> seconds between two successive login.
94 This option can only be used with --batch-size
97 --identity <str> * Use the sendemail.<id> options.
98 --to-cmd <str> * Email To: via `<str> \$patch_path`
99 --cc-cmd <str> * Email Cc: via `<str> \$patch_path`
100 --suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
101 --[no-]cc-cover * Email Cc: addresses in the cover letter.
102 --[no-]to-cover * Email To: addresses in the cover letter.
103 --[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on.
104 --[no-]suppress-from * Send to self. Default off.
105 --[no-]chain-reply-to * Chain In-Reply-To: fields. Default off.
106 --[no-]thread * Use In-Reply-To: field. Default on.
109 --confirm <str> * Confirm recipients before sending;
110 auto, cc, compose, always, or never.
111 --quiet * Output one line of info per email.
112 --dry-run * Don't actually send the emails.
113 --[no-]validate * Perform patch sanity checks. Default on.
114 --[no-]format-patch * understand any non optional arguments as
115 `git format-patch` ones.
116 --force * Send even if safety checks would prevent it.
119 --dump-aliases * Dump configured aliases and exit.
125 sub completion_helper
{
126 print Git
::command
('format-patch', '--git-completion-helper');
130 # most mail servers generate the Date: header, but not all...
131 sub format_2822_time
{
133 my @localtm = localtime($time);
134 my @gmttm = gmtime($time);
135 my $localmin = $localtm[1] + $localtm[2] * 60;
136 my $gmtmin = $gmttm[1] + $gmttm[2] * 60;
137 if ($localtm[0] != $gmttm[0]) {
138 die __
("local zone differs from GMT by a non-minute interval\n");
140 if ((($gmttm[6] + 1) % 7) == $localtm[6]) {
142 } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {
144 } elsif ($gmttm[6] != $localtm[6]) {
145 die __
("local time offset greater than or equal to 24 hours\n");
147 my $offset = $localmin - $gmtmin;
148 my $offhour = $offset / 60;
149 my $offmin = abs($offset % 60);
150 if (abs($offhour) >= 24) {
151 die __
("local time offset greater than or equal to 24 hours\n");
154 return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d",
155 qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]],
157 qw(Jan Feb Mar Apr May Jun
158 Jul Aug Sep Oct Nov Dec)[$localtm[4]],
163 ($offset >= 0) ?
'+' : '-',
169 my $have_email_valid = eval { require Email
::Valid
; 1 };
174 # Regexes for RFC 2047 productions.
175 my $re_token = qr/[^][()<>@,;:\\"\/?
.= \000-\037\177-\377]+/;
176 my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
177 my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
179 # Variables we fill in automatically, or via prompting:
180 my (@to,@cc,@xh,$envelope_sender,
181 $initial_in_reply_to,$reply_to,$initial_subject,@files,
182 $author,$sender,$smtp_authpass,$annotate,$compose,$time);
183 # Things we either get from config, *or* are overridden on the
185 my ($no_cc, $no_to, $no_bcc, $no_identity);
186 my (@config_to, @getopt_to);
187 my (@config_cc, @getopt_cc);
188 my (@config_bcc, @getopt_bcc);
191 #$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
193 my $repo = eval { Git
->repository() };
194 my @repo = $repo ?
($repo) : ();
196 $ENV{"GIT_SEND_EMAIL_NOTTY"}
197 ? new Term
::ReadLine
'git-send-email', \
*STDIN
, \
*STDOUT
198 : new Term
::ReadLine
'git-send-email';
201 $term = new FakeTerm
"$@: going non-interactive";
204 # Behavior modification variables
205 my ($quiet, $dry_run) = (0, 0);
207 my $compose_filename;
209 my $dump_aliases = 0;
211 # Handle interactive edition of files.
216 my ($args, $msg) = @_;
218 my $signalled = $?
& 127;
219 my $exit_code = $?
>> 8;
220 return unless $signalled or $exit_code;
222 my @sprintf_args = ($args->[0], $exit_code);
224 # Quiet the 'redundant' warning category, except we
225 # need to support down to Perl 5.8, so we can't do a
226 # "no warnings 'redundant'", since that category was
227 # introduced in perl 5.22, and asking for it will die
230 return sprintf($msg, @sprintf_args);
232 return sprintf(__
("fatal: command '%s' died with exit code %d"),
237 my $msg = system_or_msg
(@_);
242 if (!defined($editor)) {
243 $editor = Git
::command_oneline
('var', 'GIT_EDITOR');
245 my $die_msg = __
("the editor exited uncleanly, aborting everything");
246 if (defined($multiedit) && !$multiedit) {
247 system_or_die
(['sh', '-c', $editor.' "$@"', $editor, $_], $die_msg) for @_;
249 system_or_die
(['sh', '-c', $editor.' "$@"', $editor, @_], $die_msg);
253 # Variables with corresponding config settings
254 my ($suppress_from, $signed_off_by_cc);
255 my ($cover_cc, $cover_to);
256 my ($to_cmd, $cc_cmd);
257 my ($smtp_server, $smtp_server_port, @smtp_server_options);
258 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
259 my ($batch_size, $relogin_delay);
260 my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
263 my ($auto_8bit_encoding);
264 my ($compose_encoding);
265 # Variables with corresponding config settings & hardcoded defaults
266 my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
268 my $chain_reply_to = 0;
271 my $target_xfer_encoding = 'auto';
272 my $forbid_sendmail_variables = 1;
274 my %config_bool_settings = (
275 "thread" => \
$thread,
276 "chainreplyto" => \
$chain_reply_to,
277 "suppressfrom" => \
$suppress_from,
278 "signedoffbycc" => \
$signed_off_by_cc,
279 "cccover" => \
$cover_cc,
280 "tocover" => \
$cover_to,
281 "signedoffcc" => \
$signed_off_by_cc,
282 "validate" => \
$validate,
283 "multiedit" => \
$multiedit,
284 "annotate" => \
$annotate,
285 "xmailer" => \
$use_xmailer,
286 "forbidsendmailvariables" => \
$forbid_sendmail_variables,
289 my %config_settings = (
290 "smtpserver" => \
$smtp_server,
291 "smtpserverport" => \
$smtp_server_port,
292 "smtpserveroption" => \
@smtp_server_options,
293 "smtpuser" => \
$smtp_authuser,
294 "smtppass" => \
$smtp_authpass,
295 "smtpdomain" => \
$smtp_domain,
296 "smtpauth" => \
$smtp_auth,
297 "smtpbatchsize" => \
$batch_size,
298 "smtprelogindelay" => \
$relogin_delay,
303 "aliasfiletype" => \
$aliasfiletype,
304 "bcc" => \
@config_bcc,
305 "suppresscc" => \
@suppress_cc,
306 "envelopesender" => \
$envelope_sender,
307 "confirm" => \
$confirm,
309 "assume8bitencoding" => \
$auto_8bit_encoding,
310 "composeencoding" => \
$compose_encoding,
311 "transferencoding" => \
$target_xfer_encoding,
314 my %config_path_settings = (
315 "aliasesfile" => \
@alias_files,
316 "smtpsslcertpath" => \
$smtp_ssl_cert_path,
319 # Handle Uncouth Termination
323 print color
("reset"), "\n";
325 # SMTP password masked
328 # tmp files from --compose
329 if (defined $compose_filename) {
330 if (-e
$compose_filename) {
331 printf __
("'%s' contains an intermediate version ".
332 "of the email you were composing.\n"),
335 if (-e
($compose_filename . ".final")) {
336 printf __
("'%s.final' contains the composed email.\n"),
344 $SIG{TERM
} = \
&signal_handler
;
345 $SIG{INT
} = \
&signal_handler
;
347 # Read our sendemail.* config
349 my ($configured, $prefix) = @_;
351 foreach my $setting (keys %config_bool_settings) {
352 my $target = $config_bool_settings{$setting};
353 my $v = Git
::config_bool
(@repo, "$prefix.$setting");
354 next unless defined $v;
355 next if $configured->{$setting}++;
359 foreach my $setting (keys %config_path_settings) {
360 my $target = $config_path_settings{$setting};
361 if (ref($target) eq "ARRAY") {
362 my @values = Git
::config_path
(@repo, "$prefix.$setting");
364 next if $configured->{$setting}++;
368 my $v = Git
::config_path
(@repo, "$prefix.$setting");
369 next unless defined $v;
370 next if $configured->{$setting}++;
375 foreach my $setting (keys %config_settings) {
376 my $target = $config_settings{$setting};
377 if (ref($target) eq "ARRAY") {
378 my @values = Git
::config
(@repo, "$prefix.$setting");
380 next if $configured->{$setting}++;
384 my $v = Git
::config
(@repo, "$prefix.$setting");
385 next unless defined $v;
386 next if $configured->{$setting}++;
391 if (!defined $smtp_encryption) {
392 my $setting = "$prefix.smtpencryption";
393 my $enc = Git
::config
(@repo, $setting);
394 return unless defined $enc;
395 return if $configured->{$setting}++;
397 $smtp_encryption = $enc;
398 } elsif (Git
::config_bool
(@repo, "$prefix.smtpssl")) {
399 $smtp_encryption = 'ssl';
404 # sendemail.identity yields to --identity. We must parse this
405 # special-case first before the rest of the config is read.
406 $identity = Git
::config
(@repo, "sendemail.identity");
408 "identity=s" => \
$identity,
409 "no-identity" => \
$no_identity,
412 undef $identity if $no_identity;
414 # Now we know enough to read the config
417 read_config
(\
%configured, "sendemail.$identity") if defined $identity;
418 read_config
(\
%configured, "sendemail");
421 # Begin by accumulating all the variables (defined above), that we will end up
422 # needing, first, from the command line:
425 my $git_completion_helper;
426 $rc = GetOptions
("h" => \
$help,
427 "dump-aliases" => \
$dump_aliases);
429 die __
("--dump-aliases incompatible with other options\n")
430 if !$help and $dump_aliases and @ARGV;
432 "sender|from=s" => \
$sender,
433 "in-reply-to=s" => \
$initial_in_reply_to,
434 "reply-to=s" => \
$reply_to,
435 "subject=s" => \
$initial_subject,
436 "to=s" => \
@getopt_to,
437 "to-cmd=s" => \
$to_cmd,
439 "cc=s" => \
@getopt_cc,
441 "bcc=s" => \
@getopt_bcc,
442 "no-bcc" => \
$no_bcc,
443 "chain-reply-to!" => \
$chain_reply_to,
444 "no-chain-reply-to" => sub {$chain_reply_to = 0},
445 "smtp-server=s" => \
$smtp_server,
446 "smtp-server-option=s" => \
@smtp_server_options,
447 "smtp-server-port=s" => \
$smtp_server_port,
448 "smtp-user=s" => \
$smtp_authuser,
449 "smtp-pass:s" => \
$smtp_authpass,
450 "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
451 "smtp-encryption=s" => \
$smtp_encryption,
452 "smtp-ssl-cert-path=s" => \
$smtp_ssl_cert_path,
453 "smtp-debug:i" => \
$debug_net_smtp,
454 "smtp-domain:s" => \
$smtp_domain,
455 "smtp-auth=s" => \
$smtp_auth,
456 "no-smtp-auth" => sub {$smtp_auth = 'none'},
457 "annotate!" => \
$annotate,
458 "no-annotate" => sub {$annotate = 0},
459 "compose" => \
$compose,
461 "cc-cmd=s" => \
$cc_cmd,
462 "suppress-from!" => \
$suppress_from,
463 "no-suppress-from" => sub {$suppress_from = 0},
464 "suppress-cc=s" => \
@suppress_cc,
465 "signed-off-cc|signed-off-by-cc!" => \
$signed_off_by_cc,
466 "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
467 "cc-cover|cc-cover!" => \
$cover_cc,
468 "no-cc-cover" => sub {$cover_cc = 0},
469 "to-cover|to-cover!" => \
$cover_to,
470 "no-to-cover" => sub {$cover_to = 0},
471 "confirm=s" => \
$confirm,
472 "dry-run" => \
$dry_run,
473 "envelope-sender=s" => \
$envelope_sender,
474 "thread!" => \
$thread,
475 "no-thread" => sub {$thread = 0},
476 "validate!" => \
$validate,
477 "no-validate" => sub {$validate = 0},
478 "transfer-encoding=s" => \
$target_xfer_encoding,
479 "format-patch!" => \
$format_patch,
480 "no-format-patch" => sub {$format_patch = 0},
481 "8bit-encoding=s" => \
$auto_8bit_encoding,
482 "compose-encoding=s" => \
$compose_encoding,
484 "xmailer!" => \
$use_xmailer,
485 "no-xmailer" => sub {$use_xmailer = 0},
486 "batch-size=i" => \
$batch_size,
487 "relogin-delay=i" => \
$relogin_delay,
488 "git-completion-helper" => \
$git_completion_helper,
491 # Munge any "either config or getopt, not both" variables
492 my @initial_to = @getopt_to ?
@getopt_to : ($no_to ?
() : @config_to);
493 my @initial_cc = @getopt_cc ?
@getopt_cc : ($no_cc ?
() : @config_cc);
494 my @initial_bcc = @getopt_bcc ?
@getopt_bcc : ($no_bcc ?
() : @config_bcc);
497 completion_helper
() if $git_completion_helper;
502 if ($forbid_sendmail_variables && (scalar Git
::config_regexp
("^sendmail[.]")) != 0) {
503 die __
("fatal: found configuration options for 'sendmail'\n" .
504 "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
505 "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
508 die __
("Cannot run git format-patch from outside a repository\n")
509 if $format_patch and not $repo;
511 die __
("`batch-size` and `relogin` must be specified together " .
512 "(via command-line or configuration option)\n")
513 if defined $relogin_delay and not defined $batch_size;
515 # 'default' encryption is none -- this only prevents a warning
516 $smtp_encryption = '' unless (defined $smtp_encryption);
518 # Set CC suppressions
521 foreach my $entry (@suppress_cc) {
522 # Please update $__git_send_email_suppresscc_options
523 # in git-completion.bash when you add new options.
524 die sprintf(__
("Unknown --suppress-cc field: '%s'\n"), $entry)
525 unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc|misc-by)$/;
526 $suppress_cc{$entry} = 1;
530 if ($suppress_cc{'all'}) {
531 foreach my $entry (qw
(cccmd cc author self sob body bodycc misc
-by
)) {
532 $suppress_cc{$entry} = 1;
534 delete $suppress_cc{'all'};
537 # If explicit old-style ones are specified, they trump --suppress-cc.
538 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
539 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
541 if ($suppress_cc{'body'}) {
542 foreach my $entry (qw
(sob bodycc misc
-by
)) {
543 $suppress_cc{$entry} = 1;
545 delete $suppress_cc{'body'};
548 # Set confirm's default value
549 my $confirm_unconfigured = !defined $confirm;
550 if ($confirm_unconfigured) {
551 $confirm = scalar %suppress_cc ?
'compose' : 'auto';
553 # Please update $__git_send_email_confirm_options in
554 # git-completion.bash when you add new options.
555 die sprintf(__
("Unknown --confirm setting: '%s'\n"), $confirm)
556 unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
558 # Debugging, print out the suppressions.
560 print "suppressions:\n";
561 foreach my $entry (keys %suppress_cc) {
562 printf " %-5s -> $suppress_cc{$entry}\n", $entry;
566 my ($repoauthor, $repocommitter);
567 ($repoauthor) = Git
::ident_person
(@repo, 'author');
568 ($repocommitter) = Git
::ident_person
(@repo, 'committer');
570 sub parse_address_line
{
571 return map { $_->format } Mail
::Address
->parse($_[0]);
575 return quotewords
('\s*,\s*', 1, @_);
580 sub parse_sendmail_alias
{
583 printf STDERR __
("warning: sendmail alias with quotes is not supported: %s\n"), $_;
584 } elsif (/:include:/) {
585 printf STDERR __
("warning: `:include:` not supported: %s\n"), $_;
587 printf STDERR __
("warning: `/file` or `|pipe` redirection not supported: %s\n"), $_;
588 } elsif (/^(\S+?)\s*:\s*(.+)$/) {
589 my ($alias, $addr) = ($1, $2);
590 $aliases{$alias} = [ split_addrs
($addr) ];
592 printf STDERR __
("warning: sendmail line is not recognized: %s\n"), $_;
596 sub parse_sendmail_aliases
{
601 next if /^\s*$/ || /^\s*#/;
602 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
603 parse_sendmail_alias
($s) if $s;
606 $s =~ s/\\$//; # silently tolerate stray '\' on last line
607 parse_sendmail_alias
($s) if $s;
611 # multiline formats can be supported in the future
612 mutt
=> sub { my $fh = shift; while (<$fh>) {
613 if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
614 my ($alias, $addr) = ($1, $2);
615 $addr =~ s/#.*$//; # mutt allows # comments
616 # commas delimit multiple addresses
617 my @addr = split_addrs
($addr);
619 # quotes may be escaped in the file,
620 # unescape them so we do not double-escape them later.
621 s/\\"/"/g foreach @addr;
622 $aliases{$alias} = \
@addr
624 mailrc
=> sub { my $fh = shift; while (<$fh>) {
625 if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
626 # spaces delimit multiple addresses
627 $aliases{$1} = [ quotewords
('\s+', 0, $2) ];
629 pine
=> sub { my $fh = shift; my $f='\t[^\t]*';
630 for (my $x = ''; defined($x); $x = $_) {
632 $x .= $1 while(defined($_ = <$fh>) && /^ +(.*)$/);
633 $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
634 $aliases{$1} = [ split_addrs
($2) ];
636 elm
=> sub { my $fh = shift;
638 if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
639 my ($alias, $addr) = ($1, $2);
640 $aliases{$alias} = [ split_addrs
($addr) ];
643 sendmail
=> \
&parse_sendmail_aliases
,
644 gnus
=> sub { my $fh = shift; while (<$fh>) {
645 if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
646 $aliases{$1} = [ $2 ];
648 # Please update _git_config() in git-completion.bash when you
652 if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
653 foreach my $file (@alias_files) {
654 open my $fh, '<', $file or die "opening $file: $!\n";
655 $parse_alias{$aliasfiletype}->($fh);
661 print "$_\n" for (sort keys %aliases);
665 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
666 # $f is a revision list specification to be passed to format-patch.
667 sub is_format_patch_arg
{
671 $repo->command('rev-parse', '--verify', '--quiet', $f);
672 if (defined($format_patch)) {
673 return $format_patch;
675 die sprintf(__
<<EOF, $f, $f);
676 File '%s' exists but it could also be the range of commits
677 to produce patches for. Please disambiguate by...
679 * Saying "./%s" if you mean a file; or
680 * Giving --format-patch option if you mean a range.
682 } catch Git
::Error
::Command with
{
683 # Not a valid revision. Treat it as a filename.
688 # Now that all the defaults are set, process the rest of the command line
689 # arguments and collect up the files that need to be processed.
691 while (defined(my $f = shift @ARGV)) {
693 push @rev_list_opts, "--", @ARGV;
695 } elsif (-d
$f and !is_format_patch_arg
($f)) {
697 or die sprintf(__
("Failed to opendir %s: %s"), $f, $!);
699 push @files, grep { -f
$_ } map { catfile
($f, $_) }
702 } elsif ((-f
$f or -p
$f) and !is_format_patch_arg
($f)) {
705 push @rev_list_opts, $f;
709 if (@rev_list_opts) {
710 die __
("Cannot run git format-patch from outside a repository\n")
712 push @files, $repo->command('format-patch', '-o', tempdir
(CLEANUP
=> 1), @rev_list_opts);
715 @files = handle_backup_files
(@files);
718 foreach my $f (@files) {
720 validate_patch
($f, $target_xfer_encoding);
727 print $_,"\n" for (@files);
730 print STDERR __
("\nNo patch files specified!\n\n");
734 sub get_patch_subject
{
736 open (my $fh, '<', $fn);
737 while (my $line = <$fh>) {
738 next unless ($line =~ /^Subject: (.*)$/);
743 die sprintf(__
("No subject line in %s?"), $fn);
747 # Note that this does not need to be secure, but we will make a small
748 # effort to have it be unique
749 $compose_filename = ($repo ?
750 tempfile
(".gitsendemail.msg.XXXXXX", DIR
=> $repo->repo_path()) :
751 tempfile
(".gitsendemail.msg.XXXXXX", DIR
=> "."))[1];
752 open my $c, ">", $compose_filename
753 or die sprintf(__
("Failed to open for writing %s: %s"), $compose_filename, $!);
756 my $tpl_sender = $sender || $repoauthor || $repocommitter || '';
757 my $tpl_subject = $initial_subject || '';
758 my $tpl_in_reply_to = $initial_in_reply_to || '';
759 my $tpl_reply_to = $reply_to || '';
761 print $c <<EOT1, Git::prefix_lines("GIT: ", __ <<EOT2), <<EOT3;
762 From $tpl_sender # This line is ignored.
764 Lines beginning in "GIT:" will be removed.
765 Consider including an overall diffstat or table of contents
766 for the patch you are writing.
768 Clear the body content if you don't wish to send a summary.
771 Reply-To: $tpl_reply_to
772 Subject: $tpl_subject
773 In-Reply-To: $tpl_in_reply_to
777 print $c get_patch_subject($f);
782 do_edit($compose_filename, @files);
784 do_edit($compose_filename);
787 open $c, "<", $compose_filename
788 or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
790 if (!defined $compose_encoding) {
791 $compose_encoding = "UTF-8";
795 while (my $line = <$c>) {
796 next if $line =~ m/^GIT:/;
797 parse_header_line($line, \%parsed_email);
799 $parsed_email{'body'} = filter_body($c);
804 open my $c2, ">", $compose_filename . ".final"
805 or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
808 if ($parsed_email{'From'}) {
809 $sender = delete($parsed_email{'From'});
811 if ($parsed_email{'In-Reply-To'}) {
812 $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
814 if ($parsed_email{'Reply-To'}) {
815 $reply_to = delete($parsed_email{'Reply-To'});
817 if ($parsed_email{'Subject'}) {
818 $initial_subject = delete($parsed_email{'Subject'});
819 print $c2 "Subject: " .
820 quote_subject($initial_subject, $compose_encoding) .
824 if ($parsed_email{'MIME-Version'}) {
825 print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
826 "Content-Type: $parsed_email{'Content-Type'};\n",
827 "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
828 delete($parsed_email{'MIME-Version'});
829 delete($parsed_email{'Content-Type'});
830 delete($parsed_email{'Content-Transfer-Encoding'});
831 } elsif (file_has_nonascii($compose_filename)) {
832 my $content_type = (delete($parsed_email{'Content-Type'}) or
833 "text/plain; charset=$compose_encoding");
834 print $c2 "MIME-Version: 1.0\n",
835 "Content-Type: $content_type\n",
836 "Content-Transfer-Encoding: 8bit\n";
838 # Preserve unknown headers
839 foreach my $key (keys %parsed_email) {
840 next if $key eq 'body';
841 print $c2 "$key: $parsed_email{$key}";
844 if ($parsed_email{'body'}) {
845 print $c2 "\n$parsed_email{'body'}\n";
846 delete($parsed_email{'body'});
848 print __("Summary email is empty, skipping it\n");
854 } elsif ($annotate) {
859 my ($prompt, %arg) = @_;
860 my $valid_re = $arg{valid_re};
861 my $default = $arg{default};
862 my $confirm_only = $arg{confirm_only};
865 return defined $default ? $default : undef
866 unless defined $term->IN and defined fileno($term->IN) and
867 defined $term->OUT and defined fileno($term->OUT);
869 $resp = $term->readline($prompt);
870 if (!defined $resp) { # EOF
872 return defined $default ? $default : undef;
874 if ($resp eq '' and defined $default) {
877 if (!defined $valid_re or $resp =~ /$valid_re/) {
881 my $yesno = $term->readline(
882 # TRANSLATORS: please keep [y/N] as is.
883 sprintf(__("Are you sure you want to use <%s> [y/N]? "), $resp));
884 if (defined $yesno && $yesno =~ /y/i) {
892 sub parse_header_line {
894 my $parsed_line = shift;
895 my $addr_pat = join "|", qw(To Cc Bcc);
897 foreach (split(/\n/, $lines)) {
898 if (/^($addr_pat):\s*(.+)$/i) {
899 $parsed_line->{$1} = [ parse_address_line
($2) ];
900 } elsif (/^([^:]*):\s*(.+)\s*$/i) {
901 $parsed_line->{$1} = $2;
909 while (my $body_line = <$c>) {
910 if ($body_line !~ m/^GIT:/) {
920 sub file_declares_8bit_cte
{
922 open (my $fh, '<', $fn);
923 while (my $line = <$fh>) {
924 last if ($line =~ /^$/);
925 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
931 foreach my $f (@files) {
932 next unless (body_or_subject_has_nonascii
($f)
933 && !file_declares_8bit_cte
($f));
934 $broken_encoding{$f} = 1;
937 if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
938 print __
("The following files are 8bit, but do not declare " .
939 "a Content-Transfer-Encoding.\n");
940 foreach my $f (sort keys %broken_encoding) {
943 $auto_8bit_encoding = ask
(__
("Which 8bit encoding should I declare [UTF-8]? "),
944 valid_re
=> qr/.{4}/, confirm_only
=> 1,
950 if (get_patch_subject
($f) =~ /\Q*** SUBJECT HERE ***\E/) {
951 die sprintf(__
("Refusing to send because the patch\n\t%s\n"
952 . "has the template subject '*** SUBJECT HERE ***'. "
953 . "Pass --force if you really want to send.\n"), $f);
958 if (defined $sender) {
959 $sender =~ s/^\s+|\s+$//g;
960 ($sender) = expand_aliases
($sender);
962 $sender = $repoauthor || $repocommitter || '';
965 # $sender could be an already sanitized address
966 # (e.g. sendemail.from could be manually sanitized by user).
967 # But it's a no-op to run sanitize_address on an already sanitized address.
968 $sender = sanitize_address
($sender);
970 my $to_whom = __
("To whom should the emails be sent (if anyone)?");
972 if (!@initial_to && !defined $to_cmd) {
973 my $to = ask
("$to_whom ",
975 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
976 push @initial_to, parse_address_line
($to) if defined $to; # sanitized/validated later
981 return map { expand_one_alias
($_) } @_;
984 my %EXPANDED_ALIASES;
985 sub expand_one_alias
{
987 if ($EXPANDED_ALIASES{$alias}) {
988 die sprintf(__
("fatal: alias '%s' expands to itself\n"), $alias);
990 local $EXPANDED_ALIASES{$alias} = 1;
991 return $aliases{$alias} ? expand_aliases
(@
{$aliases{$alias}}) : $alias;
994 @initial_to = process_address_list
(@initial_to);
995 @initial_cc = process_address_list
(@initial_cc);
996 @initial_bcc = process_address_list
(@initial_bcc);
998 if ($thread && !defined $initial_in_reply_to && $prompting) {
999 $initial_in_reply_to = ask
(
1000 __
("Message-ID to be used as In-Reply-To for the first email (if any)? "),
1002 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
1004 if (defined $initial_in_reply_to) {
1005 $initial_in_reply_to =~ s/^\s*<?//;
1006 $initial_in_reply_to =~ s/>?\s*$//;
1007 $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
1010 if (defined $reply_to) {
1011 $reply_to =~ s/^\s+|\s+$//g;
1012 ($reply_to) = expand_aliases
($reply_to);
1013 $reply_to = sanitize_address
($reply_to);
1016 if (!defined $smtp_server) {
1017 my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
1018 push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH
};
1019 foreach (@sendmail_paths) {
1025 $smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
1028 if ($compose && $compose > 0) {
1029 @files = ($compose_filename . ".final", @files);
1032 # Variables we set as part of the loop over files
1033 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
1034 $needs_confirm, $message_num, $ask_default);
1036 sub extract_valid_address
{
1037 my $address = shift;
1038 my $local_part_regexp = qr/[^<>"\s@]+/;
1039 my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
1041 # check for a local address:
1042 return $address if ($address =~ /^($local_part_regexp)$/);
1044 $address =~ s/^\s*<(.*)>\s*$/$1/;
1045 if ($have_email_valid) {
1046 return scalar Email
::Valid
->address($address);
1049 # less robust/correct than the monster regexp in Email::Valid,
1050 # but still does a 99% job, and one less dependency
1051 return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
1055 sub extract_valid_address_or_die
{
1056 my $address = shift;
1057 $address = extract_valid_address
($address);
1058 die sprintf(__
("error: unable to extract a valid address from: %s\n"), $address)
1063 sub validate_address
{
1064 my $address = shift;
1065 while (!extract_valid_address
($address)) {
1066 printf STDERR __
("error: unable to extract a valid address from: %s\n"), $address;
1067 # TRANSLATORS: Make sure to include [q] [d] [e] in your
1068 # translation. The program will only accept English input
1070 $_ = ask
(__
("What to do with this address? ([q]uit|[d]rop|[e]dit): "),
1071 valid_re
=> qr/^(?:quit|q|drop|d|edit|e)/i,
1076 cleanup_compose_files
();
1079 $address = ask
("$to_whom ",
1081 valid_re
=> qr/\@.*\./, confirm_only
=> 1);
1086 sub validate_address_list
{
1087 return (grep { defined $_ }
1088 map { validate_address
($_) } @_);
1091 # Usually don't need to change anything below here.
1093 # we make a "fake" message id by taking the current number
1094 # of seconds since the beginning of Unix time and tacking on
1095 # a random number to the end, in case we are called quicker than
1096 # 1 second since the last time we were called.
1098 # We'll setup a template for the message id, using the "from" address:
1100 my ($message_id_stamp, $message_id_serial);
1101 sub make_message_id
{
1103 if (!defined $message_id_stamp) {
1104 $message_id_stamp = strftime
("%Y%m%d%H%M%S.$$", gmtime(time));
1105 $message_id_serial = 0;
1107 $message_id_serial++;
1108 $uniq = "$message_id_stamp-$message_id_serial";
1111 for ($sender, $repocommitter, $repoauthor) {
1112 $du_part = extract_valid_address
(sanitize_address
($_));
1113 last if (defined $du_part and $du_part ne '');
1115 if (not defined $du_part or $du_part eq '') {
1116 require Sys
::Hostname
;
1117 $du_part = 'user@' . Sys
::Hostname
::hostname
();
1119 my $message_id_template = "<%s-%s>";
1120 $message_id = sprintf($message_id_template, $uniq, $du_part);
1121 #print "new message id = $message_id\n"; # Was useful for debugging
1126 $time = time - scalar $#files;
1128 sub unquote_rfc2047
{
1131 my $sep = qr/[ \t]+/;
1132 s
{$re_encoded_word(?
:$sep$re_encoded_word)*}{
1133 my @words = split $sep, $&;
1135 m/$re_encoded_word/;
1139 if ($encoding eq 'q' || $encoding eq 'Q') {
1142 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1144 # other encodings not supported yet
1149 return wantarray ?
($_, $charset) : $_;
1154 my $encoding = shift || 'UTF-8';
1155 s/([^-a-zA-Z0-9!*+\/])/sprintf
("=%02X", ord($1))/eg
;
1156 s/(.*)/=\?$encoding\?q\?$1\?=/;
1160 sub is_rfc2047_quoted
{
1163 $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1166 sub subject_needs_rfc2047_quoting
{
1169 return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1173 local $subject = shift;
1174 my $encoding = shift || 'UTF-8';
1176 if (subject_needs_rfc2047_quoting
($subject)) {
1177 return quote_rfc2047
($subject, $encoding);
1182 # use the simplest quoting being able to handle the recipient
1183 sub sanitize_address
{
1184 my ($recipient) = @_;
1186 # remove garbage after email address
1187 $recipient =~ s/(.*>).*$/$1/;
1189 my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
1191 if (not $recipient_name) {
1195 # if recipient_name is already quoted, do nothing
1196 if (is_rfc2047_quoted
($recipient_name)) {
1200 # remove non-escaped quotes
1201 $recipient_name =~ s/(^|[^\\])"/$1/g;
1203 # rfc2047 is needed if a non-ascii char is included
1204 if ($recipient_name =~ /[^[:ascii:]]/) {
1205 $recipient_name = quote_rfc2047
($recipient_name);
1208 # double quotes are needed if specials or CTLs are included
1209 elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
1210 $recipient_name =~ s/([\\\r])/\\$1/g;
1211 $recipient_name = qq["$recipient_name"];
1214 return "$recipient_name $recipient_addr";
1218 sub strip_garbage_one_address
{
1221 if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1222 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1223 # Foo Bar <foobar@example.com> [possibly garbage here]
1226 if ($addr =~ /^(<[^>]*>).*/) {
1227 # <foo@example.com> [possibly garbage here]
1228 # if garbage contains other addresses, they are ignored.
1231 if ($addr =~ /^([^"#,\s]*)/) {
1232 # address without quoting: remove anything after the address
1238 sub sanitize_address_list
{
1239 return (map { sanitize_address
($_) } @_);
1242 sub process_address_list
{
1243 my @addr_list = map { parse_address_line
($_) } @_;
1244 @addr_list = expand_aliases
(@addr_list);
1245 @addr_list = sanitize_address_list
(@addr_list);
1246 @addr_list = validate_address_list
(@addr_list);
1250 # Returns the local Fully Qualified Domain Name (FQDN) if available.
1252 # Tightly configured MTAa require that a caller sends a real DNS
1253 # domain name that corresponds the IP address in the HELO/EHLO
1254 # handshake. This is used to verify the connection and prevent
1255 # spammers from trying to hide their identity. If the DNS and IP don't
1256 # match, the receiving MTA may deny the connection.
1258 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
1260 # Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
1261 # Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
1263 # This maildomain*() code is based on ideas in Perl library Test::Reporter
1264 # /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
1268 return defined $domain && !($^O
eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1271 sub maildomain_net
{
1274 my $domain = Net
::Domain
::domainname
();
1275 $maildomain = $domain if valid_fqdn
($domain);
1280 sub maildomain_mta
{
1283 for my $host (qw(mailhost localhost)) {
1284 my $smtp = Net
::SMTP
->new($host);
1285 if (defined $smtp) {
1286 my $domain = $smtp->domain;
1289 $maildomain = $domain if valid_fqdn
($domain);
1291 last if $maildomain;
1299 return maildomain_net
() || maildomain_mta
() || 'localhost.localdomain';
1302 sub smtp_host_string
{
1303 if (defined $smtp_server_port) {
1304 return "$smtp_server:$smtp_server_port";
1306 return $smtp_server;
1310 # Returns 1 if authentication succeeded or was not necessary
1311 # (smtp_user was not specified), and 0 otherwise.
1313 sub smtp_auth_maybe
{
1314 if (!defined $smtp_authuser || $auth || (defined $smtp_auth && $smtp_auth eq "none")) {
1318 # Workaround AUTH PLAIN/LOGIN interaction defect
1319 # with Authen::SASL::Cyrus
1321 require Authen
::SASL
;
1322 Authen
::SASL
->import(qw(Perl));
1325 # Check mechanism naming as defined in:
1326 # https://tools.ietf.org/html/rfc4422#page-8
1327 if ($smtp_auth && $smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
1328 die "invalid smtp auth: '${smtp_auth}'";
1331 # TODO: Authentication may fail not because credentials were
1332 # invalid but due to other reasons, in which we should not
1333 # reject credentials.
1334 $auth = Git
::credential
({
1335 'protocol' => 'smtp',
1336 'host' => smtp_host_string
(),
1337 'username' => $smtp_authuser,
1338 # if there's no password, "git credential fill" will
1339 # give us one, otherwise it'll just pass this one.
1340 'password' => $smtp_authpass
1345 my $sasl = Authen
::SASL
->new(
1346 mechanism
=> $smtp_auth,
1348 user
=> $cred->{'username'},
1349 pass
=> $cred->{'password'},
1350 authname
=> $cred->{'username'},
1354 return !!$smtp->auth($sasl);
1357 return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
1363 sub ssl_verify_params
{
1365 require IO
::Socket
::SSL
;
1366 IO
::Socket
::SSL
->import(qw
/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1369 print STDERR
"Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1373 if (!defined $smtp_ssl_cert_path) {
1374 # use the OpenSSL defaults
1375 return (SSL_verify_mode
=> SSL_VERIFY_PEER
());
1378 if ($smtp_ssl_cert_path eq "") {
1379 return (SSL_verify_mode
=> SSL_VERIFY_NONE
());
1380 } elsif (-d
$smtp_ssl_cert_path) {
1381 return (SSL_verify_mode
=> SSL_VERIFY_PEER
(),
1382 SSL_ca_path
=> $smtp_ssl_cert_path);
1383 } elsif (-f
$smtp_ssl_cert_path) {
1384 return (SSL_verify_mode
=> SSL_VERIFY_PEER
(),
1385 SSL_ca_file
=> $smtp_ssl_cert_path);
1387 die sprintf(__
("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1391 sub file_name_is_absolute
{
1394 # msys does not grok DOS drive-prefixes
1395 if ($^O
eq 'msys') {
1396 return ($path =~ m
#^/# || $path =~ m#^[a-zA-Z]\:#)
1399 require File
::Spec
::Functions
;
1400 return File
::Spec
::Functions
::file_name_is_absolute
($path);
1403 # Prepares the email, then asks the user what to do.
1405 # If the user chooses to send the email, it's sent and 1 is returned.
1406 # If the user chooses not to send the email, 0 is returned.
1407 # If the user decides they want to make further edits, -1 is returned and the
1408 # caller is expected to call send_message again after the edits are performed.
1410 # If an error occurs sending the email, this just dies.
1413 my @recipients = unique_email_list
(@to);
1414 @cc = (grep { my $cc = extract_valid_address_or_die
($_);
1415 not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
1418 my $to = join (",\n\t", @recipients);
1419 @recipients = unique_email_list
(@recipients,@cc,@initial_bcc);
1420 @recipients = (map { extract_valid_address_or_die
($_) } @recipients);
1421 my $date = format_2822_time
($time++);
1422 my $gitversion = '@@GIT_VERSION@@';
1423 if ($gitversion =~ m/..GIT_VERSION../) {
1424 $gitversion = Git
::version
();
1427 my $cc = join(",\n\t", unique_email_list
(@cc));
1430 $ccline = "\nCc: $cc";
1432 make_message_id
() unless defined($message_id);
1434 my $header = "From: $sender
1438 Message-Id: $message_id
1441 $header .= "X-Mailer: git-send-email $gitversion\n";
1445 $header .= "In-Reply-To: $in_reply_to\n";
1446 $header .= "References: $references\n";
1449 $header .= "Reply-To: $reply_to\n";
1452 $header .= join("\n", @xh) . "\n";
1455 my @sendmail_parameters = ('-i', @recipients);
1456 my $raw_from = $sender;
1457 if (defined $envelope_sender && $envelope_sender ne "auto") {
1458 $raw_from = $envelope_sender;
1460 $raw_from = extract_valid_address
($raw_from);
1461 unshift (@sendmail_parameters,
1462 '-f', $raw_from) if(defined $envelope_sender);
1464 if ($needs_confirm && !$dry_run) {
1465 print "\n$header\n";
1466 if ($needs_confirm eq "inform") {
1467 $confirm_unconfigured = 0; # squelch this message for the rest of this run
1468 $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation
1470 The Cc list above has been expanded by additional
1471 addresses found in the patch commit message. By default
1472 send-email prompts before sending whenever this occurs.
1473 This behavior is controlled by the sendemail.confirm
1474 configuration setting.
1476 For additional information, run 'git send-email --help'.
1477 To retain the current behavior, but squelch this message,
1478 run 'git config --global sendemail.confirm auto'.
1482 # TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
1483 # translation. The program will only accept English input
1485 $_ = ask
(__
("Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "),
1486 valid_re
=> qr/^(?:yes|y|no|n|edit|e|quit|q|all|a)/i,
1487 default => $ask_default);
1488 die __
("Send this email reply required") unless defined $_;
1494 cleanup_compose_files
();
1501 unshift (@sendmail_parameters, @smtp_server_options);
1504 # We don't want to send the email.
1505 } elsif (file_name_is_absolute
($smtp_server)) {
1506 my $pid = open my $sm, '|-';
1507 defined $pid or die $!;
1509 exec($smtp_server, @sendmail_parameters) or die $!;
1511 print $sm "$header\n$message";
1512 close $sm or die $!;
1515 if (!defined $smtp_server) {
1516 die __
("The required SMTP server is not properly defined.")
1520 my $use_net_smtp_ssl = version
->parse($Net::SMTP
::VERSION
) < version
->parse("2.34");
1521 $smtp_domain ||= maildomain
();
1523 if ($smtp_encryption eq 'ssl') {
1524 $smtp_server_port ||= 465; # ssmtp
1525 require IO
::Socket
::SSL
;
1527 # Suppress "variable accessed once" warning.
1530 $IO::Socket
::SSL
::DEBUG
= 1;
1533 # Net::SMTP::SSL->new() does not forward any SSL options
1534 IO
::Socket
::SSL
::set_client_defaults
(
1535 ssl_verify_params
());
1537 if ($use_net_smtp_ssl) {
1538 require Net
::SMTP
::SSL
;
1539 $smtp ||= Net
::SMTP
::SSL
->new($smtp_server,
1540 Hello
=> $smtp_domain,
1541 Port
=> $smtp_server_port,
1542 Debug
=> $debug_net_smtp);
1545 $smtp ||= Net
::SMTP
->new($smtp_server,
1546 Hello
=> $smtp_domain,
1547 Port
=> $smtp_server_port,
1548 Debug
=> $debug_net_smtp,
1553 $smtp_server_port ||= 25;
1554 $smtp ||= Net
::SMTP
->new($smtp_server,
1555 Hello
=> $smtp_domain,
1556 Debug
=> $debug_net_smtp,
1557 Port
=> $smtp_server_port);
1558 if ($smtp_encryption eq 'tls' && $smtp) {
1559 if ($use_net_smtp_ssl) {
1560 $smtp->command('STARTTLS');
1562 if ($smtp->code != 220) {
1563 die sprintf(__
("Server does not support STARTTLS! %s"), $smtp->message);
1565 require Net
::SMTP
::SSL
;
1566 $smtp = Net
::SMTP
::SSL
->start_SSL($smtp,
1567 ssl_verify_params
())
1568 or die sprintf(__
("STARTTLS failed! %s"), IO
::Socket
::SSL
::errstr
());
1571 $smtp->starttls(ssl_verify_params
())
1572 or die sprintf(__
("STARTTLS failed! %s"), IO
::Socket
::SSL
::errstr
());
1574 # Send EHLO again to receive fresh
1575 # supported commands
1576 $smtp->hello($smtp_domain);
1581 die __
("Unable to initialize SMTP properly. Check config and use --smtp-debug."),
1582 " VALUES: server=$smtp_server ",
1583 "encryption=$smtp_encryption ",
1584 "hello=$smtp_domain",
1585 defined $smtp_server_port ?
" port=$smtp_server_port" : "";
1588 smtp_auth_maybe
or die $smtp->message;
1590 $smtp->mail( $raw_from ) or die $smtp->message;
1591 $smtp->to( @recipients ) or die $smtp->message;
1592 $smtp->data or die $smtp->message;
1593 $smtp->datasend("$header\n") or die $smtp->message;
1594 my @lines = split /^/, $message;
1595 foreach my $line (@lines) {
1596 $smtp->datasend("$line") or die $smtp->message;
1598 $smtp->dataend() or die $smtp->message;
1599 $smtp->code =~ /250|200/ or die sprintf(__
("Failed to send %s\n"), $subject).$smtp->message;
1602 printf($dry_run ? __
("Dry-Sent %s\n") : __
("Sent %s\n"), $subject);
1604 print($dry_run ? __
("Dry-OK. Log says:\n") : __
("OK. Log says:\n"));
1605 if (!file_name_is_absolute
($smtp_server)) {
1606 print "Server: $smtp_server\n";
1607 print "MAIL FROM:<$raw_from>\n";
1608 foreach my $entry (@recipients) {
1609 print "RCPT TO:<$entry>\n";
1612 print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
1614 print $header, "\n";
1616 print __
("Result: "), $smtp->code, ' ',
1617 ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
1619 print __
("Result: OK\n");
1626 $in_reply_to = $initial_in_reply_to;
1627 $references = $initial_in_reply_to || '';
1628 $subject = $initial_subject;
1631 # Prepares the email, prompts the user, sends it out
1632 # Returns 0 if an edit was done and the function should be called again, or 1
1637 open my $fh, "<", $t or die sprintf(__
("can't open file %s"), $t);
1640 my $sauthor = undef;
1641 my $author_encoding;
1642 my $has_content_type;
1645 my $has_mime_version;
1649 my $input_format = undef;
1653 # First unfold multiline header fields
1656 if (/^\s+\S/ and @header) {
1657 chomp($header[$#header]);
1659 $header[$#header] .= $_;
1664 # Now parse the header
1667 $input_format = 'mbox';
1671 if (!defined $input_format && /^[-A-Za-z]+:\s/) {
1672 $input_format = 'mbox';
1675 if (defined $input_format && $input_format eq 'mbox') {
1676 if (/^Subject:\s+(.*)$/i) {
1679 elsif (/^From:\s+(.*)$/i) {
1680 ($author, $author_encoding) = unquote_rfc2047
($1);
1681 $sauthor = sanitize_address
($author);
1682 next if $suppress_cc{'author'};
1683 next if $suppress_cc{'self'} and $sauthor eq $sender;
1684 printf(__
("(mbox) Adding cc: %s from line '%s'\n"),
1685 $1, $_) unless $quiet;
1688 elsif (/^To:\s+(.*)$/i) {
1689 foreach my $addr (parse_address_line
($1)) {
1690 printf(__
("(mbox) Adding to: %s from line '%s'\n"),
1691 $addr, $_) unless $quiet;
1695 elsif (/^Cc:\s+(.*)$/i) {
1696 foreach my $addr (parse_address_line
($1)) {
1697 my $qaddr = unquote_rfc2047
($addr);
1698 my $saddr = sanitize_address
($qaddr);
1699 if ($saddr eq $sender) {
1700 next if ($suppress_cc{'self'});
1702 next if ($suppress_cc{'cc'});
1704 printf(__
("(mbox) Adding cc: %s from line '%s'\n"),
1705 $addr, $_) unless $quiet;
1709 elsif (/^Content-type:/i) {
1710 $has_content_type = 1;
1711 if (/charset="?([^ "]+)/) {
1712 $body_encoding = $1;
1716 elsif (/^MIME-Version/i) {
1717 $has_mime_version = 1;
1720 elsif (/^Message-Id: (.*)/i) {
1723 elsif (/^Content-Transfer-Encoding: (.*)/i) {
1724 $xfer_encoding = $1 if not defined $xfer_encoding;
1726 elsif (/^In-Reply-To: (.*)/i) {
1727 if (!$initial_in_reply_to || $thread) {
1731 elsif (/^References: (.*)/i) {
1732 if (!$initial_in_reply_to || $thread) {
1736 elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1740 # In the traditional
1741 # "send lots of email" format,
1744 # So let's support that, too.
1745 $input_format = 'lots';
1746 if (@cc == 0 && !$suppress_cc{'cc'}) {
1747 printf(__
("(non-mbox) Adding cc: %s from line '%s'\n"),
1748 $_, $_) unless $quiet;
1750 } elsif (!defined $subject) {
1755 # Now parse the message body
1758 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1760 my ($what, $c) = ($1, $2);
1761 # strip garbage for the address we'll use:
1762 $c = strip_garbage_one_address
($c);
1763 # sanitize a bit more to decide whether to suppress the address:
1764 my $sc = sanitize_address
($c);
1765 if ($sc eq $sender) {
1766 next if ($suppress_cc{'self'});
1768 if ($what =~ /^Signed-off-by$/i) {
1769 next if $suppress_cc{'sob'};
1770 } elsif ($what =~ /-by$/i) {
1771 next if $suppress_cc{'misc-by'};
1772 } elsif ($what =~ /Cc/i) {
1773 next if $suppress_cc{'bodycc'};
1776 if ($c !~ /.+@.+|<.+>/) {
1777 printf("(body) Ignoring %s from line '%s'\n",
1778 $what, $_) unless $quiet;
1782 printf(__
("(body) Adding cc: %s from line '%s'\n"),
1783 $c, $_) unless $quiet;
1788 push @to, recipients_cmd
("to-cmd", "to", $to_cmd, $t)
1790 push @cc, recipients_cmd
("cc-cmd", "cc", $cc_cmd, $t)
1791 if defined $cc_cmd && !$suppress_cc{'cccmd'};
1793 if ($broken_encoding{$t} && !$has_content_type) {
1794 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1795 $has_content_type = 1;
1796 push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
1797 $body_encoding = $auto_8bit_encoding;
1800 if ($broken_encoding{$t} && !is_rfc2047_quoted
($subject)) {
1801 $subject = quote_subject
($subject, $auto_8bit_encoding);
1804 if (defined $sauthor and $sauthor ne $sender) {
1805 $message = "From: $author\n\n$message";
1806 if (defined $author_encoding) {
1807 if ($has_content_type) {
1808 if ($body_encoding eq $author_encoding) {
1809 # ok, we already have the right encoding
1812 # uh oh, we should re-encode
1816 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1817 $has_content_type = 1;
1819 "Content-Type: text/plain; charset=$author_encoding";
1823 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1824 ($message, $xfer_encoding) = apply_transfer_encoding
(
1825 $message, $xfer_encoding, $target_xfer_encoding);
1826 push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1827 unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1830 $confirm eq "always" or
1831 ($confirm =~ /^(?:auto|cc)$/ && @cc) or
1832 ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
1833 $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
1835 @to = process_address_list
(@to);
1836 @cc = process_address_list
(@cc);
1838 @to = (@initial_to, @to);
1839 @cc = (@initial_cc, @cc);
1841 if ($message_num == 1) {
1842 if (defined $cover_cc and $cover_cc) {
1845 if (defined $cover_to and $cover_to) {
1850 my $message_was_sent = send_message
();
1851 if ($message_was_sent == -1) {
1856 # set up for the next message
1857 if ($thread && $message_was_sent &&
1858 ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
1859 $message_num == 1)) {
1860 $in_reply_to = $message_id;
1861 if (length $references > 0) {
1862 $references .= "\n $message_id";
1864 $references = "$message_id";
1867 $message_id = undef;
1869 if (defined $batch_size && $num_sent == $batch_size) {
1871 $smtp->quit if defined $smtp;
1874 sleep($relogin_delay) if defined $relogin_delay;
1880 foreach my $t (@files) {
1881 while (!process_file
($t)) {
1882 # user edited the file
1886 # Execute a command (e.g. $to_cmd) to get a list of email addresses
1887 # and return a results array
1888 sub recipients_cmd
{
1889 my ($prefix, $what, $cmd, $file) = @_;
1892 open my $fh, "-|", "$cmd \Q$file\E"
1893 or die sprintf(__
("(%s) Could not execute '%s'"), $prefix, $cmd);
1894 while (my $address = <$fh>) {
1895 $address =~ s/^\s*//g;
1896 $address =~ s/\s*$//g;
1897 $address = sanitize_address
($address);
1898 next if ($address eq $sender and $suppress_cc{'self'});
1899 push @addresses, $address;
1900 printf(__
("(%s) Adding %s: %s from: '%s'\n"),
1901 $prefix, $what, $address, $cmd) unless $quiet;
1904 or die sprintf(__
("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
1908 cleanup_compose_files
();
1910 sub cleanup_compose_files
{
1911 unlink($compose_filename, $compose_filename . ".final") if $compose;
1914 $smtp->quit if $smtp;
1916 sub apply_transfer_encoding
{
1917 my $message = shift;
1921 return ($message, $to) if ($from eq $to and $from ne '7bit');
1923 require MIME
::QuotedPrint
;
1924 require MIME
::Base64
;
1926 $message = MIME
::QuotedPrint
::decode
($message)
1927 if ($from eq 'quoted-printable');
1928 $message = MIME
::Base64
::decode
($message)
1929 if ($from eq 'base64');
1931 $to = ($message =~ /(?:.{999,}|\r)/) ?
'quoted-printable' : '8bit'
1934 die __
("cannot send message as 7bit")
1935 if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
1936 return ($message, $to)
1937 if ($to eq '7bit' or $to eq '8bit');
1938 return (MIME
::QuotedPrint
::encode
($message, "\n", 0), $to)
1939 if ($to eq 'quoted-printable');
1940 return (MIME
::Base64
::encode
($message, "\n"), $to)
1941 if ($to eq 'base64');
1942 die __
("invalid transfer encoding");
1945 sub unique_email_list
{
1949 foreach my $entry (@_) {
1950 my $clean = extract_valid_address_or_die
($entry);
1951 $seen{$clean} ||= 0;
1952 next if $seen{$clean}++;
1953 push @emails, $entry;
1958 sub validate_patch
{
1959 my ($fn, $xfer_encoding) = @_;
1962 my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
1963 my $validate_hook = catfile
($hooks_path,
1964 'sendemail-validate');
1966 if (-x
$validate_hook) {
1967 my $target = abs_path
($fn);
1968 # The hook needs a correct cwd and GIT_DIR.
1969 my $cwd_save = cwd
();
1970 chdir($repo->wc_path() or $repo->repo_path())
1971 or die("chdir: $!");
1972 local $ENV{"GIT_DIR"} = $repo->repo_path();
1973 $hook_error = system_or_msg
([$validate_hook, $target]);
1974 chdir($cwd_save) or die("chdir: $!");
1977 die sprintf(__
("fatal: %s: rejected by sendemail-validate hook\n" .
1979 "warning: no patches were sent\n"), $fn, $hook_error);
1983 # Any long lines will be automatically fixed if we use a suitable transfer
1985 unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
1986 open(my $fh, '<', $fn)
1987 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
1988 while (my $line = <$fh>) {
1989 if (length($line) > 998) {
1990 die sprintf(__
("fatal: %s:%d is longer than 998 characters\n" .
1991 "warning: no patches were sent\n"), $fn, $.);
1999 my ($last, $lastlen, $file, $known_suffix) = @_;
2000 my ($suffix, $skip);
2003 if (defined $last &&
2004 ($lastlen < length($file)) &&
2005 (substr($file, 0, $lastlen) eq $last) &&
2006 ($suffix = substr($file, $lastlen)) !~ /^[a-z0-9]/i) {
2007 if (defined $known_suffix && $suffix eq $known_suffix) {
2008 printf(__
("Skipping %s with backup suffix '%s'.\n"), $file, $known_suffix);
2011 # TRANSLATORS: please keep "[y|N]" as is.
2012 my $answer = ask
(sprintf(__
("Do you really want to send %s? [y|N]: "), $file),
2013 valid_re
=> qr/^(?:y|n)/i,
2015 $skip = ($answer ne 'y');
2017 $known_suffix = $suffix;
2021 return ($skip, $known_suffix);
2024 sub handle_backup_files
{
2026 my ($last, $lastlen, $known_suffix, $skip, @result);
2027 for my $file (@file) {
2028 ($skip, $known_suffix) = handle_backup
($last, $lastlen,
2029 $file, $known_suffix);
2030 push @result, $file unless $skip;
2032 $lastlen = length($file);
2037 sub file_has_nonascii
{
2039 open(my $fh, '<', $fn)
2040 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2041 while (my $line = <$fh>) {
2042 return 1 if $line =~ /[^[:ascii:]]/;
2047 sub body_or_subject_has_nonascii
{
2049 open(my $fh, '<', $fn)
2050 or die sprintf(__
("unable to open %s: %s\n"), $fn, $!);
2051 while (my $line = <$fh>) {
2052 last if $line =~ /^$/;
2053 return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
2055 while (my $line = <$fh>) {
2056 return 1 if $line =~ /[^[:ascii:]]/;