diff options
| author | David Bremner <david@tethera.net> | 2017-08-27 15:54:50 -0300 |
|---|---|---|
| committer | David Bremner <david@tethera.net> | 2017-08-27 15:54:50 -0300 |
| commit | a565f71e1c160431ff99f088bc8fc08d367603a2 (patch) | |
| tree | 2f7c33d7296e15b2c33f6ede436d412c812c3f15 /lib | |
| parent | 00f87faf4bc19e90e19b8b27c13845efb6a68152 (diff) | |
| parent | 6354745dcd6505c5f12c185a29c25a8d1c240595 (diff) | |
Merge tag 'debian/0.25-6' into debian/stretch-backports
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.local | 27 | ||||
| -rw-r--r-- | lib/database-private.h | 4 | ||||
| -rw-r--r-- | lib/database.cc | 102 | ||||
| -rw-r--r-- | lib/gen-version-script.sh | 29 | ||||
| -rw-r--r-- | lib/index.cc | 191 | ||||
| -rw-r--r-- | lib/message-file.c | 91 | ||||
| -rw-r--r-- | lib/message-property.cc | 2 | ||||
| -rw-r--r-- | lib/message.cc | 18 | ||||
| -rw-r--r-- | lib/notmuch-private.h | 16 | ||||
| -rw-r--r-- | lib/notmuch.h | 112 | ||||
| -rw-r--r-- | lib/notmuch.sym | 7 | ||||
| -rw-r--r-- | lib/query.cc | 78 | ||||
| -rw-r--r-- | lib/regexp-fields.cc | 68 | ||||
| -rw-r--r-- | lib/regexp-fields.h | 4 | ||||
| -rw-r--r-- | lib/thread.cc | 4 |
15 files changed, 421 insertions, 332 deletions
diff --git a/lib/Makefile.local b/lib/Makefile.local index cd92fc79..bf6e0649 100644 --- a/lib/Makefile.local +++ b/lib/Makefile.local @@ -1,5 +1,12 @@ # -*- makefile -*- +dir := lib + +# The (often-reused) $dir works fine within targets/prerequisites, +# but cannot be used reliably within commands, so copy its value to a +# variable that is not reused. +lib := $(dir) + ifeq ($(PLATFORM),MACOSX) LIBRARY_SUFFIX = dylib # On OS X, library version numbers go before suffix. @@ -12,7 +19,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) $(NO_UNDEFINED_LDFLAGS) +LIBRARY_LINK_FLAG = -shared -Wl,--version-script=$(lib)/notmuch.sym,-soname=$(SONAME) $(NO_UNDEFINED_LDFLAGS) ifeq ($(PLATFORM),OPENBSD) LIBRARY_LINK_FLAG += -lc endif @@ -23,13 +30,8 @@ endif endif endif -dir := lib -extra_cflags += -I$(srcdir)/$(dir) -fPIC - -# The (often-reused) $dir works fine within targets/prerequisites, -# but cannot be used reliably within commands, so copy its value to a -# variable that is not reused. -lib := $(dir) +extra_cflags += -I$(srcdir)/$(dir) -fPIC -fvisibility=hidden +extra_cxxflags += -fvisibility-inlines-hidden libnotmuch_c_srcs = \ $(notmuch_compat_srcs) \ @@ -60,11 +62,8 @@ libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o) $(dir)/libnotmuch.a: $(libnotmuch_modules) $(call quiet,AR) rcs $@ $^ -$(dir)/$(LIBNAME): $(libnotmuch_modules) notmuch.sym util/libutil.a parse-time-string/libparse-time-string.a - $(call quiet,CXX $(CXXFLAGS)) $(libnotmuch_modules) $(FINAL_LIBNOTMUCH_LDFLAGS) $(LIBRARY_LINK_FLAG) -o $@ util/libutil.a parse-time-string/libparse-time-string.a - -notmuch.sym: $(srcdir)/$(dir)/notmuch.h $(libnotmuch_modules) - sh $(srcdir)/$(lib)/gen-version-script.sh $< $(libnotmuch_modules) > $@ +$(dir)/$(LIBNAME): $(libnotmuch_modules) util/libnotmuch_util.a parse-time-string/libparse-time-string.a + $(call quiet,CXX $(CXXFLAGS)) $(libnotmuch_modules) $(FINAL_LIBNOTMUCH_LDFLAGS) $(LIBRARY_LINK_FLAG) -o $@ util/libnotmuch_util.a parse-time-string/libparse-time-string.a $(dir)/$(SONAME): $(dir)/$(LIBNAME) ln -sf $(LIBNAME) $@ @@ -85,5 +84,5 @@ install-$(dir): $(dir)/$(LIBNAME) SRCS := $(SRCS) $(libnotmuch_c_srcs) $(libnotmuch_cxx_srcs) CLEAN += $(libnotmuch_modules) $(dir)/$(SONAME) $(dir)/$(LINKER_NAME) -CLEAN += $(dir)/$(LIBNAME) $(dir)/libnotmuch.a notmuch.sym +CLEAN += $(dir)/$(LIBNAME) $(dir)/libnotmuch.a CLEAN += $(dir)/notmuch.h.gch diff --git a/lib/database-private.h b/lib/database-private.h index ab3d9691..727b1d61 100644 --- a/lib/database-private.h +++ b/lib/database-private.h @@ -38,8 +38,6 @@ #include <xapian.h> -#pragma GCC visibility push(hidden) - /* Bit masks for _notmuch_database::features. Features are named, * independent aspects of the database schema. * @@ -248,6 +246,4 @@ _notmuch_database_get_terms_with_prefix (void *ctx, Xapian::TermIterator &i, Xapian::TermIterator &end, const char *prefix); -#pragma GCC visibility pop - #endif diff --git a/lib/database.cc b/lib/database.cc index b7fc53ee..5b13f541 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -259,11 +259,15 @@ prefix_t prefix_table[] = { { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS }, { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS }, { "thread", "G", NOTMUCH_FIELD_EXTERNAL }, - { "tag", "K", NOTMUCH_FIELD_EXTERNAL }, - { "is", "K", NOTMUCH_FIELD_EXTERNAL }, + { "tag", "K", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "is", "K", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, { "id", "Q", NOTMUCH_FIELD_EXTERNAL }, - { "mid", "Q", NOTMUCH_FIELD_EXTERNAL }, - { "path", "P", NOTMUCH_FIELD_EXTERNAL }, + { "mid", "Q", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, + { "path", "P", NOTMUCH_FIELD_EXTERNAL| + NOTMUCH_FIELD_PROCESSOR }, { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL }, /* * Unconditionally add ':' to reduce potential ambiguity with @@ -271,7 +275,8 @@ prefix_t prefix_table[] = { * letters. See Xapian document termprefixes.html for related * discussion. */ - { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL }, + { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL | + NOTMUCH_FIELD_PROCESSOR }, #if HAVE_XAPIAN_FIELD_PROCESSOR { "date", NULL, NOTMUCH_FIELD_EXTERNAL | NOTMUCH_FIELD_PROCESSOR }, @@ -313,7 +318,8 @@ _setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch) else if (STRNCMP_LITERAL(prefix->name, "query") == 0) fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release (); else - fp = (new RegexpFieldProcessor (prefix->name, *notmuch->query_parser, notmuch))->release (); + fp = (new RegexpFieldProcessor (prefix->name, prefix->flags, + *notmuch->query_parser, notmuch))->release (); /* we treat all field-processor fields as boolean in order to get the raw input */ notmuch->query_parser->add_boolean_prefix (prefix->name, fp); @@ -1493,7 +1499,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, query = notmuch_query_create (notmuch, ""); unsigned msg_count; - status = notmuch_query_count_messages_st (query, &msg_count); + status = notmuch_query_count_messages (query, &msg_count); if (status) goto DONE; @@ -1531,7 +1537,7 @@ notmuch_database_upgrade (notmuch_database_t *notmuch, query = notmuch_query_create (notmuch, ""); - status = notmuch_query_search_messages_st (query, &messages); + status = notmuch_query_search_messages (query, &messages); if (status) goto DONE; for (; @@ -2493,53 +2499,53 @@ notmuch_database_add_message (notmuch_database_t *notmuch, if (ret) goto DONE; - try { - /* Before we do any real work, (especially before doing a - * potential SHA-1 computation on the entire file's contents), - * let's make sure that what we're looking at looks like an - * actual email message. - */ - from = _notmuch_message_file_get_header (message_file, "from"); - subject = _notmuch_message_file_get_header (message_file, "subject"); - to = _notmuch_message_file_get_header (message_file, "to"); - - if ((from == NULL || *from == '\0') && - (subject == NULL || *subject == '\0') && - (to == NULL || *to == '\0')) - { - ret = NOTMUCH_STATUS_FILE_NOT_EMAIL; - goto DONE; - } - - /* Now that we're sure it's mail, the first order of business - * is to find a message ID (or else create one ourselves). */ + /* Before we do any real work, (especially before doing a + * potential SHA-1 computation on the entire file's contents), + * let's make sure that what we're looking at looks like an + * actual email message. + */ + from = _notmuch_message_file_get_header (message_file, "from"); + subject = _notmuch_message_file_get_header (message_file, "subject"); + to = _notmuch_message_file_get_header (message_file, "to"); - header = _notmuch_message_file_get_header (message_file, "message-id"); - if (header && *header != '\0') { - message_id = _parse_message_id (message_file, header, NULL); + if ((from == NULL || *from == '\0') && + (subject == NULL || *subject == '\0') && + (to == NULL || *to == '\0')) { + ret = NOTMUCH_STATUS_FILE_NOT_EMAIL; + goto DONE; + } - /* So the header value isn't RFC-compliant, but it's - * better than no message-id at all. */ - if (message_id == NULL) - message_id = talloc_strdup (message_file, header); - } + /* Now that we're sure it's mail, the first order of business + * is to find a message ID (or else create one ourselves). + */ + header = _notmuch_message_file_get_header (message_file, "message-id"); + if (header && *header != '\0') { + message_id = _parse_message_id (message_file, header, NULL); - if (message_id == NULL ) { - /* No message-id at all, let's generate one by taking a - * hash over the file's contents. */ - char *sha1 = _notmuch_sha1_of_file (filename); + /* So the header value isn't RFC-compliant, but it's + * better than no message-id at all. + */ + if (message_id == NULL) + message_id = talloc_strdup (message_file, header); + } - /* If that failed too, something is really wrong. Give up. */ - if (sha1 == NULL) { - ret = NOTMUCH_STATUS_FILE_ERROR; - goto DONE; - } + if (message_id == NULL ) { + /* No message-id at all, let's generate one by taking a + * hash over the file's contents. + */ + char *sha1 = _notmuch_sha1_of_file (filename); - message_id = talloc_asprintf (message_file, - "notmuch-sha1-%s", sha1); - free (sha1); + /* If that failed too, something is really wrong. Give up. */ + if (sha1 == NULL) { + ret = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; } + message_id = talloc_asprintf (message_file, "notmuch-sha1-%s", sha1); + free (sha1); + } + + try { /* Now that we have a message ID, we get a message object, * (which may or may not reference an existing document in the * database). */ diff --git a/lib/gen-version-script.sh b/lib/gen-version-script.sh deleted file mode 100644 index 5621f2a9..00000000 --- a/lib/gen-version-script.sh +++ /dev/null @@ -1,29 +0,0 @@ -set -eu - -# we go through a bit of work to get the unmangled names of the -# typeinfo symbols because of -# https://sourceware.org/bugzilla/show_bug.cgi?id=10326 - -if [ $# -lt 2 ]; then - echo Usage: $0 header obj1 obj2 obj3 - exit 1; -fi - -HEADER=$1 -shift - -printf '{\nglobal:\n' -nm $* | awk '$1 ~ "^[0-9a-fA-F][0-9a-fA-F]*$" && $3 ~ "Xapian.*Error" {print $3}' | sort | uniq | \ -while read sym; do - demangled=$(c++filt $sym) - case $demangled in - typeinfo*) - printf "\t$sym;\n" - ;; - *) - ;; - esac -done -nm $* | awk '$1 ~ "^[0-9a-fA-F][0-9a-fA-F]*$" && $2 == "T" && $3 ~ "^(getline|getdelim|canonicalize_file_name)$" {print $3 ";"}' -sed -n 's/^[[:space:]]*\(notmuch_[a-z_]*\)[[:space:]]*(.*/ \1;/p' $HEADER -printf "local: *;\n};\n" diff --git a/lib/index.cc b/lib/index.cc index 8c145540..10420d84 100644 --- a/lib/index.cc +++ b/lib/index.cc @@ -24,13 +24,74 @@ #include <xapian.h> + +typedef struct { + int state; + int a; + int b; + int next_if_match; + int next_if_not_match; +} scanner_state_t; + +/* Simple, linear state-transition diagram for the uuencode filter. + * + * If the character being processed is within the range of [a, b] + * for the current state then we transition next_if_match + * state. If not, we transition to the next_if_not_match state. + * + * The final two states are special in that they are the states in + * which we discard data. */ +static const int first_uuencode_skipping_state = 11; +static const scanner_state_t uuencode_states[] = { + {0, 'b', 'b', 1, 0}, + {1, 'e', 'e', 2, 0}, + {2, 'g', 'g', 3, 0}, + {3, 'i', 'i', 4, 0}, + {4, 'n', 'n', 5, 0}, + {5, ' ', ' ', 6, 0}, + {6, '0', '7', 7, 0}, + {7, '0', '7', 8, 0}, + {8, '0', '7', 9, 0}, + {9, ' ', ' ', 10, 0}, + {10, '\n', '\n', 11, 10}, + {11, 'M', 'M', 12, 0}, + {12, ' ', '`', 12, 11} +}; + +/* The following table is intended to implement this DFA (in 'dot' + format). Note that 2 and 3 are "hidden" states used to step through + the possible out edges of state 1. + +digraph html_filter { + 0 -> 1 [label="<"]; + 0 -> 0; + 1 -> 4 [label="'"]; + 1 -> 5 [label="\""]; + 1 -> 0 [label=">"]; + 1 -> 1; + 4 -> 1 [label="'"]; + 4 -> 4; + 5 -> 1 [label="\""]; + 5 -> 5; +} +*/ +static const int first_html_skipping_state = 1; +static const scanner_state_t html_states[] = { + {0, '<', '<', 1, 0}, + {1, '\'', '\'', 4, 2}, /* scanning for quote or > */ + {1, '"', '"', 5, 3}, + {1, '>', '>', 0, 1}, + {4, '\'', '\'', 1, 4}, /* inside single quotes */ + {5, '"', '"', 1, 5}, /* inside double quotes */ +}; + /* Oh, how I wish that gobject didn't require so much noisy boilerplate! * (Though I have at least eliminated some of the stock set...) */ -typedef struct _NotmuchFilterDiscardUuencode NotmuchFilterDiscardUuencode; -typedef struct _NotmuchFilterDiscardUuencodeClass NotmuchFilterDiscardUuencodeClass; +typedef struct _NotmuchFilterDiscardNonTerm NotmuchFilterDiscardNonTerm; +typedef struct _NotmuchFilterDiscardNonTermClass NotmuchFilterDiscardNonTermClass; /** - * NotmuchFilterDiscardUuencode: + * NotmuchFilterDiscardNonTerm: * * @parent_object: parent #GMimeFilter * @encode: encoding vs decoding @@ -54,18 +115,21 @@ typedef struct _NotmuchFilterDiscardUuencodeClass NotmuchFilterDiscardUuencodeCl * final line of encoded data (the line not starting with M) will be * indexed. **/ -struct _NotmuchFilterDiscardUuencode { +struct _NotmuchFilterDiscardNonTerm { GMimeFilter parent_object; + GMimeContentType *content_type; int state; + int first_skipping_state; + const scanner_state_t *states; }; -struct _NotmuchFilterDiscardUuencodeClass { +struct _NotmuchFilterDiscardNonTermClass { GMimeFilterClass parent_class; }; -static GMimeFilter *notmuch_filter_discard_uuencode_new (void); +static GMimeFilter *notmuch_filter_discard_non_term_new (GMimeContentType *content); -static void notmuch_filter_discard_uuencode_finalize (GObject *object); +static void notmuch_filter_discard_non_term_finalize (GObject *object); static GMimeFilter *filter_copy (GMimeFilter *filter); static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace, @@ -78,14 +142,14 @@ static void filter_reset (GMimeFilter *filter); static GMimeFilterClass *parent_class = NULL; static void -notmuch_filter_discard_uuencode_class_init (NotmuchFilterDiscardUuencodeClass *klass) +notmuch_filter_discard_non_term_class_init (NotmuchFilterDiscardNonTermClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass); parent_class = (GMimeFilterClass *) g_type_class_ref (GMIME_TYPE_FILTER); - object_class->finalize = notmuch_filter_discard_uuencode_finalize; + object_class->finalize = notmuch_filter_discard_non_term_finalize; filter_class->copy = filter_copy; filter_class->filter = filter_filter; @@ -94,7 +158,7 @@ notmuch_filter_discard_uuencode_class_init (NotmuchFilterDiscardUuencodeClass *k } static void -notmuch_filter_discard_uuencode_finalize (GObject *object) +notmuch_filter_discard_non_term_finalize (GObject *object) { G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -102,67 +166,46 @@ notmuch_filter_discard_uuencode_finalize (GObject *object) static GMimeFilter * filter_copy (GMimeFilter *gmime_filter) { - (void) gmime_filter; - return notmuch_filter_discard_uuencode_new (); + NotmuchFilterDiscardNonTerm *filter = (NotmuchFilterDiscardNonTerm *) gmime_filter; + return notmuch_filter_discard_non_term_new (filter->content_type); } static void filter_filter (GMimeFilter *gmime_filter, char *inbuf, size_t inlen, size_t prespace, char **outbuf, size_t *outlen, size_t *outprespace) { - NotmuchFilterDiscardUuencode *filter = (NotmuchFilterDiscardUuencode *) gmime_filter; + NotmuchFilterDiscardNonTerm *filter = (NotmuchFilterDiscardNonTerm *) gmime_filter; + const scanner_state_t *states = filter->states; register const char *inptr = inbuf; const char *inend = inbuf + inlen; char *outptr; (void) prespace; - /* Simple, linear state-transition diagram for our filter. - * - * If the character being processed is within the range of [a, b] - * for the current state then we transition next_if_match - * state. If not, we transition to the next_if_not_match state. - * - * The final two states are special in that they are the states in - * which we discard data. */ - static const struct { - int state; - int a; - int b; - int next_if_match; - int next_if_not_match; - } states[] = { - {0, 'b', 'b', 1, 0}, - {1, 'e', 'e', 2, 0}, - {2, 'g', 'g', 3, 0}, - {3, 'i', 'i', 4, 0}, - {4, 'n', 'n', 5, 0}, - {5, ' ', ' ', 6, 0}, - {6, '0', '7', 7, 0}, - {7, '0', '7', 8, 0}, - {8, '0', '7', 9, 0}, - {9, ' ', ' ', 10, 0}, - {10, '\n', '\n', 11, 10}, - {11, 'M', 'M', 12, 0}, - {12, ' ', '`', 12, 11} - }; int next; g_mime_filter_set_size (gmime_filter, inlen, FALSE); outptr = gmime_filter->outbuf; + next = filter->state; while (inptr < inend) { - if (*inptr >= states[filter->state].a && - *inptr <= states[filter->state].b) - { - next = states[filter->state].next_if_match; - } - else - { - next = states[filter->state].next_if_not_match; - } + /* Each state is defined by a contiguous set of rows of the + * state table marked by a common value for '.state'. The + * state numbers must be equal to the index of the first row + * in a given state; thus the loop condition here looks for a + * jump to a first row of a state, which is a real transition + * in the underlying DFA. + */ + do { + if (*inptr >= states[next].a && *inptr <= states[next].b) { + next = states[next].next_if_match; + } else { + next = states[next].next_if_not_match; + } + + } while (next != states[next].state); - if (filter->state < 11) + if (filter->state < filter->first_skipping_state) *outptr++ = *inptr; filter->state = next; @@ -185,41 +228,49 @@ filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace static void filter_reset (GMimeFilter *gmime_filter) { - NotmuchFilterDiscardUuencode *filter = (NotmuchFilterDiscardUuencode *) gmime_filter; + NotmuchFilterDiscardNonTerm *filter = (NotmuchFilterDiscardNonTerm *) gmime_filter; filter->state = 0; } /** - * notmuch_filter_discard_uuencode_new: + * notmuch_filter_discard_non_term_new: * - * Returns: a new #NotmuchFilterDiscardUuencode filter. + * Returns: a new #NotmuchFilterDiscardNonTerm filter. **/ static GMimeFilter * -notmuch_filter_discard_uuencode_new (void) +notmuch_filter_discard_non_term_new (GMimeContentType *content_type) { static GType type = 0; - NotmuchFilterDiscardUuencode *filter; + NotmuchFilterDiscardNonTerm *filter; if (!type) { static const GTypeInfo info = { - sizeof (NotmuchFilterDiscardUuencodeClass), + sizeof (NotmuchFilterDiscardNonTermClass), NULL, /* base_class_init */ NULL, /* base_class_finalize */ - (GClassInitFunc) notmuch_filter_discard_uuencode_class_init, + (GClassInitFunc) notmuch_filter_discard_non_term_class_init, NULL, /* class_finalize */ NULL, /* class_data */ - sizeof (NotmuchFilterDiscardUuencode), + sizeof (NotmuchFilterDiscardNonTerm), 0, /* n_preallocs */ NULL, /* instance_init */ NULL /* value_table */ }; - type = g_type_register_static (GMIME_TYPE_FILTER, "NotmuchFilterDiscardUuencode", &info, (GTypeFlags) 0); + type = g_type_register_static (GMIME_TYPE_FILTER, "NotmuchFilterDiscardNonTerm", &info, (GTypeFlags) 0); } - filter = (NotmuchFilterDiscardUuencode *) g_object_newv (type, 0, NULL); + filter = (NotmuchFilterDiscardNonTerm *) g_object_newv (type, 0, NULL); + filter->content_type = content_type; filter->state = 0; + if (g_mime_content_type_is_type (content_type, "text", "html")) { + filter->states = html_states; + filter->first_skipping_state = first_html_skipping_state; + } else { + filter->states = uuencode_states; + filter->first_skipping_state = first_uuencode_skipping_state; + } return (GMimeFilter *) filter; } @@ -306,7 +357,7 @@ _index_mime_part (notmuch_message_t *message, GMimeObject *part) { GMimeStream *stream, *filter; - GMimeFilter *discard_uuencode_filter; + GMimeFilter *discard_non_term_filter; GMimeDataWrapper *wrapper; GByteArray *byte_array; GMimeContentDisposition *disposition; @@ -396,10 +447,10 @@ _index_mime_part (notmuch_message_t *message, g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (stream), FALSE); filter = g_mime_stream_filter_new (stream); - discard_uuencode_filter = notmuch_filter_discard_uuencode_new (); + discard_non_term_filter = notmuch_filter_discard_non_term_new (content_type); g_mime_stream_filter_add (GMIME_STREAM_FILTER (filter), - discard_uuencode_filter); + discard_non_term_filter); charset = g_mime_object_get_content_type_parameter (part, "charset"); if (charset) { @@ -421,7 +472,7 @@ _index_mime_part (notmuch_message_t *message, g_object_unref (stream); g_object_unref (filter); - g_object_unref (discard_uuencode_filter); + g_object_unref (discard_non_term_filter); g_byte_array_append (byte_array, (guint8 *) "\0", 1); body = (char *) g_byte_array_free (byte_array, FALSE); @@ -439,7 +490,7 @@ _notmuch_message_index_file (notmuch_message_t *message, { GMimeMessage *mime_message; InternetAddressList *addresses; - const char *from, *subject; + const char *subject; notmuch_status_t status; status = _notmuch_message_file_get_mime_message (message_file, @@ -447,12 +498,10 @@ _notmuch_message_index_file (notmuch_message_t *message, if (status) return status; - from = g_mime_message_get_sender (mime_message); - - addresses = internet_address_list_parse_string (from); + addresses = g_mime_message_get_from (mime_message); if (addresses) { _index_address_list (message, "from", addresses); - g_object_unref (addresses); + g_mime_2_6_unref (addresses); } addresses = g_mime_message_get_all_recipients (mime_message); diff --git a/lib/message-file.c b/lib/message-file.c index db18b163..d7acf0d5 100644 --- a/lib/message-file.c +++ b/lib/message-file.c @@ -201,6 +201,38 @@ _notmuch_message_file_get_mime_message (notmuch_message_file_t *message, * * Return NULL on errors, empty string for non-existing headers. */ + +static char * +_extend_header (char *combined, const char *value) { + char *decoded; + + decoded = g_mime_utils_header_decode_text (value); + if (! decoded) { + if (combined) { + g_free (combined); + combined = NULL; + } + goto DONE; + } + + if (combined) { + char *tmp = g_strdup_printf ("%s %s", combined, decoded); + g_free (decoded); + g_free (combined); + if (! tmp) { + combined = NULL; + goto DONE; + } + + combined = tmp; + } else { + combined = decoded; + } + DONE: + return combined; +} + +#if (GMIME_MAJOR_VERSION < 3) static char * _notmuch_message_file_get_combined_header (notmuch_message_file_t *message, const char *header) @@ -222,37 +254,13 @@ _notmuch_message_file_get_combined_header (notmuch_message_file_t *message, do { const char *value; - char *decoded; - if (strcasecmp (g_mime_header_iter_get_name (iter), header) != 0) continue; /* Note that GMime retains ownership of value... */ value = g_mime_header_iter_get_value (iter); - /* ... while decoded needs to be freed with g_free(). */ - decoded = g_mime_utils_header_decode_text (value); - if (! decoded) { - if (combined) { - g_free (combined); - combined = NULL; - } - goto DONE; - } - - if (combined) { - char *tmp = g_strdup_printf ("%s %s", combined, decoded); - g_free (decoded); - g_free (combined); - if (! tmp) { - combined = NULL; - goto DONE; - } - - combined = tmp; - } else { - combined = decoded; - } + combined = _extend_header (combined, value); } while (g_mime_header_iter_next (iter)); /* Return empty string for non-existing headers. */ @@ -264,6 +272,39 @@ _notmuch_message_file_get_combined_header (notmuch_message_file_t *message, return combined; } +#else +static char * +_notmuch_message_file_get_combined_header (notmuch_message_file_t *message, + const char *header) +{ + char *combined = NULL; + GMimeHeaderList *headers; + + headers = g_mime_object_get_header_list (GMIME_OBJECT (message->message)); + if (! headers) + return NULL; + + + for (int i=0; i < g_mime_header_list_get_count (headers); i++) { + const char *value; + GMimeHeader *g_header = g_mime_header_list_get_header_at (headers, i); + + if (strcasecmp (g_mime_header_get_name (g_header), header) != 0) + continue; + + /* GMime retains ownership of value, we hope */ + value = g_mime_header_get_value (g_header); + + combined = _extend_header (combined, value); + } + + /* Return empty string for non-existing headers. */ + if (! combined) + combined = g_strdup (""); + + return combined; +} +#endif const char * _notmuch_message_file_get_header (notmuch_message_file_t *message, diff --git a/lib/message-property.cc b/lib/message-property.cc index 0b13cac3..f32d5550 100644 --- a/lib/message-property.cc +++ b/lib/message-property.cc @@ -51,7 +51,7 @@ _notmuch_message_modify_property (notmuch_message_t *message, const char *key, c if (key == NULL || value == NULL) return NOTMUCH_STATUS_NULL_POINTER; - if (index (key, '=')) + if (strchr (key, '=')) return NOTMUCH_STATUS_ILLEGAL_ARGUMENT; term = talloc_asprintf (message, "%s=%s", key, value); diff --git a/lib/message.cc b/lib/message.cc index 36a07a88..f78e5a9d 100644 --- a/lib/message.cc +++ b/lib/message.cc @@ -26,7 +26,7 @@ #include <gmime/gmime.h> -struct visible _notmuch_message { +struct _notmuch_message { notmuch_database_t *notmuch; Xapian::docid doc_id; int frozen; @@ -1034,10 +1034,16 @@ _notmuch_message_set_header_values (notmuch_message_t *message, /* GMime really doesn't want to see a NULL date, so protect its * sensibilities. */ - if (date == NULL || *date == '\0') + if (date == NULL || *date == '\0') { time_value = 0; - else - time_value = g_mime_utils_header_decode_date (date, NULL); + } else { + time_value = g_mime_utils_header_decode_date_unix (date); + /* + * Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=779923 + */ + if (time_value < 0) + time_value = 0; + } message->doc.add_value (NOTMUCH_VALUE_TIMESTAMP, Xapian::sortable_serialise (time_value)); @@ -1123,7 +1129,7 @@ _notmuch_message_delete (notmuch_message_t *message) query = notmuch_query_create (notmuch, query_string); if (query == NULL) return NOTMUCH_STATUS_OUT_OF_MEMORY; - status = notmuch_query_count_messages_st (query, &count); + status = notmuch_query_count_messages (query, &count); if (status) { notmuch_query_destroy (query); return status; @@ -1837,7 +1843,7 @@ _notmuch_message_ensure_property_map (notmuch_message_t *message) const char *key; char *value; - value = index(node->string, '='); + value = strchr(node->string, '='); if (!value) INTERNAL_ERROR ("malformed property term"); diff --git a/lib/notmuch-private.h b/lib/notmuch-private.h index 8587e86c..5dfebf5d 100644 --- a/lib/notmuch-private.h +++ b/lib/notmuch-private.h @@ -46,14 +46,12 @@ NOTMUCH_BEGIN_DECLS #include <talloc.h> -#include <gmime/gmime.h> +#include "gmime-extra.h" #include "xutil.h" #include "error_util.h" #include "string-util.h" -#pragma GCC visibility push(hidden) - #ifdef DEBUG # define DEBUG_DATABASE_SANITY 1 # define DEBUG_QUERY 1 @@ -76,12 +74,6 @@ NOTMUCH_BEGIN_DECLS #define unused(x) x __attribute__ ((unused)) -#ifdef __cplusplus -# define visible __attribute__((visibility("default"))) -#else -# define visible -#endif - /* Thanks to Andrew Tridgell's (SAMBA's) talloc for this definition of * unlikely. The talloc source code comes to us via the GNU LGPL v. 3. */ @@ -455,7 +447,7 @@ typedef struct _notmuch_message_list { * somewhere with some nasty C++ objects in it. We'll try to maintain * ignorance of that here. (See notmuch_mset_messages_t in query.cc) */ -struct visible _notmuch_messages { +struct _notmuch_messages { notmuch_bool_t is_of_list_type; notmuch_doc_id_set_t *excluded_doc_ids; notmuch_message_node_t *iterator; @@ -524,7 +516,7 @@ typedef struct _notmuch_string_node { struct _notmuch_string_node *next; } notmuch_string_node_t; -typedef struct visible _notmuch_string_list { +typedef struct _notmuch_string_list { int length; notmuch_string_node_t *head; notmuch_string_node_t **tail; @@ -621,6 +613,4 @@ _notmuch_talloc_steal (const void *new_ctx, const T *ptr) #endif #endif -#pragma GCC visibility pop - #endif diff --git a/lib/notmuch.h b/lib/notmuch.h index 16da8be9..17f0872e 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -43,6 +43,8 @@ NOTMUCH_BEGIN_DECLS #include <time.h> +#pragma GCC visibility push(default) + #ifndef FALSE #define FALSE 0 #endif @@ -55,8 +57,8 @@ NOTMUCH_BEGIN_DECLS * The library version number. This must agree with the soname * version in Makefile.local. */ -#define LIBNOTMUCH_MAJOR_VERSION 4 -#define LIBNOTMUCH_MINOR_VERSION 4 +#define LIBNOTMUCH_MAJOR_VERSION 5 +#define LIBNOTMUCH_MINOR_VERSION 0 #define LIBNOTMUCH_MICRO_VERSION 0 @@ -180,6 +182,11 @@ typedef enum _notmuch_status { */ NOTMUCH_STATUS_PATH_ERROR, /** + * The requested operation was ignored. Depending on the function, + * this may not be an actual error. + */ + NOTMUCH_STATUS_IGNORED, + /** * One of the arguments violates the preconditions for the * function, in a way not covered by a more specific argument. */ @@ -812,10 +819,20 @@ notmuch_query_get_sort (const notmuch_query_t *query); /** * Add a tag that will be excluded from the query results by default. - * This exclusion will be overridden if this tag appears explicitly in + * This exclusion will be ignored if this tag appears explicitly in * the query. + * + * @returns + * + * NOTMUCH_STATUS_SUCCESS: excluded was added successfully. + * + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. + * Most likely a problem lazily parsing the query string. + * + * NOTMUCH_STATUS_IGNORED: tag is explicitly present in the query, so + * not excluded. */ -void +notmuch_status_t notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag); /** @@ -855,24 +872,22 @@ 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). * - * @since libnotmuch 4.2 (notmuch 0.20) + * @since libnotmuch 5.0 (notmuch 0.25) */ notmuch_status_t -notmuch_query_search_threads_st (notmuch_query_t *query, - notmuch_threads_t **out); +notmuch_query_search_threads (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 alias for notmuch_query_search_threads. * - * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please - * use notmuch_query_search_threads_st instead. + * @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please + * use notmuch_query_search_threads instead. * */ -NOTMUCH_DEPRECATED(4,3) -notmuch_threads_t * -notmuch_query_search_threads (notmuch_query_t *query); +NOTMUCH_DEPRECATED(5,0) +notmuch_status_t +notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t **out); /** * Execute a query for messages, returning a notmuch_messages_t object @@ -913,23 +928,23 @@ notmuch_query_search_threads (notmuch_query_t *query); * * If a Xapian exception occurs this function will return NULL. * - * @since libnotmuch 4.2 (notmuch 0.20) + * @since libnotmuch 5 (notmuch 0.25) */ notmuch_status_t -notmuch_query_search_messages_st (notmuch_query_t *query, - notmuch_messages_t **out); +notmuch_query_search_messages (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 alias for notmuch_query_search_messages * - * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please use - * notmuch_query_search_messages_st instead. + * @deprecated Deprecated as of libnotmuch 5 (notmuch 0.25). Please use + * notmuch_query_search_messages instead. * */ -NOTMUCH_DEPRECATED(4,3) -notmuch_messages_t * -notmuch_query_search_messages (notmuch_query_t *query); + +NOTMUCH_DEPRECATED(5,0) +notmuch_status_t +notmuch_query_search_messages_st (notmuch_query_t *query, + notmuch_messages_t **out); /** * Destroy a notmuch_query_t along with any associated resources. @@ -1010,22 +1025,21 @@ notmuch_threads_destroy (notmuch_threads_t *threads); * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The * value of *count is not defined. * - * @since libnotmuch 4.3 (notmuch 0.21) + * @since libnotmuch 5 (notmuch 0.25) */ notmuch_status_t -notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count); +notmuch_query_count_messages (notmuch_query_t *query, unsigned int *count); /** - * like notmuch_query_count_messages_st, but without a status return. + * Deprecated alias for notmuch_query_count_messages * - * 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. + * @deprecated Deprecated since libnotmuch 5.0 (notmuch 0.25). Please + * use notmuch_query_count_messages instead. */ -NOTMUCH_DEPRECATED(4,3) -unsigned int -notmuch_query_count_messages (notmuch_query_t *query); +NOTMUCH_DEPRECATED(5,0) +notmuch_status_t +notmuch_query_count_messages_st (notmuch_query_t *query, unsigned int *count); /** * Return the number of threads matching a search. @@ -1047,22 +1061,20 @@ notmuch_query_count_messages (notmuch_query_t *query); * NOTMUCH_STATUS_XAPIAN_EXCEPTION: a Xapian exception occured. The * value of *count is not defined. * - * @since libnotmuch 4.3 (notmuch 0.21) + * @since libnotmuch 5 (notmuch 0.25) */ notmuch_status_t -notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count); +notmuch_query_count_threads (notmuch_query_t *query, unsigned *count); /** - * like notmuch_query_count_threads, but without a status return. - * - * May return 0 in case of errors. + * Deprecated alias for notmuch_query_count_threads * - * @deprecated Deprecated as of libnotmuch 4.3 (notmuch 0.21). Please + * @deprecated Deprecated as of libnotmuch 5.0 (notmuch 0.25). Please * use notmuch_query_count_threads_st instead. */ -NOTMUCH_DEPRECATED(4,3) -unsigned int -notmuch_query_count_threads (notmuch_query_t *query); +NOTMUCH_DEPRECATED(5,0) +notmuch_status_t +notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count); /** * Get the thread ID of 'thread'. @@ -1556,11 +1568,11 @@ notmuch_message_maildir_flags_to_tags (notmuch_message_t *message); * its filename ends with the sequence ":2," followed by zero or more * of the following single-character flags (in ASCII order): * - * 'D' iff the message has the "draft" tag - * 'F' iff the message has the "flagged" tag - * 'P' iff the message has the "passed" tag - * 'R' iff the message has the "replied" tag - * 'S' iff the message does not have the "unread" tag + * * flag 'D' iff the message has the "draft" tag + * * flag 'F' iff the message has the "flagged" tag + * * flag 'P' iff the message has the "passed" tag + * * flag 'R' iff the message has the "replied" tag + * * flag 'S' iff the message does not have the "unread" tag * * Any existing flags unmentioned in the list above will be preserved * in the renaming. @@ -2110,6 +2122,8 @@ notmuch_bool_t notmuch_built_with (const char *name); /* @} */ +#pragma GCC visibility pop + NOTMUCH_END_DECLS #endif diff --git a/lib/notmuch.sym b/lib/notmuch.sym new file mode 100644 index 00000000..7d0c0af4 --- /dev/null +++ b/lib/notmuch.sym @@ -0,0 +1,7 @@ +{ +global: + _ZTI*; + _ZTS*; + notmuch_*; +local: *; +}; diff --git a/lib/query.cc b/lib/query.cc index 59e9141a..9c6ecc8d 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -49,7 +49,7 @@ struct _notmuch_doc_id_set { #define DOCIDSET_WORD(bit) ((bit) / CHAR_BIT) #define DOCIDSET_BIT(bit) ((bit) % CHAR_BIT) -struct visible _notmuch_threads { +struct _notmuch_threads { notmuch_query_t *query; /* The ordered list of doc ids matched by the query. */ @@ -177,29 +177,22 @@ notmuch_query_get_sort (const notmuch_query_t *query) return query->sort; } -void +notmuch_status_t notmuch_query_add_tag_exclude (notmuch_query_t *query, const char *tag) { notmuch_status_t status; char *term; status = _notmuch_query_ensure_parsed (query); - /* The following is not ideal error handling, but to avoid - * breaking the ABI, we can live with it for now. In particular at - * least in the notmuch CLI, any syntax error in the query is - * caught in a later call to _notmuch_query_ensure_parsed with a - * better error path. - * - * TODO: add status return to this function. - */ if (status) - return; + return status; term = talloc_asprintf (query, "%s%s", _find_prefix ("tag"), tag); if (query->terms.count(term) != 0) - return; /* XXX report ignoring exclude? */ + return NOTMUCH_STATUS_IGNORED; _notmuch_string_list_append (query->exclude_terms, term); + return NOTMUCH_STATUS_SUCCESS; } /* We end up having to call the destructors explicitly because we had @@ -233,20 +226,16 @@ _notmuch_exclude_tags (notmuch_query_t *query) return exclude_query; } -notmuch_messages_t * -notmuch_query_search_messages (notmuch_query_t *query) + +notmuch_status_t +notmuch_query_search_messages_st (notmuch_query_t *query, + notmuch_messages_t **out) { - notmuch_status_t status; - notmuch_messages_t *messages; - status = notmuch_query_search_messages_st (query, &messages); - if (status) - return NULL; - else - return messages; + return notmuch_query_search_messages (query, out); } notmuch_status_t -notmuch_query_search_messages_st (notmuch_query_t *query, +notmuch_query_search_messages (notmuch_query_t *query, notmuch_messages_t **out) { return _notmuch_query_search_documents (query, "mail", out); @@ -497,22 +486,15 @@ _notmuch_threads_destructor (notmuch_threads_t *threads) return 0; } - -notmuch_threads_t * -notmuch_query_search_threads (notmuch_query_t *query) +notmuch_status_t +notmuch_query_search_threads_st (notmuch_query_t *query, notmuch_threads_t **out) { - notmuch_status_t status; - notmuch_threads_t *threads; - status = notmuch_query_search_threads_st (query, &threads); - if (status) - return NULL; - else - return threads; + return notmuch_query_search_threads(query, out); } notmuch_status_t -notmuch_query_search_threads_st (notmuch_query_t *query, - notmuch_threads_t **out) +notmuch_query_search_threads (notmuch_query_t *query, + notmuch_threads_t **out) { notmuch_threads_t *threads; notmuch_messages_t *messages; @@ -526,7 +508,7 @@ notmuch_query_search_threads_st (notmuch_query_t *query, threads->query = query; - status = notmuch_query_search_messages_st (query, &messages); + status = notmuch_query_search_messages (query, &messages); if (status) { talloc_free (threads); return status; @@ -609,18 +591,14 @@ notmuch_threads_destroy (notmuch_threads_t *threads) talloc_free (threads); } -unsigned int -notmuch_query_count_messages (notmuch_query_t *query) +notmuch_status_t +notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out) { - notmuch_status_t status; - unsigned int count; - - status = notmuch_query_count_messages_st (query, &count); - return status ? 0 : count; + return notmuch_query_count_messages (query, count_out); } notmuch_status_t -notmuch_query_count_messages_st (notmuch_query_t *query, unsigned *count_out) +notmuch_query_count_messages (notmuch_query_t *query, unsigned *count_out) { return _notmuch_query_count_documents (query, "mail", count_out); } @@ -695,18 +673,14 @@ _notmuch_query_count_documents (notmuch_query_t *query, const char *type, unsign return NOTMUCH_STATUS_SUCCESS; } -unsigned -notmuch_query_count_threads (notmuch_query_t *query) +notmuch_status_t +notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count) { - notmuch_status_t status; - unsigned int count; - - status = notmuch_query_count_threads_st (query, &count); - return status ? 0 : count; + return notmuch_query_count_threads (query, count); } notmuch_status_t -notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count) +notmuch_query_count_threads (notmuch_query_t *query, unsigned *count) { notmuch_messages_t *messages; GHashTable *hash; @@ -715,7 +689,7 @@ notmuch_query_count_threads_st (notmuch_query_t *query, unsigned *count) sort = query->sort; query->sort = NOTMUCH_SORT_UNSORTED; - ret = notmuch_query_search_messages_st (query, &messages); + ret = notmuch_query_search_messages (query, &messages); if (ret) return ret; query->sort = sort; diff --git a/lib/regexp-fields.cc b/lib/regexp-fields.cc index 1651677c..084bc8c0 100644 --- a/lib/regexp-fields.cc +++ b/lib/regexp-fields.cc @@ -135,42 +135,76 @@ static inline Xapian::valueno _find_slot (std::string prefix) return NOTMUCH_VALUE_FROM; else if (prefix == "subject") return NOTMUCH_VALUE_SUBJECT; + else if (prefix == "mid") + return NOTMUCH_VALUE_MESSAGE_ID; else - throw Xapian::QueryParserError ("unsupported regexp field '" + prefix + "'"); + return Xapian::BAD_VALUENO; } -RegexpFieldProcessor::RegexpFieldProcessor (std::string prefix, Xapian::QueryParser &parser_, notmuch_database_t *notmuch_) - : slot (_find_slot (prefix)), term_prefix (_find_prefix (prefix.c_str ())), - parser (parser_), notmuch (notmuch_) +RegexpFieldProcessor::RegexpFieldProcessor (std::string prefix, + notmuch_field_flag_t options_, + Xapian::QueryParser &parser_, + notmuch_database_t *notmuch_) + : slot (_find_slot (prefix)), + term_prefix (_find_prefix (prefix.c_str ())), + options (options_), + parser (parser_), + notmuch (notmuch_) { }; Xapian::Query RegexpFieldProcessor::operator() (const std::string & str) { - if (str.size () == 0) - return Xapian::Query(Xapian::Query::OP_AND_NOT, + if (str.empty ()) { + if (options & NOTMUCH_FIELD_PROBABILISTIC) { + return Xapian::Query(Xapian::Query::OP_AND_NOT, Xapian::Query::MatchAll, Xapian::Query (Xapian::Query::OP_WILDCARD, term_prefix)); + } else { + return Xapian::Query (term_prefix); + } + } if (str.at (0) == '/') { - if (str.at (str.size () - 1) == '/'){ - RegexpPostingSource *postings = new RegexpPostingSource (slot, str.substr(1,str.size () - 2)); - return Xapian::Query (postings->release ()); + if (str.length() > 1 && str.at (str.size () - 1) == '/'){ + std::string regexp_str = str.substr(1,str.size () - 2); + if (slot != Xapian::BAD_VALUENO) { + RegexpPostingSource *postings = new RegexpPostingSource (slot, regexp_str); + return Xapian::Query (postings->release ()); + } else { + std::vector<std::string> terms; + regex_t regexp; + + compile_regex(regexp, regexp_str.c_str ()); + for (Xapian::TermIterator it = notmuch->xapian_db->allterms_begin (term_prefix); + it != notmuch->xapian_db->allterms_end (); ++it) { + if (regexec (®exp, (*it).c_str () + term_prefix.size(), + 0, NULL, 0) == 0) + terms.push_back(*it); + } + return Xapian::Query (Xapian::Query::OP_OR, terms.begin(), terms.end()); + } } else { throw Xapian::QueryParserError ("unmatched regex delimiter in '" + str + "'"); } } else { - /* TODO replace this with a nicer API level triggering of - * phrase parsing, when possible */ - std::string query_str; + if (options & NOTMUCH_FIELD_PROBABILISTIC) { + /* TODO replace this with a nicer API level triggering of + * phrase parsing, when possible */ + std::string query_str; - if (str.find (' ') != std::string::npos) - query_str = '"' + str + '"'; - else - query_str = str; + if (str.find (' ') != std::string::npos) + query_str = '"' + str + '"'; + else + query_str = str; - return parser.parse_query (query_str, NOTMUCH_QUERY_PARSER_FLAGS, term_prefix); + return parser.parse_query (query_str, NOTMUCH_QUERY_PARSER_FLAGS, term_prefix); + } else { + /* Boolean prefix */ + std::string term = term_prefix + str; + return Xapian::Query (term); + } } } #endif diff --git a/lib/regexp-fields.h b/lib/regexp-fields.h index a4ba7ad8..d5f93445 100644 --- a/lib/regexp-fields.h +++ b/lib/regexp-fields.h @@ -65,11 +65,13 @@ class RegexpFieldProcessor : public Xapian::FieldProcessor { protected: Xapian::valueno slot; std::string term_prefix; + notmuch_field_flag_t options; Xapian::QueryParser &parser; notmuch_database_t *notmuch; public: - RegexpFieldProcessor (std::string prefix, Xapian::QueryParser &parser_, notmuch_database_t *notmuch_); + RegexpFieldProcessor (std::string prefix, notmuch_field_flag_t options, + Xapian::QueryParser &parser_, notmuch_database_t *notmuch_); ~RegexpFieldProcessor () { }; diff --git a/lib/thread.cc b/lib/thread.cc index 84ee5298..1a1ecfa5 100644 --- a/lib/thread.cc +++ b/lib/thread.cc @@ -26,7 +26,7 @@ #define EMPTY_STRING(s) ((s)[0] == '\0') -struct visible _notmuch_thread { +struct _notmuch_thread { notmuch_database_t *notmuch; char *thread_id; char *subject; @@ -505,7 +505,7 @@ _notmuch_thread_create (void *ctx, * oldest or newest subject is desired. */ notmuch_query_set_sort (thread_id_query, NOTMUCH_SORT_OLDEST_FIRST); - status = notmuch_query_search_messages_st (thread_id_query, &messages); + status = notmuch_query_search_messages (thread_id_query, &messages); if (status) goto DONE; |
