Skip to content

Commit

Permalink
Merge branch 'js/maint-send-email' into maint
Browse files Browse the repository at this point in the history
* js/maint-send-email:
  send-email: don't create temporary compose file until it is needed
  send-email: --suppress-cc improvements
  send-email: handle multiple Cc addresses when reading mbox message
  send-email: allow send-email to run outside a repo
  • Loading branch information
Junio C Hamano committed Mar 11, 2009
2 parents ecab04d + afe756c commit 7681ed2
Show file tree
Hide file tree
Showing 3 changed files with 305 additions and 112 deletions.
27 changes: 19 additions & 8 deletions Documentation/git-send-email.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,14 +177,25 @@ Automating

--suppress-cc::
Specify an additional category of recipients to suppress the
auto-cc of. 'self' will avoid including the sender, 'author' will
avoid including the patch author, 'cc' will avoid including anyone
mentioned in Cc lines in the patch, 'sob' will avoid including
anyone mentioned in Signed-off-by lines, and 'cccmd' will avoid
running the --cc-cmd. 'all' will suppress all auto cc values.
Default is the value of 'sendemail.suppresscc' configuration value;
if that is unspecified, default to 'self' if --suppress-from is
specified, as well as 'sob' if --no-signed-off-cc is specified.
auto-cc of:
+
--
- 'author' will avoid including the patch author
- 'self' will avoid including the sender
- 'cc' will avoid including anyone mentioned in Cc lines in the patch header
except for self (use 'self' for that).
- 'ccbody' will avoid including anyone mentioned in Cc lines in the
patch body (commit message) except for self (use 'self' for that).
- 'sob' will avoid including anyone mentioned in Signed-off-by lines except
for self (use 'self' for that).
- 'cccmd' will avoid running the --cc-cmd.
- 'body' is equivalent to 'sob' + 'ccbody'
- 'all' will suppress all auto cc values.
--
+
Default is the value of 'sendemail.suppresscc' configuration value; if
that is unspecified, default to 'self' if --suppress-from is
specified, as well as 'body' if --no-signed-off-cc is specified.

--[no-]suppress-from::
If this is set, do not add the From: address to the cc: list.
Expand Down
198 changes: 119 additions & 79 deletions git-send-email.perl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use Text::ParseWords;
use Data::Dumper;
use Term::ANSIColor;
use File::Temp qw/ tempdir /;
use File::Temp qw/ tempdir tempfile /;
use Error qw(:try);
use Git;

