]> git.cworth.org Git - notmuch/blobdiff - lib/message.cc
emacs: Add new option notmuch-search-hide-excluded
[notmuch] / lib / message.cc
index 7af6ab82a721699ac7f09153724b9e8038484b2a..46638f800997d4c5250b3592e4be8ee79abc2a21 100644 (file)
@@ -169,6 +169,7 @@ _notmuch_message_create_for_document (const void *talloc_owner,
 
     message->doc = doc;
     message->termpos = 0;
+    message->modified = false;
 
     return message;
 }
@@ -288,7 +289,7 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
 
        doc_id = _notmuch_database_generate_doc_id (notmuch);
     } catch (const Xapian::Error &error) {
-       _notmuch_database_log (notmuch_message_get_database (message),
+       _notmuch_database_log (notmuch,
                               "A Xapian exception occurred creating message: %s\n",
                               error.get_msg ().c_str ());
        notmuch->exception_reported = true;
@@ -340,23 +341,6 @@ _notmuch_message_get_term (notmuch_message_t *message,
     return value;
 }
 
-/*
- * For special applications where we only want the thread id, reading
- * in all metadata is a heavy I/O penalty.
- */
-const char *
-_notmuch_message_get_thread_id_only (notmuch_message_t *message)
-{
-
-    Xapian::TermIterator i = message->doc.termlist_begin ();
-    Xapian::TermIterator end = message->doc.termlist_end ();
-
-    message->thread_id = _notmuch_message_get_term (message, i, end,
-                                                   _find_prefix ("thread"));
-    return message->thread_id;
-}
-
-
 static void
 _notmuch_message_ensure_metadata (notmuch_message_t *message, void *field)
 {
@@ -735,6 +719,8 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
            /* Ignore failure to remove non-existent term. */
        }
     }
+
+    _notmuch_message_invalidate_metadata (message, "property");
 }
 
 
@@ -742,7 +728,7 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix)
  * properties, along with any automatic tags*/
 /* According to Xapian API docs, none of these calls throw
  * exceptions */
-notmuch_private_status_t
+static notmuch_private_status_t
 _notmuch_message_remove_indexed_terms (notmuch_message_t *message)
 {
     Xapian::TermIterator i;
@@ -808,7 +794,7 @@ is_maildir (const char *p)
 }
 
 /* Add "folder:" term for directory. */
