X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=lib%2Fdatabase.cc;h=a3824956fc2fdbcedea927a4cd60a49a613b1f29;hb=95deec1b2767695bce5f4e3dc3336859825682f7;hp=7d09119cecddf54a94e34b8f2a9948ee203fbb85;hpb=6ca6c089e9df7affe6bee0392197509a24ab2546;p=notmuch diff --git a/lib/database.cc b/lib/database.cc index 7d09119c..a3824956 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -213,6 +213,17 @@ notmuch_status_to_string (notmuch_status_t status) } } +static void +find_doc_ids_for_term (notmuch_database_t *notmuch, + const char *term, + Xapian::PostingIterator *begin, + Xapian::PostingIterator *end) +{ + *begin = notmuch->xapian_db->postlist_begin (term); + + *end = notmuch->xapian_db->postlist_end (term); +} + static void find_doc_ids (notmuch_database_t *notmuch, const char *prefix_name, @@ -220,15 +231,12 @@ find_doc_ids (notmuch_database_t *notmuch, Xapian::PostingIterator *begin, Xapian::PostingIterator *end) { - Xapian::PostingIterator i; char *term; term = talloc_asprintf (notmuch, "%s%s", _find_prefix (prefix_name), value); - *begin = notmuch->xapian_db->postlist_begin (term); - - *end = notmuch->xapian_db->postlist_end (term); + find_doc_ids_for_term (notmuch, term, begin, end); talloc_free (term); } @@ -246,10 +254,19 @@ find_unique_doc_id (notmuch_database_t *notmuch, if (i == end) { *doc_id = 0; return NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND; - } else { - *doc_id = *i; - return NOTMUCH_PRIVATE_STATUS_SUCCESS; } + + *doc_id = *i; + +#if DEBUG_DATABASE_SANITY + i++; + + if (i != end) + INTERNAL_ERROR ("Term %s:%s is not unique as expected.\n", + prefix_name, value); +#endif + + return NOTMUCH_PRIVATE_STATUS_SUCCESS; } static Xapian::Document @@ -734,6 +751,38 @@ _notmuch_database_get_directory_path (void *ctx, return talloc_strdup (ctx, document.get_data ().c_str ()); } +/* Given a legal 'filename' for the database, (either relative to + * database path or absolute with initial components identical to + * database path), return a new string (with 'ctx' as the talloc + * owner) suitable for use as a direntry term value. + */ +notmuch_status_t +_notmuch_database_filename_to_direntry (void *ctx, + notmuch_database_t *notmuch, + const char *filename, + char **direntry) +{ + const char *relative, *directory, *basename; + Xapian::docid directory_id; + notmuch_status_t status; + + relative = _notmuch_database_relative_path (notmuch, filename); + + status = _notmuch_database_split_path (ctx, relative, + &directory, &basename); + if (status) + return status; + + status = _notmuch_database_find_directory_id (notmuch, directory, + &directory_id); + if (status) + return status; + + *direntry = talloc_asprintf (ctx, "%u:%s", directory_id, basename); + + return NOTMUCH_STATUS_SUCCESS; +} + /* Given a legal 'path' for the database, return the relative path. * * The return value will be a pointer to the originl path contents, @@ -843,7 +892,6 @@ notmuch_database_get_directory_mtime (notmuch_database_t *notmuch, notmuch_private_status_t status; const char *db_path = NULL; time_t ret = 0; - void *local = talloc_new (notmuch); db_path = directory_db_path (path); @@ -1188,23 +1236,24 @@ notmuch_database_add_message (notmuch_database_t *notmuch, goto DONE; } + _notmuch_message_add_filename (message, filename); + /* Is this a newly created message object? */ if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { - _notmuch_message_set_filename (message, filename); _notmuch_message_add_term (message, "type", "mail"); - } else { - ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; - goto DONE; - } - ret = _notmuch_database_link_message (notmuch, message, message_file); - if (ret) - goto DONE; + ret = _notmuch_database_link_message (notmuch, message, + message_file); + if (ret) + goto DONE; - date = notmuch_message_file_get_header (message_file, "date"); - _notmuch_message_set_date (message, date); + date = notmuch_message_file_get_header (message_file, "date"); + _notmuch_message_set_date (message, date); - _notmuch_message_index_file (message, filename); + _notmuch_message_index_file (message, filename); + } else { + ret = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; + } _notmuch_message_sync (message); } catch (const Xapian::Error &error) { @@ -1229,6 +1278,59 @@ notmuch_database_add_message (notmuch_database_t *notmuch, return ret; } +notmuch_status_t +notmuch_database_remove_message (notmuch_database_t *notmuch, + const char *filename) +{ + Xapian::WritableDatabase *db; + void *local = talloc_new (notmuch); + const char *direntry_prefix = _find_prefix ("direntry"); + char *direntry, *term; + Xapian::PostingIterator i, end; + Xapian::Document document; + notmuch_status_t status; + + if (notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) { + fprintf (stderr, "Attempted to update a read-only database.\n"); + return NOTMUCH_STATUS_READONLY_DATABASE; + } + + db = static_cast (notmuch->xapian_db); + + status = _notmuch_database_filename_to_direntry (local, notmuch, + filename, &direntry); + if (status) + return status; + + term = talloc_asprintf (notmuch, "%s%s", direntry_prefix, direntry); + + find_doc_ids_for_term (notmuch, term, &i, &end); + + for ( ; i != end; i++) { + Xapian::TermIterator j; + + document = find_document_for_doc_id (notmuch, *i); + + document.remove_term (term); + + j = document.termlist_begin (); + j.skip_to (direntry_prefix); + + /* Was this the last direntry in the message? */ + if (j == document.termlist_end () || + strncmp ((*j).c_str (), direntry_prefix, strlen (direntry_prefix))) + { + db->delete_document (document.get_docid ()); + } else { + db->replace_document (document.get_docid (), document); + } + } + + talloc_free (local); + + return NOTMUCH_STATUS_SUCCESS; +} + notmuch_tags_t * _notmuch_convert_tags (void *ctx, Xapian::TermIterator &i, Xapian::TermIterator &end)