From 1d02dd64afe245a2b5a8461feeba975e61f0c233 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 11 Nov 2010 00:07:24 -0800 Subject: [PATCH] lib: Add new, public notmuch_message_get_filenames This augments the existing notmuch_message_get_filename by allowing the caller access to all filenames in the case of multiple files for a single message. To support this, we split the iterator (notmuch_filenames_t) away from the list storage (notmuch_filename_list_t) where previously these were a single object (notmuch_filenames_t). Then, whenever the user asks for a file or filename, the message object lazily creates a complete notmuch_filename_list_t and then: For notmuch_message_get_filename, returns the first filename in the list. For notmuch_message_get_filenames, creates and returns a new iterator for the filename list. --- lib/directory.cc | 14 +++--- lib/filenames.c | 72 +++++++++++++++------------- lib/message.cc | 109 +++++++++++++++++++++++++++--------------- lib/notmuch-private.h | 30 ++++++++++-- lib/notmuch.h | 15 +++++- 5 files changed, 155 insertions(+), 85 deletions(-) diff --git a/lib/directory.cc b/lib/directory.cc index 16492c0d..946be4f4 100644 --- a/lib/directory.cc +++ b/lib/directory.cc @@ -33,12 +33,12 @@ _create_filenames_for_terms_with_prefix (void *ctx, notmuch_database_t *notmuch, const char *prefix) { - notmuch_filenames_t *filenames; + notmuch_filename_list_t *filename_list; Xapian::TermIterator i, end; int prefix_len = strlen (prefix); - filenames = _notmuch_filenames_create (ctx); - if (unlikely (filenames == NULL)) + filename_list = _notmuch_filename_list_create (ctx); + if (unlikely (filename_list == NULL)) return NULL; end = notmuch->xapian_db->allterms_end (prefix); @@ -47,13 +47,11 @@ _create_filenames_for_terms_with_prefix (void *ctx, { std::string term = *i; - _notmuch_filenames_add_filename (filenames, term.c_str () + - prefix_len); + _notmuch_filename_list_add_filename (filename_list, term.c_str () + + prefix_len); } - _notmuch_filenames_move_to_first (filenames); - - return filenames; + return _notmuch_filenames_create (ctx, filename_list); } struct _notmuch_directory { diff --git a/lib/filenames.c b/lib/filenames.c index cff9e830..50e14354 100644 --- a/lib/filenames.c +++ b/lib/filenames.c @@ -20,55 +20,67 @@ #include "notmuch-private.h" -typedef struct _notmuch_filenames_node { - char *filename; - struct _notmuch_filenames_node *next; -} notmuch_filenames_node_t; - struct _notmuch_filenames { - notmuch_filenames_node_t *head; - notmuch_filenames_node_t **tail; - notmuch_filenames_node_t *iterator; + notmuch_filename_node_t *iterator; }; -/* Create a new notmuch_filenames_t object, with 'ctx' as its +/* Create a new notmuch_filename_list_t object, with 'ctx' as its * talloc owner. * * This function can return NULL in case of out-of-memory. */ -notmuch_filenames_t * -_notmuch_filenames_create (const void *ctx) +notmuch_filename_list_t * +_notmuch_filename_list_create (const void *ctx) { - notmuch_filenames_t *filenames; + notmuch_filename_list_t *list; - filenames = talloc (ctx, notmuch_filenames_t); - if (unlikely (filenames == NULL)) + list = talloc (ctx, notmuch_filename_list_t); + if (unlikely (list == NULL)) return NULL; - filenames->head = NULL; - filenames->tail = &filenames->head; - - filenames->iterator = NULL; + list->head = NULL; + list->tail = &list->head; - return filenames; + return list; } -/* Append a single 'node' to the end of 'filenames'. - */ void -_notmuch_filenames_add_filename (notmuch_filenames_t *filenames, - const char *filename) +_notmuch_filename_list_add_filename (notmuch_filename_list_t *list, + const char *filename) { /* Create and initialize new node. */ - notmuch_filenames_node_t *node = talloc (filenames, - notmuch_filenames_node_t); + notmuch_filename_node_t *node = talloc (list, + notmuch_filename_node_t); node->filename = talloc_strdup (node, filename); node->next = NULL; /* Append the node to the list. */ - *(filenames->tail) = node; - filenames->tail = &node->next; + *(list->tail) = node; + list->tail = &node->next; +} + +void +_notmuch_filename_list_destroy (notmuch_filename_list_t *list) +{ + talloc_free (list); +} + +/* The notmuch_filenames_t is an iterator object for a + * notmuch_filename_list_t */ +notmuch_filenames_t * +_notmuch_filenames_create (const void *ctx, + notmuch_filename_list_t *list) +{ + notmuch_filenames_t *filenames; + + filenames = talloc (ctx, notmuch_filenames_t); + if (unlikely (filenames == NULL)) + return NULL; + + filenames->iterator = list->head; + + return filenames; } notmuch_bool_t @@ -89,12 +101,6 @@ notmuch_filenames_get (notmuch_filenames_t *filenames) return filenames->iterator->filename; } -void -_notmuch_filenames_move_to_first (notmuch_filenames_t *filenames) -{ - filenames->iterator = filenames->head; -} - void notmuch_filenames_move_to_next (notmuch_filenames_t *filenames) { diff --git a/lib/message.cc b/lib/message.cc index bc9cd259..83e05191 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -32,7 +32,7 @@ struct _notmuch_message { char *message_id; char *thread_id; char *in_reply_to; - char *filename; + notmuch_filename_list_t *filename_list; char *author; notmuch_message_file_t *message_file; notmuch_message_list_t *replies; @@ -101,7 +101,7 @@ _notmuch_message_create_for_document (const void *talloc_owner, message->message_id = NULL; message->thread_id = NULL; message->in_reply_to = NULL; - message->filename = NULL; + message->filename_list = NULL; message->message_file = NULL; message->author = NULL; @@ -432,9 +432,9 @@ _notmuch_message_add_filename (notmuch_message_t *message, void *local = talloc_new (message); char *direntry; - if (message->filename) { - talloc_free (message->filename); - message->filename = NULL; + if (message->filename_list) { + _notmuch_filename_list_destroy (message->filename_list); + message->filename_list = NULL; } if (filename == NULL) @@ -465,28 +465,23 @@ _notmuch_message_clear_data (notmuch_message_t *message) message->doc.set_data (""); } -const char * -notmuch_message_get_filename (notmuch_message_t *message) +static void +_notmuch_message_ensure_filename_list (notmuch_message_t *message) { const char *prefix = _find_prefix ("file-direntry"); int prefix_len = strlen (prefix); Xapian::TermIterator i; - char *colon, *direntry = NULL; - const char *db_path, *directory, *basename; - unsigned int directory_id; - void *local = talloc_new (message); - if (message->filename) - return message->filename; + if (message->filename_list) + return; + + message->filename_list = _notmuch_filename_list_create (message); i = message->doc.termlist_begin (); i.skip_to (prefix); - if (i != message->doc.termlist_end ()) - direntry = talloc_strdup (local, (*i).c_str ()); - if (i == message->doc.termlist_end () || - strncmp (direntry, prefix, prefix_len)) + strncmp ((*i).c_str (), prefix, prefix_len)) { /* A message document created by an old version of notmuch * (prior to rename support) will have the filename in the @@ -501,39 +496,77 @@ notmuch_message_get_filename (notmuch_message_t *message) if (data == NULL) INTERNAL_ERROR ("message with no filename"); - message->filename = talloc_strdup (message, data); + _notmuch_filename_list_add_filename (message->filename_list, data); - return message->filename; + return; } - direntry += prefix_len; + for (; i != message->doc.termlist_end (); i++) { + void *local = talloc_new (message); + const char *db_path, *directory, *basename, *filename; + char *colon, *direntry = NULL; + unsigned int directory_id; - directory_id = strtol (direntry, &colon, 10); + /* Terminate loop at first term without desired prefix. */ + if (strncmp ((*i).c_str (), prefix, prefix_len)) + break; - if (colon == NULL || *colon != ':') - INTERNAL_ERROR ("malformed direntry"); + direntry = talloc_strdup (local, (*i).c_str ()); - basename = colon + 1; + direntry += prefix_len; - *colon = '\0'; + directory_id = strtol (direntry, &colon, 10); - db_path = notmuch_database_get_path (message->notmuch); + if (colon == NULL || *colon != ':') + INTERNAL_ERROR ("malformed direntry"); - directory = _notmuch_database_get_directory_path (local, - message->notmuch, - directory_id); + basename = colon + 1; - 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); - talloc_free ((void *) directory); + *colon = '\0'; - talloc_free (local); + db_path = notmuch_database_get_path (message->notmuch); + + directory = _notmuch_database_get_directory_path (local, + message->notmuch, + directory_id); + + if (strlen (directory)) + filename = talloc_asprintf (message, "%s/%s/%s", + db_path, directory, basename); + else + filename = talloc_asprintf (message, "%s/%s", + db_path, basename); + + _notmuch_filename_list_add_filename (message->filename_list, + filename); + + talloc_free (local); + } +} + +const char * +notmuch_message_get_filename (notmuch_message_t *message) +{ + _notmuch_message_ensure_filename_list (message); + + if (message->filename_list == NULL) + return NULL; + + if (message->filename_list->head == NULL || + message->filename_list->head->filename == NULL) + { + INTERNAL_ERROR ("message with no filename"); + } + + return message->filename_list->head->filename; +} + +notmuch_filenames_t * +notmuch_message_get_filenames (notmuch_message_t *message) +{ + _notmuch_message_ensure_filename_list (message); - return message->filename; + return _notmuch_filenames_create (message, message->filename_list); } notmuch_bool_t diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 6a9d5ddd..37ccbb31 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -450,15 +450,35 @@ _notmuch_tags_prepare_iterator (notmuch_tags_t *tags); /* filenames.c */ -notmuch_filenames_t * -_notmuch_filenames_create (const void *ctx); +typedef struct _notmuch_filename_node { + char *filename; + struct _notmuch_filename_node *next; +} notmuch_filename_node_t; + +typedef struct _notmuch_filename_list { + notmuch_filename_node_t *head; + notmuch_filename_node_t **tail; +} notmuch_filename_list_t; +notmuch_filename_list_t * +_notmuch_filename_list_create (const void *ctx); + +/* Add 'filename' to 'list'. + * + * The list will create its own talloced copy of 'filename'. + */ void -_notmuch_filenames_add_filename (notmuch_filenames_t *filenames, - const char *filename); +_notmuch_filename_list_add_filename (notmuch_filename_list_t *list, + const char *filename); void -_notmuch_filenames_move_to_first (notmuch_filenames_t *filenames); +_notmuch_filename_list_destroy (notmuch_filename_list_t *list); + +/* The notmuch_filenames_t is an iterator object for a + * notmuch_filename_list_t */ +notmuch_filenames_t * +_notmuch_filenames_create (const void *ctx, + notmuch_filename_list_t *list); #pragma GCC visibility pop diff --git a/lib/notmuch.h b/lib/notmuch.h index b15f1249..413b5709 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -772,11 +772,24 @@ notmuch_message_get_replies (notmuch_message_t *message); * Note: If this message corresponds to multiple files in the mail * store, (that is, multiple files contain identical message IDs), * this function will arbitrarily return a single one of those - * filenames. + * filenames. See notmuch_message_get_filenames for returning the + * complete list of filenames. */ const char * notmuch_message_get_filename (notmuch_message_t *message); +/* Get all filenames for the email corresponding to 'message'. + * + * Returns a notmuch_filenames_t iterator listing all the filenames + * associated with 'message'. These files may not have identical + * content, but each will have the identical Message-ID. + * + * Each filename in the iterator is an absolute filename, (the initial + * component will match notmuch_database_get_path() ). + */ +notmuch_filenames_t * +notmuch_message_get_filenames (notmuch_message_t *message); + /* Message flags */ typedef enum _notmuch_message_flag { NOTMUCH_MESSAGE_FLAG_MATCH -- 2.26.2