X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=lib%2Fmessage.cc;h=956a70a9572f861d5ba5aadc1d4154f15794e398;hb=a9e0786f72bd01186b58b739986e7ac0680ff7c0;hp=bbfc2500bd92f12dfade22db471fb6b22bf9613b;hpb=54ec8a0fd87ae7a32c8208be67a345c0eeea7f69;p=notmuch diff --git a/lib/message.cc b/lib/message.cc index bbfc2500..956a70a9 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -39,6 +39,9 @@ struct visible _notmuch_message { notmuch_message_file_t *message_file; notmuch_message_list_t *replies; unsigned long flags; + /* For flags that are initialized on-demand, lazy_flags indicates + * if each flag has been initialized. */ + unsigned long lazy_flags; Xapian::Document doc; Xapian::termcount termpos; @@ -99,6 +102,7 @@ _notmuch_message_create_for_document (const void *talloc_owner, message->frozen = 0; message->flags = 0; + message->lazy_flags = 0; /* Each of these will be lazily created as needed. */ message->message_id = NULL; @@ -192,7 +196,7 @@ _notmuch_message_create (const void *talloc_owner, * * There is already a document with message ID 'message_id' in the * database. The returned message can be used to query/modify the - * document. + * document. The message may be a ghost message. * * NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND: * @@ -279,7 +283,7 @@ _notmuch_message_get_term (notmuch_message_t *message, if (i == end) return NULL; - std::string term = *i; + const std::string &term = *i; if (strncmp (term.c_str(), prefix, prefix_len)) return NULL; @@ -305,6 +309,7 @@ _notmuch_message_ensure_metadata (notmuch_message_t *message) const char *thread_prefix = _find_prefix ("thread"), *tag_prefix = _find_prefix ("tag"), *id_prefix = _find_prefix ("id"), + *type_prefix = _find_prefix ("type"), *filename_prefix = _find_prefix ("file-direntry"), *replyto_prefix = _find_prefix ("replyto"); @@ -337,10 +342,25 @@ _notmuch_message_ensure_metadata (notmuch_message_t *message) message->message_id = _notmuch_message_get_term (message, i, end, id_prefix); + /* Get document type */ + assert (strcmp (id_prefix, type_prefix) < 0); + if (! NOTMUCH_TEST_BIT (message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST)) { + i.skip_to (type_prefix); + /* "T" is the prefix "type" fields. See + * BOOLEAN_PREFIX_INTERNAL. */ + if (*i == "Tmail") + NOTMUCH_CLEAR_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST); + else if (*i == "Tghost") + NOTMUCH_SET_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST); + else + INTERNAL_ERROR ("Message without type term"); + NOTMUCH_SET_BIT (&message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST); + } + /* Get filename list. Here we get only the terms. We lazily * expand them to full file names when needed in * _notmuch_message_ensure_filename_list. */ - assert (strcmp (id_prefix, filename_prefix) < 0); + assert (strcmp (type_prefix, filename_prefix) < 0); if (!message->filename_term_list && !message->filename_list) message->filename_term_list = _notmuch_database_get_terms_with_prefix (message, i, end, @@ -371,6 +391,11 @@ _notmuch_message_invalidate_metadata (notmuch_message_t *message, message->tag_list = NULL; } + if (strcmp ("type", prefix_name) == 0) { + NOTMUCH_CLEAR_BIT (&message->flags, NOTMUCH_MESSAGE_FLAG_GHOST); + NOTMUCH_CLEAR_BIT (&message->lazy_flags, NOTMUCH_MESSAGE_FLAG_GHOST); + } + if (strcmp ("file-direntry", prefix_name) == 0) { talloc_free (message->filename_term_list); talloc_free (message->filename_list); @@ -616,15 +641,16 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message) unsigned int directory_id; const char *direntry, *directory; char *colon; + const std::string &term = *i; /* Terminate loop at first term without desired prefix. */ - if (strncmp ((*i).c_str (), direntry_prefix, direntry_prefix_len)) + if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len)) break; /* Indicate that there are filenames remaining. */ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID; - direntry = (*i).c_str (); + direntry = term.c_str (); direntry += direntry_prefix_len; directory_id = strtol (direntry, &colon, 10); @@ -869,7 +895,11 @@ notmuch_bool_t notmuch_message_get_flag (notmuch_message_t *message, notmuch_message_flag_t flag) { - return message->flags & (1 << flag); + if (flag == NOTMUCH_MESSAGE_FLAG_GHOST && + ! NOTMUCH_TEST_BIT (message->lazy_flags, flag)) + _notmuch_message_ensure_metadata (message); + + return NOTMUCH_TEST_BIT (message->flags, flag); } void @@ -877,9 +907,10 @@ notmuch_message_set_flag (notmuch_message_t *message, notmuch_message_flag_t flag, notmuch_bool_t enable) { if (enable) - message->flags |= (1 << flag); + NOTMUCH_SET_BIT (&message->flags, flag); else - message->flags &= ~(1 << flag); + NOTMUCH_CLEAR_BIT (&message->flags, flag); + NOTMUCH_SET_BIT (&message->lazy_flags, flag); } time_t @@ -896,6 +927,9 @@ notmuch_message_get_date (notmuch_message_t *message) return 0; } + if (value.empty ()) + /* sortable_unserialise is undefined on empty string */ + return 0; return Xapian::sortable_unserialise (value); } @@ -986,6 +1020,24 @@ _notmuch_message_delete (notmuch_message_t *message) return NOTMUCH_STATUS_SUCCESS; } +/* Transform a blank message into a ghost message. The caller must + * _notmuch_message_sync the message. */ +notmuch_private_status_t +_notmuch_message_initialize_ghost (notmuch_message_t *message, + const char *thread_id) +{ + notmuch_private_status_t status; + + status = _notmuch_message_add_term (message, "type", "ghost"); + if (status) + return status; + status = _notmuch_message_add_term (message, "thread", thread_id); + if (status) + return status; + + return NOTMUCH_PRIVATE_STATUS_SUCCESS; +} + /* Ensure that 'message' is not holding any file object open. Future * calls to various functions will still automatically open the * message file as needed.