mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-21 18:38:08 +01:00
lib/parse-sexp: parse user headers
One subtle aspect is the replacement of _find_prefix with _notmuch_database_prefix, which understands user headers. Otherwise the code mainly consists of creating a fake prefix record (since the user prefixes are not in the prefix table) and error handling.
This commit is contained in:
parent
cc5992a304
commit
a07ef8abf5
3 changed files with 78 additions and 4 deletions
|
@ -224,6 +224,10 @@ EXAMPLES
|
||||||
``(not (to *))``
|
``(not (to *))``
|
||||||
Match messages with an empty or invalid 'To' and 'Cc' field.
|
Match messages with an empty or invalid 'To' and 'Cc' field.
|
||||||
|
|
||||||
|
``(List *)``
|
||||||
|
Match messages with a non-empty List-Id header, assuming
|
||||||
|
configuration ``index.header.List=List-Id``
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ _sexp_parse_wildcard (notmuch_database_t *notmuch,
|
||||||
Xapian::Query &output)
|
Xapian::Query &output)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::string term_prefix = parent ? _find_prefix (parent->name) : "";
|
std::string term_prefix = parent ? _notmuch_database_prefix (notmuch, parent->name) : "";
|
||||||
|
|
||||||
if (parent && ! (parent->flags & SEXP_FLAG_WILDCARD)) {
|
if (parent && ! (parent->flags & SEXP_FLAG_WILDCARD)) {
|
||||||
_notmuch_database_log (notmuch, "'%s' does not support wildcard queries\n", parent->name);
|
_notmuch_database_log (notmuch, "'%s' does not support wildcard queries\n", parent->name);
|
||||||
|
@ -272,6 +272,27 @@ _sexp_parse_infix (notmuch_database_t *notmuch, const _sexp_prefix_t *parent,
|
||||||
return NOTMUCH_STATUS_SUCCESS;
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static notmuch_status_t
|
||||||
|
_sexp_parse_header (notmuch_database_t *notmuch, const _sexp_prefix_t *parent,
|
||||||
|
const sexp_t *sx, Xapian::Query &output)
|
||||||
|
{
|
||||||
|
_sexp_prefix_t user_prefix;
|
||||||
|
|
||||||
|
user_prefix.name = sx->list->val;
|
||||||
|
user_prefix.flags = SEXP_FLAG_FIELD | SEXP_FLAG_WILDCARD;
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
_notmuch_database_log (notmuch, "nested field: '%s' inside '%s'\n",
|
||||||
|
sx->list->val, parent->name);
|
||||||
|
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = &user_prefix;
|
||||||
|
|
||||||
|
return _sexp_combine_query (notmuch, parent, Xapian::Query::OP_AND, Xapian::Query::MatchAll,
|
||||||
|
sx->list->next, output);
|
||||||
|
}
|
||||||
|
|
||||||
/* Here we expect the s-expression to be a proper list, with first
|
/* Here we expect the s-expression to be a proper list, with first
|
||||||
* element defining and operation, or as a special case the empty
|
* element defining and operation, or as a special case the empty
|
||||||
* list */
|
* list */
|
||||||
|
@ -281,7 +302,7 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
||||||
Xapian::Query &output)
|
Xapian::Query &output)
|
||||||
{
|
{
|
||||||
if (sx->ty == SEXP_VALUE) {
|
if (sx->ty == SEXP_VALUE) {
|
||||||
std::string term_prefix = parent ? _find_prefix (parent->name) : "";
|
std::string term_prefix = parent ? _notmuch_database_prefix (notmuch, parent->name) : "";
|
||||||
|
|
||||||
if (sx->aty == SEXP_BASIC && strcmp (sx->val, "*") == 0) {
|
if (sx->aty == SEXP_BASIC && strcmp (sx->val, "*") == 0) {
|
||||||
return _sexp_parse_wildcard (notmuch, parent, "", output);
|
return _sexp_parse_wildcard (notmuch, parent, "", output);
|
||||||
|
@ -291,6 +312,7 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
||||||
output = Xapian::Query (term_prefix + sx->val);
|
output = Xapian::Query (term_prefix + sx->val);
|
||||||
return NOTMUCH_STATUS_SUCCESS;
|
return NOTMUCH_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
return _sexp_parse_one_term (notmuch, term_prefix, sx, output);
|
return _sexp_parse_one_term (notmuch, term_prefix, sx, output);
|
||||||
} else {
|
} else {
|
||||||
|
@ -299,7 +321,7 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
||||||
if (prefix->flags & SEXP_FLAG_FIELD) {
|
if (prefix->flags & SEXP_FLAG_FIELD) {
|
||||||
notmuch_status_t status;
|
notmuch_status_t status;
|
||||||
Xapian::Query subquery;
|
Xapian::Query subquery;
|
||||||
term_prefix = _find_prefix (prefix->name);
|
term_prefix = _notmuch_database_prefix (notmuch, prefix->name);
|
||||||
status = _sexp_parse_one_term (notmuch, term_prefix, sx, subquery);
|
status = _sexp_parse_one_term (notmuch, term_prefix, sx, subquery);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
|
@ -323,6 +345,11 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
||||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for user defined field */
|
||||||
|
if (_notmuch_string_map_get (notmuch->user_prefix, sx->list->val)) {
|
||||||
|
return _sexp_parse_header (notmuch, parent, sx, output);
|
||||||
|
}
|
||||||
|
|
||||||
for (_sexp_prefix_t *prefix = prefixes; prefix && prefix->name; prefix++) {
|
for (_sexp_prefix_t *prefix = prefixes; prefix && prefix->name; prefix++) {
|
||||||
if (strcmp (prefix->name, sx->list->val) == 0) {
|
if (strcmp (prefix->name, sx->list->val) == 0) {
|
||||||
if (prefix->flags & SEXP_FLAG_FIELD) {
|
if (prefix->flags & SEXP_FLAG_FIELD) {
|
||||||
|
@ -362,7 +389,6 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
|
||||||
}
|
}
|
||||||
|
|
||||||
_notmuch_database_log (notmuch, "unknown prefix '%s'\n", sx->list->val);
|
_notmuch_database_log (notmuch, "unknown prefix '%s'\n", sx->list->val);
|
||||||
|
|
||||||
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
return NOTMUCH_STATUS_BAD_QUERY_SYNTAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -732,4 +732,48 @@ notmuch search date:2009-11-18..2009-11-18 and tag:unread > EXPECTED
|
||||||
notmuch search --query=sexp '(and (infix "date:2009-11-18..2009-11-18") (infix "tag:unread"))' > OUTPUT
|
notmuch search --query=sexp '(and (infix "date:2009-11-18..2009-11-18") (infix "tag:unread"))' > OUTPUT
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "user header (unknown header)"
|
||||||
|
notmuch search --query=sexp '(FooBar)' >& OUTPUT
|
||||||
|
cat <<EOF > EXPECTED
|
||||||
|
notmuch search: Syntax error in query
|
||||||
|
unknown prefix 'FooBar'
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "adding user header"
|
||||||
|
test_expect_code 0 "notmuch config set index.header.List \"List-Id\""
|
||||||
|
|
||||||
|
test_begin_subtest "reindexing"
|
||||||
|
test_expect_code 0 'notmuch reindex "*"'
|
||||||
|
|
||||||
|
test_begin_subtest "wildcard search for user header"
|
||||||
|
grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
|
||||||
|
notmuch search --output=files --query=sexp '(List *)' | sort | notmuch_dir_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "wildcard search for user header 2"
|
||||||
|
grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
|
||||||
|
notmuch search --output=files --query=sexp '(List (starts-with not))' | sort | notmuch_dir_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "search for user header"
|
||||||
|
notmuch search List:notmuch | notmuch_search_sanitize > EXPECTED
|
||||||
|
notmuch search --query=sexp '(List notmuch)' | notmuch_search_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "search for user header (list token)"
|
||||||
|
notmuch search List:notmuch | notmuch_search_sanitize > EXPECTED
|
||||||
|
notmuch search --query=sexp '(List notmuch.notmuchmail.org)' | notmuch_search_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "search for user header (quoted string)"
|
||||||
|
notmuch search 'List:"notmuch notmuchmail org"' | notmuch_search_sanitize > EXPECTED
|
||||||
|
notmuch search --query=sexp '(List "notmuch notmuchmail org")' | notmuch_search_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "search for user header (atoms)"
|
||||||
|
notmuch search 'List:"notmuch notmuchmail org"' | notmuch_search_sanitize > EXPECTED
|
||||||
|
notmuch search --query=sexp '(List notmuch notmuchmail org)' | notmuch_search_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Loading…
Reference in a new issue