-static notmuch_status_t
+NODISCARD static notmuch_status_t
 _notmuch_message_add_folder_terms (notmuch_message_t *message,
                                   const char *directory)
 {
@@ -844,7 +830,10 @@ _notmuch_message_add_folder_terms (notmuch_message_t *message,
        *folder = '\0';
     }
 
-    _notmuch_message_add_term (message, "folder", folder);
+    if (notmuch_status_t status = COERCE_STATUS (_notmuch_message_add_term (message, "folder",
+                                                                           folder),
+                                                "adding folder term"))
+       return status;
 
     talloc_free (folder);
 
@@ -855,12 +844,17 @@ _notmuch_message_add_folder_terms (notmuch_message_t *message,
 #define RECURSIVE_SUFFIX "/**"
 
 /* Add "path:" terms for directory. */
-static notmuch_status_t
+NODISCARD static notmuch_status_t
 _notmuch_message_add_path_terms (notmuch_message_t *message,
                                 const char *directory)
 {
+    notmuch_status_t status;
+
     /* Add exact "path:" term. */
-    _notmuch_message_add_term (message, "path", directory);
+    status = COERCE_STATUS (_notmuch_message_add_term (message, "path", directory),
+                           "adding path term");
+    if (status)
+       return status;
 
     if (strlen (directory)) {
        char *path, *p;
@@ -873,7 +867,10 @@ _notmuch_message_add_path_terms (notmuch_message_t *message,
        for (p = path + strlen (path) - 1; p > path; p--) {
            if (*p == '/') {
                strcpy (p, RECURSIVE_SUFFIX);
-               _notmuch_message_add_term (message, "path", path);
+               status = COERCE_STATUS (_notmuch_message_add_term (message, "path", path),
+                                       "adding path term");
+               if (status)
+                   return status;
            }
        }
 
@@ -881,7 +878,10 @@ _notmuch_message_add_path_terms (notmuch_message_t *message,
     }
 
     /* Recursive all-matching path:** for consistency. */
-    _notmuch_message_add_term (message, "path", "**");
+    status = COERCE_STATUS (_notmuch_message_add_term (message, "path", "**"),
+                           "adding path term");
+    if (status)
+       return status;
 
     return NOTMUCH_STATUS_SUCCESS;
 }
@@ -900,6 +900,7 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message)
        const char *direntry, *directory;
        char *colon;
        const std::string &term = *i;
+       notmuch_status_t term_status;
 
        /* Terminate loop at first term without desired prefix. */
        if (strncmp (term.c_str (), direntry_prefix, direntry_prefix_len))
@@ -920,8 +921,13 @@ _notmuch_message_add_directory_terms (void *ctx, notmuch_message_t *message)
                                                          message->notmuch,
                                                          directory_id);
 
-       _notmuch_message_add_folder_terms (message, directory);
-       _notmuch_message_add_path_terms (message, directory);
+       term_status = _notmuch_message_add_folder_terms (message, directory);
+       if (term_status)
+           return term_status;
+
+       term_status = _notmuch_message_add_path_terms (message, directory);
+       if (term_status)
+           return term_status;
     }
 
     return status;
@@ -937,6 +943,7 @@ _notmuch_message_add_filename (notmuch_message_t *message,
 {
     const char *relative, *directory;
     notmuch_status_t status;
+    notmuch_private_status_t private_status;
     void *local = talloc_new (message);
     char *direntry;
 
@@ -960,10 +967,25 @@ _notmuch_message_add_filename (notmuch_message_t *message,
 
     /* New file-direntry allows navigating to this message with
      * notmuch_directory_get_child_files() . */
-    _notmuch_message_add_term (message, "file-direntry", direntry);
+    private_status = _notmuch_message_add_term (message, "file-direntry", direntry);
+    switch (private_status) {
+    case NOTMUCH_PRIVATE_STATUS_SUCCESS:
+       break;
+    case NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG:
+       _notmuch_database_log (message->notmuch, "filename too long for file-direntry term: %s\n",
+                              filename);
+       return NOTMUCH_STATUS_PATH_ERROR;
+    default:
+       return COERCE_STATUS (private_status, "adding file-direntry term");
+    }
 
-    _notmuch_message_add_folder_terms (message, directory);
-    _notmuch_message_add_path_terms (message, directory);
+    status = _notmuch_message_add_folder_terms (message, directory);
+    if (status)
+       return status;
+
+    status = _notmuch_message_add_path_terms (message, directory);
+    if (status)
+       return status;
 
     talloc_free (local);
 
@@ -1371,21 +1393,22 @@ _notmuch_message_delete (notmuch_message_t *message)
     if (status)
        return status;
 
-    message->notmuch->writable_xapian_db->delete_document (message->doc_id);
-
-    /* if this was a ghost to begin with, we are done */
-    private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
-    if (private_status)
-       return COERCE_STATUS (private_status,
-                             "Error trying to determine whether message was a ghost");
-    if (is_ghost)
-       return NOTMUCH_STATUS_SUCCESS;
-
-    /* look for a non-ghost message in the same thread */
     try {
        Xapian::PostingIterator thread_doc, thread_doc_end;
        Xapian::PostingIterator mail_doc, mail_doc_end;
 
+       /* look for a non-ghost message in the same thread */
+       /* if this was a ghost to begin with, we are done */
+       private_status = _notmuch_message_has_term (message, "type", "ghost", &is_ghost);
+       if (private_status)
+           return COERCE_STATUS (private_status,
+                                 "Error trying to determine whether message was a ghost");
+
+       message->notmuch->writable_xapian_db->delete_document (message->doc_id);
+
+       if (is_ghost)
+           return NOTMUCH_STATUS_SUCCESS;
+
        _notmuch_database_find_doc_ids (message->notmuch, "thread", tid, &thread_doc,
                                        &thread_doc_end);
        _notmuch_database_find_doc_ids (message->notmuch, "type", "mail", &mail_doc, &mail_doc_end);
@@ -1482,31 +1505,37 @@ _notmuch_message_close (notmuch_message_t *message)
  *
  * This change will not be reflected in the database until the next
  * call to _notmuch_message_sync. */
-notmuch_private_status_t
+NODISCARD notmuch_private_status_t
 _notmuch_message_add_term (notmuch_message_t *message,
                           const char *prefix_name,
                           const char *value)
 {
 
     char *term;
+    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) {
+       status = NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG;
+       goto DONE;
+    }
 
-    if (strlen (term) > NOTMUCH_TERM_MAX)
-       return NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG;
-
-    message->doc.add_term (term, 0);
-    message->modified = true;
+    try {
+       message->doc.add_term (term, 0);
+       message->modified = true;
+       _notmuch_message_invalidate_metadata (message, prefix_name);
+    } catch (Xapian::Error &error) {
+       LOG_XAPIAN_EXCEPTION (message, error);
+       status = NOTMUCH_PRIVATE_STATUS_XAPIAN_EXCEPTION;
+    }
 
+  DONE:
     talloc_free (term);
-
-    _notmuch_message_invalidate_metadata (message, prefix_name);
-
-    return NOTMUCH_PRIVATE_STATUS_SUCCESS;
+    return status;
 }
 
 /* Parse 'text' and add a term to 'message' for each parsed word. Each
@@ -1551,7 +1580,7 @@ _notmuch_message_gen_terms (notmuch_message_t *message,
  *
  * This change will not be reflected in the database until the next
  * call to _notmuch_message_sync. */
-notmuch_private_status_t
+NODISCARD notmuch_private_status_t
 _notmuch_message_remove_term (notmuch_message_t *message,
                              const char *prefix_name,
                              const char *value)
@@ -1570,11 +1599,12 @@ _notmuch_message_remove_term (notmuch_message_t *message,
     try {
        message->doc.remove_term (term);
        message->modified = true;
-    } catch (const Xapian::InvalidArgumentError) {
+    } catch (const Xapian::InvalidArgumentError &error) {
        /* 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. */
+       LOG_XAPIAN_EXCEPTION (message, error);
     }
 
     talloc_free (term);
@@ -2020,6 +2050,10 @@ notmuch_message_tags_to_maildir_flags (notmuch_message_t *message)
     char *to_set, *to_clear;
     notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
 
+    status = _notmuch_database_ensure_writable (message->notmuch);
+    if (status)
+       return status;
+
     _get_maildir_flag_actions (message, &to_set, &to_clear);
 
     for (filenames = notmuch_message_get_filenames (message);
@@ -2283,7 +2317,11 @@ notmuch_message_reindex (notmuch_message_t *message,
        if (thread_id == NULL)
            thread_id = orig_thread_id;
 
-       _notmuch_message_add_term (message, "thread", thread_id);
+       ret = COERCE_STATUS (_notmuch_message_add_term (message, "thread", thread_id),
+                            "adding thread term");
+       if (ret)
+           goto DONE;
+
        /* Take header values only from first filename */
        if (found == 0)
            _notmuch_message_set_header_values (message, date, from, subject);
@@ -2301,7 +2339,11 @@ notmuch_message_reindex (notmuch_message_t *message,
     }
     if (found == 0) {
        /* put back thread id to help cleanup */
-       _notmuch_message_add_term (message, "thread", orig_thread_id);
+       ret = COERCE_STATUS (_notmuch_message_add_term (message, "thread", orig_thread_id),
+                            "adding thread term");
+       if (ret)
+           goto DONE;
+
        ret = _notmuch_message_delete (message);
     } else {
        _notmuch_message_sync (message);