Merge branch 'jk/maint-send-email-compose'
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 May 2008 20:57:50 +0000 (13:57 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 21 May 2008 20:57:50 +0000 (13:57 -0700)
* jk/maint-send-email-compose:
send-email: rfc2047-quote subject lines with non-ascii characters
send-email: specify content-type of --compose body

Conflicts:

t/t9001-send-email.sh

Due to 065096c (git-send-email.perl: Handle shell metacharacters in
$EDITOR properly, 2008-05-04) which is a backward incompatible change (but
it makes handling of EDITOR consistent with other parts of the system),
the test script t9001 had to be adjusted.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
1  2 
git-send-email.perl
t/t9001-send-email.sh
diff --combined git-send-email.perl
index f5a86d39796b3cdc8e996cc1db259edf4475ef6c,455a5705967c74d44868ba9f153861e43e8b1939..a598fdc890c817875766c29aa714d622af770f4b
@@@ -168,8 -168,7 +168,8 @@@ my $envelope_sender
  # Example reply to:
  #$initial_reply_to = ''; #<20050203173208.GA23964@foobar.com>';
  
 -my $repo = Git->repository();
 +my $repo = eval { Git->repository() };
 +my @repo = $repo ? ($repo) : ();
  my $term = eval {
        $ENV{"GIT_SEND_EMAIL_NOTTY"}
                ? new Term::ReadLine 'git-send-email', \*STDIN, \*STDOUT
@@@ -203,7 -202,6 +203,7 @@@ my %config_settings = 
      "smtpuser" => \$smtp_authuser,
      "smtppass" => \$smtp_authpass,
      "to" => \@to,
 +    "cc" => \@initial_cc,
      "cccmd" => \$cc_cmd,
      "aliasfiletype" => \$aliasfiletype,
      "bcc" => \@bcclist,
@@@ -273,25 -271,25 +273,25 @@@ sub read_config 
  
        foreach my $setting (keys %config_bool_settings) {
                my $target = $config_bool_settings{$setting}->[0];
 -              $$target = $repo->config_bool("$prefix.$setting") unless (defined $$target);
 +              $$target = Git::config_bool(@repo, "$prefix.$setting") unless (defined $$target);
        }
  
        foreach my $setting (keys %config_settings) {
                my $target = $config_settings{$setting};
                if (ref($target) eq "ARRAY") {
                        unless (@$target) {
 -                              my @values = $repo->config("$prefix.$setting");
 +                              my @values = Git::config(@repo, "$prefix.$setting");
                                @$target = @values if (@values && defined $values[0]);
                        }
                }
                else {
 -                      $$target = $repo->config("$prefix.$setting") unless (defined $$target);
 +                      $$target = Git::config(@repo, "$prefix.$setting") unless (defined $$target);
                }
        }
  }
  
  # read configuration from [sendemail "$identity"], fall back on [sendemail]
 -$identity = $repo->config("sendemail.identity") unless (defined $identity);
 +$identity = Git::config(@repo, "sendemail.identity") unless (defined $identity);
  read_config("sendemail.$identity") if (defined $identity);
  read_config("sendemail");
  
@@@ -329,9 -327,8 +329,9 @@@ if (0) 
        }
  }
  
 -my ($repoauthor) = $repo->ident_person('author');
 -my ($repocommitter) = $repo->ident_person('committer');
 +my ($repoauthor, $repocommitter);
 +($repoauthor) = Git::ident_person(@repo, 'author');
 +($repocommitter) = Git::ident_person(@repo, 'committer');
  
  # Verify the user input
  
