X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=lib%2Fmessage.cc;h=4677f1df1565bc6df7cff75d459f7d063b10139a;hp=1ddce3c692bebdc94fa22023a7b80d05345d69c4;hb=9eebae3da4510a671cbbb2f476c2dc04099b4415;hpb=e6ad3a5dd4ca7a09a4760c4eb6721217cc906aaa diff --git a/lib/message.cc b/lib/message.cc index 1ddce3c6..4677f1df 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -728,7 +728,7 @@ _notmuch_message_add_filename (notmuch_message_t *message, * Note: This function does not remove a document from the database, * even if the specified filename is the only filename for this * message. For that functionality, see - * _notmuch_database_remove_message. */ + * notmuch_database_remove_message. */ notmuch_status_t _notmuch_message_remove_filename (notmuch_message_t *message, const char *filename) @@ -998,6 +998,16 @@ _notmuch_message_set_header_values (notmuch_message_t *message, message->modified = TRUE; } +/* Upgrade a message to support NOTMUCH_FEATURE_LAST_MOD. The caller + * must call _notmuch_message_sync. */ +void +_notmuch_message_upgrade_last_mod (notmuch_message_t *message) +{ + /* _notmuch_message_sync will update the last modification + * revision; we just have to ask it to. */ + message->modified = TRUE; +} + /* Synchronize changes made to message->doc out into the database. */ void _notmuch_message_sync (notmuch_message_t *message) @@ -1010,25 +1020,61 @@ _notmuch_message_sync (notmuch_message_t *message) if (! message->modified) return; + /* Update the last modification of this message. */ + if (message->notmuch->features & NOTMUCH_FEATURE_LAST_MOD) + /* sortable_serialise gives a reasonably compact encoding, + * which directly translates to reduced IO when scanning the + * value stream. Since it's built for doubles, we only get 53 + * effective bits, but that's still enough for the database to + * last a few centuries at 1 million revisions per second. */ + message->doc.add_value (NOTMUCH_VALUE_LAST_MOD, + Xapian::sortable_serialise ( + _notmuch_database_new_revision ( + message->notmuch))); + db = static_cast (message->notmuch->xapian_db); db->replace_document (message->doc_id, message->doc); message->modified = FALSE; } -/* Delete a message document from the database. */ +/* Delete a message document from the database, leaving a ghost + * message in its place */ notmuch_status_t _notmuch_message_delete (notmuch_message_t *message) { notmuch_status_t status; Xapian::WritableDatabase *db; + const char *mid, *tid; + notmuch_message_t *ghost; + notmuch_private_status_t private_status; + notmuch_database_t *notmuch; + + mid = notmuch_message_get_message_id (message); + tid = notmuch_message_get_thread_id (message); + notmuch = message->notmuch; status = _notmuch_database_ensure_writable (message->notmuch); if (status) return status; - db = static_cast (message->notmuch->xapian_db); + db = static_cast (notmuch->xapian_db); db->delete_document (message->doc_id); - return NOTMUCH_STATUS_SUCCESS; + + /* and reintroduce a ghost in its place */ + ghost = _notmuch_message_create_for_message_id (notmuch, mid, &private_status); + if (private_status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND) { + private_status = _notmuch_message_initialize_ghost (ghost, tid); + if (! private_status) + _notmuch_message_sync (ghost); + } else if (private_status == NOTMUCH_PRIVATE_STATUS_SUCCESS) { + /* this is deeply weird, and we should not have gotten into + this state. is there a better error message to return + here? */ + return NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; + } + + notmuch_message_destroy (ghost); + return COERCE_STATUS (private_status, "Error converting to ghost message"); } /* Transform a blank message into a ghost message. The caller must @@ -1158,7 +1204,7 @@ _notmuch_message_remove_term (notmuch_message_t *message, message->doc.remove_term (term); message->modified = TRUE; } catch (const Xapian::InvalidArgumentError) { - /* We'll let the philosopher's try to wrestle with the + /* We'll let the philosophers try to wrestle with the * question of whether failing to remove that which was not * there in the first place is failure. For us, we'll silently * consider it all good. */ @@ -1171,6 +1217,41 @@ _notmuch_message_remove_term (notmuch_message_t *message, return NOTMUCH_PRIVATE_STATUS_SUCCESS; } +notmuch_private_status_t +_notmuch_message_has_term (notmuch_message_t *message, + const char *prefix_name, + const char *value, + notmuch_bool_t *result) +{ + char *term; + notmuch_bool_t out = FALSE; + notmuch_private_status_t status = NOTMUCH_PRIVATE_STATUS_SUCCESS; + + if (value == NULL) + return NOTMUCH_PRIVATE_STATUS_NULL_POINTER; + + term = talloc_asprintf (message, "%s%s", + _find_prefix (prefix_name), value); + + if (strlen (term) > NOTMUCH_TERM_MAX) + return NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG; + + try { + /* Look for the exact term */ + Xapian::TermIterator i = message->doc.termlist_begin (); + i.skip_to (term); + if (i != message->doc.termlist_end () && + !strcmp ((*i).c_str (), term)) + out = TRUE; + } catch (Xapian::Error &error) { + status = NOTMUCH_PRIVATE_STATUS_XAPIAN_EXCEPTION; + } + talloc_free (term); + + *result = out; + return status; +} + notmuch_status_t notmuch_message_add_tag (notmuch_message_t *message, const char *tag) {