--- /dev/null
+Return-Path: <dominik@with-h.at>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id 7481B431FBF\r
+ for <notmuch@notmuchmail.org>; Mon, 30 Jul 2012 05:41:19 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none]\r
+ autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id Uss7dRFTcjhE for <notmuch@notmuchmail.org>;\r
+ Mon, 30 Jul 2012 05:41:17 -0700 (PDT)\r
+Received: from www73.your-server.de (www73.your-server.de [213.133.104.73])\r
+ (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
+ (No client certificate requested)\r
+ by olra.theworths.org (Postfix) with ESMTPS id 126A9431FAE\r
+ for <notmuch@notmuchmail.org>; Mon, 30 Jul 2012 05:41:17 -0700 (PDT)\r
+Received: from [78.46.5.203] (helo=sslproxy01.your-server.de)\r
+ by www73.your-server.de with esmtpsa (TLSv1:AES256-SHA:256)\r
+ (Exim 4.74) (envelope-from <dominik@with-h.at>) id 1SvpHa-0002ER-O6\r
+ for notmuch@notmuchmail.org; Mon, 30 Jul 2012 14:41:10 +0200\r
+Received: from [132.187.246.115] (helo=fuckup.uni-wuerzburg.de)\r
+ by sslproxy01.your-server.de with esmtpsa\r
+ (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.72)\r
+ (envelope-from <dominik@with-h.at>) id 1SvpHR-0003tl-IF\r
+ for notmuch@notmuchmail.org; Mon, 30 Jul 2012 14:41:02 +0200\r
+Date: Mon, 30 Jul 2012 14:39:28 +0200\r
+From: Dominik Peteler <dominik@with-h.at>\r
+To: notmuch@notmuchmail.org\r
+Subject: Re: [PATCHv2] cli: Hooks for tag-command\r
+Message-ID: <20120730123928.GA749@fuckup.uni-wuerzburg.de>\r
+References:\r
+ <CAB+hUn_XHQQ9MDaVXvOMzfM8SdKCWUgnjNQvxJaQWWyc3H621Q@mail.gmail.com>\r
+ <1342634970-12991-1-git-send-email-dominik@with-h.at>\r
+MIME-Version: 1.0\r
+Content-Type: multipart/signed; micalg=pgp-sha1;\r
+ protocol="application/pgp-signature"; boundary="5vNYLRcllDrimb99"\r
+Content-Disposition: inline\r
+In-Reply-To: <1342634970-12991-1-git-send-email-dominik@with-h.at>\r
+X-PGP-Key: http://www.with-h.at/pubkey.asc\r
+User-Agent: Mutt/1.5.21 (2011-07-01)\r
+X-Authenticated-Sender: dude@with-h.at\r
+X-Virus-Scanned: Clear (ClamAV 0.97.3/15190/Mon Jul 30 10:41:49 2012)\r
+X-Mailman-Approved-At: Mon, 30 Jul 2012 06:47:37 -0700\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Mon, 30 Jul 2012 12:41:19 -0000\r
+\r
+\r
+--5vNYLRcllDrimb99\r
+Content-Type: text/plain; charset=us-ascii\r
+Content-Disposition: inline\r
+Content-Transfer-Encoding: quoted-printable\r
+\r
+hello,\r
+\r
+I hope I don't bother you but so far I didn't get any reply to my last mail=\r
+ with the patch for tag-command hooks.\r
+Did you accept the patch or not ? If not, please tell my if I can improve i=\r
+t.\r
+And do you have a opinion about my suggestion to pass the message-ids of re=\r
+tagged mails to the hook ?\r
+\r
+regards\r
+\r
+dominik\r
+\r
+\r
+\r
+On Wed 2012-07-18 20:09, Dominik Peteler wrote:\r
+> hello,\r
+>=20\r
+> I improved my patch according to Janis mail:\r
+> * new cli syntax: notmuch tag [ --no-hooks ] -- <tag ops> [ -- ] <search=\r
+ terms>\r
+> * adjusted man pages and wrote tests\r
+>=20\r
+> I had the idea to improve this feature by passing the message-ids or the =\r
+filename to the hooks.\r
+> What's your opinion about that ? Any suggestions ?\r
+>=20\r
+> regards\r
+>=20\r
+> dominik\r
+>=20\r
+>=20\r
+>=20\r
+> There are two hooks:\r
+> * pre-tag: Run before tagging\r
+> * post-tag: Run after\r
+>=20\r
+> This allows users to react on changes of tags. For example,\r
+> you might want to move a message to a special Maildir\r
+> depending on its notmuch tags.\r
+> ---\r
+> man/man1/notmuch-tag.1 | 22 +++++++++++++++++++-\r
+> man/man5/notmuch-hooks.5 | 19 ++++++++++++++++++\r
+> notmuch-tag.c | 52 ++++++++++++++++++++++++++++++++++++++++++=\r
++++---\r
+> test/hooks | 36 +++++++++++++++++++++++++++++++++\r
+> test/tagging | 28 ++++++++++++++++++++++++++\r
+> 5 files changed, 153 insertions(+), 4 deletions(-)\r
+>=20\r
+> diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1\r
+> index d810e1b..e00e189 100644\r
+> --- a/man/man1/notmuch-tag.1\r
+> +++ b/man/man1/notmuch-tag.1\r
+> @@ -4,7 +4,11 @@ notmuch-tag \- add/remove tags for all messages matching=\r
+ the search terms\r
+> =20\r
+> .SH SYNOPSIS\r
+> .B notmuch tag\r
+> -.RI "+<" tag> "|\-<" tag "> [...] [\-\-] <" search-term ">..."\r
+> +.RI "+<" tag "> |\-<" tag "> [...] [\-\-] <" search-term ">..."\r
+> +\r
+> +.B notmuch tag\r
+> +.RB "[" --no-hooks "]"\r
+> +.RI "\-\- +<" tag "> |\-<" tag "> [...] \-\- <" search-term ">..."\r
+> =20\r
+> .SH DESCRIPTION\r
+> =20\r
+> @@ -29,6 +33,22 @@ updates the maildir flags according to tag changes if =\r
+the\r
+> configuration option is enabled. See \fBnotmuch-config\fR(1) for\r
+> details.\r
+> =20\r
+> +The\r
+> +.B tag\r
+> +command supports hooks. See \fBnotmuch-hooks(5)\fR\r
+> +for more details on hooks.\r
+> +\r
+> +Supported options for\r
+> +.B tag\r
+> +include\r
+> +.RS 4\r
+> +.TP 4\r
+> +.BR \-\-no\-hooks\r
+> +\r
+> +Prevents hooks from being run.\r
+> +.RE\r
+> +.RE\r
+> +\r
+> .SH SEE ALSO\r
+> =20\r
+> \fBnotmuch\fR(1), \fBnotmuch-config\fR(1), \fBnotmuch-count\fR(1),\r
+> diff --git a/man/man5/notmuch-hooks.5 b/man/man5/notmuch-hooks.5\r
+> index b914a29..e193ef5 100644\r
+> --- a/man/man5/notmuch-hooks.5\r
+> +++ b/man/man5/notmuch-hooks.5\r
+> @@ -38,6 +38,25 @@ the scan or import.\r
+> Typically this hook is used to perform additional query\-based tagging o=\r
+n the\r
+> imported messages.\r
+> .RE\r
+> +.RS 4\r
+> +.TP 4\r
+> +.B pre\-tag\r
+> +This hook is invoked by the\r
+> +.B tag\r
+> +command before tagging messages. If this\r
+> +hook exits with a non-zero status, notmuch will abort further processing=\r
+ of the\r
+> +.B tag\r
+> +command.\r
+> +.RE\r
+> +.RS 4\r
+> +.TP 4\r
+> +.B post\-tag\r
+> +This hook is invoked by the\r
+> +.B tag\r
+> +command after messages have been tagged. The hook will not be run if the=\r
+re have been any errors during\r
+> +the tagging.\r
+> +.RE\r
+> +\r
+> =20\r
+> .SH SEE ALSO\r
+> =20\r
+> diff --git a/notmuch-tag.c b/notmuch-tag.c\r
+> index 7d18639..7572059 100644\r
+> --- a/notmuch-tag.c\r
+> +++ b/notmuch-tag.c\r
+> @@ -174,9 +174,17 @@ notmuch_tag_command (void *ctx, int argc, char *argv=\r
+[])\r
+> int tag_ops_count =3D 0;\r
+> char *query_string;\r
+> notmuch_config_t *config;\r
+> + const char *db_path;\r
+> notmuch_database_t *notmuch;\r
+> struct sigaction action;\r
+> notmuch_bool_t synchronize_flags;\r
+> + /* Points to the position of the "--" delimiters, e. g.\r
+> + * <optional arguments> arg_delimiters[0] <tag ops> arg_delimiter=\r
+s[1] <search terms>\r
+> + *\r
+> + * arg_delimiters[0] may remain -1 if there are no arguments given\r
+> + * arg_delimiters[0] may remain -1 if there is no delimiter between =\r
+tag ops and search terms */\r
+> + int arg_delimiters[2] =3D {-1, -1};\r
+> + notmuch_bool_t run_hooks =3D TRUE;\r
+> int i;\r
+> int ret;\r
+> =20\r
+> @@ -197,11 +205,37 @@ notmuch_tag_command (void *ctx, int argc, char *arg=\r
+v[])\r
+> return 1;\r
+> }\r
+> =20\r
+> + /* Determine position of delimiters */\r
+> for (i =3D 0; i < argc; i++) {\r
+> if (strcmp (argv[i], "--") =3D=3D 0) {\r
+> - i++;\r
+> - break;\r
+> + if (arg_delimiters[1] =3D=3D -1) {\r
+> + arg_delimiters[1] =3D i;\r
+> + } else if (arg_delimiters[0] =3D=3D -1) {\r
+> + arg_delimiters[0] =3D arg_delimiters[1];\r
+> + arg_delimiters[1] =3D i;\r
+> + } else {\r
+> + fprintf (stderr, "Error: 'notmuch tag' requires delimiter \"--\" at mo=\r
+st two times.\n");\r
+> + return 1;\r
+> + }\r
+> }\r
+> + }\r
+> +\r
+> + /* Process arguments if present */\r
+> + for (i =3D 0; i < arg_delimiters[0]; i++) {\r
+> + if (strcmp (argv[i], "--no-hooks") =3D=3D 0) {\r
+> + run_hooks =3D FALSE;\r
+> + } else {\r
+> + fprintf (stderr, "Error: 'notmuch tag' doesn't recognize argument '=\r
+%s'.\n", argv[i]);\r
+> + return 1;\r
+> + }\r
+> + }\r
+> +\r
+> + /* Set arg_delimiters[1] to argc if no delimiters at all are present=\r
+ */\r
+> + if (arg_delimiters[1] =3D=3D -1)\r
+> + arg_delimiters[1] =3D argc;\r
+> +\r
+> + /* Read tag ops */\r
+> + for (i =3D arg_delimiters[0]+1; i < arg_delimiters[1]; i++) {\r
+> if (argv[i][0] =3D=3D '+' || argv[i][0] =3D=3D '-') {\r
+> tag_ops[tag_ops_count].tag =3D argv[i] + 1;\r
+> tag_ops[tag_ops_count].remove =3D (argv[i][0] =3D=3D '-');\r
+> @@ -229,7 +263,15 @@ notmuch_tag_command (void *ctx, int argc, char *argv=\r
+[])\r
+> if (config =3D=3D NULL)\r
+> return 1;\r
+> =20\r
+> - if (notmuch_database_open (notmuch_config_get_database_path (config),\r
+> + db_path =3D notmuch_config_get_database_path (config);\r
+> +\r
+> + if (run_hooks) {\r
+> + ret =3D notmuch_run_hook (db_path, "pre-tag");\r
+> + if (ret)\r
+> + return ret;\r
+> + }\r
+> +\r
+> + if (notmuch_database_open (db_path,\r
+> NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))\r
+> return 1;\r
+> =20\r
+> @@ -239,5 +281,9 @@ notmuch_tag_command (void *ctx, int argc, char *argv[=\r
+])\r
+> =20\r
+> notmuch_database_destroy (notmuch);\r
+> =20\r
+> + if (!ret && run_hooks) {\r
+> + ret =3D notmuch_run_hook (db_path, "post-tag");\r
+> + }\r
+> +\r
+> return ret;\r
+> }\r
+> diff --git a/test/hooks b/test/hooks\r
+> index 77e8569..ae857cc 100755\r
+> --- a/test/hooks\r
+> +++ b/test/hooks\r
+> @@ -31,6 +31,7 @@ rm_hooks () {\r
+> # add a message to generate mail dir and database\r
+> add_message\r
+> =20\r
+> +# {pre,post}-new hooks\r
+> test_begin_subtest "pre-new is run"\r
+> rm_hooks\r
+> generate_message\r
+> @@ -101,4 +102,39 @@ EOF\r
+> chmod +x "${HOOK_DIR}/pre-new"\r
+> test_expect_code 1 "hook execution failure" "notmuch new"\r
+> =20\r
+> +\r
+> +\r
+> +# {pre,post}-tag hooks\r
+> +test_begin_subtest "pre-tag is run"\r
+> +rm_hooks\r
+> +generate_message\r
+> +create_echo_hook "pre-tag" expected output\r
+> +notmuch tag +foo -- '*' > /dev/null\r
+> +test_expect_equal_file expected output\r
+> +\r
+> +test_begin_subtest "post-tag is run"\r
+> +rm_hooks\r
+> +generate_message\r
+> +create_echo_hook "post-tag" expected output\r
+> +notmuch tag +foo -- '*' > /dev/null\r
+> +test_expect_equal_file expected output\r
+> +\r
+> +test_begin_subtest "pre-tag is run before post-new"\r
+> +rm_hooks\r
+> +generate_message\r
+> +create_echo_hook "pre-tag" pre-tag.expected pre-tag.output\r
+> +create_echo_hook "post-tag" post-tag.expected post-tag.output\r
+> +notmuch tag +foo -- '*' > /dev/null\r
+> +test_expect_equal_file post-tag.expected post-tag.output\r
+> +\r
+> +test_begin_subtest "pre-tag non-zero exit status (hook status)"\r
+> +rm_hooks\r
+> +generate_message\r
+> +create_failing_hook "pre-tag"\r
+> +output=3D`notmuch tag +foo -- '*' 2>&1`\r
+> +test_expect_equal "$output" "Error: pre-tag hook failed with status 13"\r
+> +\r
+> +# depends on the previous subtest leaving broken hook behind\r
+> +test_expect_code 1 "pre-tag non-zero exit status (notmuch status)" "notm=\r
+uch tag +foo -- '*'"\r
+> +\r
+> test_done\r
+> diff --git a/test/tagging b/test/tagging\r
+> index e4782ed..5167f4f 100755\r
+> --- a/test/tagging\r
+> +++ b/test/tagging\r
+> @@ -46,4 +46,32 @@ test_expect_equal "$output" "\\r
+> thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 u=\r
+nread)\r
+> thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 tag4 u=\r
+nread)"\r
+> =20\r
+> +test_begin_subtest "Arguments mixed with tag ops"\r
+> +notmuch tag +-no-hooks --no-hooks -- One\r
+> +notmuch tag --no-hooks +-no-hooks -tag4 -- Two\r
+> +output=3D$(notmuch search \* | notmuch_search_sanitize)\r
+> +test_expect_equal "$output" "\\r
+> +thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 u=\r
+nread)\r
+> +thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (-no-hooks inbox t=\r
+ag1 unread)"\r
+> +notmuch tag --no-hooks -- Two\r
+> +\r
+> +test_begin_subtest "Arguments with correct position"\r
+> +notmuch tag --no-hooks -- +tag4 -tag4 -- One\r
+> +output=3D$(notmuch search \* | notmuch_search_sanitize)\r
+> +test_expect_equal "$output" "\\r
+> +thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 u=\r
+nread)\r
+> +thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread=\r
+)"\r
+> +\r
+> +test_begin_subtest "Missing arguments"\r
+> +notmuch tag -- +tag4 -tag4 -- One\r
+> +output=3D$(notmuch search \* | notmuch_search_sanitize)\r
+> +test_expect_equal "$output" "\\r
+> +thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; One (:\" inbox tag1 u=\r
+nread)\r
+> +thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Two (inbox tag1 unread=\r
+)"\r
+> +\r
+> +test_begin_subtest "Unknown argument"\r
+> +output=3D$(notmuch tag --no-blubb -- +tag4 -tag4 -- One 2>&1)\r
+> +test_expect_equal "$output" "\\r
+> +Error: 'notmuch tag' doesn't recognize argument '--no-blubb'."\r
+> +\r
+> test_done\r
+> --=20\r
+> 1.7.11.2\r
+>=20\r
+\r
+--5vNYLRcllDrimb99\r
+Content-Type: application/pgp-signature\r
+\r
+-----BEGIN PGP SIGNATURE-----\r
+Version: GnuPG v2.0.19 (GNU/Linux)\r
+\r
+iQIcBAEBAgAGBQJQFoCAAAoJEFxmf0CweVkTFrkQAJtoYSf5F5C4+sRjc4QAqzZN\r
+Sa9ZUgDpacVhx5jcPgEwJpyAmTIoBl70jpZtUyz/r2/jb9ofcaRhRWi+SUhZUSDi\r
+cA0lSq4W9HoRvz0AiuggdgzE0ydungL+CJsrWwQZrVYnXMcpoVf+NIKCnkGU2dZo\r
+I7fGRWeSklfGysKehsKHX3G8UUzvicnr7EBd7gWN5+x9PE6RJZXNR/cx9YiRS03s\r
+n1kvfEPyyK3J8l2Gz42Vh16/RmFPAFc07/aIpylOp8l4qBz6WDWQy7gGFDjwFscU\r
+P4NlPC0fugCLawnF4z+H/5zffhLN9BL5LvsQ3p9AZ0PLLlmfVuke54y/g07PuIOO\r
+a4HyIeyhHsXdJcJYut7xFxzFN8kt89yfXtLVUSRO6OOAOwcGF8UEhdf6UYGKn3wZ\r
+zLMkF+vXmkDIKq7RfwvNX++pR/NXU14zDfZ5s1ywuZ0tBmmiqjfVa8hh1zh3HrdB\r
+PQGh2AnSFrZRCCcvXsmVVvCsybC6fKrldrNRB/q7lNyn6W8TyeKZObGu0cshHEi0\r
+KKNl5olunoiKUN2cSc8uoa9Kc1BFek91SLz0+gdOlV3FKlEGGBPnmihDanDFZATg\r
+07qw8XvcdK3/pSgNVVGRc6Lcr+xyYLJ1dC0dBB+jDQBlE4dj0guChF93IEa/MXTv\r
+Od3M+3RH8oSHRGMUvL1a\r
+=eWDC\r
+-----END PGP SIGNATURE-----\r
+\r
+--5vNYLRcllDrimb99--\r