--- /dev/null
+Return-Path: <keithp@keithp.com>\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 D65B1431FBF\r
+ for <notmuch@notmuchmail.org>; Fri, 20 Nov 2009 23:15:21 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\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 gqoniYFNYKxp for <notmuch@notmuchmail.org>;\r
+ Fri, 20 Nov 2009 23:15:17 -0800 (PST)\r
+Received: from keithp.com (home.keithp.com [63.227.221.253])\r
+ by olra.theworths.org (Postfix) with ESMTP id 64B03431FAE\r
+ for <notmuch@notmuchmail.org>; Fri, 20 Nov 2009 23:15:17 -0800 (PST)\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by keithp.com (Postfix) with ESMTP id CC404760222\r
+ for <notmuch@notmuchmail.org>; Fri, 20 Nov 2009 23:15:16 -0800 (PST)\r
+X-Virus-Scanned: Debian amavisd-new at keithp.com\r
+Received: from keithp.com ([127.0.0.1])\r
+ by localhost (keithp.com [127.0.0.1]) (amavisd-new, port 10024)\r
+ with LMTP id H3w9F2ijbayT; Fri, 20 Nov 2009 23:15:12 -0800 (PST)\r
+Received: by keithp.com (Postfix, from userid 1033)\r
+ id C5AC1B9404C; Fri, 20 Nov 2009 23:15:12 -0800 (PST)\r
+Received: from koto.keithp.com (localhost [127.0.0.1])\r
+ by keithp.com (Postfix) with ESMTP id C0C9076012C;\r
+ Fri, 20 Nov 2009 23:15:12 -0800 (PST)\r
+Received: by koto.keithp.com (Postfix, from userid 1488)\r
+ id 6C3681982A8; Fri, 20 Nov 2009 23:15:12 -0800 (PST)\r
+From: Keith Packard <keithp@keithp.com>\r
+To: notmuch@notmuchmail.org\r
+Date: Fri, 20 Nov 2009 23:15:07 -0800\r
+Message-Id: <1258787708-21121-2-git-send-email-keithp@keithp.com>\r
+X-Mailer: git-send-email 1.6.5.2\r
+In-Reply-To: <1258787708-21121-1-git-send-email-keithp@keithp.com>\r
+References: <1258787708-21121-1-git-send-email-keithp@keithp.com>\r
+Subject: [notmuch] [PATCH 2/3] Add 'notmuch count' command to show the count\r
+ of matching messages\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.12\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: Sat, 21 Nov 2009 07:15:22 -0000\r
+\r
+Getting the count of matching threads or messages is a fairly\r
+expensive operation. Xapian provides a very efficient mechanism that\r
+returns an approximate value, so use that for this new command.\r
+\r
+This returns the number of matching messages, not threads, as that is\r
+cheap to compute.\r
+\r
+Signed-off-by: Keith Packard <keithp@keithp.com>\r
+---\r
+ Makefile.local | 1 +\r
+ lib/notmuch.h | 8 ++++\r
+ lib/query.cc | 52 ++++++++++++++++++++++++++\r
+ notmuch-client.h | 3 +\r
+ notmuch-count.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\r
+ notmuch.c | 11 +++++\r
+ 6 files changed, 184 insertions(+), 0 deletions(-)\r
+ create mode 100644 notmuch-count.c\r
+\r
+diff --git a/Makefile.local b/Makefile.local\r
+index 3c99624..cbd75ce 100644\r
+--- a/Makefile.local\r
++++ b/Makefile.local\r
+@@ -5,6 +5,7 @@ emacs: notmuch.elc\r
+ notmuch_client_srcs = \\r
+ notmuch.c \\r
+ notmuch-config.c \\r
++ notmuch-count.c \\r
+ notmuch-dump.c \\r
+ notmuch-new.c \\r
+ notmuch-reply.c \\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index cc713a3..937f3b6 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -459,6 +459,14 @@ notmuch_threads_advance (notmuch_threads_t *threads);\r
+ void\r
+ notmuch_threads_destroy (notmuch_threads_t *threads);\r
+ \r
++/* Return an estimate of the number of messages matching a search\r
++ *\r
++ * This function performs a search and returns Xapian's best\r
++ * guess as to number of matching messages.\r
++ */\r
++unsigned\r
++notmuch_query_count_messages (notmuch_query_t *query);\r
++ \r
+ /* Get the thread ID of 'thread'.\r
+ *\r
+ * The returned string belongs to 'thread' and as such, should not be\r
+diff --git a/lib/query.cc b/lib/query.cc\r
+index ea521dd..dff9634 100644\r
+--- a/lib/query.cc\r
++++ b/lib/query.cc\r
+@@ -278,3 +278,55 @@ notmuch_threads_destroy (notmuch_threads_t *threads)\r
+ {\r
+ talloc_free (threads);\r
+ }\r
++\r
++unsigned\r
++notmuch_query_count_messages (notmuch_query_t *query)\r
++{\r
++ notmuch_database_t *notmuch = query->notmuch;\r
++ const char *query_string = query->query_string;\r
++ Xapian::doccount count;\r
++\r
++ try {\r
++ Xapian::Enquire enquire (*notmuch->xapian_db);\r
++ Xapian::Query mail_query (talloc_asprintf (query, "%s%s",\r
++ _find_prefix ("type"),\r
++ "mail"));\r
++ Xapian::Query string_query, final_query;\r
++ Xapian::MSet mset;\r
++ unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN |\r
++ Xapian::QueryParser::FLAG_PHRASE |\r
++ Xapian::QueryParser::FLAG_LOVEHATE |\r
++ Xapian::QueryParser::FLAG_BOOLEAN_ANY_CASE |\r
++ Xapian::QueryParser::FLAG_WILDCARD |\r
++ Xapian::QueryParser::FLAG_PURE_NOT);\r
++\r
++ if (strcmp (query_string, "") == 0) {\r
++ final_query = mail_query;\r
++ } else {\r
++ string_query = notmuch->query_parser->\r
++ parse_query (query_string, flags);\r
++ final_query = Xapian::Query (Xapian::Query::OP_AND,\r
++ mail_query, string_query);\r
++ }\r
++\r
++ enquire.set_weighting_scheme(Xapian::BoolWeight());\r
++ enquire.set_docid_order(Xapian::Enquire::ASCENDING);\r
++\r
++#if DEBUG_QUERY\r
++ fprintf (stderr, "Final query is:\n%s\n", final_query.get_description().c_str());\r
++#endif\r
++\r
++ enquire.set_query (final_query);\r
++\r
++ mset = enquire.get_mset (0, notmuch->xapian_db->get_doccount ());\r
++\r
++ count = mset.get_matches_estimated();\r
++\r
++ } catch (const Xapian::Error &error) {\r
++ fprintf (stderr, "A Xapian exception occurred: %s\n",\r
++ error.get_msg().c_str());\r
++ fprintf (stderr, "Query string was: %s\n", query->query_string);\r
++ }\r
++\r
++ return count;\r
++}\r
+diff --git a/notmuch-client.h b/notmuch-client.h\r
+index b65aa77..9884497 100644\r
+--- a/notmuch-client.h\r
++++ b/notmuch-client.h\r
+@@ -91,6 +91,9 @@ chomp_newline (char *str)\r
+ }\r
+ \r
+ int\r
++notmuch_count_command (void *ctx, int argc, char *argv[]);\r
++\r
++int\r
+ notmuch_dump_command (void *ctx, int argc, char *argv[]);\r
+ \r
+ int\r
+diff --git a/notmuch-count.c b/notmuch-count.c\r
+new file mode 100644\r
+index 0000000..68e428f\r
+--- /dev/null\r
++++ b/notmuch-count.c\r
+@@ -0,0 +1,109 @@\r
++/* notmuch - Not much of an email program, (just index and search)\r
++ *\r
++ * Copyright © 2009 Carl Worth\r
++ * Copyright © 2009 Keith Packard\r
++ *\r
++ * This program is free software: you can redistribute it and/or modify\r
++ * it under the terms of the GNU General Public License as published by\r
++ * the Free Software Foundation, either version 3 of the License, or\r
++ * (at your option) any later version.\r
++ *\r
++ * This program is distributed in the hope that it will be useful,\r
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
++ * GNU General Public License for more details.\r
++ *\r
++ * You should have received a copy of the GNU General Public License\r
++ * along with this program. If not, see http://www.gnu.org/licenses/ .\r
++ *\r
++ * Author: Keith Packard <keithp@keithp.com>\r
++ */\r
++\r
++#include "notmuch-client.h"\r
++\r
++int\r
++notmuch_count_command (void *ctx, int argc, char *argv[])\r
++{\r
++ notmuch_config_t *config;\r
++ notmuch_database_t *notmuch;\r
++ notmuch_query_t *query;\r
++ char *query_str;\r
++ char *opt, *end;\r
++ int i;\r
++#if 0\r
++ int i, first = 0, max_threads = -1;\r
++ notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST;\r
++#endif\r
++\r
++ for (i = 0; i < argc && argv[i][0] == '-'; i++) {\r
++ if (strcmp (argv[i], "--") == 0) {\r
++ i++;\r
++ break;\r
++ }\r
++#if 0\r
++ if (STRNCMP_LITERAL (argv[i], "--first=") == 0) {\r
++ opt = argv[i] + sizeof ("--first=") - 1;\r
++ first = strtoul (opt, &end, 10);\r
++ if (*opt == '\0' || *end != '\0') {\r
++ fprintf (stderr, "Invalid value for --first: %s\n", opt);\r
++ return 1;\r
++ }\r
++ } else if (STRNCMP_LITERAL (argv[i], "--max-threads=") == 0) {\r
++ opt = argv[i] + sizeof ("--max-threads=") - 1;\r
++ max_threads = strtoul (opt, &end, 10);\r
++ if (*opt == '\0' || *end != '\0') {\r
++ fprintf (stderr, "Invalid value for --max-threads: %s\n", opt);\r
++ return 1;\r
++ }\r
++ } else if (STRNCMP_LITERAL (argv[i], "--sort=") == 0) {\r
++ opt = argv[i] + sizeof ("--sort=") - 1;\r
++ if (strcmp (opt, "oldest-first") == 0) {\r
++ sort = NOTMUCH_SORT_OLDEST_FIRST;\r
++ } else if (strcmp (opt, "newest-first") == 0) {\r
++ sort = NOTMUCH_SORT_NEWEST_FIRST;\r
++ } else {\r
++ fprintf (stderr, "Invalid value for --sort: %s\n", opt);\r
++ return 1;\r
++ }\r
++ } else\r
++#endif\r
++ {\r
++ fprintf (stderr, "Unrecognized option: %s\n", argv[i]);\r
++ return 1;\r
++ }\r
++ }\r
++\r
++ argc -= i;\r
++ argv += i;\r
++\r
++ config = notmuch_config_open (ctx, NULL, NULL);\r
++ if (config == NULL)\r
++ return 1;\r
++\r
++ notmuch = notmuch_database_open (notmuch_config_get_database_path (config));\r
++ if (notmuch == NULL)\r
++ return 1;\r
++\r
++ query_str = query_string_from_args (ctx, argc, argv);\r
++ if (query_str == NULL) {\r
++ fprintf (stderr, "Out of memory.\n");\r
++ return 1;\r
++ }\r
++ if (*query_str == '\0') {\r
++ fprintf (stderr, "Error: notmuch count requires at least one count term.\n");\r
++ return 1;\r
++ }\r
++\r
++ query = notmuch_query_create (notmuch, query_str);\r
++ if (query == NULL) {\r
++ fprintf (stderr, "Out of memory\n");\r
++ return 1;\r
++ }\r
++\r
++ printf ("%u\n", notmuch_query_count_messages(query));\r
++\r
++ notmuch_query_destroy (query);\r
++ notmuch_database_close (notmuch);\r
++\r
++ return 0;\r
++}\r
+diff --git a/notmuch.c b/notmuch.c\r
+index 5cc8e4c..8387692 100644\r
+--- a/notmuch.c\r
++++ b/notmuch.c\r
+@@ -179,6 +179,17 @@ command_t commands[] = {\r
+ "\n"\r
+ "\t\tSee \"notmuch help search-terms\" for details of the search\n"\r
+ "\t\tterms syntax." },\r
++ { "count", notmuch_count_command,\r
++ "<search-terms> [...]",\r
++ "\t\tCount messages matching the search terms.",\r
++ "\t\tThe number of matching messages is output to stdout.\n"\r
++ "\n"\r
++ "\t\tA common use of \"notmuch count\" is to display the count\n"\r
++ "\t\tof messages matching both a specific tag and either inbox\n"\r
++ "\t\tor unread\n"\r
++ "\n"\r
++ "\t\tSee \"notmuch help search-terms\" for details of the search\n"\r
++ "\t\tterms syntax." },\r
+ { "reply", notmuch_reply_command,\r
+ "<search-terms> [...]",\r
+ "\t\tConstruct a reply template for a set of messages.",\r
+-- \r
+1.6.5.2\r
+\r