mail-search-args-simplify.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "lib.h"
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen#include "array.h"
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen#include "hash.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "mail-search.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstruct mail_search_simplify_prev_arg {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen enum mail_search_arg_type type;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen enum mail_search_arg_flag search_flags;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen enum mail_search_date_type date_type;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen enum mail_flags mail_flags;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen bool match_not;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen bool fuzzy;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen } bin_mask;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen const char *hdr_field_name_mask;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen const char *str_mask;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct mail_search_arg *prev_arg;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen};
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstruct mail_search_simplify_ctx {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen pool_t pool;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* arg mask => prev_arg */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen HASH_TABLE(struct mail_search_simplify_prev_arg *,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct mail_search_simplify_prev_arg *) prev_args;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen bool parent_and;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen bool removals;
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen bool initialized;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen};
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic int
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenmail_search_simplify_prev_arg_cmp(const struct mail_search_simplify_prev_arg *arg1,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen const struct mail_search_simplify_prev_arg *arg2)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen int ret;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = memcmp(&arg1->bin_mask, &arg2->bin_mask, sizeof(arg1->bin_mask));
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (ret == 0)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = null_strcmp(arg1->hdr_field_name_mask, arg2->hdr_field_name_mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (ret == 0)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ret = null_strcmp(arg1->str_mask, arg2->str_mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return ret;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic unsigned int
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenmail_search_simplify_prev_arg_hash(const struct mail_search_simplify_prev_arg *arg)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen unsigned int hash;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen hash = mem_hash(&arg->bin_mask, sizeof(arg->bin_mask));
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (arg->hdr_field_name_mask != NULL)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen hash ^= str_hash(arg->hdr_field_name_mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (arg->str_mask != NULL)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen hash ^= str_hash(arg->str_mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return hash;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic void mail_search_arg_get_base_mask(const struct mail_search_arg *arg,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_simplify_prev_arg *mask_r)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(mask_r);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mask_r->bin_mask.type = arg->type;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mask_r->bin_mask.fuzzy = arg->fuzzy;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mask_r->bin_mask.search_flags = arg->value.search_flags;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic struct mail_search_arg **
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenmail_search_args_simplify_get_prev_argp(struct mail_search_simplify_ctx *ctx,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen const struct mail_search_simplify_prev_arg *mask)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct mail_search_simplify_prev_arg *prev_arg;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg = hash_table_lookup(ctx->prev_args, mask);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (prev_arg == NULL) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg = p_new(ctx->pool, struct mail_search_simplify_prev_arg, 1);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen prev_arg->bin_mask = mask->bin_mask;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen prev_arg->hdr_field_name_mask =
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen p_strdup(ctx->pool, mask->hdr_field_name_mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen prev_arg->str_mask =
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen p_strdup(ctx->pool, mask->str_mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen hash_table_insert(ctx->prev_args, prev_arg, prev_arg);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return &prev_arg->prev_arg;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainenstatic bool
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainenmail_search_args_merge_mask(struct mail_search_simplify_ctx *ctx,
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen struct mail_search_arg *args,
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen const struct mail_search_simplify_prev_arg *mask)
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen{
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen struct mail_search_arg **prev_argp;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, mask);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen if (*prev_argp == NULL) {
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen *prev_argp = args;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return FALSE;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen }
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (ctx->initialized)
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen mail_search_arg_one_deinit(args);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen if ((*prev_argp)->match_not != args->match_not) {
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen /* a && !a = 0 */
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen if (ctx->initialized)
1270cb6b6139001b0a89f595ad0868b1f3a0af45Timo Sirainen mail_search_arg_one_deinit(*prev_argp);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen (*prev_argp)->type = SEARCH_ALL;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen (*prev_argp)->match_not = ctx->parent_and;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen }
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen /* duplicate keyword. */
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return TRUE;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen}
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstatic bool mail_search_args_merge_flags(struct mail_search_simplify_ctx *ctx,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen struct mail_search_arg *args)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_simplify_prev_arg mask;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_search_arg_get_base_mask(args, &mask);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen mask.bin_mask.mail_flags = args->value.flags;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen return mail_search_args_merge_mask(ctx, args, &mask);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainenstatic bool
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainenmail_search_args_merge_keywords(struct mail_search_simplify_ctx *ctx,
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen struct mail_search_arg *args)
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen{
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen struct mail_search_simplify_prev_arg mask;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen mail_search_arg_get_base_mask(args, &mask);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen mask.str_mask = args->value.str;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return mail_search_args_merge_mask(ctx, args, &mask);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen}
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainenstatic void mail_search_args_simplify_set(struct mail_search_arg *args)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen{
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen const struct seq_range *seqset;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen unsigned int count;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (args->match_not) {
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen /* invert the set to drop the NOT. Note that (uint32_t)-1
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen matches the last existing mail, which we don't know at this
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen point. lib-imap/imap-seqset.c has similar code that
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen disallows using (uint32_t)-1 as a real UID. */
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (seq_range_exists(&args->value.seqset, (uint32_t)-1))
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen return;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen args->match_not = FALSE;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen seq_range_array_invert(&args->value.seqset, 1, (uint32_t)-2);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen seqset = array_get(&args->value.seqset, &count);
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (count == 1 && seqset->seq1 == 1 && seqset->seq2 >= (uint32_t)-2) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* 1:* is the same as ALL. */
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen args->type = SEARCH_ALL;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen } else if (count == 0) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* empty set is the same as NOT ALL. this is mainly coming
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen from mail_search_args_merge_set() intersection. */
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen args->type = SEARCH_ALL;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen args->match_not = TRUE;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen}
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainenstatic bool mail_search_args_merge_set(struct mail_search_simplify_ctx *ctx,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen struct mail_search_arg *args)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_simplify_prev_arg mask;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen struct mail_search_arg **prev_argp;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (args->match_not) {
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen /* "*" used - can't simplify it */
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen return FALSE;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_search_arg_get_base_mask(args, &mask);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen mask.bin_mask.match_not = args->match_not;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (*prev_argp == NULL) {
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen *prev_argp = args;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return FALSE;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen } else if (ctx->parent_and) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen seq_range_array_intersect(&(*prev_argp)->value.seqset,
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen &args->value.seqset);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen return TRUE;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen } else {
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen seq_range_array_merge(&(*prev_argp)->value.seqset,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen &args->value.seqset);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return TRUE;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen}
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainenstatic bool mail_search_args_merge_time(struct mail_search_simplify_ctx *ctx,
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct mail_search_arg *args)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_simplify_prev_arg mask;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen struct mail_search_arg **prev_argp, *prev_arg;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen mail_search_arg_get_base_mask(args, &mask);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen mask.bin_mask.match_not = args->match_not;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mask.bin_mask.date_type = args->value.date_type;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (*prev_argp == NULL) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen *prev_argp = args;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg = *prev_argp;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen switch (args->type) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_BEFORE:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (ctx->parent_and) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (prev_arg->value.time < args->value.time) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg < 5 AND arg < 10 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg < 10 AND arg < 5 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg->value.time = args->value.time;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (prev_arg->value.time < args->value.time) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg < 5 OR arg < 10 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg->value.time = args->value.time;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg < 10 OR arg < 5 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return TRUE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_ON:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (prev_arg->value.time == args->value.time)
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return TRUE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_SINCE:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (ctx->parent_and) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (prev_arg->value.time < args->value.time) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg >= 5 AND arg >= 10 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg->value.time = args->value.time;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg >= 10 AND arg >= 5 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (prev_arg->value.time < args->value.time) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg >= 5 OR arg >= 10 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* prev_arg >= 10 OR arg >= 5 */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen prev_arg->value.time = args->value.time;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return TRUE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen default:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen return FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen}
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainenstatic bool mail_search_args_merge_size(struct mail_search_simplify_ctx *ctx,
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen struct mail_search_arg *args)
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_simplify_prev_arg mask;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen struct mail_search_arg **prev_argp, *prev_arg;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen mail_search_arg_get_base_mask(args, &mask);
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen mask.bin_mask.match_not = args->match_not;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (*prev_argp == NULL) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen *prev_argp = args;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return FALSE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen prev_arg = *prev_argp;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen switch (args->type) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case SEARCH_SMALLER:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (ctx->parent_and) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (prev_arg->value.size < args->value.size) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg < 5 AND arg < 10 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg < 10 AND arg < 5 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen prev_arg->value.size = args->value.size;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (prev_arg->value.size < args->value.size) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg < 5 OR arg < 10 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen prev_arg->value.size = args->value.size;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg < 10 OR arg < 5 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return TRUE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case SEARCH_LARGER:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (ctx->parent_and) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (prev_arg->value.size < args->value.size) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg >= 5 AND arg >= 10 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen prev_arg->value.size = args->value.size;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg >= 10 AND arg >= 5 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (prev_arg->value.size < args->value.size) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg >= 5 OR arg >= 10 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen } else {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* prev_arg >= 10 OR arg >= 5 */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen prev_arg->value.size = args->value.size;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return TRUE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen default:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen return FALSE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen}
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainenstatic bool mail_search_args_merge_text(struct mail_search_simplify_ctx *ctx,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_arg *args)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen{
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen struct mail_search_simplify_prev_arg mask;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_search_arg_get_base_mask(args, &mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mask.hdr_field_name_mask = args->hdr_field_name;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mask.str_mask = args->value.str;
92f9871ac981201fe0a47f6c909f790cce14b240Timo Sirainen return mail_search_args_merge_mask(ctx, args, &mask);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen}
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic bool
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenmail_search_args_have_equal(const struct mail_search_arg *args,
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const struct mail_search_arg *wanted_arg)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const struct mail_search_arg *arg;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (mail_search_arg_one_equals(arg, wanted_arg))
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return TRUE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return FALSE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainenstatic bool
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenmail_search_args_remove_equal(struct mail_search_args *all_args,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen struct mail_search_arg **argsp,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen const struct mail_search_arg *wanted_arg,
632018810af689442569cbb0139c55868923ccfeTimo Sirainen bool check_subs)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen{
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct mail_search_arg **argp;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen bool found = FALSE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen for (argp = argsp; (*argp) != NULL; ) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (mail_search_arg_one_equals(*argp, wanted_arg)) {
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (all_args->init_refcount > 0)
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen mail_search_arg_one_deinit(*argp);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen *argp = (*argp)->next;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen found = TRUE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen } else if (check_subs) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen i_assert((*argp)->type == SEARCH_SUB ||
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen (*argp)->type == SEARCH_OR);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (!mail_search_args_remove_equal(all_args, &(*argp)->value.subargs, wanted_arg, FALSE)) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* we already verified that this should have
632018810af689442569cbb0139c55868923ccfeTimo Sirainen existed. */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen i_unreached();
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if ((*argp)->value.subargs == NULL)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen *argp = (*argp)->next;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen else
632018810af689442569cbb0139c55868923ccfeTimo Sirainen argp = &(*argp)->next;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen found = TRUE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen } else {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen argp = &(*argp)->next;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return found;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen}
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic bool
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenmail_search_args_have_all_equal(struct mail_search_arg *parent_arg,
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const struct mail_search_arg *wanted_args)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen const struct mail_search_arg *arg;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen i_assert(parent_arg->type == SEARCH_SUB ||
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen parent_arg->type == SEARCH_OR);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen for (arg = wanted_args; arg != NULL; arg = arg->next) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (!mail_search_args_have_equal(parent_arg->value.subargs, arg))
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return FALSE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return TRUE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic unsigned int
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenmail_search_args_count(const struct mail_search_arg *args)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen unsigned int count;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen for (count = 0; args != NULL; count++)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen args = args->next;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return count;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainenstatic bool
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenmail_search_args_simplify_drop_redundant_args(struct mail_search_args *all_args,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen struct mail_search_arg **argsp,
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen bool and_arg)
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen{
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen struct mail_search_arg *arg, **argp, one_arg, *lowest_arg = NULL;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen enum mail_search_arg_type child_subargs_type;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen unsigned int count, lowest_count = UINT_MAX;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen bool ret = FALSE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen if (*argsp == NULL)
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen return FALSE;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen child_subargs_type = and_arg ? SEARCH_OR : SEARCH_SUB;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* find the arg which has the lowest number of child args */
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen for (arg = *argsp; arg != NULL; arg = arg->next) {
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen if (arg->type != child_subargs_type) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen one_arg = *arg;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen one_arg.next = NULL;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen lowest_arg = &one_arg;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen break;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen count = mail_search_args_count(arg->value.subargs);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (count < lowest_count) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen lowest_arg = arg->value.subargs;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen lowest_count = count;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen i_assert(lowest_arg != NULL);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* if there are any args that include lowest_arg, drop the arg since
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen it's redundant. (non-SUB duplicates are dropped elsewhere.) */
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen for (argp = argsp; *argp != NULL; ) {
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen if (*argp != lowest_arg && (*argp)->type == child_subargs_type &&
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen (*argp)->value.subargs != lowest_arg &&
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen mail_search_args_have_all_equal(*argp, lowest_arg)) {
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (all_args->init_refcount > 0)
b8b005887cd7f72520c6dcc325461faeecc5f9e9Timo Sirainen mail_search_arg_one_deinit(*argp);
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen *argp = (*argp)->next;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ret = TRUE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen } else {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen argp = &(*argp)->next;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen return ret;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen}
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainenstatic bool
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenmail_search_args_simplify_extract_common(struct mail_search_args *all_args,
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen struct mail_search_arg **argsp,
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen pool_t pool, bool and_arg)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen{
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen /* Simple SUB example:
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen (a AND b) OR (a AND c) -> a AND (b OR c)
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen More complicated example:
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen (c1 AND c2 AND u1 AND u2) OR (c1 AND c2 AND u3 AND u4) ->
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen c1 AND c2 AND ((u1 AND u2) OR (u3 AND u4))
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen Similarly for ORs:
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen (a OR b) AND (a OR c) -> a OR (b AND c)
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen (c1 OR c2 OR u1 OR u2) AND (c1 OR c2 OR u3 OR u4) ->
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen c1 OR c2 OR ((u1 OR u2) AND (u3 OR u4))
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen struct mail_search_arg *arg, *sub_arg, *sub_next;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen struct mail_search_arg *new_arg, *child_arg, *common_args = NULL;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen enum mail_search_arg_type child_subargs_type;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen if (*argsp == NULL || (*argsp)->next == NULL) {
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen /* single arg, nothing to extract */
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen return FALSE;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen child_subargs_type = and_arg ? SEARCH_OR : SEARCH_SUB;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen /* find the first arg with child_subargs_type */
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen for (arg = *argsp; arg != NULL; arg = arg->next) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (arg->type == child_subargs_type)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen break;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (arg == NULL)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return FALSE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen for (sub_arg = arg->value.subargs; sub_arg != NULL; sub_arg = sub_next) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen sub_next = sub_arg->next;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* check if sub_arg is found from all the args */
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen for (arg = *argsp; arg != NULL; arg = arg->next) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (mail_search_arg_one_equals(arg, sub_arg)) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* the whole arg matches */
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen } else if (arg->type == child_subargs_type &&
632018810af689442569cbb0139c55868923ccfeTimo Sirainen mail_search_args_have_equal(arg->value.subargs, sub_arg)) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* exists as subarg */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen } else {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen break;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (arg != NULL)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen continue;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* extract the arg and put it to common_args */
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen mail_search_args_remove_equal(all_args, argsp, sub_arg, TRUE);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen sub_arg->next = common_args;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen common_args = sub_arg;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (common_args == NULL)
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return FALSE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen /* replace all the original args with a single new SUB/OR arg */
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen new_arg = p_new(pool, struct mail_search_arg, 1);
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen new_arg->type = child_subargs_type;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen if (*argsp == NULL) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* there are only common args */
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen new_arg->value.subargs = common_args;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen } else {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen /* replace OR arg with AND(OR(non_common_args), common_args)
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen or
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen replace AND arg with OR(AND(non_common_args), common_args) */
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen child_arg = p_new(pool, struct mail_search_arg, 1);
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen child_arg->type = and_arg ? SEARCH_SUB : SEARCH_OR;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen child_arg->value.subargs = *argsp;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen child_arg->next = common_args;
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen new_arg->value.subargs = child_arg;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen *argsp = new_arg;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen return TRUE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen}
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainenstatic bool
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainenmail_search_args_simplify_sub(struct mail_search_args *all_args, pool_t pool,
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen struct mail_search_arg **argsp, bool parent_and)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen struct mail_search_simplify_ctx ctx;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen struct mail_search_arg *sub, **all_argsp = argsp;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen bool merged;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx);
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen ctx.initialized = all_args->init_refcount > 0;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ctx.parent_and = parent_and;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ctx.pool = pool_alloconly_create("mail search args simplify", 1024);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen hash_table_create(&ctx.prev_args, ctx.pool, 0,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_search_simplify_prev_arg_hash,
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen mail_search_simplify_prev_arg_cmp);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen while (*argsp != NULL) {
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen struct mail_search_arg *args = *argsp;
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (args->match_not && (args->type == SEARCH_SUB ||
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->type == SEARCH_OR)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* neg(p and q and ..) == neg(p) or neg(q) or ..
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen neg(p or q or ..) == neg(p) and neg(q) and .. */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->type = args->type == SEARCH_SUB ?
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen SEARCH_OR : SEARCH_SUB;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->match_not = FALSE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen sub = args->value.subargs;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen do {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen sub->match_not = !sub->match_not;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen sub = sub->next;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen } while (sub != NULL);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if ((args->type == SEARCH_SUB && parent_and) ||
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen (args->type == SEARCH_OR && !parent_and) ||
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ((args->type == SEARCH_SUB || args->type == SEARCH_OR) &&
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->value.subargs->next == NULL)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* p and (q and ..) == p and q and ..
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen p or (q or ..) == p or q or ..
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen (p) = p */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen sub = args->value.subargs;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen for (; sub->next != NULL; sub = sub->next) ;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen sub->next = args->next;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen *args = *args->value.subargs;
c89ceadf661bde22e1cd9dc2eac09c19202e65ecTimo Sirainen ctx.removals = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen continue;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (args->type == SEARCH_SUB ||
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->type == SEARCH_OR ||
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->type == SEARCH_INTHREAD) {
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen i_assert(!args->match_not);
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen if (args->type != SEARCH_INTHREAD) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen bool and_arg = args->type == SEARCH_SUB;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (mail_search_args_simplify_drop_redundant_args(all_args, &args->value.subargs, and_arg))
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ctx.removals = TRUE;
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (mail_search_args_simplify_extract_common(all_args, &args->value.subargs, pool, and_arg))
632018810af689442569cbb0139c55868923ccfeTimo Sirainen ctx.removals = TRUE;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen }
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (mail_search_args_simplify_sub(all_args, pool, &args->value.subargs,
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen args->type != SEARCH_OR))
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen ctx.removals = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (args->type == SEARCH_SEQSET ||
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen args->type == SEARCH_UIDSET)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen mail_search_args_simplify_set(args);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* try to merge arguments */
1e167fbb281ccf41178a0b70495193c768f9ff75Timo Sirainen merged = FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen switch (args->type) {
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen case SEARCH_ALL: {
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen if (*all_argsp == args && args->next == NULL) {
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen /* this arg has no siblings - no merging */
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen break;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen }
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen if ((parent_and && !args->match_not) ||
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen (!parent_and && args->match_not)) {
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen /* .. AND ALL ..
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen .. OR NOT ALL ..
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen This arg is irrelevant -> drop */
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen merged = TRUE;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen break;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen }
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen /* .. AND NOT ALL ..
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen .. OR ALL ..
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen The other args are irrelevant -> drop them */
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen *all_argsp = args;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen args->next = NULL;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen ctx.removals = TRUE;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen break;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_FLAGS:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen merged = mail_search_args_merge_flags(&ctx, args);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen case SEARCH_KEYWORDS:
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen merged = mail_search_args_merge_keywords(&ctx, args);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_SEQSET:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_UIDSET:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen merged = mail_search_args_merge_set(&ctx, args);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_BEFORE:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_ON:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen case SEARCH_SINCE:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen merged = mail_search_args_merge_time(&ctx, args);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case SEARCH_SMALLER:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen case SEARCH_LARGER:
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen merged = mail_search_args_merge_size(&ctx, args);
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen case SEARCH_BODY:
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen case SEARCH_TEXT:
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen if (args->value.str[0] == '\0') {
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen /* BODY "" and TEXT "" matches everything */
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen args->type = SEARCH_ALL;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen ctx.removals = TRUE;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen break;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen }
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen /* fall through */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen case SEARCH_HEADER:
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen case SEARCH_HEADER_ADDRESS:
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen case SEARCH_HEADER_COMPRESS_LWSP:
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen merged = mail_search_args_merge_text(&ctx, args);
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen default:
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen break;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (merged) {
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen *argsp = args->next;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ctx.removals = TRUE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen continue;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
37ce8d49a351f073958624b78c702af75362c1cbTimo Sirainen argsp = &args->next;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen hash_table_destroy(&ctx.prev_args);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen pool_unref(&ctx.pool);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen return ctx.removals;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainenstatic bool
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainenmail_search_args_simplify_merge_flags(struct mail_search_arg **argsp,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen bool parent_and)
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen{
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen struct mail_search_arg *prev_flags = NULL;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen bool removals = FALSE;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen while (*argsp != NULL) {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen struct mail_search_arg *args = *argsp;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen if (args->type == SEARCH_SUB ||
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen args->type == SEARCH_OR ||
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen args->type == SEARCH_INTHREAD) {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen if (mail_search_args_simplify_merge_flags(&args->value.subargs,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen args->type != SEARCH_OR))
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen removals = TRUE;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen } else if (args->type != SEARCH_FLAGS) {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen /* ignore non-flags */
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen } else if (!((!args->match_not && parent_and) ||
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen (args->match_not && !parent_and))) {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen /* can't merge these flags args */
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen } else if (prev_flags == NULL) {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen /* first flags arg */
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen prev_flags = args;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen } else {
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen /* merge to previous arg */
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen prev_flags->value.flags |= args->value.flags;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen *argsp = args->next;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen removals = TRUE;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen continue;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen }
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen argsp = &args->next;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen }
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen return removals;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen}
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenstatic bool
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenmail_search_args_unnest_inthreads(struct mail_search_args *args,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct mail_search_arg **argp,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen bool parent_inthreads, bool parent_and)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct mail_search_arg *arg, *thread_arg, *or_arg;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen bool child_inthreads = FALSE, non_inthreads = FALSE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen for (arg = *argp; arg != NULL; arg = arg->next) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen switch (arg->type) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen case SEARCH_SUB:
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen case SEARCH_OR:
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (!mail_search_args_unnest_inthreads(args,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen &arg->value.subargs, parent_inthreads,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->type != SEARCH_OR)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->result = 1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen child_inthreads = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen } else {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->result = 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen non_inthreads = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen break;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen case SEARCH_INTHREAD:
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (mail_search_args_unnest_inthreads(args,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen &arg->value.subargs, TRUE, TRUE)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* children converted to SEARCH_INTHREADs */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->type = SEARCH_SUB;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->have_inthreads = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->result = 1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen child_inthreads = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen break;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen default:
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->result = 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen non_inthreads = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen break;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (!parent_inthreads || !child_inthreads || !non_inthreads)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return FALSE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* put all non-INTHREADs under a single INTHREAD */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen thread_arg = p_new(args->pool, struct mail_search_arg, 1);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen thread_arg->type = SEARCH_INTHREAD;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen while (*argp != NULL) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg = *argp;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen argp = &(*argp)->next;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (arg->result == 0) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* not an INTHREAD or a SUB/OR with only INTHREADs */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen arg->next = thread_arg->value.subargs;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen thread_arg->value.subargs = arg;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (!parent_and) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* We want to OR the args */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen or_arg = p_new(args->pool, struct mail_search_arg, 1);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen or_arg->type = SEARCH_OR;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen or_arg->value.subargs = thread_arg->value.subargs;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen thread_arg->value.subargs = or_arg;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenvoid mail_search_args_simplify(struct mail_search_args *args)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen bool removals;
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen args->simplified = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen removals = mail_search_args_simplify_sub(args, args->pool, &args->args, TRUE);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (mail_search_args_unnest_inthreads(args, &args->args,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen FALSE, TRUE)) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* we may have added some extra SUBs that could be dropped */
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (mail_search_args_simplify_sub(args, args->pool, &args->args, TRUE))
c89ceadf661bde22e1cd9dc2eac09c19202e65ecTimo Sirainen removals = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen do {
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (mail_search_args_simplify_drop_redundant_args(args, &args->args, TRUE))
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen removals = TRUE;
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen if (mail_search_args_simplify_extract_common(args, &args->args, args->pool, TRUE))
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen removals = TRUE;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen if (removals)
fccd110b494a7e31f23d31d9e3bc3e986c9bb1a8Timo Sirainen removals = mail_search_args_simplify_sub(args, args->pool, &args->args, TRUE);
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen /* do the flag merging into a single arg only at the end.
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen up until then they're treated as any other search args,
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen which simplifies their handling. after the flags merging is
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen done, further simplifications are still possible. */
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen if (mail_search_args_simplify_merge_flags(&args->args, TRUE))
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen removals = TRUE;
cc23ad7b8ab96d93d5ab5139c431fcdd8d9e1d72Timo Sirainen } while (removals);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}