Merge branch 'jk/maint-send-email-alias-loop'
authorJunio C Hamano <gitster@pobox.com>
Sat, 25 Jul 2009 07:44:45 +0000 (00:44 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 25 Jul 2009 07:44:45 +0000 (00:44 -0700)
* jk/maint-send-email-alias-loop:
send-email: detect cycles in alias expansion

1  2 
git-send-email.perl
diff --combined git-send-email.perl
index 8ce6f1fe57579201c09cf960caed98d330ab2bbb,f299c2dba25140ee320530c4f8852a24cbbf120c..d508f83349b57ac2e7148f090e2abbf0a398fce4
@@@ -210,7 -210,6 +210,7 @@@ my %config_settings = 
      "envelopesender" => \$envelope_sender,
      "multiedit" => \$multiedit,
      "confirm"   => \$confirm,
 +    "from" => \$sender,
  );
  
  # Handle Uncouth Termination
@@@ -334,7 -333,7 +334,7 @@@ if (@suppress_cc) 
  }
  
  if ($suppress_cc{'all'}) {
 -      foreach my $entry (qw (ccmd cc author self sob body bodycc)) {
 +      foreach my $entry (qw (cccmd cc author self sob body bodycc)) {
                $suppress_cc{$entry} = 1;
        }
        delete $suppress_cc{'all'};
@@@ -410,7 -409,7 +410,7 @@@ my %parse_alias = 
        mailrc => sub { my $fh = shift; while (<$fh>) {
                if (/^alias\s+(\S+)\s+(.*)$/) {
                        # spaces delimit multiple addresses
 -                      $aliases{$1} = [ split(/\s+/, $2) ];
 +                      $aliases{$1} = [ quotewords('\s+', 0, $2) ];
                }}},
        pine => sub { my $fh = shift; my $f='\t[^\t]*';
                for (my $x = ''; defined($x); $x = $_) {
@@@ -538,7 -537,7 +538,7 @@@ if ($compose) 
  
        print C <<EOT;
  From $tpl_sender # This line is ignored.
 -GIT: Lines beginning in "GIT: " will be removed.
 +GIT: Lines beginning in "GIT:" will be removed.
  GIT: Consider including an overall diffstat or table of contents
  GIT: for the patch you are writing.
  GIT:
@@@ -553,6 -552,8 +553,6 @@@ EO
        }
        close(C);
  
 -      my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
 -
        if ($annotate) {
                do_edit($compose_filename, @files);
        } else {
        my $in_body = 0;
        my $summary_empty = 1;
        while(<C>) {
 -              next if m/^GIT: /;
 +              next if m/^GIT:/;
                if ($in_body) {
                        $summary_empty = 0 unless (/^\n$/);
                } elsif (/^\n$/) {
                        if ($need_8bit_cte) {
                                print C2 "MIME-Version: 1.0\n",
                                         "Content-Type: text/plain; ",
 -                                         "charset=utf-8\n",
 +                                         "charset=UTF-8\n",
                                         "Content-Transfer-Encoding: 8bit\n";
                        }
                } elsif (/^MIME-Version:/i) {
@@@ -654,13 -655,17 +654,17 @@@ if (!@to) 
  }
  
  sub expand_aliases {
-       my @cur = @_;
-       my @last;
-       do {
-               @last = @cur;
-               @cur = map { $aliases{$_} ? @{$aliases{$_}} : $_ } @last;
-       } while (join(',',@cur) ne join(',',@last));
-       return @cur;
+       return map { expand_one_alias($_) } @_;
+ }
+ my %EXPANDED_ALIASES;
+ sub expand_one_alias {
+       my $alias = shift;
+       if ($EXPANDED_ALIASES{$alias}) {
+               die "fatal: alias '$alias' expands to itself\n";
+       }
+       local $EXPANDED_ALIASES{$alias} = 1;
+       return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
  }
  
  @to = expand_aliases(@to);
@@@ -766,20 -771,12 +770,20 @@@ sub unquote_rfc2047 
  
  sub quote_rfc2047 {
        local $_ = shift;
 -      my $encoding = shift || 'utf-8';
 +      my $encoding = shift || 'UTF-8';
        s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
        s/(.*)/=\?$encoding\?q\?$1\?=/;
        return $_;
  }
  
 +sub is_rfc2047_quoted {
 +      my $s = shift;
 +      my $token = '[^][()<>@,;:"\/?.= \000-\037\177-\377]+';
 +      my $encoded_text = '[!->@-~]+';
 +      length($s) <= 75 &&
 +      $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
 +}
 +
  # use the simplest quoting being able to handle the recipient
  sub sanitize_address
  {
        }
  
        # if recipient_name is already quoted, do nothing
 -      if ($recipient_name =~ /^("[[:ascii:]]*"|=\?utf-8\?q\?.*\?=)$/) {
 +      if (is_rfc2047_quoted($recipient_name)) {
                return $recipient;
        }
  
  
  }
  
 +# Returns 1 if the message was sent, and 0 otherwise.
 +# In actuality, the whole program dies when there
 +# is an error sending a message.
 +
  sub send_message
  {
        my @recipients = unique_email_list(@to);
@@@ -883,7 -876,7 +887,7 @@@ X-Mailer: git-send-email $gitversio
                         default => $ask_default);
                die "Send this email reply required" unless defined $_;
                if (/^n/i) {
 -                      return;
 +                      return 0;
                } elsif (/^q/i) {
                        cleanup_compose_files();
                        exit(0);
                $smtp->data or die $smtp->message;
                $smtp->datasend("$header\n$message") or die $smtp->message;
                $smtp->dataend() or die $smtp->message;
 -              $smtp->ok or die "Failed to send $subject\n".$smtp->message;
 +              $smtp->code =~ /250|200/ or die "Failed to send $subject\n".$smtp->message;
        }
        if ($quiet) {
                printf (($dry_run ? "Dry-" : "")."Sent %s\n", $subject);
                        print "Result: OK\n";
                }
        }
 +
 +      return 1;
  }
  
  $reply_to = $initial_reply_to;
@@@ -1104,7 -1095,7 +1108,7 @@@ foreach my $t (@files) 
        close F;
  
        if (defined $cc_cmd && !$suppress_cc{'cccmd'}) {
 -              open(F, "$cc_cmd $t |")
 +              open(F, "$cc_cmd \Q$t\E |")
                        or die "(cc-cmd) Could not execute '$cc_cmd'";
                while(<F>) {
                        my $c = $_;
  
        @cc = (@initial_cc, @cc);
  
 -      send_message();
 +      my $message_was_sent = send_message();
  
        # set up for the next message
 -      if ($chain_reply_to || !defined $reply_to || length($reply_to) == 0) {
 +      if ($thread && $message_was_sent &&
 +              ($chain_reply_to || !defined $reply_to || length($reply_to) == 0)) {
                $reply_to = $message_id;
                if (length $references > 0) {
                        $references .= "\n $message_id";