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,
|
notmuch_database_t *notmuch,
|
||||||
const char *prefix)
|
const char *prefix)
|
||||||
{
|
{
|
||||||
notmuch_filenames_t *filenames;
|
notmuch_filename_list_t *filename_list;
|
||||||
Xapian::TermIterator i, end;
|
Xapian::TermIterator i, end;
|
||||||
int prefix_len = strlen (prefix);
|
int prefix_len = strlen (prefix);
|
||||||
|
|
||||||
filenames = _notmuch_filenames_create (ctx);
|
filename_list = _notmuch_filename_list_create (ctx);
|
||||||
if (unlikely (filenames == NULL))
|
if (unlikely (filename_list == NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
end = notmuch->xapian_db->allterms_end (prefix);
|
end = notmuch->xapian_db->allterms_end (prefix);
|
||||||
|
@ -47,13 +47,11 @@ _create_filenames_for_terms_with_prefix (void *ctx,
|
||||||
{
|
{
|
||||||
std::string term = *i;
|
std::string term = *i;
|
||||||
|
|
||||||
_notmuch_filenames_add_filename (filenames, term.c_str () +
|
_notmuch_filename_list_add_filename (filename_list, term.c_str () +
|
||||||
prefix_len);
|
prefix_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
_notmuch_filenames_move_to_first (filenames);
|
return _notmuch_filenames_create (ctx, filename_list);
|
||||||
|
|
||||||
return filenames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct _notmuch_directory {
|
struct _notmuch_directory {
|
||||||
|
|
|
@ -20,24 +20,57 @@
|
||||||
|
|
||||||
#include "notmuch-private.h"
|
#include "notmuch-private.h"
|
||||||
|
|
||||||
typedef struct _notmuch_filenames_node {
|
|
||||||
char *filename;
|
|
||||||
struct _notmuch_filenames_node *next;
|
|
||||||
} notmuch_filenames_node_t;
|
|
||||||
|
|
||||||
struct _notmuch_filenames {
|
struct _notmuch_filenames {
|
||||||
notmuch_filenames_node_t *head;
|
notmuch_filename_node_t *iterator;
|
||||||
notmuch_filenames_node_t **tail;
|
|
||||||
notmuch_filenames_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.
|
* talloc owner.
|
||||||
*
|
*
|
||||||
* This function can return NULL in case of out-of-memory.
|
* 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_t *
|
||||||
_notmuch_filenames_create (const void *ctx)
|
_notmuch_filenames_create (const void *ctx,
|
||||||
|
notmuch_filename_list_t *list)
|
||||||
{
|
{
|
||||||
notmuch_filenames_t *filenames;
|
notmuch_filenames_t *filenames;
|
||||||
|
|
||||||
|
@ -45,32 +78,11 @@ _notmuch_filenames_create (const void *ctx)
|
||||||
if (unlikely (filenames == NULL))
|
if (unlikely (filenames == NULL))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
filenames->head = NULL;
|
filenames->iterator = list->head;
|
||||||
filenames->tail = &filenames->head;
|
|
||||||
|
|
||||||
filenames->iterator = NULL;
|
|
||||||
|
|
||||||
return filenames;
|
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_bool_t
|
||||||
notmuch_filenames_valid (notmuch_filenames_t *filenames)
|
notmuch_filenames_valid (notmuch_filenames_t *filenames)
|
||||||
{
|
{
|
||||||
|
@ -89,12 +101,6 @@ notmuch_filenames_get (notmuch_filenames_t *filenames)
|
||||||
return filenames->iterator->filename;
|
return filenames->iterator->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
_notmuch_filenames_move_to_first (notmuch_filenames_t *filenames)
|
|
||||||
{
|
|
||||||
filenames->iterator = filenames->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
notmuch_filenames_move_to_next (notmuch_filenames_t *filenames)
|
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 *message_id;
|
||||||
char *thread_id;
|
char *thread_id;
|
||||||
char *in_reply_to;
|
char *in_reply_to;
|
||||||
char *filename;
|
notmuch_filename_list_t *filename_list;
|
||||||
char *author;
|
char *author;
|
||||||
notmuch_message_file_t *message_file;
|
notmuch_message_file_t *message_file;
|
||||||
notmuch_message_list_t *replies;
|
notmuch_message_list_t *replies;
|
||||||
|
@ -101,7 +101,7 @@ _notmuch_message_create_for_document (const void *talloc_owner,
|
||||||
message->message_id = NULL;
|
message->message_id = NULL;
|
||||||
message->thread_id = NULL;
|
message->thread_id = NULL;
|
||||||
message->in_reply_to = NULL;
|
message->in_reply_to = NULL;
|
||||||
message->filename = NULL;
|
message->filename_list = NULL;
|
||||||
message->message_file = NULL;
|
message->message_file = NULL;
|
||||||
message->author = NULL;
|
message->author = NULL;
|
||||||
|
|
||||||
|
@ -432,9 +432,9 @@ _notmuch_message_add_filename (notmuch_message_t *message,
|
||||||
void *local = talloc_new (message);
|
void *local = talloc_new (message);
|
||||||
char *direntry;
|
char *direntry;
|
||||||
|
|
||||||
if (message->filename) {
|
if (message->filename_list) {
|
||||||
talloc_free (message->filename);
|
_notmuch_filename_list_destroy (message->filename_list);
|
||||||
message->filename = NULL;
|
message->filename_list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename == NULL)
|
if (filename == NULL)
|
||||||
|
@ -465,28 +465,23 @@ _notmuch_message_clear_data (notmuch_message_t *message)
|
||||||
message->doc.set_data ("");
|
message->doc.set_data ("");
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
static void
|
||||||
notmuch_message_get_filename (notmuch_message_t *message)
|
_notmuch_message_ensure_filename_list (notmuch_message_t *message)
|
||||||
{
|
{
|
||||||
const char *prefix = _find_prefix ("file-direntry");
|
const char *prefix = _find_prefix ("file-direntry");
|
||||||
int prefix_len = strlen (prefix);
|
int prefix_len = strlen (prefix);
|
||||||
Xapian::TermIterator i;
|
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)
|
if (message->filename_list)
|
||||||
return message->filename;
|
return;
|
||||||
|
|
||||||
|
message->filename_list = _notmuch_filename_list_create (message);
|
||||||
|
|
||||||
i = message->doc.termlist_begin ();
|
i = message->doc.termlist_begin ();
|
||||||
i.skip_to (prefix);
|
i.skip_to (prefix);
|
||||||
|
|
||||||
if (i != message->doc.termlist_end ())
|
|
||||||
direntry = talloc_strdup (local, (*i).c_str ());
|
|
||||||
|
|
||||||
if (i == message->doc.termlist_end () ||
|
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
|
/* A message document created by an old version of notmuch
|
||||||
* (prior to rename support) will have the filename in the
|
* (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)
|
if (data == NULL)
|
||||||
INTERNAL_ERROR ("message with no filename");
|
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 != ':')
|
direntry = talloc_strdup (local, (*i).c_str ());
|
||||||
INTERNAL_ERROR ("malformed direntry");
|
|
||||||
|
|
||||||
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,
|
basename = colon + 1;
|
||||||
message->notmuch,
|
|
||||||
directory_id);
|
|
||||||
|
|
||||||
if (strlen (directory))
|
*colon = '\0';
|
||||||
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);
|
|
||||||
|
|
||||||
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
|
notmuch_bool_t
|
||||||
|
|
|
@ -450,15 +450,35 @@ _notmuch_tags_prepare_iterator (notmuch_tags_t *tags);
|
||||||
|
|
||||||
/* filenames.c */
|
/* 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_t *
|
||||||
_notmuch_filenames_create (const void *ctx);
|
_notmuch_filenames_create (const void *ctx,
|
||||||
|
notmuch_filename_list_t *list);
|
||||||
void
|
|
||||||
_notmuch_filenames_add_filename (notmuch_filenames_t *filenames,
|
|
||||||
const char *filename);
|
|
||||||
|
|
||||||
void
|
|
||||||
_notmuch_filenames_move_to_first (notmuch_filenames_t *filenames);
|
|
||||||
|
|
||||||
#pragma GCC visibility pop
|
#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
|
* Note: If this message corresponds to multiple files in the mail
|
||||||
* store, (that is, multiple files contain identical message IDs),
|
* store, (that is, multiple files contain identical message IDs),
|
||||||
* this function will arbitrarily return a single one of those
|
* 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 *
|
const char *
|
||||||
notmuch_message_get_filename (notmuch_message_t *message);
|
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 */
|
/* Message flags */
|
||||||
typedef enum _notmuch_message_flag {
|
typedef enum _notmuch_message_flag {
|
||||||
NOTMUCH_MESSAGE_FLAG_MATCH
|
NOTMUCH_MESSAGE_FLAG_MATCH
|
||||||
|
|
Loading…
Reference in a new issue