parse_mailboxes: accept extra text after <...> address

The test introduced in this commit succeeds without the patch to Git.pm if Mail::Address is installed, but fails otherwise because our in-house parser does not accept any text after the email address. They succeed both with and without Mail::Address after this commit. Mail::Address accepts extra text and considers it as part of the name, iff the address is surrounded with <...>. The implementation mimics this behavior as closely as possible. This mostly restores the behavior we had before b1c8a11 (send-email: allow multiple emails using --cc, --to and --bcc, 2015-06-30), but we keep the possibility to handle comma-separated lists. Reported-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthieu Moy committed Oct 13, 2016 at 07:47 UTC e3fdbcc8e16474f50749a384175f78908c4f038e
2 files changed +36 -6
perl/Git.pm
+7 -6
@@ -878,6 +878,7 @@ sub parse_mailboxes {
878 # divide the string in tokens of the above form
879 my $re_token = qr/(?:$re_quote|$re_word|$re_comment|\S)/;
880 my @tokens = map { $_ =~ /\s*($re_token)\s*/g } @_;
881 + my $end_of_addr_seen = 0;
882
883 # add a delimiter to simplify treatment for the last mailbox
884 push @tokens, ",";
@@ -887,10 +888,10 @@ sub parse_mailboxes {
888 if ($token =~ /^[,;]$/) {
889 # if buffer still contains undeterminated strings
890 # append it at the end of @address or @phrase
890 - if (@address) {
891 - push @address, @buffer;
892 - } else {
891 + if ($end_of_addr_seen) {
892 push @phrase, @buffer;
893 + } else {
894 + push @address, @buffer;
895 }
896
897 my $str_phrase = join ' ', @phrase;
@@ -914,16 +915,16 @@ sub parse_mailboxes {
915 push @addr_list, $str_mailbox if ($str_mailbox);
916
917 @phrase = @address = @comment = @buffer = ();
918 + $end_of_addr_seen = 0;
919 } elsif ($token =~ /^\(/) {
920 push @comment, $token;
921 } elsif ($token eq "<") {
922 push @phrase, (splice @address), (splice @buffer);
923 } elsif ($token eq ">") {
924 + $end_of_addr_seen = 1;
925 push @address, (splice @buffer);
923 - } elsif ($token eq "@") {
926 + } elsif ($token eq "@" && !$end_of_addr_seen) {
927 push @address, (splice @buffer), "@";
925 - } elsif ($token eq ".") {
926 - push @address, (splice @buffer), ".";
928 } else {
929 push @buffer, $token;
930 }
t/t9001-send-email.sh
+29
@@ -140,6 +140,35 @@ test_expect_success $PREREQ 'Verify commandline' '
140 test_cmp expected commandline1
141 '
142
143 +test_expect_success $PREREQ 'setup expect for cc trailer' "
144 +cat >expected-cc <<\EOF
145 +!recipient@example.com!
146 +!author@example.com!
147 +!one@example.com!
148 +!two@example.com!
149 +!three@example.com!
150 +!four@example.com!
151 +!five@example.com!
152 +EOF
153 +"
154 +
155 +test_expect_success $PREREQ 'cc trailer with various syntax' '
156 + test_commit cc-trailer &&
157 + test_when_finished "git reset --hard HEAD^" &&
158 + git commit --amend -F - <<-EOF &&
159 + Test Cc: trailers.
160 +
161 + Cc: one@example.com
162 + Cc: <two@example.com> # this is part of the name
163 + Cc: <three@example.com>, <four@example.com> # not.five@example.com
164 + Cc: "Some # Body" <five@example.com> [part.of.name.too]
165 + EOF
166 + clean_fake_sendmail &&
167 + git send-email -1 --to=recipient@example.com \
168 + --smtp-server="$(pwd)/fake.sendmail" &&
169 + test_cmp expected-cc commandline1
170 +'
171 +
172 test_expect_success $PREREQ 'setup expect' "
173 cat >expected-show-all-headers <<\EOF
174 0001-Second.patch