aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Bremner <david@tethera.net>2016-06-28 16:48:30 +0200
committerDavid Bremner <david@tethera.net>2016-06-28 16:48:30 +0200
commit7fe91ddc4f47170724d455e84d5d262410d569f2 (patch)
tree4ba841df17c181ab6a785d408c4e5f8316bda9c1 /lib
parent148ceed198f98524db8482e212804c5a510d696b (diff)
parentea5caecec5c50833a6f5a422e217a71eee6324af (diff)
Merge tag 'debian/0.22-1' into jessie-backports
notmuch Debian 0.22-1 upload (same as 0.22)
Diffstat (limited to 'lib')
-rw-r--r--lib/database.cc22
-rw-r--r--lib/index.cc3
-rw-r--r--lib/message.cc115
-rw-r--r--lib/notmuch-private.h17
-rw-r--r--lib/notmuch.h11
-rw-r--r--lib/query.cc18
6 files changed, 162 insertions, 24 deletions
diff --git a/lib/database.cc b/lib/database.cc
index 5e86955d..c8c5e261 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1635,6 +1635,9 @@ notmuch_database_begin_atomic (notmuch_database_t *notmuch)
notmuch->atomic_nesting > 0)
goto DONE;
+ if (notmuch_database_needs_upgrade(notmuch))
+ return NOTMUCH_STATUS_UPGRADE_REQUIRED;
+
try {
(static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db))->begin_transaction (false);
} catch (const Xapian::Error &error) {
@@ -1758,18 +1761,11 @@ _notmuch_database_split_path (void *ctx,
slash = path + strlen (path) - 1;
/* First, skip trailing slashes. */
- while (slash != path) {
- if (*slash != '/')
- break;
-
+ while (slash != path && *slash == '/')
--slash;
- }
/* Then, find a slash. */
- while (slash != path) {
- if (*slash == '/')
- break;
-
+ while (slash != path && *slash != '/') {
if (basename)
*basename = slash;
@@ -1777,12 +1773,8 @@ _notmuch_database_split_path (void *ctx,
}
/* Finally, skip multiple slashes. */
- while (slash != path) {
- if (*slash != '/')
- break;
-
+ while (slash != path && *(slash - 1) == '/')
--slash;
- }
if (slash == path) {
if (directory)
@@ -1791,7 +1783,7 @@ _notmuch_database_split_path (void *ctx,
*basename = path;
} else {
if (directory)
- *directory = talloc_strndup (ctx, path, slash - path + 1);
+ *directory = talloc_strndup (ctx, path, slash - path);
}
return NOTMUCH_STATUS_SUCCESS;
diff --git a/lib/index.cc b/lib/index.cc
index e81aa819..f166aefd 100644
--- a/lib/index.cc
+++ b/lib/index.cc
@@ -377,7 +377,8 @@ _index_mime_part (notmuch_message_t *message,
disposition = g_mime_object_get_content_disposition (part);
if (disposition &&
- strcmp (disposition->disposition, GMIME_DISPOSITION_ATTACHMENT) == 0)
+ strcasecmp (g_mime_content_disposition_get_disposition (disposition),
+ GMIME_DISPOSITION_ATTACHMENT) == 0)
{
const char *filename = g_mime_part_get_filename (GMIME_PART (part));
diff --git a/lib/message.cc b/lib/message.cc
index 26b5e76e..68393055 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)
@@ -1037,20 +1037,90 @@ _notmuch_message_sync (notmuch_message_t *message)
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, *query_string;
+ notmuch_message_t *ghost;
+ notmuch_private_status_t private_status;
+ notmuch_database_t *notmuch;
+ notmuch_query_t *query;
+ unsigned int count = 0;
+ notmuch_bool_t is_ghost;
+
+ 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 <Xapian::WritableDatabase *> (message->notmuch->xapian_db);
+ db = static_cast <Xapian::WritableDatabase *> (notmuch->xapian_db);
db->delete_document (message->doc_id);
- return NOTMUCH_STATUS_SUCCESS;
+
+ /* 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;
+
+ query_string = talloc_asprintf (message, "thread:%s", tid);
+ query = notmuch_query_create (notmuch, query_string);
+ if (query == NULL)
+ return NOTMUCH_STATUS_OUT_OF_MEMORY;
+ status = notmuch_query_count_messages_st (query, &count);
+ if (status) {
+ notmuch_query_destroy (query);
+ return status;
+ }
+
+ if (count > 0) {
+ /* reintroduce a ghost in its place because there are still
+ * other active messages in this thread: */
+ 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? */
+ status = NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID;
+ }
+
+ notmuch_message_destroy (ghost);
+ status = COERCE_STATUS (private_status, "Error converting to ghost message");
+ } else {
+ /* the thread is empty; drop all ghost messages from it */
+ notmuch_messages_t *messages;
+ status = _notmuch_query_search_documents (query,
+ "ghost",
+ &messages);
+ if (status == NOTMUCH_STATUS_SUCCESS) {
+ notmuch_status_t last_error = NOTMUCH_STATUS_SUCCESS;
+ while (notmuch_messages_valid (messages)) {
+ message = notmuch_messages_get (messages);
+ status = _notmuch_message_delete (message);
+ if (status) /* we'll report the last failure we see;
+ * if there is more than one failure, we
+ * forget about previous ones */
+ last_error = status;
+ notmuch_message_destroy (message);
+ notmuch_messages_move_to_next (messages);
+ }
+ status = last_error;
+ }
+ }
+ notmuch_query_destroy (query);
+ return status;
}
/* Transform a blank message into a ghost message. The caller must
@@ -1180,7 +1250,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. */
@@ -1193,6 +1263,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)
{
diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h
index 5dd4770e..92807975 100644
--- a/lib/notmuch-private.h
+++ b/lib/notmuch-private.h
@@ -280,6 +280,12 @@ _notmuch_message_remove_term (notmuch_message_t *message,
const char *value);
notmuch_private_status_t
+_notmuch_message_has_term (notmuch_message_t *message,
+ const char *prefix_name,
+ const char *value,
+ notmuch_bool_t *result);
+
+notmuch_private_status_t
_notmuch_message_gen_terms (notmuch_message_t *message,
const char *prefix_name,
const char *text);
@@ -477,6 +483,17 @@ void
_notmuch_doc_id_set_remove (notmuch_doc_id_set_t *doc_ids,
unsigned int doc_id);
+/* querying xapian documents by type (e.g. "mail" or "ghost"): */
+notmuch_status_t
+_notmuch_query_search_documents (notmuch_query_t *query,
+ const char *type,
+ notmuch_messages_t **out);
+
+notmuch_status_t
+_notmuch_query_count_documents (notmuch_query_t *query,
+ const char *type,
+ unsigned *count_out);
+
/* message.cc */
void
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 85b56bf1..cb46fc05 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -59,8 +59,17 @@ NOTMUCH_BEGIN_DECLS
#define LIBNOTMUCH_MINOR_VERSION 3
#define LIBNOTMUCH_MICRO_VERSION 0
+
+#if defined (__clang_major__) && __clang_major__ >= 3 \
+ || defined (__GNUC__) && __GNUC__ >= 5 \
+ || defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 5
#define NOTMUCH_DEPRECATED(major,minor) \
__attribute__ ((deprecated ("function deprecated as of libnotmuch " #major "." #minor)))
+#else
+#define NOTMUCH_DEPRECATED(major,minor) __attribute__ ((deprecated))
+#endif
+
+
#endif /* __DOXYGEN__ */
/**
@@ -1752,7 +1761,7 @@ notmuch_filenames_t *
notmuch_directory_get_child_files (notmuch_directory_t *directory);
/**
- * Get a notmuch_filenams_t iterator listing all the filenames of
+ * Get a notmuch_filenames_t iterator listing all the filenames of
* sub-directories in the database within the given directory.
*
* The returned filenames will be the basename-entries only (not
diff --git a/lib/query.cc b/lib/query.cc
index e627bfc2..77a7926b 100644
--- a/lib/query.cc
+++ b/lib/query.cc
@@ -187,6 +187,14 @@ notmuch_status_t
notmuch_query_search_messages_st (notmuch_query_t *query,
notmuch_messages_t **out)
{
+ return _notmuch_query_search_documents (query, "mail", out);
+}
+
+notmuch_status_t
+_notmuch_query_search_documents (notmuch_query_t *query,
+ const char *type,
+ notmuch_messages_t **out)
+{
notmuch_database_t *notmuch = query->notmuch;
const char *query_string = query->query_string;
notmuch_mset_messages_t *messages;
@@ -208,7 +216,7 @@ notmuch_query_search_messages_st (notmuch_query_t *query,
Xapian::Enquire enquire (*notmuch->xapian_db);
Xapian::Query mail_query (talloc_asprintf (query, "%s%s",
_find_prefix ("type"),
- "mail"));
+ type));
Xapian::Query string_query, final_query, exclude_query;
Xapian::MSet mset;
Xapian::MSetIterator iterator;
@@ -554,6 +562,12 @@ notmuch_query_count_messages (notmuch_query_t *query)
notmuch_status_t
notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out)
{
+ return _notmuch_query_count_documents (query, "mail", count_out);
+}
+
+notmuch_status_t
+_notmuch_query_count_documents (notmuch_query_t *query, const char *type, unsigned *count_out)
+{
notmuch_database_t *notmuch = query->notmuch;
const char *query_string = query->query_string;
Xapian::doccount count = 0;
@@ -562,7 +576,7 @@ notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out)
Xapian::Enquire enquire (*notmuch->xapian_db);
Xapian::Query mail_query (talloc_asprintf (query, "%s%s",
_find_prefix ("type"),
- "mail"));
+ type));
Xapian::Query string_query, final_query, exclude_query;
Xapian::MSet mset;
unsigned int flags = (Xapian::QueryParser::FLAG_BOOLEAN |