--- /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 1FA52431FC3\r
+ for <notmuch@notmuchmail.org>; Mon, 16 Jul 2012 23:04:47 -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 3kmB97ShtoIg for <notmuch@notmuchmail.org>;\r
+ Mon, 16 Jul 2012 23:04:45 -0700 (PDT)\r
+X-Greylist: delayed 1617 seconds by postgrey-1.32 at olra;\r
+ Mon, 16 Jul 2012 23:04:45 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 2371A431FBC\r
+ for <notmuch@notmuchmail.org>; Mon, 16 Jul 2012 23:04:45 -0700 (PDT)\r
+Received: from [78.46.5.204] (helo=sslproxy02.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>)\r
+ id 1Sr0Tf-00010u-Ig; Tue, 17 Jul 2012 07:37:43 +0200\r
+Received: from [188.194.53.208] (helo=localhost.localdomain)\r
+ by sslproxy02.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>)\r
+ id 1Sr0Te-0001dT-16; Tue, 17 Jul 2012 07:37:42 +0200\r
+From: Dominik Peteler <dominik@with-h.at>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH] cli: Hooks for tag-command\r
+Date: Tue, 17 Jul 2012 07:36:13 +0200\r
+Message-Id: <1342503373-16979-1-git-send-email-dominik@with-h.at>\r
+X-Mailer: git-send-email 1.7.11.2\r
+X-Authenticated-Sender: dude@with-h.at\r
+X-Virus-Scanned: Clear (ClamAV 0.97.3/15142/Tue Jul 17 04:44:44 2012)\r
+X-Mailman-Approved-At: Tue, 17 Jul 2012 14:24:57 -0700\r
+Cc: Dominik Peteler <dominik@with-h.at>\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: Tue, 17 Jul 2012 06:04:47 -0000\r
+\r
+hello,\r
+\r
+I attached some modifications which I made to notmuch. Comes with man pages and test.\r
+\r
+regards\r
+\r
+dominik\r
+\r
+\r
+\r
+There are two hooks:\r
+ * pre-tag: Run before tagging\r
+ * post-tag: Run after\r
+\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 | 17 +++++++++++++++++\r
+ man/man5/notmuch-hooks.5 | 23 +++++++++++++++++++++++\r
+ notmuch-tag.c | 25 +++++++++++++++++++++----\r
+ test/hooks | 36 ++++++++++++++++++++++++++++++++++++\r
+ 4 files changed, 97 insertions(+), 4 deletions(-)\r
+\r
+diff --git a/man/man1/notmuch-tag.1 b/man/man1/notmuch-tag.1\r
+index d810e1b..8d8b7b2 100644\r
+--- a/man/man1/notmuch-tag.1\r
++++ b/man/man1/notmuch-tag.1\r
+@@ -4,6 +4,7 @@ notmuch-tag \- add/remove tags for all messages matching the search terms\r
+ \r
+ .SH SYNOPSIS\r
+ .B notmuch tag\r
++.RB "[" --no-hooks "]"\r
+ .RI "+<" tag> "|\-<" tag "> [...] [\-\-] <" search-term ">..."\r
+ \r
+ .SH DESCRIPTION\r
+@@ -29,6 +30,22 @@ updates the maildir flags according to tag changes if the\r
+ configuration option is enabled. See \fBnotmuch-config\fR(1) for\r
+ details.\r
+ \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
+ \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..7399627 100644\r
+--- a/man/man5/notmuch-hooks.5\r
++++ b/man/man5/notmuch-hooks.5\r
+@@ -38,6 +38,29 @@ the scan or import.\r
+ Typically this hook is used to perform additional query\-based tagging on 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 of the\r
++.B tag\r
++command.\r
++\r
++Typically this hook is used for syncing the Maildir with notmuch tags.\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 there have been any errors during\r
++the tagging.\r
++\r
++Typically this hook is used for syncing the Maildir with notmuch tags.\r
++.RE\r
++\r
+ \r
+ .SH SEE ALSO\r
+ \r
+diff --git a/notmuch-tag.c b/notmuch-tag.c\r
+index 7d18639..e98d3a0 100644\r
+--- a/notmuch-tag.c\r
++++ b/notmuch-tag.c\r
+@@ -174,9 +174,11 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+ int tag_ops_count = 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
++ notmuch_bool_t run_hooks = TRUE;\r
+ int i;\r
+ int ret;\r
+ \r
+@@ -198,11 +200,12 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+ }\r
+ \r
+ for (i = 0; i < argc; i++) {\r
+- if (strcmp (argv[i], "--") == 0) {\r
++ if (strcmp (argv[i], "--no-hooks") == 0) {\r
++ run_hooks = FALSE;\r
++ } else if (strcmp (argv[i], "--") == 0) {\r
+ i++;\r
+ break;\r
+- }\r
+- if (argv[i][0] == '+' || argv[i][0] == '-') {\r
++ } else if (argv[i][0] == '+' || argv[i][0] == '-') {\r
+ tag_ops[tag_ops_count].tag = argv[i] + 1;\r
+ tag_ops[tag_ops_count].remove = (argv[i][0] == '-');\r
+ tag_ops_count++;\r
+@@ -229,7 +232,15 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+ if (config == NULL)\r
+ return 1;\r
+ \r
+- if (notmuch_database_open (notmuch_config_get_database_path (config),\r
++ db_path = notmuch_config_get_database_path (config);\r
++\r
++ if (run_hooks) {\r
++ ret = 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
+ \r
+@@ -239,5 +250,11 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])\r
+ \r
+ notmuch_database_destroy (notmuch);\r
+ \r
++ if (run_hooks) {\r
++ ret = notmuch_run_hook (db_path, "post-tag");\r
++ if (ret)\r
++ return ret;\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
+ \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
+ \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=`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)" "notmuch tag +foo -- '*'"\r
++\r
+ test_done\r
+-- \r
+1.7.11.2\r
+\r