bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "lib.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "array.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "mail-namespace.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "mail-search.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-api-private.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-tokenizer.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-filter.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-user.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen#include "fts-search-args.h"
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic void strings_deduplicate(ARRAY_TYPE(const_string) *arr)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const char *const *strings;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen unsigned int i, count;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen strings = array_get(arr, &count);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen for (i = 1; i < count; ) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen if (strcmp(strings[i-1], strings[i]) == 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_delete(arr, i, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen strings = array_get(arr, &count);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen } else {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen i++;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenstatic struct mail_search_arg *
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenfts_search_arg_create_or(const struct mail_search_arg *orig_arg, pool_t pool,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const ARRAY_TYPE(const_string) *tokens)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct mail_search_arg *arg, *or_arg, **argp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const char *const *tokenp;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* create the OR arg first as the parent */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen or_arg = p_new(pool, struct mail_search_arg, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen or_arg->type = SEARCH_OR;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* now create all the child args for the OR */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen argp = &or_arg->value.subargs;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_foreach(tokens, tokenp) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen arg = p_new(pool, struct mail_search_arg, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *arg = *orig_arg;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen arg->match_not = FALSE; /* we copied this to the root OR */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen arg->next = NULL;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen arg->value.str = p_strdup(pool, *tokenp);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen *argp = arg;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen argp = &arg->next;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return or_arg;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainenstatic int
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenfts_backend_dovecot_expand_tokens(struct fts_filter *filter,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen pool_t pool,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen struct mail_search_arg *parent_arg,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const struct mail_search_arg *orig_arg,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char *orig_token, const char *token,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char **error_r)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct mail_search_arg *arg;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen ARRAY_TYPE(const_string) tokens;
1d0f568e26ce5cbf18cd7bb335c6eea20a7e3770Teemu Huovila const char *token2, *error;
db090e2a48bcc5ce162af0c36eef04407421379dTeemu Huovila int ret;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen t_array_init(&tokens, 4);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* first add the word exactly as it without any tokenization */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_append(&tokens, &orig_token, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* then add it tokenized, but without filtering */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_append(&tokens, &token, 1);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* add the word filtered */
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (filter != NULL) {
db090e2a48bcc5ce162af0c36eef04407421379dTeemu Huovila token2 = t_strdup(token);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen ret = fts_filter_filter(filter, &token2, &error);
db090e2a48bcc5ce162af0c36eef04407421379dTeemu Huovila if (ret > 0) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen token2 = t_strdup(token2);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_append(&tokens, &token2, 1);
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen } else if (ret < 0) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen *error_r = t_strdup_printf("Couldn't filter search token: %s", error);
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return -1;
513b045d3cb2325250e74f0a92c144f9307eee44Timo Sirainen } else {
513b045d3cb2325250e74f0a92c144f9307eee44Timo Sirainen /* The filter dropped the token, which means it was
513b045d3cb2325250e74f0a92c144f9307eee44Timo Sirainen never even indexed. Ignore this word entirely in the
513b045d3cb2325250e74f0a92c144f9307eee44Timo Sirainen search query. */
513b045d3cb2325250e74f0a92c144f9307eee44Timo Sirainen return 0;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen array_sort(&tokens, i_strcmp_p);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen strings_deduplicate(&tokens);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen arg = fts_search_arg_create_or(orig_arg, pool, &tokens);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen arg->next = parent_arg->value.subargs;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen parent_arg->value.subargs = arg;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenstatic int
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainenfts_backend_dovecot_tokenize_lang(struct fts_user_language *user_lang,
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen pool_t pool, struct mail_search_arg *or_arg,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen struct mail_search_arg *orig_arg,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char *orig_token, const char **error_r)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen{
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t orig_token_len = strlen(orig_token);
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen struct mail_search_arg *and_arg;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char *token, *error;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen int ret;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen /* we want all the tokens found from the string to be found, so create
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen a parent AND and place all the filtered token alternatives under
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen it */
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen and_arg = p_new(pool, struct mail_search_arg, 1);
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen and_arg->type = SEARCH_SUB;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen and_arg->next = or_arg->value.subargs;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->value.subargs = and_arg;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen /* reset tokenizer between search args in case there's any state left
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen from some previous failure */
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen fts_tokenizer_reset(user_lang->search_tokenizer);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen while ((ret = fts_tokenizer_next(user_lang->search_tokenizer,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen (const void *)orig_token,
c5b642067ab1fb48b3f07a0a3fd08abe6aacd611Timo Sirainen orig_token_len, &token, &error)) > 0) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_backend_dovecot_expand_tokens(user_lang->filter, pool,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen and_arg, orig_arg, orig_token,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen token, error_r) < 0)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen }
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen while (ret >= 0 &&
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen (ret = fts_tokenizer_final(user_lang->search_tokenizer, &token, &error)) > 0) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (fts_backend_dovecot_expand_tokens(user_lang->filter, pool,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen and_arg, orig_arg, orig_token,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen token, error_r) < 0)
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen }
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen if (ret < 0) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen *error_r = t_strdup_printf("Couldn't tokenize search args: %s", error);
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen }
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen if (and_arg->value.subargs == NULL) {
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen /* nothing was actually expanded, remove the empty and_arg */
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->value.subargs = NULL;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen }
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen return 0;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen}
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainenstatic int fts_search_arg_expand(struct fts_backend *backend, pool_t pool,
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen struct mail_search_arg **argp)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen const ARRAY_TYPE(fts_user_language) *languages;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen struct fts_user_language *const *langp;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen struct mail_search_arg *or_arg, *orig_arg = *argp;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen const char *error, *orig_token = orig_arg->value.str;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
4a3584d6abec84ffd4d430667c6a7c58bb3f8b1aTimo Sirainen if (((*argp)->type == SEARCH_HEADER ||
4a3584d6abec84ffd4d430667c6a7c58bb3f8b1aTimo Sirainen (*argp)->type == SEARCH_HEADER_ADDRESS ||
4a3584d6abec84ffd4d430667c6a7c58bb3f8b1aTimo Sirainen (*argp)->type == SEARCH_HEADER_COMPRESS_LWSP) &&
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen !fts_header_has_language((*argp)->hdr_field_name)) {
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen /* use only the data-language */
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen languages = fts_user_get_data_languages(backend->ns->user);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen } else {
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen languages = fts_user_get_all_languages(backend->ns->user);
ebcd7cf40e53c2bbc98f7f686e206cda5c0e3111Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen /* OR together all the different expansions for different languages.
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen it's enough for one of them to match. */
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg = p_new(pool, struct mail_search_arg, 1);
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->type = SEARCH_OR;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->match_not = orig_arg->match_not;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->next = orig_arg->next;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen array_foreach(languages, langp) {
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen if (fts_backend_dovecot_tokenize_lang(*langp, pool, or_arg,
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen orig_arg, orig_token, &error) < 0) {
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen i_error("fts: %s", error);
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return -1;
dbf26a3ea43cd79fe88f01ec99c7d9440679b996Timo Sirainen }
8b1a9a4d63b0abccdf7cb1acb8359d5396dd657bTimo Sirainen }
aaed9e3ce98759e0cb1258fc14e1076b71791445Timo Sirainen
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen if (or_arg->value.subargs == NULL) {
aaed9e3ce98759e0cb1258fc14e1076b71791445Timo Sirainen /* we couldn't parse any tokens from the input */
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->type = SEARCH_ALL;
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen or_arg->match_not = !or_arg->match_not;
aaed9e3ce98759e0cb1258fc14e1076b71791445Timo Sirainen }
23b586b2cf5760527529f9963c04875c8566a24dTimo Sirainen *argp = or_arg;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainenstatic int
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenfts_search_args_expand_tree(struct fts_backend *backend, pool_t pool,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct mail_search_arg **argp)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen int ret;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen for (; *argp != NULL; argp = &(*argp)->next) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen switch ((*argp)->type) {
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_OR:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_SUB:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_INTHREAD:
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen if (fts_search_args_expand_tree(backend, pool,
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen &(*argp)->value.subargs) < 0)
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen break;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_HEADER:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_HEADER_ADDRESS:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_HEADER_COMPRESS_LWSP:
5ed7a7fd838ba316cee9c59244d263227eb2b0d8Timo Sirainen if ((*argp)->value.str[0] == '\0') {
5ed7a7fd838ba316cee9c59244d263227eb2b0d8Timo Sirainen /* we're testing for the existence of
5ed7a7fd838ba316cee9c59244d263227eb2b0d8Timo Sirainen the header */
5ed7a7fd838ba316cee9c59244d263227eb2b0d8Timo Sirainen break;
5ed7a7fd838ba316cee9c59244d263227eb2b0d8Timo Sirainen }
f784d5bb8edbec88829524135cfa100129f5384dTimo Sirainen /* fall through */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_BODY:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen case SEARCH_TEXT:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen T_BEGIN {
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen ret = fts_search_arg_expand(backend, pool, argp);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen } T_END;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen if (ret < 0)
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen break;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen default:
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen break;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen }
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainenint fts_search_args_expand(struct fts_backend *backend,
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen struct mail_search_args *args)
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen{
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen struct mail_search_arg *args_dup, *orig_args = args->args;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen /* don't keep re-expanding every time the search args are used.
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen this is especially important to avoid an assert-crash in
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen index_search_result_update_flags(). */
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen if (args->fts_expanded)
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen return 0;
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen args->fts_expanded = TRUE;
44ca7644e6df9e5ce7e7d0cc3767f63153c10bd7Timo Sirainen
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen /* duplicate the args, so if expansion fails we haven't changed
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen anything */
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen args_dup = mail_search_arg_dup(args->pool, args->args);
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen if (fts_search_args_expand_tree(backend, args->pool, &args_dup) < 0)
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen return -1;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen /* we'll need to re-simplify the args if we changed anything */
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen args->simplified = FALSE;
98fe03ecad7fcf0973584b9ab0b4dc4848881d56Timo Sirainen args->args = args_dup;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen mail_search_args_simplify(args);
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen /* duplicated args aren't initialized */
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen i_assert(args->init_refcount > 0);
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen mail_search_arg_init(args, args_dup, FALSE, NULL);
6eca434b47b7b700f7df80a0e1ce31d0fd45d1fdTimo Sirainen mail_search_arg_deinit(orig_args);
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen return 0;
1537d20b852cbbf0d6971790b84e0cce5ca61307Timo Sirainen}