diff --git a/lib/database.cc b/lib/database.cc index f122c2e4..7d09119c 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -63,6 +63,11 @@ typedef struct { * * tag: Any tags associated with this message by the user. * + * direntry: A colon-separated pair of values (INTEGER:STRING), + * where INTEGER is the document ID of a directory + * document, and STRING is the name of a file within + * that directory for this mail message. + * * A mail document also has two values: * * TIMESTAMP: The time_t value corresponding to the message's @@ -75,8 +80,7 @@ typedef struct { * user in searching. But the database doesn't really care itself * about any of these. * - * Finally, the data portion of a mail document contains the path name - * of the mail message (relative to the database path). + * The data portion of a mail document is empty. * * Directory document * ------------------ @@ -122,6 +126,7 @@ prefix_t BOOLEAN_PREFIX_INTERNAL[] = { { "reference", "XREFERENCE" }, { "replyto", "XREPLYTO" }, { "directory", "XDIRECTORY" }, + { "direntry", "XDIRENTRY" }, { "parent", "XPARENT" }, }; @@ -717,6 +722,18 @@ _notmuch_database_find_directory_id (notmuch_database_t *notmuch, return status; } +const char * +_notmuch_database_get_directory_path (void *ctx, + notmuch_database_t *notmuch, + unsigned int doc_id) +{ + Xapian::Document document; + + document = find_document_for_doc_id (notmuch, doc_id); + + return talloc_strdup (ctx, document.get_data ().c_str ()); +} + /* Given a legal 'path' for the database, return the relative path. * * The return value will be a pointer to the originl path contents, @@ -812,6 +829,8 @@ notmuch_database_set_directory_mtime (notmuch_database_t *notmuch, if (db_path != path) free ((char *) db_path); + talloc_free (local); + return ret; } @@ -844,8 +863,6 @@ notmuch_database_get_directory_mtime (notmuch_database_t *notmuch, if (db_path != path) free ((char *) db_path); - talloc_free (local); - return ret; } diff --git a/lib/index.cc b/lib/index.cc index 125fa6c9..e58bc870 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -31,7 +31,7 @@ _index_address_mailbox (notmuch_message_t *message, { InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX (address); const char *name, *addr; - void *local = talloc_new (NULL); + void *local = talloc_new (message); name = internet_address_get_name (address); addr = internet_address_mailbox_get_addr (mailbox); diff --git a/lib/message.cc b/lib/message.cc index 7c7ea7a1..3f533423 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -392,11 +392,15 @@ notmuch_message_get_replies (notmuch_message_t *message) * * This change will not be reflected in the database until the next * call to _notmuch_message_set_sync. */ -void +notmuch_status_t _notmuch_message_set_filename (notmuch_message_t *message, const char *filename) { - const char *relative; + const char *relative, *directory, *basename; + char *term; + Xapian::docid directory_id; + notmuch_status_t status; + void *local = talloc_new (message); if (message->filename) { talloc_free (message->filename); @@ -407,26 +411,79 @@ _notmuch_message_set_filename (notmuch_message_t *message, INTERNAL_ERROR ("Message filename cannot be NULL."); relative = _notmuch_database_relative_path (message->notmuch, filename); - message->doc.set_data (relative); + + status = _notmuch_database_split_path (local, relative, + &directory, &basename); + if (status) + return status; + + status = _notmuch_database_find_directory_id (message->notmuch, directory, + &directory_id); + if (status) + return status; + + term = talloc_asprintf (local, "%s%u:%s", + _find_prefix ("direntry"), directory_id, basename); + + message->doc.add_term (term); + + talloc_free (local); + + return NOTMUCH_STATUS_SUCCESS; } const char * notmuch_message_get_filename (notmuch_message_t *message) { - std::string filename_str; - const char *db_path; + const char *prefix = _find_prefix ("direntry"); + int prefix_len = strlen (prefix); + Xapian::TermIterator i; + char *direntry, *colon; + const char *db_path, *directory, *basename; + unsigned int directory_id; + void *local = talloc_new (message); if (message->filename) return message->filename; - filename_str = message->doc.get_data (); + 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)) + { + INTERNAL_ERROR ("message with no filename"); + } + + direntry += prefix_len; + + directory_id = strtol (direntry, &colon, 10); + + if (colon == NULL || *colon != ':') + INTERNAL_ERROR ("malformed direntry"); + + basename = colon + 1; + + *colon = '\0'; + db_path = notmuch_database_get_path (message->notmuch); - if (filename_str[0] != '/') - message->filename = talloc_asprintf (message, "%s/%s", db_path, - filename_str.c_str ()); + 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_strdup (message, filename_str.c_str ()); + message->filename = talloc_asprintf (message, "%s/%s", + db_path, basename); + talloc_free ((void *) directory); + + talloc_free (local); return message->filename; } diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 9f470c9f..5a930bb3 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -166,6 +166,11 @@ _notmuch_database_find_directory_id (notmuch_database_t *database, const char *path, unsigned int *directory_id); +const char * +_notmuch_database_get_directory_path (void *ctx, + notmuch_database_t *notmuch, + unsigned int doc_id); + /* thread.cc */ notmuch_thread_t * @@ -205,7 +210,7 @@ _notmuch_message_gen_terms (notmuch_message_t *message, const char *prefix_name, const char *text); -void +notmuch_status_t _notmuch_message_set_filename (notmuch_message_t *message, const char *filename);