diff options
| author | David Bremner <david@tethera.net> | 2015-12-13 08:39:11 -0400 |
|---|---|---|
| committer | David Bremner <david@tethera.net> | 2015-12-13 08:39:11 -0400 |
| commit | e3cd357fdddd2d8d29e8eea0b40a1043c46f1791 (patch) | |
| tree | b0e4f0549fc1216439e4593b73206c7923995ad4 /lib | |
| parent | ad5b7434978ed98b1eb832b77684869f5d02594a (diff) | |
| parent | 1432a4f946e0f236179b53ac71d03764da725f33 (diff) | |
Merge tag 'debian/0.21-3' into jessie-backports
uploaded to unstable
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.local | 23 | ||||
| -rw-r--r-- | lib/database-private.h | 18 | ||||
| -rw-r--r-- | lib/database.cc | 107 | ||||
| -rw-r--r-- | lib/directory.cc | 25 | ||||
| -rw-r--r-- | lib/gen-version-script.sh | 1 | ||||
| -rw-r--r-- | lib/message-file.c | 21 | ||||
| -rw-r--r-- | lib/message.cc | 34 | ||||
| -rw-r--r-- | lib/notmuch-private.h | 11 | ||||
| -rw-r--r-- | lib/notmuch.h | 144 | ||||
| -rw-r--r-- | lib/parse-time-vrp.cc | 5 | ||||
| -rw-r--r-- | lib/query.cc | 53 | ||||
| -rw-r--r-- | lib/thread.cc | 7 |
12 files changed, 358 insertions, 91 deletions
diff --git a/lib/Makefile.local b/lib/Makefile.local index f9ecd50e..3a070907 100644 --- a/lib/Makefile.local +++ b/lib/Makefile.local @@ -1,26 +1,5 @@ # -*- makefile -*- -# The major version of the library interface. This will control the soname. -# As such, this number must be incremented for any incompatible change to -# the library interface, (such as the deletion of an API or a major -# semantic change that breaks formerly functioning code). -# -LIBNOTMUCH_VERSION_MAJOR = 4 - -# The minor version of the library interface. This should be incremented at -# the time of release for any additions to the library interface, -# (and when it is incremented, the release version of the library should -# be reset to 0). -LIBNOTMUCH_VERSION_MINOR = 2 - -# The release version the library interface. This should be incremented at -# the time of release if there have been no changes to the interface, (but -# simply compatible changes to the implementation). -LIBNOTMUCH_VERSION_RELEASE = 0 - -# Note: Don't forget to change the VERSION macros in notmuch.h when -# any of the above change. - ifeq ($(PLATFORM),MACOSX) LIBRARY_SUFFIX = dylib # On OS X, library version numbers go before suffix. @@ -33,7 +12,7 @@ LIBRARY_SUFFIX = so LINKER_NAME = libnotmuch.$(LIBRARY_SUFFIX) SONAME = $(LINKER_NAME).$(LIBNOTMUCH_VERSION_MAJOR) LIBNAME = $(SONAME).$(LIBNOTMUCH_VERSION_MINOR).$(LIBNOTMUCH_VERSION_RELEASE) -LIBRARY_LINK_FLAG = -shared -Wl,--version-script=notmuch.sym,-soname=$(SONAME) -Wl,--no-undefined +LIBRARY_LINK_FLAG = -shared -Wl,--version-script=notmuch.sym,-soname=$(SONAME) $(NO_UNDEFINED_LDFLAGS) ifeq ($(PLATFORM),OPENBSD) LIBRARY_LINK_FLAG += -lc endif diff --git a/lib/database-private.h b/lib/database-private.h index 24243db2..3fb10f7a 100644 --- a/lib/database-private.h +++ b/lib/database-private.h @@ -100,6 +100,12 @@ enum _notmuch_features { * * Introduced: version 3. */ NOTMUCH_FEATURE_INDEXED_MIMETYPES = 1 << 5, + + /* If set, messages store the revision number of the last + * modification in NOTMUCH_VALUE_LAST_MOD. + * + * Introduced: version 3. */ + NOTMUCH_FEATURE_LAST_MOD = 1 << 6, }; /* In C++, a named enum is its own type, so define bitwise operators @@ -145,6 +151,8 @@ struct _notmuch_database { notmuch_database_mode_t mode; int atomic_nesting; + /* TRUE if changes have been made in this atomic section */ + notmuch_bool_t atomic_dirty; Xapian::Database *xapian_db; /* Bit mask of features used by this database. This is a @@ -158,10 +166,17 @@ struct _notmuch_database { * next library call. May be NULL */ char *status_string; + /* Highest committed revision number. Modifications are recorded + * under a higher revision number, which can be generated with + * notmuch_database_new_revision. */ + unsigned long revision; + const char *uuid; + Xapian::QueryParser *query_parser; Xapian::TermGenerator *term_gen; Xapian::ValueRangeProcessor *value_range_processor; Xapian::ValueRangeProcessor *date_range_processor; + Xapian::ValueRangeProcessor *last_mod_range_processor; }; /* Prior to database version 3, features were implied by the database @@ -179,7 +194,8 @@ struct _notmuch_database { * will have it). */ #define NOTMUCH_FEATURES_CURRENT \ (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_DIRECTORY_DOCS | \ - NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS) + NOTMUCH_FEATURE_BOOL_FOLDER | NOTMUCH_FEATURE_GHOSTS | \ + NOTMUCH_FEATURE_LAST_MOD) /* Return the list of terms from the given iterator matching a prefix. * The prefix will be stripped from the strings in the returned list. diff --git a/lib/database.cc b/lib/database.cc index cffab62c..5e86955d 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -101,6 +101,9 @@ typedef struct { * * SUBJECT: The value of the "Subject" header * + * LAST_MOD: The revision number as of the last tag or + * filename change. + * * In addition, terms from the content of the message are added with * "from", "to", "attachment", and "subject" prefixes for use by the * user in searching. Similarly, terms from the path of the mail @@ -310,6 +313,8 @@ static const struct { * them. */ { NOTMUCH_FEATURE_INDEXED_MIMETYPES, "indexed MIME types", "w"}, + { NOTMUCH_FEATURE_LAST_MOD, + "modification tracking", "w"}, }; const char * @@ -342,6 +347,8 @@ notmuch_status_to_string (notmuch_status_t status) return "Unsupported operation"; case NOTMUCH_STATUS_UPGRADE_REQUIRED: return "Operation requires a database upgrade"; + case NOTMUCH_STATUS_PATH_ERROR: + return "Path supplied is illegal for this function"; default: case NOTMUCH_STATUS_LAST_STATUS: return "Unknown error status value"; @@ -657,6 +664,12 @@ notmuch_database_create_verbose (const char *path, goto DONE; } + if (path[0] != '/') { + message = strdup ("Error: Database path must be absolute.\n"); + status = NOTMUCH_STATUS_PATH_ERROR; + goto DONE; + } + err = stat (path, &st); if (err) { IGNORE_RESULT (asprintf (&message, "Error: Cannot create database at %s: %s.\n", @@ -729,6 +742,23 @@ _notmuch_database_ensure_writable (notmuch_database_t *notmuch) return NOTMUCH_STATUS_SUCCESS; } +/* Allocate a revision number for the next change. */ +unsigned long +_notmuch_database_new_revision (notmuch_database_t *notmuch) +{ + unsigned long new_revision = notmuch->revision + 1; + + /* If we're in an atomic section, hold off on updating the + * committed revision number until we commit the atomic section. + */ + if (notmuch->atomic_nesting) + notmuch->atomic_dirty = TRUE; + else + notmuch->revision = new_revision; + + return new_revision; +} + /* Parse a database features string from the given database version. * Returns the feature bit set. * @@ -847,6 +877,12 @@ notmuch_database_open_verbose (const char *path, goto DONE; } + if (path[0] != '/') { + message = strdup ("Error: Database path must be absolute.\n"); + status = NOTMUCH_STATUS_PATH_ERROR; + goto DONE; + } + if (! (notmuch_path = talloc_asprintf (local, "%s/%s", path, ".notmuch"))) { message = strdup ("Out of memory\n"); status = NOTMUCH_STATUS_OUT_OF_MEMORY; @@ -890,6 +926,7 @@ notmuch_database_open_verbose (const char *path, notmuch->atomic_nesting = 0; try { string last_thread_id; + string last_mod; if (mode == NOTMUCH_DATABASE_MODE_READ_WRITE) { notmuch->xapian_db = new Xapian::WritableDatabase (xapian_path, @@ -948,11 +985,22 @@ notmuch_database_open_verbose (const char *path, INTERNAL_ERROR ("Malformed database last_thread_id: %s", str); } + /* Get current highest revision number. */ + last_mod = notmuch->xapian_db->get_value_upper_bound ( + NOTMUCH_VALUE_LAST_MOD); + if (last_mod.empty ()) + notmuch->revision = 0; + else + notmuch->revision = Xapian::sortable_unserialise (last_mod); + notmuch->uuid = talloc_strdup ( + notmuch, notmuch->xapian_db->get_uuid ().c_str ()); + notmuch->query_parser = new Xapian::QueryParser; notmuch->term_gen = new Xapian::TermGenerator; notmuch->term_gen->set_stemmer (Xapian::Stem ("english")); notmuch->value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); notmuch->date_range_processor = new ParseTimeValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); + notmuch->last_mod_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_LAST_MOD, "lastmod:"); notmuch->query_parser->set_default_op (Xapian::Query::OP_AND); notmuch->query_parser->set_database (*notmuch->xapian_db); @@ -960,6 +1008,7 @@ notmuch_database_open_verbose (const char *path, notmuch->query_parser->set_stemming_strategy (Xapian::QueryParser::STEM_SOME); notmuch->query_parser->add_valuerangeprocessor (notmuch->value_range_processor); notmuch->query_parser->add_valuerangeprocessor (notmuch->date_range_processor); + notmuch->query_parser->add_valuerangeprocessor (notmuch->last_mod_range_processor); for (i = 0; i < ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) { prefix_t *prefix = &BOOLEAN_PREFIX_EXTERNAL[i]; @@ -1038,6 +1087,8 @@ notmuch_database_close (notmuch_database_t *notmuch) notmuch->value_range_processor = NULL; delete notmuch->date_range_processor; notmuch->date_range_processor = NULL; + delete notmuch->last_mod_range_processor; + notmuch->last_mod_range_processor = NULL; return status; } @@ -1321,6 +1372,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, enum _notmuch_features target_features, new_features; notmuch_status_t status; notmuch_private_status_t private_status; + notmuch_query_t *query = NULL; unsigned int count = 0, total = 0; status = _notmuch_database_ensure_writable (notmuch); @@ -1336,7 +1388,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, return NOTMUCH_STATUS_SUCCESS; if (progress_notify) { - /* Setup our handler for SIGALRM */ + /* Set up our handler for SIGALRM */ memset (&action, 0, sizeof (struct sigaction)); action.sa_handler = handle_sigalrm; sigemptyset (&action.sa_mask); @@ -1355,10 +1407,18 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, /* Figure out how much total work we need to do. */ if (new_features & - (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER)) { - notmuch_query_t *query = notmuch_query_create (notmuch, ""); - total += notmuch_query_count_messages (query); + (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER | + NOTMUCH_FEATURE_LAST_MOD)) { + query = notmuch_query_create (notmuch, ""); + unsigned msg_count; + + status = notmuch_query_count_messages_st (query, &msg_count); + if (status) + goto DONE; + + total += msg_count; notmuch_query_destroy (query); + query = NULL; } if (new_features & NOTMUCH_FEATURE_DIRECTORY_DOCS) { t_end = db->allterms_end ("XTIMESTAMP"); @@ -1382,13 +1442,18 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, /* Perform per-message upgrades. */ if (new_features & - (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER)) { - notmuch_query_t *query = notmuch_query_create (notmuch, ""); + (NOTMUCH_FEATURE_FILE_TERMS | NOTMUCH_FEATURE_BOOL_FOLDER | + NOTMUCH_FEATURE_LAST_MOD)) { notmuch_messages_t *messages; notmuch_message_t *message; char *filename; - for (messages = notmuch_query_search_messages (query); + query = notmuch_query_create (notmuch, ""); + + status = notmuch_query_search_messages_st (query, &messages); + if (status) + goto DONE; + for (; notmuch_messages_valid (messages); notmuch_messages_move_to_next (messages)) { @@ -1419,6 +1484,14 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, if (new_features & NOTMUCH_FEATURE_BOOL_FOLDER) _notmuch_message_upgrade_folder (message); + /* Prior to NOTMUCH_FEATURE_LAST_MOD, messages did not + * track modification revisions. Give all messages the + * next available revision; since we just started tracking + * revisions for this database, that will be 1. + */ + if (new_features & NOTMUCH_FEATURE_LAST_MOD) + _notmuch_message_upgrade_last_mod (message); + _notmuch_message_sync (message); notmuch_message_destroy (message); @@ -1427,6 +1500,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, } notmuch_query_destroy (query); + query = NULL; } /* Perform per-directory upgrades. */ @@ -1547,6 +1621,9 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, sigaction (SIGALRM, &action, NULL); } + if (query) + notmuch_query_destroy (query); + talloc_free (local); return status; } @@ -1601,11 +1678,25 @@ notmuch_database_end_atomic (notmuch_database_t *notmuch) return NOTMUCH_STATUS_XAPIAN_EXCEPTION; } + if (notmuch->atomic_dirty) { + ++notmuch->revision; + notmuch->atomic_dirty = FALSE; + } + DONE: notmuch->atomic_nesting--; return NOTMUCH_STATUS_SUCCESS; } +unsigned long +notmuch_database_get_revision (notmuch_database_t *notmuch, + const char **uuid) +{ + if (uuid) + *uuid = notmuch->uuid; + return notmuch->revision; +} + /* We allow the user to use arbitrarily long paths for directories. But * we have a term-length limit. So if we exceed that, we'll use the * SHA-1 of the path for the database term. @@ -2576,7 +2667,7 @@ notmuch_database_get_all_tags (notmuch_database_t *db) } const char * -notmuch_database_status_string (notmuch_database_t *notmuch) +notmuch_database_status_string (const notmuch_database_t *notmuch) { return notmuch->status_string; } diff --git a/lib/directory.cc b/lib/directory.cc index b836ea28..78637b3a 100644 --- a/lib/directory.cc +++ b/lib/directory.cc @@ -281,6 +281,31 @@ notmuch_directory_get_child_directories (notmuch_directory_t *directory) return child_directories; } +notmuch_status_t +notmuch_directory_delete (notmuch_directory_t *directory) +{ + notmuch_status_t status; + Xapian::WritableDatabase *db; + + status = _notmuch_database_ensure_writable (directory->notmuch); + if (status) + return status; + + try { + db = static_cast <Xapian::WritableDatabase *> (directory->notmuch->xapian_db); + db->delete_document (directory->document_id); + } catch (const Xapian::Error &error) { + _notmuch_database_log (directory->notmuch, + "A Xapian exception occurred deleting directory entry: %s.\n", + error.get_msg().c_str()); + directory->notmuch->exception_reported = TRUE; + status = NOTMUCH_STATUS_XAPIAN_EXCEPTION; + } + notmuch_directory_destroy (directory); + + return NOTMUCH_STATUS_SUCCESS; +} + void notmuch_directory_destroy (notmuch_directory_t *directory) { diff --git a/lib/gen-version-script.sh b/lib/gen-version-script.sh index 64a73749..84770011 100644 --- a/lib/gen-version-script.sh +++ b/lib/gen-version-script.sh @@ -1,3 +1,4 @@ +set -eu # we go through a bit of work to get the unmangled names of the # typeinfo symbols because of diff --git a/lib/message-file.c b/lib/message-file.c index 8ac96e8e..ee305202 100644 --- a/lib/message-file.c +++ b/lib/message-file.c @@ -38,27 +38,6 @@ struct _notmuch_message_file { }; static int -strcase_equal (const void *a, const void *b) -{ - return strcasecmp (a, b) == 0; -} - -static unsigned int -strcase_hash (const void *ptr) -{ - const char *s = ptr; - - /* This is the djb2 hash. */ - unsigned int hash = 5381; - while (s && *s) { - hash = ((hash << 5) + hash) + tolower (*s); - s++; - } - - return hash; -} - -static int _notmuch_message_file_destructor (notmuch_message_file_t *message) { if (message->headers) diff --git a/lib/message.cc b/lib/message.cc index 5bc7aff1..26b5e76e 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -43,6 +43,9 @@ struct visible _notmuch_message { * if each flag has been initialized. */ unsigned long lazy_flags; + /* Message document modified since last sync */ + notmuch_bool_t modified; + Xapian::Document doc; Xapian::termcount termpos; }; @@ -539,6 +542,7 @@ _notmuch_message_remove_terms (notmuch_message_t *message, const char *prefix) try { message->doc.remove_term ((*i)); + message->modified = TRUE; } catch (const Xapian::InvalidArgumentError) { /* Ignore failure to remove non-existent term. */ } @@ -793,6 +797,7 @@ void _notmuch_message_clear_data (notmuch_message_t *message) { message->doc.set_data (""); + message->modified = TRUE; } static void @@ -990,6 +995,17 @@ _notmuch_message_set_header_values (notmuch_message_t *message, Xapian::sortable_serialise (time_value)); message->doc.add_value (NOTMUCH_VALUE_FROM, from); message->doc.add_value (NOTMUCH_VALUE_SUBJECT, subject); + 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. */ @@ -1001,8 +1017,24 @@ _notmuch_message_sync (notmuch_message_t *message) if (message->notmuch->mode == NOTMUCH_DATABASE_MODE_READ_ONLY) return; + 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 <Xapian::WritableDatabase *> (message->notmuch->xapian_db); db->replace_document (message->doc_id, message->doc); + message->modified = FALSE; } /* Delete a message document from the database. */ @@ -1077,6 +1109,7 @@ _notmuch_message_add_term (notmuch_message_t *message, return NOTMUCH_PRIVATE_STATUS_TERM_TOO_LONG; message->doc.add_term (term, 0); + message->modified = TRUE; talloc_free (term); @@ -1145,6 +1178,7 @@ _notmuch_message_remove_term (notmuch_message_t *message, try { message->doc.remove_term (term); + message->modified = TRUE; } catch (const Xapian::InvalidArgumentError) { /* We'll let the philosopher's try to wrestle with the * question of whether failing to remove that which was not diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index cc9ce12c..5dd4770e 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -50,6 +50,7 @@ NOTMUCH_BEGIN_DECLS #include "xutil.h" #include "error_util.h" +#include "string-util.h" #pragma GCC visibility push(hidden) @@ -107,7 +108,8 @@ typedef enum { NOTMUCH_VALUE_TIMESTAMP = 0, NOTMUCH_VALUE_MESSAGE_ID, NOTMUCH_VALUE_FROM, - NOTMUCH_VALUE_SUBJECT + NOTMUCH_VALUE_SUBJECT, + NOTMUCH_VALUE_LAST_MOD, } notmuch_value_t; /* Xapian (with flint backend) complains if we provide a term longer @@ -194,6 +196,9 @@ void _notmuch_database_log (notmuch_database_t *notmuch, const char *format, ...); +unsigned long +_notmuch_database_new_revision (notmuch_database_t *notmuch); + const char * _notmuch_database_relative_path (notmuch_database_t *notmuch, const char *path); @@ -305,6 +310,10 @@ _notmuch_message_set_header_values (notmuch_message_t *message, const char *date, const char *from, const char *subject); + +void +_notmuch_message_upgrade_last_mod (notmuch_message_t *message); + void _notmuch_message_sync (notmuch_message_t *message); diff --git a/lib/notmuch.h b/lib/notmuch.h index 20c4e019..85b56bf1 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -56,9 +56,11 @@ NOTMUCH_BEGIN_DECLS * version in Makefile.local. */ #define LIBNOTMUCH_MAJOR_VERSION 4 -#define LIBNOTMUCH_MINOR_VERSION 2 +#define LIBNOTMUCH_MINOR_VERSION 3 #define LIBNOTMUCH_MICRO_VERSION 0 +#define NOTMUCH_DEPRECATED(major,minor) \ + __attribute__ ((deprecated ("function deprecated as of libnotmuch " #major "." #minor))) #endif /* __DOXYGEN__ */ /** @@ -164,6 +166,11 @@ typedef enum _notmuch_status { */ NOTMUCH_STATUS_UPGRADE_REQUIRED, /** + * There is a problem with the proposed path, e.g. a relative path + * passed to a function expecting an absolute path. + */ + NOTMUCH_STATUS_PATH_ERROR, + /** * Not an actual status value. Just a way to find out how many * valid status values there are. */ @@ -306,7 +313,7 @@ notmuch_database_open_verbose (const char *path, * */ const char * -notmuch_database_status_string (notmuch_database_t *notmuch); +notmuch_database_status_string (const notmuch_database_t *notmuch); /** * Commit changes and close the given notmuch database. @@ -461,6 +468,24 @@ notmuch_status_t notmuch_database_end_atomic (notmuch_database_t *notmuch); /** + * Return the committed database revision and UUID. + * + * The database revision number increases monotonically with each + * commit to the database. Hence, all messages and message changes + * committed to the database (that is, visible to readers) have a last + * modification revision <= the committed database revision. Any + * messages committed in the future will be assigned a modification + * revision > the committed database revision. + * + * The UUID is a NUL-terminated opaque string that uniquely identifies + * this database. Two revision numbers are only comparable if they + * have the same database UUID. + */ +unsigned long +notmuch_database_get_revision (notmuch_database_t *notmuch, + const char **uuid); + +/** * Retrieve a directory object from the database for 'path'. * * Here, 'path' should be a path relative to the path of 'database' @@ -703,7 +728,13 @@ typedef enum { * Return the query_string of this query. See notmuch_query_create. */ const char * -notmuch_query_get_query_string (notmuch_query_t *query); +notmuch_query_get_query_string (const notmuch_query_t *query); + +/** + * Return the notmuch database of this query. See notmuch_query_create. + */ +notmuch_database_t * +notmuch_query_get_database (const notmuch_query_t *query); /** * Exclude values for notmuch_query_set_omit_excluded. The strange @@ -760,7 +791,7 @@ notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort); * notmuch_query_set_sort. */ notmuch_sort_t -notmuch_query_get_sort (notmuch_query_t *query); +notmuch_query_get_sort (const notmuch_query_t *query); /** * Add a tag that will be excluded from the query results by default. @@ -807,20 +838,26 @@ notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag); * notmuch_threads_destroy function, but there's no good reason * to call it if the query is about to be destroyed). * - * If a Xapian exception occurs this function will return NULL. - * For better error reporting, use the _st variant. - */ -notmuch_threads_t * -notmuch_query_search_threads (notmuch_query_t *query); - -/** - * Like notmuch_query_search_threads, but with a status return. + * @since libnotmuch 4.2 (notmuch 0.20) */ notmuch_status_t notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t **out); /** + * Like notmuch_query_search_threads_st, but without a status return. + * + * If a Xapian exception occurs this function will return NULL. + * + * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please + * use notmuch_query_search_threads_st instead. + * + */ +NOTMUCH_DEPRECATED(4,3) +notmuch_threads_t * +notmuch_query_search_threads (notmuch_query_t *query); + +/** * Execute a query for messages, returning a notmuch_messages_t object * which can be used to iterate over the results. The returned * messages object is owned by the query and as such, will only be @@ -858,17 +895,24 @@ notmuch_query_search_threads_st (notmuch_query_t *query, * reason to call it if the query is about to be destroyed). * * If a Xapian exception occurs this function will return NULL. - * For better error reporting, use the _st variant. - */ -notmuch_messages_t * -notmuch_query_search_messages (notmuch_query_t *query); - -/** - * Like notmuch_query_search_messages, but with a status return. + * + * @since libnotmuch 4.2 (notmuch 0.20) */ notmuch_status_t notmuch_query_search_messages_st (notmuch_query_t *query, notmuch_messages_t **out); +/** + * Like notmuch_query_search_messages, but without a status return. + * + * If a Xapian exception occurs this function will return NULL. + * + * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please use + * notmuch_query_search_messages_st instead. + * + */ +NOTMUCH_DEPRECATED(4,3) +notmuch_messages_t * +notmuch_query_search_messages (notmuch_query_t *query); /** * Destroy a notmuch_query_t along with any associated resources. @@ -942,10 +986,28 @@ notmuch_threads_destroy (notmuch_threads_t *threads); * This function performs a search and returns the number of matching * messages. * - * If a Xapian exception occurs, this function may return 0 (after - * printing a message). + * @returns + * + * NOTMUCH_STATUS_SUCCESS: query completed successfully. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The + * value of *count is not defined. + * + * @since libnotmuch 4.3 (notmuch 0.21) + */ +notmuch_status_t +notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count); + +/** + * like notmuch_query_count_messages_st, but without a status return. + * + * May return 0 in the case of errors. + * + * @deprecated Deprecated since libnotmuch 4.3 (notmuch 0.21). Please + * use notmuch_query_count_messages_st instead. */ -unsigned +NOTMUCH_DEPRECATED(4,3) +unsigned int notmuch_query_count_messages (notmuch_query_t *query); /** @@ -956,11 +1018,33 @@ notmuch_query_count_messages (notmuch_query_t *query); * search. * * Note that this is a significantly heavier operation than - * notmuch_query_count_messages(). + * notmuch_query_count_messages{_st}(). * - * If an error occurs, this function may return 0. + * @returns + * + * NOTMUCH_STATUS_OUT_OF_MEMORY: Memory allocation failed. The value + * of *count is not defined + + * NOTMUCH_STATUS_SUCCESS: query completed successfully. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The + * value of *count is not defined. + * + * @since libnotmuch 4.3 (notmuch 0.21) + */ +notmuch_status_t +notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count); + +/** + * like notmuch_query_count_threads, but without a status return. + * + * May return 0 in case of errors. + * + * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please + * use notmuch_query_count_threads_st instead. */ -unsigned +NOTMUCH_DEPRECATED(4,3) +unsigned int notmuch_query_count_threads (notmuch_query_t *query); /** @@ -1678,6 +1762,16 @@ notmuch_filenames_t * notmuch_directory_get_child_directories (notmuch_directory_t *directory); /** + * Delete directory document from the database, and destroy the + * notmuch_directory_t object. Assumes any child directories and files + * have been deleted by the caller. + * + * @since libnotmuch 4.3 (notmuch 0.21) + */ +notmuch_status_t +notmuch_directory_delete (notmuch_directory_t *directory); + +/** * Destroy a notmuch_directory_t object. */ void diff --git a/lib/parse-time-vrp.cc b/lib/parse-time-vrp.cc index 33f07db3..03804cf5 100644 --- a/lib/parse-time-vrp.cc +++ b/lib/parse-time-vrp.cc @@ -31,6 +31,7 @@ Xapian::valueno ParseTimeValueRangeProcessor::operator() (std::string &begin, std::string &end) { time_t t, now; + std::string b; /* Require date: prefix in start of the range... */ if (STRNCMP_LITERAL (begin.c_str (), PREFIX)) @@ -38,6 +39,7 @@ ParseTimeValueRangeProcessor::operator() (std::string &begin, std::string &end) /* ...and remove it. */ begin.erase (0, sizeof (PREFIX) - 1); + b = begin; /* Use the same 'now' for begin and end. */ if (time (&now) == (time_t) -1) @@ -51,6 +53,9 @@ ParseTimeValueRangeProcessor::operator() (std::string &begin, std::string &end) } if (!end.empty ()) { + if (end == "!" && ! b.empty ()) + end = b; + if (parse_time_string (end.c_str (), &t, &now, PARSE_TIME_ROUND_UP_INCLUSIVE)) return Xapian::BAD_VALUENO; diff --git a/lib/query.cc b/lib/query.cc index 9cedb6a8..e627bfc2 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -98,7 +98,7 @@ notmuch_query_create (notmuch_database_t *notmuch, } const char * -notmuch_query_get_query_string (notmuch_query_t *query) +notmuch_query_get_query_string (const notmuch_query_t *query) { return query->query_string; } @@ -117,7 +117,7 @@ notmuch_query_set_sort (notmuch_query_t *query, notmuch_sort_t sort) } notmuch_sort_t -notmuch_query_get_sort (notmuch_query_t *query) +notmuch_query_get_sort (const notmuch_query_t *query) { return query->sort; } @@ -541,9 +541,19 @@ notmuch_threads_destroy (notmuch_threads_t *threads) talloc_free (threads); } -unsigned +unsigned int notmuch_query_count_messages (notmuch_query_t *query) { + notmuch_status_t status; + unsigned int count; + + status = notmuch_query_count_messages_st (query, &count); + return status ? 0 : count; +} + +notmuch_status_t +notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out) +{ notmuch_database_t *notmuch = query->notmuch; const char *query_string = query->query_string; Xapian::doccount count = 0; @@ -605,31 +615,44 @@ notmuch_query_count_messages (notmuch_query_t *query) "Query string was: %s\n", error.get_msg().c_str(), query->query_string); - + return NOTMUCH_STATUS_XAPIAN_EXCEPTION; } - return count; + *count_out = count; + return NOTMUCH_STATUS_SUCCESS; } unsigned notmuch_query_count_threads (notmuch_query_t *query) { + notmuch_status_t status; + unsigned int count; + + status = notmuch_query_count_threads_st (query, &count); + return status ? 0 : count; +} + +notmuch_status_t +notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count) +{ notmuch_messages_t *messages; GHashTable *hash; - unsigned int count; notmuch_sort_t sort; + notmuch_status_t ret = NOTMUCH_STATUS_SUCCESS; sort = query->sort; query->sort = NOTMUCH_SORT_UNSORTED; - messages = notmuch_query_search_messages (query); + ret = notmuch_query_search_messages_st (query, &messages); + if (ret) + return ret; query->sort = sort; if (messages == NULL) - return 0; + return NOTMUCH_STATUS_XAPIAN_EXCEPTION; hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); if (hash == NULL) { talloc_free (messages); - return 0; + return NOTMUCH_STATUS_OUT_OF_MEMORY; } while (notmuch_messages_valid (messages)) { @@ -638,7 +661,7 @@ notmuch_query_count_threads (notmuch_query_t *query) char *thread_id_copy = talloc_strdup (messages, thread_id); if (unlikely (thread_id_copy == NULL)) { notmuch_message_destroy (message); - count = 0; + ret = NOTMUCH_STATUS_OUT_OF_MEMORY; goto DONE; } g_hash_table_insert (hash, thread_id_copy, NULL); @@ -646,11 +669,17 @@ notmuch_query_count_threads (notmuch_query_t *query) notmuch_messages_move_to_next (messages); } - count = g_hash_table_size (hash); + *count = g_hash_table_size (hash); DONE: g_hash_table_unref (hash); talloc_free (messages); - return count; + return ret; +} + +notmuch_database_t * +notmuch_query_get_database (const notmuch_query_t *query) +{ + return query->notmuch; } diff --git a/lib/thread.cc b/lib/thread.cc index 9847cf8b..0c937d76 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -447,6 +447,7 @@ _notmuch_thread_create (void *ctx, notmuch_messages_t *messages; notmuch_message_t *message; + notmuch_status_t status; seed_message = _notmuch_message_create (local, notmuch, seed_doc_id, NULL); if (! seed_message) @@ -504,7 +505,11 @@ _notmuch_thread_create (void *ctx, * oldest or newest subject is desired. */ notmuch_query_set_sort (thread_id_query, NOTMUCH_SORT_OLDEST_FIRST); - for (messages = notmuch_query_search_messages (thread_id_query); + status = notmuch_query_search_messages_st (thread_id_query, &messages); + if (status) + goto DONE; + + for (; notmuch_messages_valid (messages); notmuch_messages_move_to_next (messages)) { |