@@@ -418,7 -415,7 +418,7 @@@ if (@files) 
  
  my $prompting = 0;
  if (!defined $sender) {
 -      $sender = $repoauthor || $repocommitter;
 +      $sender = $repoauthor || $repocommitter || '';
  
        while (1) {
                $_ = $term->readline("Who should the emails appear to be from? [$sender] ");
@@@ -512,8 -509,8 +512,8 @@@ GIT: for the patch you are writing
  EOT
        close(C);
  
 -      my $editor = $ENV{GIT_EDITOR} || $repo->config("core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
 -      system('sh', '-c', '$0 $@', $editor, $compose_filename);
 +      my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
 +      system('sh', '-c', $editor.' "$@"', $editor, $compose_filename);
  
        open(C2,">",$compose_filename . ".final")
                or die "Failed to open $compose_filename.final : " . $!;
        open(C,"<",$compose_filename)
                or die "Failed to open $compose_filename : " . $!;
  
+       my $need_8bit_cte = file_has_nonascii($compose_filename);
+       my $in_body = 0;
        while(<C>) {
                next if m/^GIT: /;
+               if (!$in_body && /^\n$/) {
+                       $in_body = 1;
+                       if ($need_8bit_cte) {
+                               print C2 "MIME-Version: 1.0\n",
+                                        "Content-Type: text/plain; ",
+                                          "charset=utf-8\n",
+                                        "Content-Transfer-Encoding: 8bit\n";
+                       }
+               }
+               if (!$in_body && /^MIME-Version:/i) {
+                       $need_8bit_cte = 0;
+               }
+               if (!$in_body && /^Subject: ?(.*)/i) {
+                       my $subject = $1;
+                       $_ = "Subject: " .
+                               ($subject =~ /[^[:ascii:]]/ ?
+                                quote_rfc2047($subject) :
+                                $subject) .
+                               "\n";
+               }
                print C2 $_;
        }
        close(C);
@@@ -613,6 -632,14 +635,14 @@@ sub unquote_rfc2047 
        return wantarray ? ($_, $encoding) : $_;
  }
  
+ sub quote_rfc2047 {
+       local $_ = shift;
+       my $encoding = shift || 'utf-8';
+       s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
+       s/(.*)/=\?$encoding\?q\?$1\?=/;
+       return $_;
+ }
  # use the simplest quoting being able to handle the recipient
  sub sanitize_address
  {
  
        # rfc2047 is needed if a non-ascii char is included
        if ($recipient_name =~ /[^[:ascii:]]/) {
-               $recipient_name =~ s/([^-a-zA-Z0-9!*+\/])/sprintf("=%02X", ord($1))/eg;
-               $recipient_name =~ s/(.*)/=\?utf-8\?q\?$1\?=/;
+               $recipient_name = quote_rfc2047($recipient_name);
        }
  
        # double quotes are needed if specials or CTLs are included
        elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
 -              $recipient_name =~ s/(["\\\r])/\\$1/;
 +              $recipient_name =~ s/(["\\\r])/\\$1/g;
                $recipient_name = "\"$recipient_name\"";
        }
  
@@@ -959,3 -985,13 +988,13 @@@ sub validate_patch 
        }
        return undef;
  }
+ sub file_has_nonascii {
+       my $fn = shift;
+       open(my $fh, '<', $fn)
+               or die "unable to open $fn: $!\n";
+       while (my $line = <$fh>) {
+               return 1 if $line =~ /[^[:ascii:]]/;
+       }
+       return 0;
+ }
diff --combined t/t9001-send-email.sh
index 04baa61c0485377d033f4a10d2bb8ceeac1a4686,a4bcd282b609bb522d8f541a857c274996aa6842..3e4eb63f1c4d63d6ff38c79ff1f7a47fa3aa1597
@@@ -139,16 -139,15 +139,16 @@@ test_expect_success 'Valid In-Reply-To 
  
  test_expect_success 'setup fake editor' '
        (echo "#!/bin/sh" &&
 -       echo "echo fake edit >>\$1"
 +       echo "echo fake edit >>\"\$1\""
        ) >fake-editor &&
        chmod +x fake-editor
  '
  
 +test_set_editor "$(pwd)/fake-editor"
 +
  test_expect_success '--compose works' '
        clean_fake_sendmail &&
        echo y | \
 -              GIT_EDITOR=$(pwd)/fake-editor \
                GIT_SEND_EMAIL_NOTTY=1 \
                git send-email \
                --compose --subject foo \
@@@ -167,70 -166,63 +167,129 @@@ test_expect_success 'second message is 
        grep "Subject:.*Second" msgtxt2
  '
  
 -       echo "echo utf8 body: àéìöú >>\$1"
 +cat >expected-show-all-headers <<\EOF
 +0001-Second.patch
 +(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
 +Dry-OK. Log says:
 +Server: relay.example.com
 +MAIL FROM:<from@example.com>
 +RCPT TO:<to@example.com>,<cc@example.com>,<author@example.com>
 +From: Example <from@example.com>
 +To: to@example.com
 +Cc: cc@example.com, A <author@example.com>
 +Subject: [PATCH 1/1] Second.
 +Date: DATE-STRING
 +Message-Id: MESSAGE-ID-STRING
 +X-Mailer: X-MAILER-STRING
 +
 +Result: OK
 +EOF
 +
 +test_expect_success 'sendemail.cc set' '
 +      git config sendemail.cc cc@example.com &&
 +      git send-email \
 +              --dry-run \
 +              --from="Example <from@example.com>" \
 +              --to=to@example.com \
 +              --smtp-server relay.example.com \
 +              $patches |
 +      sed     -e "s/^\(Date:\).*/\1 DATE-STRING/" \
 +              -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 +              -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 +              >actual-show-all-headers &&
 +      test_cmp expected-show-all-headers actual-show-all-headers
 +'
 +
 +cat >expected-show-all-headers <<\EOF
 +0001-Second.patch
 +(mbox) Adding cc: A <author@example.com> from line 'From: A <author@example.com>'
 +Dry-OK. Log says:
 +Server: relay.example.com
 +MAIL FROM:<from@example.com>
 +RCPT TO:<to@example.com>,<author@example.com>
 +From: Example <from@example.com>
 +To: to@example.com
 +Cc: A <author@example.com>
 +Subject: [PATCH 1/1] Second.
 +Date: DATE-STRING
 +Message-Id: MESSAGE-ID-STRING
 +X-Mailer: X-MAILER-STRING
 +
 +Result: OK
 +EOF
 +
 +test_expect_success 'sendemail.cc unset' '
 +      git config --unset sendemail.cc &&
 +      git send-email \
 +              --dry-run \
 +              --from="Example <from@example.com>" \
 +              --to=to@example.com \
 +              --smtp-server relay.example.com \
 +              $patches |
 +      sed     -e "s/^\(Date:\).*/\1 DATE-STRING/" \
 +              -e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 +              -e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 +              >actual-show-all-headers &&
 +      test_cmp expected-show-all-headers actual-show-all-headers
 +'
 +
+ test_expect_success '--compose adds MIME for utf8 body' '
+       clean_fake_sendmail &&
+       (echo "#!/bin/sh" &&
 -        GIT_EDITOR=$(pwd)/fake-editor-utf8 \
++       echo "echo utf8 body: àéìöú >>\"\$1\""
+       ) >fake-editor-utf8 &&
+       chmod +x fake-editor-utf8 &&
+       echo y | \
 -       echo " echo utf8 body: àéìöú) >\$1"
++        GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+         GIT_SEND_EMAIL_NOTTY=1 \
+         git send-email \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=utf-8" msgtxt1
+ '
+ test_expect_success '--compose respects user mime type' '
+       clean_fake_sendmail &&
+       (echo "#!/bin/sh" &&
+        echo "(echo MIME-Version: 1.0"
+        echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
+        echo " echo Content-Transfer-Encoding: 8bit"
+        echo " echo Subject: foo"
+        echo " echo "
 -        GIT_EDITOR=$(pwd)/fake-editor-utf8-mime \
++       echo " echo utf8 body: àéìöú) >\"\$1\""
+       ) >fake-editor-utf8-mime &&
+       chmod +x fake-editor-utf8-mime &&
+       echo y | \
 -        GIT_EDITOR=$(pwd)/fake-editor \
++        GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
+         GIT_SEND_EMAIL_NOTTY=1 \
+         git send-email \
+         --compose --subject foo \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^utf8 body" msgtxt1 &&
+       grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
+       ! grep "^Content-Type: text/plain; charset=utf-8" msgtxt1
+ '
+ test_expect_success '--compose adds MIME for utf8 subject' '
+       clean_fake_sendmail &&
+       echo y | \
++        GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+         GIT_SEND_EMAIL_NOTTY=1 \
+         git send-email \
+         --compose --subject utf8-sübjëct \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         $patches &&
+       grep "^fake edit" msgtxt1 &&
+       grep "^Subject: =?utf-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
+ '
  test_done