diff --git a/message-file.c b/message-file.c index a4c08606..18275fbf 100644 --- a/message-file.c +++ b/message-file.c @@ -70,12 +70,36 @@ strcase_hash (const void *ptr) return hash; } +static int +_notmuch_message_file_destructor (notmuch_message_file_t *message) +{ + if (message->line) + free (message->line); + + if (message->value.size) + free (message->value.str); + + if (message->headers) + g_hash_table_destroy (message->headers); + + if (message->file) + fclose (message->file); + + return 0; +} + +/* Create a new notmuch_message_file_t for 'filename' with 'ctx' as + * the talloc owner. */ notmuch_message_file_t * -notmuch_message_file_open (const char *filename) +_notmuch_message_file_open_ctx (void *ctx, const char *filename) { notmuch_message_file_t *message; - message = talloc_zero (NULL, notmuch_message_file_t); + message = talloc_zero (ctx, notmuch_message_file_t); + if (unlikely (message == NULL)) + return NULL; + + talloc_set_destructor (message, _notmuch_message_file_destructor); message->file = fopen (filename, "r"); if (message->file == NULL) @@ -98,24 +122,15 @@ notmuch_message_file_open (const char *filename) return NULL; } +notmuch_message_file_t * +notmuch_message_file_open (const char *filename) +{ + return _notmuch_message_file_open_ctx (NULL, filename); +} + void notmuch_message_file_close (notmuch_message_file_t *message) { - if (message == NULL) - return; - - if (message->line) - free (message->line); - - if (message->value.size) - free (message->value.str); - - if (message->headers) - g_hash_table_destroy (message->headers); - - if (message->file) - fclose (message->file); - talloc_free (message); } diff --git a/message.cc b/message.cc index 66dfc806..6b6141f3 100644 --- a/message.cc +++ b/message.cc @@ -29,6 +29,7 @@ struct _notmuch_message { char *message_id; char *thread_id; char *filename; + notmuch_message_file_t *message_file; Xapian::Document doc; }; @@ -98,9 +99,12 @@ _notmuch_message_create (const void *talloc_owner, message->notmuch = notmuch; message->doc_id = doc_id; - message->message_id = NULL; /* lazily created */ - message->thread_id = NULL; /* lazily created */ - message->filename = NULL; /* lazily created */ + + /* Each of these will be lazily created as needed. */ + message->message_id = NULL; + message->thread_id = NULL; + message->filename = NULL; + message->message_file = NULL; /* This is C++'s creepy "placement new", which is really just an * ugly way to call a constructor for a pre-allocated object. So @@ -224,6 +228,28 @@ notmuch_message_get_message_id (notmuch_message_t *message) return message->message_id; } +const char * +_notmuch_message_get_subject (notmuch_message_t *message) +{ + if (! message->message_file) { + notmuch_message_file_t *message_file; + const char *filename; + + filename = notmuch_message_get_filename (message); + if (unlikely (filename == NULL)) + return NULL; + + message_file = _notmuch_message_file_open_ctx (message, filename); + if (unlikely (message_file == NULL)) + return NULL; + + message->message_file = message_file; + } + + return notmuch_message_file_get_header (message->message_file, + "subject"); +} + const char * notmuch_message_get_thread_id (notmuch_message_t *message) { diff --git a/notmuch-private.h b/notmuch-private.h index ddc59b4c..42f8d275 100644 --- a/notmuch-private.h +++ b/notmuch-private.h @@ -137,6 +137,16 @@ typedef enum _notmuch_private_status { : \ (notmuch_status_t) private_status) +/* database.cc */ + +/* Lookup a prefix value by name. + * + * XXX: This should really be static inside of message.cc, and we can + * do that once we convert database.cc to use the + * _notmuch_message_add/remove_term functions. */ +const char * +_find_prefix (const char *name); + /* thread.cc */ notmuch_thread_t * @@ -147,6 +157,12 @@ _notmuch_thread_create (const void *talloc_owner, void _notmuch_thread_add_tag (notmuch_thread_t *thread, const char *tag); +void +_notmuch_thread_set_subject (notmuch_thread_t *thread, const char *subject); + +const char * +_notmuch_thread_get_subject (notmuch_thread_t *thread); + /* message.cc */ notmuch_message_t * @@ -161,13 +177,8 @@ _notmuch_message_create_for_message_id (const void *talloc_owner, const char *message_id, notmuch_status_t *status); -/* Lookup a prefix value by name. - * - * XXX: This should really be static inside of message.cc, and we can - * do that once we convert database.cc to use the - * _notmuch_message_add/remove_term functions. */ const char * -_find_prefix (const char *name); +_notmuch_message_get_subject (notmuch_message_t *message); notmuch_private_status_t _notmuch_message_add_term (notmuch_message_t *message, @@ -214,6 +225,10 @@ typedef struct _notmuch_message_file notmuch_message_file_t; notmuch_message_file_t * notmuch_message_file_open (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); + /* Close a notmuch message preivously opened with notmuch_message_open. */ void notmuch_message_file_close (notmuch_message_file_t *message); diff --git a/notmuch.c b/notmuch.c index fd0e0b25..ae1d5976 100644 --- a/notmuch.c +++ b/notmuch.c @@ -651,8 +651,11 @@ search_command (int argc, char *argv[]) thread = notmuch_thread_results_get (results); - printf ("%s (", notmuch_thread_get_thread_id (thread)); + printf ("%s %s", + notmuch_thread_get_thread_id (thread), + _notmuch_thread_get_subject (thread)); + printf (" ("); for (tags = notmuch_thread_get_tags (thread); notmuch_tags_has_more (tags); notmuch_tags_advance (tags)) @@ -662,7 +665,6 @@ search_command (int argc, char *argv[]) printf ("%s", notmuch_tags_get (tags)); first = 0; } - printf (")\n"); notmuch_thread_destroy (thread); diff --git a/notmuch.h b/notmuch.h index b4ff53e3..bf390bea 100644 --- a/notmuch.h +++ b/notmuch.h @@ -458,6 +458,20 @@ notmuch_thread_results_destroy (notmuch_thread_results_t *results); const char * notmuch_thread_get_thread_id (notmuch_thread_t *thread); +/* Get the subject of 'thread' + * + * The subject is taken from the first message (according to the query + * order---see notmuch_query_set_sort) in the query results that + * belongs to this thread. + * + * The returned string belongs to 'thread' and as such, should not be + * modified by the caller and will only be valid for as long as the + * thread is valid, (which is until notmuch_thread_destroy or until + * the query from which it derived is destroyed). + */ +const char * +notmuch_thread_get_subject (notmuch_thread_t *thread); + /* Get the tags for 'thread', returning a notmuch_tags_t object which * can be used to iterate over all tags. * diff --git a/query.cc b/query.cc index c8a91491..5fac024e 100644 --- a/query.cc +++ b/query.cc @@ -207,9 +207,15 @@ notmuch_query_search_threads (notmuch_query_t *query) thread_id, NULL, (void **) &thread)) { + const char *subject; + thread = _notmuch_thread_create (query, query->notmuch, thread_id); + subject = _notmuch_message_get_subject (message); + + _notmuch_thread_set_subject (thread, subject); + g_hash_table_insert (seen, xstrdup (thread_id), thread); g_ptr_array_add (thread_results->threads, thread); @@ -222,6 +228,8 @@ notmuch_query_search_threads (notmuch_query_t *query) tag = notmuch_tags_get (tags); _notmuch_thread_add_tag (thread, tag); } + + notmuch_message_destroy (message); } g_hash_table_unref (seen); diff --git a/thread.cc b/thread.cc index 73d17722..9b49c550 100644 --- a/thread.cc +++ b/thread.cc @@ -28,6 +28,7 @@ struct _notmuch_thread { notmuch_database_t *notmuch; char *thread_id; + char *subject; GHashTable *tags; }; @@ -69,6 +70,7 @@ _notmuch_thread_create (const void *talloc_owner, thread->notmuch = notmuch; thread->thread_id = talloc_strdup (thread, thread_id); + thread->subject = NULL; thread->tags = g_hash_table_new_full (g_str_hash, g_str_equal, free, NULL); @@ -87,6 +89,18 @@ _notmuch_thread_add_tag (notmuch_thread_t *thread, const char *tag) g_hash_table_insert (thread->tags, xstrdup (tag), NULL); } +void +_notmuch_thread_set_subject (notmuch_thread_t *thread, const char *subject) +{ + thread->subject = talloc_strdup (thread, subject); +} + +const char * +_notmuch_thread_get_subject (notmuch_thread_t *thread) +{ + return thread->subject; +} + notmuch_tags_t * notmuch_thread_get_tags (notmuch_thread_t *thread) {