--- /dev/null
+Return-Path: <sojkam1@fel.cvut.cz>\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 D128D414BBD\r
+ for <notmuch@notmuchmail.org>; Thu, 8 Apr 2010 07:43:21 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -1.9\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-1.9 tagged_above=-999 required=5\r
+ tests=[BAYES_00=-1.9] autolearn=ham\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 IkQxQXRFH36F for <notmuch@notmuchmail.org>;\r
+ Thu, 8 Apr 2010 07:43:12 -0700 (PDT)\r
+Received: from max.feld.cvut.cz (max.feld.cvut.cz [147.32.192.36])\r
+ by olra.theworths.org (Postfix) with ESMTP id 2DFD04196F2\r
+ for <notmuch@notmuchmail.org>; Thu, 8 Apr 2010 07:43:08 -0700 (PDT)\r
+Received: from localhost (unknown [192.168.200.4])\r
+ by max.feld.cvut.cz (Postfix) with ESMTP id 9222219F3411;\r
+ Thu, 8 Apr 2010 16:43:07 +0200 (CEST)\r
+X-Virus-Scanned: IMAP AMAVIS\r
+Received: from max.feld.cvut.cz ([192.168.200.1])\r
+ by localhost (styx.feld.cvut.cz [192.168.200.4]) (amavisd-new,\r
+ port 10044)\r
+ with ESMTP id 0oznKvEf7Niy; Thu, 8 Apr 2010 16:43:04 +0200 (CEST)\r
+Received: from imap.feld.cvut.cz (imap.feld.cvut.cz [147.32.192.34])\r
+ by max.feld.cvut.cz (Postfix) with ESMTP id CB34119F33F6;\r
+ Thu, 8 Apr 2010 16:43:04 +0200 (CEST)\r
+Received: from steelpick.2x.cz (k335-30.felk.cvut.cz [147.32.86.30])\r
+ (Authenticated sender: sojkam1)\r
+ by imap.feld.cvut.cz (Postfix) with ESMTPSA id C696215C062;\r
+ Thu, 8 Apr 2010 16:43:04 +0200 (CEST)\r
+Received: from wsh by steelpick.2x.cz with local (Exim 4.71)\r
+ (envelope-from <sojkam1@fel.cvut.cz>)\r
+ id 1Nzswi-0007cF-Im; Thu, 08 Apr 2010 16:43:04 +0200\r
+From: Michal Sojka <sojkam1@fel.cvut.cz>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH 2/4] Conversion to mailstore abstraction\r
+Date: Thu, 8 Apr 2010 16:42:44 +0200\r
+Message-Id: <1270737766-29237-3-git-send-email-sojkam1@fel.cvut.cz>\r
+X-Mailer: git-send-email 1.7.0.2\r
+In-Reply-To: <1270737766-29237-1-git-send-email-sojkam1@fel.cvut.cz>\r
+References: <1270737766-29237-1-git-send-email-sojkam1@fel.cvut.cz>\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: Thu, 08 Apr 2010 14:43:22 -0000\r
+\r
+The code for detection of new files in the mailstore and their\r
+addition to the database is moved from notmuch-new.c to\r
+lib/mailstore-files.c, where it is called by the abstract mailstore\r
+interface.\r
+\r
+The code was only changed to allow the progress reporting functions to\r
+be implemented outside of notmuch library, as can be seen by\r
+git diff HEAD^ -C\r
+\r
+Signed-off-by: Michal Sojka <sojkam1@fel.cvut.cz>\r
+---\r
+ lib/Makefile.local | 1 +\r
+ notmuch-new.c => lib/mailstore-files.c | 406 ++++----------------\r
+ lib/mailstore.c | 5 -\r
+ notmuch-new.c | 660 +++-----------------------------\r
+ 4 files changed, 141 insertions(+), 931 deletions(-)\r
+ copy notmuch-new.c => lib/mailstore-files.c (61%)\r
+\r
+diff --git a/lib/Makefile.local b/lib/Makefile.local\r
+index 6243af1..863df4c 100644\r
+--- a/lib/Makefile.local\r
++++ b/lib/Makefile.local\r
+@@ -32,6 +32,7 @@ extra_cflags += -I$(dir) -fPIC\r
+ libnotmuch_c_srcs = \\r
+ $(dir)/libsha1.c \\r
+ $(dir)/mailstore.c \\r
++ $(dir)/mailstore-files.c\\r
+ $(dir)/message-file.c \\r
+ $(dir)/messages.c \\r
+ $(dir)/sha1.c \\r
+diff --git a/notmuch-new.c b/lib/mailstore-files.c\r
+similarity index 61%\r
+copy from notmuch-new.c\r
+copy to lib/mailstore-files.c\r
+index 2d0ba6c..8b5e1d5 100644\r
+--- a/notmuch-new.c\r
++++ b/lib/mailstore-files.c\r
+@@ -1,4 +1,5 @@\r
+-/* notmuch - Not much of an email program, (just index and search)\r
++/* mailstore-files.c - Original notmuch mail store - a collection of\r
++ * plain-text email messages (one message per file).\r
+ *\r
+ * Copyright © 2009 Carl Worth\r
+ *\r
+@@ -15,12 +16,14 @@\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: Carl Worth <cworth@cworth.org>\r
++ * Authors: Carl Worth <cworth@cworth.org>\r
++ * Michal Sojka <sojkam1@fel.cvut.cz>\r
+ */\r
+ \r
+-#include "notmuch-client.h"\r
+-\r
+-#include <unistd.h>\r
++#define _GNU_SOURCE /* For asprintf() */\r
++#include "notmuch.h"\r
++#include "mailstore-private.h"\r
++#include <dirent.h>\r
+ \r
+ typedef struct _filename_node {\r
+ char *filename;\r
+@@ -32,38 +35,10 @@ typedef struct _filename_list {\r
+ _filename_node_t **tail;\r
+ } _filename_list_t;\r
+ \r
+-typedef struct {\r
+- int output_is_a_tty;\r
+- int verbose;\r
+-\r
+- int total_files;\r
+- int processed_files;\r
+- int added_messages;\r
+- struct timeval tv_start;\r
+-\r
++typedef struct _indexing_context_priv {\r
+ _filename_list_t *removed_files;\r
+ _filename_list_t *removed_directories;\r
+-} add_files_state_t;\r
+-\r
+-static volatile sig_atomic_t do_add_files_print_progress = 0;\r
+-\r
+-static void\r
+-handle_sigalrm (unused (int signal))\r
+-{\r
+- do_add_files_print_progress = 1;\r
+-}\r
+-\r
+-static volatile sig_atomic_t interrupted;\r
+-\r
+-static void\r
+-handle_sigint (unused (int sig))\r
+-{\r
+- ssize_t ignored;\r
+- static char msg[] = "Stopping... \n";\r
+-\r
+- ignored = write(2, msg, sizeof(msg)-1);\r
+- interrupted = 1;\r
+-}\r
++} _indexing_context_priv_t;\r
+ \r
+ static _filename_list_t *\r
+ _filename_list_create (const void *ctx)\r
+@@ -100,34 +75,6 @@ tag_inbox_and_unread (notmuch_message_t *message)\r
+ notmuch_message_add_tag (message, "unread");\r
+ }\r
+ \r
+-static void\r
+-add_files_print_progress (add_files_state_t *state)\r
+-{\r
+- struct timeval tv_now;\r
+- double elapsed_overall, rate_overall;\r
+-\r
+- gettimeofday (&tv_now, NULL);\r
+-\r
+- elapsed_overall = notmuch_time_elapsed (state->tv_start, tv_now);\r
+- rate_overall = (state->processed_files) / elapsed_overall;\r
+-\r
+- printf ("Processed %d", state->processed_files);\r
+-\r
+- if (state->total_files) {\r
+- double time_remaining;\r
+-\r
+- time_remaining = ((state->total_files - state->processed_files) /\r
+- rate_overall);\r
+- printf (" of %d files (", state->total_files);\r
+- notmuch_time_print_formatted_seconds (time_remaining);\r
+- printf (" remaining). \r");\r
+- } else {\r
+- printf (" files (%d files/sec.) \r", (int) rate_overall);\r
+- }\r
+-\r
+- fflush (stdout);\r
+-}\r
+-\r
+ static int\r
+ dirent_sort_inode (const struct dirent **a, const struct dirent **b)\r
+ {\r
+@@ -169,6 +116,7 @@ _entries_resemble_maildir (struct dirent **entries, int count)\r
+ return 0;\r
+ }\r
+ \r
++\r
+ /* Examine 'path' recursively as follows:\r
+ *\r
+ * o Ask the filesystem for the mtime of 'path' (fs_mtime)\r
+@@ -205,9 +153,9 @@ _entries_resemble_maildir (struct dirent **entries, int count)\r
+ * o Tell the database to update its time of 'path' to 'fs_mtime'\r
+ */\r
+ static notmuch_status_t\r
+-add_files_recursive (notmuch_database_t *notmuch,\r
++add_files_recursive (notmuch_mailstore_t *mailstore,\r
+ const char *path,\r
+- add_files_state_t *state)\r
++ notmuch_indexing_context_t *state)\r
+ {\r
+ DIR *dir = NULL;\r
+ struct dirent *entry = NULL;\r
+@@ -222,6 +170,8 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ notmuch_filenames_t *db_subdirs = NULL;\r
+ struct stat st;\r
+ notmuch_bool_t is_maildir, new_directory;\r
++ _indexing_context_priv_t *priv = state->priv;\r
++ notmuch_database_t *notmuch = mailstore->notmuch;\r
+ \r
+ if (stat (path, &st)) {\r
+ fprintf (stderr, "Error reading directory %s: %s\n",\r
+@@ -268,7 +218,7 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries);\r
+ \r
+ for (i = 0; i < num_fs_entries; i++) {\r
+- if (interrupted)\r
++ if (state->interrupted)\r
+ break;\r
+ \r
+ entry = fs_entries[i];\r
+@@ -302,7 +252,7 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ }\r
+ \r
+ next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);\r
+- status = add_files_recursive (notmuch, next, state);\r
++ status = add_files_recursive (mailstore, next, state);\r
+ if (status && ret == NOTMUCH_STATUS_SUCCESS)\r
+ ret = status;\r
+ talloc_free (next);\r
+@@ -317,7 +267,7 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ /* Pass 2: Scan for new files, removed files, and removed directories. */\r
+ for (i = 0; i < num_fs_entries; i++)\r
+ {\r
+- if (interrupted)\r
++ if (state->interrupted)\r
+ break;\r
+ \r
+ entry = fs_entries[i];\r
+@@ -327,11 +277,11 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ while (notmuch_filenames_valid (db_files) &&\r
+ strcmp (notmuch_filenames_get (db_files), entry->d_name) < 0)\r
+ {\r
+- char *absolute = talloc_asprintf (state->removed_files,\r
++ char *absolute = talloc_asprintf (priv->removed_files,\r
+ "%s/%s", path,\r
+ notmuch_filenames_get (db_files));\r
+ \r
+- _filename_list_add (state->removed_files, absolute);\r
++ _filename_list_add (priv->removed_files, absolute);\r
+ \r
+ notmuch_filenames_move_to_next (db_files);\r
+ }\r
+@@ -343,10 +293,10 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ \r
+ if (strcmp (filename, entry->d_name) < 0)\r
+ {\r
+- char *absolute = talloc_asprintf (state->removed_directories,\r
++ char *absolute = talloc_asprintf (priv->removed_directories,\r
+ "%s/%s", path, filename);\r
+ \r
+- _filename_list_add (state->removed_directories, absolute);\r
++ _filename_list_add (priv->removed_directories, absolute);\r
+ }\r
+ \r
+ notmuch_filenames_move_to_next (db_subdirs);\r
+@@ -394,18 +344,8 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ \r
+ state->processed_files++;\r
+ \r
+- if (state->verbose) {\r
+- if (state->output_is_a_tty)\r
+- printf("\r\033[K");\r
+-\r
+- printf ("%i/%i: %s",\r
+- state->processed_files,\r
+- state->total_files,\r
+- next);\r
+-\r
+- putchar((state->output_is_a_tty) ? '\r' : '\n');\r
+- fflush (stdout);\r
+- }\r
++ if (state->verbose && state->print_verbose_cb)\r
++ state->print_verbose_cb(state, next);\r
+ \r
+ status = notmuch_database_add_message (notmuch, next, &message);\r
+ switch (status) {\r
+@@ -445,46 +385,50 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ message = NULL;\r
+ }\r
+ \r
+- if (do_add_files_print_progress) {\r
+- do_add_files_print_progress = 0;\r
+- add_files_print_progress (state);\r
++ if (state->print_progress &&\r
++ state->print_progress_cb) {\r
++ state->print_progress = 0;\r
++ state->print_progress_cb (state);\r
+ }\r
+ \r
+ talloc_free (next);\r
+ next = NULL;\r
+ }\r
+ \r
++ if (state->interrupted)\r
++ goto DONE;\r
++\r
+ /* Now that we've walked the whole filesystem list, anything left\r
+ * over in the database lists has been deleted. */\r
+ while (notmuch_filenames_valid (db_files))\r
+ {\r
+- char *absolute = talloc_asprintf (state->removed_files,\r
++ char *absolute = talloc_asprintf (priv->removed_files,\r
+ "%s/%s", path,\r
+ notmuch_filenames_get (db_files));\r
+ \r
+- _filename_list_add (state->removed_files, absolute);\r
++ _filename_list_add (priv->removed_files, absolute);\r
+ \r
+ notmuch_filenames_move_to_next (db_files);\r
+ }\r
+ \r
+ while (notmuch_filenames_valid (db_subdirs))\r
+ {\r
+- char *absolute = talloc_asprintf (state->removed_directories,\r
++ char *absolute = talloc_asprintf (priv->removed_directories,\r
+ "%s/%s", path,\r
+ notmuch_filenames_get (db_subdirs));\r
+ \r
+- _filename_list_add (state->removed_directories, absolute);\r
++ _filename_list_add (priv->removed_directories, absolute);\r
+ \r
+ notmuch_filenames_move_to_next (db_subdirs);\r
+ }\r
+ \r
+- if (! interrupted) {\r
++ if (! state->interrupted) {\r
+ status = notmuch_directory_set_mtime (directory, fs_mtime);\r
+ if (status && ret == NOTMUCH_STATUS_SUCCESS)\r
+ ret = status;\r
+ }\r
+ \r
+- DONE:\r
++DONE:\r
+ if (next)\r
+ talloc_free (next);\r
+ if (entry)\r
+@@ -503,67 +447,6 @@ add_files_recursive (notmuch_database_t *notmuch,\r
+ return ret;\r
+ }\r
+ \r
+-/* This is the top-level entry point for add_files. It does a couple\r
+- * of error checks, sets up the progress-printing timer and then calls\r
+- * into the recursive function. */\r
+-static notmuch_status_t\r
+-add_files (notmuch_database_t *notmuch,\r
+- const char *path,\r
+- add_files_state_t *state)\r
+-{\r
+- notmuch_status_t status;\r
+- struct sigaction action;\r
+- struct itimerval timerval;\r
+- notmuch_bool_t timer_is_active = FALSE;\r
+- struct stat st;\r
+-\r
+- if (state->output_is_a_tty && ! debugger_is_active () && ! state->verbose) {\r
+- /* Setup our handler for SIGALRM */\r
+- memset (&action, 0, sizeof (struct sigaction));\r
+- action.sa_handler = handle_sigalrm;\r
+- sigemptyset (&action.sa_mask);\r
+- action.sa_flags = SA_RESTART;\r
+- sigaction (SIGALRM, &action, NULL);\r
+-\r
+- /* Then start a timer to send SIGALRM once per second. */\r
+- timerval.it_interval.tv_sec = 1;\r
+- timerval.it_interval.tv_usec = 0;\r
+- timerval.it_value.tv_sec = 1;\r
+- timerval.it_value.tv_usec = 0;\r
+- setitimer (ITIMER_REAL, &timerval, NULL);\r
+-\r
+- timer_is_active = TRUE;\r
+- }\r
+-\r
+- if (stat (path, &st)) {\r
+- fprintf (stderr, "Error reading directory %s: %s\n",\r
+- path, strerror (errno));\r
+- return NOTMUCH_STATUS_FILE_ERROR;\r
+- }\r
+-\r
+- if (! S_ISDIR (st.st_mode)) {\r
+- fprintf (stderr, "Error: %s is not a directory.\n", path);\r
+- return NOTMUCH_STATUS_FILE_ERROR;\r
+- }\r
+-\r
+- status = add_files_recursive (notmuch, path, state);\r
+-\r
+- if (timer_is_active) {\r
+- /* Now stop the timer. */\r
+- timerval.it_interval.tv_sec = 0;\r
+- timerval.it_interval.tv_usec = 0;\r
+- timerval.it_value.tv_sec = 0;\r
+- timerval.it_value.tv_usec = 0;\r
+- setitimer (ITIMER_REAL, &timerval, NULL);\r
+-\r
+- /* And disable the signal handler. */\r
+- action.sa_handler = SIG_IGN;\r
+- sigaction (SIGALRM, &action, NULL);\r
+- }\r
+-\r
+- return status;\r
+-}\r
+-\r
+ /* XXX: This should be merged with the add_files function since it\r
+ * shares a lot of logic with it. */\r
+ /* Recursively count all regular files in path and all sub-directories\r
+@@ -571,7 +454,9 @@ add_files (notmuch_database_t *notmuch,\r
+ * initialized to zero by the top-level caller before calling\r
+ * count_files). */\r
+ static void\r
+-count_files (const char *path, int *count)\r
++count_files (notmuch_mailstore_t *mailstore,\r
++ const char *path, int *count,\r
++ volatile sig_atomic_t *interrupted)\r
+ {\r
+ struct dirent *entry = NULL;\r
+ char *next;\r
+@@ -580,13 +465,14 @@ count_files (const char *path, int *count)\r
+ int num_fs_entries = scandir (path, &fs_entries, 0, dirent_sort_inode);\r
+ int i = 0;\r
+ \r
++ (void)mailstore;\r
+ if (num_fs_entries == -1) {\r
+ fprintf (stderr, "Warning: failed to open directory %s: %s\n",\r
+ path, strerror (errno));\r
+ goto DONE;\r
+ }\r
+ \r
+- while (!interrupted) {\r
++ while (!*interrupted) {\r
+ if (i == num_fs_entries)\r
+ break;\r
+ \r
+@@ -620,45 +506,19 @@ count_files (const char *path, int *count)\r
+ fflush (stdout);\r
+ }\r
+ } else if (S_ISDIR (st.st_mode)) {\r
+- count_files (next, count);\r
++ count_files (mailstore, next, count, interrupted);\r
+ }\r
+ \r
+ free (next);\r
+ }\r
+ \r
+- DONE:\r
++DONE:\r
+ if (entry)\r
+ free (entry);\r
+ if (fs_entries)\r
+ free (fs_entries);\r
+ }\r
+ \r
+-static void\r
+-upgrade_print_progress (void *closure,\r
+- double progress)\r
+-{\r
+- add_files_state_t *state = closure;\r
+-\r
+- printf ("Upgrading database: %.2f%% complete", progress * 100.0);\r
+-\r
+- if (progress > 0) {\r
+- struct timeval tv_now;\r
+- double elapsed, time_remaining;\r
+-\r
+- gettimeofday (&tv_now, NULL);\r
+-\r
+- elapsed = notmuch_time_elapsed (state->tv_start, tv_now);\r
+- time_remaining = (elapsed / progress) * (1.0 - progress);\r
+- printf (" (");\r
+- notmuch_time_print_formatted_seconds (time_remaining);\r
+- printf (" remaining)");\r
+- }\r
+-\r
+- printf (". \r");\r
+-\r
+- fflush (stdout);\r
+-}\r
+-\r
+ /* Recursively remove all filenames from the database referring to\r
+ * 'path' (or to any of its children). */\r
+ static void\r
+@@ -702,163 +562,51 @@ _remove_directory (void *ctx,\r
+ notmuch_directory_destroy (directory);\r
+ }\r
+ \r
+-int\r
+-notmuch_new_command (void *ctx, int argc, char *argv[])\r
++static notmuch_private_status_t\r
++index_new(notmuch_mailstore_t *mailstore, const char* path,\r
++ notmuch_indexing_context_t *indexing_ctx)\r
+ {\r
+- notmuch_config_t *config;\r
+- notmuch_database_t *notmuch;\r
+- add_files_state_t add_files_state;\r
+- double elapsed;\r
+- struct timeval tv_now;\r
+- int ret = 0;\r
+- struct stat st;\r
+- const char *db_path;\r
+- char *dot_notmuch_path;\r
+- struct sigaction action;\r
++ _indexing_context_priv_t *priv;\r
+ _filename_node_t *f;\r
+- int renamed_files, removed_files;\r
+- notmuch_status_t status;\r
+- int i;\r
+-\r
+- add_files_state.verbose = 0;\r
+- add_files_state.output_is_a_tty = isatty (fileno (stdout));\r
+-\r
+- for (i = 0; i < argc && argv[i][0] == '-'; i++) {\r
+- if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) {\r
+- add_files_state.verbose = 1;\r
+- } else {\r
+- fprintf (stderr, "Unrecognized option: %s\n", argv[i]);\r
+- return 1;\r
+- }\r
+- }\r
+-\r
+- config = notmuch_config_open (ctx, NULL, NULL);\r
+- if (config == NULL)\r
+- return 1;\r
++ notmuch_status_t status, ret;\r
++ notmuch_database_t *notmuch = mailstore->notmuch;\r
+ \r
+- db_path = notmuch_config_get_database_path (config);\r
++ priv = talloc(NULL, _indexing_context_priv_t);\r
++ indexing_ctx->priv = priv;\r
++ if (priv == NULL)\r
++ return NOTMUCH_STATUS_OUT_OF_MEMORY;\r
+ \r
+- dot_notmuch_path = talloc_asprintf (ctx, "%s/%s", db_path, ".notmuch");\r
++ priv->removed_files = _filename_list_create (priv);\r
++ priv->removed_directories = _filename_list_create (priv);\r
+ \r
+- if (stat (dot_notmuch_path, &st)) {\r
+- int count;\r
++ ret = add_files_recursive(mailstore, path, indexing_ctx);\r
+ \r
+- count = 0;\r
+- count_files (db_path, &count);\r
+- if (interrupted)\r
+- return 1;\r
+-\r
+- printf ("Found %d total files (that's not much mail).\n", count);\r
+- notmuch = notmuch_database_create (db_path,\r
+- notmuch_config_get_mailstore (config));\r
+- add_files_state.total_files = count;\r
+- } else {\r
+- notmuch = notmuch_database_open (db_path,\r
+- NOTMUCH_DATABASE_MODE_READ_WRITE,\r
+- notmuch_config_get_mailstore (config));\r
+- if (notmuch == NULL)\r
+- return 1;\r
+-\r
+- if (notmuch_database_needs_upgrade (notmuch)) {\r
+- printf ("Welcome to a new version of notmuch! Your database will now be upgraded.\n");\r
+- gettimeofday (&add_files_state.tv_start, NULL);\r
+- notmuch_database_upgrade (notmuch, upgrade_print_progress,\r
+- &add_files_state);\r
+- printf ("Your notmuch database has now been upgraded to database format version %u.\n",\r
+- notmuch_database_get_version (notmuch));\r
+- }\r
+-\r
+- add_files_state.total_files = 0;\r
+- }\r
+-\r
+- if (notmuch == NULL)\r
+- return 1;\r
+-\r
+- /* Setup our handler for SIGINT. We do this after having\r
+- * potentially done a database upgrade we this interrupt handler\r
+- * won't support. */\r
+- memset (&action, 0, sizeof (struct sigaction));\r
+- action.sa_handler = handle_sigint;\r
+- sigemptyset (&action.sa_mask);\r
+- action.sa_flags = SA_RESTART;\r
+- sigaction (SIGINT, &action, NULL);\r
+-\r
+- talloc_free (dot_notmuch_path);\r
+- dot_notmuch_path = NULL;\r
+-\r
+- add_files_state.processed_files = 0;\r
+- add_files_state.added_messages = 0;\r
+- gettimeofday (&add_files_state.tv_start, NULL);\r
+-\r
+- add_files_state.removed_files = _filename_list_create (ctx);\r
+- add_files_state.removed_directories = _filename_list_create (ctx);\r
+-\r
+- ret = add_files (notmuch, db_path, &add_files_state);\r
+-\r
+- removed_files = 0;\r
+- renamed_files = 0;\r
+- for (f = add_files_state.removed_files->head; f; f = f->next) {\r
++ indexing_ctx->removed_files = 0;\r
++ indexing_ctx->renamed_files = 0;\r
++ for (f = priv->removed_files->head; f; f = f->next) {\r
+ status = notmuch_database_remove_message (notmuch, f->filename);\r
+ if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)\r
+- renamed_files++;\r
++ indexing_ctx->renamed_files++;\r
+ else\r
+- removed_files++;\r
+- }\r
+-\r
+- for (f = add_files_state.removed_directories->head; f; f = f->next) {\r
+- _remove_directory (ctx, notmuch, f->filename,\r
+- &renamed_files, &removed_files);\r
+- }\r
+-\r
+- talloc_free (add_files_state.removed_files);\r
+- talloc_free (add_files_state.removed_directories);\r
+-\r
+- gettimeofday (&tv_now, NULL);\r
+- elapsed = notmuch_time_elapsed (add_files_state.tv_start,\r
+- tv_now);\r
+-\r
+- if (add_files_state.processed_files) {\r
+- printf ("Processed %d %s in ", add_files_state.processed_files,\r
+- add_files_state.processed_files == 1 ?\r
+- "file" : "total files");\r
+- notmuch_time_print_formatted_seconds (elapsed);\r
+- if (elapsed > 1) {\r
+- printf (" (%d files/sec.). \n",\r
+- (int) (add_files_state.processed_files / elapsed));\r
+- } else {\r
+- printf (". \n");\r
+- }\r
+- }\r
+-\r
+- if (add_files_state.added_messages) {\r
+- printf ("Added %d new %s to the database.",\r
+- add_files_state.added_messages,\r
+- add_files_state.added_messages == 1 ?\r
+- "message" : "messages");\r
+- } else {\r
+- printf ("No new mail.");\r
+- }\r
+-\r
+- if (removed_files) {\r
+- printf (" Removed %d %s.",\r
+- removed_files,\r
+- removed_files == 1 ? "message" : "messages");\r
+- }\r
+-\r
+- if (renamed_files) {\r
+- printf (" Detected %d file %s.",\r
+- renamed_files,\r
+- renamed_files == 1 ? "rename" : "renames");\r
++ indexing_ctx->removed_files++;\r
+ }\r
+ \r
+- printf ("\n");\r
+-\r
+- if (ret) {\r
+- printf ("\nNote: At least one error was encountered: %s\n",\r
+- notmuch_status_to_string (ret));\r
++ for (f = priv->removed_directories->head; f; f = f->next) {\r
++ _remove_directory (priv, notmuch, f->filename,\r
++ &indexing_ctx->renamed_files,\r
++ &indexing_ctx->removed_files);\r
+ }\r
+ \r
+- notmuch_database_close (notmuch);\r
++ talloc_free(priv);\r
+ \r
+- return ret || interrupted;\r
++ return ret;\r
+ }\r
++\r
++/* Original notmuch mail store */\r
++struct _notmuch_mailstore mailstore_files = {\r
++ .type = "files",\r
++ .count_files = count_files,\r
++ .index_new = index_new,\r
++ .sync_tags = NULL, /* We cannot store tags in this mailstore. */\r
++ .open_file = NULL, /* Currently not implemented */\r
++};\r
+diff --git a/lib/mailstore.c b/lib/mailstore.c\r
+index eb27952..709db72 100644\r
+--- a/lib/mailstore.c\r
++++ b/lib/mailstore.c\r
+@@ -23,11 +23,6 @@\r
+ \r
+ #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))\r
+ \r
+-/* Original notmuch mail store */\r
+-struct _notmuch_mailstore mailstore_files = {\r
+- .type = "files",\r
+-};\r
+-\r
+ static notmuch_mailstore_t *available[] = {\r
+ &mailstore_files,\r
+ };\r
+diff --git a/notmuch-new.c b/notmuch-new.c\r
+index 2d0ba6c..6c527e9 100644\r
+--- a/notmuch-new.c\r
++++ b/notmuch-new.c\r
+@@ -22,35 +22,12 @@\r
+ \r
+ #include <unistd.h>\r
+ \r
+-typedef struct _filename_node {\r
+- char *filename;\r
+- struct _filename_node *next;\r
+-} _filename_node_t;\r
+-\r
+-typedef struct _filename_list {\r
+- _filename_node_t *head;\r
+- _filename_node_t **tail;\r
+-} _filename_list_t;\r
+-\r
+-typedef struct {\r
+- int output_is_a_tty;\r
+- int verbose;\r
+-\r
+- int total_files;\r
+- int processed_files;\r
+- int added_messages;\r
+- struct timeval tv_start;\r
+-\r
+- _filename_list_t *removed_files;\r
+- _filename_list_t *removed_directories;\r
+-} add_files_state_t;\r
+-\r
+-static volatile sig_atomic_t do_add_files_print_progress = 0;\r
++notmuch_indexing_context_t *indexing_ctx;\r
+ \r
+ static void\r
+ handle_sigalrm (unused (int signal))\r
+ {\r
+- do_add_files_print_progress = 1;\r
++ indexing_ctx->print_progress = 1;\r
+ }\r
+ \r
+ static volatile sig_atomic_t interrupted;\r
+@@ -62,63 +39,35 @@ handle_sigint (unused (int sig))\r
+ static char msg[] = "Stopping... \n";\r
+ \r
+ ignored = write(2, msg, sizeof(msg)-1);\r
+- interrupted = 1;\r
+-}\r
+-\r
+-static _filename_list_t *\r
+-_filename_list_create (const void *ctx)\r
+-{\r
+- _filename_list_t *list;\r
+-\r
+- list = talloc (ctx, _filename_list_t);\r
+- if (list == NULL)\r
+- return NULL;\r
+-\r
+- list->head = NULL;\r
+- list->tail = &list->head;\r
+-\r
+- return list;\r
+-}\r
+-\r
+-static void\r
+-_filename_list_add (_filename_list_t *list,\r
+- const char *filename)\r
+-{\r
+- _filename_node_t *node = talloc (list, _filename_node_t);\r
+-\r
+- node->filename = talloc_strdup (list, filename);\r
+- node->next = NULL;\r
+-\r
+- *(list->tail) = node;\r
+- list->tail = &node->next;\r
++ indexing_ctx->interrupted = 1;\r
+ }\r
+ \r
+-static void\r
+-tag_inbox_and_unread (notmuch_message_t *message)\r
+-{\r
+- notmuch_message_add_tag (message, "inbox");\r
+- notmuch_message_add_tag (message, "unread");\r
+-}\r
++struct print_ctx {\r
++ int total_files;\r
++ struct timeval tv_start;\r
++ int output_is_a_tty;\r
++};\r
+ \r
+ static void\r
+-add_files_print_progress (add_files_state_t *state)\r
++add_files_print_progress (notmuch_indexing_context_t *state)\r
+ {\r
++ struct print_ctx *print_ctx = state->print_ctx;\r
+ struct timeval tv_now;\r
+ double elapsed_overall, rate_overall;\r
+ \r
+ gettimeofday (&tv_now, NULL);\r
+ \r
+- elapsed_overall = notmuch_time_elapsed (state->tv_start, tv_now);\r
++ elapsed_overall = notmuch_time_elapsed (print_ctx->tv_start, tv_now);\r
+ rate_overall = (state->processed_files) / elapsed_overall;\r
+ \r
+ printf ("Processed %d", state->processed_files);\r
+ \r
+- if (state->total_files) {\r
++ if (print_ctx->total_files) {\r
+ double time_remaining;\r
+ \r
+- time_remaining = ((state->total_files - state->processed_files) /\r
++ time_remaining = ((print_ctx->total_files - state->processed_files) /\r
+ rate_overall);\r
+- printf (" of %d files (", state->total_files);\r
++ printf (" of %d files (", print_ctx->total_files);\r
+ notmuch_time_print_formatted_seconds (time_remaining);\r
+ printf (" remaining). \r");\r
+ } else {\r
+@@ -128,396 +77,42 @@ add_files_print_progress (add_files_state_t *state)\r
+ fflush (stdout);\r
+ }\r
+ \r
+-static int\r
+-dirent_sort_inode (const struct dirent **a, const struct dirent **b)\r
+-{\r
+- return ((*a)->d_ino < (*b)->d_ino) ? -1 : 1;\r
+-}\r
+-\r
+-static int\r
+-dirent_sort_strcmp_name (const struct dirent **a, const struct dirent **b)\r
+-{\r
+- return strcmp ((*a)->d_name, (*b)->d_name);\r
+-}\r
+-\r
+-/* Test if the directory looks like a Maildir directory.\r
+- *\r
+- * Search through the array of directory entries to see if we can find all\r
+- * three subdirectories typical for Maildir, that is "new", "cur", and "tmp".\r
+- *\r
+- * Return 1 if the directory looks like a Maildir and 0 otherwise.\r
+- */\r
+-static int\r
+-_entries_resemble_maildir (struct dirent **entries, int count)\r
+-{\r
+- int i, found = 0;\r
+-\r
+- for (i = 0; i < count; i++) {\r
+- if (entries[i]->d_type != DT_DIR && entries[i]->d_type != DT_UNKNOWN)\r
+- continue;\r
+-\r
+- if (strcmp(entries[i]->d_name, "new") == 0 ||\r
+- strcmp(entries[i]->d_name, "cur") == 0 ||\r
+- strcmp(entries[i]->d_name, "tmp") == 0)\r
+- {\r
+- found++;\r
+- if (found == 3)\r
+- return 1;\r
+- }\r
+- }\r
+-\r
+- return 0;\r
+-}\r
+-\r
+-/* Examine 'path' recursively as follows:\r
+- *\r
+- * o Ask the filesystem for the mtime of 'path' (fs_mtime)\r
+- * o Ask the database for its timestamp of 'path' (db_mtime)\r
+- *\r
+- * o Ask the filesystem for files and directories within 'path'\r
+- * (via scandir and stored in fs_entries)\r
+- * o Ask the database for files and directories within 'path'\r
+- * (db_files and db_subdirs)\r
+- *\r
+- * o Pass 1: For each directory in fs_entries, recursively call into\r
+- * this same function.\r
+- *\r
+- * o Pass 2: If 'fs_mtime' > 'db_mtime', then walk fs_entries\r
+- * simultaneously with db_files and db_subdirs. Look for one of\r
+- * three interesting cases:\r
+- *\r
+- * 1. Regular file in fs_entries and not in db_files\r
+- * This is a new file to add_message into the database.\r
+- *\r
+- * 2. Filename in db_files not in fs_entries.\r
+- * This is a file that has been removed from the mail store.\r
+- *\r
+- * 3. Directory in db_subdirs not in fs_entries\r
+- * This is a directory that has been removed from the mail store.\r
+- *\r
+- * Note that the addition of a directory is not interesting here,\r
+- * since that will have been taken care of in pass 1. Also, we\r
+- * don't immediately act on file/directory removal since we must\r
+- * ensure that in the case of a rename that the new filename is\r
+- * added before the old filename is removed, (so that no\r
+- * information is lost from the database).\r
+- *\r
+- * o Tell the database to update its time of 'path' to 'fs_mtime'\r
+- */\r
+-static notmuch_status_t\r
+-add_files_recursive (notmuch_database_t *notmuch,\r
+- const char *path,\r
+- add_files_state_t *state)\r
++static void\r
++add_files_print_verbose (notmuch_indexing_context_t *state, const char *filename)\r
+ {\r
+- DIR *dir = NULL;\r
+- struct dirent *entry = NULL;\r
+- char *next = NULL;\r
+- time_t fs_mtime, db_mtime;\r
+- notmuch_status_t status, ret = NOTMUCH_STATUS_SUCCESS;\r
+- notmuch_message_t *message = NULL;\r
+- struct dirent **fs_entries = NULL;\r
+- int i, num_fs_entries;\r
+- notmuch_directory_t *directory;\r
+- notmuch_filenames_t *db_files = NULL;\r
+- notmuch_filenames_t *db_subdirs = NULL;\r
+- struct stat st;\r
+- notmuch_bool_t is_maildir, new_directory;\r
+-\r
+- if (stat (path, &st)) {\r
+- fprintf (stderr, "Error reading directory %s: %s\n",\r
+- path, strerror (errno));\r
+- return NOTMUCH_STATUS_FILE_ERROR;\r
+- }\r
+-\r
+- /* This is not an error since we may have recursed based on a\r
+- * symlink to a regular file, not a directory, and we don't know\r
+- * that until this stat. */\r
+- if (! S_ISDIR (st.st_mode))\r
+- return NOTMUCH_STATUS_SUCCESS;\r
+-\r
+- fs_mtime = st.st_mtime;\r
+-\r
+- directory = notmuch_database_get_directory (notmuch, path);\r
+- db_mtime = notmuch_directory_get_mtime (directory);\r
+-\r
+- if (db_mtime == 0) {\r
+- new_directory = TRUE;\r
+- db_files = NULL;\r
+- db_subdirs = NULL;\r
+- } else {\r
+- new_directory = FALSE;\r
+- db_files = notmuch_directory_get_child_files (directory);\r
+- db_subdirs = notmuch_directory_get_child_directories (directory);\r
+- }\r
+-\r
+- /* If the database knows about this directory, then we sort based\r
+- * on strcmp to match the database sorting. Otherwise, we can do\r
+- * inode-based sorting for faster filesystem operation. */\r
+- num_fs_entries = scandir (path, &fs_entries, 0,\r
+- new_directory ?\r
+- dirent_sort_inode : dirent_sort_strcmp_name);\r
+-\r
+- if (num_fs_entries == -1) {\r
+- fprintf (stderr, "Error opening directory %s: %s\n",\r
+- path, strerror (errno));\r
+- ret = NOTMUCH_STATUS_FILE_ERROR;\r
+- goto DONE;\r
+- }\r
+-\r
+- /* Pass 1: Recurse into all sub-directories. */\r
+- is_maildir = _entries_resemble_maildir (fs_entries, num_fs_entries);\r
+-\r
+- for (i = 0; i < num_fs_entries; i++) {\r
+- if (interrupted)\r
+- break;\r
+-\r
+- entry = fs_entries[i];\r
+-\r
+- /* We only want to descend into directories.\r
+- * But symlinks can be to directories too, of course.\r
+- *\r
+- * And if the filesystem doesn't tell us the file type in the\r
+- * scandir results, then it might be a directory (and if not,\r
+- * then we'll stat and return immediately in the next level of\r
+- * recursion). */\r
+- if (entry->d_type != DT_DIR &&\r
+- entry->d_type != DT_LNK &&\r
+- entry->d_type != DT_UNKNOWN)\r
+- {\r
+- continue;\r
+- }\r
+-\r
+- /* Ignore special directories to avoid infinite recursion.\r
+- * Also ignore the .notmuch directory and any "tmp" directory\r
+- * that appears within a maildir.\r
+- */\r
+- /* XXX: Eventually we'll want more sophistication to let the\r
+- * user specify files to be ignored. */\r
+- if (strcmp (entry->d_name, ".") == 0 ||\r
+- strcmp (entry->d_name, "..") == 0 ||\r
+- (is_maildir && strcmp (entry->d_name, "tmp") == 0) ||\r
+- strcmp (entry->d_name, ".notmuch") ==0)\r
+- {\r
+- continue;\r
+- }\r
+-\r
+- next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);\r
+- status = add_files_recursive (notmuch, next, state);\r
+- if (status && ret == NOTMUCH_STATUS_SUCCESS)\r
+- ret = status;\r
+- talloc_free (next);\r
+- next = NULL;\r
+- }\r
++ struct print_ctx *print_ctx = state->print_ctx;\r
++ if (print_ctx->output_is_a_tty)\r
++ printf("\r\033[K");\r
+ \r
+- /* If this directory hasn't been modified since the last\r
+- * "notmuch new", then we can skip the second pass entirely. */\r
+- if (fs_mtime <= db_mtime)\r
+- goto DONE;\r
++ printf ("%i/%i: %s",\r
++ state->processed_files,\r
++ print_ctx->total_files,\r
++ filename);\r
+ \r
+- /* Pass 2: Scan for new files, removed files, and removed directories. */\r
+- for (i = 0; i < num_fs_entries; i++)\r
+- {\r
+- if (interrupted)\r
+- break;\r
+-\r
+- entry = fs_entries[i];\r
+-\r
+- /* Check if we've walked past any names in db_files or\r
+- * db_subdirs. If so, these have been deleted. */\r
+- while (notmuch_filenames_valid (db_files) &&\r
+- strcmp (notmuch_filenames_get (db_files), entry->d_name) < 0)\r
+- {\r
+- char *absolute = talloc_asprintf (state->removed_files,\r
+- "%s/%s", path,\r
+- notmuch_filenames_get (db_files));\r
+-\r
+- _filename_list_add (state->removed_files, absolute);\r
+-\r
+- notmuch_filenames_move_to_next (db_files);\r
+- }\r
+-\r
+- while (notmuch_filenames_valid (db_subdirs) &&\r
+- strcmp (notmuch_filenames_get (db_subdirs), entry->d_name) <= 0)\r
+- {\r
+- const char *filename = notmuch_filenames_get (db_subdirs);\r
+-\r
+- if (strcmp (filename, entry->d_name) < 0)\r
+- {\r
+- char *absolute = talloc_asprintf (state->removed_directories,\r
+- "%s/%s", path, filename);\r
+-\r
+- _filename_list_add (state->removed_directories, absolute);\r
+- }\r
+-\r
+- notmuch_filenames_move_to_next (db_subdirs);\r
+- }\r
+-\r
+- /* If we're looking at a symlink, we only want to add it if it\r
+- * links to a regular file, (and not to a directory, say).\r
+- *\r
+- * Similarly, if the file is of unknown type (due to filesytem\r
+- * limitations), then we also need to look closer.\r
+- *\r
+- * In either case, a stat does the trick.\r
+- */\r
+- if (entry->d_type == DT_LNK || entry->d_type == DT_UNKNOWN) {\r
+- int err;\r
+-\r
+- next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);\r
+- err = stat (next, &st);\r
+- talloc_free (next);\r
+- next = NULL;\r
+-\r
+- /* Don't emit an error for a link pointing nowhere, since\r
+- * the directory-traversal pass will have already done\r
+- * that. */\r
+- if (err)\r
+- continue;\r
+-\r
+- if (! S_ISREG (st.st_mode))\r
+- continue;\r
+- } else if (entry->d_type != DT_REG) {\r
+- continue;\r
+- }\r
+-\r
+- /* Don't add a file that we've added before. */\r
+- if (notmuch_filenames_valid (db_files) &&\r
+- strcmp (notmuch_filenames_get (db_files), entry->d_name) == 0)\r
+- {\r
+- notmuch_filenames_move_to_next (db_files);\r
+- continue;\r
+- }\r
+-\r
+- /* We're now looking at a regular file that doesn't yet exist\r
+- * in the database, so add it. */\r
+- next = talloc_asprintf (notmuch, "%s/%s", path, entry->d_name);\r
+-\r
+- state->processed_files++;\r
+-\r
+- if (state->verbose) {\r
+- if (state->output_is_a_tty)\r
+- printf("\r\033[K");\r
+-\r
+- printf ("%i/%i: %s",\r
+- state->processed_files,\r
+- state->total_files,\r
+- next);\r
+-\r
+- putchar((state->output_is_a_tty) ? '\r' : '\n');\r
+- fflush (stdout);\r
+- }\r
+-\r
+- status = notmuch_database_add_message (notmuch, next, &message);\r
+- switch (status) {\r
+- /* success */\r
+- case NOTMUCH_STATUS_SUCCESS:\r
+- state->added_messages++;\r
+- tag_inbox_and_unread (message);\r
+- break;\r
+- /* Non-fatal issues (go on to next file) */\r
+- case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID:\r
+- /* Stay silent on this one. */\r
+- break;\r
+- case NOTMUCH_STATUS_FILE_NOT_EMAIL:\r
+- fprintf (stderr, "Note: Ignoring non-mail file: %s\n",\r
+- next);\r
+- break;\r
+- /* Fatal issues. Don't process anymore. */\r
+- case NOTMUCH_STATUS_READ_ONLY_DATABASE:\r
+- case NOTMUCH_STATUS_XAPIAN_EXCEPTION:\r
+- case NOTMUCH_STATUS_OUT_OF_MEMORY:\r
+- fprintf (stderr, "Error: %s. Halting processing.\n",\r
+- notmuch_status_to_string (status));\r
+- ret = status;\r
+- goto DONE;\r
+- default:\r
+- case NOTMUCH_STATUS_FILE_ERROR:\r
+- case NOTMUCH_STATUS_NULL_POINTER:\r
+- case NOTMUCH_STATUS_TAG_TOO_LONG:\r
+- case NOTMUCH_STATUS_UNBALANCED_FREEZE_THAW:\r
+- case NOTMUCH_STATUS_LAST_STATUS:\r
+- INTERNAL_ERROR ("add_message returned unexpected value: %d", status);\r
+- goto DONE;\r
+- }\r
+-\r
+- if (message) {\r
+- notmuch_message_destroy (message);\r
+- message = NULL;\r
+- }\r
+-\r
+- if (do_add_files_print_progress) {\r
+- do_add_files_print_progress = 0;\r
+- add_files_print_progress (state);\r
+- }\r
+-\r
+- talloc_free (next);\r
+- next = NULL;\r
+- }\r
+-\r
+- /* Now that we've walked the whole filesystem list, anything left\r
+- * over in the database lists has been deleted. */\r
+- while (notmuch_filenames_valid (db_files))\r
+- {\r
+- char *absolute = talloc_asprintf (state->removed_files,\r
+- "%s/%s", path,\r
+- notmuch_filenames_get (db_files));\r
+-\r
+- _filename_list_add (state->removed_files, absolute);\r
+-\r
+- notmuch_filenames_move_to_next (db_files);\r
+- }\r
+-\r
+- while (notmuch_filenames_valid (db_subdirs))\r
+- {\r
+- char *absolute = talloc_asprintf (state->removed_directories,\r
+- "%s/%s", path,\r
+- notmuch_filenames_get (db_subdirs));\r
+-\r
+- _filename_list_add (state->removed_directories, absolute);\r
+-\r
+- notmuch_filenames_move_to_next (db_subdirs);\r
+- }\r
+-\r
+- if (! interrupted) {\r
+- status = notmuch_directory_set_mtime (directory, fs_mtime);\r
+- if (status && ret == NOTMUCH_STATUS_SUCCESS)\r
+- ret = status;\r
+- }\r
+-\r
+- DONE:\r
+- if (next)\r
+- talloc_free (next);\r
+- if (entry)\r
+- free (entry);\r
+- if (dir)\r
+- closedir (dir);\r
+- if (fs_entries)\r
+- free (fs_entries);\r
+- if (db_subdirs)\r
+- notmuch_filenames_destroy (db_subdirs);\r
+- if (db_files)\r
+- notmuch_filenames_destroy (db_files);\r
+- if (directory)\r
+- notmuch_directory_destroy (directory);\r
+-\r
+- return ret;\r
++ putchar((print_ctx->output_is_a_tty) ? '\r' : '\n');\r
++ fflush (stdout);\r
+ }\r
+ \r
+ /* This is the top-level entry point for add_files. It does a couple\r
+ * of error checks, sets up the progress-printing timer and then calls\r
+ * into the recursive function. */\r
+ static notmuch_status_t\r
+-add_files (notmuch_database_t *notmuch,\r
++add_files (notmuch_mailstore_t *mailstore,\r
+ const char *path,\r
+- add_files_state_t *state)\r
++ notmuch_indexing_context_t *state) /* FIXME: rename */\r
+ {\r
++ struct print_ctx *print_ctx = state->print_ctx;\r
+ notmuch_status_t status;\r
+ struct sigaction action;\r
+ struct itimerval timerval;\r
+ notmuch_bool_t timer_is_active = FALSE;\r
+ struct stat st;\r
+ \r
+- if (state->output_is_a_tty && ! debugger_is_active () && ! state->verbose) {\r
++ state->print_progress = 0;\r
++ state->print_progress_cb = add_files_print_progress;\r
++ state->print_verbose_cb = add_files_print_verbose;\r
++\r
++ if (print_ctx->output_is_a_tty && ! debugger_is_active () && ! state->verbose) {\r
+ /* Setup our handler for SIGALRM */\r
+ memset (&action, 0, sizeof (struct sigaction));\r
+ action.sa_handler = handle_sigalrm;\r
+@@ -546,7 +141,7 @@ add_files (notmuch_database_t *notmuch,\r
+ return NOTMUCH_STATUS_FILE_ERROR;\r
+ }\r
+ \r
+- status = add_files_recursive (notmuch, path, state);\r
++ status = notmuch_mailstore_index_new (mailstore, path, state);\r
+ \r
+ if (timer_is_active) {\r
+ /* Now stop the timer. */\r
+@@ -564,80 +159,12 @@ add_files (notmuch_database_t *notmuch,\r
+ return status;\r
+ }\r
+ \r
+-/* XXX: This should be merged with the add_files function since it\r
+- * shares a lot of logic with it. */\r
+-/* Recursively count all regular files in path and all sub-directories\r
+- * of path. The result is added to *count (which should be\r
+- * initialized to zero by the top-level caller before calling\r
+- * count_files). */\r
+-static void\r
+-count_files (const char *path, int *count)\r
+-{\r
+- struct dirent *entry = NULL;\r
+- char *next;\r
+- struct stat st;\r
+- struct dirent **fs_entries = NULL;\r
+- int num_fs_entries = scandir (path, &fs_entries, 0, dirent_sort_inode);\r
+- int i = 0;\r
+-\r
+- if (num_fs_entries == -1) {\r
+- fprintf (stderr, "Warning: failed to open directory %s: %s\n",\r
+- path, strerror (errno));\r
+- goto DONE;\r
+- }\r
+-\r
+- while (!interrupted) {\r
+- if (i == num_fs_entries)\r
+- break;\r
+-\r
+- entry = fs_entries[i++];\r
+-\r
+- /* Ignore special directories to avoid infinite recursion.\r
+- * Also ignore the .notmuch directory.\r
+- */\r
+- /* XXX: Eventually we'll want more sophistication to let the\r
+- * user specify files to be ignored. */\r
+- if (strcmp (entry->d_name, ".") == 0 ||\r
+- strcmp (entry->d_name, "..") == 0 ||\r
+- strcmp (entry->d_name, ".notmuch") == 0)\r
+- {\r
+- continue;\r
+- }\r
+-\r
+- if (asprintf (&next, "%s/%s", path, entry->d_name) == -1) {\r
+- next = NULL;\r
+- fprintf (stderr, "Error descending from %s to %s: Out of memory\n",\r
+- path, entry->d_name);\r
+- continue;\r
+- }\r
+-\r
+- stat (next, &st);\r
+-\r
+- if (S_ISREG (st.st_mode)) {\r
+- *count = *count + 1;\r
+- if (*count % 1000 == 0) {\r
+- printf ("Found %d files so far.\r", *count);\r
+- fflush (stdout);\r
+- }\r
+- } else if (S_ISDIR (st.st_mode)) {\r
+- count_files (next, count);\r
+- }\r
+-\r
+- free (next);\r
+- }\r
+-\r
+- DONE:\r
+- if (entry)\r
+- free (entry);\r
+- if (fs_entries)\r
+- free (fs_entries);\r
+-}\r
+-\r
+ static void\r
+ upgrade_print_progress (void *closure,\r
+ double progress)\r
+ {\r
+- add_files_state_t *state = closure;\r
++ notmuch_indexing_context_t *state = closure;\r
++ struct print_ctx *print_ctx = state->print_ctx;\r
+ \r
+ printf ("Upgrading database: %.2f%% complete", progress * 100.0);\r
+ \r
+@@ -647,7 +174,7 @@ upgrade_print_progress (void *closure,\r
+ \r
+ gettimeofday (&tv_now, NULL);\r
+ \r
+- elapsed = notmuch_time_elapsed (state->tv_start, tv_now);\r
++ elapsed = notmuch_time_elapsed (print_ctx->tv_start, tv_now);\r
+ time_remaining = (elapsed / progress) * (1.0 - progress);\r
+ printf (" (");\r
+ notmuch_time_print_formatted_seconds (time_remaining);\r
+@@ -659,55 +186,13 @@ upgrade_print_progress (void *closure,\r
+ fflush (stdout);\r
+ }\r
+ \r
+-/* Recursively remove all filenames from the database referring to\r
+- * 'path' (or to any of its children). */\r
+-static void\r
+-_remove_directory (void *ctx,\r
+- notmuch_database_t *notmuch,\r
+- const char *path,\r
+- int *renamed_files,\r
+- int *removed_files)\r
+-{\r
+- notmuch_directory_t *directory;\r
+- notmuch_filenames_t *files, *subdirs;\r
+- notmuch_status_t status;\r
+- char *absolute;\r
+-\r
+- directory = notmuch_database_get_directory (notmuch, path);\r
+-\r
+- for (files = notmuch_directory_get_child_files (directory);\r
+- notmuch_filenames_valid (files);\r
+- notmuch_filenames_move_to_next (files))\r
+- {\r
+- absolute = talloc_asprintf (ctx, "%s/%s", path,\r
+- notmuch_filenames_get (files));\r
+- status = notmuch_database_remove_message (notmuch, absolute);\r
+- if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)\r
+- *renamed_files = *renamed_files + 1;\r
+- else\r
+- *removed_files = *removed_files + 1;\r
+- talloc_free (absolute);\r
+- }\r
+-\r
+- for (subdirs = notmuch_directory_get_child_directories (directory);\r
+- notmuch_filenames_valid (subdirs);\r
+- notmuch_filenames_move_to_next (subdirs))\r
+- {\r
+- absolute = talloc_asprintf (ctx, "%s/%s", path,\r
+- notmuch_filenames_get (subdirs));\r
+- _remove_directory (ctx, notmuch, absolute, renamed_files, removed_files);\r
+- talloc_free (absolute);\r
+- }\r
+-\r
+- notmuch_directory_destroy (directory);\r
+-}\r
+-\r
+ int\r
+ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ {\r
+ notmuch_config_t *config;\r
+ notmuch_database_t *notmuch;\r
+- add_files_state_t add_files_state;\r
++ struct print_ctx print_ctx;\r
++ notmuch_indexing_context_t add_files_state; /* FIXME: Rename */\r
+ double elapsed;\r
+ struct timeval tv_now;\r
+ int ret = 0;\r
+@@ -715,13 +200,15 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ const char *db_path;\r
+ char *dot_notmuch_path;\r
+ struct sigaction action;\r
+- _filename_node_t *f;\r
+- int renamed_files, removed_files;\r
+- notmuch_status_t status;\r
+ int i;\r
++ notmuch_mailstore_t *mailstore;\r
++\r
++ memset (&add_files_state, 0, sizeof(add_files_state));\r
++ indexing_ctx = &add_files_state;\r
+ \r
+ add_files_state.verbose = 0;\r
+- add_files_state.output_is_a_tty = isatty (fileno (stdout));\r
++ add_files_state.print_ctx = &print_ctx;\r
++ print_ctx.output_is_a_tty = isatty (fileno (stdout));\r
+ \r
+ for (i = 0; i < argc && argv[i][0] == '-'; i++) {\r
+ if (STRNCMP_LITERAL (argv[i], "--verbose") == 0) {\r
+@@ -737,6 +224,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ return 1;\r
+ \r
+ db_path = notmuch_config_get_database_path (config);\r
++ mailstore = notmuch_config_get_mailstore (config);\r
+ \r
+ dot_notmuch_path = talloc_asprintf (ctx, "%s/%s", db_path, ".notmuch");\r
+ \r
+@@ -744,31 +232,29 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ int count;\r
+ \r
+ count = 0;\r
+- count_files (db_path, &count);\r
++ notmuch_mailstore_count_files (mailstore, db_path, &count, &interrupted);\r
+ if (interrupted)\r
+ return 1;\r
+ \r
+ printf ("Found %d total files (that's not much mail).\n", count);\r
+- notmuch = notmuch_database_create (db_path,\r
+- notmuch_config_get_mailstore (config));\r
+- add_files_state.total_files = count;\r
++ notmuch = notmuch_database_create (db_path, mailstore);\r
++ print_ctx.total_files = count;\r
+ } else {\r
+- notmuch = notmuch_database_open (db_path,\r
+- NOTMUCH_DATABASE_MODE_READ_WRITE,\r
+- notmuch_config_get_mailstore (config));\r
++ notmuch = notmuch_database_open (db_path, NOTMUCH_DATABASE_MODE_READ_WRITE,\r
++ mailstore);\r
+ if (notmuch == NULL)\r
+ return 1;\r
+ \r
+ if (notmuch_database_needs_upgrade (notmuch)) {\r
+ printf ("Welcome to a new version of notmuch! Your database will now be upgraded.\n");\r
+- gettimeofday (&add_files_state.tv_start, NULL);\r
++ gettimeofday (&print_ctx.tv_start, NULL);\r
+ notmuch_database_upgrade (notmuch, upgrade_print_progress,\r
+ &add_files_state);\r
+ printf ("Your notmuch database has now been upgraded to database format version %u.\n",\r
+ notmuch_database_get_version (notmuch));\r
+ }\r
+ \r
+- add_files_state.total_files = 0;\r
++ print_ctx.total_files = 0;\r
+ }\r
+ \r
+ if (notmuch == NULL)\r
+@@ -777,6 +263,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ /* Setup our handler for SIGINT. We do this after having\r
+ * potentially done a database upgrade we this interrupt handler\r
+ * won't support. */\r
++ add_files_state.interrupted = 0;\r
+ memset (&action, 0, sizeof (struct sigaction));\r
+ action.sa_handler = handle_sigint;\r
+ sigemptyset (&action.sa_mask);\r
+@@ -788,33 +275,12 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ \r
+ add_files_state.processed_files = 0;\r
+ add_files_state.added_messages = 0;\r
+- gettimeofday (&add_files_state.tv_start, NULL);\r
+-\r
+- add_files_state.removed_files = _filename_list_create (ctx);\r
+- add_files_state.removed_directories = _filename_list_create (ctx);\r
+-\r
+- ret = add_files (notmuch, db_path, &add_files_state);\r
+-\r
+- removed_files = 0;\r
+- renamed_files = 0;\r
+- for (f = add_files_state.removed_files->head; f; f = f->next) {\r
+- status = notmuch_database_remove_message (notmuch, f->filename);\r
+- if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)\r
+- renamed_files++;\r
+- else\r
+- removed_files++;\r
+- }\r
+-\r
+- for (f = add_files_state.removed_directories->head; f; f = f->next) {\r
+- _remove_directory (ctx, notmuch, f->filename,\r
+- &renamed_files, &removed_files);\r
+- }\r
++ gettimeofday (&print_ctx.tv_start, NULL);\r
+ \r
+- talloc_free (add_files_state.removed_files);\r
+- talloc_free (add_files_state.removed_directories);\r
++ ret = add_files (mailstore, db_path, &add_files_state);\r
+ \r
+ gettimeofday (&tv_now, NULL);\r
+- elapsed = notmuch_time_elapsed (add_files_state.tv_start,\r
++ elapsed = notmuch_time_elapsed (print_ctx.tv_start,\r
+ tv_now);\r
+ \r
+ if (add_files_state.processed_files) {\r
+@@ -839,16 +305,16 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\r
+ printf ("No new mail.");\r
+ }\r
+ \r
+- if (removed_files) {\r
++ if (add_files_state.removed_files) {\r
+ printf (" Removed %d %s.",\r
+- removed_files,\r
+- removed_files == 1 ? "message" : "messages");\r
++ add_files_state.removed_files,\r
++ add_files_state.removed_files == 1 ? "message" : "messages");\r
+ }\r
+ \r
+- if (renamed_files) {\r
++ if (add_files_state.renamed_files) {\r
+ printf (" Detected %d file %s.",\r
+- renamed_files,\r
+- renamed_files == 1 ? "rename" : "renames");\r
++ add_files_state.renamed_files,\r
++ add_files_state.renamed_files == 1 ? "rename" : "renames");\r
+ }\r
+ \r
+ printf ("\n");\r
+-- \r
+1.7.0.2\r
+\r