{"thread":{"id":"59639","subject":"[PATCH 0/2] send-email: add --header-cmd option","startedAt":"2023-04-23T12:28:05Z","lastAt":"2023-05-08T19:19:26Z","messageCount":30,"participants":["Maxim Cournoyer","Junio C Hamano","Eric Sunshine","Felipe Contreras"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"475897","messageId":"20230423122744.4865-1-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":null,"subject":"[PATCH 0/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-23T12:27:42Z","receivedAt":"2023-04-23T12:28:05Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi,\n\nThis adds a new --header-cmd option to the send-email command, joining\nin the ranks of '--cc-cmd' and '--to-cmd'.  The header-cmd script\nprovided as argument should output 'header: value' lines, such as:\n\n  X-Debbugs-Cc: someone@example.com\n  AnotherHeader: somevalue\n  [...]\n\nThis change was motivated by the use case of easing collaboration\nusing Debbugs in GNU Guix [0].\n\n[0]  https://issues.guix.gnu.org/58813\n\nThanks,\n\nMaxim Cournoyer (2):\n  send-email: extract execute_cmd from recipients_cmd\n  send-email: add --header-cmd option\n\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   |  5 ++++\n git-send-email.perl                | 38 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 21 +++++++++++++++--\n 4 files changed, 54 insertions(+), 11 deletions(-)\n\n\nbase-commit: 7580f92ffa970b9484ac214f7b53cec5e26ca4bc\n-- \n2.39.2\n\n"},{"id":"475898","messageId":"20230423122744.4865-2-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230423122744.4865-1-maxim.cournoyer@gmail.com","subject":"[PATCH 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-23T12:27:43Z","receivedAt":"2023-04-23T12:28:11Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"This refactor is to pave the way for the addition of the new\n'--header-cmd' option to the send-email command.\n---\n git-send-email.perl | 26 ++++++++++++++++++++------\n 1 file changed, 20 insertions(+), 6 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex fd8cd0d46f..d2febbda1f 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -2,6 +2,7 @@\n #\n # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n+# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n #\n # GPL v2 (See COPYING)\n #\n@@ -2006,15 +2007,30 @@ sub process_file {\n \t}\n }\n \n+# Execute a command (e.g., $x_cmd) and return its output lines as an\n+# array.\n+sub execute_cmd {\n+\tmy ($prefix, $cmd, $file) = @_;\n+\tmy @lines = ();\n+\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n+\t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n+\twhile (my $line = <$fh>) {\n+\t\tlast if $line =~ /^$/;\n+\t\tpush @lines, $line;\n+\t}\n+\tclose $fh\n+\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n+\treturn @lines;\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\n \tmy ($prefix, $what, $cmd, $file) = @_;\n-\n+\tmy @lines = ();\n \tmy @addresses = ();\n-\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n-\t    or die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n-\twhile (my $address = <$fh>) {\n+\t@lines = execute_cmd($prefix, $cmd, $file);\n+\tfor my $address (@lines) {\n \t\t$address =~ s/^\\s*//g;\n \t\t$address =~ s/\\s*$//g;\n \t\t$address = sanitize_address($address);\n@@ -2023,8 +2039,6 @@ sub recipients_cmd {\n \t\tprintf(__(\"(%s) Adding %s: %s from: '%s'\\n\"),\n \t\t       $prefix, $what, $address, $cmd) unless $quiet;\n \t\t}\n-\tclose $fh\n-\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n \treturn @addresses;\n }\n \n-- \n2.39.2\n\n"},{"id":"475899","messageId":"20230423122744.4865-3-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230423122744.4865-1-maxim.cournoyer@gmail.com","subject":"[PATCH 2/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-23T12:27:44Z","receivedAt":"2023-04-23T12:28:19Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Sometimes, adding a header different than CC or TO is desirable; for\nexample, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers\nto keep people in CC; this is an example use case enabled by the new\n'--header-cmd' option.\n---\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   |  5 +++++\n git-send-email.perl                | 12 +++++++++---\n t/t9001-send-email.sh              | 21 +++++++++++++++++++--\n 4 files changed, 34 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 51da7088a8..3d0f516520 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -58,6 +58,7 @@ sendemail.annotate::\n sendemail.bcc::\n sendemail.cc::\n sendemail.ccCmd::\n+sendemail.headerCmd::\n sendemail.chainReplyTo::\n sendemail.envelopeSender::\n sendemail.from::\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b0f438ec99..354c0d06db 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -320,6 +320,11 @@ Automating\n \tOutput of this command must be single email address per line.\n \tDefault is the value of `sendemail.ccCmd` configuration value.\n \n+--header-cmd=<command>::\n+\tSpecify a command to execute once per patch file which should\n+\tgenerate arbitrary, patch file specific header entries.\n+\tDefault is the value of `sendemail.headerCmd` configuration value.\n+\n --[no-]chain-reply-to::\n \tIf this is set, each email will be sent as a reply to the previous\n \temail sent.  If disabled with \"--no-chain-reply-to\", all emails after\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex d2febbda1f..676dd83d89 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -88,8 +88,9 @@ sub usage {\n \n   Automating:\n     --identity              <str>  * Use the sendemail.<id> options.\n-    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`\n-    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`\n+    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`.\n+    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`.\n+    --header-cmd            <str>  * Add headers via `<str> \\$patch_path`.\n     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.\n     --[no-]cc-cover                * Email Cc: addresses in the cover letter.\n     --[no-]to-cover                * Email To: addresses in the cover letter.\n@@ -270,7 +271,7 @@ sub do_edit {\n # Variables with corresponding config settings\n my ($suppress_from, $signed_off_by_cc);\n my ($cover_cc, $cover_to);\n-my ($to_cmd, $cc_cmd);\n+my ($to_cmd, $cc_cmd, $header_cmd);\n my ($smtp_server, $smtp_server_port, @smtp_server_options);\n my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);\n my ($batch_size, $relogin_delay);\n@@ -319,6 +320,7 @@ sub do_edit {\n     \"tocmd\" => \\$to_cmd,\n     \"cc\" => \\@config_cc,\n     \"cccmd\" => \\$cc_cmd,\n+    \"headercmd\" => \\$header_cmd,\n     \"aliasfiletype\" => \\$aliasfiletype,\n     \"bcc\" => \\@config_bcc,\n     \"suppresscc\" => \\@suppress_cc,\n@@ -520,6 +522,7 @@ sub config_regexp {\n \t\t    \"compose\" => \\$compose,\n \t\t    \"quiet\" => \\$quiet,\n \t\t    \"cc-cmd=s\" => \\$cc_cmd,\n+\t\t    \"header-cmd=s\" => \\$header_cmd,\n \t\t    \"suppress-from!\" => \\$suppress_from,\n \t\t    \"no-suppress-from\" => sub {$suppress_from = 0},\n \t\t    \"suppress-cc=s\" => \\@suppress_cc,\n@@ -1777,6 +1780,9 @@ sub process_file {\n \t\t\tpush(@header, $_);\n \t\t}\n \t}\n+\t# Add computed headers, if applicable.\n+\tpush @header, execute_cmd(\"header-cmd\", $header_cmd, $t)\n+\t\tif defined $header_cmd;\n \t# Now parse the header\n \tforeach(@header) {\n \t\tif (/^From /) {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 0de83b5d2b..3393725107 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -374,13 +374,16 @@ 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+test_expect_success $PREREQ 'setup cmd scripts' '\n \twrite_script tocmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^tocmd--//p\" \"$1\"\n \tEOF\n-\twrite_script cccmd-sed <<-\\EOF\n+\twrite_script cccmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^cccmd--//p\" \"$1\"\n \tEOF\n+\twrite_script headercmd-sed <<-\\EOF\n+\tsed -n -e \"s/^headercmd--//p\" \"$1\"\n+\tEOF\n '\n \n test_expect_success $PREREQ 'tocmd works' '\n@@ -410,6 +413,20 @@ test_expect_success $PREREQ 'cccmd works' '\n \tgrep \"^\tcccmd@example.com\" msgtxt1\n '\n \n+test_expect_success $PREREQ 'headercmd works' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\techo \"headercmd--X-Debbugs-CC: dummy@example.com\" >>headercmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch \\\n+\t\t&&\n+\tgrep \"^X-Debbugs-CC: dummy@example.com\" msgtxt1\n+'\n+\n test_expect_success $PREREQ 'reject long lines' '\n \tz8=zzzzzzzz &&\n \tz64=$z8$z8$z8$z8$z8$z8$z8$z8 &&\n-- \n2.39.2\n\n"},{"id":"475977","messageId":"xmqqjzy19coy.fsf@gitster.g","threadId":"59639","inReplyTo":"20230423122744.4865-1-maxim.cournoyer@gmail.com","subject":"Re: [PATCH 0/2] send-email: add --header-cmd option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-04-24T21:45:33Z","receivedAt":"2023-04-24T21:45:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n\n> This adds a new --header-cmd option to the send-email command, joining\n> in the ranks of '--cc-cmd' and '--to-cmd'.\n\nIt sounds more like it makes these old two unnecessary, which is a\nvery good thing if it is the case ;-).\n"},{"id":"475978","messageId":"xmqqedo99cnu.fsf@gitster.g","threadId":"59639","inReplyTo":"20230423122744.4865-2-maxim.cournoyer@gmail.com","subject":"Re: [PATCH 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-04-24T21:46:13Z","receivedAt":"2023-04-24T21:47:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n\n> This refactor is to pave the way for the addition of the new\n> '--header-cmd' option to the send-email command.\n> ---\n>  git-send-email.perl | 26 ++++++++++++++++++++------\n>  1 file changed, 20 insertions(+), 6 deletions(-)\n\nMissing sign-off?\n\n> diff --git a/git-send-email.perl b/git-send-email.perl\n> index fd8cd0d46f..d2febbda1f 100755\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> @@ -2,6 +2,7 @@\n>  #\n>  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n>  # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n> +# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n>  #\n>  # GPL v2 (See COPYING)\n>  #\n> @@ -2006,15 +2007,30 @@ sub process_file {\n>  \t}\n>  }\n>  \n> +# Execute a command (e.g., $x_cmd) and return its output lines as an\n> +# array.\n> +sub execute_cmd {\n> +\tmy ($prefix, $cmd, $file) = @_;\n> +\tmy @lines = ();\n> +\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n> +\t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n> +\twhile (my $line = <$fh>) {\n> +\t\tlast if $line =~ /^$/;\n> +\t\tpush @lines, $line;\n> +\t}\n> +\tclose $fh\n> +\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n> +\treturn @lines;\n> +}\n> +\n>  # Execute a command (e.g. $to_cmd) to get a list of email addresses\n>  # and return a results array\n>  sub recipients_cmd {\n>  \tmy ($prefix, $what, $cmd, $file) = @_;\n> -\n> +\tmy @lines = ();\n>  \tmy @addresses = ();\n> -\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n> -\t    or die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n> -\twhile (my $address = <$fh>) {\n> +\t@lines = execute_cmd($prefix, $cmd, $file);\n> +\tfor my $address (@lines) {\n>  \t\t$address =~ s/^\\s*//g;\n>  \t\t$address =~ s/\\s*$//g;\n>  \t\t$address = sanitize_address($address);\n> @@ -2023,8 +2039,6 @@ sub recipients_cmd {\n>  \t\tprintf(__(\"(%s) Adding %s: %s from: '%s'\\n\"),\n>  \t\t       $prefix, $what, $address, $cmd) unless $quiet;\n>  \t\t}\n> -\tclose $fh\n> -\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n>  \treturn @addresses;\n>  }\n"},{"id":"475980","messageId":"xmqqh6t57x0y.fsf@gitster.g","threadId":"59639","inReplyTo":"20230423122744.4865-3-maxim.cournoyer@gmail.com","subject":"Re: [PATCH 2/2] send-email: add --header-cmd option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-04-24T22:09:17Z","receivedAt":"2023-04-24T22:09:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n\n> Sometimes, adding a header different than CC or TO is desirable; for\n> example, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers\n> to keep people in CC; this is an example use case enabled by the new\n> '--header-cmd' option.\n> ---\n\nMissing sign-off?\n\n>  Documentation/config/sendemail.txt |  1 +\n>  Documentation/git-send-email.txt   |  5 +++++\n>  git-send-email.perl                | 12 +++++++++---\n>  t/t9001-send-email.sh              | 21 +++++++++++++++++++--\n>  4 files changed, 34 insertions(+), 5 deletions(-)\n>\n> diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\n> index 51da7088a8..3d0f516520 100644\n> --- a/Documentation/config/sendemail.txt\n> +++ b/Documentation/config/sendemail.txt\n> @@ -58,6 +58,7 @@ sendemail.annotate::\n>  sendemail.bcc::\n>  sendemail.cc::\n>  sendemail.ccCmd::\n> +sendemail.headerCmd::\n>  sendemail.chainReplyTo::\n>  sendemail.envelopeSender::\n>  sendemail.from::\n\nWhy here?\n\nAsking because existing other entries look sorted lexicographically.\n\n> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\n> index b0f438ec99..354c0d06db 100644\n> --- a/Documentation/git-send-email.txt\n> +++ b/Documentation/git-send-email.txt\n> @@ -320,6 +320,11 @@ Automating\n>  \tOutput of this command must be single email address per line.\n>  \tDefault is the value of `sendemail.ccCmd` configuration value.\n>  \n> +--header-cmd=<command>::\n> +\tSpecify a command to execute once per patch file which should\n> +\tgenerate arbitrary, patch file specific header entries.\n\n\"arbitrary, patch file specific\" sounds like a problematic thing to\nsay here.  If it is truly arbitrary, then it is up to the user to\nemit identical output for all patches and there is no reason to\ninisist it has to be ptach file specific.  I am sure you meant \"you\ndo not have to add the same set of headres with the same values for\nall messages\", but that is very much obvious once you said \"command\nto execute once per patch file\".\n\nBy the way, does it apply also to the cover-letter, which is not a\npatch file?  I presume it does, in which case we shouldn't be saying\n\"once per patch file\", but something like \"once per outgoing message\"\nor something.\n\nAlso, its output is not really arbitrary.  It has to emit RFC-2822\nstyle header lines.  Emitting a block of lines, with an empty line\nin it, would be a disaster, isn't it?  The expected output format\nfor the <command> this option specifies needs to be described a bit\nbetter.\n\n\tSpecify a command that is executed once per outgoing message\n\tand output RFC-2822 style header lines to be inserted into\n\tthem.\n\nor something like that?\n\n> +\tDefault is the value of `sendemail.headerCmd` configuration value.\n\nMake it clear what you mean by the Default here.  If you configure\nthe variable, will the command be always used without any way to\nturn it off?  Or does it specify the default value to be used when\n\"git send-email ---header-cmd\" option is used without any value?\n\nIf it is the former, there should be a way to turn it off from the\ncommand line, probably.\n\n> diff --git a/git-send-email.perl b/git-send-email.perl\n> index d2febbda1f..676dd83d89 100755\n> --- a/git-send-email.perl\n> +++ b/git-send-email.perl\n> @@ -88,8 +88,9 @@ sub usage {\n>  \n>    Automating:\n>      --identity              <str>  * Use the sendemail.<id> options.\n> -    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`\n> -    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`\n> +    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`.\n> +    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`.\n> +    --header-cmd            <str>  * Add headers via `<str> \\$patch_path`.\n>      --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.\n>      --[no-]cc-cover                * Email Cc: addresses in the cover letter.\n>      --[no-]to-cover                * Email To: addresses in the cover letter.\n> @@ -270,7 +271,7 @@ sub do_edit {\n>  # Variables with corresponding config settings\n>  my ($suppress_from, $signed_off_by_cc);\n>  my ($cover_cc, $cover_to);\n> -my ($to_cmd, $cc_cmd);\n> +my ($to_cmd, $cc_cmd, $header_cmd);\n>  my ($smtp_server, $smtp_server_port, @smtp_server_options);\n>  my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);\n>  my ($batch_size, $relogin_delay);\n> @@ -319,6 +320,7 @@ sub do_edit {\n>      \"tocmd\" => \\$to_cmd,\n>      \"cc\" => \\@config_cc,\n>      \"cccmd\" => \\$cc_cmd,\n> +    \"headercmd\" => \\$header_cmd,\n>      \"aliasfiletype\" => \\$aliasfiletype,\n>      \"bcc\" => \\@config_bcc,\n>      \"suppresscc\" => \\@suppress_cc,\n> @@ -520,6 +522,7 @@ sub config_regexp {\n>  \t\t    \"compose\" => \\$compose,\n>  \t\t    \"quiet\" => \\$quiet,\n>  \t\t    \"cc-cmd=s\" => \\$cc_cmd,\n> +\t\t    \"header-cmd=s\" => \\$header_cmd,\n>  \t\t    \"suppress-from!\" => \\$suppress_from,\n>  \t\t    \"no-suppress-from\" => sub {$suppress_from = 0},\n>  \t\t    \"suppress-cc=s\" => \\@suppress_cc,\n> @@ -1777,6 +1780,9 @@ sub process_file {\n>  \t\t\tpush(@header, $_);\n>  \t\t}\n>  \t}\n> +\t# Add computed headers, if applicable.\n> +\tpush @header, execute_cmd(\"header-cmd\", $header_cmd, $t)\n> +\t\tif defined $header_cmd;\n\nWhile execute_cmd() may be a good enough interface to be used\nwithout much post-processing to read cc-cmd and to-cmd output (but\nnotice that even there it needs post-processing), I do not think it\nis a good interface to directly use to read header lines without any\npostprocessing like patch [2/2] does.  Its use in recipients_cmd()\nis OK primarily because it is about just reading bunch of values\nplaced on Cc: or To: lines.  If you are going to use it in arbitrary\nsets of header lines, it is very likely that you would need to\nhandle header folding (see what the loop before \"# Now parse the\nheader\" is doing to preprocess <$fh>, which is not done for lines\nyou read into @header in [2/2]).\n\n\nThanks.\n"},{"id":"475998","messageId":"875y9kspax.fsf@gmail.com","threadId":"59639","inReplyTo":"xmqqjzy19coy.fsf@gitster.g","subject":"Re: [PATCH 0/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T01:50:30Z","receivedAt":"2023-04-25T01:50:37Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi Junio,\n\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n>\n>> This adds a new --header-cmd option to the send-email command, joining\n>> in the ranks of '--cc-cmd' and '--to-cmd'.\n>\n> It sounds more like it makes these old two unnecessary, which is a\n> very good thing if it is the case ;-).\n\nYou are right, that --header-cmd can be considered as some kind of\ngeneralization of the more specific --cc-cmd and --to-cmd options; I\nhadn't given it much thought myself :-).\n\n-- \nThanks,\nMaxim\n"},{"id":"475999","messageId":"87y1mgrail.fsf@gmail.com","threadId":"59639","inReplyTo":"xmqqedo99cnu.fsf@gitster.g","subject":"Re: [PATCH 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T01:55:14Z","receivedAt":"2023-04-25T01:55:37Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hello,\n\nAnd thanks for offering a review!\n\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n>\n>> This refactor is to pave the way for the addition of the new\n>> '--header-cmd' option to the send-email command.\n>> ---\n>>  git-send-email.perl | 26 ++++++++++++++++++++------\n>>  1 file changed, 20 insertions(+), 6 deletions(-)\n>\n> Missing sign-off?\n\nAdded locally; thanks.\n\n-- \nThanks,\nMaxim\n"},{"id":"476031","messageId":"87y1mgortc.fsf@gmail.com","threadId":"59639","inReplyTo":"xmqqh6t57x0y.fsf@gitster.g","subject":"Re: [PATCH 2/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T16:22:07Z","receivedAt":"2023-04-25T16:22:16Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi,\n\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n>\n>> Sometimes, adding a header different than CC or TO is desirable; for\n>> example, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers\n>> to keep people in CC; this is an example use case enabled by the new\n>> '--header-cmd' option.\n>> ---\n>\n> Missing sign-off?\n\nAdded.\n\n>>  Documentation/config/sendemail.txt |  1 +\n>>  Documentation/git-send-email.txt   |  5 +++++\n>>  git-send-email.perl                | 12 +++++++++---\n>>  t/t9001-send-email.sh              | 21 +++++++++++++++++++--\n>>  4 files changed, 34 insertions(+), 5 deletions(-)\n>>\n>> diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\n>> index 51da7088a8..3d0f516520 100644\n>> --- a/Documentation/config/sendemail.txt\n>> +++ b/Documentation/config/sendemail.txt\n>> @@ -58,6 +58,7 @@ sendemail.annotate::\n>>  sendemail.bcc::\n>>  sendemail.cc::\n>>  sendemail.ccCmd::\n>> +sendemail.headerCmd::\n>>  sendemail.chainReplyTo::\n>>  sendemail.envelopeSender::\n>>  sendemail.from::\n>\n> Why here?\n>\n> Asking because existing other entries look sorted lexicographically.\n\nOops.  Fixed.\n\n\n>> diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\n>> index b0f438ec99..354c0d06db 100644\n>> --- a/Documentation/git-send-email.txt\n>> +++ b/Documentation/git-send-email.txt\n>> @@ -320,6 +320,11 @@ Automating\n>>  \tOutput of this command must be single email address per line.\n>>  \tDefault is the value of `sendemail.ccCmd` configuration value.\n>>\n>> +--header-cmd=<command>::\n>> +\tSpecify a command to execute once per patch file which should\n>> +\tgenerate arbitrary, patch file specific header entries.\n>\n> \"arbitrary, patch file specific\" sounds like a problematic thing to\n> say here.  If it is truly arbitrary, then it is up to the user to\n> emit identical output for all patches and there is no reason to\n> inisist it has to be ptach file specific.  I am sure you meant \"you\n> do not have to add the same set of headres with the same values for\n> all messages\", but that is very much obvious once you said \"command\n> to execute once per patch file\".\n\nThat is indeed what I meant.\n\n> By the way, does it apply also to the cover-letter, which is not a\n> patch file?  I presume it does, in which case we shouldn't be saying\n> \"once per patch file\", but something like \"once per outgoing message\"\n> or something.\n\nI think it happens for every message (the logic is in the\n'process_files' procedure), so it'd also apply to the cover letter\n(which is produced with the extension .patch by format-patch, although\nit isn't a patch as you noted :-)).\n\n> Also, its output is not really arbitrary.  It has to emit RFC-2822\n> style header lines.  Emitting a block of lines, with an empty line\n> in it, would be a disaster, isn't it?  The expected output format\n> for the <command> this option specifies needs to be described a bit\n> better.\n\nI'm not too familiar with the email format; but I presume an empty line\nwould signal the end of a message?  That'd be bad yes, but I think it\ncannot currently happen given the 'last if $line =~ /^$/;' guard at in\nexecute_cmd around line 2023; it'd means headers following an empty line\nwould be discarded though.  The expected use case is indeed for a user's\nscript to produce RFC 2822 style headers to messages.\n\n> \tSpecify a command that is executed once per outgoing message\n> \tand output RFC-2822 style header lines to be inserted into\n> \tthem.\n>\n> or something like that?\n\nThat's much clearer, thanks.  I've reworded the text following your\nsuggestion.\n\n>> +\tDefault is the value of `sendemail.headerCmd` configuration value.\n>\n> Make it clear what you mean by the Default here.  If you configure\n> the variable, will the command be always used without any way to\n> turn it off?  Or does it specify the default value to be used when\n> \"git send-email ---header-cmd\" option is used without any value?\n>\n> If it is the former, there should be a way to turn it off from the\n> command line, probably.\n\nThe former (a true default with no way to turn it off other than\nredefining it), which I believe is the same behavior as for --cc-cmd or\n--to-cmd.  There are no '--no-cc-cmd' or '--no-to-cmd' options, although\ntheir result can be filtered via the '--no-cc' and '--no-to' options.\nLooking in the source, options supporting '--no-' always appear to be\nboolean toggles (on/off) though, so I'm not sure how a '--no-header-cmd'\nthat take a value can currently be implemented.  Perhaps it could be\nadded later if there is a need?\n\n>> diff --git a/git-send-email.perl b/git-send-email.perl\n>> index d2febbda1f..676dd83d89 100755\n>> --- a/git-send-email.perl\n>> +++ b/git-send-email.perl\n>> @@ -88,8 +88,9 @@ sub usage {\n>>\n>>    Automating:\n>>      --identity              <str>  * Use the sendemail.<id> options.\n>> -    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`\n>> -    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`\n>> +    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`.\n>> +    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`.\n>> +    --header-cmd            <str>  * Add headers via `<str> \\$patch_path`.\n>>      --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.\n>>      --[no-]cc-cover                * Email Cc: addresses in the cover letter.\n>>      --[no-]to-cover                * Email To: addresses in the cover letter.\n>> @@ -270,7 +271,7 @@ sub do_edit {\n>>  # Variables with corresponding config settings\n>>  my ($suppress_from, $signed_off_by_cc);\n>>  my ($cover_cc, $cover_to);\n>> -my ($to_cmd, $cc_cmd);\n>> +my ($to_cmd, $cc_cmd, $header_cmd);\n>>  my ($smtp_server, $smtp_server_port, @smtp_server_options);\n>>  my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);\n>>  my ($batch_size, $relogin_delay);\n>> @@ -319,6 +320,7 @@ sub do_edit {\n>>      \"tocmd\" => \\$to_cmd,\n>>      \"cc\" => \\@config_cc,\n>>      \"cccmd\" => \\$cc_cmd,\n>> +    \"headercmd\" => \\$header_cmd,\n>>      \"aliasfiletype\" => \\$aliasfiletype,\n>>      \"bcc\" => \\@config_bcc,\n>>      \"suppresscc\" => \\@suppress_cc,\n>> @@ -520,6 +522,7 @@ sub config_regexp {\n>>  \t\t    \"compose\" => \\$compose,\n>>  \t\t    \"quiet\" => \\$quiet,\n>>  \t\t    \"cc-cmd=s\" => \\$cc_cmd,\n>> +\t\t    \"header-cmd=s\" => \\$header_cmd,\n>>  \t\t    \"suppress-from!\" => \\$suppress_from,\n>>  \t\t    \"no-suppress-from\" => sub {$suppress_from = 0},\n>>  \t\t    \"suppress-cc=s\" => \\@suppress_cc,\n>> @@ -1777,6 +1780,9 @@ sub process_file {\n>>  \t\t\tpush(@header, $_);\n>>  \t\t}\n>>  \t}\n>> +\t# Add computed headers, if applicable.\n>> +\tpush @header, execute_cmd(\"header-cmd\", $header_cmd, $t)\n>> +\t\tif defined $header_cmd;\n>\n> While execute_cmd() may be a good enough interface to be used\n> without much post-processing to read cc-cmd and to-cmd output (but\n> notice that even there it needs post-processing), I do not think it\n> is a good interface to directly use to read header lines without any\n> postprocessing like patch [2/2] does.\n>\n> Its use in recipients_cmd() is OK primarily because it is about just\n> reading bunch of values placed on Cc: or To: lines.  If you are going\n> to use it in arbitrary sets of header lines, it is very likely that\n> you would need to handle header folding (see what the loop before \"#\n> Now parse the header\" is doing to preprocess <$fh>, which is not done\n> for lines you read into @header in [2/2]).\n\nI've extracted such postprocessing into fold_headers and applied\nexecute_cmd to it in new invoke_header_cmd subroutine.\n\nv2 will follow shortly.\n\nThanks for the review!\n\n--\nMaxim\n"},{"id":"476033","messageId":"20230425162631.13684-1-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"xmqqh6t57x0y.fsf@gitster.g","subject":"[PATCH v2 0/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T16:26:29Z","receivedAt":"2023-04-25T16:26:53Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hello,\n\nThis v2 addresses most of the review comments from Junio (thanks!).\nIt clarifies the documentation text and postprocesses the headers,\nadding support for multiline headers.\n\nThanks,\n\nMaxim Cournoyer (2):\n  send-email: extract execute_cmd from recipients_cmd\n  send-email: add --header-cmd option\n\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   |  8 ++++\n git-send-email.perl                | 74 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 21 ++++++++-\n 4 files changed, 85 insertions(+), 19 deletions(-)\n\nDiff-intervalle contre v1 :\n1:  216b40c1b8 = 1:  216b40c1b8 send-email: extract execute_cmd from recipients_cmd\n2:  332d8ac4fe = 2:  332d8ac4fe send-email: add --header-cmd option\n\nbase-commit: 7580f92ffa970b9484ac214f7b53cec5e26ca4bc\n-- \n2.39.2\n\n"},{"id":"476034","messageId":"20230425162631.13684-2-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230425162631.13684-1-maxim.cournoyer@gmail.com","subject":"[PATCH v2 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T16:26:32Z","receivedAt":"2023-04-25T16:27:54Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"This refactor is to pave the way for the addition of the new\n'--header-cmd' option to the send-email command.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\n git-send-email.perl | 25 +++++++++++++++++++------\n 1 file changed, 19 insertions(+), 6 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex fd8cd0d46f..b8d77ad214 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -2,6 +2,7 @@\n #\n # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n+# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n #\n # GPL v2 (See COPYING)\n #\n@@ -2006,15 +2007,29 @@ sub process_file {\n \t}\n }\n \n+# Execute a command and return its output lines as an array.\n+sub execute_cmd {\n+\tmy ($prefix, $cmd, $file) = @_;\n+\tmy @lines = ();\n+\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n+\t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n+\twhile (my $line = <$fh>) {\n+\t\tlast if $line =~ /^$/;\n+\t\tpush @lines, $line;\n+\t}\n+\tclose $fh\n+\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n+\treturn @lines;\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\n \tmy ($prefix, $what, $cmd, $file) = @_;\n-\n+\tmy @lines = ();\n \tmy @addresses = ();\n-\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n-\t    or die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n-\twhile (my $address = <$fh>) {\n+\t@lines = execute_cmd($prefix, $cmd, $file);\n+\tfor my $address (@lines) {\n \t\t$address =~ s/^\\s*//g;\n \t\t$address =~ s/\\s*$//g;\n \t\t$address = sanitize_address($address);\n@@ -2023,8 +2038,6 @@ sub recipients_cmd {\n \t\tprintf(__(\"(%s) Adding %s: %s from: '%s'\\n\"),\n \t\t       $prefix, $what, $address, $cmd) unless $quiet;\n \t\t}\n-\tclose $fh\n-\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n \treturn @addresses;\n }\n \n-- \n2.39.2\n\n"},{"id":"476035","messageId":"xmqqcz3s3oz7.fsf@gitster.g","threadId":"59639","inReplyTo":"87y1mgortc.fsf@gmail.com","subject":"Re: [PATCH 2/2] send-email: add --header-cmd option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-04-25T16:29:00Z","receivedAt":"2023-04-25T16:29:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n\n> I'm not too familiar with the email format; but I presume an empty line\n> would signal the end of a message?  That'd be bad yes, but I think it\n> cannot currently happen given the 'last if $line =~ /^$/;' guard at in\n> execute_cmd around line 2023; it'd means headers following an empty line\n> would be discarded though.  The expected use case is indeed for a user's\n> script to produce RFC 2822 style headers to messages.\n\nYes, silently discarding the end-user input is what I meant by a\ndisaster.\n\n> The former (a true default with no way to turn it off other than\n> redefining it), which I believe is the same behavior as for --cc-cmd or\n> --to-cmd.  There are no '--no-cc-cmd' or '--no-to-cmd' options, although\n> their result can be filtered via the '--no-cc' and '--no-to' options.\n\nYup.\n\n> Looking in the source, options supporting '--no-' always appear to be\n> boolean toggles (on/off) though, so I'm not sure how a '--no-header-cmd'\n> that take a value can currently be implemented.  Perhaps it could be\n> added later if there is a need?\n\nPerhaps we can do without a configuration variable first, and\nperhaps the variable could be added later if there is a need and a\nproper way to turn it off per invocation basis.\n\n> I've extracted such postprocessing into fold_headers and applied\n> execute_cmd to it in new invoke_header_cmd subroutine.\n\nSounds like a good approach (without looking the actual patch).\n\nThanks.\n"},{"id":"476036","messageId":"20230425162631.13684-3-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230425162631.13684-1-maxim.cournoyer@gmail.com","subject":"[PATCH v2 2/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T16:26:34Z","receivedAt":"2023-04-25T16:29:16Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Sometimes, adding a header different than CC or TO is desirable; for\nexample, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers\nto keep people in CC; this is an example use case enabled by the new\n'--header-cmd' option.\n\nThe header folding logic is extracted to a subroutine so that it can\nbe reused.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   |  8 +++++\n git-send-email.perl                | 49 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 21 +++++++++++--\n 4 files changed, 66 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 51da7088a8..92a9ebe98c 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -61,6 +61,7 @@ sendemail.ccCmd::\n sendemail.chainReplyTo::\n sendemail.envelopeSender::\n sendemail.from::\n+sendemail.headerCmd::\n sendemail.signedoffbycc::\n sendemail.smtpPass::\n sendemail.suppresscc::\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b0f438ec99..295a3dd67c 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -320,6 +320,14 @@ Automating\n \tOutput of this command must be single email address per line.\n \tDefault is the value of `sendemail.ccCmd` configuration value.\n \n+--header-cmd=<command>::\n+\tSpecify a command that is executed once per outgoing message\n+\tand output RFC 2822 style header lines to be inserted into\n+\tthem. When the `sendemail.headerCmd` configuration variable is\n+\tset, its value is always used. When --header-cmd is provided\n+\tat the command line, its value takes precedence over the\n+\t`sendemail.headerCmd` configuration variable.\n+\n --[no-]chain-reply-to::\n \tIf this is set, each email will be sent as a reply to the previous\n \temail sent.  If disabled with \"--no-chain-reply-to\", all emails after\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex b8d77ad214..906fc1964d 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -88,8 +88,9 @@ sub usage {\n \n   Automating:\n     --identity              <str>  * Use the sendemail.<id> options.\n-    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`\n-    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`\n+    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`.\n+    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`.\n+    --header-cmd            <str>  * Add headers via `<str> \\$patch_path`.\n     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.\n     --[no-]cc-cover                * Email Cc: addresses in the cover letter.\n     --[no-]to-cover                * Email To: addresses in the cover letter.\n@@ -270,7 +271,7 @@ sub do_edit {\n # Variables with corresponding config settings\n my ($suppress_from, $signed_off_by_cc);\n my ($cover_cc, $cover_to);\n-my ($to_cmd, $cc_cmd);\n+my ($to_cmd, $cc_cmd, $header_cmd);\n my ($smtp_server, $smtp_server_port, @smtp_server_options);\n my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);\n my ($batch_size, $relogin_delay);\n@@ -319,6 +320,7 @@ sub do_edit {\n     \"tocmd\" => \\$to_cmd,\n     \"cc\" => \\@config_cc,\n     \"cccmd\" => \\$cc_cmd,\n+    \"headercmd\" => \\$header_cmd,\n     \"aliasfiletype\" => \\$aliasfiletype,\n     \"bcc\" => \\@config_bcc,\n     \"suppresscc\" => \\@suppress_cc,\n@@ -520,6 +522,7 @@ sub config_regexp {\n \t\t    \"compose\" => \\$compose,\n \t\t    \"quiet\" => \\$quiet,\n \t\t    \"cc-cmd=s\" => \\$cc_cmd,\n+\t\t    \"header-cmd=s\" => \\$header_cmd,\n \t\t    \"suppress-from!\" => \\$suppress_from,\n \t\t    \"no-suppress-from\" => sub {$suppress_from = 0},\n \t\t    \"suppress-cc=s\" => \\@suppress_cc,\n@@ -1766,17 +1769,15 @@ sub process_file {\n \t$subject = $initial_subject;\n \t$message = \"\";\n \t$message_num++;\n-\t# First unfold multiline header fields\n+\t# Retrieve and fold header fields.\n+\tmy @header_lines = ();\n \twhile(<$fh>) {\n \t\tlast if /^\\s*$/;\n-\t\tif (/^\\s+\\S/ and @header) {\n-\t\t\tchomp($header[$#header]);\n-\t\t\ts/^\\s+/ /;\n-\t\t\t$header[$#header] .= $_;\n-\t    } else {\n-\t\t\tpush(@header, $_);\n-\t\t}\n+\t\tpush(@header_lines, $_);\n \t}\n+\t@header = fold_headers(@header_lines);\n+\t# Add computed headers, if applicable.\n+\tpush @header, invoke_header_cmd($header_cmd, $t) if defined $header_cmd;\n \t# Now parse the header\n \tforeach(@header) {\n \t\tif (/^From /) {\n@@ -2022,6 +2023,32 @@ sub execute_cmd {\n \treturn @lines;\n }\n \n+# Process headers lines, folding multiline headers as defined by RFC\n+# 2822.\n+sub fold_headers {\n+\tmy @headers;\n+\tforeach(@_) {\n+\t\tlast if /^\\s*$/;\n+\t\tif (/^\\s+\\S/ and @headers) {\n+\t\t\tchomp($headers[$#headers]);\n+\t\t\ts/^\\s+/ /;\n+\t\t\t$headers[$#headers] .= $_;\n+\t\t} else {\n+\t\t\tpush(@headers, $_);\n+\t\t}\n+\t}\n+\treturn @headers;\n+}\n+\n+# Invoke the provided CMD with FILE as an argument, which should\n+# output RFC 2822 email headers. Fold multiline headers and return the\n+# headers as an array.\n+sub invoke_header_cmd {\n+\tmy ($cmd, $file) = @_;\n+\tmy @lines = execute_cmd(\"header-cmd\", $header_cmd, $file);\n+\treturn fold_headers(@lines);\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 0de83b5d2b..3393725107 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -374,13 +374,16 @@ 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+test_expect_success $PREREQ 'setup cmd scripts' '\n \twrite_script tocmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^tocmd--//p\" \"$1\"\n \tEOF\n-\twrite_script cccmd-sed <<-\\EOF\n+\twrite_script cccmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^cccmd--//p\" \"$1\"\n \tEOF\n+\twrite_script headercmd-sed <<-\\EOF\n+\tsed -n -e \"s/^headercmd--//p\" \"$1\"\n+\tEOF\n '\n \n test_expect_success $PREREQ 'tocmd works' '\n@@ -410,6 +413,20 @@ test_expect_success $PREREQ 'cccmd works' '\n \tgrep \"^\tcccmd@example.com\" msgtxt1\n '\n \n+test_expect_success $PREREQ 'headercmd works' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\techo \"headercmd--X-Debbugs-CC: dummy@example.com\" >>headercmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch \\\n+\t\t&&\n+\tgrep \"^X-Debbugs-CC: dummy@example.com\" msgtxt1\n+'\n+\n test_expect_success $PREREQ 'reject long lines' '\n \tz8=zzzzzzzz &&\n \tz64=$z8$z8$z8$z8$z8$z8$z8$z8 &&\n-- \n2.39.2\n\n"},{"id":"476038","messageId":"CAPig+cQ+6m35cTXr20-BNyHRsQQq2nTNERCH8N9NMsUP8Ct7mA@mail.gmail.com","threadId":"59639","inReplyTo":"20230425162631.13684-2-maxim.cournoyer@gmail.com","subject":"Re: [PATCH v2 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-04-25T17:04:50Z","receivedAt":"2023-04-25T17:05:08Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Apr 25, 2023 at 12:46 PM Maxim Cournoyer\n<maxim.cournoyer@gmail.com> wrote:\n> diff --git a/git-send-email.perl b/git-send-email.perl\n> @@ -2,6 +2,7 @@\n>  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n>  # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n> +# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n\nLet's avoid this change, please. Many people have worked on this file\nover the years -- often making changes far more substantial than those\nmade by this patch series -- who have not staked such a claim.\n"},{"id":"476054","messageId":"20230425185013.14351-1-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"xmqqcz3s3oz7.fsf@gitster.g","subject":"[PATCH v3 0/3] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T18:50:10Z","receivedAt":"2023-04-25T18:51:49Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hello,\n\nThis third revision adds some input validation, to detect invalid\noutput coming from user scripts used with 'git send-email'.  It also\nadds a test to ensure multiline (folded) headers are correctly\nsupported.\n\nThanks,\n\nMaxim Cournoyer (3):\n  send-email: extract execute_cmd from recipients_cmd\n  send-email: add --header-cmd option\n  send-email: detect empty blank lines in command output\n\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   |  8 +++\n git-send-email.perl                | 82 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 56 +++++++++++++++++++-\n 4 files changed, 128 insertions(+), 19 deletions(-)\n\n\nbase-commit: 7580f92ffa970b9484ac214f7b53cec5e26ca4bc\n-- \n2.39.2\n\n"},{"id":"476055","messageId":"20230425185013.14351-2-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230425185013.14351-1-maxim.cournoyer@gmail.com","subject":"[PATCH v3 1/3] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T18:50:11Z","receivedAt":"2023-04-25T18:51:55Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"This refactor is to pave the way for the addition of the new\n'--header-cmd' option to the send-email command.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\n git-send-email.perl | 25 +++++++++++++++++++------\n 1 file changed, 19 insertions(+), 6 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex fd8cd0d46f..b8d77ad214 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -2,6 +2,7 @@\n #\n # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n+# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n #\n # GPL v2 (See COPYING)\n #\n@@ -2006,15 +2007,29 @@ sub process_file {\n \t}\n }\n \n+# Execute a command and return its output lines as an array.\n+sub execute_cmd {\n+\tmy ($prefix, $cmd, $file) = @_;\n+\tmy @lines = ();\n+\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n+\t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n+\twhile (my $line = <$fh>) {\n+\t\tlast if $line =~ /^$/;\n+\t\tpush @lines, $line;\n+\t}\n+\tclose $fh\n+\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n+\treturn @lines;\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\n \tmy ($prefix, $what, $cmd, $file) = @_;\n-\n+\tmy @lines = ();\n \tmy @addresses = ();\n-\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n-\t    or die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n-\twhile (my $address = <$fh>) {\n+\t@lines = execute_cmd($prefix, $cmd, $file);\n+\tfor my $address (@lines) {\n \t\t$address =~ s/^\\s*//g;\n \t\t$address =~ s/\\s*$//g;\n \t\t$address = sanitize_address($address);\n@@ -2023,8 +2038,6 @@ sub recipients_cmd {\n \t\tprintf(__(\"(%s) Adding %s: %s from: '%s'\\n\"),\n \t\t       $prefix, $what, $address, $cmd) unless $quiet;\n \t\t}\n-\tclose $fh\n-\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n \treturn @addresses;\n }\n \n-- \n2.39.2\n\n"},{"id":"476056","messageId":"20230425185013.14351-3-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230425185013.14351-1-maxim.cournoyer@gmail.com","subject":"[PATCH v3 2/3] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T18:50:12Z","receivedAt":"2023-04-25T18:51:57Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Sometimes, adding a header different than CC or TO is desirable; for\nexample, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers\nto keep people in CC; this is an example use case enabled by the new\n'--header-cmd' option.\n\nThe header unfolding logic is extracted to a subroutine so that it can\nbe reused; a test is added for coverage.\n---\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   |  8 +++++\n git-send-email.perl                | 49 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 39 ++++++++++++++++++++++--\n 4 files changed, 84 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 51da7088a8..92a9ebe98c 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -61,6 +61,7 @@ sendemail.ccCmd::\n sendemail.chainReplyTo::\n sendemail.envelopeSender::\n sendemail.from::\n+sendemail.headerCmd::\n sendemail.signedoffbycc::\n sendemail.smtpPass::\n sendemail.suppresscc::\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b0f438ec99..295a3dd67c 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -320,6 +320,14 @@ Automating\n \tOutput of this command must be single email address per line.\n \tDefault is the value of `sendemail.ccCmd` configuration value.\n \n+--header-cmd=<command>::\n+\tSpecify a command that is executed once per outgoing message\n+\tand output RFC 2822 style header lines to be inserted into\n+\tthem. When the `sendemail.headerCmd` configuration variable is\n+\tset, its value is always used. When --header-cmd is provided\n+\tat the command line, its value takes precedence over the\n+\t`sendemail.headerCmd` configuration variable.\n+\n --[no-]chain-reply-to::\n \tIf this is set, each email will be sent as a reply to the previous\n \temail sent.  If disabled with \"--no-chain-reply-to\", all emails after\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex b8d77ad214..666b37adc9 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -88,8 +88,9 @@ sub usage {\n \n   Automating:\n     --identity              <str>  * Use the sendemail.<id> options.\n-    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`\n-    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`\n+    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`.\n+    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`.\n+    --header-cmd            <str>  * Add headers via `<str> \\$patch_path`.\n     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.\n     --[no-]cc-cover                * Email Cc: addresses in the cover letter.\n     --[no-]to-cover                * Email To: addresses in the cover letter.\n@@ -270,7 +271,7 @@ sub do_edit {\n # Variables with corresponding config settings\n my ($suppress_from, $signed_off_by_cc);\n my ($cover_cc, $cover_to);\n-my ($to_cmd, $cc_cmd);\n+my ($to_cmd, $cc_cmd, $header_cmd);\n my ($smtp_server, $smtp_server_port, @smtp_server_options);\n my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);\n my ($batch_size, $relogin_delay);\n@@ -319,6 +320,7 @@ sub do_edit {\n     \"tocmd\" => \\$to_cmd,\n     \"cc\" => \\@config_cc,\n     \"cccmd\" => \\$cc_cmd,\n+    \"headercmd\" => \\$header_cmd,\n     \"aliasfiletype\" => \\$aliasfiletype,\n     \"bcc\" => \\@config_bcc,\n     \"suppresscc\" => \\@suppress_cc,\n@@ -520,6 +522,7 @@ sub config_regexp {\n \t\t    \"compose\" => \\$compose,\n \t\t    \"quiet\" => \\$quiet,\n \t\t    \"cc-cmd=s\" => \\$cc_cmd,\n+\t\t    \"header-cmd=s\" => \\$header_cmd,\n \t\t    \"suppress-from!\" => \\$suppress_from,\n \t\t    \"no-suppress-from\" => sub {$suppress_from = 0},\n \t\t    \"suppress-cc=s\" => \\@suppress_cc,\n@@ -1766,17 +1769,15 @@ sub process_file {\n \t$subject = $initial_subject;\n \t$message = \"\";\n \t$message_num++;\n-\t# First unfold multiline header fields\n+\t# Retrieve and unfold header fields.\n+\tmy @header_lines = ();\n \twhile(<$fh>) {\n \t\tlast if /^\\s*$/;\n-\t\tif (/^\\s+\\S/ and @header) {\n-\t\t\tchomp($header[$#header]);\n-\t\t\ts/^\\s+/ /;\n-\t\t\t$header[$#header] .= $_;\n-\t    } else {\n-\t\t\tpush(@header, $_);\n-\t\t}\n+\t\tpush(@header_lines, $_);\n \t}\n+\t@header = unfold_headers(@header_lines);\n+\t# Add computed headers, if applicable.\n+\tpush @header, invoke_header_cmd($header_cmd, $t) if defined $header_cmd;\n \t# Now parse the header\n \tforeach(@header) {\n \t\tif (/^From /) {\n@@ -2022,6 +2023,32 @@ sub execute_cmd {\n \treturn @lines;\n }\n \n+# Process headers lines, unfolding multiline headers as defined by RFC\n+# 2822.\n+sub unfold_headers {\n+\tmy @headers;\n+\tforeach(@_) {\n+\t\tlast if /^\\s*$/;\n+\t\tif (/^\\s+\\S/ and @headers) {\n+\t\t\tchomp($headers[$#headers]);\n+\t\t\ts/^\\s+/ /;\n+\t\t\t$headers[$#headers] .= $_;\n+\t\t} else {\n+\t\t\tpush(@headers, $_);\n+\t\t}\n+\t}\n+\treturn @headers;\n+}\n+\n+# Invoke the provided CMD with FILE as an argument, which should\n+# output RFC 2822 email headers. Fold multiline headers and return the\n+# headers as an array.\n+sub invoke_header_cmd {\n+\tmy ($cmd, $file) = @_;\n+\tmy @lines = execute_cmd(\"header-cmd\", $header_cmd, $file);\n+\treturn unfold_headers(@lines);\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 0de83b5d2b..230f436f23 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -374,13 +374,16 @@ 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+test_expect_success $PREREQ 'setup cmd scripts' '\n \twrite_script tocmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^tocmd--//p\" \"$1\"\n \tEOF\n-\twrite_script cccmd-sed <<-\\EOF\n+\twrite_script cccmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^cccmd--//p\" \"$1\"\n \tEOF\n+\twrite_script headercmd-sed <<-\\EOF\n+\tsed -n -e \"s/^headercmd--//p\" \"$1\"\n+\tEOF\n '\n \n test_expect_success $PREREQ 'tocmd works' '\n@@ -410,6 +413,38 @@ test_expect_success $PREREQ 'cccmd works' '\n \tgrep \"^\tcccmd@example.com\" msgtxt1\n '\n \n+test_expect_success $PREREQ 'headercmd works' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\techo \"headercmd--X-Debbugs-CC: dummy@example.com\" >>headercmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch \\\n+\t\t&&\n+\tgrep \"^X-Debbugs-CC: dummy@example.com\" msgtxt1\n+'\n+\n+test_expect_success $PREREQ 'multiline fields are correctly unfolded' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\twrite_script headercmd-multiline <<-\\EOF &&\n+\techo \"X-Debbugs-CC: someone@example.com\n+FoldedField: This is a tale\n+ best told using\n+ multiple lines.\"\n+\tEOF\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-multiline \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch &&\n+\tgrep \"^FoldedField: This is a tale best told using multiple lines.$\" msgtxt1\n+'\n+\n test_expect_success $PREREQ 'reject long lines' '\n \tz8=zzzzzzzz &&\n \tz64=$z8$z8$z8$z8$z8$z8$z8$z8 &&\n-- \n2.39.2\n\n"},{"id":"476057","messageId":"20230425185013.14351-4-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230425185013.14351-1-maxim.cournoyer@gmail.com","subject":"[PATCH v3 3/3] send-email: detect empty blank lines in command output","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T18:50:13Z","receivedAt":"2023-04-25T18:52:04Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"The email format does not allow blank lines in headers; detect such\ninput and report it as malformed and add a test for it.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\n git-send-email.perl   | 12 ++++++++++--\n t/t9001-send-email.sh | 17 +++++++++++++++++\n 2 files changed, 27 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 666b37adc9..5adcbbeb49 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -2008,14 +2008,22 @@ sub process_file {\n \t}\n }\n \n-# Execute a command and return its output lines as an array.\n+# Execute a command and return its output lines as an array.  Blank\n+# lines which do not appear at the end of the output are reported as\n+# errors.\n sub execute_cmd {\n \tmy ($prefix, $cmd, $file) = @_;\n \tmy @lines = ();\n+\tmy $seen_blank_line = 0;\n \topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n \t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n \twhile (my $line = <$fh>) {\n-\t\tlast if $line =~ /^$/;\n+\t\tdie sprintf(__(\"(%s) Malformed output from '%s'\"), $prefix, $cmd)\n+\t\t    if $seen_blank_line;\n+\t\tif ($line =~ /^$/) {\n+\t\t\t$seen_blank_line = $line =~ /^$/;\n+\t\t\tnext;\n+\t\t}\n \t\tpush @lines, $line;\n \t}\n \tclose $fh\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 230f436f23..6701dd8848 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -445,6 +445,23 @@ FoldedField: This is a tale\n \tgrep \"^FoldedField: This is a tale best told using multiple lines.$\" msgtxt1\n '\n \n+# Blank lines in the middle of the output of a command are invalid.\n+test_expect_success $PREREQ 'malform output reported on blank lines in command output' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\twrite_script headercmd-malformed-output <<-\\EOF &&\n+\techo \"X-Debbugs-CC: someone@example.com\n+\n+SomeOtherField: someone-else@example.com\"\n+\tEOF\n+\t! git send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-malformed-output \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch\n+'\n+\n test_expect_success $PREREQ 'reject long lines' '\n \tz8=zzzzzzzz &&\n \tz64=$z8$z8$z8$z8$z8$z8$z8$z8 &&\n-- \n2.39.2\n\n"},{"id":"476061","messageId":"87leifpzco.fsf@gmail.com","threadId":"59639","inReplyTo":"xmqqcz3s3oz7.fsf@gitster.g","subject":"Re: [PATCH 2/2] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T18:53:59Z","receivedAt":"2023-04-25T18:55:09Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi Junio,\n\nJunio C Hamano <gitster@pobox.com> writes:\n\n> Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:\n>\n>> I'm not too familiar with the email format; but I presume an empty line\n>> would signal the end of a message?  That'd be bad yes, but I think it\n>> cannot currently happen given the 'last if $line =~ /^$/;' guard at in\n>> execute_cmd around line 2023; it'd means headers following an empty line\n>> would be discarded though.  The expected use case is indeed for a user's\n>> script to produce RFC 2822 style headers to messages.\n>\n> Yes, silently discarding the end-user input is what I meant by a\n> disaster.\n\nIn v3 just sent, empty blank lines are now detected and reported as an\nerror.\n\n>> The former (a true default with no way to turn it off other than\n>> redefining it), which I believe is the same behavior as for --cc-cmd or\n>> --to-cmd.  There are no '--no-cc-cmd' or '--no-to-cmd' options, although\n>> their result can be filtered via the '--no-cc' and '--no-to' options.\n>\n> Yup.\n>\n>> Looking in the source, options supporting '--no-' always appear to be\n>> boolean toggles (on/off) though, so I'm not sure how a '--no-header-cmd'\n>> that take a value can currently be implemented.  Perhaps it could be\n>> added later if there is a need?\n>\n> Perhaps we can do without a configuration variable first, and\n> perhaps the variable could be added later if there is a need and a\n> proper way to turn it off per invocation basis.\n\nI'd like to preserve the sendemail.headerCmd configuration variable; as\nit properly enables the use case that motivated this change :-).  If it\nmeans I need to add some ad-hoc --no-header-cmd, I can do so; let me\nknow!\n\n>> I've extracted such postprocessing into fold_headers and applied\n>> execute_cmd to it in new invoke_header_cmd subroutine.\n>\n> Sounds like a good approach (without looking the actual patch).\n\nOK.  Make sure to look at the latest revision, v3.\n\nThanks again!\n\n-- \nMaxim\n"},{"id":"476064","messageId":"87h6t3pyn1.fsf@gmail.com","threadId":"59639","inReplyTo":"CAPig+cQ+6m35cTXr20-BNyHRsQQq2nTNERCH8N9NMsUP8Ct7mA@mail.gmail.com","subject":"Re: [PATCH v2 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-04-25T19:09:22Z","receivedAt":"2023-04-25T19:09:37Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi Eric,\n\nEric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Tue, Apr 25, 2023 at 12:46 PM Maxim Cournoyer\n> <maxim.cournoyer@gmail.com> wrote:\n>> diff --git a/git-send-email.perl b/git-send-email.perl\n>> @@ -2,6 +2,7 @@\n>>  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n>>  # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n>> +# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n>\n> Let's avoid this change, please. Many people have worked on this file\n> over the years -- often making changes far more substantial than those\n> made by this patch series -- who have not staked such a claim.\n\nI don't mind to drop this hunk if it's unwelcome/not current practice.\nI didn't mean to try to steal anyone's spotlight :-).  I know this\ncontribution is tiny; I barely write Perl (it's still enough of a change\nto be protected by copyright though, but I don't mind too much).\n\nCheers,\n\n-- \nMaxim\n"},{"id":"476331","messageId":"20230501143848.19674-1-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"xmqqcz3s3oz7.fsf@gitster.g","subject":"[PATCH v4 0/3] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-01T14:38:45Z","receivedAt":"2023-05-01T14:39:23Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hello,\n\nThis v4 drops the copyright hunk as suggested by Eric, and adds a\n --no-header-cmd as suggested by Junio.\n\nThanks you!\n\nMaxim Cournoyer (3):\n  send-email: extract execute_cmd from recipients_cmd\n  send-email: add --header-cmd, --no-header-cmd options\n  send-email: detect empty blank lines in command output\n\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   | 11 ++++\n git-send-email.perl                | 87 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 71 +++++++++++++++++++++++-\n 4 files changed, 150 insertions(+), 20 deletions(-)\n\nDiff-intervalle contre v3 :\n-:  ---------- > 1:  4bc38e69bd send-email: extract execute_cmd from recipients_cmd\n-:  ---------- > 2:  60606e8d21 send-email: add --header-cmd, --no-header-cmd options.\n-:  ---------- > 3:  2ed6a3f965 send-email: detect empty blank lines in command output\n\nbase-commit: 48d89b51b3bb8a60580c36731b96a7206ce1e5b9\n-- \n2.39.2\n\n"},{"id":"476332","messageId":"20230501143848.19674-2-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230501143848.19674-1-maxim.cournoyer@gmail.com","subject":"[PATCH v4 1/3] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-01T14:38:46Z","receivedAt":"2023-05-01T14:39:30Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"This refactor is to pave the way for the addition of the new\n'--header-cmd' option to the send-email command.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\nNew in v4:\n- Drop copyright line.\n\n git-send-email.perl | 24 ++++++++++++++++++------\n 1 file changed, 18 insertions(+), 6 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 66c9171109..04503e3c3c 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -2021,15 +2021,29 @@ sub process_file {\n \t}\n }\n \n+# Execute a command and return its output lines as an array.\n+sub execute_cmd {\n+\tmy ($prefix, $cmd, $file) = @_;\n+\tmy @lines = ();\n+\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n+\t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n+\twhile (my $line = <$fh>) {\n+\t\tlast if $line =~ /^$/;\n+\t\tpush @lines, $line;\n+\t}\n+\tclose $fh\n+\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n+\treturn @lines;\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\n \tmy ($prefix, $what, $cmd, $file) = @_;\n-\n+\tmy @lines = ();\n \tmy @addresses = ();\n-\topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n-\t    or die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n-\twhile (my $address = <$fh>) {\n+\t@lines = execute_cmd($prefix, $cmd, $file);\n+\tfor my $address (@lines) {\n \t\t$address =~ s/^\\s*//g;\n \t\t$address =~ s/\\s*$//g;\n \t\t$address = sanitize_address($address);\n@@ -2038,8 +2052,6 @@ sub recipients_cmd {\n \t\tprintf(__(\"(%s) Adding %s: %s from: '%s'\\n\"),\n \t\t       $prefix, $what, $address, $cmd) unless $quiet;\n \t\t}\n-\tclose $fh\n-\t    or die sprintf(__(\"(%s) failed to close pipe to '%s'\"), $prefix, $cmd);\n \treturn @addresses;\n }\n \n-- \n2.39.2\n\n"},{"id":"476333","messageId":"20230501143848.19674-3-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230501143848.19674-1-maxim.cournoyer@gmail.com","subject":"[PATCH v4 2/3] send-email: add --header-cmd, --no-header-cmd options","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-01T14:38:47Z","receivedAt":"2023-05-01T14:39:32Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Sometimes, adding a header different than CC or TO is desirable; for\nexample, when using Debbugs, it is best to use 'X-Debbugs-Cc' headers\nto keep people in CC; this is an example use case enabled by the new\n'--header-cmd' option.\n\nThe header unfolding logic is extracted to a subroutine so that it can\nbe reused; a test is added for coverage.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\nNew in v4:\n- Add a --no-header-cmd.\n\n Documentation/config/sendemail.txt |  1 +\n Documentation/git-send-email.txt   | 11 ++++++\n git-send-email.perl                | 55 +++++++++++++++++++++++-------\n t/t9001-send-email.sh              | 54 +++++++++++++++++++++++++++--\n 4 files changed, 107 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt\nindex 51da7088a8..92a9ebe98c 100644\n--- a/Documentation/config/sendemail.txt\n+++ b/Documentation/config/sendemail.txt\n@@ -61,6 +61,7 @@ sendemail.ccCmd::\n sendemail.chainReplyTo::\n sendemail.envelopeSender::\n sendemail.from::\n+sendemail.headerCmd::\n sendemail.signedoffbycc::\n sendemail.smtpPass::\n sendemail.suppresscc::\ndiff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt\nindex b0f438ec99..4d2ae061f9 100644\n--- a/Documentation/git-send-email.txt\n+++ b/Documentation/git-send-email.txt\n@@ -320,6 +320,17 @@ Automating\n \tOutput of this command must be single email address per line.\n \tDefault is the value of `sendemail.ccCmd` configuration value.\n \n+--header-cmd=<command>::\n+\tSpecify a command that is executed once per outgoing message\n+\tand output RFC 2822 style header lines to be inserted into\n+\tthem. When the `sendemail.headerCmd` configuration variable is\n+\tset, its value is always used. When --header-cmd is provided\n+\tat the command line, its value takes precedence over the\n+\t`sendemail.headerCmd` configuration variable.\n+\n+--no-header-cmd::\n+\tDisable any header command in use.\n+\n --[no-]chain-reply-to::\n \tIf this is set, each email will be sent as a reply to the previous\n \temail sent.  If disabled with \"--no-chain-reply-to\", all emails after\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 04503e3c3c..32febe9af3 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -87,8 +87,10 @@ sub usage {\n \n   Automating:\n     --identity              <str>  * Use the sendemail.<id> options.\n-    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`\n-    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`\n+    --to-cmd                <str>  * Email To: via `<str> \\$patch_path`.\n+    --cc-cmd                <str>  * Email Cc: via `<str> \\$patch_path`.\n+    --header-cmd            <str>  * Add headers via `<str> \\$patch_path`.\n+    --no-header-cmd                * Disable any header command in use.\n     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, misc-by, all.\n     --[no-]cc-cover                * Email Cc: addresses in the cover letter.\n     --[no-]to-cover                * Email To: addresses in the cover letter.\n@@ -202,7 +204,7 @@ sub format_2822_time {\n \t$author,$sender,$smtp_authpass,$annotate,$compose,$time);\n # Things we either get from config, *or* are overridden on the\n # command-line.\n-my ($no_cc, $no_to, $no_bcc, $no_identity);\n+my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd);\n my (@config_to, @getopt_to);\n my (@config_cc, @getopt_cc);\n my (@config_bcc, @getopt_bcc);\n@@ -269,7 +271,7 @@ sub do_edit {\n # Variables with corresponding config settings\n my ($suppress_from, $signed_off_by_cc);\n my ($cover_cc, $cover_to);\n-my ($to_cmd, $cc_cmd);\n+my ($to_cmd, $cc_cmd, $header_cmd);\n my ($smtp_server, $smtp_server_port, @smtp_server_options);\n my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path);\n my ($batch_size, $relogin_delay);\n@@ -318,6 +320,7 @@ sub do_edit {\n     \"tocmd\" => \\$to_cmd,\n     \"cc\" => \\@config_cc,\n     \"cccmd\" => \\$cc_cmd,\n+    \"headercmd\" => \\$header_cmd,\n     \"aliasfiletype\" => \\$aliasfiletype,\n     \"bcc\" => \\@config_bcc,\n     \"suppresscc\" => \\@suppress_cc,\n@@ -519,6 +522,8 @@ sub config_regexp {\n \t\t    \"compose\" => \\$compose,\n \t\t    \"quiet\" => \\$quiet,\n \t\t    \"cc-cmd=s\" => \\$cc_cmd,\n+\t\t    \"header-cmd=s\" => \\$header_cmd,\n+\t\t    \"no-header-cmd\" => \\$no_header_cmd,\n \t\t    \"suppress-from!\" => \\$suppress_from,\n \t\t    \"no-suppress-from\" => sub {$suppress_from = 0},\n \t\t    \"suppress-cc=s\" => \\@suppress_cc,\n@@ -1780,16 +1785,16 @@ sub process_file {\n \t$subject = $initial_subject;\n \t$message = \"\";\n \t$message_num++;\n-\t# First unfold multiline header fields\n+\t# Retrieve and unfold header fields.\n+\tmy @header_lines = ();\n \twhile(<$fh>) {\n \t\tlast if /^\\s*$/;\n-\t\tif (/^\\s+\\S/ and @header) {\n-\t\t\tchomp($header[$#header]);\n-\t\t\ts/^\\s+/ /;\n-\t\t\t$header[$#header] .= $_;\n-\t    } else {\n-\t\t\tpush(@header, $_);\n-\t\t}\n+\t\tpush(@header_lines, $_);\n+\t}\n+\t@header = unfold_headers(@header_lines);\n+\t# Add computed headers, if applicable.\n+\tunless ($no_header_cmd || ! $header_cmd) {\n+\t\tpush @header, invoke_header_cmd($header_cmd, $t);\n \t}\n \t# Now parse the header\n \tforeach(@header) {\n@@ -2036,6 +2041,32 @@ sub execute_cmd {\n \treturn @lines;\n }\n \n+# Process headers lines, unfolding multiline headers as defined by RFC\n+# 2822.\n+sub unfold_headers {\n+\tmy @headers;\n+\tforeach(@_) {\n+\t\tlast if /^\\s*$/;\n+\t\tif (/^\\s+\\S/ and @headers) {\n+\t\t\tchomp($headers[$#headers]);\n+\t\t\ts/^\\s+/ /;\n+\t\t\t$headers[$#headers] .= $_;\n+\t\t} else {\n+\t\t\tpush(@headers, $_);\n+\t\t}\n+\t}\n+\treturn @headers;\n+}\n+\n+# Invoke the provided CMD with FILE as an argument, which should\n+# output RFC 2822 email headers. Fold multiline headers and return the\n+# headers as an array.\n+sub invoke_header_cmd {\n+\tmy ($cmd, $file) = @_;\n+\tmy @lines = execute_cmd(\"header-cmd\", $header_cmd, $file);\n+\treturn unfold_headers(@lines);\n+}\n+\n # Execute a command (e.g. $to_cmd) to get a list of email addresses\n # and return a results array\n sub recipients_cmd {\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex 6520346246..dfc5be581f 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -374,13 +374,16 @@ 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+test_expect_success $PREREQ 'setup cmd scripts' '\n \twrite_script tocmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^tocmd--//p\" \"$1\"\n \tEOF\n-\twrite_script cccmd-sed <<-\\EOF\n+\twrite_script cccmd-sed <<-\\EOF &&\n \tsed -n -e \"s/^cccmd--//p\" \"$1\"\n \tEOF\n+\twrite_script headercmd-sed <<-\\EOF\n+\tsed -n -e \"s/^headercmd--//p\" \"$1\"\n+\tEOF\n '\n \n test_expect_success $PREREQ 'tocmd works' '\n@@ -410,6 +413,53 @@ test_expect_success $PREREQ 'cccmd works' '\n \tgrep \"^\tcccmd@example.com\" msgtxt1\n '\n \n+test_expect_success $PREREQ 'headercmd works' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\techo \"headercmd--X-Debbugs-CC: dummy@example.com\" >>headercmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-sed \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch \\\n+\t\t&&\n+\tgrep \"^X-Debbugs-CC: dummy@example.com\" msgtxt1\n+'\n+\n+test_expect_success $PREREQ '--no-header-cmd works' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\techo \"headercmd--X-Debbugs-CC: dummy@example.com\" >>headercmd.patch &&\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-sed \\\n+                --no-header-cmd \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch \\\n+\t\t&&\n+\t! grep \"^X-Debbugs-CC: dummy@example.com\" msgtxt1\n+'\n+\n+test_expect_success $PREREQ 'multiline fields are correctly unfolded' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\twrite_script headercmd-multiline <<-\\EOF &&\n+\techo \"X-Debbugs-CC: someone@example.com\n+FoldedField: This is a tale\n+ best told using\n+ multiple lines.\"\n+\tEOF\n+\tgit send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-multiline \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch &&\n+\tgrep \"^FoldedField: This is a tale best told using multiple lines.$\" msgtxt1\n+'\n+\n test_expect_success $PREREQ 'reject long lines' '\n \tz8=zzzzzzzz &&\n \tz64=$z8$z8$z8$z8$z8$z8$z8$z8 &&\n-- \n2.39.2\n\n"},{"id":"476334","messageId":"20230501143848.19674-4-maxim.cournoyer@gmail.com","threadId":"59639","inReplyTo":"20230501143848.19674-1-maxim.cournoyer@gmail.com","subject":"[PATCH v4 3/3] send-email: detect empty blank lines in command output","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-01T14:38:48Z","receivedAt":"2023-05-01T14:39:34Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"The email format does not allow blank lines in headers; detect such\ninput and report it as malformed and add a test for it.\n\nSigned-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>\n---\n git-send-email.perl   | 12 ++++++++++--\n t/t9001-send-email.sh | 17 +++++++++++++++++\n 2 files changed, 27 insertions(+), 2 deletions(-)\n\ndiff --git a/git-send-email.perl b/git-send-email.perl\nindex 32febe9af3..22a64e608f 100755\n--- a/git-send-email.perl\n+++ b/git-send-email.perl\n@@ -2026,14 +2026,22 @@ sub process_file {\n \t}\n }\n \n-# Execute a command and return its output lines as an array.\n+# Execute a command and return its output lines as an array.  Blank\n+# lines which do not appear at the end of the output are reported as\n+# errors.\n sub execute_cmd {\n \tmy ($prefix, $cmd, $file) = @_;\n \tmy @lines = ();\n+\tmy $seen_blank_line = 0;\n \topen my $fh, \"-|\", \"$cmd \\Q$file\\E\"\n \t\tor die sprintf(__(\"(%s) Could not execute '%s'\"), $prefix, $cmd);\n \twhile (my $line = <$fh>) {\n-\t\tlast if $line =~ /^$/;\n+\t\tdie sprintf(__(\"(%s) Malformed output from '%s'\"), $prefix, $cmd)\n+\t\t    if $seen_blank_line;\n+\t\tif ($line =~ /^$/) {\n+\t\t\t$seen_blank_line = $line =~ /^$/;\n+\t\t\tnext;\n+\t\t}\n \t\tpush @lines, $line;\n \t}\n \tclose $fh\ndiff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh\nindex dfc5be581f..6519eea1ed 100755\n--- a/t/t9001-send-email.sh\n+++ b/t/t9001-send-email.sh\n@@ -460,6 +460,23 @@ FoldedField: This is a tale\n \tgrep \"^FoldedField: This is a tale best told using multiple lines.$\" msgtxt1\n '\n \n+# Blank lines in the middle of the output of a command are invalid.\n+test_expect_success $PREREQ 'malform output reported on blank lines in command output' '\n+\tclean_fake_sendmail &&\n+\tcp $patches headercmd.patch &&\n+\twrite_script headercmd-malformed-output <<-\\EOF &&\n+\techo \"X-Debbugs-CC: someone@example.com\n+\n+SomeOtherField: someone-else@example.com\"\n+\tEOF\n+\t! git send-email \\\n+\t\t--from=\"Example <nobody@example.com>\" \\\n+\t\t--to=nobody@example.com \\\n+\t\t--header-cmd=./headercmd-malformed-output \\\n+\t\t--smtp-server=\"$(pwd)/fake.sendmail\" \\\n+\t\theadercmd.patch\n+'\n+\n test_expect_success $PREREQ 'reject long lines' '\n \tz8=zzzzzzzz &&\n \tz64=$z8$z8$z8$z8$z8$z8$z8$z8 &&\n-- \n2.39.2\n\n"},{"id":"476447","messageId":"645158de9d0d0_1ba2d294a6@chronos.notmuch","threadId":"59639","inReplyTo":"87h6t3pyn1.fsf@gmail.com","subject":"Re: [PATCH v2 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-05-02T18:39:26Z","receivedAt":"2023-05-02T18:39:35Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Maxim Cournoyer wrote:\n> Eric Sunshine <sunshine@sunshineco.com> writes:\n> \n> > On Tue, Apr 25, 2023 at 12:46 PM Maxim Cournoyer\n> > <maxim.cournoyer@gmail.com> wrote:\n> >> diff --git a/git-send-email.perl b/git-send-email.perl\n> >> @@ -2,6 +2,7 @@\n> >>  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n> >>  # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n> >> +# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n> >\n> > Let's avoid this change, please. Many people have worked on this file\n> > over the years -- often making changes far more substantial than those\n> > made by this patch series -- who have not staked such a claim.\n> \n> I don't mind to drop this hunk if it's unwelcome/not current practice.\n\nIn most open source projects the practice is that only the top one or two\ncontributors are mentioned.\n\n> it's still enough of a change to be protected by copyright though, but\n> I don't mind too much.\n\nMy understanding is that your work is protected by copyright laws\nregardless of whether or not a copyright notice exists. Not that it\nwould matter much in practice though, because the cases where copyright\nmatters in open source projects is very fringe.\n\nCheers.\n\n-- \nFelipe Contreras"},{"id":"476457","messageId":"871qjy31iu.fsf@gmail.com","threadId":"59639","inReplyTo":"645158de9d0d0_1ba2d294a6@chronos.notmuch","subject":"Re: [PATCH v2 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-02T20:46:01Z","receivedAt":"2023-05-02T20:46:09Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi,\n\nFelipe Contreras <felipe.contreras@gmail.com> writes:\n\n> Maxim Cournoyer wrote:\n>> Eric Sunshine <sunshine@sunshineco.com> writes:\n>> \n>> > On Tue, Apr 25, 2023 at 12:46 PM Maxim Cournoyer\n>> > <maxim.cournoyer@gmail.com> wrote:\n>> >> diff --git a/git-send-email.perl b/git-send-email.perl\n>> >> @@ -2,6 +2,7 @@\n>> >>  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n>> >>  # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n>> >> +# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n>> >\n>> > Let's avoid this change, please. Many people have worked on this file\n>> > over the years -- often making changes far more substantial than those\n>> > made by this patch series -- who have not staked such a claim.\n>> \n>> I don't mind to drop this hunk if it's unwelcome/not current practice.\n>\n> In most open source projects the practice is that only the top one or two\n> contributors are mentioned.\n\nI see.  I got used adding copyright lines from contributing to GNU Guix,\nwhich retains everyone's minimally substantial changes copyright notices\n(if they wish), but that's probably not too common, given even the GNU\nmaintainer's manual says [0]:\n\n   But if contributors are not all assigning their copyrights to a\n   single copyright holder, it can easily happen that one file has\n   several copyright holders. Each contributor of nontrivial text is a\n   copyright holder.\n\n   In that case, you should always include a copyright notice in the\n   name of main copyright holder of the file. You can also include\n   copyright notices for other copyright holders as well, and this is a\n   good idea for those who have contributed a large amount and for those\n   who specifically ask for notices in their names. (Sometimes the\n   license on code that you copy in may require preserving certain\n   copyright notices.) But you don’t have to include a notice for\n   everyone who contributed to the file (which would be rather\n   inconvenient).\n\n[0]  https://www.gnu.org/prep/maintain/html_node/Copyright-Notices.html\n\n>> it's still enough of a change to be protected by copyright though, but\n>> I don't mind too much.\n>\n> My understanding is that your work is protected by copyright laws\n> regardless of whether or not a copyright notice exists. Not that it\n> would matter much in practice though, because the cases where copyright\n> matters in open source projects is very fringe.\n\nYou are right; written works are automatically protected by copyright.\nI think copyright ownership would matter in case the copyright holders\nwant to intent legal action against an entity violating the license of\nthe Git project (GPL v2).  Hopefully that'll never be necessary.\n\n-- \nThanks,\nMaxim\n"},{"id":"476469","messageId":"6451858c41a39_200ae294c3@chronos.notmuch","threadId":"59639","inReplyTo":"871qjy31iu.fsf@gmail.com","subject":"Re: [PATCH v2 1/2] send-email: extract execute_cmd from recipients_cmd","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-05-02T21:50:04Z","receivedAt":"2023-05-02T21:50:10Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Maxim Cournoyer wrote:\n> Felipe Contreras <felipe.contreras@gmail.com> writes:\n> \n> > Maxim Cournoyer wrote:\n> >> Eric Sunshine <sunshine@sunshineco.com> writes:\n> >> \n> >> > On Tue, Apr 25, 2023 at 12:46 PM Maxim Cournoyer\n> >> > <maxim.cournoyer@gmail.com> wrote:\n> >> >> diff --git a/git-send-email.perl b/git-send-email.perl\n> >> >> @@ -2,6 +2,7 @@\n> >> >>  # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>\n> >> >>  # Copyright 2005 Ryan Anderson <ryan@michonline.com>\n> >> >> +# Copyright 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>\n> >> >\n> >> > Let's avoid this change, please. Many people have worked on this file\n> >> > over the years -- often making changes far more substantial than those\n> >> > made by this patch series -- who have not staked such a claim.\n> >> \n> >> I don't mind to drop this hunk if it's unwelcome/not current practice.\n> >\n> > In most open source projects the practice is that only the top one or two\n> > contributors are mentioned.\n> \n> I see.  I got used adding copyright lines from contributing to GNU Guix,\n> which retains everyone's minimally substantial changes copyright notices\n> (if they wish), but that's probably not too common, given even the GNU\n> maintainer's manual says [0]:\n\nI would say GNU practices are not what most OSS projects follow.\n\n> >> it's still enough of a change to be protected by copyright though, but\n> >> I don't mind too much.\n> >\n> > My understanding is that your work is protected by copyright laws\n> > regardless of whether or not a copyright notice exists. Not that it\n> > would matter much in practice though, because the cases where copyright\n> > matters in open source projects is very fringe.\n> \n> You are right; written works are automatically protected by copyright.\n> I think copyright ownership would matter in case the copyright holders\n> want to intent legal action against an entity violating the license of\n> the Git project (GPL v2).  Hopefully that'll never be necessary.\n\nYes, that is one instance, but it only matters if your wishes contradict those\nof the other copyright holders, that is: they want to sue, and you don't, or\nyou don't want to sue, and they do. As long as your wishes align the those of\nthe other developers in the Git community, it doesn't matter.\n\nCheers.\n\n-- \nFelipe Contreras"},{"id":"476746","messageId":"87r0rqvp2z.fsf@gmail.com","threadId":"59639","inReplyTo":"20230501143848.19674-1-maxim.cournoyer@gmail.com","subject":"Re: [PATCH v4 0/3] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-08T15:07:48Z","receivedAt":"2023-05-08T15:07:53Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi,\n\nJust checking if everything is OK with this submission?  If not, let me\nknow.\n\nThanks you,\n\n-- \nMaxim\n"},{"id":"476763","messageId":"CAPig+cTEngaoEbipX9cFSZn3Mro5qW_OKeK32Wkoof-cy0jBiA@mail.gmail.com","threadId":"59639","inReplyTo":"87r0rqvp2z.fsf@gmail.com","subject":"Re: [PATCH v4 0/3] send-email: add --header-cmd option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-05-08T16:59:42Z","receivedAt":"2023-05-08T17:00:18Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, May 8, 2023 at 11:07 AM Maxim Cournoyer\n<maxim.cournoyer@gmail.com> wrote:\n> Just checking if everything is OK with this submission?  If not, let me\n> know.\n\nAccording to Junio's most recent \"What's Cooking\"[1], this patch\nseries is slated to be merged to his \"next\" branch, which means there\nis nothing else you need to do. Eventually it should make it into\n\"master\" and (presumably) into an actual release. You can monitor the\n\"What's Cooking\" emails to see how the patch series progresses.\n\n[1]: https://lore.kernel.org/git/xmqqmt2ibcq2.fsf@gitster.g/\n"},{"id":"476795","messageId":"87wn1ityw7.fsf@gmail.com","threadId":"59639","inReplyTo":"CAPig+cTEngaoEbipX9cFSZn3Mro5qW_OKeK32Wkoof-cy0jBiA@mail.gmail.com","subject":"Re: [PATCH v4 0/3] send-email: add --header-cmd option","fromName":"Maxim Cournoyer","fromEmail":"maxim.cournoyer@gmail.com","sentAt":"2023-05-08T19:18:48Z","receivedAt":"2023-05-08T19:19:26Z","isPatch":true,"sender":{"key":"maxim.cournoyer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8332263?v=4"},"body":"Hi Eric,\n\nEric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Mon, May 8, 2023 at 11:07 AM Maxim Cournoyer\n> <maxim.cournoyer@gmail.com> wrote:\n>> Just checking if everything is OK with this submission?  If not, let me\n>> know.\n>\n> According to Junio's most recent \"What's Cooking\"[1], this patch\n> series is slated to be merged to his \"next\" branch, which means there\n> is nothing else you need to do. Eventually it should make it into\n> \"master\" and (presumably) into an actual release. You can monitor the\n> \"What's Cooking\" emails to see how the patch series progresses.\n>\n> [1]: https://lore.kernel.org/git/xmqqmt2ibcq2.fsf@gitster.g/\n\nOK, great!  Thanks for the update and link.\n\n-- \nMaxim\n"}]}