Expand Down Expand Up @@ -68,9 +68,8 @@ sub usage {
Automating:
--identity <str> * Use the sendemail.<id> options.
--cc-cmd <str> * Email Cc: via `<str> \$patch_path`
--suppress-cc <str> * author, self, sob, cccmd, all.
--[no-]signed-off-by-cc * Send to Cc: and Signed-off-by:
addresses. Default on.
--suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, all.
--[no-]signed-off-by-cc * Send to Signed-off-by: addresses. Default on.
--[no-]suppress-from * Send to self. Default off.
--[no-]chain-reply-to * Chain In-Reply-To: fields. Default on.
--[no-]thread * Use In-Reply-To: field. Default on.
Expand Down Expand Up @@ -126,6 +125,7 @@ sub format_2822_time {
}

my $have_email_valid = eval { require Email::Valid; 1 };
my $have_mail_address = eval { require Mail::Address; 1 };
my $smtp;
my $auth;

Expand Down Expand Up @@ -156,7 +156,7 @@ sub format_2822_time {
# Behavior modification variables
my ($quiet, $dry_run) = (0, 0);
my $format_patch;
my $compose_filename = $repo->repo_path() . "/.gitsendemail.msg.$$";
my $compose_filename;

# Handle interactive edition of files.
my $multiedit;
Expand Down Expand Up @@ -219,11 +219,13 @@ sub signal_handler {
system "stty echo";

# tmp files from --compose
if (-e $compose_filename) {
print "'$compose_filename' contains an intermediate version of the email you were composing.\n";
}
if (-e ($compose_filename . ".final")) {
print "'$compose_filename.final' contains the composed email.\n"
if (defined $compose_filename) {
if (-e $compose_filename) {
print "'$compose_filename' contains an intermediate version of the email you were composing.\n";
}
if (-e ($compose_filename . ".final")) {
print "'$compose_filename.final' contains the composed email.\n"
}
}

exit;
Expand Down Expand Up @@ -267,6 +269,9 @@ sub signal_handler {
usage();
}

die "Cannot run git format-patch from outside a repository\n"
if $format_patch and not $repo;

# Now, let's fill any that aren't set in with defaults:

sub read_config {
Expand Down Expand Up @@ -318,13 +323,13 @@ sub read_config {
if (@suppress_cc) {
foreach my $entry (@suppress_cc) {
die "Unknown --suppress-cc field: '$entry'\n"
unless $entry =~ /^(all|cccmd|cc|author|self|sob)$/;
unless $entry =~ /^(all|cccmd|cc|author|self|sob|body|bodycc)$/;
$suppress_cc{$entry} = 1;
}
}

if ($suppress_cc{'all'}) {
foreach my $entry (qw (ccmd cc author self sob)) {
foreach my $entry (qw (ccmd cc author self sob body bodycc)) {
$suppress_cc{$entry} = 1;
}
delete $suppress_cc{'all'};
Expand All @@ -334,6 +339,13 @@ sub read_config {
$suppress_cc{'self'} = $suppress_from if defined $suppress_from;
$suppress_cc{'sob'} = !$signed_off_by_cc if defined $signed_off_by_cc;

if ($suppress_cc{'body'}) {
foreach my $entry (qw (sob bodycc)) {
$suppress_cc{$entry} = 1;
}
delete $suppress_cc{'body'};
}

# Debugging, print out the suppressions.
if (0) {
print "suppressions:\n";
Expand All @@ -360,6 +372,14 @@ sub read_config {
die "Comma in --bcclist entry: $entry'\n" unless $entry !~ m/,/;
}

sub parse_address_line {
if ($have_mail_address) {
return map { $_->format } Mail::Address->parse($_[0]);
} else {
return split_addrs($_[0]);
}
}

sub split_addrs {
return quotewords('\s*,\s*', 1, @_);
}
Expand Down Expand Up @@ -404,6 +424,7 @@ sub split_addrs {

# returns 1 if the conflict must be solved using it as a format-patch argument
sub check_file_rev_conflict($) {
return unless $repo;
my $f = shift;
try {
$repo->command('rev-parse', '--verify', '--quiet', $f);
Expand Down Expand Up @@ -445,6 +466,8 @@ ($)
}

if (@rev_list_opts) {
die "Cannot run git format-patch from outside a repository\n"
unless $repo;
push @files, $repo->command('format-patch', '-o', tempdir(CLEANUP => 1), @rev_list_opts);
}

Expand Down Expand Up @@ -481,6 +504,9 @@ ($)
if ($compose) {
# Note that this does not need to be secure, but we will make a small
# effort to have it be unique
$compose_filename = ($repo ?
tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
open(C,">",$compose_filename)
or die "Failed to open for writing $compose_filename: $!";

Expand Down Expand Up @@ -593,7 +619,7 @@ ($)
}

my $to = $_;
push @to, split_addrs($to);
push @to, parse_address_line($to);
$prompting++;
}

Expand Down Expand Up @@ -920,88 +946,102 @@ sub send_message
@cc = @initial_cc;
@xh = ();
my $input_format = undef;
my $header_done = 0;
my @header = ();
$message = "";
# First unfold multiline header fields
while(<F>) {
if (!$header_done) {
if (/^From /) {
$input_format = 'mbox';
next;
last if /^\s*$/;
if (/^\s+\S/ and @header) {
chomp($header[$#header]);
s/^\s+/ /;
$header[$#header] .= $_;
} else {
push(@header, $_);
}
}
# Now parse the header
foreach(@header) {
if (/^From /) {
$input_format = 'mbox';
next;
}
chomp;
if (!defined $input_format && /^[-A-Za-z]+:\s/) {
$input_format = 'mbox';
}

if (defined $input_format && $input_format eq 'mbox') {
if (/^Subject:\s+(.*)$/) {
$subject = $1;
}
chomp;
if (!defined $input_format && /^[-A-Za-z]+:\s/) {
$input_format = 'mbox';
elsif (/^From:\s+(.*)$/) {
($author, $author_encoding) = unquote_rfc2047($1);
next if $suppress_cc{'author'};
next if $suppress_cc{'self'} and $author eq $sender;
printf("(mbox) Adding cc: %s from line '%s'\n",
$1, $_) unless $quiet;
push @cc, $1;
}

if (defined $input_format && $input_format eq 'mbox') {
if (/^Subject:\s+(.*)$/) {
$subject = $1;

} elsif (/^(Cc|From):\s+(.*)$/) {
if (unquote_rfc2047($2) eq $sender) {
elsif (/^Cc:\s+(.*)$/) {
foreach my $addr (parse_address_line($1)) {
if (unquote_rfc2047($addr) eq $sender) {
next if ($suppress_cc{'self'});
}
elsif ($1 eq 'From') {
($author, $author_encoding)
= unquote_rfc2047($2);
next if ($suppress_cc{'author'});
} else {
next if ($suppress_cc{'cc'});
}
printf("(mbox) Adding cc: %s from line '%s'\n",
$2, $_) unless $quiet;
push @cc, $2;
}
elsif (/^Content-type:/i) {
$has_content_type = 1;
if (/charset="?([^ "]+)/) {
$body_encoding = $1;
}
push @xh, $_;
}
elsif (/^Message-Id: (.*)/i) {
$message_id = $1;
$addr, $_) unless $quiet;
push @cc, $addr;
}
elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_;
}

} else {
# In the traditional
# "send lots of email" format,
# line 1 = cc
# line 2 = subject
# So let's support that, too.
$input_format = 'lots';
if (@cc == 0 && !$suppress_cc{'cc'}) {
printf("(non-mbox) Adding cc: %s from line '%s'\n",
$_, $_) unless $quiet;

push @cc, $_;

} elsif (!defined $subject) {
$subject = $_;
}
elsif (/^Content-type:/i) {
$has_content_type = 1;
if (/charset="?([^ "]+)/) {
$body_encoding = $1;
}
push @xh, $_;
}

# A whitespace line will terminate the headers
if (m/^\s*$/) {
$header_done = 1;
elsif (/^Message-Id: (.*)/i) {
$message_id = $1;
}
elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
push @xh, $_;
}

} else {
$message .= $_;
if (/^(Signed-off-by|Cc): (.*)$/i) {
next if ($suppress_cc{'sob'});
chomp;
my $c = $2;
chomp $c;
next if ($c eq $sender and $suppress_cc{'self'});
push @cc, $c;
printf("(sob) Adding cc: %s from line '%s'\n",
$c, $_) unless $quiet;
# In the traditional
# "send lots of email" format,
# line 1 = cc
# line 2 = subject
# So let's support that, too.
$input_format = 'lots';
if (@cc == 0 && !$suppress_cc{'cc'}) {
printf("(non-mbox) Adding cc: %s from line '%s'\n",
$_, $_) unless $quiet;
push @cc, $_;
} elsif (!defined $subject) {
$subject = $_;
}
}
}
# Now parse the message body
while(<F>) {
$message .= $_;
if (/^(Signed-off-by|Cc): (.*)$/i) {
chomp;
my ($what, $c) = ($1, $2);
chomp $c;
if ($c eq $sender) {
next if ($suppress_cc{'self'});
} else {
next if $suppress_cc{'sob'} and $what =~ /Signed-off-by/i;
next if $suppress_cc{'bodycc'} and $what =~ /Cc/i;
}
push @cc, $c;
printf("(body) Adding cc: %s from line '%s'\n",
$c, $_) unless $quiet;
}
}
close F;

if (defined $cc_cmd && !$suppress_cc{'cccmd'}) {
Expand All @@ -1020,7 +1060,7 @@ sub send_message
or die "(cc-cmd) failed to close pipe to '$cc_cmd'";
}

if (defined $author) {
if (defined $author and $author ne $sender) {
$message = "From: $author\n\n$message";
if (defined $author_encoding) {
if ($has_content_type) {
Expand Down
Loading

0 comments on commit 7681ed2

Please sign in to comment.