[PATCH 3/4] Access messages through mail store interface

Michal Sojka sojkam1 at fel.cvut.cz
Thu Apr 8 07:42:45 PDT 2010


This patch modifies notmuch binary to access the messages through mail
store interface, so that non-file based mail stores can also be
implemented.

The API of notmuch library was changed. Now,
notmuch_message_get_filename() returns relative file name with respect
to the database path. As a result, notmuch show also outputs relative
paths so that MUAs need to be changed.

Signed-off-by: Michal Sojka <sojkam1 at fel.cvut.cz>
---
 lib/database.cc       |   14 +++++++++++---
 lib/index.cc          |    8 ++++++--
 lib/mailstore-files.c |   18 +++++++++++++++++-
 lib/message-file.c    |    8 ++++----
 lib/message.cc        |   33 +++++++++++++++++++++++++--------
 lib/notmuch-private.h |    6 +++---
 lib/notmuch.h         |   16 ++++++++++++++--
 lib/sha1.c            |    6 +-----
 notmuch-client.h      |    2 +-
 notmuch-reply.c       |   10 +++++++++-
 notmuch-show.c        |   14 ++++++++++++--
 show-message.c        |   14 +-------------
 12 files changed, 104 insertions(+), 45 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 93c8d0f..bd64ed3 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1374,6 +1374,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
     notmuch_message_t *message = NULL;
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
     notmuch_private_status_t private_status;
+    const char *relative;
 
     const char *date, *header;
     const char *from, *to, *subject;
@@ -1386,7 +1387,8 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
     if (ret)
 	return ret;
 
-    message_file = notmuch_message_file_open (filename);
+    relative = _notmuch_database_relative_path (notmuch, filename);
+    message_file = notmuch_message_file_open (notmuch->mailstore, relative);
     if (message_file == NULL)
 	return NOTMUCH_STATUS_FILE_ERROR;
 
