mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-21 18:38:08 +01:00
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.
This commit is contained in:
parent
d87db88432
commit
1d02dd64af
5 changed files with 163 additions and 93 deletions
|
@ -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 {
|
||||
|
|
|
@ -20,24 +20,57 @@
|
|||
|
||||
#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_filename_list_t *
|
||||
_notmuch_filename_list_create (const void *ctx)
|
||||
{
|
||||
notmuch_filename_list_t *list;
|
||||
|
||||
list = talloc (ctx, notmuch_filename_list_t);
|
||||
if (unlikely (list == NULL))
|
||||
return NULL;
|
||||
|
||||
list->head = NULL;
|
||||
list->tail = &list->head;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
_notmuch_filename_list_add_filename (notmuch_filename_list_t *list,
|
||||
const char *filename)
|
||||
{
|
||||
/* Create and initialize new node. */
|
||||
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. */
|
||||
*(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_filenames_create (const void *ctx,
|
||||
notmuch_filename_list_t *list)
|
||||
{
|
||||
notmuch_filenames_t *filenames;
|
||||
|
||||
|
@ -45,32 +78,11 @@ _notmuch_filenames_create (const void *ctx)
|
|||
if (unlikely (filenames == NULL))
|
||||
return NULL;
|
||||
|
||||
filenames->head = NULL;
|
||||
filenames->tail = &filenames->head;
|
||||
|
||||
filenames->iterator = NULL;
|
||||
filenames->iterator = list->head;
|
||||
|
||||
return filenames;
|
||||
}
|
||||
|
||||
/* Append a single 'node' to the end of 'filenames'.
|
||||
*/
|
||||
void
|
||||
_notmuch_filenames_add_filename (notmuch_filenames_t *filenames,
|
||||
const char *filename)
|
||||
{
|
||||
/* Create and initialize new node. */
|
||||
notmuch_filenames_node_t *node = talloc (filenames,
|
||||
notmuch_filenames_node_t);
|
||||
|
||||
node->filename = talloc_strdup (node, filename);
|
||||
node->next = NULL;
|
||||
|
||||
/* Append the node to the list. */
|
||||
*(filenames->tail) = node;
|
||||
filenames->tail = &node->next;
|
||||
}
|
||||
|
||||
notmuch_bool_t
|
||||
notmuch_filenames_valid (notmuch_filenames_t *filenames)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
109
lib/message.cc
109
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);
|
||||
|
||||
return message->filename;
|
||||
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 _notmuch_filenames_create (message, message->filename_list);
|
||||
}
|
||||
|
||||
notmuch_bool_t
|
||||
|
|
|
@ -450,15 +450,35 @@ _notmuch_tags_prepare_iterator (notmuch_tags_t *tags);
|
|||
|
||||
/* filenames.c */
|
||||
|
||||
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_filename_list_add_filename (notmuch_filename_list_t *list,
|
||||
const char *filename);
|
||||
|
||||
void
|
||||
_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);
|
||||
|
||||
void
|
||||
_notmuch_filenames_add_filename (notmuch_filenames_t *filenames,
|
||||
const char *filename);
|
||||
|
||||
void
|
||||
_notmuch_filenames_move_to_first (notmuch_filenames_t *filenames);
|
||||
_notmuch_filenames_create (const void *ctx,
|
||||
notmuch_filename_list_t *list);
|
||||
|
||||
#pragma GCC visibility pop
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue