Merge branch 'en/ort-perf-batch-8'
[alt-git.git] / git-send-email.perl
blob1f425c08091d400e1d2e94533411c1b778f561de
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;
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 do_edit {
216 if (!defined($editor)) {
217 $editor = Git::command_oneline('var', 'GIT_EDITOR');
219 if (defined($multiedit) && !$multiedit) {
220 map {
221 system('sh', '-c', $editor.' "$@"', $editor, $_);
222 if (($? & 127) || ($? >> 8)) {
223 die(__("the editor exited uncleanly, aborting everything"));
225 } @_;
226 } else {
227 system('sh', '-c', $editor.' "$@"', $editor, @_);
228 if (($? & 127) || ($? >> 8)) {
229 die(__("the editor exited uncleanly, aborting everything"));
234 # Variables with corresponding config settings
235 my ($suppress_from, $signed_off_by_cc);
236 my ($cover_cc, $cover_to);
237 my ($to_cmd, $cc_cmd);
238 my ($smtp_server, $smtp_server_port, @smtp_server_options);
239 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
240 my ($batch_size, $relogin_delay);
241 my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
242 my ($confirm);
243 my (@suppress_cc);
244 my ($auto_8bit_encoding);
245 my ($compose_encoding);
246 # Variables with corresponding config settings & hardcoded defaults
247 my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
248 my $thread = 1;
249 my $chain_reply_to = 0;
250 my $use_xmailer = 1;
251 my $validate = 1;
252 my $target_xfer_encoding = 'auto';
253 my $forbid_sendmail_variables = 1;
255 my %config_bool_settings = (
256 "thread" => \$thread,
257 "chainreplyto" => \$chain_reply_to,
258 "suppressfrom" => \$suppress_from,
259 "signedoffbycc" => \$signed_off_by_cc,
260 "cccover" => \$cover_cc,
261 "tocover" => \$cover_to,
262 "signedoffcc" => \$signed_off_by_cc,
263 "validate" => \$validate,
264 "multiedit" => \$multiedit,
265 "annotate" => \$annotate,
266 "xmailer" => \$use_xmailer,
267 "forbidsendmailvariables" => \$forbid_sendmail_variables,
270 my %config_settings = (
271 "smtpserver" => \$smtp_server,
272 "smtpserverport" => \$smtp_server_port,
273 "smtpserveroption" => \@smtp_server_options,
274 "smtpuser" => \$smtp_authuser,
275 "smtppass" => \$smtp_authpass,
276 "smtpdomain" => \$smtp_domain,
277 "smtpauth" => \$smtp_auth,
278 "smtpbatchsize" => \$batch_size,
279 "smtprelogindelay" => \$relogin_delay,
280 "to" => \@config_to,
281 "tocmd" => \$to_cmd,
282 "cc" => \@config_cc,
283 "cccmd" => \$cc_cmd,
284 "aliasfiletype" => \$aliasfiletype,
285 "bcc" => \@config_bcc,
286 "suppresscc" => \@suppress_cc,
287 "envelopesender" => \$envelope_sender,
288 "confirm" => \$confirm,
289 "from" => \$sender,
290 "assume8bitencoding" => \$auto_8bit_encoding,
291 "composeencoding" => \$compose_encoding,
292 "transferencoding" => \$target_xfer_encoding,
295 my %config_path_settings = (
296 "aliasesfile" => \@alias_files,
297 "smtpsslcertpath" => \$smtp_ssl_cert_path,
300 # Handle Uncouth Termination
301 sub signal_handler {
303 # Make text normal
304 print color("reset"), "\n";
306 # SMTP password masked
307 system "stty echo";
309 # tmp files from --compose
310 if (defined $compose_filename) {
311 if (-e $compose_filename) {
312 printf __("'%s' contains an intermediate version ".
313 "of the email you were composing.\n"),
314 $compose_filename;
316 if (-e ($compose_filename . ".final")) {
317 printf __("'%s.final' contains the composed email.\n"),
318 $compose_filename;
322 exit;
325 $SIG{TERM} = \&signal_handler;
326 $SIG{INT} = \&signal_handler;
328 # Read our sendemail.* config
329 sub read_config {
330 my ($configured, $prefix) = @_;
332 foreach my $setting (keys %config_bool_settings) {
333 my $target = $config_bool_settings{$setting};
334 my $v = Git::config_bool(@repo, "$prefix.$setting");
335 next unless defined $v;
336 next if $configured->{$setting}++;
337 $$target = $v;
340 foreach my $setting (keys %config_path_settings) {
341 my $target = $config_path_settings{$setting};
342 if (ref($target) eq "ARRAY") {
343 my @values = Git::config_path(@repo, "$prefix.$setting");
344 next unless @values;
345 next if $configured->{$setting}++;
346 @$target = @values;
348 else {
349 my $v = Git::config_path(@repo, "$prefix.$setting");
350 next unless defined $v;
351 next if $configured->{$setting}++;
352 $$target = $v;
356 foreach my $setting (keys %config_settings) {
357 my $target = $config_settings{$setting};
358 if (ref($target) eq "ARRAY") {
359 my @values = Git::config(@repo, "$prefix.$setting");
360 next unless @values;
361 next if $configured->{$setting}++;
362 @$target = @values;
364 else {
365 my $v = Git::config(@repo, "$prefix.$setting");
366 next unless defined $v;
367 next if $configured->{$setting}++;
368 $$target = $v;
372 if (!defined $smtp_encryption) {
373 my $setting = "$prefix.smtpencryption";
374 my $enc = Git::config(@repo, $setting);
375 return unless defined $enc;
376 return if $configured->{$setting}++;
377 if (defined $enc) {
378 $smtp_encryption = $enc;
379 } elsif (Git::config_bool(@repo, "$prefix.smtpssl")) {
380 $smtp_encryption = 'ssl';
385 # sendemail.identity yields to --identity. We must parse this
386 # special-case first before the rest of the config is read.
387 $identity = Git::config(@repo, "sendemail.identity");
388 my $rc = GetOptions(
389 "identity=s" => \$identity,
390 "no-identity" => \$no_identity,
392 usage() unless $rc;
393 undef $identity if $no_identity;
395 # Now we know enough to read the config
397 my %configured;
398 read_config(\%configured, "sendemail.$identity") if defined $identity;
399 read_config(\%configured, "sendemail");
402 # Begin by accumulating all the variables (defined above), that we will end up
403 # needing, first, from the command line:
405 my $help;
406 my $git_completion_helper;
407 $rc = GetOptions("h" => \$help,
408 "dump-aliases" => \$dump_aliases);
409 usage() unless $rc;
410 die __("--dump-aliases incompatible with other options\n")
411 if !$help and $dump_aliases and @ARGV;
412 $rc = GetOptions(
413 "sender|from=s" => \$sender,
414 "in-reply-to=s" => \$initial_in_reply_to,
415 "reply-to=s" => \$reply_to,
416 "subject=s" => \$initial_subject,
417 "to=s" => \@getopt_to,
418 "to-cmd=s" => \$to_cmd,
419 "no-to" => \$no_to,
420 "cc=s" => \@getopt_cc,
421 "no-cc" => \$no_cc,
422 "bcc=s" => \@getopt_bcc,
423 "no-bcc" => \$no_bcc,
424 "chain-reply-to!" => \$chain_reply_to,
425 "no-chain-reply-to" => sub {$chain_reply_to = 0},
426 "smtp-server=s" => \$smtp_server,
427 "smtp-server-option=s" => \@smtp_server_options,
428 "smtp-server-port=s" => \$smtp_server_port,
429 "smtp-user=s" => \$smtp_authuser,
430 "smtp-pass:s" => \$smtp_authpass,
431 "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
432 "smtp-encryption=s" => \$smtp_encryption,
433 "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
434 "smtp-debug:i" => \$debug_net_smtp,
435 "smtp-domain:s" => \$smtp_domain,
436 "smtp-auth=s" => \$smtp_auth,
437 "no-smtp-auth" => sub {$smtp_auth = 'none'},
438 "annotate!" => \$annotate,
439 "no-annotate" => sub {$annotate = 0},
440 "compose" => \$compose,
441 "quiet" => \$quiet,
442 "cc-cmd=s" => \$cc_cmd,
443 "suppress-from!" => \$suppress_from,
444 "no-suppress-from" => sub {$suppress_from = 0},
445 "suppress-cc=s" => \@suppress_cc,
446 "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
447 "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
448 "cc-cover|cc-cover!" => \$cover_cc,
449 "no-cc-cover" => sub {$cover_cc = 0},
450 "to-cover|to-cover!" => \$cover_to,
451 "no-to-cover" => sub {$cover_to = 0},
452 "confirm=s" => \$confirm,
453 "dry-run" => \$dry_run,
454 "envelope-sender=s" => \$envelope_sender,
455 "thread!" => \$thread,
456 "no-thread" => sub {$thread = 0},
457 "validate!" => \$validate,
458 "no-validate" => sub {$validate = 0},
459 "transfer-encoding=s" => \$target_xfer_encoding,
460 "format-patch!" => \$format_patch,
461 "no-format-patch" => sub {$format_patch = 0},
462 "8bit-encoding=s" => \$auto_8bit_encoding,
463 "compose-encoding=s" => \$compose_encoding,
464 "force" => \$force,
465 "xmailer!" => \$use_xmailer,
466 "no-xmailer" => sub {$use_xmailer = 0},
467 "batch-size=i" => \$batch_size,
468 "relogin-delay=i" => \$relogin_delay,
469 "git-completion-helper" => \$git_completion_helper,
472 # Munge any "either config or getopt, not both" variables
473 my @initial_to = @getopt_to ? @getopt_to : ($no_to ? () : @config_to);
474 my @initial_cc = @getopt_cc ? @getopt_cc : ($no_cc ? () : @config_cc);
475 my @initial_bcc = @getopt_bcc ? @getopt_bcc : ($no_bcc ? () : @config_bcc);
477 usage() if $help;
478 completion_helper() if $git_completion_helper;
479 unless ($rc) {
480 usage();
483 if ($forbid_sendmail_variables && (scalar Git::config_regexp("^sendmail[.]")) != 0) {
484 die __("fatal: found configuration options for 'sendmail'\n" .
485 "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
486 "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
489 die __("Cannot run git format-patch from outside a repository\n")
490 if $format_patch and not $repo;
492 die __("`batch-size` and `relogin` must be specified together " .
493 "(via command-line or configuration option)\n")
494 if defined $relogin_delay and not defined $batch_size;
496 # 'default' encryption is none -- this only prevents a warning
497 $smtp_encryption = '' unless (defined $smtp_encryption);
499 # Set CC suppressions
500 my(%suppress_cc);
501 if (@suppress_cc) {
502 foreach my $entry (@suppress_cc) {
503 # Please update $__git_send_email_suppresscc_options
504 # in git-completion.bash when you add new options.
505 die sprintf(__("Unknown --suppress-cc field: '%s'\n"), $entry)
506 unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc|misc-by)$/;
507 $suppress_cc{$entry} = 1;
511 if ($suppress_cc{'all'}) {
512 foreach my $entry (qw (cccmd cc author self sob body bodycc misc-by)) {
513 $suppress_cc{$entry} = 1;
515 delete $suppress_cc{'all'};
518 # If explicit old-style ones are specified, they trump --suppress-cc.
519 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
520 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
522 if ($suppress_cc{'body'}) {
523 foreach my $entry (qw (sob bodycc misc-by)) {
524 $suppress_cc{$entry} = 1;
526 delete $suppress_cc{'body'};
529 # Set confirm's default value
530 my $confirm_unconfigured = !defined $confirm;
531 if ($confirm_unconfigured) {
532 $confirm = scalar %suppress_cc ? 'compose' : 'auto';
534 # Please update $__git_send_email_confirm_options in
535 # git-completion.bash when you add new options.
536 die sprintf(__("Unknown --confirm setting: '%s'\n"), $confirm)
537 unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
539 # Debugging, print out the suppressions.
540 if (0) {
541 print "suppressions:\n";
542 foreach my $entry (keys %suppress_cc) {
543 printf " %-5s -> $suppress_cc{$entry}\n", $entry;
547 my ($repoauthor, $repocommitter);
548 ($repoauthor) = Git::ident_person(@repo, 'author');
549 ($repocommitter) = Git::ident_person(@repo, 'committer');
551 sub parse_address_line {
552 return map { $_->format } Mail::Address->parse($_[0]);
555 sub split_addrs {
556 return quotewords('\s*,\s*', 1, @_);
559 my %aliases;
561 sub parse_sendmail_alias {
562 local $_ = shift;
563 if (/"/) {
564 printf STDERR __("warning: sendmail alias with quotes is not supported: %s\n"), $_;
565 } elsif (/:include:/) {
566 printf STDERR __("warning: `:include:` not supported: %s\n"), $_;
567 } elsif (/[\/|]/) {
568 printf STDERR __("warning: `/file` or `|pipe` redirection not supported: %s\n"), $_;
569 } elsif (/^(\S+?)\s*:\s*(.+)$/) {
570 my ($alias, $addr) = ($1, $2);
571 $aliases{$alias} = [ split_addrs($addr) ];
572 } else {
573 printf STDERR __("warning: sendmail line is not recognized: %s\n"), $_;
577 sub parse_sendmail_aliases {
578 my $fh = shift;
579 my $s = '';
580 while (<$fh>) {
581 chomp;
582 next if /^\s*$/ || /^\s*#/;
583 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
584 parse_sendmail_alias($s) if $s;
585 $s = $_;
587 $s =~ s/\\$//; # silently tolerate stray '\' on last line
588 parse_sendmail_alias($s) if $s;
591 my %parse_alias = (
592 # multiline formats can be supported in the future
593 mutt => sub { my $fh = shift; while (<$fh>) {
594 if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
595 my ($alias, $addr) = ($1, $2);
596 $addr =~ s/#.*$//; # mutt allows # comments
597 # commas delimit multiple addresses
598 my @addr = split_addrs($addr);
600 # quotes may be escaped in the file,
601 # unescape them so we do not double-escape them later.
602 s/\\"/"/g foreach @addr;
603 $aliases{$alias} = \@addr
604 }}},
605 mailrc => sub { my $fh = shift; while (<$fh>) {
606 if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
607 # spaces delimit multiple addresses
608 $aliases{$1} = [ quotewords('\s+', 0, $2) ];
609 }}},
610 pine => sub { my $fh = shift; my $f='\t[^\t]*';
611 for (my $x = ''; defined($x); $x = $_) {
612 chomp $x;
613 $x .= $1 while(defined($_ = <$fh>) && /^ +(.*)$/);
614 $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
615 $aliases{$1} = [ split_addrs($2) ];
617 elm => sub { my $fh = shift;
618 while (<$fh>) {
619 if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
620 my ($alias, $addr) = ($1, $2);
621 $aliases{$alias} = [ split_addrs($addr) ];
623 } },
624 sendmail => \&parse_sendmail_aliases,
625 gnus => sub { my $fh = shift; while (<$fh>) {
626 if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
627 $aliases{$1} = [ $2 ];
629 # Please update _git_config() in git-completion.bash when you
630 # add new MUAs.
633 if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
634 foreach my $file (@alias_files) {
635 open my $fh, '<', $file or die "opening $file: $!\n";
636 $parse_alias{$aliasfiletype}->($fh);
637 close $fh;
641 if ($dump_aliases) {
642 print "$_\n" for (sort keys %aliases);
643 exit(0);
646 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
647 # $f is a revision list specification to be passed to format-patch.
648 sub is_format_patch_arg {
649 return unless $repo;
650 my $f = shift;
651 try {
652 $repo->command('rev-parse', '--verify', '--quiet', $f);
653 if (defined($format_patch)) {
654 return $format_patch;
656 die sprintf(__ <<EOF, $f, $f);
657 File '%s' exists but it could also be the range of commits
658 to produce patches for. Please disambiguate by...
660 * Saying "./%s" if you mean a file; or
661 * Giving --format-patch option if you mean a range.
663 } catch Git::Error::Command with {
664 # Not a valid revision. Treat it as a filename.
665 return 0;
669 # Now that all the defaults are set, process the rest of the command line
670 # arguments and collect up the files that need to be processed.
671 my @rev_list_opts;
672 while (defined(my $f = shift @ARGV)) {
673 if ($f eq "--") {
674 push @rev_list_opts, "--", @ARGV;
675 @ARGV = ();
676 } elsif (-d $f and !is_format_patch_arg($f)) {
677 opendir my $dh, $f
678 or die sprintf(__("Failed to opendir %s: %s"), $f, $!);
680 push @files, grep { -f $_ } map { catfile($f, $_) }
681 sort readdir $dh;
682 closedir $dh;
683 } elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) {
684 push @files, $f;
685 } else {
686 push @rev_list_opts, $f;
690 if (@rev_list_opts) {
691 die __("Cannot run git format-patch from outside a repository\n")
692 unless $repo;
693 push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
696 @files = handle_backup_files(@files);
698 if ($validate) {
699 foreach my $f (@files) {
700 unless (-p $f) {
701 my $error = validate_patch($f, $target_xfer_encoding);
702 $error and die sprintf(__("fatal: %s: %s\nwarning: no patches were sent\n"),
703 $f, $error);
708 if (@files) {
709 unless ($quiet) {
710 print $_,"\n" for (@files);
712 } else {
713 print STDERR __("\nNo patch files specified!\n\n");
714 usage();
717 sub get_patch_subject {
718 my $fn = shift;
719 open (my $fh, '<', $fn);
720 while (my $line = <$fh>) {
721 next unless ($line =~ /^Subject: (.*)$/);
722 close $fh;
723 return "GIT: $1\n";
725 close $fh;
726 die sprintf(__("No subject line in %s?"), $fn);
729 if ($compose) {
730 # Note that this does not need to be secure, but we will make a small
731 # effort to have it be unique
732 $compose_filename = ($repo ?
733 tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
734 tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
735 open my $c, ">", $compose_filename
736 or die sprintf(__("Failed to open for writing %s: %s"), $compose_filename, $!);
739 my $tpl_sender = $sender || $repoauthor || $repocommitter || '';
740 my $tpl_subject = $initial_subject || '';
741 my $tpl_in_reply_to = $initial_in_reply_to || '';
742 my $tpl_reply_to = $reply_to || '';
744 print $c <<EOT1, Git::prefix_lines("GIT: ", __ <<EOT2), <<EOT3;
745 From $tpl_sender # This line is ignored.
746 EOT1
747 Lines beginning in "GIT:" will be removed.
748 Consider including an overall diffstat or table of contents
749 for the patch you are writing.
751 Clear the body content if you don't wish to send a summary.
752 EOT2
753 From: $tpl_sender
754 Reply-To: $tpl_reply_to
755 Subject: $tpl_subject
756 In-Reply-To: $tpl_in_reply_to
758 EOT3
759 for my $f (@files) {
760 print $c get_patch_subject($f);
762 close $c;
764 if ($annotate) {
765 do_edit($compose_filename, @files);
766 } else {
767 do_edit($compose_filename);
770 open $c, "<", $compose_filename
771 or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
773 if (!defined $compose_encoding) {
774 $compose_encoding = "UTF-8";
777 my %parsed_email;
778 while (my $line = <$c>) {
779 next if $line =~ m/^GIT:/;
780 parse_header_line($line, \%parsed_email);
781 if ($line =~ /^$/) {
782 $parsed_email{'body'} = filter_body($c);
785 close $c;
787 open my $c2, ">", $compose_filename . ".final"
788 or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
791 if ($parsed_email{'From'}) {
792 $sender = delete($parsed_email{'From'});
794 if ($parsed_email{'In-Reply-To'}) {
795 $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
797 if ($parsed_email{'Reply-To'}) {
798 $reply_to = delete($parsed_email{'Reply-To'});
800 if ($parsed_email{'Subject'}) {
801 $initial_subject = delete($parsed_email{'Subject'});
802 print $c2 "Subject: " .
803 quote_subject($initial_subject, $compose_encoding) .
804 "\n";
807 if ($parsed_email{'MIME-Version'}) {
808 print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
809 "Content-Type: $parsed_email{'Content-Type'};\n",
810 "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
811 delete($parsed_email{'MIME-Version'});
812 delete($parsed_email{'Content-Type'});
813 delete($parsed_email{'Content-Transfer-Encoding'});
814 } elsif (file_has_nonascii($compose_filename)) {
815 my $content_type = (delete($parsed_email{'Content-Type'}) or
816 "text/plain; charset=$compose_encoding");
817 print $c2 "MIME-Version: 1.0\n",
818 "Content-Type: $content_type\n",
819 "Content-Transfer-Encoding: 8bit\n";
821 # Preserve unknown headers
822 foreach my $key (keys %parsed_email) {
823 next if $key eq 'body';
824 print $c2 "$key: $parsed_email{$key}";
827 if ($parsed_email{'body'}) {
828 print $c2 "\n$parsed_email{'body'}\n";
829 delete($parsed_email{'body'});
830 } else {
831 print __("Summary email is empty, skipping it\n");
832 $compose = -1;
835 close $c2;
837 } elsif ($annotate) {
838 do_edit(@files);
841 sub ask {
842 my ($prompt, %arg) = @_;
843 my $valid_re = $arg{valid_re};
844 my $default = $arg{default};
845 my $confirm_only = $arg{confirm_only};
846 my $resp;
847 my $i = 0;
848 return defined $default ? $default : undef
849 unless defined $term->IN and defined fileno($term->IN) and
850 defined $term->OUT and defined fileno($term->OUT);
851 while ($i++ < 10) {
852 $resp = $term->readline($prompt);
853 if (!defined $resp) { # EOF
854 print "\n";
855 return defined $default ? $default : undef;
857 if ($resp eq '' and defined $default) {
858 return $default;
860 if (!defined $valid_re or $resp =~ /$valid_re/) {
861 return $resp;
863 if ($confirm_only) {
864 my $yesno = $term->readline(
865 # TRANSLATORS: please keep [y/N] as is.
866 sprintf(__("Are you sure you want to use <%s> [y/N]? "), $resp));
867 if (defined $yesno && $yesno =~ /y/i) {
868 return $resp;
872 return;
875 sub parse_header_line {
876 my $lines = shift;
877 my $parsed_line = shift;
878 my $addr_pat = join "|", qw(To Cc Bcc);
880 foreach (split(/\n/, $lines)) {
881 if (/^($addr_pat):\s*(.+)$/i) {
882 $parsed_line->{$1} = [ parse_address_line($2) ];
883 } elsif (/^([^:]*):\s*(.+)\s*$/i) {
884 $parsed_line->{$1} = $2;
889 sub filter_body {
890 my $c = shift;
891 my $body = "";
892 while (my $body_line = <$c>) {
893 if ($body_line !~ m/^GIT:/) {
894 $body .= $body_line;
897 return $body;
901 my %broken_encoding;
903 sub file_declares_8bit_cte {
904 my $fn = shift;
905 open (my $fh, '<', $fn);
906 while (my $line = <$fh>) {
907 last if ($line =~ /^$/);
908 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
910 close $fh;
911 return 0;
914 foreach my $f (@files) {
915 next unless (body_or_subject_has_nonascii($f)
916 && !file_declares_8bit_cte($f));
917 $broken_encoding{$f} = 1;
920 if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
921 print __("The following files are 8bit, but do not declare " .
922 "a Content-Transfer-Encoding.\n");
923 foreach my $f (sort keys %broken_encoding) {
924 print " $f\n";
926 $auto_8bit_encoding = ask(__("Which 8bit encoding should I declare [UTF-8]? "),
927 valid_re => qr/.{4}/, confirm_only => 1,
928 default => "UTF-8");
931 if (!$force) {
932 for my $f (@files) {
933 if (get_patch_subject($f) =~ /\Q*** SUBJECT HERE ***\E/) {
934 die sprintf(__("Refusing to send because the patch\n\t%s\n"
935 . "has the template subject '*** SUBJECT HERE ***'. "
936 . "Pass --force if you really want to send.\n"), $f);
941 if (defined $sender) {
942 $sender =~ s/^\s+|\s+$//g;
943 ($sender) = expand_aliases($sender);
944 } else {
945 $sender = $repoauthor || $repocommitter || '';
948 # $sender could be an already sanitized address
949 # (e.g. sendemail.from could be manually sanitized by user).
950 # But it's a no-op to run sanitize_address on an already sanitized address.
951 $sender = sanitize_address($sender);
953 my $to_whom = __("To whom should the emails be sent (if anyone)?");
954 my $prompting = 0;
955 if (!@initial_to && !defined $to_cmd) {
956 my $to = ask("$to_whom ",
957 default => "",
958 valid_re => qr/\@.*\./, confirm_only => 1);
959 push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
960 $prompting++;
963 sub expand_aliases {
964 return map { expand_one_alias($_) } @_;
967 my %EXPANDED_ALIASES;
968 sub expand_one_alias {
969 my $alias = shift;
970 if ($EXPANDED_ALIASES{$alias}) {
971 die sprintf(__("fatal: alias '%s' expands to itself\n"), $alias);
973 local $EXPANDED_ALIASES{$alias} = 1;
974 return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
977 @initial_to = process_address_list(@initial_to);
978 @initial_cc = process_address_list(@initial_cc);
979 @initial_bcc = process_address_list(@initial_bcc);
981 if ($thread && !defined $initial_in_reply_to && $prompting) {
982 $initial_in_reply_to = ask(
983 __("Message-ID to be used as In-Reply-To for the first email (if any)? "),
984 default => "",
985 valid_re => qr/\@.*\./, confirm_only => 1);
987 if (defined $initial_in_reply_to) {
988 $initial_in_reply_to =~ s/^\s*<?//;
989 $initial_in_reply_to =~ s/>?\s*$//;
990 $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
993 if (defined $reply_to) {
994 $reply_to =~ s/^\s+|\s+$//g;
995 ($reply_to) = expand_aliases($reply_to);
996 $reply_to = sanitize_address($reply_to);
999 if (!defined $smtp_server) {
1000 my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
1001 push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
1002 foreach (@sendmail_paths) {
1003 if (-x $_) {
1004 $smtp_server = $_;
1005 last;
1008 $smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
1011 if ($compose && $compose > 0) {
1012 @files = ($compose_filename . ".final", @files);
1015 # Variables we set as part of the loop over files
1016 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
1017 $needs_confirm, $message_num, $ask_default);
1019 sub extract_valid_address {
1020 my $address = shift;
1021 my $local_part_regexp = qr/[^<>"\s@]+/;
1022 my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
1024 # check for a local address:
1025 return $address if ($address =~ /^($local_part_regexp)$/);
1027 $address =~ s/^\s*<(.*)>\s*$/$1/;
1028 if ($have_email_valid) {
1029 return scalar Email::Valid->address($address);
1032 # less robust/correct than the monster regexp in Email::Valid,
1033 # but still does a 99% job, and one less dependency
1034 return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
1035 return;
1038 sub extract_valid_address_or_die {
1039 my $address = shift;
1040 $address = extract_valid_address($address);
1041 die sprintf(__("error: unable to extract a valid address from: %s\n"), $address)
1042 if !$address;
1043 return $address;
1046 sub validate_address {
1047 my $address = shift;
1048 while (!extract_valid_address($address)) {
1049 printf STDERR __("error: unable to extract a valid address from: %s\n"), $address;
1050 # TRANSLATORS: Make sure to include [q] [d] [e] in your
1051 # translation. The program will only accept English input
1052 # at this point.
1053 $_ = ask(__("What to do with this address? ([q]uit|[d]rop|[e]dit): "),
1054 valid_re => qr/^(?:quit|q|drop|d|edit|e)/i,
1055 default => 'q');
1056 if (/^d/i) {
1057 return undef;
1058 } elsif (/^q/i) {
1059 cleanup_compose_files();
1060 exit(0);
1062 $address = ask("$to_whom ",
1063 default => "",
1064 valid_re => qr/\@.*\./, confirm_only => 1);
1066 return $address;
1069 sub validate_address_list {
1070 return (grep { defined $_ }
1071 map { validate_address($_) } @_);
1074 # Usually don't need to change anything below here.
1076 # we make a "fake" message id by taking the current number
1077 # of seconds since the beginning of Unix time and tacking on
1078 # a random number to the end, in case we are called quicker than
1079 # 1 second since the last time we were called.
1081 # We'll setup a template for the message id, using the "from" address:
1083 my ($message_id_stamp, $message_id_serial);
1084 sub make_message_id {
1085 my $uniq;
1086 if (!defined $message_id_stamp) {
1087 $message_id_stamp = strftime("%Y%m%d%H%M%S.$$", gmtime(time));
1088 $message_id_serial = 0;
1090 $message_id_serial++;
1091 $uniq = "$message_id_stamp-$message_id_serial";
1093 my $du_part;
1094 for ($sender, $repocommitter, $repoauthor) {
1095 $du_part = extract_valid_address(sanitize_address($_));
1096 last if (defined $du_part and $du_part ne '');
1098 if (not defined $du_part or $du_part eq '') {
1099 require Sys::Hostname;
1100 $du_part = 'user@' . Sys::Hostname::hostname();
1102 my $message_id_template = "<%s-%s>";
1103 $message_id = sprintf($message_id_template, $uniq, $du_part);
1104 #print "new message id = $message_id\n"; # Was useful for debugging
1109 $time = time - scalar $#files;
1111 sub unquote_rfc2047 {
1112 local ($_) = @_;
1113 my $charset;
1114 my $sep = qr/[ \t]+/;
1115 s{$re_encoded_word(?:$sep$re_encoded_word)*}{
1116 my @words = split $sep, $&;
1117 foreach (@words) {
1118 m/$re_encoded_word/;
1119 $charset = $1;
1120 my $encoding = $2;
1121 my $text = $3;
1122 if ($encoding eq 'q' || $encoding eq 'Q') {
1123 $_ = $text;
1124 s/_/ /g;
1125 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1126 } else {
1127 # other encodings not supported yet
1130 join '', @words;
1131 }eg;
1132 return wantarray ? ($_, $charset) : $_;
1135 sub quote_rfc2047 {
1136 local $_ = shift;
1137 my $encoding = shift || 'UTF-8';
1138 s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
1139 s/(.*)/=\?$encoding\?q\?$1\?=/;
1140 return $_;
1143 sub is_rfc2047_quoted {
1144 my $s = shift;
1145 length($s) <= 75 &&
1146 $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1149 sub subject_needs_rfc2047_quoting {
1150 my $s = shift;
1152 return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1155 sub quote_subject {
1156 local $subject = shift;
1157 my $encoding = shift || 'UTF-8';
1159 if (subject_needs_rfc2047_quoting($subject)) {
1160 return quote_rfc2047($subject, $encoding);
1162 return $subject;
1165 # use the simplest quoting being able to handle the recipient
1166 sub sanitize_address {
1167 my ($recipient) = @_;
1169 # remove garbage after email address
1170 $recipient =~ s/(.*>).*$/$1/;
1172 my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
1174 if (not $recipient_name) {
1175 return $recipient;
1178 # if recipient_name is already quoted, do nothing
1179 if (is_rfc2047_quoted($recipient_name)) {
1180 return $recipient;
1183 # remove non-escaped quotes
1184 $recipient_name =~ s/(^|[^\\])"/$1/g;
1186 # rfc2047 is needed if a non-ascii char is included
1187 if ($recipient_name =~ /[^[:ascii:]]/) {
1188 $recipient_name = quote_rfc2047($recipient_name);
1191 # double quotes are needed if specials or CTLs are included
1192 elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
1193 $recipient_name =~ s/([\\\r])/\\$1/g;
1194 $recipient_name = qq["$recipient_name"];
1197 return "$recipient_name $recipient_addr";
1201 sub strip_garbage_one_address {
1202 my ($addr) = @_;
1203 chomp $addr;
1204 if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1205 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1206 # Foo Bar <foobar@example.com> [possibly garbage here]
1207 return $1;
1209 if ($addr =~ /^(<[^>]*>).*/) {
1210 # <foo@example.com> [possibly garbage here]
1211 # if garbage contains other addresses, they are ignored.
1212 return $1;
1214 if ($addr =~ /^([^"#,\s]*)/) {
1215 # address without quoting: remove anything after the address
1216 return $1;
1218 return $addr;
1221 sub sanitize_address_list {
1222 return (map { sanitize_address($_) } @_);
1225 sub process_address_list {
1226 my @addr_list = map { parse_address_line($_) } @_;
1227 @addr_list = expand_aliases(@addr_list);
1228 @addr_list = sanitize_address_list(@addr_list);
1229 @addr_list = validate_address_list(@addr_list);
1230 return @addr_list;
1233 # Returns the local Fully Qualified Domain Name (FQDN) if available.
1235 # Tightly configured MTAa require that a caller sends a real DNS
1236 # domain name that corresponds the IP address in the HELO/EHLO
1237 # handshake. This is used to verify the connection and prevent
1238 # spammers from trying to hide their identity. If the DNS and IP don't
1239 # match, the receiving MTA may deny the connection.
1241 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
1243 # Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
1244 # Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
1246 # This maildomain*() code is based on ideas in Perl library Test::Reporter
1247 # /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
1249 sub valid_fqdn {
1250 my $domain = shift;
1251 return defined $domain && !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1254 sub maildomain_net {
1255 my $maildomain;
1257 my $domain = Net::Domain::domainname();
1258 $maildomain = $domain if valid_fqdn($domain);
1260 return $maildomain;
1263 sub maildomain_mta {
1264 my $maildomain;
1266 for my $host (qw(mailhost localhost)) {
1267 my $smtp = Net::SMTP->new($host);
1268 if (defined $smtp) {
1269 my $domain = $smtp->domain;
1270 $smtp->quit;
1272 $maildomain = $domain if valid_fqdn($domain);
1274 last if $maildomain;
1278 return $maildomain;
1281 sub maildomain {
1282 return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
1285 sub smtp_host_string {
1286 if (defined $smtp_server_port) {
1287 return "$smtp_server:$smtp_server_port";
1288 } else {
1289 return $smtp_server;
1293 # Returns 1 if authentication succeeded or was not necessary
1294 # (smtp_user was not specified), and 0 otherwise.
1296 sub smtp_auth_maybe {
1297 if (!defined $smtp_authuser || $auth || (defined $smtp_auth && $smtp_auth eq "none")) {
1298 return 1;
1301 # Workaround AUTH PLAIN/LOGIN interaction defect
1302 # with Authen::SASL::Cyrus
1303 eval {
1304 require Authen::SASL;
1305 Authen::SASL->import(qw(Perl));
1308 # Check mechanism naming as defined in:
1309 # https://tools.ietf.org/html/rfc4422#page-8
1310 if ($smtp_auth && $smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
1311 die "invalid smtp auth: '${smtp_auth}'";
1314 # TODO: Authentication may fail not because credentials were
1315 # invalid but due to other reasons, in which we should not
1316 # reject credentials.
1317 $auth = Git::credential({
1318 'protocol' => 'smtp',
1319 'host' => smtp_host_string(),
1320 'username' => $smtp_authuser,
1321 # if there's no password, "git credential fill" will
1322 # give us one, otherwise it'll just pass this one.
1323 'password' => $smtp_authpass
1324 }, sub {
1325 my $cred = shift;
1327 if ($smtp_auth) {
1328 my $sasl = Authen::SASL->new(
1329 mechanism => $smtp_auth,
1330 callback => {
1331 user => $cred->{'username'},
1332 pass => $cred->{'password'},
1333 authname => $cred->{'username'},
1337 return !!$smtp->auth($sasl);
1340 return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
1343 return $auth;
1346 sub ssl_verify_params {
1347 eval {
1348 require IO::Socket::SSL;
1349 IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1351 if ($@) {
1352 print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1353 return;
1356 if (!defined $smtp_ssl_cert_path) {
1357 # use the OpenSSL defaults
1358 return (SSL_verify_mode => SSL_VERIFY_PEER());
1361 if ($smtp_ssl_cert_path eq "") {
1362 return (SSL_verify_mode => SSL_VERIFY_NONE());
1363 } elsif (-d $smtp_ssl_cert_path) {
1364 return (SSL_verify_mode => SSL_VERIFY_PEER(),
1365 SSL_ca_path => $smtp_ssl_cert_path);
1366 } elsif (-f $smtp_ssl_cert_path) {
1367 return (SSL_verify_mode => SSL_VERIFY_PEER(),
1368 SSL_ca_file => $smtp_ssl_cert_path);
1369 } else {
1370 die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1374 sub file_name_is_absolute {
1375 my ($path) = @_;
1377 # msys does not grok DOS drive-prefixes
1378 if ($^O eq 'msys') {
1379 return ($path =~ m#^/# || $path =~ m#^[a-zA-Z]\:#)
1382 require File::Spec::Functions;
1383 return File::Spec::Functions::file_name_is_absolute($path);
1386 # Prepares the email, then asks the user what to do.
1388 # If the user chooses to send the email, it's sent and 1 is returned.
1389 # If the user chooses not to send the email, 0 is returned.
1390 # If the user decides they want to make further edits, -1 is returned and the
1391 # caller is expected to call send_message again after the edits are performed.
1393 # If an error occurs sending the email, this just dies.
1395 sub send_message {
1396 my @recipients = unique_email_list(@to);
1397 @cc = (grep { my $cc = extract_valid_address_or_die($_);
1398 not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
1400 @cc);
1401 my $to = join (",\n\t", @recipients);
1402 @recipients = unique_email_list(@recipients,@cc,@initial_bcc);
1403 @recipients = (map { extract_valid_address_or_die($_) } @recipients);
1404 my $date = format_2822_time($time++);
1405 my $gitversion = '@@GIT_VERSION@@';
1406 if ($gitversion =~ m/..GIT_VERSION../) {
1407 $gitversion = Git::version();
1410 my $cc = join(",\n\t", unique_email_list(@cc));
1411 my $ccline = "";
1412 if ($cc ne '') {
1413 $ccline = "\nCc: $cc";
1415 make_message_id() unless defined($message_id);
1417 my $header = "From: $sender
1418 To: $to${ccline}
1419 Subject: $subject
1420 Date: $date
1421 Message-Id: $message_id
1423 if ($use_xmailer) {
1424 $header .= "X-Mailer: git-send-email $gitversion\n";
1426 if ($in_reply_to) {
1428 $header .= "In-Reply-To: $in_reply_to\n";
1429 $header .= "References: $references\n";
1431 if ($reply_to) {
1432 $header .= "Reply-To: $reply_to\n";
1434 if (@xh) {
1435 $header .= join("\n", @xh) . "\n";
1438 my @sendmail_parameters = ('-i', @recipients);
1439 my $raw_from = $sender;
1440 if (defined $envelope_sender && $envelope_sender ne "auto") {
1441 $raw_from = $envelope_sender;
1443 $raw_from = extract_valid_address($raw_from);
1444 unshift (@sendmail_parameters,
1445 '-f', $raw_from) if(defined $envelope_sender);
1447 if ($needs_confirm && !$dry_run) {
1448 print "\n$header\n";
1449 if ($needs_confirm eq "inform") {
1450 $confirm_unconfigured = 0; # squelch this message for the rest of this run
1451 $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation
1452 print __ <<EOF ;
1453 The Cc list above has been expanded by additional
1454 addresses found in the patch commit message. By default
1455 send-email prompts before sending whenever this occurs.
1456 This behavior is controlled by the sendemail.confirm
1457 configuration setting.
1459 For additional information, run 'git send-email --help'.
1460 To retain the current behavior, but squelch this message,
1461 run 'git config --global sendemail.confirm auto'.
1465 # TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
1466 # translation. The program will only accept English input
1467 # at this point.
1468 $_ = ask(__("Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "),
1469 valid_re => qr/^(?:yes|y|no|n|edit|e|quit|q|all|a)/i,
1470 default => $ask_default);
1471 die __("Send this email reply required") unless defined $_;
1472 if (/^n/i) {
1473 return 0;
1474 } elsif (/^e/i) {
1475 return -1;
1476 } elsif (/^q/i) {
1477 cleanup_compose_files();
1478 exit(0);
1479 } elsif (/^a/i) {
1480 $confirm = 'never';
1484 unshift (@sendmail_parameters, @smtp_server_options);
1486 if ($dry_run) {
1487 # We don't want to send the email.
1488 } elsif (file_name_is_absolute($smtp_server)) {
1489 my $pid = open my $sm, '|-';
1490 defined $pid or die $!;
1491 if (!$pid) {
1492 exec($smtp_server, @sendmail_parameters) or die $!;
1494 print $sm "$header\n$message";
1495 close $sm or die $!;
1496 } else {
1498 if (!defined $smtp_server) {
1499 die __("The required SMTP server is not properly defined.")
1502 require Net::SMTP;
1503 my $use_net_smtp_ssl = version->parse($Net::SMTP::VERSION) < version->parse("2.34");
1504 $smtp_domain ||= maildomain();
1506 if ($smtp_encryption eq 'ssl') {
1507 $smtp_server_port ||= 465; # ssmtp
1508 require IO::Socket::SSL;
1510 # Suppress "variable accessed once" warning.
1512 no warnings 'once';
1513 $IO::Socket::SSL::DEBUG = 1;
1516 # Net::SMTP::SSL->new() does not forward any SSL options
1517 IO::Socket::SSL::set_client_defaults(
1518 ssl_verify_params());
1520 if ($use_net_smtp_ssl) {
1521 require Net::SMTP::SSL;
1522 $smtp ||= Net::SMTP::SSL->new($smtp_server,
1523 Hello => $smtp_domain,
1524 Port => $smtp_server_port,
1525 Debug => $debug_net_smtp);
1527 else {
1528 $smtp ||= Net::SMTP->new($smtp_server,
1529 Hello => $smtp_domain,
1530 Port => $smtp_server_port,
1531 Debug => $debug_net_smtp,
1532 SSL => 1);
1535 elsif (!$smtp) {
1536 $smtp_server_port ||= 25;
1537 $smtp ||= Net::SMTP->new($smtp_server,
1538 Hello => $smtp_domain,
1539 Debug => $debug_net_smtp,
1540 Port => $smtp_server_port);
1541 if ($smtp_encryption eq 'tls' && $smtp) {
1542 if ($use_net_smtp_ssl) {
1543 $smtp->command('STARTTLS');
1544 $smtp->response();
1545 if ($smtp->code != 220) {
1546 die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message);
1548 require Net::SMTP::SSL;
1549 $smtp = Net::SMTP::SSL->start_SSL($smtp,
1550 ssl_verify_params())
1551 or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
1553 else {
1554 $smtp->starttls(ssl_verify_params())
1555 or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
1557 # Send EHLO again to receive fresh
1558 # supported commands
1559 $smtp->hello($smtp_domain);
1563 if (!$smtp) {
1564 die __("Unable to initialize SMTP properly. Check config and use --smtp-debug."),
1565 " VALUES: server=$smtp_server ",
1566 "encryption=$smtp_encryption ",
1567 "hello=$smtp_domain",
1568 defined $smtp_server_port ? " port=$smtp_server_port" : "";
1571 smtp_auth_maybe or die $smtp->message;
1573 $smtp->mail( $raw_from ) or die $smtp->message;
1574 $smtp->to( @recipients ) or die $smtp->message;
1575 $smtp->data or die $smtp->message;
1576 $smtp->datasend("$header\n") or die $smtp->message;
1577 my @lines = split /^/, $message;
1578 foreach my $line (@lines) {
1579 $smtp->datasend("$line") or die $smtp->message;
1581 $smtp->dataend() or die $smtp->message;
1582 $smtp->code =~ /250|200/ or die sprintf(__("Failed to send %s\n"), $subject).$smtp->message;
1584 if ($quiet) {
1585 printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
1586 } else {
1587 print($dry_run ? __("Dry-OK. Log says:\n") : __("OK. Log says:\n"));
1588 if (!file_name_is_absolute($smtp_server)) {
1589 print "Server: $smtp_server\n";
1590 print "MAIL FROM:<$raw_from>\n";
1591 foreach my $entry (@recipients) {
1592 print "RCPT TO:<$entry>\n";
1594 } else {
1595 print "Sendmail: $smtp_server ".join(' ',@sendmail_parameters)."\n";
1597 print $header, "\n";
1598 if ($smtp) {
1599 print __("Result: "), $smtp->code, ' ',
1600 ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
1601 } else {
1602 print __("Result: OK\n");
1606 return 1;
1609 $in_reply_to = $initial_in_reply_to;
1610 $references = $initial_in_reply_to || '';
1611 $subject = $initial_subject;
1612 $message_num = 0;
1614 # Prepares the email, prompts the user, sends it out
1615 # Returns 0 if an edit was done and the function should be called again, or 1
1616 # otherwise.
1617 sub process_file {
1618 my ($t) = @_;
1620 open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
1622 my $author = undef;
1623 my $sauthor = undef;
1624 my $author_encoding;
1625 my $has_content_type;
1626 my $body_encoding;
1627 my $xfer_encoding;
1628 my $has_mime_version;
1629 @to = ();
1630 @cc = ();
1631 @xh = ();
1632 my $input_format = undef;
1633 my @header = ();
1634 $message = "";
1635 $message_num++;
1636 # First unfold multiline header fields
1637 while(<$fh>) {
1638 last if /^\s*$/;
1639 if (/^\s+\S/ and @header) {
1640 chomp($header[$#header]);
1641 s/^\s+/ /;
1642 $header[$#header] .= $_;
1643 } else {
1644 push(@header, $_);
1647 # Now parse the header
1648 foreach(@header) {
1649 if (/^From /) {
1650 $input_format = 'mbox';
1651 next;
1653 chomp;
1654 if (!defined $input_format && /^[-A-Za-z]+:\s/) {
1655 $input_format = 'mbox';
1658 if (defined $input_format && $input_format eq 'mbox') {
1659 if (/^Subject:\s+(.*)$/i) {
1660 $subject = $1;
1662 elsif (/^From:\s+(.*)$/i) {
1663 ($author, $author_encoding) = unquote_rfc2047($1);
1664 $sauthor = sanitize_address($author);
1665 next if $suppress_cc{'author'};
1666 next if $suppress_cc{'self'} and $sauthor eq $sender;
1667 printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1668 $1, $_) unless $quiet;
1669 push @cc, $1;
1671 elsif (/^To:\s+(.*)$/i) {
1672 foreach my $addr (parse_address_line($1)) {
1673 printf(__("(mbox) Adding to: %s from line '%s'\n"),
1674 $addr, $_) unless $quiet;
1675 push @to, $addr;
1678 elsif (/^Cc:\s+(.*)$/i) {
1679 foreach my $addr (parse_address_line($1)) {
1680 my $qaddr = unquote_rfc2047($addr);
1681 my $saddr = sanitize_address($qaddr);
1682 if ($saddr eq $sender) {
1683 next if ($suppress_cc{'self'});
1684 } else {
1685 next if ($suppress_cc{'cc'});
1687 printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1688 $addr, $_) unless $quiet;
1689 push @cc, $addr;
1692 elsif (/^Content-type:/i) {
1693 $has_content_type = 1;
1694 if (/charset="?([^ "]+)/) {
1695 $body_encoding = $1;
1697 push @xh, $_;
1699 elsif (/^MIME-Version/i) {
1700 $has_mime_version = 1;
1701 push @xh, $_;
1703 elsif (/^Message-Id: (.*)/i) {
1704 $message_id = $1;
1706 elsif (/^Content-Transfer-Encoding: (.*)/i) {
1707 $xfer_encoding = $1 if not defined $xfer_encoding;
1709 elsif (/^In-Reply-To: (.*)/i) {
1710 if (!$initial_in_reply_to || $thread) {
1711 $in_reply_to = $1;
1714 elsif (/^References: (.*)/i) {
1715 if (!$initial_in_reply_to || $thread) {
1716 $references = $1;
1719 elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1720 push @xh, $_;
1722 } else {
1723 # In the traditional
1724 # "send lots of email" format,
1725 # line 1 = cc
1726 # line 2 = subject
1727 # So let's support that, too.
1728 $input_format = 'lots';
1729 if (@cc == 0 && !$suppress_cc{'cc'}) {
1730 printf(__("(non-mbox) Adding cc: %s from line '%s'\n"),
1731 $_, $_) unless $quiet;
1732 push @cc, $_;
1733 } elsif (!defined $subject) {
1734 $subject = $_;
1738 # Now parse the message body
1739 while(<$fh>) {
1740 $message .= $_;
1741 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1742 chomp;
1743 my ($what, $c) = ($1, $2);
1744 # strip garbage for the address we'll use:
1745 $c = strip_garbage_one_address($c);
1746 # sanitize a bit more to decide whether to suppress the address:
1747 my $sc = sanitize_address($c);
1748 if ($sc eq $sender) {
1749 next if ($suppress_cc{'self'});
1750 } else {
1751 if ($what =~ /^Signed-off-by$/i) {
1752 next if $suppress_cc{'sob'};
1753 } elsif ($what =~ /-by$/i) {
1754 next if $suppress_cc{'misc-by'};
1755 } elsif ($what =~ /Cc/i) {
1756 next if $suppress_cc{'bodycc'};
1759 if ($c !~ /.+@.+|<.+>/) {
1760 printf("(body) Ignoring %s from line '%s'\n",
1761 $what, $_) unless $quiet;
1762 next;
1764 push @cc, $c;
1765 printf(__("(body) Adding cc: %s from line '%s'\n"),
1766 $c, $_) unless $quiet;
1769 close $fh;
1771 push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
1772 if defined $to_cmd;
1773 push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
1774 if defined $cc_cmd && !$suppress_cc{'cccmd'};
1776 if ($broken_encoding{$t} && !$has_content_type) {
1777 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1778 $has_content_type = 1;
1779 push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
1780 $body_encoding = $auto_8bit_encoding;
1783 if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) {
1784 $subject = quote_subject($subject, $auto_8bit_encoding);
1787 if (defined $sauthor and $sauthor ne $sender) {
1788 $message = "From: $author\n\n$message";
1789 if (defined $author_encoding) {
1790 if ($has_content_type) {
1791 if ($body_encoding eq $author_encoding) {
1792 # ok, we already have the right encoding
1794 else {
1795 # uh oh, we should re-encode
1798 else {
1799 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1800 $has_content_type = 1;
1801 push @xh,
1802 "Content-Type: text/plain; charset=$author_encoding";
1806 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1807 ($message, $xfer_encoding) = apply_transfer_encoding(
1808 $message, $xfer_encoding, $target_xfer_encoding);
1809 push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1810 unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1812 $needs_confirm = (
1813 $confirm eq "always" or
1814 ($confirm =~ /^(?:auto|cc)$/ && @cc) or
1815 ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
1816 $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
1818 @to = process_address_list(@to);
1819 @cc = process_address_list(@cc);
1821 @to = (@initial_to, @to);
1822 @cc = (@initial_cc, @cc);
1824 if ($message_num == 1) {
1825 if (defined $cover_cc and $cover_cc) {
1826 @initial_cc = @cc;
1828 if (defined $cover_to and $cover_to) {
1829 @initial_to = @to;
1833 my $message_was_sent = send_message();
1834 if ($message_was_sent == -1) {
1835 do_edit($t);
1836 return 0;
1839 # set up for the next message
1840 if ($thread && $message_was_sent &&
1841 ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
1842 $message_num == 1)) {
1843 $in_reply_to = $message_id;
1844 if (length $references > 0) {
1845 $references .= "\n $message_id";
1846 } else {
1847 $references = "$message_id";
1850 $message_id = undef;
1851 $num_sent++;
1852 if (defined $batch_size && $num_sent == $batch_size) {
1853 $num_sent = 0;
1854 $smtp->quit if defined $smtp;
1855 undef $smtp;
1856 undef $auth;
1857 sleep($relogin_delay) if defined $relogin_delay;
1860 return 1;
1863 foreach my $t (@files) {
1864 while (!process_file($t)) {
1865 # user edited the file
1869 # Execute a command (e.g. $to_cmd) to get a list of email addresses
1870 # and return a results array
1871 sub recipients_cmd {
1872 my ($prefix, $what, $cmd, $file) = @_;
1874 my @addresses = ();
1875 open my $fh, "-|", "$cmd \Q$file\E"
1876 or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
1877 while (my $address = <$fh>) {
1878 $address =~ s/^\s*//g;
1879 $address =~ s/\s*$//g;
1880 $address = sanitize_address($address);
1881 next if ($address eq $sender and $suppress_cc{'self'});
1882 push @addresses, $address;
1883 printf(__("(%s) Adding %s: %s from: '%s'\n"),
1884 $prefix, $what, $address, $cmd) unless $quiet;
1886 close $fh
1887 or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
1888 return @addresses;
1891 cleanup_compose_files();
1893 sub cleanup_compose_files {
1894 unlink($compose_filename, $compose_filename . ".final") if $compose;
1897 $smtp->quit if $smtp;
1899 sub apply_transfer_encoding {
1900 my $message = shift;
1901 my $from = shift;
1902 my $to = shift;
1904 return ($message, $to) if ($from eq $to and $from ne '7bit');
1906 require MIME::QuotedPrint;
1907 require MIME::Base64;
1909 $message = MIME::QuotedPrint::decode($message)
1910 if ($from eq 'quoted-printable');
1911 $message = MIME::Base64::decode($message)
1912 if ($from eq 'base64');
1914 $to = ($message =~ /(?:.{999,}|\r)/) ? 'quoted-printable' : '8bit'
1915 if $to eq 'auto';
1917 die __("cannot send message as 7bit")
1918 if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
1919 return ($message, $to)
1920 if ($to eq '7bit' or $to eq '8bit');
1921 return (MIME::QuotedPrint::encode($message, "\n", 0), $to)
1922 if ($to eq 'quoted-printable');
1923 return (MIME::Base64::encode($message, "\n"), $to)
1924 if ($to eq 'base64');
1925 die __("invalid transfer encoding");
1928 sub unique_email_list {
1929 my %seen;
1930 my @emails;
1932 foreach my $entry (@_) {
1933 my $clean = extract_valid_address_or_die($entry);
1934 $seen{$clean} ||= 0;
1935 next if $seen{$clean}++;
1936 push @emails, $entry;
1938 return @emails;
1941 sub validate_patch {
1942 my ($fn, $xfer_encoding) = @_;
1944 if ($repo) {
1945 my $validate_hook = catfile(catdir($repo->repo_path(), 'hooks'),
1946 'sendemail-validate');
1947 my $hook_error;
1948 if (-x $validate_hook) {
1949 my $target = abs_path($fn);
1950 # The hook needs a correct cwd and GIT_DIR.
1951 my $cwd_save = cwd();
1952 chdir($repo->wc_path() or $repo->repo_path())
1953 or die("chdir: $!");
1954 local $ENV{"GIT_DIR"} = $repo->repo_path();
1955 $hook_error = "rejected by sendemail-validate hook"
1956 if system($validate_hook, $target);
1957 chdir($cwd_save) or die("chdir: $!");
1959 return $hook_error if $hook_error;
1962 # Any long lines will be automatically fixed if we use a suitable transfer
1963 # encoding.
1964 unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
1965 open(my $fh, '<', $fn)
1966 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
1967 while (my $line = <$fh>) {
1968 if (length($line) > 998) {
1969 return sprintf(__("%s: patch contains a line longer than 998 characters"), $.);
1973 return;
1976 sub handle_backup {
1977 my ($last, $lastlen, $file, $known_suffix) = @_;
1978 my ($suffix, $skip);
1980 $skip = 0;
1981 if (defined $last &&
1982 ($lastlen < length($file)) &&
1983 (substr($file, 0, $lastlen) eq $last) &&
1984 ($suffix = substr($file, $lastlen)) !~ /^[a-z0-9]/i) {
1985 if (defined $known_suffix && $suffix eq $known_suffix) {
1986 printf(__("Skipping %s with backup suffix '%s'.\n"), $file, $known_suffix);
1987 $skip = 1;
1988 } else {
1989 # TRANSLATORS: please keep "[y|N]" as is.
1990 my $answer = ask(sprintf(__("Do you really want to send %s? [y|N]: "), $file),
1991 valid_re => qr/^(?:y|n)/i,
1992 default => 'n');
1993 $skip = ($answer ne 'y');
1994 if ($skip) {
1995 $known_suffix = $suffix;
1999 return ($skip, $known_suffix);
2002 sub handle_backup_files {
2003 my @file = @_;
2004 my ($last, $lastlen, $known_suffix, $skip, @result);
2005 for my $file (@file) {
2006 ($skip, $known_suffix) = handle_backup($last, $lastlen,
2007 $file, $known_suffix);
2008 push @result, $file unless $skip;
2009 $last = $file;
2010 $lastlen = length($file);
2012 return @result;
2015 sub file_has_nonascii {
2016 my $fn = shift;
2017 open(my $fh, '<', $fn)
2018 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2019 while (my $line = <$fh>) {
2020 return 1 if $line =~ /[^[:ascii:]]/;
2022 return 0;
2025 sub body_or_subject_has_nonascii {
2026 my $fn = shift;
2027 open(my $fh, '<', $fn)
2028 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2029 while (my $line = <$fh>) {
2030 last if $line =~ /^$/;
2031 return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
2033 while (my $line = <$fh>) {
2034 return 1 if $line =~ /[^[:ascii:]]/;
2036 return 0;