@@ -1438,9 +1440,15 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
 	}
 
 	if (message_id == NULL ) {
+	    FILE *file;
+	    char *sha1 = NULL;
 	    /* No message-id at all, let's generate one by taking a
 	     * hash over the file's contents. */
-	    char *sha1 = notmuch_sha1_of_file (filename);
+	    file = notmuch_mailstore_open_file (notmuch->mailstore, relative);
+	    if (file) {
+		sha1 = notmuch_sha1_of_file (file);
+		fclose (file);
+	    }
 
 	    /* If that failed too, something is really wrong. Give up. */
 	    if (sha1 == NULL) {
@@ -1483,7 +1491,7 @@ notmuch_database_add_message (notmuch_database_t *notmuch,
 	    date = notmuch_message_file_get_header (message_file, "date");
 	    _notmuch_message_set_date (message, date);
 
-	    _notmuch_message_index_file (message, filename);
+	    _notmuch_message_index_file (message, relative);
 	} else {
 	    ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
 	}
diff --git a/lib/index.cc b/lib/index.cc
index cf93025..4d8c4dd 100644
--- a/lib/index.cc
+++ b/lib/index.cc
@@ -425,15 +425,19 @@ _notmuch_message_index_file (notmuch_message_t *message,
     const char *from, *subject;
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
     static int initialized = 0;
+    notmuch_mailstore_t *mailstore;
 
     if (! initialized) {
 	g_mime_init (0);
 	initialized = 1;
     }
 
-    file = fopen (filename, "r");
+    mailstore = notmuch_message_get_mailstore(message);
+    file = notmuch_mailstore_open_file (mailstore, filename);
     if (! file) {
-	fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
+	fprintf (stderr, "Error opening %s: %s\n",
+		 notmuch_message_get_filename (message),
+		 strerror (errno));
 	ret = NOTMUCH_STATUS_FILE_ERROR;
 	goto DONE;
     }
diff --git a/lib/mailstore-files.c b/lib/mailstore-files.c
index 8b5e1d5..f2cb8d7 100644
--- a/lib/mailstore-files.c
+++ b/lib/mailstore-files.c
@@ -602,11 +602,27 @@ index_new(notmuch_mailstore_t *mailstore, const char* path,
     return ret;
 }
 
+static FILE *
+open_file(notmuch_mailstore_t *mailstore, const char *filename)
+{
+    const char *db_path;
+    char *abs_filename;
+    FILE *file;
+    
+    db_path = notmuch_database_get_path(mailstore->notmuch);
+    abs_filename = talloc_asprintf(NULL, "%s/%s", db_path, filename);
+    if (unlikely(abs_filename == NULL))
+	return NULL;
+    file = fopen (abs_filename, "r");
+    talloc_free(abs_filename);
+    return file;
+}
+
 /* Original notmuch mail store */
 struct _notmuch_mailstore mailstore_files = {
     .type = "files",
     .count_files = count_files,
     .index_new = index_new,
     .sync_tags = NULL,		/* We cannot store tags in this mailstore. */
-    .open_file = NULL,		/* Currently not implemented */
+    .open_file = open_file,
 };
diff --git a/lib/message-file.c b/lib/message-file.c
index 0c152a3..13c9f4c 100644
--- a/lib/message-file.c
+++ b/lib/message-file.c
@@ -94,7 +94,7 @@ _notmuch_message_file_destructor (notmuch_message_file_t *message)
 /* Create a new notmuch_message_file_t for 'filename' with 'ctx' as
  * the talloc owner. */
 notmuch_message_file_t *
-_notmuch_message_file_open_ctx (void *ctx, const char *filename)
+_notmuch_message_file_open_ctx (void *ctx, notmuch_mailstore_t *mailstore, const char *filename)
 {
     notmuch_message_file_t *message;
 
@@ -104,7 +104,7 @@ _notmuch_message_file_open_ctx (void *ctx, const char *filename)
 
     talloc_set_destructor (message, _notmuch_message_file_destructor);
 
-    message->file = fopen (filename, "r");
+    message->file = notmuch_mailstore_open_file(mailstore, filename);
     if (message->file == NULL)
 	goto FAIL;
 
@@ -126,9 +126,9 @@ _notmuch_message_file_open_ctx (void *ctx, const char *filename)
 }
 
 notmuch_message_file_t *
-notmuch_message_file_open (const char *filename)
+notmuch_message_file_open (notmuch_mailstore_t *mailstore, const char *filename)
 {
-    return _notmuch_message_file_open_ctx (NULL, filename);
+    return _notmuch_message_file_open_ctx (NULL, mailstore, filename);
 }
 
 void
diff --git a/lib/message.cc b/lib/message.cc
index c32ee7d..c7eff7c 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -247,6 +247,7 @@ static void
 _notmuch_message_ensure_message_file (notmuch_message_t *message)
 {
     const char *filename;
+    notmuch_mailstore_t *mailstore;
 
     if (message->message_file)
 	return;
@@ -255,7 +256,9 @@ _notmuch_message_ensure_message_file (notmuch_message_t *message)
     if (unlikely (filename == NULL))
 	return;
 
-    message->message_file = _notmuch_message_file_open_ctx (message, filename);
+    mailstore = notmuch_message_get_mailstore (message);
+
+    message->message_file = _notmuch_message_file_open_ctx (message, mailstore, filename);
 }
 
 const char *
@@ -429,7 +432,7 @@ notmuch_message_get_filename (notmuch_message_t *message)
     int prefix_len = strlen (prefix);
     Xapian::TermIterator i;
     char *colon, *direntry = NULL;
-    const char *db_path, *directory, *basename;
+    const char *directory, *basename;
     unsigned int directory_id;
     void *local = talloc_new (message);
 
@@ -474,18 +477,16 @@ notmuch_message_get_filename (notmuch_message_t *message)
 
     *colon = '\0';
 
-    db_path = notmuch_database_get_path (message->notmuch);
-
     directory = _notmuch_database_get_directory_path (local,
 						      message->notmuch,
 						      directory_id);
 
     if (strlen (directory))
-	message->filename = talloc_asprintf (message, "%s/%s/%s",
-					     db_path, directory, basename);
-    else
 	message->filename = talloc_asprintf (message, "%s/%s",
-					     db_path, basename);
+					     directory, basename);
+    else
+	message->filename = talloc_asprintf (message, "%s",
+					     basename);
     talloc_free ((void *) directory);
 
     talloc_free (local);
@@ -493,6 +494,22 @@ notmuch_message_get_filename (notmuch_message_t *message)
     return message->filename;
 }
 
+FILE *
+notmuch_message_fopen (notmuch_message_t *message)
+{
+    const char *filename;
+    filename = notmuch_message_get_filename (message);
+    return notmuch_mailstore_open_file (message->notmuch->mailstore,
+					filename);
+}
+
+notmuch_mailstore_t *
+notmuch_message_get_mailstore (notmuch_message_t *message)
+{
+    return message->notmuch->mailstore;
+}
+
+
 notmuch_bool_t
 notmuch_message_get_flag (notmuch_message_t *message,
 			  notmuch_message_flag_t flag)
diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
index d52d84d..bab2090 100644
--- a/lib/notmuch-private.h
+++ b/lib/notmuch-private.h
@@ -295,11 +295,11 @@ typedef struct _notmuch_message_file notmuch_message_file_t;
  * Returns NULL if any error occurs.
  */
 notmuch_message_file_t *
-notmuch_message_file_open (const char *filename);
+notmuch_message_file_open (notmuch_mailstore_t *mailstore, const char *filename);
 
 /* Like notmuch_message_file_open but with 'ctx' as the talloc owner. */
 notmuch_message_file_t *
-_notmuch_message_file_open_ctx (void *ctx, const char *filename);
+_notmuch_message_file_open_ctx (void *ctx, notmuch_mailstore_t *mailstore, const char *filename);
 
 /* Close a notmuch message previously opened with notmuch_message_open. */
 void
@@ -402,7 +402,7 @@ char *
 notmuch_sha1_of_string (const char *str);
 
 char *
-notmuch_sha1_of_file (const char *filename);
+notmuch_sha1_of_file (FILE *file);
 
 /* tags.c */
 
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 31e47a4..54de0bd 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -739,8 +739,8 @@ notmuch_message_get_replies (notmuch_message_t *message);
 
 /* Get a filename for the email corresponding to 'message'.
  *
- * The returned filename is an absolute filename, (the initial
- * component will match notmuch_database_get_path() ).
+ * The returned filename is an relative filename of the message within
+ * the mail store.
  *
  * The returned string belongs to the message so should not be
  * modified or freed by the caller (nor should it be referenced after
@@ -754,6 +754,18 @@ notmuch_message_get_replies (notmuch_message_t *message);
 const char *
 notmuch_message_get_filename (notmuch_message_t *message);
 
+/* Return file handle to read the content of the message.
+ *
+ * This is a helper function which determines message filename and
+ * calls notmuch_mailstore_open_file().
+ */
+FILE *
+notmuch_message_fopen (notmuch_message_t *message);
+
+/* Get a pointer to the mailstore where the message is stored */
+notmuch_mailstore_t *
+notmuch_message_get_mailstore (notmuch_message_t *message);
+
 /* Message flags */
 typedef enum _notmuch_message_flag {
     NOTMUCH_MESSAGE_FLAG_MATCH,
diff --git a/lib/sha1.c b/lib/sha1.c
index cc48108..a8991b1 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -74,9 +74,8 @@ notmuch_sha1_of_string (const char *str)
  * file not found, etc.), this function returns NULL.
  */
 char *
-notmuch_sha1_of_file (const char *filename)
+notmuch_sha1_of_file (FILE *file)
 {
-    FILE *file;
 #define BLOCK_SIZE 4096
     unsigned char block[BLOCK_SIZE];
     size_t bytes_read;
@@ -84,7 +83,6 @@ notmuch_sha1_of_file (const char *filename)
     unsigned char digest[SHA1_DIGEST_SIZE];
     char *result;
 
-    file = fopen (filename, "r");
     if (file == NULL)
 	return NULL;
 
@@ -108,8 +106,6 @@ notmuch_sha1_of_file (const char *filename)
 
     result = _hex_of_sha1_digest (digest);
 
-    fclose (file);
-
     return result;
 }
 
diff --git a/notmuch-client.h b/notmuch-client.h
index d8c8df4..728e448 100644
--- a/notmuch-client.h
+++ b/notmuch-client.h
@@ -126,7 +126,7 @@ char *
 query_string_from_args (void *ctx, int argc, char *argv[]);
 
 notmuch_status_t
-show_message_body (const char *filename,
+show_message_body (FILE *file,
 		   void (*show_part) (GMimeObject *part, int *part_count));
 
 notmuch_status_t
diff --git a/notmuch-reply.c b/notmuch-reply.c
index 1ec28cd..32d17ef 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -347,6 +347,7 @@ guess_from_received_header (notmuch_config_t *config, notmuch_message_t *message
 static int
 notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_t *query)
 {
+    FILE *file;
     GMimeMessage *reply;
     notmuch_messages_t *messages;
     notmuch_message_t *message;
@@ -415,7 +416,14 @@ notmuch_reply_format_default(void *ctx, notmuch_config_t *config, notmuch_query_
 		notmuch_message_get_header (message, "date"),
 		notmuch_message_get_header (message, "from"));
 
-	show_message_body (notmuch_message_get_filename (message), reply_part);
+	file = notmuch_message_fopen (message);
+	if (file) {
+	    show_message_body (file, reply_part);
+	    fclose (file);
+	} else
+	    fprintf (stderr, "Error opening %s: %s\n",
+		     notmuch_message_get_filename (message),
+		     strerror (errno));
 
 	notmuch_message_destroy (message);
     }
diff --git a/notmuch-show.c b/notmuch-show.c
index 6dca672..66fd773 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -339,6 +339,8 @@ format_part_json (GMimeObject *part, int *part_count)
 static void
 show_message (void *ctx, const show_format_t *format, notmuch_message_t *message, int indent)
 {
+    FILE *file;
+
     fputs (format->message_start, stdout);
     if (format->message)
 	format->message(ctx, message, indent);
@@ -349,8 +351,16 @@ show_message (void *ctx, const show_format_t *format, notmuch_message_t *message
     fputs (format->header_end, stdout);
 
     fputs (format->body_start, stdout);
-    if (format->part)
-	show_message_body (notmuch_message_get_filename (message), format->part);
+    if (format->part) {
+	file = notmuch_message_fopen (message);
+	if (file) {
+	    show_message_body (file, format->part);
+	    fclose (file);
+	} else
+	    fprintf (stderr, "Error opening %s: %s\n",
+		     notmuch_message_get_filename (message),
+		     strerror (errno));
+    }
     fputs (format->body_end, stdout);
 
     fputs (format->message_end, stdout);
diff --git a/show-message.c b/show-message.c
index b1b61be..79911a7 100644
--- a/show-message.c
+++ b/show-message.c
@@ -60,23 +60,15 @@ show_message_part (GMimeObject *part, int *part_count,
 }
 
 notmuch_status_t
-show_message_body (const char *filename,
+show_message_body (FILE *file,
 		   void (*show_part) (GMimeObject *part, int *part_count))
 {
     GMimeStream *stream = NULL;
     GMimeParser *parser = NULL;
     GMimeMessage *mime_message = NULL;
     notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS;
-    FILE *file = NULL;
     int part_count = 0;
 
-    file = fopen (filename, "r");
-    if (! file) {
-	fprintf (stderr, "Error opening %s: %s\n", filename, strerror (errno));
-	ret = NOTMUCH_STATUS_FILE_ERROR;
-	goto DONE;
-    }
-
     stream = g_mime_stream_file_new (file);
     g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream), FALSE);
 
@@ -87,7 +79,6 @@ show_message_body (const char *filename,
     show_message_part (g_mime_message_get_mime_part (mime_message),
 		       &part_count, show_part);
 
-  DONE:
     if (mime_message)
 	g_object_unref (mime_message);
 
@@ -97,9 +88,6 @@ show_message_body (const char *filename,
     if (stream)
 	g_object_unref (stream);
 
-    if (file)
-	fclose (file);
-
     return ret;
 }
 
-- 
1.7.0.2



More information about the notmuch mailing list