send-email tests: support GIT_TEST_PERL_FATAL_WARNINGS=true
[git/debian.git] / git-send-email.perl
blob1630e87cd4df7e486fed5681cefcd0abcec8204a
1 #!/usr/bin/perl
3 # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>
4 # Copyright 2005 Ryan Anderson <ryan@michonline.com>
6 # GPL v2 (See COPYING)
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.
19 use 5.008;
20 use strict;
21 use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
22 use POSIX qw/strftime/;
23 use Term::ReadLine;
24 use Getopt::Long;
25 use Text::ParseWords;
26 use Term::ANSIColor;
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);
31 use Git;
32 use Git::I18N;
33 use Net::Domain ();
34 use Net::SMTP ();
35 use Git::LoadCPAN::Mail::Address;
37 Getopt::Long::Configure qw/ pass_through /;
39 package FakeTerm;
40 sub new {
41 my ($class, $reason) = @_;
42 return bless \$reason, shift;
44 sub readline {
45 my $self = shift;
46 die "Cannot use readline on FakeTerm: $$self";
48 package main;
51 sub usage {
52 print <<EOT;
53 git send-email [options] <file | directory | rev-list options >
54 git send-email --dump-aliases
56 Composing:
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)
71 Sending:
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
83 verification.
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
89 `--smtp-auth=none`
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
96 Automating:
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.
108 Administering:
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.
118 Information:
119 --dump-aliases * Dump configured aliases and exit.
122 exit(1);
125 sub completion_helper {
126 print Git::command('format-patch', '--git-completion-helper');
127 exit(0);
130 # most mail servers generate the Date: header, but not all...
131 sub format_2822_time {
132 my ($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]) {
141 $localmin += 1440;
142 } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {
143 $localmin -= 1440;
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]],
156 $localtm[3],
157 qw(Jan Feb Mar Apr May Jun
158 Jul Aug Sep Oct Nov Dec)[$localtm[4]],
159 $localtm[5]+1900,
160 $localtm[2],
161 $localtm[1],
162 $localtm[0],
163 ($offset >= 0) ? '+' : '-',
164 abs($offhour),
165 $offmin,
169 my $have_email_valid = eval { require Email::Valid; 1 };
170 my $smtp;
171 my $auth;
172 my $num_sent = 0;
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
184 # command-line.
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);
190 # Example reply to:
191 #$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
193 my $repo = eval { Git->repository() };
194 my @repo = $repo ? ($repo) : ();
195 my $term = eval {
196 $ENV{"GIT_SEND_EMAIL_NOTTY"}
197 ? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
198 : new Term::ReadLine 'git-send-email';
200 if ($@) {
201 $term = new FakeTerm "$@: going non-interactive";
204 # Behavior modification variables
205 my ($quiet, $dry_run) = (0, 0);
206 my $format_patch;
207 my $compose_filename;
208 my $force = 0;
209 my $dump_aliases = 0;
211 # Handle interactive edition of files.
212 my $multiedit;
213 my $editor;
215 sub system_or_msg {
216 my ($args, $msg) = @_;
217 system(@$args);
218 my $signalled = $? & 127;
219 my $exit_code = $? >> 8;
220 return unless $signalled or $exit_code;
222 my @sprintf_args = ($args->[0], $exit_code);
223 if (defined $msg) {
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
228 # on older perls.
229 no warnings;
230 return sprintf($msg, @sprintf_args);
232 return sprintf(__("fatal: command '%s' died with exit code %d"),
233 @sprintf_args);
236 sub system_or_die {
237 my $msg = system_or_msg(@_);
238 die $msg if $msg;
241 sub do_edit {
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 @_;
248 } else {
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);
261 my ($confirm);
262 my (@suppress_cc);
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()
267 my $thread = 1;
268 my $chain_reply_to = 0;
269 my $use_xmailer = 1;
270 my $validate = 1;
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,
299 "to" => \@config_to,
300 "tocmd" => \$to_cmd,
301 "cc" => \@config_cc,
302 "cccmd" => \$cc_cmd,
303 "aliasfiletype" => \$aliasfiletype,
304 "bcc" => \@config_bcc,
305 "suppresscc" => \@suppress_cc,
306 "envelopesender" => \$envelope_sender,
307 "confirm" => \$confirm,
308 "from" => \$sender,
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
320 sub signal_handler {
322 # Make text normal
323 print color("reset"), "\n";
325 # SMTP password masked
326 system "stty echo";
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"),
333 $compose_filename;
335 if (-e ($compose_filename . ".final")) {
336 printf __("'%s.final' contains the composed email.\n"),
337 $compose_filename;
341 exit;
344 $SIG{TERM} = \&signal_handler;
345 $SIG{INT} = \&signal_handler;
347 # Read our sendemail.* config
348 sub read_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}++;
356 $$target = $v;
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");
363 next unless @values;
364 next if $configured->{$setting}++;
365 @$target = @values;
367 else {
368 my $v = Git::config_path(@repo, "$prefix.$setting");
369 next unless defined $v;
370 next if $configured->{$setting}++;
371 $$target = $v;
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");
379 next unless @values;
380 next if $configured->{$setting}++;
381 @$target = @values;
383 else {
384 my $v = Git::config(@repo, "$prefix.$setting");
385 next unless defined $v;
386 next if $configured->{$setting}++;
387 $$target = $v;
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}++;
396 if (defined $enc) {
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");
407 my $rc = GetOptions(
408 "identity=s" => \$identity,
409 "no-identity" => \$no_identity,
411 usage() unless $rc;
412 undef $identity if $no_identity;
414 # Now we know enough to read the config
416 my %configured;
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:
424 my $help;
425 my $git_completion_helper;
426 $rc = GetOptions("h" => \$help,
427 "dump-aliases" => \$dump_aliases);
428 usage() unless $rc;
429 die __("--dump-aliases incompatible with other options\n")
430 if !$help and $dump_aliases and @ARGV;
431 $rc = GetOptions(
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,
438 "no-to" => \$no_to,
439 "cc=s" => \@getopt_cc,
440 "no-cc" => \$no_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,
460 "quiet" => \$quiet,
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,
483 "force" => \$force,
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);
496 usage() if $help;
497 completion_helper() if $git_completion_helper;
498 unless ($rc) {
499 usage();
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
519 my(%suppress_cc);
520 if (@suppress_cc) {
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.
559 if (0) {
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]);
574 sub split_addrs {
575 return quotewords('\s*,\s*', 1, @_);
578 my %aliases;
580 sub parse_sendmail_alias {
581 local $_ = shift;
582 if (/"/) {
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"), $_;
586 } elsif (/[\/|]/) {
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) ];
591 } else {
592 printf STDERR __("warning: sendmail line is not recognized: %s\n"), $_;
596 sub parse_sendmail_aliases {
597 my $fh = shift;
598 my $s = '';
599 while (<$fh>) {
600 chomp;
601 next if /^\s*$/ || /^\s*#/;
602 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
603 parse_sendmail_alias($s) if $s;
604 $s = $_;
606 $s =~ s/\\$//; # silently tolerate stray '\' on last line
607 parse_sendmail_alias($s) if $s;
610 my %parse_alias = (
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
623 }}},
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) ];
628 }}},
629 pine => sub { my $fh = shift; my $f='\t[^\t]*';
630 for (my $x = ''; defined($x); $x = $_) {
631 chomp $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;
637 while (<$fh>) {
638 if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
639 my ($alias, $addr) = ($1, $2);
640 $aliases{$alias} = [ split_addrs($addr) ];
642 } },
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
649 # add new MUAs.
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);
656 close $fh;
660 if ($dump_aliases) {
661 print "$_\n" for (sort keys %aliases);
662 exit(0);
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 {
668 return unless $repo;
669 my $f = shift;
670 try {
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.
684 return 0;
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.
690 my @rev_list_opts;
691 while (defined(my $f = shift @ARGV)) {
692 if ($f eq "--") {
693 push @rev_list_opts, "--", @ARGV;
694 @ARGV = ();
695 } elsif (-d $f and !is_format_patch_arg($f)) {
696 opendir my $dh, $f
697 or die sprintf(__("Failed to opendir %s: %s"), $f, $!);
699 push @files, grep { -f $_ } map { catfile($f, $_) }
700 sort readdir $dh;
701 closedir $dh;
702 } elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) {
703 push @files, $f;
704 } else {
705 push @rev_list_opts, $f;
709 if (@rev_list_opts) {
710 die __("Cannot run git format-patch from outside a repository\n")
711 unless $repo;
712 push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
715 @files = handle_backup_files(@files);
717 if ($validate) {
718 foreach my $f (@files) {
719 unless (-p $f) {
720 validate_patch($f, $target_xfer_encoding);
725 if (@files) {
726 unless ($quiet) {
727 print $_,"\n" for (@files);
729 } else {
730 print STDERR __("\nNo patch files specified!\n\n");
731 usage();
734 sub get_patch_subject {
735 my $fn = shift;
736 open (my $fh, '<', $fn);
737 while (my $line = <$fh>) {
738 next unless ($line =~ /^Subject: (.*)$/);
739 close $fh;
740 return "GIT: $1\n";
742 close $fh;
743 die sprintf(__("No subject line in %s?"), $fn);
746 if ($compose) {
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.
763 EOT1
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.
769 EOT2
770 From: $tpl_sender
771 Reply-To: $tpl_reply_to
772 Subject: $tpl_subject
773 In-Reply-To: $tpl_in_reply_to
775 EOT3
776 for my $f (@files) {
777 print $c get_patch_subject($f);
779 close $c;
781 if ($annotate) {
782 do_edit($compose_filename, @files);
783 } else {
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";
794 my %parsed_email;
795 while (my $line = <$c>) {
796 next if $line =~ m/^GIT:/;
797 parse_header_line($line, \%parsed_email);
798 if ($line =~ /^$/) {
799 $parsed_email{'body'} = filter_body($c);
802 close $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) .
821 "\n";
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'});
847 } else {
848 print __("Summary email is empty, skipping it\n");
849 $compose = -1;
852 close $c2;
854 } elsif ($annotate) {
855 do_edit(@files);
858 sub ask {
859 my ($prompt, %arg) = @_;
860 my $valid_re = $arg{valid_re};
861 my $default = $arg{default};
862 my $confirm_only = $arg{confirm_only};
863 my $resp;
864 my $i = 0;
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);
868 while ($i++ < 10) {
869 $resp = $term->readline($prompt);
870 if (!defined $resp) { # EOF
871 print "\n";
872 return defined $default ? $default : undef;
874 if ($resp eq '' and defined $default) {
875 return $default;
877 if (!defined $valid_re or $resp =~ /$valid_re/) {
878 return $resp;
880 if ($confirm_only) {
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) {
885 return $resp;
889 return;
892 sub parse_header_line {
893 my $lines = shift;
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;
906 sub filter_body {
907 my $c = shift;
908 my $body = "";
909 while (my $body_line = <$c>) {
910 if ($body_line !~ m/^GIT:/) {
911 $body .= $body_line;
914 return $body;
918 my %broken_encoding;
920 sub file_declares_8bit_cte {
921 my $fn = shift;
922 open (my $fh, '<', $fn);
923 while (my $line = <$fh>) {
924 last if ($line =~ /^$/);
925 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
927 close $fh;
928 return 0;
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) {
941 print " $f\n";
943 $auto_8bit_encoding = ask(__("Which 8bit encoding should I declare [UTF-8]? "),
944 valid_re => qr/.{4}/, confirm_only => 1,
945 default => "UTF-8");
948 if (!$force) {
949 for my $f (@files) {
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);
961 } else {
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)?");
971 my $prompting = 0;
972 if (!@initial_to && !defined $to_cmd) {
973 my $to = ask("$to_whom ",
974 default => "",
975 valid_re => qr/\@.*\./, confirm_only => 1);
976 push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
977 $prompting++;
980 sub expand_aliases {
981 return map { expand_one_alias($_) } @_;
984 my %EXPANDED_ALIASES;
985 sub expand_one_alias {
986 my $alias = shift;
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)? "),
1001 default => "",
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) {
1020 if (-x $_) {
1021 $smtp_server = $_;
1022 last;
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)/;
1052 return;
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)
1059 if !$address;
1060 return $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
1069 # at this point.
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,
1072 default => 'q');
1073 if (/^d/i) {
1074 return undef;
1075 } elsif (/^q/i) {
1076 cleanup_compose_files();
1077 exit(0);
1079 $address = ask("$to_whom ",
1080 default => "",
1081 valid_re => qr/\@.*\./, confirm_only => 1);
1083 return $address;
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 {
1102 my $uniq;
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";
1110 my $du_part;
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 {
1129 local ($_) = @_;
1130 my $charset;
1131 my $sep = qr/[ \t]+/;
1132 s{$re_encoded_word(?:$sep$re_encoded_word)*}{
1133 my @words = split $sep, $&;
1134 foreach (@words) {
1135 m/$re_encoded_word/;
1136 $charset = $1;
1137 my $encoding = $2;
1138 my $text = $3;
1139 if ($encoding eq 'q' || $encoding eq 'Q') {
1140 $_ = $text;
1141 s/_/ /g;
1142 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1143 } else {
1144 # other encodings not supported yet
1147 join '', @words;
1148 }eg;
1149 return wantarray ? ($_, $charset) : $_;
1152 sub quote_rfc2047 {
1153 local $_ = shift;
1154 my $encoding = shift || 'UTF-8';
1155 s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
1156 s/(.*)/=\?$encoding\?q\?$1\?=/;
1157 return $_;
1160 sub is_rfc2047_quoted {
1161 my $s = shift;
1162 length($s) <= 75 &&
1163 $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1166 sub subject_needs_rfc2047_quoting {
1167 my $s = shift;
1169 return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1172 sub quote_subject {
1173 local $subject = shift;
1174 my $encoding = shift || 'UTF-8';
1176 if (subject_needs_rfc2047_quoting($subject)) {
1177 return quote_rfc2047($subject, $encoding);
1179 return $subject;
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) {
1192 return $recipient;
1195 # if recipient_name is already quoted, do nothing
1196 if (is_rfc2047_quoted($recipient_name)) {
1197 return $recipient;
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 {
1219 my ($addr) = @_;
1220 chomp $addr;
1221 if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1222 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1223 # Foo Bar <foobar@example.com> [possibly garbage here]
1224 return $1;
1226 if ($addr =~ /^(<[^>]*>).*/) {
1227 # <foo@example.com> [possibly garbage here]
1228 # if garbage contains other addresses, they are ignored.
1229 return $1;
1231 if ($addr =~ /^([^"#,\s]*)/) {
1232 # address without quoting: remove anything after the address
1233 return $1;
1235 return $addr;
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);
1247 return @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 ()
1266 sub valid_fqdn {
1267 my $domain = shift;
1268 return defined $domain && !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1271 sub maildomain_net {
1272 my $maildomain;
1274 my $domain = Net::Domain::domainname();
1275 $maildomain = $domain if valid_fqdn($domain);
1277 return $maildomain;
1280 sub maildomain_mta {
1281 my $maildomain;
1283 for my $host (qw(mailhost localhost)) {
1284 my $smtp = Net::SMTP->new($host);
1285 if (defined $smtp) {
1286 my $domain = $smtp->domain;
1287 $smtp->quit;
1289 $maildomain = $domain if valid_fqdn($domain);
1291 last if $maildomain;
1295 return $maildomain;
1298 sub 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";
1305 } else {
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")) {
1315 return 1;
1318 # Workaround AUTH PLAIN/LOGIN interaction defect
1319 # with Authen::SASL::Cyrus
1320 eval {
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
1341 }, sub {
1342 my $cred = shift;
1344 if ($smtp_auth) {
1345 my $sasl = Authen::SASL->new(
1346 mechanism => $smtp_auth,
1347 callback => {
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'});
1360 return $auth;
1363 sub ssl_verify_params {
1364 eval {
1365 require IO::Socket::SSL;
1366 IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1368 if ($@) {
1369 print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1370 return;
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);
1386 } else {
1387 die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1391 sub file_name_is_absolute {
1392 my ($path) = @_;
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.
1412 sub send_message {
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
1417 @cc);
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));
1428 my $ccline = "";
1429 if ($cc ne '') {
1430 $ccline = "\nCc: $cc";
1432 make_message_id() unless defined($message_id);
1434 my $header = "From: $sender
1435 To: $to${ccline}
1436 Subject: $subject
1437 Date: $date
1438 Message-Id: $message_id
1440 if ($use_xmailer) {
1441 $header .= "X-Mailer: git-send-email $gitversion\n";
1443 if ($in_reply_to) {
1445 $header .= "In-Reply-To: $in_reply_to\n";
1446 $header .= "References: $references\n";
1448 if ($reply_to) {
1449 $header .= "Reply-To: $reply_to\n";
1451 if (@xh) {
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
1469 print __ <<EOF ;
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
1484 # at this point.
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 $_;
1489 if (/^n/i) {
1490 return 0;
1491 } elsif (/^e/i) {
1492 return -1;
1493 } elsif (/^q/i) {
1494 cleanup_compose_files();
1495 exit(0);
1496 } elsif (/^a/i) {
1497 $confirm = 'never';
1501 unshift (@sendmail_parameters, @smtp_server_options);
1503 if ($dry_run) {
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 $!;
1508 if (!$pid) {
1509 exec($smtp_server, @sendmail_parameters) or die $!;
1511 print $sm "$header\n$message";
1512 close $sm or die $!;
1513 } else {
1515 if (!defined $smtp_server) {
1516 die __("The required SMTP server is not properly defined.")
1519 require Net::SMTP;
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.
1529 no warnings 'once';
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);
1544 else {
1545 $smtp ||= Net::SMTP->new($smtp_server,
1546 Hello => $smtp_domain,
1547 Port => $smtp_server_port,
1548 Debug => $debug_net_smtp,
1549 SSL => 1);
1552 elsif (!$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');
1561 $smtp->response();
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());
1570 else {
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);
1580 if (!$smtp) {
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;
1601 if ($quiet) {
1602 printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
1603 } else {
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";
1611 } else {
1612 print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
1614 print $header, "\n";
1615 if ($smtp) {
1616 print __("Result: "), $smtp->code, ' ',
1617 ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
1618 } else {
1619 print __("Result: OK\n");
1623 return 1;
1626 $in_reply_to = $initial_in_reply_to;
1627 $references = $initial_in_reply_to || '';
1628 $subject = $initial_subject;
1629 $message_num = 0;
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
1633 # otherwise.
1634 sub process_file {
1635 my ($t) = @_;
1637 open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
1639 my $author = undef;
1640 my $sauthor = undef;
1641 my $author_encoding;
1642 my $has_content_type;
1643 my $body_encoding;
1644 my $xfer_encoding;
1645 my $has_mime_version;
1646 @to = ();
1647 @cc = ();
1648 @xh = ();
1649 my $input_format = undef;
1650 my @header = ();
1651 $message = "";
1652 $message_num++;
1653 # First unfold multiline header fields
1654 while(<$fh>) {
1655 last if /^\s*$/;
1656 if (/^\s+\S/ and @header) {
1657 chomp($header[$#header]);
1658 s/^\s+/ /;
1659 $header[$#header] .= $_;
1660 } else {
1661 push(@header, $_);
1664 # Now parse the header
1665 foreach(@header) {
1666 if (/^From /) {
1667 $input_format = 'mbox';
1668 next;
1670 chomp;
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) {
1677 $subject = $1;
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;
1686 push @cc, $1;
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;
1692 push @to, $addr;
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'});
1701 } else {
1702 next if ($suppress_cc{'cc'});
1704 printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1705 $addr, $_) unless $quiet;
1706 push @cc, $addr;
1709 elsif (/^Content-type:/i) {
1710 $has_content_type = 1;
1711 if (/charset="?([^ "]+)/) {
1712 $body_encoding = $1;
1714 push @xh, $_;
1716 elsif (/^MIME-Version/i) {
1717 $has_mime_version = 1;
1718 push @xh, $_;
1720 elsif (/^Message-Id: (.*)/i) {
1721 $message_id = $1;
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) {
1728 $in_reply_to = $1;
1731 elsif (/^References: (.*)/i) {
1732 if (!$initial_in_reply_to || $thread) {
1733 $references = $1;
1736 elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1737 push @xh, $_;
1739 } else {
1740 # In the traditional
1741 # "send lots of email" format,
1742 # line 1 = cc
1743 # line 2 = subject
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;
1749 push @cc, $_;
1750 } elsif (!defined $subject) {
1751 $subject = $_;
1755 # Now parse the message body
1756 while(<$fh>) {
1757 $message .= $_;
1758 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1759 chomp;
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'});
1767 } else {
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;
1779 next;
1781 push @cc, $c;
1782 printf(__("(body) Adding cc: %s from line '%s'\n"),
1783 $c, $_) unless $quiet;
1786 close $fh;
1788 push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
1789 if defined $to_cmd;
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
1811 else {
1812 # uh oh, we should re-encode
1815 else {
1816 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1817 $has_content_type = 1;
1818 push @xh,
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;
1829 $needs_confirm = (
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) {
1843 @initial_cc = @cc;
1845 if (defined $cover_to and $cover_to) {
1846 @initial_to = @to;
1850 my $message_was_sent = send_message();
1851 if ($message_was_sent == -1) {
1852 do_edit($t);
1853 return 0;
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";
1863 } else {
1864 $references = "$message_id";
1867 $message_id = undef;
1868 $num_sent++;
1869 if (defined $batch_size && $num_sent == $batch_size) {
1870 $num_sent = 0;
1871 $smtp->quit if defined $smtp;
1872 undef $smtp;
1873 undef $auth;
1874 sleep($relogin_delay) if defined $relogin_delay;
1877 return 1;
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) = @_;
1891 my @addresses = ();
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;
1903 close $fh
1904 or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
1905 return @addresses;
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;
1918 my $from = shift;
1919 my $to = 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'
1932 if $to eq 'auto';
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 {
1946 my %seen;
1947 my @emails;
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;
1955 return @emails;
1958 sub validate_patch {
1959 my ($fn, $xfer_encoding) = @_;
1961 if ($repo) {
1962 my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
1963 my $validate_hook = catfile($hooks_path,
1964 'sendemail-validate');
1965 my $hook_error;
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: $!");
1976 if ($hook_error) {
1977 die sprintf(__("fatal: %s: rejected by sendemail-validate hook\n" .
1978 "%s\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
1984 # encoding.
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, $.);
1995 return;
1998 sub handle_backup {
1999 my ($last, $lastlen, $file, $known_suffix) = @_;
2000 my ($suffix, $skip);
2002 $skip = 0;
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);
2009 $skip = 1;
2010 } else {
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,
2014 default => 'n');
2015 $skip = ($answer ne 'y');
2016 if ($skip) {
2017 $known_suffix = $suffix;
2021 return ($skip, $known_suffix);
2024 sub handle_backup_files {
2025 my @file = @_;
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;
2031 $last = $file;
2032 $lastlen = length($file);
2034 return @result;
2037 sub file_has_nonascii {
2038 my $fn = shift;
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:]]/;
2044 return 0;
2047 sub body_or_subject_has_nonascii {
2048 my $fn = shift;
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:]]/;
2058 return 0;