builtin/cat-file: mark 'git cat-file' sparse-index compatible
[git/gitster.git] / git-send-email.perl
blobcdcee1d0cf96144bd986019663f13cea63e5ae40
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.008001;
20 use strict;
21 use warnings $ENV{GIT_PERL_FATAL_WARNINGS} ? qw(FATAL all) : ();
22 use Getopt::Long;
23 use Git::LoadCPAN::Error qw(:try);
24 use Git;
25 use Git::I18N;
27 Getopt::Long::Configure qw/ pass_through /;
29 sub usage {
30 print <<EOT;
31 git send-email [<options>] <file|directory>
32 git send-email [<options>] <format-patch options>
33 git send-email --dump-aliases
34 git send-email --translate-aliases
36 Composing:
37 --from <str> * Email From:
38 --[no-]to <str> * Email To:
39 --[no-]cc <str> * Email Cc:
40 --[no-]bcc <str> * Email Bcc:
41 --subject <str> * Email "Subject:"
42 --reply-to <str> * Email "Reply-To:"
43 --in-reply-to <str> * Email "In-Reply-To:"
44 --[no-]xmailer * Add "X-Mailer:" header (default).
45 --[no-]annotate * Review each patch that will be sent in an editor.
46 --compose * Open an editor for introduction.
47 --compose-encoding <str> * Encoding to assume for introduction.
48 --8bit-encoding <str> * Encoding to assume 8bit mails if undeclared
49 --transfer-encoding <str> * Transfer encoding to use (quoted-printable, 8bit, base64)
51 Sending:
52 --envelope-sender <str> * Email envelope sender.
53 --sendmail-cmd <str> * Command to run to send email.
54 --smtp-server <str:int> * Outgoing SMTP server to use. The port
55 is optional. Default 'localhost'.
56 --smtp-server-option <str> * Outgoing SMTP server option to use.
57 --smtp-server-port <int> * Outgoing SMTP server port.
58 --smtp-user <str> * Username for SMTP-AUTH.
59 --smtp-pass <str> * Password for SMTP-AUTH; not necessary.
60 --smtp-encryption <str> * tls or ssl; anything else disables.
61 --smtp-ssl * Deprecated. Use '--smtp-encryption ssl'.
62 --smtp-ssl-cert-path <str> * Path to ca-certificates (either directory or file).
63 Pass an empty string to disable certificate
64 verification.
65 --smtp-domain <str> * The domain name sent to HELO/EHLO handshake
66 --smtp-auth <str> * Space-separated list of allowed AUTH mechanisms, or
67 "none" to disable authentication.
68 This setting forces to use one of the listed mechanisms.
69 --no-smtp-auth Disable SMTP authentication. Shorthand for
70 `--smtp-auth=none`
71 --smtp-debug <0|1> * Disable, enable Net::SMTP debug.
73 --batch-size <int> * send max <int> message per connection.
74 --relogin-delay <int> * delay <int> seconds between two successive login.
75 This option can only be used with --batch-size
77 Automating:
78 --identity <str> * Use the sendemail.<id> options.
79 --to-cmd <str> * Email To: via `<str> \$patch_path`.
80 --cc-cmd <str> * Email Cc: via `<str> \$patch_path`.
81 --header-cmd <str> * Add headers via `<str> \$patch_path`.
82 --no-header-cmd * Disable any header command in use.
83 --suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
84 --[no-]cc-cover * Email Cc: addresses in the cover letter.
85 --[no-]to-cover * Email To: addresses in the cover letter.
86 --[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on.
87 --[no-]suppress-from * Send to self. Default off.
88 --[no-]chain-reply-to * Chain In-Reply-To: fields. Default off.
89 --[no-]thread * Use In-Reply-To: field. Default on.
91 Administering:
92 --confirm <str> * Confirm recipients before sending;
93 auto, cc, compose, always, or never.
94 --quiet * Output one line of info per email.
95 --dry-run * Don't actually send the emails.
96 --[no-]validate * Perform patch sanity checks. Default on.
97 --[no-]format-patch * understand any non optional arguments as
98 `git format-patch` ones.
99 --force * Send even if safety checks would prevent it.
101 Information:
102 --dump-aliases * Dump configured aliases and exit.
103 --translate-aliases * Translate aliases read from standard
104 input according to the configured email
105 alias file(s), outputting the result to
106 standard output.
109 exit(1);
112 sub uniq {
113 my %seen;
114 grep !$seen{$_}++, @_;
117 sub completion_helper {
118 my ($original_opts) = @_;
119 my %not_for_completion = (
120 "git-completion-helper" => undef,
121 "h" => undef,
123 my @send_email_opts = ();
125 foreach my $key (keys %$original_opts) {
126 unless (exists $not_for_completion{$key}) {
127 my $negatable = ($key =~ s/!$//);
129 if ($key =~ /[:=][si]$/) {
130 $key =~ s/[:=][si]$//;
131 push (@send_email_opts, "--$_=") foreach (split (/\|/, $key));
132 } else {
133 push (@send_email_opts, "--$_") foreach (split (/\|/, $key));
134 if ($negatable) {
135 push (@send_email_opts, "--no-$_") foreach (split (/\|/, $key));
141 my @format_patch_opts = split(/ /, Git::command('format-patch', '--git-completion-helper'));
142 my @opts = (@send_email_opts, @format_patch_opts);
143 @opts = uniq (grep !/^$/, @opts);
144 # There's an implicit '\n' here already, no need to add an explicit one.
145 print "@opts";
146 exit(0);
149 # most mail servers generate the Date: header, but not all...
150 sub format_2822_time {
151 my ($time) = @_;
152 my @localtm = localtime($time);
153 my @gmttm = gmtime($time);
154 my $localmin = $localtm[1] + $localtm[2] * 60;
155 my $gmtmin = $gmttm[1] + $gmttm[2] * 60;
156 if ($localtm[0] != $gmttm[0]) {
157 die __("local zone differs from GMT by a non-minute interval\n");
159 if ((($gmttm[6] + 1) % 7) == $localtm[6]) {
160 $localmin += 1440;
161 } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {
162 $localmin -= 1440;
163 } elsif ($gmttm[6] != $localtm[6]) {
164 die __("local time offset greater than or equal to 24 hours\n");
166 my $offset = $localmin - $gmtmin;
167 my $offhour = $offset / 60;
168 my $offmin = abs($offset % 60);
169 if (abs($offhour) >= 24) {
170 die __("local time offset greater than or equal to 24 hours\n");
173 return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d",
174 qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]],
175 $localtm[3],
176 qw(Jan Feb Mar Apr May Jun
177 Jul Aug Sep Oct Nov Dec)[$localtm[4]],
178 $localtm[5]+1900,
179 $localtm[2],
180 $localtm[1],
181 $localtm[0],
182 ($offset >= 0) ? '+' : '-',
183 abs($offhour),
184 $offmin,
188 my $smtp;
189 my $auth;
190 my $num_sent = 0;
192 # Regexes for RFC 2047 productions.
193 my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/;
194 my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
195 my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
197 # Variables we fill in automatically, or via prompting:
198 my (@to,@cc,@xh,$envelope_sender,
199 $initial_in_reply_to,$reply_to,$initial_subject,@files,
200 $author,$sender,$smtp_authpass,$annotate,$compose,$time);
201 # Things we either get from config, *or* are overridden on the
202 # command-line.
203 my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);
204 my (@config_to, @getopt_to);
205 my (@config_cc, @getopt_cc);
206 my (@config_bcc, @getopt_bcc);
208 # Example reply to:
209 #$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
211 my $repo = eval { Git->repository() };
212 my @repo = $repo ? ($repo) : ();
214 # Behavior modification variables
215 my ($quiet, $dry_run) = (0, 0);
216 my $format_patch;
217 my $compose_filename;
218 my $force = 0;
219 my $dump_aliases = 0;
220 my $translate_aliases = 0;
222 # Variables to prevent short format-patch options from being captured
223 # as abbreviated send-email options
224 my $reroll_count;
226 # Handle interactive edition of files.
227 my $multiedit;
228 my $editor;
230 sub system_or_msg {
231 my ($args, $msg, $cmd_name) = @_;
232 system(@$args);
233 my $signalled = $? & 127;
234 my $exit_code = $? >> 8;
235 return unless $signalled or $exit_code;
237 my @sprintf_args = ($cmd_name ? $cmd_name : $args->[0], $exit_code);
238 if (defined $msg) {
239 # Quiet the 'redundant' warning category, except we
240 # need to support down to Perl 5.8.1, so we can't do a
241 # "no warnings 'redundant'", since that category was
242 # introduced in perl 5.22, and asking for it will die
243 # on older perls.
244 no warnings;
245 return sprintf($msg, @sprintf_args);
247 return sprintf(__("fatal: command '%s' died with exit code %d"),
248 @sprintf_args);
251 sub system_or_die {
252 my $msg = system_or_msg(@_);
253 die $msg if $msg;
256 sub do_edit {
257 if (!defined($editor)) {
258 $editor = Git::command_oneline('var', 'GIT_EDITOR');
260 my $die_msg = __("the editor exited uncleanly, aborting everything");
261 if (defined($multiedit) && !$multiedit) {
262 system_or_die(['sh', '-c', $editor.' "$@"', $editor, $_], $die_msg) for @_;
263 } else {
264 system_or_die(['sh', '-c', $editor.' "$@"', $editor, @_], $die_msg);
268 # Variables with corresponding config settings
269 my ($suppress_from, $signed_off_by_cc);
270 my ($cover_cc, $cover_to);
271 my ($to_cmd, $cc_cmd, $header_cmd);
272 my ($smtp_server, $smtp_server_port, @smtp_server_options);
273 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
274 my ($batch_size, $relogin_delay);
275 my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
276 my ($confirm);
277 my (@suppress_cc);
278 my ($auto_8bit_encoding);
279 my ($compose_encoding);
280 my ($sendmail_cmd);
281 # Variables with corresponding config settings & hardcoded defaults
282 my ($debug_net_smtp) = 0; # Net::SMTP, see send_message()
283 my $thread = 1;
284 my $chain_reply_to = 0;
285 my $use_xmailer = 1;
286 my $validate = 1;
287 my $target_xfer_encoding = 'auto';
288 my $forbid_sendmail_variables = 1;
290 my %config_bool_settings = (
291 "thread" => \$thread,
292 "chainreplyto" => \$chain_reply_to,
293 "suppressfrom" => \$suppress_from,
294 "signedoffbycc" => \$signed_off_by_cc,
295 "cccover" => \$cover_cc,
296 "tocover" => \$cover_to,
297 "signedoffcc" => \$signed_off_by_cc,
298 "validate" => \$validate,
299 "multiedit" => \$multiedit,
300 "annotate" => \$annotate,
301 "xmailer" => \$use_xmailer,
302 "forbidsendmailvariables" => \$forbid_sendmail_variables,
305 my %config_settings = (
306 "smtpencryption" => \$smtp_encryption,
307 "smtpserver" => \$smtp_server,
308 "smtpserverport" => \$smtp_server_port,
309 "smtpserveroption" => \@smtp_server_options,
310 "smtpuser" => \$smtp_authuser,
311 "smtppass" => \$smtp_authpass,
312 "smtpdomain" => \$smtp_domain,
313 "smtpauth" => \$smtp_auth,
314 "smtpbatchsize" => \$batch_size,
315 "smtprelogindelay" => \$relogin_delay,
316 "to" => \@config_to,
317 "tocmd" => \$to_cmd,
318 "cc" => \@config_cc,
319 "cccmd" => \$cc_cmd,
320 "headercmd" => \$header_cmd,
321 "aliasfiletype" => \$aliasfiletype,
322 "bcc" => \@config_bcc,
323 "suppresscc" => \@suppress_cc,
324 "envelopesender" => \$envelope_sender,
325 "confirm" => \$confirm,
326 "from" => \$sender,
327 "assume8bitencoding" => \$auto_8bit_encoding,
328 "composeencoding" => \$compose_encoding,
329 "transferencoding" => \$target_xfer_encoding,
330 "sendmailcmd" => \$sendmail_cmd,
333 my %config_path_settings = (
334 "aliasesfile" => \@alias_files,
335 "smtpsslcertpath" => \$smtp_ssl_cert_path,
338 # Handle Uncouth Termination
339 sub signal_handler {
340 # Make text normal
341 require Term::ANSIColor;
342 print Term::ANSIColor::color("reset"), "\n";
344 # SMTP password masked
345 system "stty echo";
347 # tmp files from --compose
348 if (defined $compose_filename) {
349 if (-e $compose_filename) {
350 printf __("'%s' contains an intermediate version ".
351 "of the email you were composing.\n"),
352 $compose_filename;
354 if (-e ($compose_filename . ".final")) {
355 printf __("'%s.final' contains the composed email.\n"),
356 $compose_filename;
360 exit;
363 $SIG{TERM} = \&signal_handler;
364 $SIG{INT} = \&signal_handler;
366 # Read our sendemail.* config
367 sub read_config {
368 my ($known_keys, $configured, $prefix) = @_;
370 foreach my $setting (keys %config_bool_settings) {
371 my $target = $config_bool_settings{$setting};
372 my $key = "$prefix.$setting";
373 next unless exists $known_keys->{$key};
374 my $v = (@{$known_keys->{$key}} == 1 &&
375 (defined $known_keys->{$key}->[0] &&
376 $known_keys->{$key}->[0] =~ /^(?:true|false)$/s))
377 ? $known_keys->{$key}->[0] eq 'true'
378 : Git::config_bool(@repo, $key);
379 next unless defined $v;
380 next if $configured->{$setting}++;
381 $$target = $v;
384 foreach my $setting (keys %config_path_settings) {
385 my $target = $config_path_settings{$setting};
386 my $key = "$prefix.$setting";
387 next unless exists $known_keys->{$key};
388 if (ref($target) eq "ARRAY") {
389 my @values = Git::config_path(@repo, $key);
390 next unless @values;
391 next if $configured->{$setting}++;
392 @$target = @values;
394 else {
395 my $v = Git::config_path(@repo, "$prefix.$setting");
396 next unless defined $v;
397 next if $configured->{$setting}++;
398 $$target = $v;
402 foreach my $setting (keys %config_settings) {
403 my $target = $config_settings{$setting};
404 my $key = "$prefix.$setting";
405 next unless exists $known_keys->{$key};
406 if (ref($target) eq "ARRAY") {
407 my @values = @{$known_keys->{$key}};
408 @values = grep { defined } @values;
409 next if $configured->{$setting}++;
410 @$target = @values;
412 else {
413 my $v = $known_keys->{$key}->[-1];
414 next unless defined $v;
415 next if $configured->{$setting}++;
416 $$target = $v;
421 sub config_regexp {
422 my ($regex) = @_;
423 my @ret;
424 eval {
425 my $ret = Git::command(
426 'config',
427 '--null',
428 '--get-regexp',
429 $regex,
431 @ret = map {
432 # We must always return ($k, $v) here, since
433 # empty config values will be just "key\0",
434 # not "key\nvalue\0".
435 my ($k, $v) = split /\n/, $_, 2;
436 ($k, $v);
437 } split /\0/, $ret;
439 } or do {
440 # If we have no keys we're OK, otherwise re-throw
441 die $@ if $@->value != 1;
443 return @ret;
446 # Save ourselves a lot of work of shelling out to 'git config' (it
447 # parses 'bool' etc.) by only doing so for config keys that exist.
448 my %known_config_keys;
450 my @kv = config_regexp("^sende?mail[.]");
451 while (my ($k, $v) = splice @kv, 0, 2) {
452 push @{$known_config_keys{$k}} => $v;
456 # sendemail.identity yields to --identity. We must parse this
457 # special-case first before the rest of the config is read.
459 my $key = "sendemail.identity";
460 $identity = Git::config(@repo, $key) if exists $known_config_keys{$key};
462 my %identity_options = (
463 "identity=s" => \$identity,
464 "no-identity" => \$no_identity,
466 my $rc = GetOptions(%identity_options);
467 usage() unless $rc;
468 undef $identity if $no_identity;
470 # Now we know enough to read the config
472 my %configured;
473 read_config(\%known_config_keys, \%configured, "sendemail.$identity") if defined $identity;
474 read_config(\%known_config_keys, \%configured, "sendemail");
477 # Begin by accumulating all the variables (defined above), that we will end up
478 # needing, first, from the command line:
480 my $help;
481 my $git_completion_helper;
482 my %dump_aliases_options = (
483 "h" => \$help,
484 "dump-aliases" => \$dump_aliases,
485 "translate-aliases" => \$translate_aliases,
487 $rc = GetOptions(%dump_aliases_options);
488 usage() unless $rc;
489 die __("--dump-aliases incompatible with other options\n")
490 if !$help and ($dump_aliases or $translate_aliases) and @ARGV;
491 die __("--dump-aliases and --translate-aliases are mutually exclusive\n")
492 if !$help and $dump_aliases and $translate_aliases;
493 my %options = (
494 "sender|from=s" => \$sender,
495 "in-reply-to=s" => \$initial_in_reply_to,
496 "reply-to=s" => \$reply_to,
497 "subject=s" => \$initial_subject,
498 "to=s" => \@getopt_to,
499 "to-cmd=s" => \$to_cmd,
500 "no-to" => \$no_to,
501 "cc=s" => \@getopt_cc,
502 "no-cc" => \$no_cc,
503 "bcc=s" => \@getopt_bcc,
504 "no-bcc" => \$no_bcc,
505 "chain-reply-to!" => \$chain_reply_to,
506 "sendmail-cmd=s" => \$sendmail_cmd,
507 "smtp-server=s" => \$smtp_server,
508 "smtp-server-option=s" => \@smtp_server_options,
509 "smtp-server-port=s" => \$smtp_server_port,
510 "smtp-user=s" => \$smtp_authuser,
511 "smtp-pass:s" => \$smtp_authpass,
512 "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
513 "smtp-encryption=s" => \$smtp_encryption,
514 "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
515 "smtp-debug:i" => \$debug_net_smtp,
516 "smtp-domain:s" => \$smtp_domain,
517 "smtp-auth=s" => \$smtp_auth,
518 "no-smtp-auth" => sub {$smtp_auth = 'none'},
519 "annotate!" => \$annotate,
520 "compose" => \$compose,
521 "quiet" => \$quiet,
522 "cc-cmd=s" => \$cc_cmd,
523 "header-cmd=s" => \$header_cmd,
524 "no-header-cmd" => \$no_header_cmd,
525 "suppress-from!" => \$suppress_from,
526 "suppress-cc=s" => \@suppress_cc,
527 "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
528 "cc-cover!" => \$cover_cc,
529 "to-cover!" => \$cover_to,
530 "confirm=s" => \$confirm,
531 "dry-run" => \$dry_run,
532 "envelope-sender=s" => \$envelope_sender,
533 "thread!" => \$thread,
534 "validate!" => \$validate,
535 "transfer-encoding=s" => \$target_xfer_encoding,
536 "format-patch!" => \$format_patch,
537 "8bit-encoding=s" => \$auto_8bit_encoding,
538 "compose-encoding=s" => \$compose_encoding,
539 "force" => \$force,
540 "xmailer!" => \$use_xmailer,
541 "batch-size=i" => \$batch_size,
542 "relogin-delay=i" => \$relogin_delay,
543 "git-completion-helper" => \$git_completion_helper,
544 "v=s" => \$reroll_count,
546 $rc = GetOptions(%options);
548 # Munge any "either config or getopt, not both" variables
549 my @initial_to = @getopt_to ? @getopt_to : ($no_to ? () : @config_to);
550 my @initial_cc = @getopt_cc ? @getopt_cc : ($no_cc ? () : @config_cc);
551 my @initial_bcc = @getopt_bcc ? @getopt_bcc : ($no_bcc ? () : @config_bcc);
553 usage() if $help;
554 my %all_options = (%options, %dump_aliases_options, %identity_options);
555 completion_helper(\%all_options) if $git_completion_helper;
556 unless ($rc) {
557 usage();
560 if ($forbid_sendmail_variables && grep { /^sendmail/s } keys %known_config_keys) {
561 die __("fatal: found configuration options for 'sendmail'\n" .
562 "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
563 "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
566 die __("Cannot run git format-patch from outside a repository\n")
567 if $format_patch and not $repo;
569 die __("`batch-size` and `relogin` must be specified together " .
570 "(via command-line or configuration option)\n")
571 if defined $relogin_delay and not defined $batch_size;
573 # 'default' encryption is none -- this only prevents a warning
574 $smtp_encryption = '' unless (defined $smtp_encryption);
576 # Set CC suppressions
577 my(%suppress_cc);
578 if (@suppress_cc) {
579 foreach my $entry (@suppress_cc) {
580 # Please update $__git_send_email_suppresscc_options
581 # in git-completion.bash when you add new options.
582 die sprintf(__("Unknown --suppress-cc field: '%s'\n"), $entry)
583 unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc|misc-by)$/;
584 $suppress_cc{$entry} = 1;
588 if ($suppress_cc{'all'}) {
589 foreach my $entry (qw (cccmd cc author self sob body bodycc misc-by)) {
590 $suppress_cc{$entry} = 1;
592 delete $suppress_cc{'all'};
595 # If explicit old-style ones are specified, they trump --suppress-cc.
596 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
597 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
599 if ($suppress_cc{'body'}) {
600 foreach my $entry (qw (sob bodycc misc-by)) {
601 $suppress_cc{$entry} = 1;
603 delete $suppress_cc{'body'};
606 # Set confirm's default value
607 my $confirm_unconfigured = !defined $confirm;
608 if ($confirm_unconfigured) {
609 $confirm = scalar %suppress_cc ? 'compose' : 'auto';
611 # Please update $__git_send_email_confirm_options in
612 # git-completion.bash when you add new options.
613 die sprintf(__("Unknown --confirm setting: '%s'\n"), $confirm)
614 unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
616 # Debugging, print out the suppressions.
617 if (0) {
618 print "suppressions:\n";
619 foreach my $entry (keys %suppress_cc) {
620 printf " %-5s -> $suppress_cc{$entry}\n", $entry;
624 my ($repoauthor, $repocommitter);
626 my %cache;
627 my ($author, $committer);
628 my $common = sub {
629 my ($what) = @_;
630 return $cache{$what} if exists $cache{$what};
631 ($cache{$what}) = Git::ident_person(@repo, $what);
632 return $cache{$what};
634 $repoauthor = sub { $common->('author') };
635 $repocommitter = sub { $common->('committer') };
638 sub parse_address_line {
639 require Git::LoadCPAN::Mail::Address;
640 return map { $_->format } Mail::Address->parse($_[0]);
643 sub split_addrs {
644 require Text::ParseWords;
645 return Text::ParseWords::quotewords('\s*,\s*', 1, @_);
648 my %aliases;
650 sub parse_sendmail_alias {
651 local $_ = shift;
652 if (/"/) {
653 printf STDERR __("warning: sendmail alias with quotes is not supported: %s\n"), $_;
654 } elsif (/:include:/) {
655 printf STDERR __("warning: `:include:` not supported: %s\n"), $_;
656 } elsif (/[\/|]/) {
657 printf STDERR __("warning: `/file` or `|pipe` redirection not supported: %s\n"), $_;
658 } elsif (/^(\S+?)\s*:\s*(.+)$/) {
659 my ($alias, $addr) = ($1, $2);
660 $aliases{$alias} = [ split_addrs($addr) ];
661 } else {
662 printf STDERR __("warning: sendmail line is not recognized: %s\n"), $_;
666 sub parse_sendmail_aliases {
667 my $fh = shift;
668 my $s = '';
669 while (<$fh>) {
670 chomp;
671 next if /^\s*$/ || /^\s*#/;
672 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
673 parse_sendmail_alias($s) if $s;
674 $s = $_;
676 $s =~ s/\\$//; # silently tolerate stray '\' on last line
677 parse_sendmail_alias($s) if $s;
680 my %parse_alias = (
681 # multiline formats can be supported in the future
682 mutt => sub { my $fh = shift; while (<$fh>) {
683 if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
684 my ($alias, $addr) = ($1, $2);
685 $addr =~ s/#.*$//; # mutt allows # comments
686 # commas delimit multiple addresses
687 my @addr = split_addrs($addr);
689 # quotes may be escaped in the file,
690 # unescape them so we do not double-escape them later.
691 s/\\"/"/g foreach @addr;
692 $aliases{$alias} = \@addr
693 }}},
694 mailrc => sub { my $fh = shift; while (<$fh>) {
695 if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
696 require Text::ParseWords;
697 # spaces delimit multiple addresses
698 $aliases{$1} = [ Text::ParseWords::quotewords('\s+', 0, $2) ];
699 }}},
700 pine => sub { my $fh = shift; my $f='\t[^\t]*';
701 for (my $x = ''; defined($x); $x = $_) {
702 chomp $x;
703 $x .= $1 while(defined($_ = <$fh>) && /^ +(.*)$/);
704 $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
705 $aliases{$1} = [ split_addrs($2) ];
707 elm => sub { my $fh = shift;
708 while (<$fh>) {
709 if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
710 my ($alias, $addr) = ($1, $2);
711 $aliases{$alias} = [ split_addrs($addr) ];
713 } },
714 sendmail => \&parse_sendmail_aliases,
715 gnus => sub { my $fh = shift; while (<$fh>) {
716 if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
717 $aliases{$1} = [ $2 ];
719 # Please update _git_config() in git-completion.bash when you
720 # add new MUAs.
723 if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
724 foreach my $file (@alias_files) {
725 open my $fh, '<', $file or die "opening $file: $!\n";
726 $parse_alias{$aliasfiletype}->($fh);
727 close $fh;
731 if ($dump_aliases) {
732 print "$_\n" for (sort keys %aliases);
733 exit(0);
736 if ($translate_aliases) {
737 while (<STDIN>) {
738 my @addr_list = parse_address_line($_);
739 @addr_list = expand_aliases(@addr_list);
740 @addr_list = sanitize_address_list(@addr_list);
741 print "$_\n" for @addr_list;
743 exit(0);
746 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
747 # $f is a revision list specification to be passed to format-patch.
748 sub is_format_patch_arg {
749 return unless $repo;
750 my $f = shift;
751 try {
752 $repo->command('rev-parse', '--verify', '--quiet', $f);
753 if (defined($format_patch)) {
754 return $format_patch;
756 die sprintf(__(<<EOF), $f, $f);
757 File '%s' exists but it could also be the range of commits
758 to produce patches for. Please disambiguate by...
760 * Saying "./%s" if you mean a file; or
761 * Giving --format-patch option if you mean a range.
763 } catch Git::Error::Command with {
764 # Not a valid revision. Treat it as a filename.
765 return 0;
769 # Now that all the defaults are set, process the rest of the command line
770 # arguments and collect up the files that need to be processed.
771 my @rev_list_opts;
772 while (defined(my $f = shift @ARGV)) {
773 if ($f eq "--") {
774 push @rev_list_opts, "--", @ARGV;
775 @ARGV = ();
776 } elsif (-d $f and !is_format_patch_arg($f)) {
777 opendir my $dh, $f
778 or die sprintf(__("Failed to opendir %s: %s"), $f, $!);
780 require File::Spec;
781 push @files, grep { -f $_ } map { File::Spec->catfile($f, $_) }
782 sort readdir $dh;
783 closedir $dh;
784 } elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) {
785 push @files, $f;
786 } else {
787 push @rev_list_opts, $f;
791 if (@rev_list_opts) {
792 die __("Cannot run git format-patch from outside a repository\n")
793 unless $repo;
794 require File::Temp;
795 push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1),
796 defined $reroll_count ? ('-v', $reroll_count) : (),
797 @rev_list_opts);
800 if (defined $sender) {
801 $sender =~ s/^\s+|\s+$//g;
802 ($sender) = expand_aliases($sender);
803 } else {
804 $sender = $repoauthor->() || $repocommitter->() || '';
807 # $sender could be an already sanitized address
808 # (e.g. sendemail.from could be manually sanitized by user).
809 # But it's a no-op to run sanitize_address on an already sanitized address.
810 $sender = sanitize_address($sender);
812 $time = time - scalar $#files;
814 @files = handle_backup_files(@files);
816 if (@files) {
817 unless ($quiet) {
818 print $_,"\n" for (@files);
820 } else {
821 print STDERR __("\nNo patch files specified!\n\n");
822 usage();
825 sub get_patch_subject {
826 my $fn = shift;
827 open (my $fh, '<', $fn);
828 while (my $line = <$fh>) {
829 next unless ($line =~ /^Subject: (.*)$/);
830 close $fh;
831 return "GIT: $1\n";
833 close $fh;
834 die sprintf(__("No subject line in %s?"), $fn);
837 if ($compose) {
838 # Note that this does not need to be secure, but we will make a small
839 # effort to have it be unique
840 require File::Temp;
841 $compose_filename = ($repo ?
842 File::Temp::tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
843 File::Temp::tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
844 open my $c, ">", $compose_filename
845 or die sprintf(__("Failed to open for writing %s: %s"), $compose_filename, $!);
848 my $tpl_sender = $sender || $repoauthor->() || $repocommitter->() || '';
849 my $tpl_subject = $initial_subject || '';
850 my $tpl_in_reply_to = $initial_in_reply_to || '';
851 my $tpl_reply_to = $reply_to || '';
852 my $tpl_to = join(',', @initial_to);
853 my $tpl_cc = join(',', @initial_cc);
854 my $tpl_bcc = join(', ', @initial_bcc);
856 print $c <<EOT1, Git::prefix_lines("GIT: ", __(<<EOT2)), <<EOT3;
857 From $tpl_sender # This line is ignored.
858 EOT1
859 Lines beginning in "GIT:" will be removed.
860 Consider including an overall diffstat or table of contents
861 for the patch you are writing.
863 Clear the body content if you don't wish to send a summary.
864 EOT2
865 From: $tpl_sender
866 To: $tpl_to
867 Cc: $tpl_cc
868 Bcc: $tpl_bcc
869 Reply-To: $tpl_reply_to
870 Subject: $tpl_subject
871 In-Reply-To: $tpl_in_reply_to
873 EOT3
874 for my $f (@files) {
875 print $c get_patch_subject($f);
877 close $c;
879 if ($annotate) {
880 do_edit($compose_filename, @files);
881 } else {
882 do_edit($compose_filename);
885 open my $c2, ">", $compose_filename . ".final"
886 or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
888 open $c, "<", $compose_filename
889 or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
891 my $need_8bit_cte = file_has_nonascii($compose_filename);
892 my $in_body = 0;
893 my $summary_empty = 1;
894 if (!defined $compose_encoding) {
895 $compose_encoding = "UTF-8";
897 while(<$c>) {
898 next if m/^GIT:/;
899 if ($in_body) {
900 $summary_empty = 0 unless (/^\n$/);
901 } elsif (/^\n$/) {
902 $in_body = 1;
903 if ($need_8bit_cte) {
904 print $c2 "MIME-Version: 1.0\n",
905 "Content-Type: text/plain; ",
906 "charset=$compose_encoding\n",
907 "Content-Transfer-Encoding: 8bit\n";
909 } elsif (/^MIME-Version:/i) {
910 $need_8bit_cte = 0;
911 } elsif (/^Subject:\s*(.+)\s*$/i) {
912 $initial_subject = $1;
913 my $subject = $initial_subject;
914 $_ = "Subject: " .
915 quote_subject($subject, $compose_encoding) .
916 "\n";
917 } elsif (/^In-Reply-To:\s*(.+)\s*$/i) {
918 $initial_in_reply_to = $1;
919 next;
920 } elsif (/^Reply-To:\s*(.+)\s*$/i) {
921 $reply_to = $1;
922 } elsif (/^From:\s*(.+)\s*$/i) {
923 $sender = $1;
924 next;
925 } elsif (/^To:\s*(.+)\s*$/i) {
926 @initial_to = parse_address_line($1);
927 next;
928 } elsif (/^Cc:\s*(.+)\s*$/i) {
929 @initial_cc = parse_address_line($1);
930 next;
931 } elsif (/^Bcc:/i) {
932 @initial_bcc = parse_address_line($1);
933 next;
935 print $c2 $_;
937 close $c;
938 close $c2;
940 if ($summary_empty) {
941 print __("Summary email is empty, skipping it\n");
942 $compose = -1;
944 } elsif ($annotate) {
945 do_edit(@files);
949 # Only instantiate one $term per program run, since some
950 # Term::ReadLine providers refuse to create a second instance.
951 my $term;
952 sub term {
953 require Term::ReadLine;
954 if (!defined $term) {
955 $term = $ENV{"GIT_SEND_EMAIL_NOTTY"}
956 ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT)
957 : Term::ReadLine->new('git-send-email');
959 return $term;
963 sub ask {
964 my ($prompt, %arg) = @_;
965 my $valid_re = $arg{valid_re};
966 my $default = $arg{default};
967 my $confirm_only = $arg{confirm_only};
968 my $resp;
969 my $i = 0;
970 my $term = term();
971 return defined $default ? $default : undef
972 unless defined $term->IN and defined fileno($term->IN) and
973 defined $term->OUT and defined fileno($term->OUT);
974 while ($i++ < 10) {
975 $resp = $term->readline($prompt);
976 if (!defined $resp) { # EOF
977 print "\n";
978 return defined $default ? $default : undef;
980 if ($resp eq '' and defined $default) {
981 return $default;
983 if (!defined $valid_re or $resp =~ /$valid_re/) {
984 return $resp;
986 if ($confirm_only) {
987 my $yesno = $term->readline(
988 # TRANSLATORS: please keep [y/N] as is.
989 sprintf(__("Are you sure you want to use <%s> [y/N]? "), $resp));
990 if (defined $yesno && $yesno =~ /y/i) {
991 return $resp;
995 return;
998 my %broken_encoding;
1000 sub file_declares_8bit_cte {
1001 my $fn = shift;
1002 open (my $fh, '<', $fn);
1003 while (my $line = <$fh>) {
1004 last if ($line =~ /^$/);
1005 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
1007 close $fh;
1008 return 0;
1011 foreach my $f (@files) {
1012 next unless (body_or_subject_has_nonascii($f)
1013 && !file_declares_8bit_cte($f));
1014 $broken_encoding{$f} = 1;
1017 if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
1018 print __("The following files are 8bit, but do not declare " .
1019 "a Content-Transfer-Encoding.\n");
1020 foreach my $f (sort keys %broken_encoding) {
1021 print " $f\n";
1023 $auto_8bit_encoding = ask(__("Which 8bit encoding should I declare [UTF-8]? "),
1024 valid_re => qr/.{4}/, confirm_only => 1,
1025 default => "UTF-8");
1028 if (!$force) {
1029 for my $f (@files) {
1030 if (get_patch_subject($f) =~ /\Q*** SUBJECT HERE ***\E/) {
1031 die sprintf(__("Refusing to send because the patch\n\t%s\n"
1032 . "has the template subject '*** SUBJECT HERE ***'. "
1033 . "Pass --force if you really want to send.\n"), $f);
1038 my $to_whom = __("To whom should the emails be sent (if anyone)?");
1039 my $prompting = 0;
1040 if (!@initial_to && !defined $to_cmd) {
1041 my $to = ask("$to_whom ",
1042 default => "",
1043 valid_re => qr/\@.*\./, confirm_only => 1);
1044 push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
1045 $prompting++;
1048 sub expand_aliases {
1049 return map { expand_one_alias($_) } @_;
1052 my %EXPANDED_ALIASES;
1053 sub expand_one_alias {
1054 my $alias = shift;
1055 if ($EXPANDED_ALIASES{$alias}) {
1056 die sprintf(__("fatal: alias '%s' expands to itself\n"), $alias);
1058 local $EXPANDED_ALIASES{$alias} = 1;
1059 return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
1062 @initial_to = process_address_list(@initial_to);
1063 @initial_cc = process_address_list(@initial_cc);
1064 @initial_bcc = process_address_list(@initial_bcc);
1066 if ($thread && !defined $initial_in_reply_to && $prompting) {
1067 $initial_in_reply_to = ask(
1068 __("Message-ID to be used as In-Reply-To for the first email (if any)? "),
1069 default => "",
1070 valid_re => qr/\@.*\./, confirm_only => 1);
1072 if (defined $initial_in_reply_to) {
1073 $initial_in_reply_to =~ s/^\s*<?//;
1074 $initial_in_reply_to =~ s/>?\s*$//;
1075 $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
1078 if (defined $reply_to) {
1079 $reply_to =~ s/^\s+|\s+$//g;
1080 ($reply_to) = expand_aliases($reply_to);
1081 $reply_to = sanitize_address($reply_to);
1084 if (!defined $sendmail_cmd && !defined $smtp_server) {
1085 my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
1086 push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
1087 foreach (@sendmail_paths) {
1088 if (-x $_) {
1089 $sendmail_cmd = $_;
1090 last;
1094 if (!defined $sendmail_cmd) {
1095 $smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*
1099 if ($compose && $compose > 0) {
1100 @files = ($compose_filename . ".final", @files);
1103 # Variables we set as part of the loop over files
1104 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
1105 $needs_confirm, $message_num, $ask_default);
1107 sub extract_valid_address {
1108 my $address = shift;
1109 my $local_part_regexp = qr/[^<>"\s@]+/;
1110 my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
1112 # check for a local address:
1113 return $address if ($address =~ /^($local_part_regexp)$/);
1115 $address =~ s/^\s*<(.*)>\s*$/$1/;
1116 my $have_email_valid = eval { require Email::Valid; 1 };
1117 if ($have_email_valid) {
1118 return scalar Email::Valid->address($address);
1121 # less robust/correct than the monster regexp in Email::Valid,
1122 # but still does a 99% job, and one less dependency
1123 return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
1124 return;
1127 sub extract_valid_address_or_die {
1128 my $address = shift;
1129 my $valid_address = extract_valid_address($address);
1130 die sprintf(__("error: unable to extract a valid address from: %s\n"), $address)
1131 if !$valid_address;
1132 return $valid_address;
1135 sub validate_address {
1136 my $address = shift;
1137 while (!extract_valid_address($address)) {
1138 printf STDERR __("error: unable to extract a valid address from: %s\n"), $address;
1139 # TRANSLATORS: Make sure to include [q] [d] [e] in your
1140 # translation. The program will only accept English input
1141 # at this point.
1142 $_ = ask(__("What to do with this address? ([q]uit|[d]rop|[e]dit): "),
1143 valid_re => qr/^(?:quit|q|drop|d|edit|e)/i,
1144 default => 'q');
1145 if (/^d/i) {
1146 return undef;
1147 } elsif (/^q/i) {
1148 cleanup_compose_files();
1149 exit(0);
1151 $address = ask("$to_whom ",
1152 default => "",
1153 valid_re => qr/\@.*\./, confirm_only => 1);
1155 return $address;
1158 sub validate_address_list {
1159 return (grep { defined $_ }
1160 map { validate_address($_) } @_);
1163 # Usually don't need to change anything below here.
1165 # we make a "fake" message id by taking the current number
1166 # of seconds since the beginning of Unix time and tacking on
1167 # a random number to the end, in case we are called quicker than
1168 # 1 second since the last time we were called.
1170 # We'll setup a template for the message id, using the "from" address:
1172 my ($message_id_stamp, $message_id_serial);
1173 sub make_message_id {
1174 my $uniq;
1175 if (!defined $message_id_stamp) {
1176 require POSIX;
1177 $message_id_stamp = POSIX::strftime("%Y%m%d%H%M%S.$$", gmtime(time));
1178 $message_id_serial = 0;
1180 $message_id_serial++;
1181 $uniq = "$message_id_stamp-$message_id_serial";
1183 my $du_part;
1184 for ($sender, $repocommitter->(), $repoauthor->()) {
1185 $du_part = extract_valid_address(sanitize_address($_));
1186 last if (defined $du_part and $du_part ne '');
1188 if (not defined $du_part or $du_part eq '') {
1189 require Sys::Hostname;
1190 $du_part = 'user@' . Sys::Hostname::hostname();
1192 my $message_id_template = "<%s-%s>";
1193 $message_id = sprintf($message_id_template, $uniq, $du_part);
1194 #print "new message id = $message_id\n"; # Was useful for debugging
1197 sub unquote_rfc2047 {
1198 local ($_) = @_;
1199 my $charset;
1200 my $sep = qr/[ \t]+/;
1201 s{$re_encoded_word(?:$sep$re_encoded_word)*}{
1202 my @words = split $sep, $&;
1203 foreach (@words) {
1204 m/$re_encoded_word/;
1205 $charset = $1;
1206 my $encoding = $2;
1207 my $text = $3;
1208 if ($encoding eq 'q' || $encoding eq 'Q') {
1209 $_ = $text;
1210 s/_/ /g;
1211 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1212 } else {
1213 # other encodings not supported yet
1216 join '', @words;
1217 }eg;
1218 return wantarray ? ($_, $charset) : $_;
1221 sub quote_rfc2047 {
1222 local $_ = shift;
1223 my $encoding = shift || 'UTF-8';
1224 s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
1225 s/(.*)/=\?$encoding\?q\?$1\?=/;
1226 return $_;
1229 sub is_rfc2047_quoted {
1230 my $s = shift;
1231 length($s) <= 75 &&
1232 $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1235 sub subject_needs_rfc2047_quoting {
1236 my $s = shift;
1238 return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1241 sub quote_subject {
1242 local $subject = shift;
1243 my $encoding = shift || 'UTF-8';
1245 if (subject_needs_rfc2047_quoting($subject)) {
1246 return quote_rfc2047($subject, $encoding);
1248 return $subject;
1251 # use the simplest quoting being able to handle the recipient
1252 sub sanitize_address {
1253 my ($recipient) = @_;
1255 # remove garbage after email address
1256 $recipient =~ s/(.*>).*$/$1/;
1258 my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
1260 if (not $recipient_name) {
1261 return $recipient;
1264 # if recipient_name is already quoted, do nothing
1265 if (is_rfc2047_quoted($recipient_name)) {
1266 return $recipient;
1269 # remove non-escaped quotes
1270 $recipient_name =~ s/(^|[^\\])"/$1/g;
1272 # rfc2047 is needed if a non-ascii char is included
1273 if ($recipient_name =~ /[^[:ascii:]]/) {
1274 $recipient_name = quote_rfc2047($recipient_name);
1277 # double quotes are needed if specials or CTLs are included
1278 elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
1279 $recipient_name =~ s/([\\\r])/\\$1/g;
1280 $recipient_name = qq["$recipient_name"];
1283 return "$recipient_name $recipient_addr";
1287 sub strip_garbage_one_address {
1288 my ($addr) = @_;
1289 chomp $addr;
1290 if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1291 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1292 # Foo Bar <foobar@example.com> [possibly garbage here]
1293 return $1;
1295 if ($addr =~ /^(<[^>]*>).*/) {
1296 # <foo@example.com> [possibly garbage here]
1297 # if garbage contains other addresses, they are ignored.
1298 return $1;
1300 if ($addr =~ /^([^"#,\s]*)/) {
1301 # address without quoting: remove anything after the address
1302 return $1;
1304 return $addr;
1307 sub sanitize_address_list {
1308 return (map { sanitize_address($_) } @_);
1311 sub process_address_list {
1312 my @addr_list = map { parse_address_line($_) } @_;
1313 @addr_list = expand_aliases(@addr_list);
1314 @addr_list = sanitize_address_list(@addr_list);
1315 @addr_list = validate_address_list(@addr_list);
1316 return @addr_list;
1319 # Returns the local Fully Qualified Domain Name (FQDN) if available.
1321 # Tightly configured MTAa require that a caller sends a real DNS
1322 # domain name that corresponds the IP address in the HELO/EHLO
1323 # handshake. This is used to verify the connection and prevent
1324 # spammers from trying to hide their identity. If the DNS and IP don't
1325 # match, the receiving MTA may deny the connection.
1327 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
1329 # Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
1330 # Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
1332 # This maildomain*() code is based on ideas in Perl library Test::Reporter
1333 # /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
1335 sub valid_fqdn {
1336 my $domain = shift;
1337 return defined $domain && !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1340 sub maildomain_net {
1341 my $maildomain;
1343 require Net::Domain;
1344 my $domain = Net::Domain::domainname();
1345 $maildomain = $domain if valid_fqdn($domain);
1347 return $maildomain;
1350 sub maildomain_mta {
1351 my $maildomain;
1353 for my $host (qw(mailhost localhost)) {
1354 require Net::SMTP;
1355 my $smtp = Net::SMTP->new($host);
1356 if (defined $smtp) {
1357 my $domain = $smtp->domain;
1358 $smtp->quit;
1360 $maildomain = $domain if valid_fqdn($domain);
1362 last if $maildomain;
1366 return $maildomain;
1369 sub maildomain {
1370 return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
1373 sub smtp_host_string {
1374 if (defined $smtp_server_port) {
1375 return "$smtp_server:$smtp_server_port";
1376 } else {
1377 return $smtp_server;
1381 # Returns 1 if authentication succeeded or was not necessary
1382 # (smtp_user was not specified), and 0 otherwise.
1384 sub smtp_auth_maybe {
1385 if (!defined $smtp_authuser || $auth || (defined $smtp_auth && $smtp_auth eq "none")) {
1386 return 1;
1389 # Workaround AUTH PLAIN/LOGIN interaction defect
1390 # with Authen::SASL::Cyrus
1391 eval {
1392 require Authen::SASL;
1393 Authen::SASL->import(qw(Perl));
1396 # Check mechanism naming as defined in:
1397 # https://tools.ietf.org/html/rfc4422#page-8
1398 if ($smtp_auth && $smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
1399 die "invalid smtp auth: '${smtp_auth}'";
1402 # TODO: Authentication may fail not because credentials were
1403 # invalid but due to other reasons, in which we should not
1404 # reject credentials.
1405 $auth = Git::credential({
1406 'protocol' => 'smtp',
1407 'host' => smtp_host_string(),
1408 'username' => $smtp_authuser,
1409 # if there's no password, "git credential fill" will
1410 # give us one, otherwise it'll just pass this one.
1411 'password' => $smtp_authpass
1412 }, sub {
1413 my $cred = shift;
1415 if ($smtp_auth) {
1416 my $sasl = Authen::SASL->new(
1417 mechanism => $smtp_auth,
1418 callback => {
1419 user => $cred->{'username'},
1420 pass => $cred->{'password'},
1421 authname => $cred->{'username'},
1425 return !!$smtp->auth($sasl);
1428 return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
1431 return $auth;
1434 sub ssl_verify_params {
1435 eval {
1436 require IO::Socket::SSL;
1437 IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1439 if ($@) {
1440 print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1441 return;
1444 if (!defined $smtp_ssl_cert_path) {
1445 # use the OpenSSL defaults
1446 return (SSL_verify_mode => SSL_VERIFY_PEER());
1449 if ($smtp_ssl_cert_path eq "") {
1450 return (SSL_verify_mode => SSL_VERIFY_NONE());
1451 } elsif (-d $smtp_ssl_cert_path) {
1452 return (SSL_verify_mode => SSL_VERIFY_PEER(),
1453 SSL_ca_path => $smtp_ssl_cert_path);
1454 } elsif (-f $smtp_ssl_cert_path) {
1455 return (SSL_verify_mode => SSL_VERIFY_PEER(),
1456 SSL_ca_file => $smtp_ssl_cert_path);
1457 } else {
1458 die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1462 sub file_name_is_absolute {
1463 my ($path) = @_;
1465 # msys does not grok DOS drive-prefixes
1466 if ($^O eq 'msys') {
1467 return ($path =~ m#^/# || $path =~ m#^[a-zA-Z]\:#)
1470 require File::Spec::Functions;
1471 return File::Spec::Functions::file_name_is_absolute($path);
1474 sub gen_header {
1475 my @recipients = unique_email_list(@to);
1476 @cc = (grep { my $cc = extract_valid_address_or_die($_);
1477 not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
1479 @cc);
1480 my $to = join (",\n\t", @recipients);
1481 @recipients = unique_email_list(@recipients,@cc,@initial_bcc);
1482 @recipients = (map { extract_valid_address_or_die($_) } @recipients);
1483 my $date = format_2822_time($time++);
1484 my $gitversion = '@@GIT_VERSION@@';
1485 if ($gitversion =~ m/..GIT_VERSION../) {
1486 $gitversion = Git::version();
1489 my $cc = join(",\n\t", unique_email_list(@cc));
1490 my $ccline = "";
1491 if ($cc ne '') {
1492 $ccline = "\nCc: $cc";
1494 make_message_id() unless defined($message_id);
1496 my $header = "From: $sender
1497 To: $to${ccline}
1498 Subject: $subject
1499 Date: $date
1500 Message-ID: $message_id
1502 if ($use_xmailer) {
1503 $header .= "X-Mailer: git-send-email $gitversion\n";
1505 if ($in_reply_to) {
1507 $header .= "In-Reply-To: $in_reply_to\n";
1508 $header .= "References: $references\n";
1510 if ($reply_to) {
1511 $header .= "Reply-To: $reply_to\n";
1513 if (@xh) {
1514 $header .= join("\n", @xh) . "\n";
1516 my $recipients_ref = \@recipients;
1517 return ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header);
1520 # Prepares the email, then asks the user what to do.
1522 # If the user chooses to send the email, it's sent and 1 is returned.
1523 # If the user chooses not to send the email, 0 is returned.
1524 # If the user decides they want to make further edits, -1 is returned and the
1525 # caller is expected to call send_message again after the edits are performed.
1527 # If an error occurs sending the email, this just dies.
1529 sub send_message {
1530 my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
1531 my @recipients = @$recipients_ref;
1533 my @sendmail_parameters = ('-i', @recipients);
1534 my $raw_from = $sender;
1535 if (defined $envelope_sender && $envelope_sender ne "auto") {
1536 $raw_from = $envelope_sender;
1538 $raw_from = extract_valid_address($raw_from);
1539 unshift (@sendmail_parameters,
1540 '-f', $raw_from) if(defined $envelope_sender);
1542 if ($needs_confirm && !$dry_run) {
1543 print "\n$header\n";
1544 if ($needs_confirm eq "inform") {
1545 $confirm_unconfigured = 0; # squelch this message for the rest of this run
1546 $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation
1547 print __ <<EOF ;
1548 The Cc list above has been expanded by additional
1549 addresses found in the patch commit message. By default
1550 send-email prompts before sending whenever this occurs.
1551 This behavior is controlled by the sendemail.confirm
1552 configuration setting.
1554 For additional information, run 'git send-email --help'.
1555 To retain the current behavior, but squelch this message,
1556 run 'git config --global sendemail.confirm auto'.
1560 # TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
1561 # translation. The program will only accept English input
1562 # at this point.
1563 $_ = ask(__("Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "),
1564 valid_re => qr/^(?:yes|y|no|n|edit|e|quit|q|all|a)/i,
1565 default => $ask_default);
1566 die __("Send this email reply required") unless defined $_;
1567 if (/^n/i) {
1568 return 0;
1569 } elsif (/^e/i) {
1570 return -1;
1571 } elsif (/^q/i) {
1572 cleanup_compose_files();
1573 exit(0);
1574 } elsif (/^a/i) {
1575 $confirm = 'never';
1579 unshift (@sendmail_parameters, @smtp_server_options);
1581 if ($dry_run) {
1582 # We don't want to send the email.
1583 } elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {
1584 my $pid = open my $sm, '|-';
1585 defined $pid or die $!;
1586 if (!$pid) {
1587 if (defined $sendmail_cmd) {
1588 exec ("sh", "-c", "$sendmail_cmd \"\$@\"", "-", @sendmail_parameters)
1589 or die $!;
1590 } else {
1591 exec ($smtp_server, @sendmail_parameters)
1592 or die $!;
1595 print $sm "$header\n$message";
1596 close $sm or die $!;
1597 } else {
1599 if (!defined $smtp_server) {
1600 die __("The required SMTP server is not properly defined.")
1603 require Net::SMTP;
1604 my $use_net_smtp_ssl = version->parse($Net::SMTP::VERSION) < version->parse("2.34");
1605 $smtp_domain ||= maildomain();
1607 if ($smtp_encryption eq 'ssl') {
1608 $smtp_server_port ||= 465; # ssmtp
1609 require IO::Socket::SSL;
1611 # Suppress "variable accessed once" warning.
1613 no warnings 'once';
1614 $IO::Socket::SSL::DEBUG = 1;
1617 # Net::SMTP::SSL->new() does not forward any SSL options
1618 IO::Socket::SSL::set_client_defaults(
1619 ssl_verify_params());
1621 if ($use_net_smtp_ssl) {
1622 require Net::SMTP::SSL;
1623 $smtp ||= Net::SMTP::SSL->new($smtp_server,
1624 Hello => $smtp_domain,
1625 Port => $smtp_server_port,
1626 Debug => $debug_net_smtp);
1628 else {
1629 $smtp ||= Net::SMTP->new($smtp_server,
1630 Hello => $smtp_domain,
1631 Port => $smtp_server_port,
1632 Debug => $debug_net_smtp,
1633 SSL => 1);
1636 elsif (!$smtp) {
1637 $smtp_server_port ||= 25;
1638 $smtp ||= Net::SMTP->new($smtp_server,
1639 Hello => $smtp_domain,
1640 Debug => $debug_net_smtp,
1641 Port => $smtp_server_port);
1642 if ($smtp_encryption eq 'tls' && $smtp) {
1643 if ($use_net_smtp_ssl) {
1644 $smtp->command('STARTTLS');
1645 $smtp->response();
1646 if ($smtp->code != 220) {
1647 die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message);
1649 require Net::SMTP::SSL;
1650 $smtp = Net::SMTP::SSL->start_SSL($smtp,
1651 ssl_verify_params())
1652 or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
1654 else {
1655 $smtp->starttls(ssl_verify_params())
1656 or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
1658 # Send EHLO again to receive fresh
1659 # supported commands
1660 $smtp->hello($smtp_domain);
1664 if (!$smtp) {
1665 die __("Unable to initialize SMTP properly. Check config and use --smtp-debug."),
1666 " VALUES: server=$smtp_server ",
1667 "encryption=$smtp_encryption ",
1668 "hello=$smtp_domain",
1669 defined $smtp_server_port ? " port=$smtp_server_port" : "";
1672 smtp_auth_maybe or die $smtp->message;
1674 $smtp->mail( $raw_from ) or die $smtp->message;
1675 $smtp->to( @recipients ) or die $smtp->message;
1676 $smtp->data or die $smtp->message;
1677 $smtp->datasend("$header\n") or die $smtp->message;
1678 my @lines = split /^/, $message;
1679 foreach my $line (@lines) {
1680 $smtp->datasend("$line") or die $smtp->message;
1682 $smtp->dataend() or die $smtp->message;
1683 $smtp->code =~ /250|200/ or die sprintf(__("Failed to send %s\n"), $subject).$smtp->message;
1685 if ($quiet) {
1686 printf($dry_run ? __("Dry-Sent %s") : __("Sent %s"), $subject);
1687 print "\n";
1688 } else {
1689 print($dry_run ? __("Dry-OK. Log says:") : __("OK. Log says:"));
1690 print "\n";
1691 if (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {
1692 print "Server: $smtp_server\n";
1693 print "MAIL FROM:<$raw_from>\n";
1694 foreach my $entry (@recipients) {
1695 print "RCPT TO:<$entry>\n";
1697 } else {
1698 my $sm;
1699 if (defined $sendmail_cmd) {
1700 $sm = $sendmail_cmd;
1701 } else {
1702 $sm = $smtp_server;
1705 print "Sendmail: $sm ".join(' ',@sendmail_parameters)."\n";
1707 print $header, "\n";
1708 if ($smtp) {
1709 print __("Result: "), $smtp->code, ' ',
1710 ($smtp->message =~ /\n([^\n]+\n)$/s);
1711 } else {
1712 print __("Result: OK");
1714 print "\n";
1717 return 1;
1720 sub pre_process_file {
1721 my ($t, $quiet) = @_;
1723 open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
1725 my $author = undef;
1726 my $sauthor = undef;
1727 my $author_encoding;
1728 my $has_content_type;
1729 my $body_encoding;
1730 my $xfer_encoding;
1731 my $has_mime_version;
1732 @to = ();
1733 @cc = ();
1734 @xh = ();
1735 my $input_format = undef;
1736 my @header = ();
1737 $subject = $initial_subject;
1738 $message = "";
1739 $message_num++;
1740 undef $message_id;
1741 # Retrieve and unfold header fields.
1742 my @header_lines = ();
1743 while(<$fh>) {
1744 last if /^\s*$/;
1745 push(@header_lines, $_);
1747 @header = unfold_headers(@header_lines);
1748 # Add computed headers, if applicable.
1749 unless ($no_header_cmd || ! $header_cmd) {
1750 push @header, invoke_header_cmd($header_cmd, $t);
1752 # Now parse the header
1753 foreach(@header) {
1754 if (/^From /) {
1755 $input_format = 'mbox';
1756 next;
1758 chomp;
1759 if (!defined $input_format && /^[-A-Za-z]+:\s/) {
1760 $input_format = 'mbox';
1763 if (defined $input_format && $input_format eq 'mbox') {
1764 if (/^Subject:\s+(.*)$/i) {
1765 $subject = $1;
1767 elsif (/^From:\s+(.*)$/i) {
1768 ($author, $author_encoding) = unquote_rfc2047($1);
1769 $sauthor = sanitize_address($author);
1770 next if $suppress_cc{'author'};
1771 next if $suppress_cc{'self'} and $sauthor eq $sender;
1772 printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1773 $1, $_) unless $quiet;
1774 push @cc, $1;
1776 elsif (/^To:\s+(.*)$/i) {
1777 foreach my $addr (parse_address_line($1)) {
1778 printf(__("(mbox) Adding to: %s from line '%s'\n"),
1779 $addr, $_) unless $quiet;
1780 push @to, $addr;
1783 elsif (/^Cc:\s+(.*)$/i) {
1784 foreach my $addr (parse_address_line($1)) {
1785 my $qaddr = unquote_rfc2047($addr);
1786 my $saddr = sanitize_address($qaddr);
1787 if ($saddr eq $sender) {
1788 next if ($suppress_cc{'self'});
1789 } else {
1790 next if ($suppress_cc{'cc'});
1792 printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1793 $addr, $_) unless $quiet;
1794 push @cc, $addr;
1797 elsif (/^Content-type:/i) {
1798 $has_content_type = 1;
1799 if (/charset="?([^ "]+)/) {
1800 $body_encoding = $1;
1802 push @xh, $_;
1804 elsif (/^MIME-Version/i) {
1805 $has_mime_version = 1;
1806 push @xh, $_;
1808 elsif (/^Message-ID: (.*)/i) {
1809 $message_id = $1;
1811 elsif (/^Content-Transfer-Encoding: (.*)/i) {
1812 $xfer_encoding = $1 if not defined $xfer_encoding;
1814 elsif (/^In-Reply-To: (.*)/i) {
1815 if (!$initial_in_reply_to || $thread) {
1816 $in_reply_to = $1;
1819 elsif (/^References: (.*)/i) {
1820 if (!$initial_in_reply_to || $thread) {
1821 $references = $1;
1824 elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1825 push @xh, $_;
1827 } else {
1828 # In the traditional
1829 # "send lots of email" format,
1830 # line 1 = cc
1831 # line 2 = subject
1832 # So let's support that, too.
1833 $input_format = 'lots';
1834 if (@cc == 0 && !$suppress_cc{'cc'}) {
1835 printf(__("(non-mbox) Adding cc: %s from line '%s'\n"),
1836 $_, $_) unless $quiet;
1837 push @cc, $_;
1838 } elsif (!defined $subject) {
1839 $subject = $_;
1843 # Now parse the message body
1844 while(<$fh>) {
1845 $message .= $_;
1846 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1847 chomp;
1848 my ($what, $c) = ($1, $2);
1849 # strip garbage for the address we'll use:
1850 $c = strip_garbage_one_address($c);
1851 # sanitize a bit more to decide whether to suppress the address:
1852 my $sc = sanitize_address($c);
1853 if ($sc eq $sender) {
1854 next if ($suppress_cc{'self'});
1855 } else {
1856 if ($what =~ /^Signed-off-by$/i) {
1857 next if $suppress_cc{'sob'};
1858 } elsif ($what =~ /-by$/i) {
1859 next if $suppress_cc{'misc-by'};
1860 } elsif ($what =~ /Cc/i) {
1861 next if $suppress_cc{'bodycc'};
1864 if ($c !~ /.+@.+|<.+>/) {
1865 printf("(body) Ignoring %s from line '%s'\n",
1866 $what, $_) unless $quiet;
1867 next;
1869 push @cc, $sc;
1870 printf(__("(body) Adding cc: %s from line '%s'\n"),
1871 $sc, $_) unless $quiet;
1874 close $fh;
1876 push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t, $quiet)
1877 if defined $to_cmd;
1878 push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t, $quiet)
1879 if defined $cc_cmd && !$suppress_cc{'cccmd'};
1881 if ($broken_encoding{$t} && !$has_content_type) {
1882 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1883 $has_content_type = 1;
1884 push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
1885 $body_encoding = $auto_8bit_encoding;
1888 if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) {
1889 $subject = quote_subject($subject, $auto_8bit_encoding);
1892 if (defined $sauthor and $sauthor ne $sender) {
1893 $message = "From: $author\n\n$message";
1894 if (defined $author_encoding) {
1895 if ($has_content_type) {
1896 if ($body_encoding eq $author_encoding) {
1897 # ok, we already have the right encoding
1899 else {
1900 # uh oh, we should re-encode
1903 else {
1904 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1905 $has_content_type = 1;
1906 push @xh,
1907 "Content-Type: text/plain; charset=$author_encoding";
1911 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1912 ($message, $xfer_encoding) = apply_transfer_encoding(
1913 $message, $xfer_encoding, $target_xfer_encoding);
1914 push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1915 unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1917 $needs_confirm = (
1918 $confirm eq "always" or
1919 ($confirm =~ /^(?:auto|cc)$/ && @cc) or
1920 ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
1921 $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
1923 @to = process_address_list(@to);
1924 @cc = process_address_list(@cc);
1926 @to = (@initial_to, @to);
1927 @cc = (@initial_cc, @cc);
1929 if ($message_num == 1) {
1930 if (defined $cover_cc and $cover_cc) {
1931 @initial_cc = @cc;
1933 if (defined $cover_to and $cover_to) {
1934 @initial_to = @to;
1939 # Prepares the email, prompts the user, and sends it out
1940 # Returns 0 if an edit was done and the function should be called again, or 1
1941 # on the email being successfully sent out.
1942 sub process_file {
1943 my ($t) = @_;
1945 pre_process_file($t, $quiet);
1947 my $message_was_sent = send_message();
1948 if ($message_was_sent == -1) {
1949 do_edit($t);
1950 return 0;
1953 # set up for the next message
1954 if ($thread) {
1955 if ($message_was_sent &&
1956 ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
1957 $message_num == 1)) {
1958 $in_reply_to = $message_id;
1959 if (length $references > 0) {
1960 $references .= "\n $message_id";
1961 } else {
1962 $references = "$message_id";
1965 } elsif (!defined $initial_in_reply_to) {
1966 # --thread and --in-reply-to manage the "In-Reply-To" header and by
1967 # extension the "References" header. If these commands are not used, reset
1968 # the header values to their defaults.
1969 $in_reply_to = undef;
1970 $references = '';
1972 $message_id = undef;
1973 $num_sent++;
1974 if (defined $batch_size && $num_sent == $batch_size) {
1975 $num_sent = 0;
1976 $smtp->quit if defined $smtp;
1977 undef $smtp;
1978 undef $auth;
1979 sleep($relogin_delay) if defined $relogin_delay;
1982 return 1;
1985 sub initialize_modified_loop_vars {
1986 $in_reply_to = $initial_in_reply_to;
1987 $references = $initial_in_reply_to || '';
1988 $message_num = 0;
1991 if ($validate) {
1992 # FIFOs can only be read once, exclude them from validation.
1993 my @real_files = ();
1994 foreach my $f (@files) {
1995 unless (-p $f) {
1996 push(@real_files, $f);
2000 # Run the loop once again to avoid gaps in the counter due to FIFO
2001 # arguments provided by the user.
2002 my $num = 1;
2003 my $num_files = scalar @real_files;
2004 $ENV{GIT_SENDEMAIL_FILE_TOTAL} = "$num_files";
2005 initialize_modified_loop_vars();
2006 foreach my $r (@real_files) {
2007 $ENV{GIT_SENDEMAIL_FILE_COUNTER} = "$num";
2008 pre_process_file($r, 1);
2009 validate_patch($r, $target_xfer_encoding);
2010 $num += 1;
2012 delete $ENV{GIT_SENDEMAIL_FILE_COUNTER};
2013 delete $ENV{GIT_SENDEMAIL_FILE_TOTAL};
2016 initialize_modified_loop_vars();
2017 foreach my $t (@files) {
2018 while (!process_file($t)) {
2019 # user edited the file
2023 # Execute a command and return its output lines as an array. Blank
2024 # lines which do not appear at the end of the output are reported as
2025 # errors.
2026 sub execute_cmd {
2027 my ($prefix, $cmd, $file) = @_;
2028 my @lines = ();
2029 my $seen_blank_line = 0;
2030 open my $fh, "-|", "$cmd \Q$file\E"
2031 or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
2032 while (my $line = <$fh>) {
2033 die sprintf(__("(%s) Malformed output from '%s'"), $prefix, $cmd)
2034 if $seen_blank_line;
2035 if ($line =~ /^$/) {
2036 $seen_blank_line = $line =~ /^$/;
2037 next;
2039 push @lines, $line;
2041 close $fh
2042 or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
2043 return @lines;
2046 # Process headers lines, unfolding multiline headers as defined by RFC
2047 # 2822.
2048 sub unfold_headers {
2049 my @headers;
2050 foreach(@_) {
2051 last if /^\s*$/;
2052 if (/^\s+\S/ and @headers) {
2053 chomp($headers[$#headers]);
2054 s/^\s+/ /;
2055 $headers[$#headers] .= $_;
2056 } else {
2057 push(@headers, $_);
2060 return @headers;
2063 # Invoke the provided CMD with FILE as an argument, which should
2064 # output RFC 2822 email headers. Fold multiline headers and return the
2065 # headers as an array.
2066 sub invoke_header_cmd {
2067 my ($cmd, $file) = @_;
2068 my @lines = execute_cmd("header-cmd", $header_cmd, $file);
2069 return unfold_headers(@lines);
2072 # Execute a command (e.g. $to_cmd) to get a list of email addresses
2073 # and return a results array
2074 sub recipients_cmd {
2075 my ($prefix, $what, $cmd, $file, $quiet) = @_;
2076 my @lines = ();
2077 my @addresses = ();
2079 @lines = execute_cmd($prefix, $cmd, $file);
2080 for my $address (@lines) {
2081 $address =~ s/^\s*//g;
2082 $address =~ s/\s*$//g;
2083 $address = sanitize_address($address);
2084 next if ($address eq $sender and $suppress_cc{'self'});
2085 push @addresses, $address;
2086 printf(__("(%s) Adding %s: %s from: '%s'\n"),
2087 $prefix, $what, $address, $cmd) unless $quiet;
2089 return @addresses;
2092 cleanup_compose_files();
2094 sub cleanup_compose_files {
2095 unlink($compose_filename, $compose_filename . ".final") if $compose;
2098 $smtp->quit if $smtp;
2100 sub apply_transfer_encoding {
2101 my $message = shift;
2102 my $from = shift;
2103 my $to = shift;
2105 return ($message, $to) if ($from eq $to and $from ne '7bit');
2107 require MIME::QuotedPrint;
2108 require MIME::Base64;
2110 $message = MIME::QuotedPrint::decode($message)
2111 if ($from eq 'quoted-printable');
2112 $message = MIME::Base64::decode($message)
2113 if ($from eq 'base64');
2115 $to = ($message =~ /(?:.{999,}|\r)/) ? 'quoted-printable' : '8bit'
2116 if $to eq 'auto';
2118 die __("cannot send message as 7bit")
2119 if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
2120 return ($message, $to)
2121 if ($to eq '7bit' or $to eq '8bit');
2122 return (MIME::QuotedPrint::encode($message, "\n", 0), $to)
2123 if ($to eq 'quoted-printable');
2124 return (MIME::Base64::encode($message, "\n"), $to)
2125 if ($to eq 'base64');
2126 die __("invalid transfer encoding");
2129 sub unique_email_list {
2130 my %seen;
2131 my @emails;
2133 foreach my $entry (@_) {
2134 my $clean = extract_valid_address_or_die($entry);
2135 $seen{$clean} ||= 0;
2136 next if $seen{$clean}++;
2137 push @emails, $entry;
2139 return @emails;
2142 sub validate_patch {
2143 my ($fn, $xfer_encoding) = @_;
2145 if ($repo) {
2146 my $hook_name = 'sendemail-validate';
2147 my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
2148 require File::Spec;
2149 my $validate_hook = File::Spec->catfile($hooks_path, $hook_name);
2150 my $hook_error;
2151 if (-x $validate_hook) {
2152 require Cwd;
2153 my $target = Cwd::abs_path($fn);
2154 # The hook needs a correct cwd and GIT_DIR.
2155 my $cwd_save = Cwd::getcwd();
2156 chdir($repo->wc_path() or $repo->repo_path())
2157 or die("chdir: $!");
2158 local $ENV{"GIT_DIR"} = $repo->repo_path();
2160 my ($recipients_ref, $to, $date, $gitversion, $cc, $ccline, $header) = gen_header();
2162 require File::Temp;
2163 my ($header_filehandle, $header_filename) = File::Temp::tempfile(
2164 TEMPLATE => ".gitsendemail.header.XXXXXX",
2165 DIR => $repo->repo_path(),
2166 UNLINK => 1,
2168 print $header_filehandle $header;
2170 my @cmd = ("git", "hook", "run", "--ignore-missing",
2171 $hook_name, "--");
2172 my @cmd_msg = (@cmd, "<patch>", "<header>");
2173 my @cmd_run = (@cmd, $target, $header_filename);
2174 $hook_error = system_or_msg(\@cmd_run, undef, "@cmd_msg");
2175 chdir($cwd_save) or die("chdir: $!");
2177 if ($hook_error) {
2178 $hook_error = sprintf(
2179 __("fatal: %s: rejected by %s hook\n%s\nwarning: no patches were sent\n"),
2180 $fn, $hook_name, $hook_error);
2181 die $hook_error;
2185 # Any long lines will be automatically fixed if we use a suitable transfer
2186 # encoding.
2187 unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
2188 open(my $fh, '<', $fn)
2189 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2190 while (my $line = <$fh>) {
2191 if (length($line) > 998) {
2192 die sprintf(__("fatal: %s:%d is longer than 998 characters\n" .
2193 "warning: no patches were sent\n"), $fn, $.);
2197 return;
2200 sub handle_backup {
2201 my ($last, $lastlen, $file, $known_suffix) = @_;
2202 my ($suffix, $skip);
2204 $skip = 0;
2205 if (defined $last &&
2206 ($lastlen < length($file)) &&
2207 (substr($file, 0, $lastlen) eq $last) &&
2208 ($suffix = substr($file, $lastlen)) !~ /^[a-z0-9]/i) {
2209 if (defined $known_suffix && $suffix eq $known_suffix) {
2210 printf(__("Skipping %s with backup suffix '%s'.\n"), $file, $known_suffix);
2211 $skip = 1;
2212 } else {
2213 # TRANSLATORS: please keep "[y|N]" as is.
2214 my $answer = ask(sprintf(__("Do you really want to send %s? [y|N]: "), $file),
2215 valid_re => qr/^(?:y|n)/i,
2216 default => 'n');
2217 $skip = ($answer ne 'y');
2218 if ($skip) {
2219 $known_suffix = $suffix;
2223 return ($skip, $known_suffix);
2226 sub handle_backup_files {
2227 my @file = @_;
2228 my ($last, $lastlen, $known_suffix, $skip, @result);
2229 for my $file (@file) {
2230 ($skip, $known_suffix) = handle_backup($last, $lastlen,
2231 $file, $known_suffix);
2232 push @result, $file unless $skip;
2233 $last = $file;
2234 $lastlen = length($file);
2236 return @result;
2239 sub file_has_nonascii {
2240 my $fn = shift;
2241 open(my $fh, '<', $fn)
2242 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2243 while (my $line = <$fh>) {
2244 return 1 if $line =~ /[^[:ascii:]]/;
2246 return 0;
2249 sub body_or_subject_has_nonascii {
2250 my $fn = shift;
2251 open(my $fh, '<', $fn)
2252 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2253 while (my $line = <$fh>) {
2254 last if $line =~ /^$/;
2255 return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
2257 while (my $line = <$fh>) {
2258 return 1 if $line =~ /[^[:ascii:]]/;
2260 return 0;