[notmuch] [PATCH 1/4] Mailstore abstraction interface
authorMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 18 Mar 2010 15:39:37 +0000 (16:39 +0100)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 17:36:24 +0000 (09:36 -0800)
00/e13fce76588ebe4721e8e5b278c7b03897edbc [new file with mode: 0644]

diff --git a/00/e13fce76588ebe4721e8e5b278c7b03897edbc b/00/e13fce76588ebe4721e8e5b278c7b03897edbc
new file mode 100644 (file)
index 0000000..160a2a0
--- /dev/null
@@ -0,0 +1,786 @@
+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 23FBE404965\r
+       for <notmuch@notmuchmail.org>; Thu, 18 Mar 2010 08:40:59 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -2.269\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-2.269 tagged_above=-999 required=5 tests=[AWL=0.330,\r
+       BAYES_00=-2.599] 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 OKmA-PbJGQQg for <notmuch@notmuchmail.org>;\r
+       Thu, 18 Mar 2010 08:40:55 -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 81BEE404964\r
+       for <notmuch@notmuchmail.org>; Thu, 18 Mar 2010 08:40:54 -0700 (PDT)\r
+Received: from localhost (unknown [192.168.200.4])\r
+       by max.feld.cvut.cz (Postfix) with ESMTP id E82B719F3409;\r
+       Thu, 18 Mar 2010 16:40:53 +0100 (CET)\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 xS-7LdHy5MBJ; Thu, 18 Mar 2010 16:40:51 +0100 (CET)\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 1D18519F3401;\r
+       Thu, 18 Mar 2010 16:40:51 +0100 (CET)\r
+Received: from steelpick.localdomain (k335-30.felk.cvut.cz [147.32.86.30])\r
+       (Authenticated sender: sojkam1)\r
+       by imap.feld.cvut.cz (Postfix) with ESMTPSA id ED612FA004;\r
+       Thu, 18 Mar 2010 16:40:50 +0100 (CET)\r
+Received: from wsh by steelpick.localdomain with local (Exim 4.71)\r
+       (envelope-from <sojkam1@fel.cvut.cz>)\r
+       id 1NsHq6-0005Hf-It; Thu, 18 Mar 2010 16:40:50 +0100\r
+From: Michal Sojka <sojkam1@fel.cvut.cz>\r
+To: notmuch@notmuchmail.org\r
+Date: Thu, 18 Mar 2010 16:39:37 +0100\r
+Message-Id: <1268926780-20045-2-git-send-email-sojkam1@fel.cvut.cz>\r
+X-Mailer: git-send-email 1.7.0\r
+In-Reply-To: <1268926780-20045-1-git-send-email-sojkam1@fel.cvut.cz>\r
+References: <1268926780-20045-1-git-send-email-sojkam1@fel.cvut.cz>\r
+Subject: [notmuch] [PATCH 1/4] Mailstore abstraction interface\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, 18 Mar 2010 15:40:59 -0000\r
+\r
+The goal of mailstore abstraction is to allow notmuch to store tags\r
+together with email messages. The abstract interface is needed because\r
+people want to use different ways of storing their emails. This\r
+patchseries implements two types of mailstore - plain files and\r
+maildir. It is expected that additional git-based mailstore will\r
+follow.\r
+\r
+This patch contains only the interface changes. No functionality is\r
+added, removed or changed.\r
+\r
+A new configuration group [mailstore] is defined. Currently, there is\r
+only one key 'type' whose value determines the used mailstore. The\r
+default value of this option is the plain-file mailstore currently\r
+implemented in notmuch.\r
+\r
+Signed-off-by: Michal Sojka <sojkam1@fel.cvut.cz>\r
+---\r
+ lib/Makefile.local      |    2 +\r
+ lib/database-private.h  |    1 +\r
+ lib/database.cc         |   15 ++++++--\r
+ lib/mailstore-files.c   |   43 ++++++++++++++++++++++++\r
+ lib/mailstore-private.h |   59 ++++++++++++++++++++++++++++++++\r
+ lib/mailstore.c         |   77 ++++++++++++++++++++++++++++++++++++++++++\r
+ lib/message.cc          |   13 +++++++\r
+ lib/notmuch.h           |   85 ++++++++++++++++++++++++++++++++++++++++++++--\r
+ notmuch-client.h        |    7 ++++\r
+ notmuch-config.c        |   34 +++++++++++++++++++\r
+ notmuch-count.c         |    3 +-\r
+ notmuch-dump.c          |    3 +-\r
+ notmuch-new.c           |    6 ++-\r
+ notmuch-reply.c         |    3 +-\r
+ notmuch-restore.c       |    3 +-\r
+ notmuch-search-tags.c   |    3 +-\r
+ notmuch-search.c        |    3 +-\r
+ notmuch-show.c          |    3 +-\r
+ notmuch-tag.c           |    3 +-\r
+ 19 files changed, 348 insertions(+), 18 deletions(-)\r
+ create mode 100644 lib/mailstore-files.c\r
+ create mode 100644 lib/mailstore-private.h\r
+ create mode 100644 lib/mailstore.c\r
+\r
+diff --git a/lib/Makefile.local b/lib/Makefile.local\r
+index 495b27e..fc8883d 100644\r
+--- a/lib/Makefile.local\r
++++ b/lib/Makefile.local\r
+@@ -3,6 +3,8 @@ extra_cflags += -I$(dir)\r
\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/lib/database-private.h b/lib/database-private.h\r
+index 41918d7..4499b1a 100644\r
+--- a/lib/database-private.h\r
++++ b/lib/database-private.h\r
+@@ -49,6 +49,7 @@ struct _notmuch_database {\r
+     Xapian::TermGenerator *term_gen;\r
+     Xapian::ValueRangeProcessor *value_range_processor;\r
\r
++    notmuch_mailstore_t *mailstore;\r
+ };\r
\r
+ /* Convert tags from Xapian internal format to notmuch format.\r
+diff --git a/lib/database.cc b/lib/database.cc\r
+index c91e97c..93c8d0f 100644\r
+--- a/lib/database.cc\r
++++ b/lib/database.cc\r
+@@ -19,6 +19,7 @@\r
+  */\r
\r
+ #include "database-private.h"\r
++#include "mailstore-private.h"\r
\r
+ #include <iostream>\r
\r
+@@ -438,7 +439,7 @@ parse_references (void *ctx,\r
+ }\r
\r
+ notmuch_database_t *\r
+-notmuch_database_create (const char *path)\r
++notmuch_database_create (const char *path, notmuch_mailstore_t *mailstore)\r
+ {\r
+     notmuch_database_t *notmuch = NULL;\r
+     char *notmuch_path = NULL;\r
+@@ -474,7 +475,8 @@ notmuch_database_create (const char *path)\r
+     }\r
\r
+     notmuch = notmuch_database_open (path,\r
+-                                   NOTMUCH_DATABASE_MODE_READ_WRITE);\r
++                                   NOTMUCH_DATABASE_MODE_READ_WRITE,\r
++                                   mailstore);\r
+     notmuch_database_upgrade (notmuch, NULL, NULL);\r
\r
+   DONE:\r
+@@ -497,7 +499,8 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch)\r
\r
+ notmuch_database_t *\r
+ notmuch_database_open (const char *path,\r
+-                     notmuch_database_mode_t mode)\r
++                     notmuch_database_mode_t mode,\r
++                     notmuch_mailstore_t *mailstore)\r
+ {\r
+     notmuch_database_t *notmuch = NULL;\r
+     char *notmuch_path = NULL, *xapian_path = NULL;\r
+@@ -605,6 +608,9 @@ notmuch_database_open (const char *path,\r
+           prefix_t *prefix = &PROBABILISTIC_PREFIX[i];\r
+           notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);\r
+       }\r
++\r
++      notmuch->mailstore = mailstore;\r
++      mailstore->notmuch = notmuch;\r
+     } catch (const Xapian::Error &error) {\r
+       fprintf (stderr, "A Xapian exception occurred opening database: %s\n",\r
+                error.get_msg().c_str());\r
+@@ -1493,7 +1499,8 @@ notmuch_database_add_message (notmuch_database_t *notmuch,\r
\r
+   DONE:\r
+     if (message) {\r
+-      if (ret == NOTMUCH_STATUS_SUCCESS && message_ret)\r
++      if ((ret == NOTMUCH_STATUS_SUCCESS ||\r
++           ret == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) && message_ret)\r
+           *message_ret = message;\r
+       else\r
+           notmuch_message_destroy (message);\r
+diff --git a/lib/mailstore-files.c b/lib/mailstore-files.c\r
+new file mode 100644\r
+index 0000000..92d7f5d\r
+--- /dev/null\r
++++ b/lib/mailstore-files.c\r
+@@ -0,0 +1,43 @@\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
++ * 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
++ * Authors: Carl Worth <cworth@cworth.org>\r
++ *        Michal Sojka <sojkam1@fel.cvut.cz>\r
++ */\r
++\r
++#include "notmuch.h"\r
++#include "mailstore-private.h"\r
++\r
++\r
++static FILE *\r
++open_file(notmuch_mailstore_t *mailstore, const char *filename)\r
++{\r
++    const char *db_path, *abs_filename;\r
++\r
++    db_path = notmuch_database_get_path(mailstore->notmuch);\r
++    abs_filename = talloc_asprintf(mailstore, "%s/%s", db_path, filename);\r
++    if (unlikely(abs_filename == NULL))\r
++      return NULL;\r
++    return fopen (abs_filename, "r");\r
++}\r
++\r
++/* Original notmuch mail store */\r
++struct _notmuch_mailstore mailstore_files = {\r
++    .type = "files",\r
++    .open_file = open_file,\r
++};\r
+diff --git a/lib/mailstore-private.h b/lib/mailstore-private.h\r
+new file mode 100644\r
+index 0000000..f606e3f\r
+--- /dev/null\r
++++ b/lib/mailstore-private.h\r
+@@ -0,0 +1,59 @@\r
++/* mailstore-private.h - Mailstore abstraction\r
++ *\r
++ * Copyright © 2010 Michal Sojka\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: Michal Sojka <sojkam1@fel.cvut.cz>\r
++ */\r
++\r
++#ifndef MAILSTORE_PRIVATE_H\r
++#define MAILSTORE_PRIVATE_H\r
++\r
++#include "notmuch-private.h"\r
++\r
++struct _notmuch_mailstore {\r
++    /* Constant fields */\r
++    const char *type;      /* identification in .notmuch-config */\r
++    void *priv;\r
++\r
++    /* Count files in mailstore so that initial invocation of notmuch\r
++     * new can report remaining time */\r
++    void (*count_files)(notmuch_mailstore_t *mailstore,\r
++                      const char *path, int *count,\r
++                      volatile sig_atomic_t *interrupted);\r
++    /* Scan for new messages and add them to the database. */\r
++    notmuch_private_status_t (*index_new)(notmuch_mailstore_t *mailstore,\r
++                                        const char* path,\r
++                                        notmuch_indexing_context_t *ctx);\r
++    /* Store the tags assigned to the 'messages' to the\r
++     * 'mailstore'. */\r
++    notmuch_private_status_t (*sync_tags)(notmuch_mailstore_t *mailstore,\r
++                                        notmuch_message_t *message);\r
++    /* Return file handle from which the message can be read.\r
++     *\r
++     * Currently, this is not used and all message access is hardcoded\r
++     * to notmuch. We will need this operation for git-based and other\r
++     * non-filesystem mailstores. */\r
++    FILE * (*open_file)(notmuch_mailstore_t *mailstore,\r
++                      const char *filename);\r
++\r
++    /* Run-time fields */\r
++    notmuch_database_t *notmuch;\r
++};\r
++\r
++extern struct _notmuch_mailstore mailstore_files;\r
++extern struct _notmuch_mailstore mailstore_maildir;\r
++\r
++#endif /* MAILSTORE_PRIVATE_H */\r
+diff --git a/lib/mailstore.c b/lib/mailstore.c\r
+new file mode 100644\r
+index 0000000..cdac9a6\r
+--- /dev/null\r
++++ b/lib/mailstore.c\r
+@@ -0,0 +1,77 @@\r
++/* mailstore.c - Mailstore abstraction\r
++ *\r
++ * Copyright © 2010 Michal Sojka\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: Michal Sojka <sojkam1@fel.cvut.cz>\r
++ */\r
++\r
++#include <notmuch.h>\r
++#include "mailstore-private.h"\r
++\r
++#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr[0]))\r
++\r
++static notmuch_mailstore_t *available[] = {\r
++    &mailstore_files,\r
++};\r
++\r
++notmuch_mailstore_t *\r
++notmuch_mailstore_get_by_type (const char *type)\r
++{\r
++    unsigned i;\r
++\r
++    if (type == NULL)\r
++      return available[0];\r
++\r
++    for (i = 0; i < ARRAY_SIZE(available); i++) {\r
++      if (strcasecmp (type, available[i]->type) == 0)\r
++          return available[i];\r
++    }\r
++    return NULL;\r
++}\r
++\r
++const char *\r
++notmuch_mailstore_get_type (notmuch_mailstore_t *mailstore)\r
++{\r
++    if (!mailstore)\r
++      return NULL;\r
++\r
++    return mailstore->type;\r
++}\r
++\r
++void\r
++notmuch_mailstore_count_files (notmuch_mailstore_t *mailstore,\r
++                            const char *path, int *count,\r
++                            volatile sig_atomic_t *interrupted)\r
++{\r
++    mailstore->count_files (mailstore, path, count, interrupted);\r
++}\r
++\r
++notmuch_status_t\r
++notmuch_mailstore_index_new (notmuch_mailstore_t *mailstore,\r
++                          const char *path,\r
++                          notmuch_indexing_context_t *ctx)\r
++{\r
++    notmuch_private_status_t status;\r
++    status = mailstore->index_new (mailstore, path, ctx);\r
++    return COERCE_STATUS (status, "Index new");\r
++}\r
++\r
++FILE *\r
++notmuch_mailstore_open_file (notmuch_mailstore_t *mailstore,\r
++                           const char *filename)\r
++{\r
++    return mailstore->open_file (mailstore, filename);\r
++}\r
+diff --git a/lib/message.cc b/lib/message.cc\r
+index 721c9a6..c32ee7d 100644\r
+--- a/lib/message.cc\r
++++ b/lib/message.cc\r
+@@ -20,6 +20,7 @@\r
\r
+ #include "notmuch-private.h"\r
+ #include "database-private.h"\r
++#include "mailstore-private.h"\r
\r
+ #include <stdint.h>\r
\r
+@@ -555,10 +556,22 @@ void\r
+ _notmuch_message_sync (notmuch_message_t *message)\r
+ {\r
+     Xapian::WritableDatabase *db;\r
++    notmuch_private_status_t status;\r
\r
+     if (message->notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY)\r
+       return;\r
\r
++    if (message->notmuch->mailstore->sync_tags) {\r
++      status = message->notmuch->mailstore->sync_tags (message->notmuch->mailstore,\r
++                                                       message);\r
++      if (status != NOTMUCH_PRIVATE_STATUS_SUCCESS) {\r
++          fprintf (stderr, "Error: Cannot sync tags to mailstore (%s)\n",\r
++                   notmuch_status_to_string ((notmuch_status_t)status));\r
++          /* Exit to avoid unsynchronized mailstore. */\r
++          exit(1);\r
++      }\r
++    }\r
++\r
+     db = static_cast <Xapian::WritableDatabase *> (message->notmuch->xapian_db);\r
+     db->replace_document (message->doc_id, message->doc);\r
+ }\r
+diff --git a/lib/notmuch.h b/lib/notmuch.h\r
+index 0d9cb0f..4f4cc8b 100644\r
+--- a/lib/notmuch.h\r
++++ b/lib/notmuch.h\r
+@@ -32,6 +32,9 @@\r
+ NOTMUCH_BEGIN_DECLS\r
\r
+ #include <time.h>\r
++#include <sys/time.h>         /* For struct timeval */\r
++#include <signal.h>           /* For sig_atomic_t */\r
++#include <stdio.h>            /* For FILE */\r
\r
+ #ifndef FALSE\r
+ #define FALSE 0\r
+@@ -119,6 +122,8 @@ typedef struct _notmuch_message notmuch_message_t;\r
+ typedef struct _notmuch_tags notmuch_tags_t;\r
+ typedef struct _notmuch_directory notmuch_directory_t;\r
+ typedef struct _notmuch_filenames notmuch_filenames_t;\r
++typedef struct _notmuch_mailstore notmuch_mailstore_t;\r
++\r
\r
+ /* Create a new, empty notmuch database located at 'path'.\r
+  *\r
+@@ -127,6 +132,8 @@ typedef struct _notmuch_filenames notmuch_filenames_t;\r
+  * create a new ".notmuch" directory within 'path' where notmuch will\r
+  * store its data.\r
+  *\r
++ * FIXME: Mailstore...\r
++ *\r
+  * After a successful call to notmuch_database_create, the returned\r
+  * database will be open so the caller should call\r
+  * notmuch_database_close when finished with it.\r
+@@ -140,7 +147,7 @@ typedef struct _notmuch_filenames notmuch_filenames_t;\r
+  * an error message on stderr).\r
+  */\r
+ notmuch_database_t *\r
+-notmuch_database_create (const char *path);\r
++notmuch_database_create (const char *path, notmuch_mailstore_t *mailstore);\r
\r
+ typedef enum {\r
+     NOTMUCH_DATABASE_MODE_READ_ONLY = 0,\r
+@@ -152,6 +159,8 @@ typedef enum {\r
\r
+ /* Open an existing notmuch database located at 'path'.\r
+  *\r
++ * The database will index mails stored in 'mailstore'.\r
++ *\r
+  * The database should have been created at some time in the past,\r
+  * (not necessarily by this process), by calling\r
+  * notmuch_database_create with 'path'. By default the database should be\r
+@@ -169,7 +178,8 @@ typedef enum {\r
+  */\r
+ notmuch_database_t *\r
+ notmuch_database_open (const char *path,\r
+-                     notmuch_database_mode_t mode);\r
++                     notmuch_database_mode_t mode,\r
++                     notmuch_mailstore_t *mailstore);\r
\r
+ /* Close the given notmuch database, freeing all associated\r
+  * resources. See notmuch_database_open. */\r
+@@ -236,7 +246,8 @@ notmuch_database_get_directory (notmuch_database_t *database,\r
+  * notmuch database will reference the filename, and will not copy the\r
+  * entire contents of the file.\r
+  *\r
+- * If 'message' is not NULL, then, on successful return '*message'\r
++ * If 'message' is not NULL, then, on successful return\r
++ * (NOTMUCH_STATUS_SUCCESS or NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) '*message'\r
+  * will be initialized to a message object that can be used for things\r
+  * such as adding tags to the just-added message. The user should call\r
+  * notmuch_message_destroy when done with the message. On any failure\r
+@@ -495,7 +506,7 @@ notmuch_threads_destroy (notmuch_threads_t *threads);\r
+  */\r
+ unsigned\r
+ notmuch_query_count_messages (notmuch_query_t *query);\r
+- \r
++\r
+ /* Get the thread ID of 'thread'.\r
+  *\r
+  * The returned string belongs to 'thread' and as such, should not be\r
+@@ -1104,6 +1115,72 @@ notmuch_filenames_move_to_next (notmuch_filenames_t *filenames);\r
+ void\r
+ notmuch_filenames_destroy (notmuch_filenames_t *filenames);\r
\r
++/* Returns notmuch_mailstore_t object of a given 'type'.\r
++ *\r
++ * The 'type' is case insensitive. If 'type' is NULL, a default\r
++ * mailstore is returned.\r
++ *\r
++ * When no available mailstore matches 'type', NULL is returned.\r
++ */\r
++notmuch_mailstore_t *\r
++notmuch_mailstore_get_by_type (const char *type);\r
++\r
++/* Returns the type of a mailstore.\r
++ *\r
++ * The returned string is owned by mailstore so should not be modified\r
++ * nor freed by the caller.\r
++ */\r
++const char *\r
++notmuch_mailstore_get_type (notmuch_mailstore_t *mailstore);\r
++\r
++/* Count emails in mailstore.\r
++ *\r
++ * This function returns when interrupted is set to non-zero value.\r
++ */\r
++void\r
++notmuch_mailstore_count_files (notmuch_mailstore_t *mailstore,\r
++                            const char *path, int *count,\r
++                            volatile sig_atomic_t *interrupted);\r
++\r
++typedef struct notmuch_indexing_context {\r
++    int output_is_a_tty;\r
++    int verbose;\r
++\r
++    int total_files;\r
++    int processed_files;\r
++    int added_messages;\r
++    int renamed_files;\r
++    int removed_files;\r
++    struct timeval tv_start;\r
++\r
++    void *priv;\r
++\r
++    volatile sig_atomic_t interrupted;\r
++    volatile sig_atomic_t print_progress;\r
++    void (*print_progress_cb)(struct notmuch_indexing_context *ctx);\r
++\r
++} notmuch_indexing_context_t;\r
++\r
++\r
++/* Index new mails in the mailstore.\r
++ *\r
++ * Mailstore is responsible for detecting new emails, adding them to\r
++ * the database and tagging them with tags stored in the mailstore.\r
++ */\r
++notmuch_status_t\r
++notmuch_mailstore_index_new (notmuch_mailstore_t *mailstore,\r
++                          const char *path,\r
++                          notmuch_indexing_context_t *ctx);\r
++\r
++/* Returns file handle to the file in the mailstore.\r
++ *\r
++ * TODO: This function is currently not used and access to mails is\r
++ * hardcoded in other parts of notmuch.\r
++ */\r
++FILE *\r
++notmuch_mailstore_open_file (notmuch_mailstore_t *mailstore,\r
++                           const char *filename);\r
++\r
+ NOTMUCH_END_DECLS\r
\r
+ #endif\r
+diff --git a/notmuch-client.h b/notmuch-client.h\r
+index c80b39c..4794b8e 100644\r
+--- a/notmuch-client.h\r
++++ b/notmuch-client.h\r
+@@ -171,6 +171,13 @@ notmuch_config_set_user_other_email (notmuch_config_t *config,\r
+                                    const char *other_email[],\r
+                                    size_t length);\r
\r
++notmuch_mailstore_t *\r
++notmuch_config_get_mailstore(notmuch_config_t *config);\r
++\r
++void\r
++notmuch_config_set_mailstore(notmuch_config_t *config,\r
++                           notmuch_mailstore_t *mailstore);\r
++\r
+ notmuch_bool_t\r
+ debugger_is_active (void);\r
\r
+diff --git a/notmuch-config.c b/notmuch-config.c\r
+index 95430db..299423a 100644\r
+--- a/notmuch-config.c\r
++++ b/notmuch-config.c\r
+@@ -62,6 +62,7 @@ struct _notmuch_config {\r
+     char *user_primary_email;\r
+     char **user_other_email;\r
+     size_t user_other_email_length;\r
++    notmuch_mailstore_t *mailstore;\r
+ };\r
\r
+ static int\r
+@@ -199,6 +200,7 @@ notmuch_config_open (void *ctx,\r
+     config->user_primary_email = NULL;\r
+     config->user_other_email = NULL;\r
+     config->user_other_email_length = 0;\r
++    config->mailstore = NULL;\r
\r
+     if (! g_key_file_load_from_file (config->key_file,\r
+                                    config->filename,\r
+@@ -264,6 +266,10 @@ notmuch_config_open (void *ctx,\r
+       }\r
+     }\r
\r
++    if (notmuch_config_get_mailstore (config) == NULL) {\r
++      notmuch_config_set_mailstore(config, notmuch_mailstore_get_by_type(NULL));\r
++    }\r
++\r
+     /* When we create a new configuration file here, we  add some\r
+      * comments to help the user understand what can be done. */\r
+     if (is_new) {\r
+@@ -452,3 +458,31 @@ notmuch_config_set_user_other_email (notmuch_config_t *config,\r
+     talloc_free (config->user_other_email);\r
+     config->user_other_email = NULL;\r
+ }\r
++\r
++notmuch_mailstore_t *\r
++notmuch_config_get_mailstore(notmuch_config_t *config)\r
++{\r
++    char *type;\r
++\r
++    if (config->mailstore == NULL) {\r
++      type = g_key_file_get_string (config->key_file,\r
++                                    "mailstore", "type", NULL);\r
++      if (type) {\r
++          config->mailstore = notmuch_mailstore_get_by_type(type);\r
++          free (type);\r
++      }\r
++    }\r
++\r
++    return config->mailstore;\r
++}\r
++\r
++void\r
++notmuch_config_set_mailstore(notmuch_config_t *config,\r
++                           notmuch_mailstore_t *mailstore)\r
++{\r
++    g_key_file_set_string (config->key_file,\r
++                         "mailstore", "type",\r
++                         notmuch_mailstore_get_type(mailstore));\r
++\r
++    config->mailstore = NULL;\r
++}\r
+diff --git a/notmuch-count.c b/notmuch-count.c\r
+index 77aa433..631b8f8 100644\r
+--- a/notmuch-count.c\r
++++ b/notmuch-count.c\r
+@@ -81,7 +81,8 @@ notmuch_count_command (void *ctx, int argc, char *argv[])\r
+       return 1;\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_ONLY);\r
++                                   NOTMUCH_DATABASE_MODE_READ_ONLY,\r
++                                   notmuch_config_get_mailstore(config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+diff --git a/notmuch-dump.c b/notmuch-dump.c\r
+index 7e7bc17..e74dfcb 100644\r
+--- a/notmuch-dump.c\r
++++ b/notmuch-dump.c\r
+@@ -36,7 +36,8 @@ notmuch_dump_command (unused (void *ctx), int argc, char *argv[])\r
+       return 1;\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_ONLY);\r
++                                   NOTMUCH_DATABASE_MODE_READ_ONLY,\r
++                                   notmuch_config_get_mailstore (config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+diff --git a/notmuch-new.c b/notmuch-new.c\r
+index 44b50aa..2d0ba6c 100644\r
+--- a/notmuch-new.c\r
++++ b/notmuch-new.c\r
+@@ -749,11 +749,13 @@ notmuch_new_command (void *ctx, int argc, char *argv[])\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 = 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_DATABASE_MODE_READ_WRITE,\r
++                                       notmuch_config_get_mailstore (config));\r
+       if (notmuch == NULL)\r
+           return 1;\r
\r
+diff --git a/notmuch-reply.c b/notmuch-reply.c\r
+index 6c15536..0d6b7cf 100644\r
+--- a/notmuch-reply.c\r
++++ b/notmuch-reply.c\r
+@@ -468,7 +468,8 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])\r
+     }\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_ONLY);\r
++                                   NOTMUCH_DATABASE_MODE_READ_ONLY,\r
++                                   notmuch_config_get_mailstore (config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+diff --git a/notmuch-restore.c b/notmuch-restore.c\r
+index b0a4e1c..97d817b 100644\r
+--- a/notmuch-restore.c\r
++++ b/notmuch-restore.c\r
+@@ -37,7 +37,8 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])\r
+       return 1;\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_WRITE);\r
++                                   NOTMUCH_DATABASE_MODE_READ_WRITE,\r
++                                   notmuch_config_get_mailstore (config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+diff --git a/notmuch-search-tags.c b/notmuch-search-tags.c\r
+index 6f3cfcc..323f416 100644\r
+--- a/notmuch-search-tags.c\r
++++ b/notmuch-search-tags.c\r
+@@ -52,7 +52,8 @@ notmuch_search_tags_command (void *ctx, int argc, char *argv[])\r
+     }\r
\r
+     db = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                              NOTMUCH_DATABASE_MODE_READ_ONLY);\r
++                              NOTMUCH_DATABASE_MODE_READ_ONLY,\r
++                              notmuch_config_get_mailstore (config));\r
+     if (db == NULL) {\r
+       goto error;\r
+     }\r
+diff --git a/notmuch-search.c b/notmuch-search.c\r
+index 4e3514b..d57479d 100644\r
+--- a/notmuch-search.c\r
++++ b/notmuch-search.c\r
+@@ -245,7 +245,8 @@ notmuch_search_command (void *ctx, int argc, char *argv[])\r
+       return 1;\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_ONLY);\r
++                                   NOTMUCH_DATABASE_MODE_READ_ONLY,\r
++                                   notmuch_config_get_mailstore (config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+diff --git a/notmuch-show.c b/notmuch-show.c\r
+index ff1fecb..26581c1 100644\r
+--- a/notmuch-show.c\r
++++ b/notmuch-show.c\r
+@@ -458,7 +458,8 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))\r
+     }\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_ONLY);\r
++                                   NOTMUCH_DATABASE_MODE_READ_ONLY,\r
++                                   notmuch_config_get_mailstore (config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+diff --git a/notmuch-tag.c b/notmuch-tag.c\r
+index 8b6f7dc..5e1a5c3 100644\r
+--- a/notmuch-tag.c\r
++++ b/notmuch-tag.c\r
+@@ -97,7 +97,8 @@ notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[]))\r
+       return 1;\r
\r
+     notmuch = notmuch_database_open (notmuch_config_get_database_path (config),\r
+-                                   NOTMUCH_DATABASE_MODE_READ_WRITE);\r
++                                   NOTMUCH_DATABASE_MODE_READ_WRITE,\r
++                                   notmuch_config_get_mailstore (config));\r
+     if (notmuch == NULL)\r
+       return 1;\r
\r
+-- \r
+1.7.0\r
+\r