The second batch
[git] / git-send-email.perl
1 #!/usr/bin/perl
2 #
3 # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>
4 # Copyright 2005 Ryan Anderson <ryan@michonline.com>
5 #
6 # GPL v2 (See COPYING)
7 #
8 # Ported to support git "mbox" format files by Ryan Anderson <ryan@michonline.com>
9 #
10 # Sends a collection of emails to the given email addresses, disturbingly fast.
11 #
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.
17 #
18
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;
36
37 Getopt::Long::Configure qw/ pass_through /;
38
39 package FakeTerm;
40 sub new {
41         my ($class, $reason) = @_;
42         return bless \$reason, shift;
43 }
44 sub readline {
45         my $self = shift;
46         die "Cannot use readline on FakeTerm: $$self";
47 }
48 package main;
49
50
51 sub usage {
52         print <<EOT;
53 git send-email [options] <file | directory | rev-list options >
54 git send-email --dump-aliases
55
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)
70
71   Sending:
72     --envelope-sender       <str>  * Email envelope sender.
73     --sendmail-cmd          <str>  * Command to run to send email.
74     --smtp-server       <str:int>  * Outgoing SMTP server to use. The port
75                                      is optional. Default 'localhost'.
76     --smtp-server-option    <str>  * Outgoing SMTP server option to use.
77     --smtp-server-port      <int>  * Outgoing SMTP server port.
78     --smtp-user             <str>  * Username for SMTP-AUTH.
79     --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
80     --smtp-encryption       <str>  * tls or ssl; anything else disables.
81     --smtp-ssl                     * Deprecated. Use '--smtp-encryption ssl'.
82     --smtp-ssl-cert-path    <str>  * Path to ca-certificates (either directory or file).
83                                      Pass an empty string to disable certificate
84                                      verification.
85     --smtp-domain           <str>  * The domain name sent to HELO/EHLO handshake
86     --smtp-auth             <str>  * Space-separated list of allowed AUTH mechanisms, or
87                                      "none" to disable authentication.
88                                      This setting forces to use one of the listed mechanisms.
89     --no-smtp-auth                   Disable SMTP authentication. Shorthand for
90                                      `--smtp-auth=none`
91     --smtp-debug            <0|1>  * Disable, enable Net::SMTP debug.
92
93     --batch-size            <int>  * send max <int> message per connection.
94     --relogin-delay         <int>  * delay <int> seconds between two successive login.
95                                      This option can only be used with --batch-size
96
97   Automating:
98     --identity              <str>  * Use the sendemail.<id> options.
99     --to-cmd                <str>  * Email To: via `<str> \$patch_path`
100     --cc-cmd                <str>  * Email Cc: via `<str> \$patch_path`
101     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.
102     --[no-]cc-cover                * Email Cc: addresses in the cover letter.
103     --[no-]to-cover                * Email To: addresses in the cover letter.
104     --[no-]signed-off-by-cc        * Send to Signed-off-by: addresses. Default on.
105     --[no-]suppress-from           * Send to self. Default off.
106     --[no-]chain-reply-to          * Chain In-Reply-To: fields. Default off.
107     --[no-]thread                  * Use In-Reply-To: field. Default on.
108
109   Administering:
110     --confirm               <str>  * Confirm recipients before sending;
111                                      auto, cc, compose, always, or never.
112     --quiet                        * Output one line of info per email.
113     --dry-run                      * Don't actually send the emails.
114     --[no-]validate                * Perform patch sanity checks. Default on.
115     --[no-]format-patch            * understand any non optional arguments as
116                                      `git format-patch` ones.
117     --force                        * Send even if safety checks would prevent it.
118
119   Information:
120     --dump-aliases                 * Dump configured aliases and exit.
121
122 EOT
123         exit(1);
124 }
125
126 sub completion_helper {
127     print Git::command('format-patch', '--git-completion-helper');
128     exit(0);
129 }
130
131 # most mail servers generate the Date: header, but not all...
132 sub format_2822_time {
133         my ($time) = @_;
134         my @localtm = localtime($time);
135         my @gmttm = gmtime($time);
136         my $localmin = $localtm[1] + $localtm[2] * 60;
137         my $gmtmin = $gmttm[1] + $gmttm[2] * 60;
138         if ($localtm[0] != $gmttm[0]) {
139                 die __("local zone differs from GMT by a non-minute interval\n");
140         }
141         if ((($gmttm[6] + 1) % 7) == $localtm[6]) {
142                 $localmin += 1440;
143         } elsif ((($gmttm[6] - 1) % 7) == $localtm[6]) {
144                 $localmin -= 1440;
145         } elsif ($gmttm[6] != $localtm[6]) {
146                 die __("local time offset greater than or equal to 24 hours\n");
147         }
148         my $offset = $localmin - $gmtmin;
149         my $offhour = $offset / 60;
150         my $offmin = abs($offset % 60);
151         if (abs($offhour) >= 24) {
152                 die __("local time offset greater than or equal to 24 hours\n");
153         }
154
155         return sprintf("%s, %2d %s %d %02d:%02d:%02d %s%02d%02d",
156                        qw(Sun Mon Tue Wed Thu Fri Sat)[$localtm[6]],
157                        $localtm[3],
158                        qw(Jan Feb Mar Apr May Jun
159                           Jul Aug Sep Oct Nov Dec)[$localtm[4]],
160                        $localtm[5]+1900,
161                        $localtm[2],
162                        $localtm[1],
163                        $localtm[0],
164                        ($offset >= 0) ? '+' : '-',
165                        abs($offhour),
166                        $offmin,
167                        );
168 }
169
170 my $have_email_valid = eval { require Email::Valid; 1 };
171 my $smtp;
172 my $auth;
173 my $num_sent = 0;
174
175 # Regexes for RFC 2047 productions.
176 my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/;
177 my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
178 my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
179
180 # Variables we fill in automatically, or via prompting:
181 my (@to,@cc,@xh,$envelope_sender,
182         $initial_in_reply_to,$reply_to,$initial_subject,@files,
183         $author,$sender,$smtp_authpass,$annotate,$compose,$time);
184 # Things we either get from config, *or* are overridden on the
185 # command-line.
186 my ($no_cc, $no_to, $no_bcc, $no_identity);
187 my (@config_to, @getopt_to);
188 my (@config_cc, @getopt_cc);
189 my (@config_bcc, @getopt_bcc);
190
191 # Example reply to:
192 #$initial_in_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
193
194 my $repo = eval { Git->repository() };
195 my @repo = $repo ? ($repo) : ();
196 my $term = eval {
197         $ENV{"GIT_SEND_EMAIL_NOTTY"}
198                 ? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
199                 : new Term::ReadLine 'git-send-email';
200 };
201 if ($@) {
202         $term = new FakeTerm "$@: going non-interactive";
203 }
204
205 # Behavior modification variables
206 my ($quiet, $dry_run) = (0, 0);
207 my $format_patch;
208 my $compose_filename;
209 my $force = 0;
210 my $dump_aliases = 0;
211
212 # Handle interactive edition of files.
213 my $multiedit;
214 my $editor;
215
216 sub system_or_msg {
217         my ($args, $msg) = @_;
218         system(@$args);
219         my $signalled = $? & 127;
220         my $exit_code = $? >> 8;
221         return unless $signalled or $exit_code;
222
223         my @sprintf_args = ($args->[0], $exit_code);
224         if (defined $msg) {
225                 # Quiet the 'redundant' warning category, except we
226                 # need to support down to Perl 5.8, so we can't do a
227                 # "no warnings 'redundant'", since that category was
228                 # introduced in perl 5.22, and asking for it will die
229                 # on older perls.
230                 no warnings;
231                 return sprintf($msg, @sprintf_args);
232         }
233         return sprintf(__("fatal: command '%s' died with exit code %d"),
234                        @sprintf_args);
235 }
236
237 sub system_or_die {
238         my $msg = system_or_msg(@_);
239         die $msg if $msg;
240 }
241
242 sub do_edit {
243         if (!defined($editor)) {
244                 $editor = Git::command_oneline('var', 'GIT_EDITOR');
245         }
246         my $die_msg = __("the editor exited uncleanly, aborting everything");
247         if (defined($multiedit) && !$multiedit) {
248                 system_or_die(['sh', '-c', $editor.' "$@"', $editor, $_], $die_msg) for @_;
249         } else {
250                 system_or_die(['sh', '-c', $editor.' "$@"', $editor, @_], $die_msg);
251         }
252 }
253
254 # Variables with corresponding config settings
255 my ($suppress_from, $signed_off_by_cc);
256 my ($cover_cc, $cover_to);
257 my ($to_cmd, $cc_cmd);
258 my ($smtp_server, $smtp_server_port, @smtp_server_options);
259 my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);
260 my ($batch_size, $relogin_delay);
261 my ($identity, $aliasfiletype, @alias_files, $smtp_domain, $smtp_auth);
262 my ($confirm);
263 my (@suppress_cc);
264 my ($auto_8bit_encoding);
265 my ($compose_encoding);
266 my ($sendmail_cmd);
267 # Variables with corresponding config settings & hardcoded defaults
268 my ($debug_net_smtp) = 0;               # Net::SMTP, see send_message()
269 my $thread = 1;
270 my $chain_reply_to = 0;
271 my $use_xmailer = 1;
272 my $validate = 1;
273 my $target_xfer_encoding = 'auto';
274 my $forbid_sendmail_variables = 1;
275
276 my %config_bool_settings = (
277     "thread" => \$thread,
278     "chainreplyto" => \$chain_reply_to,
279     "suppressfrom" => \$suppress_from,
280     "signedoffbycc" => \$signed_off_by_cc,
281     "cccover" => \$cover_cc,
282     "tocover" => \$cover_to,
283     "signedoffcc" => \$signed_off_by_cc,
284     "validate" => \$validate,
285     "multiedit" => \$multiedit,
286     "annotate" => \$annotate,
287     "xmailer" => \$use_xmailer,
288     "forbidsendmailvariables" => \$forbid_sendmail_variables,
289 );
290
291 my %config_settings = (
292     "smtpserver" => \$smtp_server,
293     "smtpserverport" => \$smtp_server_port,
294     "smtpserveroption" => \@smtp_server_options,
295     "smtpuser" => \$smtp_authuser,
296     "smtppass" => \$smtp_authpass,
297     "smtpdomain" => \$smtp_domain,
298     "smtpauth" => \$smtp_auth,
299     "smtpbatchsize" => \$batch_size,
300     "smtprelogindelay" => \$relogin_delay,
301     "to" => \@config_to,
302     "tocmd" => \$to_cmd,
303     "cc" => \@config_cc,
304     "cccmd" => \$cc_cmd,
305     "aliasfiletype" => \$aliasfiletype,
306     "bcc" => \@config_bcc,
307     "suppresscc" => \@suppress_cc,
308     "envelopesender" => \$envelope_sender,
309     "confirm"   => \$confirm,
310     "from" => \$sender,
311     "assume8bitencoding" => \$auto_8bit_encoding,
312     "composeencoding" => \$compose_encoding,
313     "transferencoding" => \$target_xfer_encoding,
314     "sendmailcmd" => \$sendmail_cmd,
315 );
316
317 my %config_path_settings = (
318     "aliasesfile" => \@alias_files,
319     "smtpsslcertpath" => \$smtp_ssl_cert_path,
320 );
321
322 # Handle Uncouth Termination
323 sub signal_handler {
324
325         # Make text normal
326         print color("reset"), "\n";
327
328         # SMTP password masked
329         system "stty echo";
330
331         # tmp files from --compose
332         if (defined $compose_filename) {
333                 if (-e $compose_filename) {
334                         printf __("'%s' contains an intermediate version ".
335                                   "of the email you were composing.\n"),
336                                   $compose_filename;
337                 }
338                 if (-e ($compose_filename . ".final")) {
339                         printf __("'%s.final' contains the composed email.\n"),
340                                   $compose_filename;
341                 }
342         }
343
344         exit;
345 };
346
347 $SIG{TERM} = \&signal_handler;
348 $SIG{INT}  = \&signal_handler;
349
350 # Read our sendemail.* config
351 sub read_config {
352         my ($configured, $prefix) = @_;
353
354         foreach my $setting (keys %config_bool_settings) {
355                 my $target = $config_bool_settings{$setting};
356                 my $v = Git::config_bool(@repo, "$prefix.$setting");
357                 next unless defined $v;
358                 next if $configured->{$setting}++;
359                 $$target = $v;
360         }
361
362         foreach my $setting (keys %config_path_settings) {
363                 my $target = $config_path_settings{$setting};
364                 if (ref($target) eq "ARRAY") {
365                         my @values = Git::config_path(@repo, "$prefix.$setting");
366                         next unless @values;
367                         next if $configured->{$setting}++;
368                         @$target = @values;
369                 }
370                 else {
371                         my $v = Git::config_path(@repo, "$prefix.$setting");
372                         next unless defined $v;
373                         next if $configured->{$setting}++;
374                         $$target = $v;
375                 }
376         }
377
378         foreach my $setting (keys %config_settings) {
379                 my $target = $config_settings{$setting};
380                 if (ref($target) eq "ARRAY") {
381                         my @values = Git::config(@repo, "$prefix.$setting");
382                         next unless @values;
383                         next if $configured->{$setting}++;
384                         @$target = @values;
385                 }
386                 else {
387                         my $v = Git::config(@repo, "$prefix.$setting");
388                         next unless defined $v;
389                         next if $configured->{$setting}++;
390                         $$target = $v;
391                 }
392         }
393
394         if (!defined $smtp_encryption) {
395                 my $setting = "$prefix.smtpencryption";
396                 my $enc = Git::config(@repo, $setting);
397                 return unless defined $enc;
398                 return if $configured->{$setting}++;
399                 if (defined $enc) {
400                         $smtp_encryption = $enc;
401                 } elsif (Git::config_bool(@repo, "$prefix.smtpssl")) {
402                         $smtp_encryption = 'ssl';
403                 }
404         }
405 }
406
407 # sendemail.identity yields to --identity. We must parse this
408 # special-case first before the rest of the config is read.
409 $identity = Git::config(@repo, "sendemail.identity");
410 my $rc = GetOptions(
411         "identity=s" => \$identity,
412         "no-identity" => \$no_identity,
413 );
414 usage() unless $rc;
415 undef $identity if $no_identity;
416
417 # Now we know enough to read the config
418 {
419     my %configured;
420     read_config(\%configured, "sendemail.$identity") if defined $identity;
421     read_config(\%configured, "sendemail");
422 }
423
424 # Begin by accumulating all the variables (defined above), that we will end up
425 # needing, first, from the command line:
426
427 my $help;
428 my $git_completion_helper;
429 $rc = GetOptions("h" => \$help,
430                  "dump-aliases" => \$dump_aliases);
431 usage() unless $rc;
432 die __("--dump-aliases incompatible with other options\n")
433     if !$help and $dump_aliases and @ARGV;
434 $rc = GetOptions(
435                     "sender|from=s" => \$sender,
436                     "in-reply-to=s" => \$initial_in_reply_to,
437                     "reply-to=s" => \$reply_to,
438                     "subject=s" => \$initial_subject,
439                     "to=s" => \@getopt_to,
440                     "to-cmd=s" => \$to_cmd,
441                     "no-to" => \$no_to,
442                     "cc=s" => \@getopt_cc,
443                     "no-cc" => \$no_cc,
444                     "bcc=s" => \@getopt_bcc,
445                     "no-bcc" => \$no_bcc,
446                     "chain-reply-to!" => \$chain_reply_to,
447                     "no-chain-reply-to" => sub {$chain_reply_to = 0},
448                     "sendmail-cmd=s" => \$sendmail_cmd,
449                     "smtp-server=s" => \$smtp_server,
450                     "smtp-server-option=s" => \@smtp_server_options,
451                     "smtp-server-port=s" => \$smtp_server_port,
452                     "smtp-user=s" => \$smtp_authuser,
453                     "smtp-pass:s" => \$smtp_authpass,
454                     "smtp-ssl" => sub { $smtp_encryption = 'ssl' },
455                     "smtp-encryption=s" => \$smtp_encryption,
456                     "smtp-ssl-cert-path=s" => \$smtp_ssl_cert_path,
457                     "smtp-debug:i" => \$debug_net_smtp,
458                     "smtp-domain:s" => \$smtp_domain,
459                     "smtp-auth=s" => \$smtp_auth,
460                     "no-smtp-auth" => sub {$smtp_auth = 'none'},
461                     "annotate!" => \$annotate,
462                     "no-annotate" => sub {$annotate = 0},
463                     "compose" => \$compose,
464                     "quiet" => \$quiet,
465                     "cc-cmd=s" => \$cc_cmd,
466                     "suppress-from!" => \$suppress_from,
467                     "no-suppress-from" => sub {$suppress_from = 0},
468                     "suppress-cc=s" => \@suppress_cc,
469                     "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
470                     "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
471                     "cc-cover|cc-cover!" => \$cover_cc,
472                     "no-cc-cover" => sub {$cover_cc = 0},
473                     "to-cover|to-cover!" => \$cover_to,
474                     "no-to-cover" => sub {$cover_to = 0},
475                     "confirm=s" => \$confirm,
476                     "dry-run" => \$dry_run,
477                     "envelope-sender=s" => \$envelope_sender,
478                     "thread!" => \$thread,
479                     "no-thread" => sub {$thread = 0},
480                     "validate!" => \$validate,
481                     "no-validate" => sub {$validate = 0},
482                     "transfer-encoding=s" => \$target_xfer_encoding,
483                     "format-patch!" => \$format_patch,
484                     "no-format-patch" => sub {$format_patch = 0},
485                     "8bit-encoding=s" => \$auto_8bit_encoding,
486                     "compose-encoding=s" => \$compose_encoding,
487                     "force" => \$force,
488                     "xmailer!" => \$use_xmailer,
489                     "no-xmailer" => sub {$use_xmailer = 0},
490                     "batch-size=i" => \$batch_size,
491                     "relogin-delay=i" => \$relogin_delay,
492                     "git-completion-helper" => \$git_completion_helper,
493          );
494
495 # Munge any "either config or getopt, not both" variables
496 my @initial_to = @getopt_to ? @getopt_to : ($no_to ? () : @config_to);
497 my @initial_cc = @getopt_cc ? @getopt_cc : ($no_cc ? () : @config_cc);
498 my @initial_bcc = @getopt_bcc ? @getopt_bcc : ($no_bcc ? () : @config_bcc);
499
500 usage() if $help;
501 completion_helper() if $git_completion_helper;
502 unless ($rc) {
503     usage();
504 }
505
506 if ($forbid_sendmail_variables && (scalar Git::config_regexp("^sendmail[.]")) != 0) {
507         die __("fatal: found configuration options for 'sendmail'\n" .
508                 "git-send-email is configured with the sendemail.* options - note the 'e'.\n" .
509                 "Set sendemail.forbidSendmailVariables to false to disable this check.\n");
510 }
511
512 die __("Cannot run git format-patch from outside a repository\n")
513         if $format_patch and not $repo;
514
515 die __("`batch-size` and `relogin` must be specified together " .
516         "(via command-line or configuration option)\n")
517         if defined $relogin_delay and not defined $batch_size;
518
519 # 'default' encryption is none -- this only prevents a warning
520 $smtp_encryption = '' unless (defined $smtp_encryption);
521
522 # Set CC suppressions
523 my(%suppress_cc);
524 if (@suppress_cc) {
525         foreach my $entry (@suppress_cc) {
526                 # Please update $__git_send_email_suppresscc_options
527                 # in git-completion.bash when you add new options.
528                 die sprintf(__("Unknown --suppress-cc field: '%s'\n"), $entry)
529                         unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc|misc-by)$/;
530                 $suppress_cc{$entry} = 1;
531         }
532 }
533
534 if ($suppress_cc{'all'}) {
535         foreach my $entry (qw (cccmd cc author self sob body bodycc misc-by)) {
536                 $suppress_cc{$entry} = 1;
537         }
538         delete $suppress_cc{'all'};
539 }
540
541 # If explicit old-style ones are specified, they trump --suppress-cc.
542 $suppress_cc{'self'} = $suppress_from if defined $suppress_from;
543 $suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;
544
545 if ($suppress_cc{'body'}) {
546         foreach my $entry (qw (sob bodycc misc-by)) {
547                 $suppress_cc{$entry} = 1;
548         }
549         delete $suppress_cc{'body'};
550 }
551
552 # Set confirm's default value
553 my $confirm_unconfigured = !defined $confirm;
554 if ($confirm_unconfigured) {
555         $confirm = scalar %suppress_cc ? 'compose' : 'auto';
556 };
557 # Please update $__git_send_email_confirm_options in
558 # git-completion.bash when you add new options.
559 die sprintf(__("Unknown --confirm setting: '%s'\n"), $confirm)
560         unless $confirm =~ /^(?:auto|cc|compose|always|never)/;
561
562 # Debugging, print out the suppressions.
563 if (0) {
564         print "suppressions:\n";
565         foreach my $entry (keys %suppress_cc) {
566                 printf "  %-5s -> $suppress_cc{$entry}\n", $entry;
567         }
568 }
569
570 my ($repoauthor, $repocommitter);
571 ($repoauthor) = Git::ident_person(@repo, 'author');
572 ($repocommitter) = Git::ident_person(@repo, 'committer');
573
574 sub parse_address_line {
575         return map { $_->format } Mail::Address->parse($_[0]);
576 }
577
578 sub split_addrs {
579         return quotewords('\s*,\s*', 1, @_);
580 }
581
582 my %aliases;
583
584 sub parse_sendmail_alias {
585         local $_ = shift;
586         if (/"/) {
587                 printf STDERR __("warning: sendmail alias with quotes is not supported: %s\n"), $_;
588         } elsif (/:include:/) {
589                 printf STDERR __("warning: `:include:` not supported: %s\n"), $_;
590         } elsif (/[\/|]/) {
591                 printf STDERR __("warning: `/file` or `|pipe` redirection not supported: %s\n"), $_;
592         } elsif (/^(\S+?)\s*:\s*(.+)$/) {
593                 my ($alias, $addr) = ($1, $2);
594                 $aliases{$alias} = [ split_addrs($addr) ];
595         } else {
596                 printf STDERR __("warning: sendmail line is not recognized: %s\n"), $_;
597         }
598 }
599
600 sub parse_sendmail_aliases {
601         my $fh = shift;
602         my $s = '';
603         while (<$fh>) {
604                 chomp;
605                 next if /^\s*$/ || /^\s*#/;
606                 $s .= $_, next if $s =~ s/\\$// || s/^\s+//;
607                 parse_sendmail_alias($s) if $s;
608                 $s = $_;
609         }
610         $s =~ s/\\$//; # silently tolerate stray '\' on last line
611         parse_sendmail_alias($s) if $s;
612 }
613
614 my %parse_alias = (
615         # multiline formats can be supported in the future
616         mutt => sub { my $fh = shift; while (<$fh>) {
617                 if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
618                         my ($alias, $addr) = ($1, $2);
619                         $addr =~ s/#.*$//; # mutt allows # comments
620                         # commas delimit multiple addresses
621                         my @addr = split_addrs($addr);
622
623                         # quotes may be escaped in the file,
624                         # unescape them so we do not double-escape them later.
625                         s/\\"/"/g foreach @addr;
626                         $aliases{$alias} = \@addr
627                 }}},
628         mailrc => sub { my $fh = shift; while (<$fh>) {
629                 if (/^alias\s+(\S+)\s+(.*?)\s*$/) {
630                         # spaces delimit multiple addresses
631                         $aliases{$1} = [ quotewords('\s+', 0, $2) ];
632                 }}},
633         pine => sub { my $fh = shift; my $f='\t[^\t]*';
634                 for (my $x = ''; defined($x); $x = $_) {
635                         chomp $x;
636                         $x .= $1 while(defined($_ = <$fh>) && /^ +(.*)$/);
637                         $x =~ /^(\S+)$f\t\(?([^\t]+?)\)?(:?$f){0,2}$/ or next;
638                         $aliases{$1} = [ split_addrs($2) ];
639                 }},
640         elm => sub  { my $fh = shift;
641                       while (<$fh>) {
642                           if (/^(\S+)\s+=\s+[^=]+=\s(\S+)/) {
643                               my ($alias, $addr) = ($1, $2);
644                                $aliases{$alias} = [ split_addrs($addr) ];
645                           }
646                       } },
647         sendmail => \&parse_sendmail_aliases,
648         gnus => sub { my $fh = shift; while (<$fh>) {
649                 if (/\(define-mail-alias\s+"(\S+?)"\s+"(\S+?)"\)/) {
650                         $aliases{$1} = [ $2 ];
651                 }}}
652         # Please update _git_config() in git-completion.bash when you
653         # add new MUAs.
654 );
655
656 if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
657         foreach my $file (@alias_files) {
658                 open my $fh, '<', $file or die "opening $file: $!\n";
659                 $parse_alias{$aliasfiletype}->($fh);
660                 close $fh;
661         }
662 }
663
664 if ($dump_aliases) {
665     print "$_\n" for (sort keys %aliases);
666     exit(0);
667 }
668
669 # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
670 # $f is a revision list specification to be passed to format-patch.
671 sub is_format_patch_arg {
672         return unless $repo;
673         my $f = shift;
674         try {
675                 $repo->command('rev-parse', '--verify', '--quiet', $f);
676                 if (defined($format_patch)) {
677                         return $format_patch;
678                 }
679                 die sprintf(__ <<EOF, $f, $f);
680 File '%s' exists but it could also be the range of commits
681 to produce patches for.  Please disambiguate by...
682
683     * Saying "./%s" if you mean a file; or
684     * Giving --format-patch option if you mean a range.
685 EOF
686         } catch Git::Error::Command with {
687                 # Not a valid revision.  Treat it as a filename.
688                 return 0;
689         }
690 }
691
692 # Now that all the defaults are set, process the rest of the command line
693 # arguments and collect up the files that need to be processed.
694 my @rev_list_opts;
695 while (defined(my $f = shift @ARGV)) {
696         if ($f eq "--") {
697                 push @rev_list_opts, "--", @ARGV;
698                 @ARGV = ();
699         } elsif (-d $f and !is_format_patch_arg($f)) {
700                 opendir my $dh, $f
701                         or die sprintf(__("Failed to opendir %s: %s"), $f, $!);
702
703                 push @files, grep { -f $_ } map { catfile($f, $_) }
704                                 sort readdir $dh;
705                 closedir $dh;
706         } elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) {
707                 push @files, $f;
708         } else {
709                 push @rev_list_opts, $f;
710         }
711 }
712
713 if (@rev_list_opts) {
714         die __("Cannot run git format-patch from outside a repository\n")
715                 unless $repo;
716         push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
717 }
718
719 @files = handle_backup_files(@files);
720
721 if ($validate) {
722         foreach my $f (@files) {
723                 unless (-p $f) {
724                         validate_patch($f, $target_xfer_encoding);
725                 }
726         }
727 }
728
729 if (@files) {
730         unless ($quiet) {
731                 print $_,"\n" for (@files);
732         }
733 } else {
734         print STDERR __("\nNo patch files specified!\n\n");
735         usage();
736 }
737
738 sub get_patch_subject {
739         my $fn = shift;
740         open (my $fh, '<', $fn);
741         while (my $line = <$fh>) {
742                 next unless ($line =~ /^Subject: (.*)$/);
743                 close $fh;
744                 return "GIT: $1\n";
745         }
746         close $fh;
747         die sprintf(__("No subject line in %s?"), $fn);
748 }
749
750 if ($compose) {
751         # Note that this does not need to be secure, but we will make a small
752         # effort to have it be unique
753         $compose_filename = ($repo ?
754                 tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
755                 tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
756         open my $c, ">", $compose_filename
757                 or die sprintf(__("Failed to open for writing %s: %s"), $compose_filename, $!);
758
759
760         my $tpl_sender = $sender || $repoauthor || $repocommitter || '';
761         my $tpl_subject = $initial_subject || '';
762         my $tpl_in_reply_to = $initial_in_reply_to || '';
763         my $tpl_reply_to = $reply_to || '';
764
765         print $c <<EOT1, Git::prefix_lines("GIT: ", __ <<EOT2), <<EOT3;
766 From $tpl_sender # This line is ignored.
767 EOT1
768 Lines beginning in "GIT:" will be removed.
769 Consider including an overall diffstat or table of contents
770 for the patch you are writing.
771
772 Clear the body content if you don't wish to send a summary.
773 EOT2
774 From: $tpl_sender
775 Reply-To: $tpl_reply_to
776 Subject: $tpl_subject
777 In-Reply-To: $tpl_in_reply_to
778
779 EOT3
780         for my $f (@files) {
781                 print $c get_patch_subject($f);
782         }
783         close $c;
784
785         if ($annotate) {
786                 do_edit($compose_filename, @files);
787         } else {
788                 do_edit($compose_filename);
789         }
790
791         open $c, "<", $compose_filename
792                 or die sprintf(__("Failed to open %s: %s"), $compose_filename, $!);
793
794         if (!defined $compose_encoding) {
795                 $compose_encoding = "UTF-8";
796         }
797
798         my %parsed_email;
799         while (my $line = <$c>) {
800                 next if $line =~ m/^GIT:/;
801                 parse_header_line($line, \%parsed_email);
802                 if ($line =~ /^$/) {
803                         $parsed_email{'body'} = filter_body($c);
804                 }
805         }
806         close $c;
807
808         open my $c2, ">", $compose_filename . ".final"
809         or die sprintf(__("Failed to open %s.final: %s"), $compose_filename, $!);
810
811
812         if ($parsed_email{'From'}) {
813                 $sender = delete($parsed_email{'From'});
814         }
815         if ($parsed_email{'In-Reply-To'}) {
816                 $initial_in_reply_to = delete($parsed_email{'In-Reply-To'});
817         }
818         if ($parsed_email{'Reply-To'}) {
819                 $reply_to = delete($parsed_email{'Reply-To'});
820         }
821         if ($parsed_email{'Subject'}) {
822                 $initial_subject = delete($parsed_email{'Subject'});
823                 print $c2 "Subject: " .
824                         quote_subject($initial_subject, $compose_encoding) .
825                         "\n";
826         }
827
828         if ($parsed_email{'MIME-Version'}) {
829                 print $c2 "MIME-Version: $parsed_email{'MIME-Version'}\n",
830                                 "Content-Type: $parsed_email{'Content-Type'};\n",
831                                 "Content-Transfer-Encoding: $parsed_email{'Content-Transfer-Encoding'}\n";
832                 delete($parsed_email{'MIME-Version'});
833                 delete($parsed_email{'Content-Type'});
834                 delete($parsed_email{'Content-Transfer-Encoding'});
835         } elsif (file_has_nonascii($compose_filename)) {
836                 my $content_type = (delete($parsed_email{'Content-Type'}) or
837                         "text/plain; charset=$compose_encoding");
838                 print $c2 "MIME-Version: 1.0\n",
839                         "Content-Type: $content_type\n",
840                         "Content-Transfer-Encoding: 8bit\n";
841         }
842         # Preserve unknown headers
843         foreach my $key (keys %parsed_email) {
844                 next if $key eq 'body';
845                 print $c2 "$key: $parsed_email{$key}";
846         }
847
848         if ($parsed_email{'body'}) {
849                 print $c2 "\n$parsed_email{'body'}\n";
850                 delete($parsed_email{'body'});
851         } else {
852                 print __("Summary email is empty, skipping it\n");
853                 $compose = -1;
854         }
855
856         close $c2;
857
858 } elsif ($annotate) {
859         do_edit(@files);
860 }
861
862 sub ask {
863         my ($prompt, %arg) = @_;
864         my $valid_re = $arg{valid_re};
865         my $default = $arg{default};
866         my $confirm_only = $arg{confirm_only};
867         my $resp;
868         my $i = 0;
869         return defined $default ? $default : undef
870                 unless defined $term->IN and defined fileno($term->IN) and
871                        defined $term->OUT and defined fileno($term->OUT);
872         while ($i++ < 10) {
873                 $resp = $term->readline($prompt);
874                 if (!defined $resp) { # EOF
875                         print "\n";
876                         return defined $default ? $default : undef;
877                 }
878                 if ($resp eq '' and defined $default) {
879                         return $default;
880                 }
881                 if (!defined $valid_re or $resp =~ /$valid_re/) {
882                         return $resp;
883                 }
884                 if ($confirm_only) {
885                         my $yesno = $term->readline(
886                                 # TRANSLATORS: please keep [y/N] as is.
887                                 sprintf(__("Are you sure you want to use <%s> [y/N]? "), $resp));
888                         if (defined $yesno && $yesno =~ /y/i) {
889                                 return $resp;
890                         }
891                 }
892         }
893         return;
894 }
895
896 sub parse_header_line {
897         my $lines = shift;
898         my $parsed_line = shift;
899         my $addr_pat = join "|", qw(To Cc Bcc);
900
901         foreach (split(/\n/, $lines)) {
902                 if (/^($addr_pat):\s*(.+)$/i) {
903                         $parsed_line->{$1} = [ parse_address_line($2) ];
904                 } elsif (/^([^:]*):\s*(.+)\s*$/i) {
905                         $parsed_line->{$1} = $2;
906                 }
907         }
908 }
909
910 sub filter_body {
911         my $c = shift;
912         my $body = "";
913         while (my $body_line = <$c>) {
914                 if ($body_line !~ m/^GIT:/) {
915                         $body .= $body_line;
916                 }
917         }
918         return $body;
919 }
920
921
922 my %broken_encoding;
923
924 sub file_declares_8bit_cte {
925         my $fn = shift;
926         open (my $fh, '<', $fn);
927         while (my $line = <$fh>) {
928                 last if ($line =~ /^$/);
929                 return 1 if ($line =~ /^Content-Transfer-Encoding: .*8bit.*$/);
930         }
931         close $fh;
932         return 0;
933 }
934
935 foreach my $f (@files) {
936         next unless (body_or_subject_has_nonascii($f)
937                      && !file_declares_8bit_cte($f));
938         $broken_encoding{$f} = 1;
939 }
940
941 if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
942         print __("The following files are 8bit, but do not declare " .
943                  "a Content-Transfer-Encoding.\n");
944         foreach my $f (sort keys %broken_encoding) {
945                 print "    $f\n";
946         }
947         $auto_8bit_encoding = ask(__("Which 8bit encoding should I declare [UTF-8]? "),
948                                   valid_re => qr/.{4}/, confirm_only => 1,
949                                   default => "UTF-8");
950 }
951
952 if (!$force) {
953         for my $f (@files) {
954                 if (get_patch_subject($f) =~ /\Q*** SUBJECT HERE ***\E/) {
955                         die sprintf(__("Refusing to send because the patch\n\t%s\n"
956                                 . "has the template subject '*** SUBJECT HERE ***'. "
957                                 . "Pass --force if you really want to send.\n"), $f);
958                 }
959         }
960 }
961
962 if (defined $sender) {
963         $sender =~ s/^\s+|\s+$//g;
964         ($sender) = expand_aliases($sender);
965 } else {
966         $sender = $repoauthor || $repocommitter || '';
967 }
968
969 # $sender could be an already sanitized address
970 # (e.g. sendemail.from could be manually sanitized by user).
971 # But it's a no-op to run sanitize_address on an already sanitized address.
972 $sender = sanitize_address($sender);
973
974 my $to_whom = __("To whom should the emails be sent (if anyone)?");
975 my $prompting = 0;
976 if (!@initial_to && !defined $to_cmd) {
977         my $to = ask("$to_whom ",
978                      default => "",
979                      valid_re => qr/\@.*\./, confirm_only => 1);
980         push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
981         $prompting++;
982 }
983
984 sub expand_aliases {
985         return map { expand_one_alias($_) } @_;
986 }
987
988 my %EXPANDED_ALIASES;
989 sub expand_one_alias {
990         my $alias = shift;
991         if ($EXPANDED_ALIASES{$alias}) {
992                 die sprintf(__("fatal: alias '%s' expands to itself\n"), $alias);
993         }
994         local $EXPANDED_ALIASES{$alias} = 1;
995         return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
996 }
997
998 @initial_to = process_address_list(@initial_to);
999 @initial_cc = process_address_list(@initial_cc);
1000 @initial_bcc = process_address_list(@initial_bcc);
1001
1002 if ($thread && !defined $initial_in_reply_to && $prompting) {
1003         $initial_in_reply_to = ask(
1004                 __("Message-ID to be used as In-Reply-To for the first email (if any)? "),
1005                 default => "",
1006                 valid_re => qr/\@.*\./, confirm_only => 1);
1007 }
1008 if (defined $initial_in_reply_to) {
1009         $initial_in_reply_to =~ s/^\s*<?//;
1010         $initial_in_reply_to =~ s/>?\s*$//;
1011         $initial_in_reply_to = "<$initial_in_reply_to>" if $initial_in_reply_to ne '';
1012 }
1013
1014 if (defined $reply_to) {
1015         $reply_to =~ s/^\s+|\s+$//g;
1016         ($reply_to) = expand_aliases($reply_to);
1017         $reply_to = sanitize_address($reply_to);
1018 }
1019
1020 if (!defined $sendmail_cmd && !defined $smtp_server) {
1021         my @sendmail_paths = qw( /usr/sbin/sendmail /usr/lib/sendmail );
1022         push @sendmail_paths, map {"$_/sendmail"} split /:/, $ENV{PATH};
1023         foreach (@sendmail_paths) {
1024                 if (-x $_) {
1025                         $sendmail_cmd = $_;
1026                         last;
1027                 }
1028         }
1029
1030         if (!defined $sendmail_cmd) {
1031                 $smtp_server = 'localhost'; # could be 127.0.0.1, too... *shrug*
1032         }
1033 }
1034
1035 if ($compose && $compose > 0) {
1036         @files = ($compose_filename . ".final", @files);
1037 }
1038
1039 # Variables we set as part of the loop over files
1040 our ($message_id, %mail, $subject, $in_reply_to, $references, $message,
1041         $needs_confirm, $message_num, $ask_default);
1042
1043 sub extract_valid_address {
1044         my $address = shift;
1045         my $local_part_regexp = qr/[^<>"\s@]+/;
1046         my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
1047
1048         # check for a local address:
1049         return $address if ($address =~ /^($local_part_regexp)$/);
1050
1051         $address =~ s/^\s*<(.*)>\s*$/$1/;
1052         if ($have_email_valid) {
1053                 return scalar Email::Valid->address($address);
1054         }
1055
1056         # less robust/correct than the monster regexp in Email::Valid,
1057         # but still does a 99% job, and one less dependency
1058         return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
1059         return;
1060 }
1061
1062 sub extract_valid_address_or_die {
1063         my $address = shift;
1064         $address = extract_valid_address($address);
1065         die sprintf(__("error: unable to extract a valid address from: %s\n"), $address)
1066                 if !$address;
1067         return $address;
1068 }
1069
1070 sub validate_address {
1071         my $address = shift;
1072         while (!extract_valid_address($address)) {
1073                 printf STDERR __("error: unable to extract a valid address from: %s\n"), $address;
1074                 # TRANSLATORS: Make sure to include [q] [d] [e] in your
1075                 # translation. The program will only accept English input
1076                 # at this point.
1077                 $_ = ask(__("What to do with this address? ([q]uit|[d]rop|[e]dit): "),
1078                         valid_re => qr/^(?:quit|q|drop|d|edit|e)/i,
1079                         default => 'q');
1080                 if (/^d/i) {
1081                         return undef;
1082                 } elsif (/^q/i) {
1083                         cleanup_compose_files();
1084                         exit(0);
1085                 }
1086                 $address = ask("$to_whom ",
1087                         default => "",
1088                         valid_re => qr/\@.*\./, confirm_only => 1);
1089         }
1090         return $address;
1091 }
1092
1093 sub validate_address_list {
1094         return (grep { defined $_ }
1095                 map { validate_address($_) } @_);
1096 }
1097
1098 # Usually don't need to change anything below here.
1099
1100 # we make a "fake" message id by taking the current number
1101 # of seconds since the beginning of Unix time and tacking on
1102 # a random number to the end, in case we are called quicker than
1103 # 1 second since the last time we were called.
1104
1105 # We'll setup a template for the message id, using the "from" address:
1106
1107 my ($message_id_stamp, $message_id_serial);
1108 sub make_message_id {
1109         my $uniq;
1110         if (!defined $message_id_stamp) {
1111                 $message_id_stamp = strftime("%Y%m%d%H%M%S.$$", gmtime(time));
1112                 $message_id_serial = 0;
1113         }
1114         $message_id_serial++;
1115         $uniq = "$message_id_stamp-$message_id_serial";
1116
1117         my $du_part;
1118         for ($sender, $repocommitter, $repoauthor) {
1119                 $du_part = extract_valid_address(sanitize_address($_));
1120                 last if (defined $du_part and $du_part ne '');
1121         }
1122         if (not defined $du_part or $du_part eq '') {
1123                 require Sys::Hostname;
1124                 $du_part = 'user@' . Sys::Hostname::hostname();
1125         }
1126         my $message_id_template = "<%s-%s>";
1127         $message_id = sprintf($message_id_template, $uniq, $du_part);
1128         #print "new message id = $message_id\n"; # Was useful for debugging
1129 }
1130
1131
1132
1133 $time = time - scalar $#files;
1134
1135 sub unquote_rfc2047 {
1136         local ($_) = @_;
1137         my $charset;
1138         my $sep = qr/[ \t]+/;
1139         s{$re_encoded_word(?:$sep$re_encoded_word)*}{
1140                 my @words = split $sep, $&;
1141                 foreach (@words) {
1142                         m/$re_encoded_word/;
1143                         $charset = $1;
1144                         my $encoding = $2;
1145                         my $text = $3;
1146                         if ($encoding eq 'q' || $encoding eq 'Q') {
1147                                 $_ = $text;
1148                                 s/_/ /g;
1149                                 s/=([0-9A-F]{2})/chr(hex($1))/egi;
1150                         } else {
1151                                 # other encodings not supported yet
1152                         }
1153                 }
1154                 join '', @words;
1155         }eg;
1156         return wantarray ? ($_, $charset) : $_;
1157 }
1158
1159 sub quote_rfc2047 {
1160         local $_ = shift;
1161         my $encoding = shift || 'UTF-8';
1162         s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
1163         s/(.*)/=\?$encoding\?q\?$1\?=/;
1164         return $_;
1165 }
1166
1167 sub is_rfc2047_quoted {
1168         my $s = shift;
1169         length($s) <= 75 &&
1170         $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
1171 }
1172
1173 sub subject_needs_rfc2047_quoting {
1174         my $s = shift;
1175
1176         return ($s =~ /[^[:ascii:]]/) || ($s =~ /=\?/);
1177 }
1178
1179 sub quote_subject {
1180         local $subject = shift;
1181         my $encoding = shift || 'UTF-8';
1182
1183         if (subject_needs_rfc2047_quoting($subject)) {
1184                 return quote_rfc2047($subject, $encoding);
1185         }
1186         return $subject;
1187 }
1188
1189 # use the simplest quoting being able to handle the recipient
1190 sub sanitize_address {
1191         my ($recipient) = @_;
1192
1193         # remove garbage after email address
1194         $recipient =~ s/(.*>).*$/$1/;
1195
1196         my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
1197
1198         if (not $recipient_name) {
1199                 return $recipient;
1200         }
1201
1202         # if recipient_name is already quoted, do nothing
1203         if (is_rfc2047_quoted($recipient_name)) {
1204                 return $recipient;
1205         }
1206
1207         # remove non-escaped quotes
1208         $recipient_name =~ s/(^|[^\\])"/$1/g;
1209
1210         # rfc2047 is needed if a non-ascii char is included
1211         if ($recipient_name =~ /[^[:ascii:]]/) {
1212                 $recipient_name = quote_rfc2047($recipient_name);
1213         }
1214
1215         # double quotes are needed if specials or CTLs are included
1216         elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
1217                 $recipient_name =~ s/([\\\r])/\\$1/g;
1218                 $recipient_name = qq["$recipient_name"];
1219         }
1220
1221         return "$recipient_name $recipient_addr";
1222
1223 }
1224
1225 sub strip_garbage_one_address {
1226         my ($addr) = @_;
1227         chomp $addr;
1228         if ($addr =~ /^(("[^"]*"|[^"<]*)? *<[^>]*>).*/) {
1229                 # "Foo Bar" <foobar@example.com> [possibly garbage here]
1230                 # Foo Bar <foobar@example.com> [possibly garbage here]
1231                 return $1;
1232         }
1233         if ($addr =~ /^(<[^>]*>).*/) {
1234                 # <foo@example.com> [possibly garbage here]
1235                 # if garbage contains other addresses, they are ignored.
1236                 return $1;
1237         }
1238         if ($addr =~ /^([^"#,\s]*)/) {
1239                 # address without quoting: remove anything after the address
1240                 return $1;
1241         }
1242         return $addr;
1243 }
1244
1245 sub sanitize_address_list {
1246         return (map { sanitize_address($_) } @_);
1247 }
1248
1249 sub process_address_list {
1250         my @addr_list = map { parse_address_line($_) } @_;
1251         @addr_list = expand_aliases(@addr_list);
1252         @addr_list = sanitize_address_list(@addr_list);
1253         @addr_list = validate_address_list(@addr_list);
1254         return @addr_list;
1255 }
1256
1257 # Returns the local Fully Qualified Domain Name (FQDN) if available.
1258 #
1259 # Tightly configured MTAa require that a caller sends a real DNS
1260 # domain name that corresponds the IP address in the HELO/EHLO
1261 # handshake. This is used to verify the connection and prevent
1262 # spammers from trying to hide their identity. If the DNS and IP don't
1263 # match, the receiving MTA may deny the connection.
1264 #
1265 # Here is a deny example of Net::SMTP with the default "localhost.localdomain"
1266 #
1267 # Net::SMTP=GLOB(0x267ec28)>>> EHLO localhost.localdomain
1268 # Net::SMTP=GLOB(0x267ec28)<<< 550 EHLO argument does not match calling host
1269 #
1270 # This maildomain*() code is based on ideas in Perl library Test::Reporter
1271 # /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
1272
1273 sub valid_fqdn {
1274         my $domain = shift;
1275         return defined $domain && !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
1276 }
1277
1278 sub maildomain_net {
1279         my $maildomain;
1280
1281         my $domain = Net::Domain::domainname();
1282         $maildomain = $domain if valid_fqdn($domain);
1283
1284         return $maildomain;
1285 }
1286
1287 sub maildomain_mta {
1288         my $maildomain;
1289
1290         for my $host (qw(mailhost localhost)) {
1291                 my $smtp = Net::SMTP->new($host);
1292                 if (defined $smtp) {
1293                         my $domain = $smtp->domain;
1294                         $smtp->quit;
1295
1296                         $maildomain = $domain if valid_fqdn($domain);
1297
1298                         last if $maildomain;
1299                 }
1300         }
1301
1302         return $maildomain;
1303 }
1304
1305 sub maildomain {
1306         return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
1307 }
1308
1309 sub smtp_host_string {
1310         if (defined $smtp_server_port) {
1311                 return "$smtp_server:$smtp_server_port";
1312         } else {
1313                 return $smtp_server;
1314         }
1315 }
1316
1317 # Returns 1 if authentication succeeded or was not necessary
1318 # (smtp_user was not specified), and 0 otherwise.
1319
1320 sub smtp_auth_maybe {
1321         if (!defined $smtp_authuser || $auth || (defined $smtp_auth && $smtp_auth eq "none")) {
1322                 return 1;
1323         }
1324
1325         # Workaround AUTH PLAIN/LOGIN interaction defect
1326         # with Authen::SASL::Cyrus
1327         eval {
1328                 require Authen::SASL;
1329                 Authen::SASL->import(qw(Perl));
1330         };
1331
1332         # Check mechanism naming as defined in:
1333         # https://tools.ietf.org/html/rfc4422#page-8
1334         if ($smtp_auth && $smtp_auth !~ /^(\b[A-Z0-9-_]{1,20}\s*)*$/) {
1335                 die "invalid smtp auth: '${smtp_auth}'";
1336         }
1337
1338         # TODO: Authentication may fail not because credentials were
1339         # invalid but due to other reasons, in which we should not
1340         # reject credentials.
1341         $auth = Git::credential({
1342                 'protocol' => 'smtp',
1343                 'host' => smtp_host_string(),
1344                 'username' => $smtp_authuser,
1345                 # if there's no password, "git credential fill" will
1346                 # give us one, otherwise it'll just pass this one.
1347                 'password' => $smtp_authpass
1348         }, sub {
1349                 my $cred = shift;
1350
1351                 if ($smtp_auth) {
1352                         my $sasl = Authen::SASL->new(
1353                                 mechanism => $smtp_auth,
1354                                 callback => {
1355                                         user => $cred->{'username'},
1356                                         pass => $cred->{'password'},
1357                                         authname => $cred->{'username'},
1358                                 }
1359                         );
1360
1361                         return !!$smtp->auth($sasl);
1362                 }
1363
1364                 return !!$smtp->auth($cred->{'username'}, $cred->{'password'});
1365         });
1366
1367         return $auth;
1368 }
1369
1370 sub ssl_verify_params {
1371         eval {
1372                 require IO::Socket::SSL;
1373                 IO::Socket::SSL->import(qw/SSL_VERIFY_PEER SSL_VERIFY_NONE/);
1374         };
1375         if ($@) {
1376                 print STDERR "Not using SSL_VERIFY_PEER due to out-of-date IO::Socket::SSL.\n";
1377                 return;
1378         }
1379
1380         if (!defined $smtp_ssl_cert_path) {
1381                 # use the OpenSSL defaults
1382                 return (SSL_verify_mode => SSL_VERIFY_PEER());
1383         }
1384
1385         if ($smtp_ssl_cert_path eq "") {
1386                 return (SSL_verify_mode => SSL_VERIFY_NONE());
1387         } elsif (-d $smtp_ssl_cert_path) {
1388                 return (SSL_verify_mode => SSL_VERIFY_PEER(),
1389                         SSL_ca_path => $smtp_ssl_cert_path);
1390         } elsif (-f $smtp_ssl_cert_path) {
1391                 return (SSL_verify_mode => SSL_VERIFY_PEER(),
1392                         SSL_ca_file => $smtp_ssl_cert_path);
1393         } else {
1394                 die sprintf(__("CA path \"%s\" does not exist"), $smtp_ssl_cert_path);
1395         }
1396 }
1397
1398 sub file_name_is_absolute {
1399         my ($path) = @_;
1400
1401         # msys does not grok DOS drive-prefixes
1402         if ($^O eq 'msys') {
1403                 return ($path =~ m#^/# || $path =~ m#^[a-zA-Z]\:#)
1404         }
1405
1406         require File::Spec::Functions;
1407         return File::Spec::Functions::file_name_is_absolute($path);
1408 }
1409
1410 # Prepares the email, then asks the user what to do.
1411 #
1412 # If the user chooses to send the email, it's sent and 1 is returned.
1413 # If the user chooses not to send the email, 0 is returned.
1414 # If the user decides they want to make further edits, -1 is returned and the
1415 # caller is expected to call send_message again after the edits are performed.
1416 #
1417 # If an error occurs sending the email, this just dies.
1418
1419 sub send_message {
1420         my @recipients = unique_email_list(@to);
1421         @cc = (grep { my $cc = extract_valid_address_or_die($_);
1422                       not grep { $cc eq $_ || $_ =~ /<\Q${cc}\E>$/ } @recipients
1423                     }
1424                @cc);
1425         my $to = join (",\n\t", @recipients);
1426         @recipients = unique_email_list(@recipients,@cc,@initial_bcc);
1427         @recipients = (map { extract_valid_address_or_die($_) } @recipients);
1428         my $date = format_2822_time($time++);
1429         my $gitversion = '@@GIT_VERSION@@';
1430         if ($gitversion =~ m/..GIT_VERSION../) {
1431             $gitversion = Git::version();
1432         }
1433
1434         my $cc = join(",\n\t", unique_email_list(@cc));
1435         my $ccline = "";
1436         if ($cc ne '') {
1437                 $ccline = "\nCc: $cc";
1438         }
1439         make_message_id() unless defined($message_id);
1440
1441         my $header = "From: $sender
1442 To: $to${ccline}
1443 Subject: $subject
1444 Date: $date
1445 Message-Id: $message_id
1446 ";
1447         if ($use_xmailer) {
1448                 $header .= "X-Mailer: git-send-email $gitversion\n";
1449         }
1450         if ($in_reply_to) {
1451
1452                 $header .= "In-Reply-To: $in_reply_to\n";
1453                 $header .= "References: $references\n";
1454         }
1455         if ($reply_to) {
1456                 $header .= "Reply-To: $reply_to\n";
1457         }
1458         if (@xh) {
1459                 $header .= join("\n", @xh) . "\n";
1460         }
1461
1462         my @sendmail_parameters = ('-i', @recipients);
1463         my $raw_from = $sender;
1464         if (defined $envelope_sender && $envelope_sender ne "auto") {
1465                 $raw_from = $envelope_sender;
1466         }
1467         $raw_from = extract_valid_address($raw_from);
1468         unshift (@sendmail_parameters,
1469                         '-f', $raw_from) if(defined $envelope_sender);
1470
1471         if ($needs_confirm && !$dry_run) {
1472                 print "\n$header\n";
1473                 if ($needs_confirm eq "inform") {
1474                         $confirm_unconfigured = 0; # squelch this message for the rest of this run
1475                         $ask_default = "y"; # assume yes on EOF since user hasn't explicitly asked for confirmation
1476                         print __ <<EOF ;
1477     The Cc list above has been expanded by additional
1478     addresses found in the patch commit message. By default
1479     send-email prompts before sending whenever this occurs.
1480     This behavior is controlled by the sendemail.confirm
1481     configuration setting.
1482
1483     For additional information, run 'git send-email --help'.
1484     To retain the current behavior, but squelch this message,
1485     run 'git config --global sendemail.confirm auto'.
1486
1487 EOF
1488                 }
1489                 # TRANSLATORS: Make sure to include [y] [n] [e] [q] [a] in your
1490                 # translation. The program will only accept English input
1491                 # at this point.
1492                 $_ = ask(__("Send this email? ([y]es|[n]o|[e]dit|[q]uit|[a]ll): "),
1493                          valid_re => qr/^(?:yes|y|no|n|edit|e|quit|q|all|a)/i,
1494                          default => $ask_default);
1495                 die __("Send this email reply required") unless defined $_;
1496                 if (/^n/i) {
1497                         return 0;
1498                 } elsif (/^e/i) {
1499                         return -1;
1500                 } elsif (/^q/i) {
1501                         cleanup_compose_files();
1502                         exit(0);
1503                 } elsif (/^a/i) {
1504                         $confirm = 'never';
1505                 }
1506         }
1507
1508         unshift (@sendmail_parameters, @smtp_server_options);
1509
1510         if ($dry_run) {
1511                 # We don't want to send the email.
1512         } elsif (defined $sendmail_cmd || file_name_is_absolute($smtp_server)) {
1513                 my $pid = open my $sm, '|-';
1514                 defined $pid or die $!;
1515                 if (!$pid) {
1516                         if (defined $sendmail_cmd) {
1517                                 exec ("sh", "-c", "$sendmail_cmd \"\$@\"", "-", @sendmail_parameters)
1518                                         or die $!;
1519                         } else {
1520                                 exec ($smtp_server, @sendmail_parameters)
1521                                         or die $!;
1522                         }
1523                 }
1524                 print $sm "$header\n$message";
1525                 close $sm or die $!;
1526         } else {
1527
1528                 if (!defined $smtp_server) {
1529                         die __("The required SMTP server is not properly defined.")
1530                 }
1531
1532                 require Net::SMTP;
1533                 my $use_net_smtp_ssl = version->parse($Net::SMTP::VERSION) < version->parse("2.34");
1534                 $smtp_domain ||= maildomain();
1535
1536                 if ($smtp_encryption eq 'ssl') {
1537                         $smtp_server_port ||= 465; # ssmtp
1538                         require IO::Socket::SSL;
1539
1540                         # Suppress "variable accessed once" warning.
1541                         {
1542                                 no warnings 'once';
1543                                 $IO::Socket::SSL::DEBUG = 1;
1544                         }
1545
1546                         # Net::SMTP::SSL->new() does not forward any SSL options
1547                         IO::Socket::SSL::set_client_defaults(
1548                                 ssl_verify_params());
1549
1550                         if ($use_net_smtp_ssl) {
1551                                 require Net::SMTP::SSL;
1552                                 $smtp ||= Net::SMTP::SSL->new($smtp_server,
1553                                                               Hello => $smtp_domain,
1554                                                               Port => $smtp_server_port,
1555                                                               Debug => $debug_net_smtp);
1556                         }
1557                         else {
1558                                 $smtp ||= Net::SMTP->new($smtp_server,
1559                                                          Hello => $smtp_domain,
1560                                                          Port => $smtp_server_port,
1561                                                          Debug => $debug_net_smtp,
1562                                                          SSL => 1);
1563                         }
1564                 }
1565                 elsif (!$smtp) {
1566                         $smtp_server_port ||= 25;
1567                         $smtp ||= Net::SMTP->new($smtp_server,
1568                                                  Hello => $smtp_domain,
1569                                                  Debug => $debug_net_smtp,
1570                                                  Port => $smtp_server_port);
1571                         if ($smtp_encryption eq 'tls' && $smtp) {
1572                                 if ($use_net_smtp_ssl) {
1573                                         $smtp->command('STARTTLS');
1574                                         $smtp->response();
1575                                         if ($smtp->code != 220) {
1576                                                 die sprintf(__("Server does not support STARTTLS! %s"), $smtp->message);
1577                                         }
1578                                         require Net::SMTP::SSL;
1579                                         $smtp = Net::SMTP::SSL->start_SSL($smtp,
1580                                                                           ssl_verify_params())
1581                                                 or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
1582                                 }
1583                                 else {
1584                                         $smtp->starttls(ssl_verify_params())
1585                                                 or die sprintf(__("STARTTLS failed! %s"), IO::Socket::SSL::errstr());
1586                                 }
1587                                 # Send EHLO again to receive fresh
1588                                 # supported commands
1589                                 $smtp->hello($smtp_domain);
1590                         }
1591                 }
1592
1593                 if (!$smtp) {
1594                         die __("Unable to initialize SMTP properly. Check config and use --smtp-debug."),
1595                             " VALUES: server=$smtp_server ",
1596                             "encryption=$smtp_encryption ",
1597                             "hello=$smtp_domain",
1598                             defined $smtp_server_port ? " port=$smtp_server_port" : "";
1599                 }
1600
1601                 smtp_auth_maybe or die $smtp->message;
1602
1603                 $smtp->mail( $raw_from ) or die $smtp->message;
1604                 $smtp->to( @recipients ) or die $smtp->message;
1605                 $smtp->data or die $smtp->message;
1606                 $smtp->datasend("$header\n") or die $smtp->message;
1607                 my @lines = split /^/, $message;
1608                 foreach my $line (@lines) {
1609                         $smtp->datasend("$line") or die $smtp->message;
1610                 }
1611                 $smtp->dataend() or die $smtp->message;
1612                 $smtp->code =~ /250|200/ or die sprintf(__("Failed to send %s\n"), $subject).$smtp->message;
1613         }
1614         if ($quiet) {
1615                 printf($dry_run ? __("Dry-Sent %s\n") : __("Sent %s\n"), $subject);
1616         } else {
1617                 print($dry_run ? __("Dry-OK. Log says:\n") : __("OK. Log says:\n"));
1618                 if (!defined $sendmail_cmd && !file_name_is_absolute($smtp_server)) {
1619                         print "Server: $smtp_server\n";
1620                         print "MAIL FROM:<$raw_from>\n";
1621                         foreach my $entry (@recipients) {
1622                             print "RCPT TO:<$entry>\n";
1623                         }
1624                 } else {
1625                         my $sm;
1626                         if (defined $sendmail_cmd) {
1627                                 $sm = $sendmail_cmd;
1628                         } else {
1629                                 $sm = $smtp_server;
1630                         }
1631
1632                         print "Sendmail: $sm ".join(' ',@sendmail_parameters)."\n";
1633                 }
1634                 print $header, "\n";
1635                 if ($smtp) {
1636                         print __("Result: "), $smtp->code, ' ',
1637                                 ($smtp->message =~ /\n([^\n]+\n)$/s), "\n";
1638                 } else {
1639                         print __("Result: OK\n");
1640                 }
1641         }
1642
1643         return 1;
1644 }
1645
1646 $in_reply_to = $initial_in_reply_to;
1647 $references = $initial_in_reply_to || '';
1648 $subject = $initial_subject;
1649 $message_num = 0;
1650
1651 # Prepares the email, prompts the user, sends it out
1652 # Returns 0 if an edit was done and the function should be called again, or 1
1653 # otherwise.
1654 sub process_file {
1655         my ($t) = @_;
1656
1657         open my $fh, "<", $t or die sprintf(__("can't open file %s"), $t);
1658
1659         my $author = undef;
1660         my $sauthor = undef;
1661         my $author_encoding;
1662         my $has_content_type;
1663         my $body_encoding;
1664         my $xfer_encoding;
1665         my $has_mime_version;
1666         @to = ();
1667         @cc = ();
1668         @xh = ();
1669         my $input_format = undef;
1670         my @header = ();
1671         $message = "";
1672         $message_num++;
1673         # First unfold multiline header fields
1674         while(<$fh>) {
1675                 last if /^\s*$/;
1676                 if (/^\s+\S/ and @header) {
1677                         chomp($header[$#header]);
1678                         s/^\s+/ /;
1679                         $header[$#header] .= $_;
1680             } else {
1681                         push(@header, $_);
1682                 }
1683         }
1684         # Now parse the header
1685         foreach(@header) {
1686                 if (/^From /) {
1687                         $input_format = 'mbox';
1688                         next;
1689                 }
1690                 chomp;
1691                 if (!defined $input_format && /^[-A-Za-z]+:\s/) {
1692                         $input_format = 'mbox';
1693                 }
1694
1695                 if (defined $input_format && $input_format eq 'mbox') {
1696                         if (/^Subject:\s+(.*)$/i) {
1697                                 $subject = $1;
1698                         }
1699                         elsif (/^From:\s+(.*)$/i) {
1700                                 ($author, $author_encoding) = unquote_rfc2047($1);
1701                                 $sauthor = sanitize_address($author);
1702                                 next if $suppress_cc{'author'};
1703                                 next if $suppress_cc{'self'} and $sauthor eq $sender;
1704                                 printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1705                                         $1, $_) unless $quiet;
1706                                 push @cc, $1;
1707                         }
1708                         elsif (/^To:\s+(.*)$/i) {
1709                                 foreach my $addr (parse_address_line($1)) {
1710                                         printf(__("(mbox) Adding to: %s from line '%s'\n"),
1711                                                 $addr, $_) unless $quiet;
1712                                         push @to, $addr;
1713                                 }
1714                         }
1715                         elsif (/^Cc:\s+(.*)$/i) {
1716                                 foreach my $addr (parse_address_line($1)) {
1717                                         my $qaddr = unquote_rfc2047($addr);
1718                                         my $saddr = sanitize_address($qaddr);
1719                                         if ($saddr eq $sender) {
1720                                                 next if ($suppress_cc{'self'});
1721                                         } else {
1722                                                 next if ($suppress_cc{'cc'});
1723                                         }
1724                                         printf(__("(mbox) Adding cc: %s from line '%s'\n"),
1725                                                 $addr, $_) unless $quiet;
1726                                         push @cc, $addr;
1727                                 }
1728                         }
1729                         elsif (/^Content-type:/i) {
1730                                 $has_content_type = 1;
1731                                 if (/charset="?([^ "]+)/) {
1732                                         $body_encoding = $1;
1733                                 }
1734                                 push @xh, $_;
1735                         }
1736                         elsif (/^MIME-Version/i) {
1737                                 $has_mime_version = 1;
1738                                 push @xh, $_;
1739                         }
1740                         elsif (/^Message-Id: (.*)/i) {
1741                                 $message_id = $1;
1742                         }
1743                         elsif (/^Content-Transfer-Encoding: (.*)/i) {
1744                                 $xfer_encoding = $1 if not defined $xfer_encoding;
1745                         }
1746                         elsif (/^In-Reply-To: (.*)/i) {
1747                                 if (!$initial_in_reply_to || $thread) {
1748                                         $in_reply_to = $1;
1749                                 }
1750                         }
1751                         elsif (/^References: (.*)/i) {
1752                                 if (!$initial_in_reply_to || $thread) {
1753                                         $references = $1;
1754                                 }
1755                         }
1756                         elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
1757                                 push @xh, $_;
1758                         }
1759                 } else {
1760                         # In the traditional
1761                         # "send lots of email" format,
1762                         # line 1 = cc
1763                         # line 2 = subject
1764                         # So let's support that, too.
1765                         $input_format = 'lots';
1766                         if (@cc == 0 && !$suppress_cc{'cc'}) {
1767                                 printf(__("(non-mbox) Adding cc: %s from line '%s'\n"),
1768                                         $_, $_) unless $quiet;
1769                                 push @cc, $_;
1770                         } elsif (!defined $subject) {
1771                                 $subject = $_;
1772                         }
1773                 }
1774         }
1775         # Now parse the message body
1776         while(<$fh>) {
1777                 $message .=  $_;
1778                 if (/^([a-z][a-z-]*-by|Cc): (.*)/i) {
1779                         chomp;
1780                         my ($what, $c) = ($1, $2);
1781                         # strip garbage for the address we'll use:
1782                         $c = strip_garbage_one_address($c);
1783                         # sanitize a bit more to decide whether to suppress the address:
1784                         my $sc = sanitize_address($c);
1785                         if ($sc eq $sender) {
1786                                 next if ($suppress_cc{'self'});
1787                         } else {
1788                                 if ($what =~ /^Signed-off-by$/i) {
1789                                         next if $suppress_cc{'sob'};
1790                                 } elsif ($what =~ /-by$/i) {
1791                                         next if $suppress_cc{'misc-by'};
1792                                 } elsif ($what =~ /Cc/i) {
1793                                         next if $suppress_cc{'bodycc'};
1794                                 }
1795                         }
1796                         if ($c !~ /.+@.+|<.+>/) {
1797                                 printf("(body) Ignoring %s from line '%s'\n",
1798                                         $what, $_) unless $quiet;
1799                                 next;
1800                         }
1801                         push @cc, $c;
1802                         printf(__("(body) Adding cc: %s from line '%s'\n"),
1803                                 $c, $_) unless $quiet;
1804                 }
1805         }
1806         close $fh;
1807
1808         push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
1809                 if defined $to_cmd;
1810         push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
1811                 if defined $cc_cmd && !$suppress_cc{'cccmd'};
1812
1813         if ($broken_encoding{$t} && !$has_content_type) {
1814                 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1815                 $has_content_type = 1;
1816                 push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
1817                 $body_encoding = $auto_8bit_encoding;
1818         }
1819
1820         if ($broken_encoding{$t} && !is_rfc2047_quoted($subject)) {
1821                 $subject = quote_subject($subject, $auto_8bit_encoding);
1822         }
1823
1824         if (defined $sauthor and $sauthor ne $sender) {
1825                 $message = "From: $author\n\n$message";
1826                 if (defined $author_encoding) {
1827                         if ($has_content_type) {
1828                                 if ($body_encoding eq $author_encoding) {
1829                                         # ok, we already have the right encoding
1830                                 }
1831                                 else {
1832                                         # uh oh, we should re-encode
1833                                 }
1834                         }
1835                         else {
1836                                 $xfer_encoding = '8bit' if not defined $xfer_encoding;
1837                                 $has_content_type = 1;
1838                                 push @xh,
1839                                   "Content-Type: text/plain; charset=$author_encoding";
1840                         }
1841                 }
1842         }
1843         $xfer_encoding = '8bit' if not defined $xfer_encoding;
1844         ($message, $xfer_encoding) = apply_transfer_encoding(
1845                 $message, $xfer_encoding, $target_xfer_encoding);
1846         push @xh, "Content-Transfer-Encoding: $xfer_encoding";
1847         unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
1848
1849         $needs_confirm = (
1850                 $confirm eq "always" or
1851                 ($confirm =~ /^(?:auto|cc)$/ && @cc) or
1852                 ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
1853         $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
1854
1855         @to = process_address_list(@to);
1856         @cc = process_address_list(@cc);
1857
1858         @to = (@initial_to, @to);
1859         @cc = (@initial_cc, @cc);
1860
1861         if ($message_num == 1) {
1862                 if (defined $cover_cc and $cover_cc) {
1863                         @initial_cc = @cc;
1864                 }
1865                 if (defined $cover_to and $cover_to) {
1866                         @initial_to = @to;
1867                 }
1868         }
1869
1870         my $message_was_sent = send_message();
1871         if ($message_was_sent == -1) {
1872                 do_edit($t);
1873                 return 0;
1874         }
1875
1876         # set up for the next message
1877         if ($thread && $message_was_sent &&
1878                 ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
1879                 $message_num == 1)) {
1880                 $in_reply_to = $message_id;
1881                 if (length $references > 0) {
1882                         $references .= "\n $message_id";
1883                 } else {
1884                         $references = "$message_id";
1885                 }
1886         }
1887         $message_id = undef;
1888         $num_sent++;
1889         if (defined $batch_size && $num_sent == $batch_size) {
1890                 $num_sent = 0;
1891                 $smtp->quit if defined $smtp;
1892                 undef $smtp;
1893                 undef $auth;
1894                 sleep($relogin_delay) if defined $relogin_delay;
1895         }
1896
1897         return 1;
1898 }
1899
1900 foreach my $t (@files) {
1901         while (!process_file($t)) {
1902                 # user edited the file
1903         }
1904 }
1905
1906 # Execute a command (e.g. $to_cmd) to get a list of email addresses
1907 # and return a results array
1908 sub recipients_cmd {
1909         my ($prefix, $what, $cmd, $file) = @_;
1910
1911         my @addresses = ();
1912         open my $fh, "-|", "$cmd \Q$file\E"
1913             or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd);
1914         while (my $address = <$fh>) {
1915                 $address =~ s/^\s*//g;
1916                 $address =~ s/\s*$//g;
1917                 $address = sanitize_address($address);
1918                 next if ($address eq $sender and $suppress_cc{'self'});
1919                 push @addresses, $address;
1920                 printf(__("(%s) Adding %s: %s from: '%s'\n"),
1921                        $prefix, $what, $address, $cmd) unless $quiet;
1922                 }
1923         close $fh
1924             or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd);
1925         return @addresses;
1926 }
1927
1928 cleanup_compose_files();
1929
1930 sub cleanup_compose_files {
1931         unlink($compose_filename, $compose_filename . ".final") if $compose;
1932 }
1933
1934 $smtp->quit if $smtp;
1935
1936 sub apply_transfer_encoding {
1937         my $message = shift;
1938         my $from = shift;
1939         my $to = shift;
1940
1941         return ($message, $to) if ($from eq $to and $from ne '7bit');
1942
1943         require MIME::QuotedPrint;
1944         require MIME::Base64;
1945
1946         $message = MIME::QuotedPrint::decode($message)
1947                 if ($from eq 'quoted-printable');
1948         $message = MIME::Base64::decode($message)
1949                 if ($from eq 'base64');
1950
1951         $to = ($message =~ /(?:.{999,}|\r)/) ? 'quoted-printable' : '8bit'
1952                 if $to eq 'auto';
1953
1954         die __("cannot send message as 7bit")
1955                 if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
1956         return ($message, $to)
1957                 if ($to eq '7bit' or $to eq '8bit');
1958         return (MIME::QuotedPrint::encode($message, "\n", 0), $to)
1959                 if ($to eq 'quoted-printable');
1960         return (MIME::Base64::encode($message, "\n"), $to)
1961                 if ($to eq 'base64');
1962         die __("invalid transfer encoding");
1963 }
1964
1965 sub unique_email_list {
1966         my %seen;
1967         my @emails;
1968
1969         foreach my $entry (@_) {
1970                 my $clean = extract_valid_address_or_die($entry);
1971                 $seen{$clean} ||= 0;
1972                 next if $seen{$clean}++;
1973                 push @emails, $entry;
1974         }
1975         return @emails;
1976 }
1977
1978 sub validate_patch {
1979         my ($fn, $xfer_encoding) = @_;
1980
1981         if ($repo) {
1982                 my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks');
1983                 my $validate_hook = catfile($hooks_path,
1984                                             'sendemail-validate');
1985                 my $hook_error;
1986                 if (-x $validate_hook) {
1987                         my $target = abs_path($fn);
1988                         # The hook needs a correct cwd and GIT_DIR.
1989                         my $cwd_save = cwd();
1990                         chdir($repo->wc_path() or $repo->repo_path())
1991                                 or die("chdir: $!");
1992                         local $ENV{"GIT_DIR"} = $repo->repo_path();
1993                         $hook_error = system_or_msg([$validate_hook, $target]);
1994                         chdir($cwd_save) or die("chdir: $!");
1995                 }
1996                 if ($hook_error) {
1997                         die sprintf(__("fatal: %s: rejected by sendemail-validate hook\n" .
1998                                        "%s\n" .
1999                                        "warning: no patches were sent\n"), $fn, $hook_error);
2000                 }
2001         }
2002
2003         # Any long lines will be automatically fixed if we use a suitable transfer
2004         # encoding.
2005         unless ($xfer_encoding =~ /^(?:auto|quoted-printable|base64)$/) {
2006                 open(my $fh, '<', $fn)
2007                         or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2008                 while (my $line = <$fh>) {
2009                         if (length($line) > 998) {
2010                                 die sprintf(__("fatal: %s:%d is longer than 998 characters\n" .
2011                                                "warning: no patches were sent\n"), $fn, $.);
2012                         }
2013                 }
2014         }
2015         return;
2016 }
2017
2018 sub handle_backup {
2019         my ($last, $lastlen, $file, $known_suffix) = @_;
2020         my ($suffix, $skip);
2021
2022         $skip = 0;
2023         if (defined $last &&
2024             ($lastlen < length($file)) &&
2025             (substr($file, 0, $lastlen) eq $last) &&
2026             ($suffix = substr($file, $lastlen)) !~ /^[a-z0-9]/i) {
2027                 if (defined $known_suffix && $suffix eq $known_suffix) {
2028                         printf(__("Skipping %s with backup suffix '%s'.\n"), $file, $known_suffix);
2029                         $skip = 1;
2030                 } else {
2031                         # TRANSLATORS: please keep "[y|N]" as is.
2032                         my $answer = ask(sprintf(__("Do you really want to send %s? [y|N]: "), $file),
2033                                          valid_re => qr/^(?:y|n)/i,
2034                                          default => 'n');
2035                         $skip = ($answer ne 'y');
2036                         if ($skip) {
2037                                 $known_suffix = $suffix;
2038                         }
2039                 }
2040         }
2041         return ($skip, $known_suffix);
2042 }
2043
2044 sub handle_backup_files {
2045         my @file = @_;
2046         my ($last, $lastlen, $known_suffix, $skip, @result);
2047         for my $file (@file) {
2048                 ($skip, $known_suffix) = handle_backup($last, $lastlen,
2049                                                        $file, $known_suffix);
2050                 push @result, $file unless $skip;
2051                 $last = $file;
2052                 $lastlen = length($file);
2053         }
2054         return @result;
2055 }
2056
2057 sub file_has_nonascii {
2058         my $fn = shift;
2059         open(my $fh, '<', $fn)
2060                 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2061         while (my $line = <$fh>) {
2062                 return 1 if $line =~ /[^[:ascii:]]/;
2063         }
2064         return 0;
2065 }
2066
2067 sub body_or_subject_has_nonascii {
2068         my $fn = shift;
2069         open(my $fh, '<', $fn)
2070                 or die sprintf(__("unable to open %s: %s\n"), $fn, $!);
2071         while (my $line = <$fh>) {
2072                 last if $line =~ /^$/;
2073                 return 1 if $line =~ /^Subject.*[^[:ascii:]]/;
2074         }
2075         while (my $line = <$fh>) {
2076                 return 1 if $line =~ /[^[:ascii:]]/;
2077         }
2078         return 0;
2079 }