{"thread":{"id":"39657","subject":"[PATCH/RFC v4 02/10] send-email: allow aliases in patch header and command script outputs","startedAt":"2015-06-17T14:18:31Z","lastAt":"2015-06-23T20:58:23Z","messageCount":50,"participants":["Remi Lespinet","Matthieu Moy","Junio C Hamano","Remi LESPINET"],"isPatch":true,"patchVersion":4,"patchTotal":10},"messages":[{"id":"264018","messageId":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":null,"subject":"[PATCH/RFC v4 01/10] t9001-send-email: move script creation in a setup test","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:31Z","receivedAt":"2015-06-17T14:18:31Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Move the creation of the scripts used in to-cmd and cc-cmd tests\nin a setup test to make them available for later tests.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n t/t9001-send-email.sh | 15 +++++++++------\n 1 file changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex a3663da..eef12e6 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -312,13 +312,19 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'\n \t)\n '\n \n+test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '\n+\twrite_script tocmd-sed <<-\\EOF &&\n+\tsed -n -e \"s/^tocmd--//p\" \"$1\"\n+\tEOF\n+\twrite_script cccmd-sed <<-\\EOF\n+\tsed -n -e \"s/^cccmd--//p\" \"$1\"\n+\tEOF\n+'\n+\n test_expect_success $PREREQ 'tocmd works' '\n \tclean_fake_sendmail &&\n \tcp $patches tocmd.patch &&\n \techo tocmd--tocmd@example.com >>tocmd.patch &&\n-\twrite_script tocmd-sed <<-\\EOF &&\n-\tsed -n -e \"s/^tocmd--//p\" \"$1\"\n-\tEOF\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to-cmd=./tocmd-sed \\\n@@ -332,9 +338,6 @@ test_expect_success $PREREQ 'cccmd works' '\n \tclean_fake_sendmail &&\n \tcp $patches cccmd.patch &&\n \techo \"cccmd--  cccmd@example.com\" >>cccmd.patch &&\n-\twrite_script cccmd-sed <<-\\EOF &&\n-\tsed -n -e \"s/^cccmd--//p\" \"$1\"\n-\tEOF\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-- \n1.9.1\n"},{"id":"264013","messageId":"1434550720-24130-2-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 02/10] send-email: allow aliases in patch header and command script outputs","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:32Z","receivedAt":"2015-06-17T14:18:32Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Interpret aliases in:\n\n  -  Header fields of patches generated by git format-patch\n     (using --to, --cc, --add-header for example) or\n     manually modified. Example of fields in header:\n\n      To: alias1\n      Cc: alias2\n      Cc: alias3\n\n  -  Outputs of command scripts specified by --cc-cmd and\n     --to-cmd. Example of script:\n\n      #!/bin/sh\n      echo alias1\n      echo alias2\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl   |  2 ++\n t/t9001-send-email.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 62 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 6bedf74..8bf38ee 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1560,7 +1560,9 @@ foreach my $t (@files) {\n \t\t($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));\n \t$needs_confirm = \"inform\" if ($needs_confirm && $confirm_unconfigured && @cc);\n \n+\t@to = expand_aliases(@to);\n \t@to = validate_address_list(sanitize_address_list(@to));\n+\t@cc = expand_aliases(@cc);\n \t@cc = validate_address_list(sanitize_address_list(@cc));\n \n \t@to = (@initial_to, @to);\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex eef12e6..f7d4132 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1579,6 +1579,66 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=sendmail' '\n \tgrep \"^!o@example\\.com!$\" commandline1\n '\n \n+test_expect_success $PREREQ 'alias support in To header' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 --to=sbd >aliased.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\taliased.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'alias support in Cc header' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 --cc=sbd >aliased.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\taliased.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'tocmd works with aliases' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 >tocmd.patch &&\n+\techo tocmd--sbd >>tocmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to-cmd=./tocmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\ttocmd.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'cccmd works with aliases' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 >cccmd.patch &&\n+\techo cccmd--sbd >>cccmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--cc-cmd=./cccmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\tcccmd.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n do_xmailer_test () {\n \texpected=$1 params=$2 &&\n \tgit format-patch -1 &&\n-- \n1.9.1\n"},{"id":"264016","messageId":"1434550720-24130-3-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 03/10] t9001-send-email: refactor header variable fields replacement","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:33Z","receivedAt":"2015-06-17T14:18:33Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Create a function which replaces Date, Message-Id and\nX-Mailer lines generated by git-send-email by a specific string:\n\nDate:.*$       -> Date: DATE-STRING\nMessage-Id:.*$ -> Message-Id: MESSAGE-ID-STRING\nX-Mailer:.*$   -> X-Mailer: X-MAILER-STRING\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n t/t9001-send-email.sh | 11 +++++++----\n 1 file changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex f7d4132..714fcae 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -522,6 +522,12 @@ Result: OK\n EOF\n \"\n \n+replace_variable_fields () {\n+\tsed\t-e \"s/^\\(Date:\\).*/\\1 DATE-STRING/\" \\\n+\t\t-e \"s/^\\(Message-Id:\\).*/\\1 MESSAGE-ID-STRING/\" \\\n+\t\t-e \"s/^\\(X-Mailer:\\).*/\\1 X-MAILER-STRING/\"\n+}\n+\n test_suppression () {\n \tgit send-email \\\n \t\t--dry-run \\\n@@ -529,10 +535,7 @@ test_suppression () {\n \t\t--from=\"Example <from@example.com>\" \\\n \t\t--to=to@example.com \\\n \t\t--smtp-server relay.example.com \\\n-\t\t$patches |\n-\tsed\t-e \"s/^\\(Date:\\).*/\\1 DATE-STRING/\" \\\n-\t\t-e \"s/^\\(Message-Id:\\).*/\\1 MESSAGE-ID-STRING/\" \\\n-\t\t-e \"s/^\\(X-Mailer:\\).*/\\1 X-MAILER-STRING/\" \\\n+\t\t$patches | replace_variable_fields \\\n \t\t>actual-suppress-$1${2+\"-$2\"} &&\n \ttest_cmp expected-suppress-$1${2+\"-$2\"} actual-suppress-$1${2+\"-$2\"}\n }\n-- \n1.9.1\n"},{"id":"264014","messageId":"1434550720-24130-4-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 04/10] send-email: refactor address list process","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:34Z","receivedAt":"2015-06-17T14:18:34Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Simplify code by creating a function which transform a list of strings\ncontaining email addresses (separated by commas, comporting aliases)\ninto a clean list of valid email addresses.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 22 ++++++++++++----------\n 1 file changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 8bf38ee..2d5c530 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -833,12 +833,9 @@ sub expand_one_alias {\n \treturn $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;\n }\n \n-@initial_to = expand_aliases(@initial_to);\n-@initial_to = validate_address_list(sanitize_address_list(@initial_to));\n-@initial_cc = expand_aliases(@initial_cc);\n-@initial_cc = validate_address_list(sanitize_address_list(@initial_cc));\n-@bcclist = expand_aliases(@bcclist);\n-@bcclist = validate_address_list(sanitize_address_list(@bcclist));\n+@initial_to = process_address_list(@initial_to);\n+@initial_cc = process_address_list(@initial_cc);\n+@bcclist = process_address_list(@bcclist);\n \n if ($thread && !defined $initial_reply_to && $prompting) {\n \t$initial_reply_to = ask(\n@@ -1051,6 +1048,13 @@ sub sanitize_address_list {\n \treturn (map { sanitize_address($_) } @_);\n }\n \n+sub process_address_list {\n+\tmy @addr_list = expand_aliases(@_);\n+\t@addr_list = sanitize_address_list(@addr_list);\n+\t@addr_list = validate_address_list(@addr_list);\n+\treturn @addr_list;\n+}\n+\n # Returns the local Fully Qualified Domain Name (FQDN) if available.\n #\n # Tightly configured MTAa require that a caller sends a real DNS\n@@ -1560,10 +1564,8 @@ foreach my $t (@files) {\n \t\t($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));\n \t$needs_confirm = \"inform\" if ($needs_confirm && $confirm_unconfigured && @cc);\n \n-\t@to = expand_aliases(@to);\n-\t@to = validate_address_list(sanitize_address_list(@to));\n-\t@cc = expand_aliases(@cc);\n-\t@cc = validate_address_list(sanitize_address_list(@cc));\n+\t@to = process_address_list(@to);\n+\t@cc = process_address_list(@cc);\n \n \t@to = (@initial_to, @to);\n \t@cc = (@initial_cc, @cc);\n-- \n1.9.1\n"},{"id":"264017","messageId":"1434550720-24130-5-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 05/10] send-email: Allow use of aliases in the From field of --compose mode","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:35Z","receivedAt":"2015-06-17T14:18:35Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Aliases were expanded before checking the From field of the\n--compose option. This is inconsistent with other fields\n(To, Cc, ...) which already support aliases.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 2d5c530..f61449d 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -555,8 +555,6 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {\n \t}\n }\n \n-($sender) = expand_aliases($sender) if defined $sender;\n-\n # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if\n # $f is a revision list specification to be passed to format-patch.\n sub is_format_patch_arg {\n@@ -801,6 +799,8 @@ if (!$force) {\n \t}\n }\n \n+($sender) = expand_aliases($sender) if defined $sender;\n+\n if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n }\n-- \n1.9.1\n"},{"id":"264015","messageId":"1434550720-24130-6-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 06/10] send-email: minor code refactoring","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:36Z","receivedAt":"2015-06-17T14:18:36Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Group expressions in a single if statement. This avoid checking\nmultiple time if the variable $sender is defined.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex f61449d..a0cd7ff 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -799,9 +799,9 @@ if (!$force) {\n \t}\n }\n \n-($sender) = expand_aliases($sender) if defined $sender;\n-\n-if (!defined $sender) {\n+if (defined $sender) {\n+\t($sender) = expand_aliases($sender);\n+} else {\n \t$sender = $repoauthor || $repocommitter || '';\n }\n \n-- \n1.9.1\n"},{"id":"264019","messageId":"1434550720-24130-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:18:37Z","receivedAt":"2015-06-17T14:18:37Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"parse_address_line had not the same behavior whether the user had\nMail::Address or not. Teach parse_address_line to behave like\nMail::Address.\n\nWhen the user input is correct, this implementation behaves\nexactly like Mail::Address except when there are quotes\ninside the name:\n\n  \"Jane Do\"e <jdoe@example.com>\n\nIn this case the result of parse_address_line is:\n\n  With M::A : \"Jane Do\" e <jdoe@example.com>\n  Without   : \"Jane Do e\" <jdoe@example.com>\n\nWhen the user input is not correct, the behavior is also mostly\nthe same.\n\nUnlike Mail::Address, this doesn't parse groups and recursive\ncommentaries.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 52 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex a0cd7ff..a1f6c18 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -477,9 +477,59 @@ foreach my $entry (@bcclist) {\n sub parse_address_line {\n \tif ($have_mail_address) {\n \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n-\t} else {\n-\t\treturn split_addrs($_[0]);\n \t}\n+\n+\tmy $commentrgx=qr/\\((?:[^)]*)\\)/;\n+\tmy $quotergx=qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n+\tmy $wordrgx=qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n+\tmy $tokenrgx = qr/(?:$quotergx|$wordrgx|$commentrgx|\\S)/;\n+\n+\tmy @tokens = map { $_ =~ /\\s*($tokenrgx)\\s*/g } @_;\n+\tpush @tokens, \",\";\n+\n+\tmy (@addr_list, @phrase, @address, @comment, @buffer) = ();\n+\tforeach my $token (@tokens) {\n+\t    if ($token =~ /^[,;]$/) {\n+\t\tif (@address) {\n+\t\t    push @address, @buffer;\n+\t\t} else {\n+\t\t    push @phrase, @buffer;\n+\t\t}\n+\n+\t\tmy $str_phrase = join ' ', @phrase;\n+\t\tmy $str_address = join '', @address;\n+\t\tmy $str_comment = join ' ', @comment;\n+\n+\t\tif ($str_phrase =~ /[][()<>:;@\\\\,.\\000-\\037\\177]/) {\n+\t\t    $str_phrase =~ s/(^|[^\\\\])\"/$1/g;\n+\t\t    $str_phrase = qq[\"$str_phrase\"];\n+\t\t}\n+\n+\t\tif ($str_address ne \"\" && $str_phrase ne \"\") {\n+\t\t    $str_address = qq[<$str_address>];\n+\t\t}\n+\n+\t\tmy $str_mailbox = \"$str_phrase $str_address $str_comment\";\n+\t\t$str_mailbox =~ s/^\\s*|\\s*$//g;\n+\t\tpush @addr_list, $str_mailbox if ($str_mailbox);\n+\n+\t\t@phrase = @address = @comment = @buffer = ();\n+\t    } elsif ($token =~ /^\\(/) {\n+\t\tpush @comment, $token;\n+\t    } elsif ($token eq \"<\") {\n+\t\tpush @phrase, (splice @address), (splice @buffer);\n+\t    } elsif ($token eq \">\") {\n+\t\tpush @address, (splice @buffer);\n+\t    } elsif ($token eq \"@\") {\n+\t\tpush @address, (splice @buffer), \"@\";\n+\t    } elsif ($token eq \".\") {\n+\t\tpush @address, (splice @buffer), \".\";\n+\t    } else {\n+\t\tpush @buffer, $token;\n+\t    }\n+\t}\n+\n+\treturn @addr_list;\n }\n \n sub split_addrs {\n-- \n1.9.1\n"},{"id":"264021","messageId":"1434551433-24614-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 08/10] send-email: consider quote as delimiter instead of character","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:30:33Z","receivedAt":"2015-06-17T14:30:33Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Do not consider quote inside a recipient name as character when\nthey are not escaped. This interprets:\n\n  \"Jane\" \"Doe\" <jdoe@example.com>\n\nas:\n\n  \"Jane Doe\" <jdoe@example.com>\n\ninstead of:\n\n  \"Jane\\\" \\\"Doe\" <jdoe@example.com>\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n\nI don't know if it's an argument for this change, but rfc2822 says:\n\n   Semantically, neither the optional CFWS outside of the quote\n   characters nor the quote characters themselves are part of the\n   quoted-string...\n\n git-send-email.perl | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex a1f6c18..8594ab9 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1078,15 +1078,17 @@ sub sanitize_address {\n \t\treturn $recipient;\n \t}\n \n+\t# remove non-escaped quotes\n+\t$recipient_name =~ s/(^|[^\\\\])\"/$1/g;\n+\n \t# rfc2047 is needed if a non-ascii char is included\n \tif ($recipient_name =~ /[^[:ascii:]]/) {\n-\t\t$recipient_name =~ s/^\"(.*)\"$/$1/;\n \t\t$recipient_name = quote_rfc2047($recipient_name);\n \t}\n \n \t# double quotes are needed if specials or CTLs are included\n \telsif ($recipient_name =~ /[][()<>@,;:\\\\\".\\000-\\037\\177]/) {\n-\t\t$recipient_name =~ s/([\"\\\\\\r])/\\\\$1/g;\n+\t\t$recipient_name =~ s/([\\\\\\r])/\\\\$1/g;\n \t\t$recipient_name = qq[\"$recipient_name\"];\n \t}\n \n-- \n1.9.1\n"},{"id":"264022","messageId":"1434551467-24668-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 09/10] send-email: allow multiple emails using --cc, --to and --bcc","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:31:07Z","receivedAt":"2015-06-17T14:31:07Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Accept a list of emails separated by commas in flags --cc, --to and\n--bcc.  Multiple addresses can already be given by using these options\nmultiple times, but it is more convenient to allow cutting-and-pasting\na list of addresses from the header of an existing e-mail message,\nwhich already lists them as comma-separated list, as a value to a\nsingle parameter.\n\nThe following format can now be used:\n\n    $ git send-email --to='Jane <jdoe@example.com>, mike@example.com'\n\nRemove the limitation imposed by 79ee555b (Check and document the\noptions to prevent mistakes, 2006-06-21) which rejected every argument\nwith comma in --cc, --to and --bcc.\n\nHelped-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\nSigned-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>\nSigned-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>\nSigned-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n Documentation/git-send-email.txt | 12 +++++------\n git-send-email.perl              | 17 ++--------------\n t/t9001-send-email.sh            | 44 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 52 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b48a764..afd9569 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -49,17 +49,17 @@ Composing\n \tof 'sendemail.annotate'. See the CONFIGURATION section for\n \t'sendemail.multiEdit'.\n \n---bcc=<address>::\n+--bcc=<address>,...::\n \tSpecify a \"Bcc:\" value for each email. Default is the value of\n \t'sendemail.bcc'.\n +\n-The --bcc option must be repeated for each user you want on the bcc list.\n+This option may be specified multiple times.\n \n---cc=<address>::\n+--cc=<address>,...::\n \tSpecify a starting \"Cc:\" value for each email.\n \tDefault is the value of 'sendemail.cc'.\n +\n-The --cc option must be repeated for each user you want on the cc list.\n+This option may be specified multiple times.\n \n --compose::\n \tInvoke a text editor (see GIT_EDITOR in linkgit:git-var[1])\n@@ -110,13 +110,13 @@ is not set, this will be prompted for.\n \tOnly necessary if --compose is also set.  If --compose\n \tis not set, this will be prompted for.\n \n---to=<address>::\n+--to=<address>,...::\n \tSpecify the primary recipient of the emails generated. Generally, this\n \twill be the upstream maintainer of the project involved. Default is the\n \tvalue of the 'sendemail.to' configuration value; if that is unspecified,\n \tand --to-cmd is not specified, this will be prompted for.\n +\n-The --to option must be repeated for each user you want on the to list.\n+This option may be specified multiple times.\n \n --8bit-encoding=<encoding>::\n \tWhen encountering a non-ASCII message or subject that does not\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 8594ab9..265299e 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -460,20 +460,6 @@ my ($repoauthor, $repocommitter);\n ($repoauthor) = Git::ident_person(@repo, 'author');\n ($repocommitter) = Git::ident_person(@repo, 'committer');\n \n-# Verify the user input\n-\n-foreach my $entry (@initial_to) {\n-\tdie \"Comma in --to entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n-foreach my $entry (@initial_cc) {\n-\tdie \"Comma in --cc entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n-foreach my $entry (@bcclist) {\n-\tdie \"Comma in --bcclist entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n sub parse_address_line {\n \tif ($have_mail_address) {\n \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n@@ -1101,7 +1087,8 @@ sub sanitize_address_list {\n }\n \n sub process_address_list {\n-\tmy @addr_list = expand_aliases(@_);\n+\tmy @addr_list = map { parse_address_line($_) } @_;\n+\t@addr_list = expand_aliases(@addr_list);\n \t@addr_list = sanitize_address_list(@addr_list);\n \t@addr_list = validate_address_list(@addr_list);\n \treturn @addr_list;\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 714fcae..3c5b853 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1675,4 +1675,48 @@ test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '\n \tdo_xmailer_test 1 \"--xmailer\"\n '\n \n+test_expect_success $PREREQ 'setup expected-list' '\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>\" \\\n+\t--to=\"to2@example.com\" \\\n+\t--to=\"to3@example.com\" \\\n+\t--cc=\"Cc 1 <cc1@example.com>\" \\\n+\t--cc=\"Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com\" \\\n+\t--bcc=\"bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>expected-list\n+'\n+\n+test_expect_success $PREREQ 'use email list in --cc --to and --bcc' '\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>, to2@example.com\" \\\n+\t--to=\"to3@example.com\" \\\n+\t--cc=\"Cc 1 <cc1@example.com>, Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com, bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n+test_expect_success $PREREQ 'aliases work with email list' '\n+\techo \"alias to2 to2@example.com\" >.mutt &&\n+\techo \"alias cc1 Cc 1 <cc1@example.com>\" >>.mutt &&\n+\ttest_config sendemail.aliasesfile \".mutt\" &&\n+\ttest_config sendemail.aliasfiletype mutt &&\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>, to2, to3@example.com\" \\\n+\t--cc=\"cc1, Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com, bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n test_done\n-- \n1.9.1\n"},{"id":"264023","messageId":"1434551525-24709-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH/RFC v4 10/10] send-email: suppress meaningless whitespaces in from field","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T14:32:05Z","receivedAt":"2015-06-17T14:32:05Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Remove leading and trailing whitespaces in from field before\ninterepreting it to improve consistency with other options.  The\nsplit_addrs function already take care of trailing and leading\nwhitespaces for to, cc and bcc fields.\nThe from option now:\n\n - has the same behavior when passing arguments like\n   \"  jdoe@example.com \", \"\\t jdoe@example.com \" or\n   \"jdoe@example.com\".\n\n - interprets aliases in string containing leading and trailing\n   whitespaces such as \" alias\" or \"alias\\t\" like other options.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl   |  1 +\n t/t9001-send-email.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 265299e..9b28dfa 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -836,6 +836,7 @@ if (!$force) {\n }\n \n if (defined $sender) {\n+\t$sender =~ s/^\\s+|\\s$//g;\n \t($sender) = expand_aliases($sender);\n } else {\n \t$sender = $repoauthor || $repocommitter || '';\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 3c5b853..8e21fb0 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1719,4 +1719,28 @@ test_expect_success $PREREQ 'aliases work with email list' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n+\techo \"alias to2 to2@example.com\" >.mutt &&\n+\techo \"alias cc1 Cc 1 <cc1@example.com>\" >>.mutt &&\n+\ttest_config sendemail.aliasesfile \".mutt\" &&\n+\ttest_config sendemail.aliasfiletype mutt &&\n+\tTO1=$(echo \"QTo 1 <to1@example.com>\" | q_to_tab) &&\n+\tTO2=$(echo \"QZto2\" | qz_to_tab_space) &&\n+\tCC1=$(echo \"cc1\" | append_cr) &&\n+\tBCC1=$(echo \"Q bcc1@example.com Q\" | q_to_nul) &&\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"\tExample <from@example.com>\" \\\n+\t--to=\"$TO1\" \\\n+\t--to=\"$TO2\" \\\n+\t--to=\"  to3@example.com   \" \\\n+\t--cc=\"$CC1\" \\\n+\t--cc=\"Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"$BCC1\" \\\n+\t--bcc=\"bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n test_done\n-- \n1.9.1\n"},{"id":"264026","messageId":"vpqr3pal71v.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1434551525-24709-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 10/10] send-email: suppress meaningless whitespaces in from field","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-17T14:54:04Z","receivedAt":"2015-06-17T14:54:04Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n>  if (defined $sender) {\n> +\t$sender =~ s/^\\s+|\\s$//g;\n\nI would say \\s+ also for the second \\s. Not really different, but it\nfeels wrong to iterate the substitution as many times as there are\ntrailing spaces to remove.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264028","messageId":"1753377376.582128.1434553916066.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"vpqr3pal71v.fsf@anie.imag.fr","subject":"[PATCH/RFC v4 10/10] send-email: suppress meaningless whitespaces in from field","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T15:11:56Z","receivedAt":"2015-06-17T15:11:56Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes\n\n> Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes: \n\n> > if (defined $sender) { \n> > + $sender =~ s/^\\s+|\\s$//g; \n\n> I would say \\s+ also for the second \\s. Not really different, but it \n> feels wrong to iterate the substitution as many times as there are \n> trailing spaces to remove. \n\nOops should have read it one more time... Thanks.\n"},{"id":"264033","messageId":"vpqoakejq38.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1434550720-24130-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-17T15:45:47Z","receivedAt":"2015-06-17T15:45:47Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> ---\n>  git-send-email.perl | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--\n>  1 file changed, 52 insertions(+), 2 deletions(-)\n>\n> diff --git a/git-send-email.perl b/git-send-email.perl\n> index a0cd7ff..a1f6c18 100755\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> @@ -477,9 +477,59 @@ foreach my $entry (@bcclist) {\n>  sub parse_address_line {\n>  \tif ($have_mail_address) {\n>  \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n> -\t} else {\n> -\t\treturn split_addrs($_[0]);\n>  \t}\n> +\n> +\tmy $commentrgx=qr/\\((?:[^)]*)\\)/;\n> +\tmy $quotergx=qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n> +\tmy $wordrgx=qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n\nSpaces around = please.\n\nThe code below is a bit hard to read (I'm neither fluent in Perl nor in\nthe RFC ...). A few more comments would help. A few examples below (it's\nup to you to integrate them or not).\n\n> +\tmy $tokenrgx = qr/(?:$quotergx|$wordrgx|$commentrgx|\\S)/;\n> +\n> +\tmy @tokens = map { $_ =~ /\\s*($tokenrgx)\\s*/g } @_;\n> +\tpush @tokens, \",\";\n\n\n        # parse a full address like\n        # \"Phrase\" (comment) <address@example.com>\n\n(to clarify the wording)\n\n> +\tmy (@addr_list, @phrase, @address, @comment, @buffer) = ();\n> +\tforeach my $token (@tokens) {\n> +\t    if ($token =~ /^[,;]$/) {\n\nHere and below: you're indenting with a 4-column offset, it should be 8.\n\n> +\t\tif (@address) {\n> +\t\t    push @address, @buffer;\n> +\t\t} else {\n> +\t\t    push @phrase, @buffer;\n> +\t\t}\n> +\n> +\t\tmy $str_phrase = join ' ', @phrase;\n> +\t\tmy $str_address = join '', @address;\n> +\t\tmy $str_comment = join ' ', @comment;\n\n                # Escape special-characters with backslash\n> +\t\tif ($str_phrase =~ /[][()<>:;@\\\\,.\\000-\\037\\177]/) {\n> +\t\t    $str_phrase =~ s/(^|[^\\\\])\"/$1/g;\n> +\t\t    $str_phrase = qq[\"$str_phrase\"];\n> +\t\t}\n> +\n> +\t\tif ($str_address ne \"\" && $str_phrase ne \"\") {\n> +\t\t    $str_address = qq[<$str_address>];\n> +\t\t}\n> +\n> +\t\tmy $str_mailbox = \"$str_phrase $str_address $str_comment\";\n> +\t\t$str_mailbox =~ s/^\\s*|\\s*$//g;\n> +\t\tpush @addr_list, $str_mailbox if ($str_mailbox);\n> +\n> +\t\t@phrase = @address = @comment = @buffer = ();\n> +\t    } elsif ($token =~ /^\\(/) {\n> +\t\tpush @comment, $token;\n> +\t    } elsif ($token eq \"<\") {\n> +\t\tpush @phrase, (splice @address), (splice @buffer);\n> +\t    } elsif ($token eq \">\") {\n> +\t\tpush @address, (splice @buffer);\n> +\t    } elsif ($token eq \"@\") {\n> +\t\tpush @address, (splice @buffer), \"@\";\n> +\t    } elsif ($token eq \".\") {\n> +\t\tpush @address, (splice @buffer), \".\";\n> +\t    } else {\n\n                # We don't know what the token belongs to yet. We'll\n                # decide where to append @buffer later.\n> +\t\tpush @buffer, $token;\n> +\t    }\n> +\t}\n> +\n> +\treturn @addr_list;\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264034","messageId":"vpqh9q6jpk3.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1434550720-24130-5-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 05/10] send-email: Allow use of aliases in the From field of --compose mode","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-17T15:57:16Z","receivedAt":"2015-06-17T15:57:16Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> Aliases were expanded before checking the From field of the\n\n\"checking\" is misleading here. I thought you meant \"check that the From\nfield is well-formed\", while you mean \"set $sender based on the From:\nfield\".\n\n> --compose option. This is inconsistent with other fields\n> (To, Cc, ...) which already support aliases.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264090","messageId":"xmqqioam58kz.fsf@gitster.dls.corp.google.com","threadId":"39657","inReplyTo":"1434550720-24130-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-17T21:27:40Z","receivedAt":"2015-06-17T21:27:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> parse_address_line had not the same behavior whether the user had\n> Mail::Address or not. Teach parse_address_line to behave like\n> Mail::Address.\n\nSounds like a fun project ;-)\n\n> +\tmy $commentrgx=qr/\\((?:[^)]*)\\)/;\n> +\tmy $quotergx=qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n> +\tmy $wordrgx=qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n> +\tmy $tokenrgx = qr/(?:$quotergx|$wordrgx|$commentrgx|\\S)/;\n\nSuffix \"rgx\" that means \"regular expression\" is a bit unusual, and\nalso hard to read when squashed to another word.  Elsewhere in the\nsame script, we seem to use $re_whatever to store precompiled\nregular expressions, so perhaps $re_comment, $re_quote, etc.?\n\n> +\tmy @tokens = map { $_ =~ /\\s*($tokenrgx)\\s*/g } @_;\n> +\tpush @tokens, \",\";\n> +\n> +\tmy (@addr_list, @phrase, @address, @comment, @buffer) = ();\n> +\tforeach my $token (@tokens) {\n> +\t    if ($token =~ /^[,;]$/) {\n> +\t\tif (@address) {\n> +\t\t    push @address, @buffer;\n> +\t\t} else {\n> +\t\t    push @phrase, @buffer;\n> +\t\t}\n> +\n> +\t\tmy $str_phrase = join ' ', @phrase;\n> +\t\tmy $str_address = join '', @address;\n> +\t\tmy $str_comment = join ' ', @comment;\n> +\n> +\t\tif ($str_phrase =~ /[][()<>:;@\\\\,.\\000-\\037\\177]/) {\n> +\t\t    $str_phrase =~ s/(^|[^\\\\])\"/$1/g;\n> +\t\t    $str_phrase = qq[\"$str_phrase\"];\n> +\t\t}\n> +\n> +\t\tif ($str_address ne \"\" && $str_phrase ne \"\") {\n> +\t\t    $str_address = qq[<$str_address>];\n> +\t\t}\n\nWe see both \"git@vger.kernel.org\" and \"<git@vger.kernel.org>\" around\nhere for an address without comment or phrase; this chooses to turn\nthem both into \"<git@vger.kernel.org>\" form?  Not a complaint but am\nthinking aloud to see if I am reading it correctly.\n\n> +\n> +\t\tmy $str_mailbox = \"$str_phrase $str_address $str_comment\";\n> +\t\t$str_mailbox =~ s/^\\s*|\\s*$//g;\n\nSo an empty @comment will not leave spaces after $str_address, which\nmakes sense (likewise for @phrase).\n\n> +\t\tpush @addr_list, $str_mailbox if ($str_mailbox);\n> +\n> +\t\t@phrase = @address = @comment = @buffer = ();\n> +\t    } elsif ($token =~ /^\\(/) {\n> +\t\tpush @comment, $token;\n> +\t    } elsif ($token eq \"<\") {\n> +\t\tpush @phrase, (splice @address), (splice @buffer);\n\nThat is a clever use of splice (My Perl's rusty; you learn new\nthings every day) ;-)\n\n> +\t    } elsif ($token eq \">\") {\n> +\t\tpush @address, (splice @buffer);\n> +\t    } elsif ($token eq \"@\") {\n> +\t\tpush @address, (splice @buffer), \"@\";\n> +\t    } elsif ($token eq \".\") {\n> +\t\tpush @address, (splice @buffer), \".\";\n> +\t    } else {\n> +\t\tpush @buffer, $token;\n> +\t    }\n> +\t}\n> +\n> +\treturn @addr_list;\n>  }\n"},{"id":"264102","messageId":"52249185.592562.1434584380271.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"vpqoakejq38.fsf@anie.imag.fr","subject":"[PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T23:39:40Z","receivedAt":"2015-06-17T23:39:40Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes\n\n> > +\tmy $commentrgx=qr/\\((?:[^)]*)\\)/;\n> > +\tmy $quotergx=qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n> > +\tmy $wordrgx=qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n> \n> Spaces around = please.\n> ...\n> > +\tforeach my $token (@tokens) {\n> > +\t    if ($token =~ /^[,;]$/) {\n> \n> Here and below: you're indenting with a 4-column offset, it should be 8.\n\nShould have spent more time on the form... Thanks\n\n> The code below is a bit hard to read (I'm neither fluent in Perl nor in\n> the RFC ...). A few more comments would help. A few examples below (it's\n> up to you to integrate them or not).\n\nOk, I'll add comments for the hardest parts.\n"},{"id":"264103","messageId":"989982277.592587.1434584914349.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"xmqqioam58kz.fsf@gitster.dls.corp.google.com","subject":"[PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-17T23:48:34Z","receivedAt":"2015-06-17T23:48:34Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"> Junio C Hamano <gitster@pobox.com> writes\n> Suffix \"rgx\" that means \"regular expression\" is a bit unusual, and\n> also hard to read when squashed to another word.  Elsewhere in the\n> same script, we seem to use $re_whatever to store precompiled\n> regular expressions, so perhaps $re_comment, $re_quote, etc.?\n\nYes it's indeed a better name. I had not seen it, thanks!\n\n\n> > +                if ($str_address ne \"\" && $str_phrase ne \"\") {\n> > +                    $str_address = qq[<$str_address>];\n> > +                }\n> \n> We see both \"git@vger.kernel.org\" and \"<git@vger.kernel.org>\" around\n> here for an address without comment or phrase; this chooses to turn\n> them both into \"<git@vger.kernel.org>\" form?  Not a complaint but am\n> thinking aloud to see if I am reading it correctly.\n\nIf there's no phrase, this will choose the \"git@vger.kernel.org\" form,\nin both cases, because it'll be recognize as an address, $str_address\nwill be \"git@vger.kernel.org\" and $str_phrase will be empty before the\nif ($str_address ne \"\" ...)\nHere are some tests:\n\nInput: <jdoe@example.com>\nSplit: jdoe@example.com\nM::A : jdoe@example.com\n----------\nInput: jdoe@example.com\nSplit: jdoe@example.com\nM::A : jdoe@example.com\n----------\nInput: Jane <jdoe@example.com>\nSplit: Jane <jdoe@example.com>\nM::A : Jane <jdoe@example.com>\n----------\nInput: Jane Doe <jdoe@example.com>\nSplit: Jane Doe <jdoe@example.com>\nM::A : Jane Doe <jdoe@example.com>\n----------\nInput: \"Jane\" <jdoe@example.com>\nSplit: \"Jane\" <jdoe@example.com>\nM::A : \"Jane\" <jdoe@example.com>\n----------\nInput: \"Doe, Jane\" <jdoe@example.com>\nSplit: \"Doe, Jane\" <jdoe@example.com>\nM::A : \"Doe, Jane\" <jdoe@example.com>\n\nI've some more tests, maybe I should put them all in this post ?\n"},{"id":"264171","messageId":"vpqh9q56yaf.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"989982277.592587.1434584914349.JavaMail.zimbra@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-18T11:39:20Z","receivedAt":"2015-06-18T11:39:20Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> I've some more tests, maybe I should put them all in this post ?\n\nYes, please post as much as you have. Ideally, this should be\nautomatically tested, but if you don't have time to write the automated\ntests, at least having a track of what you did on the list archives can\nhelp someone else to do it.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264185","messageId":"1444764681.621777.1434640131682.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"vpqh9q56yaf.fsf@anie.imag.fr","subject":"[PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-18T15:08:51Z","receivedAt":"2015-06-18T15:08:51Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"> Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n> \n> > I've some more tests, maybe I should put them all in this post ?\n> \n> Yes, please post as much as you have. Ideally, this should be\n> automatically tested, but if you don't have time to write the automated\n> tests, at least having a track of what you did on the list archives can\n> help someone else to do it.\n\nIt may not be easily readable without colors, so there are the scripts\nat the end. You can change the tested input by changing lines after\nthe \"cat >.tmplist\" line in testall.sh. (There are two scripts \ntestall.sh and testone.perl).\n\nHere are the tests results:\n\nInput: \nSplit: \nM::A : \nSame : Yes\n----------\nInput: Jane\nSplit: Jane\nM::A : Jane\nSame : Yes\n----------\nInput: jdoe@example.com\nSplit: jdoe@example.com\nM::A : jdoe@example.com\nSame : Yes\n----------\nInput: <jdoe@example.com>\nSplit: jdoe@example.com\nM::A : jdoe@example.com\nSame : Yes\n----------\nInput: Jane <jdoe@example.com>\nSplit: Jane <jdoe@example.com>\nM::A : Jane <jdoe@example.com>\nSame : Yes\n----------\nInput: Jane Doe <jdoe@example.com>\nSplit: Jane Doe <jdoe@example.com>\nM::A : Jane Doe <jdoe@example.com>\nSame : Yes\n----------\nInput: Jane\\ Doe <jdoe@example.com>\nSplit: \"Jane\\ Doe\" <jdoe@example.com>\nM::A : \"Jane \\ Doe\" <jdoe@example.com>\nSame : No\n----------\nInput: \"Jane\" <jdoe@example.com>\nSplit: \"Jane\" <jdoe@example.com>\nM::A : \"Jane\" <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Doe, Jane\" <jdoe@example.com>\nSplit: \"Doe, Jane\" <jdoe@example.com>\nM::A : \"Doe, Jane\" <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Doe, Ja\"ne <jdoe@example.com>\nSplit: \"Doe, Ja ne\" <jdoe@example.com>\nM::A : \"Doe, Ja\" ne <jdoe@example.com>\nSame : No\n----------\nInput: \"Doe, Katarina\" Jane <jdoe@example.com>\nSplit: \"Doe, Katarina Jane\" <jdoe@example.com>\nM::A : \"Doe, Katarina\" Jane <jdoe@example.com>\nSame : No\n----------\nInput: \"Jane@:;\\>.,()<Doe\" <jdoe@example.com>\nSplit: \"Jane@:;\\>.,()<Doe\" <jdoe@example.com>\nM::A : \"Jane@:;\\>.,()<Doe\" <jdoe@example.com>\nSame : Yes\n----------\nInput: Jane@:;\\.,()<>Doe <jdoe@example.com>\nSplit: Jane@:\n     : \"\\.\"\n     : Doe <jdoe@example.com> ()\nM::A : Jane@:\n     : \\.\n     : Doe <jdoe@example.com> ()\nSame : No\n----------\nInput: Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>\nSplit: Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>\nM::A : Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>\nSame : Yes\n----------\nInput: \"<jdoe@example.com>\"\nSplit: \"<jdoe@example.com>\"\nM::A : \"<jdoe@example.com>\"\nSame : Yes\n----------\nInput: \"Jane jdoe@example.com\"\nSplit: \"Jane jdoe@example.com\"\nM::A : \"Jane jdoe@example.com\"\nSame : Yes\n----------\nInput: Jane Doe <jdoe    @   example.com  >\nSplit: Jane Doe <jdoe@example.com>\nM::A : Jane Doe <jdoe@example.com>\nSame : Yes\n----------\nInput: Jane       Doe <  jdoe@example.com  >\nSplit: Jane Doe <jdoe@example.com>\nM::A : Jane Doe <jdoe@example.com>\nSame : Yes\n----------\nInput: Jane @ Doe @ Jane @ Doe\nSplit: Jane@Doe@Jane@Doe\nM::A : Jane@Doe@Jane@Doe\nSame : Yes\n----------\nInput: Jane jdoe@example.com\nSplit: Janejdoe@example.com\nM::A : Jane\n     : jdoe@example.com\nSame : No\n----------\nInput: <jdoe@example.com> Jane Doe\nSplit: jdoe@example.comJaneDoe\nM::A : Jane Doe <jdoe@example.com>\nSame : No\n----------\nInput: Jane <jdoe@example.com> Doe\nSplit: Jane <jdoe@example.comDoe>\nM::A : Jane Doe <jdoe@example.com>\nSame : No\n----------\nInput: \"Jane, 'Doe'\" <jdoe@example.com>\nSplit: \"Jane, 'Doe'\" <jdoe@example.com>\nM::A : \"Jane, 'Doe'\" <jdoe@example.com>\nSame : Yes\n----------\nInput: 'Doe, \"Jane' <jdoe@example.com>\nSplit: 'Doe\n     : \" Jane' <jdoe@example.com>\nM::A : 'Doe\n     : \" Jane' <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Jane\" \"Do\"e <jdoe@example.com>\nSplit: \"Jane\" \"Do\" e <jdoe@example.com>\nM::A : \"Jane\" \"Do\" e <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Jane' Doe\" <jdoe@example.com>\nSplit: \"Jane' Doe\" <jdoe@example.com>\nM::A : \"Jane' Doe\" <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Jane Doe <jdoe@example.com>\" <jdoe@example.com>\nSplit: \"Jane Doe <jdoe@example.com>\" <jdoe@example.com>\nM::A : \"Jane Doe <jdoe@example.com>\" <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Jane\\\" Doe\" <jdoe@example.com>\nSplit: \"Jane\\\" Doe\" <jdoe@example.com>\nM::A : \"Jane\\\" Doe\" <jdoe@example.com>\nSame : Yes\n----------\nInput: Doe, jane <jdoe@example.com>\nSplit: Doe\n     : jane <jdoe@example.com>\nM::A : Doe\n     : jane <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Jane Doe <jdoe@example.com>\nSplit: \" Jane Doe <jdoe@example.com>\nM::A : \" Jane Doe <jdoe@example.com>\nSame : Yes\n----------\nInput: \"Jane \"Kat\"a\" ri\"na\" \",Doe\" <jdoe@example.com>\nSplit: \"Jane  Kat a ri na ,Doe\" <jdoe@example.com>\nM::A : \"Jane \" Kat \"a\" ri \"na\" \",Doe\" <jdoe@example.com>\nSame : No\n----------\nInput: Jane Doe\nSplit: Jane Doe\nM::A : Jane\n     : Doe\nSame : No\n----------\nInput: Jane \"Doe <jdoe@example.com>\"\nSplit: \"Jane Doe <jdoe@example.com>\"\nM::A : Jane\n     : \"Doe <jdoe@example.com>\"\nSame : No\n----------\nInput: \\\"Jane Doe <jdoe@example.com>\nSplit: \"\\\"Jane Doe\" <jdoe@example.com>\nM::A : \\ \" Jane Doe <jdoe@example.com>\nSame : No\n----------\nInput: Jane\\\"\\\" Doe <jdoe@example.com>\nSplit: \"Jane\\\"\\\" Doe\" <jdoe@example.com>\nM::A : Jane \\ \" \\ \" Doe <jdoe@example.com>\nSame : No\n----------\nInput: 'Jane 'Doe' <jdoe@example.com>\nSplit: 'Jane 'Doe' <jdoe@example.com>\nM::A : 'Jane 'Doe' <jdoe@example.com>\nSame : Yes\n----------\nInput: 'Jane \"Katarina\\\" \\' Doe' <jdoe@example.com>\nSplit: \"'Jane  Katarina\\\" \\' Doe'\" <jdoe@example.com>\nM::A : 'Jane \" Katarina \\ \" \\ ' Doe' <jdoe@example.com>\nSame : No\n\n\n**********************************************************************\n*                          SCRIPTS PART                              *\n**********************************************************************\n\n\n---------------------------- testall.sh ----------------------------\n\n#!/bin/sh\n\ncat >.tmplist <<EOF\n\nJane\njdoe@example.com\n<jdoe@example.com>\nJane <jdoe@example.com>\nJane Doe <jdoe@example.com>\nJane\\ Doe <jdoe@example.com>\n\"Jane\" <jdoe@example.com>\n\"Doe, Jane\" <jdoe@example.com>\n\"Doe, Ja\"ne <jdoe@example.com>\n\"Doe, Katarina\" Jane <jdoe@example.com>\n\"Jane@:;\\>.,()<Doe\" <jdoe@example.com>\nJane@:;\\.,()<>Doe <jdoe@example.com>\nJane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>\n\"<jdoe@example.com>\"\n\"Jane jdoe@example.com\"\nJane Doe <jdoe    @   example.com  >\nJane       Doe <  jdoe@example.com  >\nJane @ Doe @ Jane @ Doe\nJane jdoe@example.com\n<jdoe@example.com> Jane Doe\nJane <jdoe@example.com> Doe\n\"Jane, 'Doe'\" <jdoe@example.com>\n'Doe, \"Jane' <jdoe@example.com>\n\"Jane\" \"Do\"e <jdoe@example.com>\n\"Jane' Doe\" <jdoe@example.com>\n\"Jane Doe <jdoe@example.com>\" <jdoe@example.com>\n\"Jane\\\" Doe\" <jdoe@example.com>\nDoe, jane <jdoe@example.com>\n\"Jane Doe <jdoe@example.com>\n\"Jane \"Kat\"a\" ri\"na\" \",Doe\" <jdoe@example.com>\nJane Doe\nJane \"Doe <jdoe@example.com>\"\n\\\"Jane Doe <jdoe@example.com>\nJane\\\"\\\" Doe <jdoe@example.com>\n'Jane 'Doe' <jdoe@example.com>\n'Jane \"Katarina\\\" \\' Doe' <jdoe@example.com>\nEOF\n\n\ncat .tmplist | while read -r line\ndo\n    echo \"Input: $line\"\n    ./testone.perl \"$line\"\n    echo ----------\ndone\n\n---------------------------- testone.perl ----------------------------\n\n#!/usr/bin/perl\n\nuse strict;\nuse warnings;\n\nuse Term::ANSIColor;\nuse Mail::Address;\nuse Text::ParseWords;\n\nmy $string = $ARGV[0];\n\nsub split_addrs {\n\tmy $re_comment = qr/\\((?:[^)]*)\\)/;\n\tmy $re_quote = qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n\tmy $re_word = qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n\tmy $re_token = qr/(?:$re_quote|$re_word|$re_comment|\\S)/;\n\n\tmy @tokens = map { $_ =~ /\\s*($re_token)\\s*/g } @_;\n\tpush @tokens, \",\";\n\n\tmy (@addr_list, @phrase, @address, @comment, @buffer) = ();\n\tforeach my $token (@tokens) {\n\t\tif ($token =~ /^[,;]$/) {\n\t\t\tif (@address) {\n\t\t\t\tpush @address, @buffer;\n\t\t\t} else {\n\t\t\t\tpush @phrase, @buffer;\n\t\t\t}\n\t\t\n\t\t\tmy $str_phrase = join ' ', @phrase;\n\t\t\tmy $str_address = join '', @address;\n\t\t\tmy $str_comment = join ' ', @comment;\n\t\t\n\t\t\tif ($str_phrase =~ /[][()<>:;@\\\\,.\\000-\\037\\177]/) {\n\t\t\t\t$str_phrase =~ s/(^|[^\\\\])\"/$1/g;\n\t\t\t\t$str_phrase = qq[\"$str_phrase\"];\n\t\t\t}\n\t\t\n\t\t\tif ($str_address ne \"\" && $str_phrase ne \"\") {\n\t\t\t\t$str_address = qq[<$str_address>];\n\t\t\t}\n\t\t\n\t\t\tmy $str_mailbox = \"$str_phrase $str_address $str_comment\";\n\t\t\t$str_mailbox =~ s/^\\s*|\\s*$//g;\n\t\t\tpush @addr_list, $str_mailbox if ($str_mailbox);\n\t\t\n\t\t\t@phrase = @address = @comment = @buffer = ();\n\t\t} elsif ($token =~ /^\\(/) {\n\t\t\tpush @comment, $token;\n\t\t} elsif ($token eq \"<\") {\n\t\t\tpush @phrase, (splice @address), (splice @buffer);\n\t\t} elsif ($token eq \">\") {\n\t\t\tpush @address, (splice @buffer);\n\t\t} elsif ($token eq \"@\") {\n\t\t\tpush @address, (splice @buffer), \"@\";\n\t\t} elsif ($token eq \".\") {\n\t\t\tpush @address, (splice @buffer), \".\";\n\t\t} else {\n\t\t\tpush @buffer, $token;\n\t\t}\n\t}\n\n\treturn @addr_list;\n}\n\nsub old_split {\n\tquotewords('\\s*,\\s*', 1, $_[0]);\n}\n\nmy @tab = split_addrs($string);\nmy @ref = map { $_->format } Mail::Address->parse($string);\n# my @old = old_split($string);  #can be printed to see the difference\n\nmy $tabstring = join \"\\n\", @tab;\nmy $refstring = join \"\\n\", @ref;\nmy $same = ($tabstring eq $refstring);\n\n$tabstring =~ s/\\n/\\n     : /g;\n$refstring =~ s/\\n/\\n     : /g;\n\nprint color 'bold yellow';\nprint \"Split: \", \"$tabstring\", \"\\n\";\n\nprint color 'bold blue';\nprint \"M::A : \", \"$refstring\", \"\\n\";\n\nif ($same) {\n\tprint color 'bold green';\n\tprint \"Same : \", \"Yes\", \"\\n\";\n} else {\n\tprint color 'bold red';\n\tprint \"Same : \", \"No\", \"\\n\";\n}\n\nprint color 'reset';\n\n\n \n"},{"id":"264203","messageId":"vpqvbelylfk.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1444764681.621777.1434640131682.JavaMail.zimbra@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-18T17:29:35Z","receivedAt":"2015-06-18T17:29:35Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n>> Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n>> \n>> > I've some more tests, maybe I should put them all in this post ?\n>> \n>> Yes, please post as much as you have. Ideally, this should be\n>> automatically tested, but if you don't have time to write the automated\n>> tests, at least having a track of what you did on the list archives can\n>> help someone else to do it.\n>\n> It may not be easily readable without colors, so there are the scripts\n> at the end.\n\nCool. Then almost all the work is done to get an automated test. Next\nstep would be to add the tests itself in the code. I would do that by\nadding a hidden --selfcheck option to git send-email that would compare\nMail::Address->parse($string); and split_addrs($string); for all your\ntestcases, and die if they do not match. Then calling it from the\ntestsuite would be trivial.\n\nI can do that on top of your series if you don't have time.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264253","messageId":"114284546.628903.1434662953414.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"vpqvbelylfk.fsf@anie.imag.fr","subject":"[PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-18T21:29:13Z","receivedAt":"2015-06-18T21:29:13Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n\n> Cool. Then almost all the work is done to get an automated test. Next\n> step would be to add the tests itself in the code. I would do that by\n> adding a hidden --selfcheck option to git send-email that would compare\n> Mail::Address->parse($string); and split_addrs($string); for all your\n> testcases, and die if they do not match. Then calling it from the\n> testsuite would be trivial.\n\nOk, are there such \"--selfcheck\" options elsewhere? If I understand it\nright, you want to put the tests inside the git-send-email script. I\ndon't feel really good about that but I guess it's hard to test it\notherwise...  Also what will we do with the failing tests?  Just\ndiscard them?  I think there's two sort of failing test:\n\n - When output provided by parse_address_ without Mail::Address\n   is better or has no impact at all on the code. Such as:\n\n    Input: \"Doe, Ja\"ne <jdoe@example.com>\n    Split: \"Doe, Ja ne\" <jdoe@example.com>\n    M::A : \"Doe, Ja\" ne <jdoe@example.com>\n\n   This output is done on purpose. If it was the same output with\n   Mail::Address, we could have avoided commit 8/9 of this serie btw.\n\n   I think we should also test these cases.\n\n - When we don't really care about the output, because the user entry\n   is wrong, and we just expect the script to be aborted somehow... We\n   don't need to test that.\n\nWe could also add an option to specify whether we want to use\nMail::Address or not and do the tests in t9001* (but this would\ntake much more time).\n\n> I can do that on top of your series if you don't have time.\n\nTime will become a problem soon, but I think I can handle it unless\nyou really want to do it !\n"},{"id":"264278","messageId":"vpqpp4sw4ki.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"114284546.628903.1434662953414.JavaMail.zimbra@ensimag.grenoble-inp.fr","subject":"Re: [PATCH/RFC v4 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-19T07:16:45Z","receivedAt":"2015-06-19T07:16:45Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n>\n>> Cool. Then almost all the work is done to get an automated test. Next\n>> step would be to add the tests itself in the code. I would do that by\n>> adding a hidden --selfcheck option to git send-email that would compare\n>> Mail::Address->parse($string); and split_addrs($string); for all your\n>> testcases, and die if they do not match. Then calling it from the\n>> testsuite would be trivial.\n>\n> Ok, are there such \"--selfcheck\" options elsewhere?\n\nNot as far as I know.\n\n> If I understand it right, you want to put the tests inside the\n> git-send-email script. I don't feel really good about that but I guess\n> it's hard to test it otherwise...\n\nHmm, actually there is, I didn't look at the right places yesterday.\ngit-send-email.perl already does 'use Git;', and there's already a set\nof unit-tests for Git.pm: t9700-perl-git.sh, which calls perl\n\"$TEST_DIRECTORY\"/t9700/test.pl.\n\nSo, you can just add your code as a function in Git.pm and unit-tests in\nt/t9700/test.pl.\n\n> Also what will we do with the failing tests? Just discard them? I\n> think there's two sort of failing test:\n>\n>  - When output provided by parse_address_ without Mail::Address\n>    is better or has no impact at all on the code. Such as:\n\nI'm not sure we can be \"better\" as long as we do use Mail::Address when\navailable. Any difference is potentially harmfull for the user because\nit means that Git will have different behavior on different machines.\n\nPerhaps this is an argument to use your version unconditionally and drop\nMail::Address actually.\n\nBut you can still test that with\n\n  is(parse_address_(...), \"Doe, Jane\", \"<description>\");\n\n(possibly not calling Mail::Address)\n\nhttp://search.cpan.org/~exodist/Test-Simple-1.001014/lib/Test/More.pm\n\nThe cases where Mail::Address and your version give the same result can\nbe tested with a foreach loop calling\n\n  is(parse_address_(...), Mail::Address(...), ...);\n\n>  - When we don't really care about the output, because the user entry\n>    is wrong, and we just expect the script to be aborted somehow... We\n>    don't need to test that.\n\n... but if you already have the tests, you can keep them as known\nfailure.\n\nSee the \"TODO: BLOCK\" section of the doc of Test::More.\n\n>> I can do that on top of your series if you don't have time.\n>\n> Time will become a problem soon, but I think I can handle it unless\n> you really want to do it !\n\nIf you have time, just do it.\n\nThanks,\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264417","messageId":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 01/10] t9001-send-email: move script creation in a setup test","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:44Z","receivedAt":"2015-06-20T23:17:44Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Move the creation of the scripts used in to-cmd and cc-cmd tests\nin a setup test to make them available for later tests.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n t/t9001-send-email.sh | 15 +++++++++------\n 1 file changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex a3663da..eef12e6 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -312,13 +312,19 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'\n \t)\n '\n \n+test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '\n+\twrite_script tocmd-sed <<-\\EOF &&\n+\tsed -n -e \"s/^tocmd--//p\" \"$1\"\n+\tEOF\n+\twrite_script cccmd-sed <<-\\EOF\n+\tsed -n -e \"s/^cccmd--//p\" \"$1\"\n+\tEOF\n+'\n+\n test_expect_success $PREREQ 'tocmd works' '\n \tclean_fake_sendmail &&\n \tcp $patches tocmd.patch &&\n \techo tocmd--tocmd@example.com >>tocmd.patch &&\n-\twrite_script tocmd-sed <<-\\EOF &&\n-\tsed -n -e \"s/^tocmd--//p\" \"$1\"\n-\tEOF\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to-cmd=./tocmd-sed \\\n@@ -332,9 +338,6 @@ test_expect_success $PREREQ 'cccmd works' '\n \tclean_fake_sendmail &&\n \tcp $patches cccmd.patch &&\n \techo \"cccmd--  cccmd@example.com\" >>cccmd.patch &&\n-\twrite_script cccmd-sed <<-\\EOF &&\n-\tsed -n -e \"s/^cccmd--//p\" \"$1\"\n-\tEOF\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-- \n1.9.1\n"},{"id":"264419","messageId":"1434842273-30945-2-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 02/10] send-email: allow aliases in patch header and command script outputs","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:45Z","receivedAt":"2015-06-20T23:17:45Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Interpret aliases in:\n\n  -  Header fields of patches generated by git format-patch\n     (using --to, --cc, --add-header for example) or\n     manually modified. Example of fields in header:\n\n      To: alias1\n      Cc: alias2\n      Cc: alias3\n\n  -  Outputs of command scripts specified by --cc-cmd and\n     --to-cmd. Example of script:\n\n      #!/bin/sh\n      echo alias1\n      echo alias2\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl   |  2 ++\n t/t9001-send-email.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 62 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 6bedf74..8bf38ee 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1560,7 +1560,9 @@ foreach my $t (@files) {\n \t\t($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));\n \t$needs_confirm = \"inform\" if ($needs_confirm && $confirm_unconfigured && @cc);\n \n+\t@to = expand_aliases(@to);\n \t@to = validate_address_list(sanitize_address_list(@to));\n+\t@cc = expand_aliases(@cc);\n \t@cc = validate_address_list(sanitize_address_list(@cc));\n \n \t@to = (@initial_to, @to);\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex eef12e6..f7d4132 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1579,6 +1579,66 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=sendmail' '\n \tgrep \"^!o@example\\.com!$\" commandline1\n '\n \n+test_expect_success $PREREQ 'alias support in To header' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 --to=sbd >aliased.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\taliased.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'alias support in Cc header' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 --cc=sbd >aliased.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\taliased.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'tocmd works with aliases' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 >tocmd.patch &&\n+\techo tocmd--sbd >>tocmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to-cmd=./tocmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\ttocmd.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'cccmd works with aliases' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 >cccmd.patch &&\n+\techo cccmd--sbd >>cccmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--cc-cmd=./cccmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\tcccmd.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n do_xmailer_test () {\n \texpected=$1 params=$2 &&\n \tgit format-patch -1 &&\n-- \n1.9.1\n"},{"id":"264416","messageId":"1434842273-30945-3-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 03/10] t9001-send-email: refactor header variable fields replacement","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:46Z","receivedAt":"2015-06-20T23:17:46Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Create a function which replaces Date, Message-Id and\nX-Mailer lines generated by git-send-email by a specific string:\n\nDate:.*$       -> Date: DATE-STRING\nMessage-Id:.*$ -> Message-Id: MESSAGE-ID-STRING\nX-Mailer:.*$   -> X-Mailer: X-MAILER-STRING\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n t/t9001-send-email.sh | 11 +++++++----\n 1 file changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex f7d4132..714fcae 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -522,6 +522,12 @@ Result: OK\n EOF\n \"\n \n+replace_variable_fields () {\n+\tsed\t-e \"s/^\\(Date:\\).*/\\1 DATE-STRING/\" \\\n+\t\t-e \"s/^\\(Message-Id:\\).*/\\1 MESSAGE-ID-STRING/\" \\\n+\t\t-e \"s/^\\(X-Mailer:\\).*/\\1 X-MAILER-STRING/\"\n+}\n+\n test_suppression () {\n \tgit send-email \\\n \t\t--dry-run \\\n@@ -529,10 +535,7 @@ test_suppression () {\n \t\t--from=\"Example <from@example.com>\" \\\n \t\t--to=to@example.com \\\n \t\t--smtp-server relay.example.com \\\n-\t\t$patches |\n-\tsed\t-e \"s/^\\(Date:\\).*/\\1 DATE-STRING/\" \\\n-\t\t-e \"s/^\\(Message-Id:\\).*/\\1 MESSAGE-ID-STRING/\" \\\n-\t\t-e \"s/^\\(X-Mailer:\\).*/\\1 X-MAILER-STRING/\" \\\n+\t\t$patches | replace_variable_fields \\\n \t\t>actual-suppress-$1${2+\"-$2\"} &&\n \ttest_cmp expected-suppress-$1${2+\"-$2\"} actual-suppress-$1${2+\"-$2\"}\n }\n-- \n1.9.1\n"},{"id":"264420","messageId":"1434842273-30945-4-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 04/10] send-email: refactor address list process","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:47Z","receivedAt":"2015-06-20T23:17:47Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Simplify code by creating a function which transform a list of strings\ncontaining email addresses (separated by commas, comporting aliases)\ninto a clean list of valid email addresses.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 22 ++++++++++++----------\n 1 file changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 8bf38ee..2d5c530 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -833,12 +833,9 @@ sub expand_one_alias {\n \treturn $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;\n }\n \n-@initial_to = expand_aliases(@initial_to);\n-@initial_to = validate_address_list(sanitize_address_list(@initial_to));\n-@initial_cc = expand_aliases(@initial_cc);\n-@initial_cc = validate_address_list(sanitize_address_list(@initial_cc));\n-@bcclist = expand_aliases(@bcclist);\n-@bcclist = validate_address_list(sanitize_address_list(@bcclist));\n+@initial_to = process_address_list(@initial_to);\n+@initial_cc = process_address_list(@initial_cc);\n+@bcclist = process_address_list(@bcclist);\n \n if ($thread && !defined $initial_reply_to && $prompting) {\n \t$initial_reply_to = ask(\n@@ -1051,6 +1048,13 @@ sub sanitize_address_list {\n \treturn (map { sanitize_address($_) } @_);\n }\n \n+sub process_address_list {\n+\tmy @addr_list = expand_aliases(@_);\n+\t@addr_list = sanitize_address_list(@addr_list);\n+\t@addr_list = validate_address_list(@addr_list);\n+\treturn @addr_list;\n+}\n+\n # Returns the local Fully Qualified Domain Name (FQDN) if available.\n #\n # Tightly configured MTAa require that a caller sends a real DNS\n@@ -1560,10 +1564,8 @@ foreach my $t (@files) {\n \t\t($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));\n \t$needs_confirm = \"inform\" if ($needs_confirm && $confirm_unconfigured && @cc);\n \n-\t@to = expand_aliases(@to);\n-\t@to = validate_address_list(sanitize_address_list(@to));\n-\t@cc = expand_aliases(@cc);\n-\t@cc = validate_address_list(sanitize_address_list(@cc));\n+\t@to = process_address_list(@to);\n+\t@cc = process_address_list(@cc);\n \n \t@to = (@initial_to, @to);\n \t@cc = (@initial_cc, @cc);\n-- \n1.9.1\n"},{"id":"264421","messageId":"1434842273-30945-5-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 05/10] send-email: Allow use of aliases in the From field of --compose mode","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:48Z","receivedAt":"2015-06-20T23:17:48Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Aliases were expanded before considering the From field of the\n--compose option. This is inconsistent with other fields\n(To, Cc, ...) which already support aliases.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 2d5c530..f61449d 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -555,8 +555,6 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {\n \t}\n }\n \n-($sender) = expand_aliases($sender) if defined $sender;\n-\n # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if\n # $f is a revision list specification to be passed to format-patch.\n sub is_format_patch_arg {\n@@ -801,6 +799,8 @@ if (!$force) {\n \t}\n }\n \n+($sender) = expand_aliases($sender) if defined $sender;\n+\n if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n }\n-- \n1.9.1\n"},{"id":"264418","messageId":"1434842273-30945-6-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 06/10] send-email: minor code refactoring","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:49Z","receivedAt":"2015-06-20T23:17:49Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Group expressions in a single if statement. This avoid checking\nmultiple time if the variable $sender is defined.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex f61449d..a0cd7ff 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -799,9 +799,9 @@ if (!$force) {\n \t}\n }\n \n-($sender) = expand_aliases($sender) if defined $sender;\n-\n-if (!defined $sender) {\n+if (defined $sender) {\n+\t($sender) = expand_aliases($sender);\n+} else {\n \t$sender = $repoauthor || $repocommitter || '';\n }\n \n-- \n1.9.1\n"},{"id":"264422","messageId":"1434842273-30945-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434842273-30945-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-20T23:17:50Z","receivedAt":"2015-06-20T23:17:50Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"parse_address_line had not the same behavior whether the user had\nMail::Address or not. Teach parse_address_line to behave like\nMail::Address.\n\nWhen the user input is correct, this implementation behaves\nexactly like Mail::Address except when there are quotes\ninside the name:\n\n  \"Jane Do\"e <jdoe@example.com>\n\nIn this case the result of parse_address_line is:\n\n  With M::A : \"Jane Do\" e <jdoe@example.com>\n  Without   : \"Jane Do e\" <jdoe@example.com>\n\nWhen the user input is not correct, the behavior is also mostly\nthe same.\n\nUnlike Mail::Address, this doesn't parse groups and recursive\ncommentaries.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n\n---\n\nI've added the function in Git.pm as suggested. I've also added a test\nnamed t9000-addresses.sh (I've read the README to name tests but I'm\nnot sure about the name of this test). I made a separated test\n(t9000-addresses.sh) because I think it's better not to pollute\nt9001-send-email with this.\n\nAbout the test itself, file t/t9000-addresses.sh is just a copy/paste\nof t/t0202-gettext-perl.sh. For the perl part, the TODO tests are\nverbose: they print out commands whereas test_expect_success doesn't.\nWe can redirect todo_output to a variable but I've not found better...\n(Maybe someone has the solution here ?). Also there's no summary at\nthe end of the test (as with other perl tests).\n\n git-send-email.perl  |  2 +-\n perl/Git.pm          | 67 +++++++++++++++++++++++++++++++++++++++++++++++++\n t/t9000-addresses.sh | 25 ++++++++++++++++++\n t/t9000/test.pl      | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 164 insertions(+), 1 deletion(-)\n create mode 100755 t/t9000-addresses.sh\n create mode 100755 t/t9000/test.pl\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex a0cd7ff..bced78e 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -478,7 +478,7 @@ sub parse_address_line {\n \tif ($have_mail_address) {\n \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n \t} else {\n-\t\treturn split_addrs($_[0]);\n+\t\treturn Git::parse_mailboxes($_[0]);\n \t}\n }\n \ndiff --git a/perl/Git.pm b/perl/Git.pm\nindex 9026a7b..97633e9 100644\n--- a/perl/Git.pm\n+++ b/perl/Git.pm\n@@ -1584,6 +1584,73 @@ sub DESTROY {\n \t$self->_close_cat_blob();\n }\n \n+=item parse_mailboxes\n+\n+Returns an array of mailboxes extracted from a string.\n+\n+=cut\n+\n+sub parse_mailboxes {\n+\tmy $re_comment = qr/\\((?:[^)]*)\\)/;\n+\tmy $re_quote = qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n+\tmy $re_word = qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n+\n+\t# divide the string in tokens of the above form\n+\tmy $re_token = qr/(?:$re_quote|$re_word|$re_comment|\\S)/;\n+\tmy @tokens = map { $_ =~ /\\s*($re_token)\\s*/g } @_;\n+\n+\t# add a delimiter to simplify treatment for the last mailbox\n+\tpush @tokens, \",\";\n+\n+\tmy (@addr_list, @phrase, @address, @comment, @buffer) = ();\n+\tforeach my $token (@tokens) {\n+\t\tif ($token =~ /^[,;]$/) {\n+\t\t\t# if buffer still contains undeterminated strings\n+\t\t\t# append it at the end of @address or @phrase\n+\t\t\tif (@address) {\n+\t\t\t\tpush @address, @buffer;\n+\t\t\t} else {\n+\t\t\t\tpush @phrase, @buffer;\n+\t\t\t}\n+\n+\t\t\tmy $str_phrase = join ' ', @phrase;\n+\t\t\tmy $str_address = join '', @address;\n+\t\t\tmy $str_comment = join ' ', @comment;\n+\n+\t\t\t# quote are necessary if phrase contains\n+\t\t\t# special characters\n+\t\t\tif ($str_phrase =~ /[][()<>:;@\\\\,.\\000-\\037\\177]/) {\n+\t\t\t\t$str_phrase =~ s/(^|[^\\\\])\"/$1/g;\n+\t\t\t\t$str_phrase = qq[\"$str_phrase\"];\n+\t\t\t}\n+\n+\t\t\t# add \"<>\" around the address if necessary\n+\t\t\tif ($str_address ne \"\" && $str_phrase ne \"\") {\n+\t\t\t\t$str_address = qq[<$str_address>];\n+\t\t\t}\n+\n+\t\t\tmy $str_mailbox = \"$str_phrase $str_address $str_comment\";\n+\t\t\t$str_mailbox =~ s/^\\s*|\\s*$//g;\n+\t\t\tpush @addr_list, $str_mailbox if ($str_mailbox);\n+\n+\t\t\t@phrase = @address = @comment = @buffer = ();\n+\t\t} elsif ($token =~ /^\\(/) {\n+\t\t\tpush @comment, $token;\n+\t\t} elsif ($token eq \"<\") {\n+\t\t\tpush @phrase, (splice @address), (splice @buffer);\n+\t\t} elsif ($token eq \">\") {\n+\t\t\tpush @address, (splice @buffer);\n+\t\t} elsif ($token eq \"@\") {\n+\t\t\tpush @address, (splice @buffer), \"@\";\n+\t\t} elsif ($token eq \".\") {\n+\t\t\tpush @address, (splice @buffer), \".\";\n+\t\t} else {\n+\t\t\tpush @buffer, $token;\n+\t\t}\n+\t}\n+\n+\treturn @addr_list;\n+}\n \n # Pipe implementation for ActiveState Perl.\n \ndiff --git a/t/t9000-addresses.sh b/t/t9000-addresses.sh\nnew file mode 100755\nindex 0000000..280f2c5\n--- /dev/null\n+++ b/t/t9000-addresses.sh\n@@ -0,0 +1,25 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2015\n+#\n+\n+test_description='compare address parsing with and without Mail::Address'\n+. ./test-lib.sh\n+\n+if ! test_have_prereq PERL; then\n+\tskip_all='skipping perl interface tests, perl not available'\n+\ttest_done\n+fi\n+\n+perl -MTest::More -e 0 2>/dev/null || {\n+\tskip_all=\"Perl Test::More unavailable, skipping test\"\n+\ttest_done\n+}\n+\n+test_external_has_tap=1\n+\n+test_external_without_stderr \\\n+\t'Perl address parsing function' \\\n+\tperl \"$TEST_DIRECTORY\"/t9000/test.pl\n+\n+test_done\ndiff --git a/t/t9000/test.pl b/t/t9000/test.pl\nnew file mode 100755\nindex 0000000..f8b7b34\n--- /dev/null\n+++ b/t/t9000/test.pl\n@@ -0,0 +1,71 @@\n+#!/usr/bin/perl\n+use lib (split(/:/, $ENV{GITPERLLIB}));\n+\n+use 5.008;\n+use warnings;\n+use strict;\n+\n+use Test::More;\n+\n+BEGIN {\n+\tTest::More->builder->no_ending(1);\n+}\n+\n+BEGIN { use_ok('Git') }\n+BEGIN { use_ok('Mail::Address') }\n+\n+my @success_list = (q[Jane],\n+\tq[jdoe@example.com],\n+\tq[<jdoe@example.com>],\n+\tq[Jane <jdoe@example.com>],\n+\tq[Jane Doe <jdoe@example.com>],\n+\tq[\"Jane\" <jdoe@example.com>],\n+\tq[\"Doe, Jane\" <jdoe@example.com>],\n+\tq[\"Jane@:;\\>.,()<Doe\" <jdoe@example.com>],\n+\tq[Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>],\n+\tq[\"<jdoe@example.com>\"],\n+\tq[\"Jane jdoe@example.com\"],\n+\tq[Jane Doe <jdoe    @   example.com  >],\n+\tq[Jane       Doe <  jdoe@example.com  >],\n+\tq[Jane @ Doe @ Jane @ Doe],\n+\tq[\"Jane, 'Doe'\" <jdoe@example.com>],\n+\tq['Doe, \"Jane' <jdoe@example.com>],\n+\tq[\"Jane\" \"Do\"e <jdoe@example.com>],\n+\tq[\"Jane' Doe\" <jdoe@example.com>],\n+\tq[\"Jane Doe <jdoe@example.com>\" <jdoe@example.com>],\n+\tq[\"Jane\\\" Doe\" <jdoe@example.com>],\n+\tq[Doe, jane <jdoe@example.com>],\n+\tq[\"Jane Doe <jdoe@example.com>],\n+\tq['Jane 'Doe' <jdoe@example.com>]);\n+\n+my @known_failure_list = (q[Jane\\ Doe <jdoe@example.com>],\n+\tq[\"Doe, Ja\"ne <jdoe@example.com>],\n+\tq[\"Doe, Katarina\" Jane <jdoe@example.com>],\n+\tq[Jane@:;\\.,()<>Doe <jdoe@example.com>],\n+\tq[Jane jdoe@example.com],\n+\tq[<jdoe@example.com> Jane Doe],\n+\tq[Jane <jdoe@example.com> Doe],\n+\tq[\"Jane \"Kat\"a\" ri\"na\" \",Doe\" <jdoe@example.com>],\n+\tq[Jane Doe],\n+\tq[Jane \"Doe <jdoe@example.com>\"],\n+\tq[\\\"Jane Doe <jdoe@example.com>],\n+\tq[Jane\\\"\\\" Doe <jdoe@example.com>],\n+\tq['Jane \"Katarina\\\" \\' Doe' <jdoe@example.com>]);\n+\n+foreach my $str (@success_list) {\n+\tmy @expected = map { $_->format } Mail::Address->parse(\"$str\");\n+\tmy @actual = Git::parse_mailboxes(\"$str\");\n+\tis_deeply(\\@expected, \\@actual, qq[same output : $str]);\n+}\n+\n+TODO: {\n+\tlocal $TODO = \"known breakage\";\n+\tforeach my $str (@known_failure_list) {\n+\t\tmy @expected = map { $_->format } Mail::Address->parse(\"$str\");\n+\t\tmy @actual = Git::parse_mailboxes(\"$str\");\n+\t\tis_deeply(\\@expected, \\@actual, qq[same output : $str]);\n+\t}\n+}\n+\n+my $is_passing = Test::More->builder->is_passing;\n+exit($is_passing ? 0 : 1);\n-- \n1.9.1\n"},{"id":"264426","messageId":"1692637261.3463890.1434881256090.JavaMail.zimbra@imag.fr","threadId":"39657","inReplyTo":"1434842273-30945-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH v5 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-21T10:07:36Z","receivedAt":"2015-06-21T10:07:36Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"This is the last message I received in the series, and it's labeled 07/10. Is that normal?\n\n> parse_address_line had not the same behavior whether the user had\n\nhad not -> did not have\n\n> I've added the function in Git.pm as suggested. I've also added a test\n> named t9000-addresses.sh (I've read the README to name tests but I'm\n> not sure about the name of this test). I made a separated test\n> (t9000-addresses.sh) because I think it's better not to pollute\n> t9001-send-email with this.\n\nSounds good to me.\n\n> About the test itself, file t/t9000-addresses.sh is just a copy/paste\n> of t/t0202-gettext-perl.sh. For the perl part, the TODO tests are\n> verbose: they print out commands whereas test_expect_success doesn't.\n\nIt seems it's how Test::More works. I'd keep it like this, but I have no real experience with Test::More.\n\n> We can redirect todo_output to a variable but I've not found better...\n> (Maybe someone has the solution here ?). Also there's no summary at\n> the end of the test (as with other perl tests).\n\nYou can get the 1..44 at the end with\n\nprintf \"1..%d\\n\", Test::More->builder->current_test;\n\nThis is what t9700/test.pl does.\n\n> diff --git a/perl/Git.pm b/perl/Git.pm\n> index 9026a7b..97633e9 100644\n> --- a/perl/Git.pm\n> +++ b/perl/Git.pm\n> @@ -1584,6 +1584,73 @@ sub DESTROY {\n>  \t$self->_close_cat_blob();\n>  }\n>  \n> +=item parse_mailboxes\n> +\n> +Returns an array of mailboxes extracted from a string.\n\nImperative tone => Return, not Returns.\n\nI would have put parse_mailbox near ident_person because both functions are somehow about email.\n\n> +BEGIN { use_ok('Git') }\n> +BEGIN { use_ok('Mail::Address') }\n\nThis will fail if Mail::Address is not available. It would be better to declare Mail::Address as a prerequisite in t9000-address.sh (like what you're already doing for Test::More).\n\nGood job, modulo these minor details, the series looks good to me.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264429","messageId":"1434890756-5059-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 08/10] send-email: consider quote as delimiter instead of character","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-21T12:45:54Z","receivedAt":"2015-06-21T12:45:54Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Do not consider quote inside a recipient name as character when\nthey are not escaped. This interprets:\n\n  \"Jane\" \"Doe\" <jdoe@example.com>\n\nas:\n\n  \"Jane Doe\" <jdoe@example.com>\n\ninstead of:\n\n  \"Jane\\\" \\\"Doe\" <jdoe@example.com>\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex bced78e..a03392c 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1028,15 +1028,17 @@ sub sanitize_address {\n \t\treturn $recipient;\n \t}\n \n+\t# remove non-escaped quotes\n+\t$recipient_name =~ s/(^|[^\\\\])\"/$1/g;\n+\n \t# rfc2047 is needed if a non-ascii char is included\n \tif ($recipient_name =~ /[^[:ascii:]]/) {\n-\t\t$recipient_name =~ s/^\"(.*)\"$/$1/;\n \t\t$recipient_name = quote_rfc2047($recipient_name);\n \t}\n \n \t# double quotes are needed if specials or CTLs are included\n \telsif ($recipient_name =~ /[][()<>@,;:\\\\\".\\000-\\037\\177]/) {\n-\t\t$recipient_name =~ s/([\"\\\\\\r])/\\\\$1/g;\n+\t\t$recipient_name =~ s/([\\\\\\r])/\\\\$1/g;\n \t\t$recipient_name = qq[\"$recipient_name\"];\n \t}\n \n-- \n1.9.1\n"},{"id":"264431","messageId":"1434890756-5059-2-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434890756-5059-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 09/10] send-email: allow multiple emails using --cc, --to and --bcc","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-21T12:45:55Z","receivedAt":"2015-06-21T12:45:55Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Accept a list of emails separated by commas in flags --cc, --to and\n--bcc.  Multiple addresses can already be given by using these options\nmultiple times, but it is more convenient to allow cutting-and-pasting\na list of addresses from the header of an existing e-mail message,\nwhich already lists them as comma-separated list, as a value to a\nsingle parameter.\n\nThe following format can now be used:\n\n    $ git send-email --to='Jane <jdoe@example.com>, mike@example.com'\n\nRemove the limitation imposed by 79ee555b (Check and document the\noptions to prevent mistakes, 2006-06-21) which rejected every argument\nwith comma in --cc, --to and --bcc.\n\nHelped-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\nSigned-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>\nSigned-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>\nSigned-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n Documentation/git-send-email.txt | 12 +++++------\n git-send-email.perl              | 17 ++--------------\n t/t9001-send-email.sh            | 44 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 52 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b48a764..afd9569 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -49,17 +49,17 @@ Composing\n \tof 'sendemail.annotate'. See the CONFIGURATION section for\n \t'sendemail.multiEdit'.\n \n---bcc=<address>::\n+--bcc=<address>,...::\n \tSpecify a \"Bcc:\" value for each email. Default is the value of\n \t'sendemail.bcc'.\n +\n-The --bcc option must be repeated for each user you want on the bcc list.\n+This option may be specified multiple times.\n \n---cc=<address>::\n+--cc=<address>,...::\n \tSpecify a starting \"Cc:\" value for each email.\n \tDefault is the value of 'sendemail.cc'.\n +\n-The --cc option must be repeated for each user you want on the cc list.\n+This option may be specified multiple times.\n \n --compose::\n \tInvoke a text editor (see GIT_EDITOR in linkgit:git-var[1])\n@@ -110,13 +110,13 @@ is not set, this will be prompted for.\n \tOnly necessary if --compose is also set.  If --compose\n \tis not set, this will be prompted for.\n \n---to=<address>::\n+--to=<address>,...::\n \tSpecify the primary recipient of the emails generated. Generally, this\n \twill be the upstream maintainer of the project involved. Default is the\n \tvalue of the 'sendemail.to' configuration value; if that is unspecified,\n \tand --to-cmd is not specified, this will be prompted for.\n +\n-The --to option must be repeated for each user you want on the to list.\n+This option may be specified multiple times.\n \n --8bit-encoding=<encoding>::\n \tWhen encountering a non-ASCII message or subject that does not\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex a03392c..8bf6656 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -460,20 +460,6 @@ my ($repoauthor, $repocommitter);\n ($repoauthor) = Git::ident_person(@repo, 'author');\n ($repocommitter) = Git::ident_person(@repo, 'committer');\n \n-# Verify the user input\n-\n-foreach my $entry (@initial_to) {\n-\tdie \"Comma in --to entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n-foreach my $entry (@initial_cc) {\n-\tdie \"Comma in --cc entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n-foreach my $entry (@bcclist) {\n-\tdie \"Comma in --bcclist entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n sub parse_address_line {\n \tif ($have_mail_address) {\n \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n@@ -1051,7 +1037,8 @@ sub sanitize_address_list {\n }\n \n sub process_address_list {\n-\tmy @addr_list = expand_aliases(@_);\n+\tmy @addr_list = map { parse_address_line($_) } @_;\n+\t@addr_list = expand_aliases(@addr_list);\n \t@addr_list = sanitize_address_list(@addr_list);\n \t@addr_list = validate_address_list(@addr_list);\n \treturn @addr_list;\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 714fcae..3c5b853 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1675,4 +1675,48 @@ test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '\n \tdo_xmailer_test 1 \"--xmailer\"\n '\n \n+test_expect_success $PREREQ 'setup expected-list' '\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>\" \\\n+\t--to=\"to2@example.com\" \\\n+\t--to=\"to3@example.com\" \\\n+\t--cc=\"Cc 1 <cc1@example.com>\" \\\n+\t--cc=\"Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com\" \\\n+\t--bcc=\"bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>expected-list\n+'\n+\n+test_expect_success $PREREQ 'use email list in --cc --to and --bcc' '\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>, to2@example.com\" \\\n+\t--to=\"to3@example.com\" \\\n+\t--cc=\"Cc 1 <cc1@example.com>, Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com, bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n+test_expect_success $PREREQ 'aliases work with email list' '\n+\techo \"alias to2 to2@example.com\" >.mutt &&\n+\techo \"alias cc1 Cc 1 <cc1@example.com>\" >>.mutt &&\n+\ttest_config sendemail.aliasesfile \".mutt\" &&\n+\ttest_config sendemail.aliasfiletype mutt &&\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>, to2, to3@example.com\" \\\n+\t--cc=\"cc1, Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com, bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n test_done\n-- \n1.9.1\n"},{"id":"264430","messageId":"1434890756-5059-3-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434890756-5059-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v5 10/10] send-email: suppress meaningless whitespaces in from field","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-21T12:45:56Z","receivedAt":"2015-06-21T12:45:56Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Remove leading and trailing whitespaces in from field before\ninterepreting it to improve consistency with other options.  The\nsplit_addrs function already take care of trailing and leading\nwhitespaces for to, cc and bcc fields.\nThe from option now:\n\n - has the same behavior when passing arguments like\n   \"  jdoe@example.com \", \"\\t jdoe@example.com \" or\n   \"jdoe@example.com\".\n\n - interprets aliases in string containing leading and trailing\n   whitespaces such as \" alias\" or \"alias\\t\" like other options.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl   |  1 +\n t/t9001-send-email.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 8bf6656..749d809 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -786,6 +786,7 @@ if (!$force) {\n }\n \n if (defined $sender) {\n+\t$sender =~ s/^\\s+|\\s+$//g;\n \t($sender) = expand_aliases($sender);\n } else {\n \t$sender = $repoauthor || $repocommitter || '';\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 3c5b853..8e21fb0 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1719,4 +1719,28 @@ test_expect_success $PREREQ 'aliases work with email list' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n+\techo \"alias to2 to2@example.com\" >.mutt &&\n+\techo \"alias cc1 Cc 1 <cc1@example.com>\" >>.mutt &&\n+\ttest_config sendemail.aliasesfile \".mutt\" &&\n+\ttest_config sendemail.aliasfiletype mutt &&\n+\tTO1=$(echo \"QTo 1 <to1@example.com>\" | q_to_tab) &&\n+\tTO2=$(echo \"QZto2\" | qz_to_tab_space) &&\n+\tCC1=$(echo \"cc1\" | append_cr) &&\n+\tBCC1=$(echo \"Q bcc1@example.com Q\" | q_to_nul) &&\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"\tExample <from@example.com>\" \\\n+\t--to=\"$TO1\" \\\n+\t--to=\"$TO2\" \\\n+\t--to=\"  to3@example.com   \" \\\n+\t--cc=\"$CC1\" \\\n+\t--cc=\"Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"$BCC1\" \\\n+\t--bcc=\"bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n test_done\n-- \n1.9.1\n"},{"id":"264432","messageId":"715613601.681945.1434891762535.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1692637261.3463890.1434881256090.JavaMail.zimbra@imag.fr","subject":"[PATCH v5 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-21T13:02:42Z","receivedAt":"2015-06-21T13:02:42Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Matthieu Moy <matthieu.moy@grenoble-inp.fr> writes:\n\n> This is the last message I received in the series, and it's labeled\n> 07/10. Is that normal?\n\nNo, it wasn't, I have seen no error message though... I'll take a look\nat that later.  I just sent 0008, 0009 and 0010 but I seems that I've pasted\nthe wrong line in the in-reply-to... Maybe I need more sleep.\n\n>> We can redirect todo_output to a variable but I've not found better...\n>> (Maybe someone has the solution here ?). Also there's no summary at\n>> the end of the test (as with other perl tests).\n>\n> You can get the 1..44 at the end with\n ...\n> I would have put parse_mailbox near ident_person because both\n> functions are somehow about email.\n>\n>> +BEGIN { use_ok('Git') }\n>> +BEGIN { use_ok('Mail::Address') }\n>\n> This will fail if Mail::Address is not available. It would be better\n> to declare Mail::Address as a prerequisite in t9000-address.sh (like\n> what you're already doing for Test::More).\n\nOk, will do.\n\nThanks.\n"},{"id":"264434","messageId":"vpqzj3tmc8q.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1434890756-5059-2-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH v5 09/10] send-email: allow multiple emails using --cc, --to and --bcc","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-21T13:17:57Z","receivedAt":"2015-06-21T13:17:57Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> Helped-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n\n???\n\nAt this point, it's realonable to consider that you're the main author\nof the patch, but you could add a\n\nOriginal-patch-by:\n\nto credit the initial author.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264435","messageId":"vpqfv5lmbyk.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1434842273-30945-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH v5 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-21T13:24:03Z","receivedAt":"2015-06-21T13:24:03Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"> Subject: Re: [PATCH v5 07/10] send-email: reduce dependancies impact on parse_address_line\n\ns/dependancies/dependencies/\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264666","messageId":"69022894.748633.1435090507744.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1692637261.3463890.1434881256090.JavaMail.zimbra@imag.fr","subject":"[PATCH v5 07/10] send-email: reduce dependancies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:15:07Z","receivedAt":"2015-06-23T20:15:07Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n> > We can redirect todo_output to a variable but I've not found better...\n> > (Maybe someone has the solution here ?). Also there's no summary at\n> > the end of the test (as with other perl tests).\n> \n> You can get the 1..44 at the end with\n> \n> printf \"1..%d\\n\", Test::More->builder->current_test;\n> \n> This is what t9700/test.pl does.\n\nI can also get it by removing the line \n\n Test::More->builder->no_ending(1);\n\nand replacing\n\n use Test::More;\n\nby\n\n use Test::More \"no_plan\";\n\nI think I'm going to do that, because the no_ending thing makes the\ntest suite success even if every test fails: at the end we have\n\n# test_external test Perl address parsing function was ok\n# test_external_without_stderr test no stderr: Perl address parsing function was ok\n\nin case everything is ok. With the \"no_ending\" line, only the second\nline reports failures, the first is always the same.\nI think both must be marked red.\n"},{"id":"264672","messageId":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1434550720-24130-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 01/10] t9001-send-email: move script creation in a setup test","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:07Z","receivedAt":"2015-06-23T20:30:07Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Move the creation of the scripts used in to-cmd and cc-cmd tests\nin a setup test to make them available for later tests.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n t/t9001-send-email.sh | 15 +++++++++------\n 1 file changed, 9 insertions(+), 6 deletions(-)\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex a3663da..eef12e6 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -312,13 +312,19 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email'\n \t)\n '\n \n+test_expect_success $PREREQ 'setup tocmd and cccmd scripts' '\n+\twrite_script tocmd-sed <<-\\EOF &&\n+\tsed -n -e \"s/^tocmd--//p\" \"$1\"\n+\tEOF\n+\twrite_script cccmd-sed <<-\\EOF\n+\tsed -n -e \"s/^cccmd--//p\" \"$1\"\n+\tEOF\n+'\n+\n test_expect_success $PREREQ 'tocmd works' '\n \tclean_fake_sendmail &&\n \tcp $patches tocmd.patch &&\n \techo tocmd--tocmd@example.com >>tocmd.patch &&\n-\twrite_script tocmd-sed <<-\\EOF &&\n-\tsed -n -e \"s/^tocmd--//p\" \"$1\"\n-\tEOF\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to-cmd=./tocmd-sed \\\n@@ -332,9 +338,6 @@ test_expect_success $PREREQ 'cccmd works' '\n \tclean_fake_sendmail &&\n \tcp $patches cccmd.patch &&\n \techo \"cccmd--  cccmd@example.com\" >>cccmd.patch &&\n-\twrite_script cccmd-sed <<-\\EOF &&\n-\tsed -n -e \"s/^cccmd--//p\" \"$1\"\n-\tEOF\n \tgit send-email \\\n \t\t--from=\"Example <nobody@example.com>\" \\\n \t\t--to=nobody@example.com \\\n-- \n1.9.1\n"},{"id":"264674","messageId":"1435091416-9394-2-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 02/10] send-email: allow aliases in patch header and command script outputs","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:08Z","receivedAt":"2015-06-23T20:30:08Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Interpret aliases in:\n\n  -  Header fields of patches generated by git format-patch\n     (using --to, --cc, --add-header for example) or\n     manually modified. Example of fields in header:\n\n      To: alias1\n      Cc: alias2\n      Cc: alias3\n\n  -  Outputs of command scripts specified by --cc-cmd and\n     --to-cmd. Example of script:\n\n      #!/bin/sh\n      echo alias1\n      echo alias2\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl   |  2 ++\n t/t9001-send-email.sh | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 62 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 6bedf74..8bf38ee 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1560,7 +1560,9 @@ foreach my $t (@files) {\n \t\t($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));\n \t$needs_confirm = \"inform\" if ($needs_confirm && $confirm_unconfigured && @cc);\n \n+\t@to = expand_aliases(@to);\n \t@to = validate_address_list(sanitize_address_list(@to));\n+\t@cc = expand_aliases(@cc);\n \t@cc = validate_address_list(sanitize_address_list(@cc));\n \n \t@to = (@initial_to, @to);\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex eef12e6..f7d4132 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1579,6 +1579,66 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=sendmail' '\n \tgrep \"^!o@example\\.com!$\" commandline1\n '\n \n+test_expect_success $PREREQ 'alias support in To header' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 --to=sbd >aliased.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\taliased.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'alias support in Cc header' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 --cc=sbd >aliased.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\taliased.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'tocmd works with aliases' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 >tocmd.patch &&\n+\techo tocmd--sbd >>tocmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to-cmd=./tocmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\ttocmd.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n+test_expect_success $PREREQ 'cccmd works with aliases' '\n+\tclean_fake_sendmail &&\n+\techo \"alias sbd  someone@example.org\" >.mailrc &&\n+\ttest_config sendemail.aliasesfile \".mailrc\" &&\n+\ttest_config sendemail.aliasfiletype mailrc &&\n+\tgit format-patch --stdout -1 >cccmd.patch &&\n+\techo cccmd--sbd >>cccmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--cc-cmd=./cccmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\tcccmd.patch \\\n+\t\t2>errors >out &&\n+\tgrep \"^!someone@example\\.org!$\" commandline1\n+'\n+\n do_xmailer_test () {\n \texpected=$1 params=$2 &&\n \tgit format-patch -1 &&\n-- \n1.9.1\n"},{"id":"264673","messageId":"1435091416-9394-3-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 03/10] t9001-send-email: refactor header variable fields replacement","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:09Z","receivedAt":"2015-06-23T20:30:09Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Create a function which replaces Date, Message-Id and\nX-Mailer lines generated by git-send-email by a specific string:\n\nDate:.*$       -> Date: DATE-STRING\nMessage-Id:.*$ -> Message-Id: MESSAGE-ID-STRING\nX-Mailer:.*$   -> X-Mailer: X-MAILER-STRING\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n t/t9001-send-email.sh | 11 +++++++----\n 1 file changed, 7 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex f7d4132..714fcae 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -522,6 +522,12 @@ Result: OK\n EOF\n \"\n \n+replace_variable_fields () {\n+\tsed\t-e \"s/^\\(Date:\\).*/\\1 DATE-STRING/\" \\\n+\t\t-e \"s/^\\(Message-Id:\\).*/\\1 MESSAGE-ID-STRING/\" \\\n+\t\t-e \"s/^\\(X-Mailer:\\).*/\\1 X-MAILER-STRING/\"\n+}\n+\n test_suppression () {\n \tgit send-email \\\n \t\t--dry-run \\\n@@ -529,10 +535,7 @@ test_suppression () {\n \t\t--from=\"Example <from@example.com>\" \\\n \t\t--to=to@example.com \\\n \t\t--smtp-server relay.example.com \\\n-\t\t$patches |\n-\tsed\t-e \"s/^\\(Date:\\).*/\\1 DATE-STRING/\" \\\n-\t\t-e \"s/^\\(Message-Id:\\).*/\\1 MESSAGE-ID-STRING/\" \\\n-\t\t-e \"s/^\\(X-Mailer:\\).*/\\1 X-MAILER-STRING/\" \\\n+\t\t$patches | replace_variable_fields \\\n \t\t>actual-suppress-$1${2+\"-$2\"} &&\n \ttest_cmp expected-suppress-$1${2+\"-$2\"} actual-suppress-$1${2+\"-$2\"}\n }\n-- \n1.9.1\n"},{"id":"264675","messageId":"1435091416-9394-4-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 04/10] send-email: refactor address list process","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:10Z","receivedAt":"2015-06-23T20:30:10Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Simplify code by creating a function which transform a list of strings\ncontaining email addresses (separated by commas, comporting aliases)\ninto a clean list of valid email addresses.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 22 ++++++++++++----------\n 1 file changed, 12 insertions(+), 10 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 8bf38ee..2d5c530 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -833,12 +833,9 @@ sub expand_one_alias {\n \treturn $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;\n }\n \n-@initial_to = expand_aliases(@initial_to);\n-@initial_to = validate_address_list(sanitize_address_list(@initial_to));\n-@initial_cc = expand_aliases(@initial_cc);\n-@initial_cc = validate_address_list(sanitize_address_list(@initial_cc));\n-@bcclist = expand_aliases(@bcclist);\n-@bcclist = validate_address_list(sanitize_address_list(@bcclist));\n+@initial_to = process_address_list(@initial_to);\n+@initial_cc = process_address_list(@initial_cc);\n+@bcclist = process_address_list(@bcclist);\n \n if ($thread && !defined $initial_reply_to && $prompting) {\n \t$initial_reply_to = ask(\n@@ -1051,6 +1048,13 @@ sub sanitize_address_list {\n \treturn (map { sanitize_address($_) } @_);\n }\n \n+sub process_address_list {\n+\tmy @addr_list = expand_aliases(@_);\n+\t@addr_list = sanitize_address_list(@addr_list);\n+\t@addr_list = validate_address_list(@addr_list);\n+\treturn @addr_list;\n+}\n+\n # Returns the local Fully Qualified Domain Name (FQDN) if available.\n #\n # Tightly configured MTAa require that a caller sends a real DNS\n@@ -1560,10 +1564,8 @@ foreach my $t (@files) {\n \t\t($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));\n \t$needs_confirm = \"inform\" if ($needs_confirm && $confirm_unconfigured && @cc);\n \n-\t@to = expand_aliases(@to);\n-\t@to = validate_address_list(sanitize_address_list(@to));\n-\t@cc = expand_aliases(@cc);\n-\t@cc = validate_address_list(sanitize_address_list(@cc));\n+\t@to = process_address_list(@to);\n+\t@cc = process_address_list(@cc);\n \n \t@to = (@initial_to, @to);\n \t@cc = (@initial_cc, @cc);\n-- \n1.9.1\n"},{"id":"264677","messageId":"1435091416-9394-5-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 05/10] send-email: Allow use of aliases in the From field of --compose mode","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:11Z","receivedAt":"2015-06-23T20:30:11Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Aliases were expanded before considering the From field of the\n--compose option. This is inconsistent with other fields\n(To, Cc, ...) which already support aliases.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 2d5c530..f61449d 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -555,8 +555,6 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {\n \t}\n }\n \n-($sender) = expand_aliases($sender) if defined $sender;\n-\n # is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if\n # $f is a revision list specification to be passed to format-patch.\n sub is_format_patch_arg {\n@@ -801,6 +799,8 @@ if (!$force) {\n \t}\n }\n \n+($sender) = expand_aliases($sender) if defined $sender;\n+\n if (!defined $sender) {\n \t$sender = $repoauthor || $repocommitter || '';\n }\n-- \n1.9.1\n"},{"id":"264676","messageId":"1435091416-9394-6-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 06/10] send-email: minor code refactoring","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:12Z","receivedAt":"2015-06-23T20:30:12Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Group expressions in a single if statement. This avoid checking\nmultiple time if the variable $sender is defined.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex f61449d..a0cd7ff 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -799,9 +799,9 @@ if (!$force) {\n \t}\n }\n \n-($sender) = expand_aliases($sender) if defined $sender;\n-\n-if (!defined $sender) {\n+if (defined $sender) {\n+\t($sender) = expand_aliases($sender);\n+} else {\n \t$sender = $repoauthor || $repocommitter || '';\n }\n \n-- \n1.9.1\n"},{"id":"264678","messageId":"1435091416-9394-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 07/10] send-email: reduce dependencies impact on parse_address_line","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:30:13Z","receivedAt":"2015-06-23T20:30:13Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"parse_address_line had not the same behavior whether the user had\nMail::Address or not. Teach parse_address_line to behave like\nMail::Address.\n\nWhen the user input is correct, this implementation behaves\nexactly like Mail::Address except when there are quotes\ninside the name:\n\n  \"Jane Do\"e <jdoe@example.com>\n\nIn this case the result of parse_address_line is:\n\n  With M::A : \"Jane Do\" e <jdoe@example.com>\n  Without   : \"Jane Do e\" <jdoe@example.com>\n\nWhen the user input is not correct, the behavior is also mostly\nthe same.\n\nUnlike Mail::Address, this doesn't parse groups and recursive\ncommentaries.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl  |  2 +-\n perl/Git.pm          | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n t/t9000-addresses.sh | 30 +++++++++++++++++++++++\n t/t9000/test.pl      | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 165 insertions(+), 1 deletion(-)\n create mode 100755 t/t9000-addresses.sh\n create mode 100755 t/t9000/test.pl\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex a0cd7ff..bced78e 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -478,7 +478,7 @@ sub parse_address_line {\n \tif ($have_mail_address) {\n \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n \t} else {\n-\t\treturn split_addrs($_[0]);\n+\t\treturn Git::parse_mailboxes($_[0]);\n \t}\n }\n \ndiff --git a/perl/Git.pm b/perl/Git.pm\nindex 9026a7b..19ef081 100644\n--- a/perl/Git.pm\n+++ b/perl/Git.pm\n@@ -864,6 +864,73 @@ sub ident_person {\n \treturn \"$ident[0] <$ident[1]>\";\n }\n \n+=item parse_mailboxes\n+\n+Return an array of mailboxes extracted from a string.\n+\n+=cut\n+\n+sub parse_mailboxes {\n+\tmy $re_comment = qr/\\((?:[^)]*)\\)/;\n+\tmy $re_quote = qr/\"(?:[^\\\"\\\\]|\\\\.)*\"/;\n+\tmy $re_word = qr/(?:[^][\"\\s()<>:;@\\\\,.]|\\\\.)+/;\n+\n+\t# divide the string in tokens of the above form\n+\tmy $re_token = qr/(?:$re_quote|$re_word|$re_comment|\\S)/;\n+\tmy @tokens = map { $_ =~ /\\s*($re_token)\\s*/g } @_;\n+\n+\t# add a delimiter to simplify treatment for the last mailbox\n+\tpush @tokens, \",\";\n+\n+\tmy (@addr_list, @phrase, @address, @comment, @buffer) = ();\n+\tforeach my $token (@tokens) {\n+\t\tif ($token =~ /^[,;]$/) {\n+\t\t\t# if buffer still contains undeterminated strings\n+\t\t\t# append it at the end of @address or @phrase\n+\t\t\tif (@address) {\n+\t\t\t\tpush @address, @buffer;\n+\t\t\t} else {\n+\t\t\t\tpush @phrase, @buffer;\n+\t\t\t}\n+\n+\t\t\tmy $str_phrase = join ' ', @phrase;\n+\t\t\tmy $str_address = join '', @address;\n+\t\t\tmy $str_comment = join ' ', @comment;\n+\n+\t\t\t# quote are necessary if phrase contains\n+\t\t\t# special characters\n+\t\t\tif ($str_phrase =~ /[][()<>:;@\\\\,.\\000-\\037\\177]/) {\n+\t\t\t\t$str_phrase =~ s/(^|[^\\\\])\"/$1/g;\n+\t\t\t\t$str_phrase = qq[\"$str_phrase\"];\n+\t\t\t}\n+\n+\t\t\t# add \"<>\" around the address if necessary\n+\t\t\tif ($str_address ne \"\" && $str_phrase ne \"\") {\n+\t\t\t\t$str_address = qq[<$str_address>];\n+\t\t\t}\n+\n+\t\t\tmy $str_mailbox = \"$str_phrase $str_address $str_comment\";\n+\t\t\t$str_mailbox =~ s/^\\s*|\\s*$//g;\n+\t\t\tpush @addr_list, $str_mailbox if ($str_mailbox);\n+\n+\t\t\t@phrase = @address = @comment = @buffer = ();\n+\t\t} elsif ($token =~ /^\\(/) {\n+\t\t\tpush @comment, $token;\n+\t\t} elsif ($token eq \"<\") {\n+\t\t\tpush @phrase, (splice @address), (splice @buffer);\n+\t\t} elsif ($token eq \">\") {\n+\t\t\tpush @address, (splice @buffer);\n+\t\t} elsif ($token eq \"@\") {\n+\t\t\tpush @address, (splice @buffer), \"@\";\n+\t\t} elsif ($token eq \".\") {\n+\t\t\tpush @address, (splice @buffer), \".\";\n+\t\t} else {\n+\t\t\tpush @buffer, $token;\n+\t\t}\n+\t}\n+\n+\treturn @addr_list;\n+}\n \n =item hash_object ( TYPE, FILENAME )\n \ndiff --git a/t/t9000-addresses.sh b/t/t9000-addresses.sh\nnew file mode 100755\nindex 0000000..7223d03\n--- /dev/null\n+++ b/t/t9000-addresses.sh\n@@ -0,0 +1,30 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2015\n+#\n+\n+test_description='compare address parsing with and without Mail::Address'\n+. ./test-lib.sh\n+\n+if ! test_have_prereq PERL; then\n+\tskip_all='skipping perl interface tests, perl not available'\n+\ttest_done\n+fi\n+\n+perl -MTest::More -e 0 2>/dev/null || {\n+\tskip_all=\"Perl Test::More unavailable, skipping test\"\n+\ttest_done\n+}\n+\n+perl -MMail::Address -e 0 2>/dev/null || {\n+\tskip_all=\"Perl Mail::Address unavailable, skipping test\"\n+\ttest_done\n+}\n+\n+test_external_has_tap=1\n+\n+test_external_without_stderr \\\n+\t'Perl address parsing function' \\\n+\tperl \"$TEST_DIRECTORY\"/t9000/test.pl\n+\n+test_done\ndiff --git a/t/t9000/test.pl b/t/t9000/test.pl\nnew file mode 100755\nindex 0000000..8e2b760\n--- /dev/null\n+++ b/t/t9000/test.pl\n@@ -0,0 +1,67 @@\n+#!/usr/bin/perl\n+use lib (split(/:/, $ENV{GITPERLLIB}));\n+\n+use 5.008;\n+use warnings;\n+use strict;\n+\n+use Test::More qw(no_plan);\n+use Mail::Address;\n+\n+BEGIN { use_ok('Git') }\n+\n+my @success_list = (q[Jane],\n+\tq[jdoe@example.com],\n+\tq[<jdoe@example.com>],\n+\tq[Jane <jdoe@example.com>],\n+\tq[Jane Doe <jdoe@example.com>],\n+\tq[\"Jane\" <jdoe@example.com>],\n+\tq[\"Doe, Jane\" <jdoe@example.com>],\n+\tq[\"Jane@:;\\>.,()<Doe\" <jdoe@example.com>],\n+\tq[Jane!#$%&'*+-/=?^_{|}~Doe' <jdoe@example.com>],\n+\tq[\"<jdoe@example.com>\"],\n+\tq[\"Jane jdoe@example.com\"],\n+\tq[Jane Doe <jdoe    @   example.com  >],\n+\tq[Jane       Doe <  jdoe@example.com  >],\n+\tq[Jane @ Doe @ Jane @ Doe],\n+\tq[\"Jane, 'Doe'\" <jdoe@example.com>],\n+\tq['Doe, \"Jane' <jdoe@example.com>],\n+\tq[\"Jane\" \"Do\"e <jdoe@example.com>],\n+\tq[\"Jane' Doe\" <jdoe@example.com>],\n+\tq[\"Jane Doe <jdoe@example.com>\" <jdoe@example.com>],\n+\tq[\"Jane\\\" Doe\" <jdoe@example.com>],\n+\tq[Doe, jane <jdoe@example.com>],\n+\tq[\"Jane Doe <jdoe@example.com>],\n+\tq['Jane 'Doe' <jdoe@example.com>]);\n+\n+my @known_failure_list = (q[Jane\\ Doe <jdoe@example.com>],\n+\tq[\"Doe, Ja\"ne <jdoe@example.com>],\n+\tq[\"Doe, Katarina\" Jane <jdoe@example.com>],\n+\tq[Jane@:;\\.,()<>Doe <jdoe@example.com>],\n+\tq[Jane jdoe@example.com],\n+\tq[<jdoe@example.com> Jane Doe],\n+\tq[Jane <jdoe@example.com> Doe],\n+\tq[\"Jane \"Kat\"a\" ri\"na\" \",Doe\" <jdoe@example.com>],\n+\tq[Jane Doe],\n+\tq[Jane \"Doe <jdoe@example.com>\"],\n+\tq[\\\"Jane Doe <jdoe@example.com>],\n+\tq[Jane\\\"\\\" Doe <jdoe@example.com>],\n+\tq['Jane \"Katarina\\\" \\' Doe' <jdoe@example.com>]);\n+\n+foreach my $str (@success_list) {\n+\tmy @expected = map { $_->format } Mail::Address->parse(\"$str\");\n+\tmy @actual = Git::parse_mailboxes(\"$str\");\n+\tis_deeply(\\@expected, \\@actual, qq[same output : $str]);\n+}\n+\n+TODO: {\n+\tlocal $TODO = \"known breakage\";\n+\tforeach my $str (@known_failure_list) {\n+\t\tmy @expected = map { $_->format } Mail::Address->parse(\"$str\");\n+\t\tmy @actual = Git::parse_mailboxes(\"$str\");\n+\t\tis_deeply(\\@expected, \\@actual, qq[same output : $str]);\n+\t}\n+}\n+\n+my $is_passing = Test::More->builder->is_passing;\n+exit($is_passing ? 0 : 1);\n-- \n1.9.1\n"},{"id":"264683","messageId":"vpqfv5ijh20.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1435091416-9394-7-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH v6 07/10] send-email: reduce dependencies impact on parse_address_line","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-23T20:39:03Z","receivedAt":"2015-06-23T20:39:03Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Your git send-email does not seem to like PATCHes 08-10/10 ;-).\n\nUp to PATCH 07, the series looks good.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264684","messageId":"1435092001-9923-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 08/10] send-email: consider quote as delimiter instead of character","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:40:01Z","receivedAt":"2015-06-23T20:40:01Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Do not consider quote inside a recipient name as character when\nthey are not escaped. This interprets:\n\n  \"Jane\" \"Doe\" <jdoe@example.com>\n\nas:\n\n  \"Jane Doe\" <jdoe@example.com>\n\ninstead of:\n\n  \"Jane\\\" \\\"Doe\" <jdoe@example.com>\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex bced78e..a03392c 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -1028,15 +1028,17 @@ sub sanitize_address {\n \t\treturn $recipient;\n \t}\n \n+\t# remove non-escaped quotes\n+\t$recipient_name =~ s/(^|[^\\\\])\"/$1/g;\n+\n \t# rfc2047 is needed if a non-ascii char is included\n \tif ($recipient_name =~ /[^[:ascii:]]/) {\n-\t\t$recipient_name =~ s/^\"(.*)\"$/$1/;\n \t\t$recipient_name = quote_rfc2047($recipient_name);\n \t}\n \n \t# double quotes are needed if specials or CTLs are included\n \telsif ($recipient_name =~ /[][()<>@,;:\\\\\".\\000-\\037\\177]/) {\n-\t\t$recipient_name =~ s/([\"\\\\\\r])/\\\\$1/g;\n+\t\t$recipient_name =~ s/([\\\\\\r])/\\\\$1/g;\n \t\t$recipient_name = qq[\"$recipient_name\"];\n \t}\n \n-- \n1.9.1\n"},{"id":"264685","messageId":"1435092067-10054-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 09/10] send-email: allow multiple emails using --cc, --to and --bcc","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:41:07Z","receivedAt":"2015-06-23T20:41:07Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Accept a list of emails separated by commas in flags --cc, --to and\n--bcc.  Multiple addresses can already be given by using these options\nmultiple times, but it is more convenient to allow cutting-and-pasting\na list of addresses from the header of an existing e-mail message,\nwhich already lists them as comma-separated list, as a value to a\nsingle parameter.\n\nThe following format can now be used:\n\n    $ git send-email --to='Jane <jdoe@example.com>, mike@example.com'\n\nRemove the limitation imposed by 79ee555b (Check and document the\noptions to prevent mistakes, 2006-06-21) which rejected every argument\nwith comma in --cc, --to and --bcc.\n\nHelped-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\nSigned-off-by: Mathieu Lienard--Mayor <Mathieu.Lienard--Mayor@ensimag.imag.fr>\nSigned-off-by: Jorge Juan Garcia Garcia <Jorge-Juan.Garcia-Garcia@ensimag.imag.fr>\nSigned-off-by: Matthieu Moy <Matthieu.Moy@grenoble-inp.fr>\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n Documentation/git-send-email.txt | 12 +++++------\n git-send-email.perl              | 17 ++--------------\n t/t9001-send-email.sh            | 44 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 52 insertions(+), 21 deletions(-)\n\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b48a764..afd9569 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -49,17 +49,17 @@ Composing\n \tof 'sendemail.annotate'. See the CONFIGURATION section for\n \t'sendemail.multiEdit'.\n \n---bcc=<address>::\n+--bcc=<address>,...::\n \tSpecify a \"Bcc:\" value for each email. Default is the value of\n \t'sendemail.bcc'.\n +\n-The --bcc option must be repeated for each user you want on the bcc list.\n+This option may be specified multiple times.\n \n---cc=<address>::\n+--cc=<address>,...::\n \tSpecify a starting \"Cc:\" value for each email.\n \tDefault is the value of 'sendemail.cc'.\n +\n-The --cc option must be repeated for each user you want on the cc list.\n+This option may be specified multiple times.\n \n --compose::\n \tInvoke a text editor (see GIT_EDITOR in linkgit:git-var[1])\n@@ -110,13 +110,13 @@ is not set, this will be prompted for.\n \tOnly necessary if --compose is also set.  If --compose\n \tis not set, this will be prompted for.\n \n---to=<address>::\n+--to=<address>,...::\n \tSpecify the primary recipient of the emails generated. Generally, this\n \twill be the upstream maintainer of the project involved. Default is the\n \tvalue of the 'sendemail.to' configuration value; if that is unspecified,\n \tand --to-cmd is not specified, this will be prompted for.\n +\n-The --to option must be repeated for each user you want on the to list.\n+This option may be specified multiple times.\n \n --8bit-encoding=<encoding>::\n \tWhen encountering a non-ASCII message or subject that does not\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex a03392c..8bf6656 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -460,20 +460,6 @@ my ($repoauthor, $repocommitter);\n ($repoauthor) = Git::ident_person(@repo, 'author');\n ($repocommitter) = Git::ident_person(@repo, 'committer');\n \n-# Verify the user input\n-\n-foreach my $entry (@initial_to) {\n-\tdie \"Comma in --to entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n-foreach my $entry (@initial_cc) {\n-\tdie \"Comma in --cc entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n-foreach my $entry (@bcclist) {\n-\tdie \"Comma in --bcclist entry: $entry'\\n\" unless $entry !~ m/,/;\n-}\n-\n sub parse_address_line {\n \tif ($have_mail_address) {\n \t\treturn map { $_->format } Mail::Address->parse($_[0]);\n@@ -1051,7 +1037,8 @@ sub sanitize_address_list {\n }\n \n sub process_address_list {\n-\tmy @addr_list = expand_aliases(@_);\n+\tmy @addr_list = map { parse_address_line($_) } @_;\n+\t@addr_list = expand_aliases(@addr_list);\n \t@addr_list = sanitize_address_list(@addr_list);\n \t@addr_list = validate_address_list(@addr_list);\n \treturn @addr_list;\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 714fcae..3c5b853 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1675,4 +1675,48 @@ test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '\n \tdo_xmailer_test 1 \"--xmailer\"\n '\n \n+test_expect_success $PREREQ 'setup expected-list' '\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>\" \\\n+\t--to=\"to2@example.com\" \\\n+\t--to=\"to3@example.com\" \\\n+\t--cc=\"Cc 1 <cc1@example.com>\" \\\n+\t--cc=\"Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com\" \\\n+\t--bcc=\"bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>expected-list\n+'\n+\n+test_expect_success $PREREQ 'use email list in --cc --to and --bcc' '\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>, to2@example.com\" \\\n+\t--to=\"to3@example.com\" \\\n+\t--cc=\"Cc 1 <cc1@example.com>, Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com, bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n+test_expect_success $PREREQ 'aliases work with email list' '\n+\techo \"alias to2 to2@example.com\" >.mutt &&\n+\techo \"alias cc1 Cc 1 <cc1@example.com>\" >>.mutt &&\n+\ttest_config sendemail.aliasesfile \".mutt\" &&\n+\ttest_config sendemail.aliasfiletype mutt &&\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"Example <from@example.com>\" \\\n+\t--to=\"To 1 <to1@example.com>, to2, to3@example.com\" \\\n+\t--cc=\"cc1, Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"bcc1@example.com, bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n test_done\n-- \n1.9.1\n"},{"id":"264686","messageId":"1435092114-10139-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"1435091416-9394-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"[PATCH v6 10/10] send-email: suppress meaningless whitespaces in from field","fromName":"Remi Lespinet","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:41:54Z","receivedAt":"2015-06-23T20:41:54Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Remove leading and trailing whitespaces in from field before\ninterepreting it to improve consistency with other options.  The\nsplit_addrs function already take care of trailing and leading\nwhitespaces for to, cc and bcc fields.\nThe from option now:\n\n - has the same behavior when passing arguments like\n   \"  jdoe@example.com \", \"\\t jdoe@example.com \" or\n   \"jdoe@example.com\".\n\n - interprets aliases in string containing leading and trailing\n   whitespaces such as \" alias\" or \"alias\\t\" like other options.\n\nSigned-off-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n---\n git-send-email.perl   |  1 +\n t/t9001-send-email.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 25 insertions(+)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 8bf6656..749d809 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -786,6 +786,7 @@ if (!$force) {\n }\n \n if (defined $sender) {\n+\t$sender =~ s/^\\s+|\\s+$//g;\n \t($sender) = expand_aliases($sender);\n } else {\n \t$sender = $repoauthor || $repocommitter || '';\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 3c5b853..8e21fb0 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -1719,4 +1719,28 @@ test_expect_success $PREREQ 'aliases work with email list' '\n \ttest_cmp expected-list actual-list\n '\n \n+test_expect_success $PREREQ 'leading and trailing whitespaces are removed' '\n+\techo \"alias to2 to2@example.com\" >.mutt &&\n+\techo \"alias cc1 Cc 1 <cc1@example.com>\" >>.mutt &&\n+\ttest_config sendemail.aliasesfile \".mutt\" &&\n+\ttest_config sendemail.aliasfiletype mutt &&\n+\tTO1=$(echo \"QTo 1 <to1@example.com>\" | q_to_tab) &&\n+\tTO2=$(echo \"QZto2\" | qz_to_tab_space) &&\n+\tCC1=$(echo \"cc1\" | append_cr) &&\n+\tBCC1=$(echo \"Q bcc1@example.com Q\" | q_to_nul) &&\n+\tgit send-email \\\n+\t--dry-run \\\n+\t--from=\"\tExample <from@example.com>\" \\\n+\t--to=\"$TO1\" \\\n+\t--to=\"$TO2\" \\\n+\t--to=\"  to3@example.com   \" \\\n+\t--cc=\"$CC1\" \\\n+\t--cc=\"Cc2 <cc2@example.com>\" \\\n+\t--bcc=\"$BCC1\" \\\n+\t--bcc=\"bcc2@example.com\" \\\n+\t0001-add-master.patch | replace_variable_fields \\\n+\t>actual-list &&\n+\ttest_cmp expected-list actual-list\n+'\n+\n test_done\n-- \n1.9.1\n"},{"id":"264687","messageId":"vpq616ei28w.fsf@anie.imag.fr","threadId":"39657","inReplyTo":"1435092067-10054-1-git-send-email-remi.lespinet@ensimag.grenoble-inp.fr","subject":"Re: [PATCH v6 09/10] send-email: allow multiple emails using --cc, --to and --bcc","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2015-06-23T20:44:15Z","receivedAt":"2015-06-23T20:44:15Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr> writes:\n\n> Helped-by: Remi Lespinet <remi.lespinet@ensimag.grenoble-inp.fr>\n\nThis is funny in a patch sent by the same Remi Lespinet ;-).\n\nAnyway, the whole series looks good to me now (I finally got all up to\n10/10).\n\nCheers,\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"264690","messageId":"87d20mm9ao.fsf@ensimag.grenoble-inp.fr","threadId":"39657","inReplyTo":"vpqfv5ijh20.fsf@anie.imag.fr","subject":"[PATCH v6 07/10] send-email: reduce dependencies impact on parse_address_line","fromName":"Remi LESPINET","fromEmail":"remi.lespinet@ensimag.grenoble-inp.fr","sentAt":"2015-06-23T20:58:23Z","receivedAt":"2015-06-23T20:58:23Z","isPatch":true,"sender":{"key":"remi.lespinet@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/11941160?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n\n> Your git send-email does not seem to like PATCHes 08-10/10 ;-).\n>\n> Up to PATCH 07, the series looks good.\n\nYes, I get \"Too many recipients\" error... If I specify\n--no-signoff-by-cc then this is also aborted but I get no error (at\nleast I've not seen it last time...). If I rerun git send-email with\nonly one patch, it works (even if there is no difference with the\nnumber of recipient a priori). I'll investigate asap, not\nsure it's a bug, maybe It's just me !\n"}]}