mail-search-args-simplify.c revision c89ceadf661bde22e1cd9dc2eac09c19202e65ec
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2015 Dovecot authors, see the included COPYING file */
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen /* arg mask => prev_arg */
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen HASH_TABLE(struct mail_search_simplify_prev_arg *,
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen struct mail_search_simplify_prev_arg *) prev_args;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainenmail_search_simplify_prev_arg_cmp(const struct mail_search_simplify_prev_arg *arg1,
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen const struct mail_search_simplify_prev_arg *arg2)
9fd2181788a61500641c66aec0f8c746b19bf830Timo Sirainen ret = memcmp(&arg1->bin_mask, &arg2->bin_mask, sizeof(arg1->bin_mask));
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen ret = null_strcmp(arg1->hdr_field_name_mask, arg2->hdr_field_name_mask);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen ret = null_strcmp(arg1->str_mask, arg2->str_mask);
379175cfba8150d481d9898b78330b719d128d84Timo Sirainenstatic unsigned int
379175cfba8150d481d9898b78330b719d128d84Timo Sirainenmail_search_simplify_prev_arg_hash(const struct mail_search_simplify_prev_arg *arg)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen unsigned int hash;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen hash = mem_hash(&arg->bin_mask, sizeof(arg->bin_mask));
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainenstatic void mail_search_arg_get_base_mask(const struct mail_search_arg *arg,
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen mask_r->bin_mask.search_flags = arg->value.search_flags;
a020eb653b2620a989e4795adceb6136037327b2Timo Sirainenstatic struct mail_search_arg **
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainenmail_search_args_simplify_get_prev_argp(struct mail_search_simplify_ctx *ctx,
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen const struct mail_search_simplify_prev_arg *mask)
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen struct mail_search_simplify_prev_arg *prev_arg;
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen prev_arg = hash_table_lookup(ctx->prev_args, mask);
379175cfba8150d481d9898b78330b719d128d84Timo Sirainen prev_arg = p_new(ctx->pool, struct mail_search_simplify_prev_arg, 1);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen p_strdup(ctx->pool, mask->hdr_field_name_mask);
7b64db32b95286235612eebb5d37d296a49306f7Timo Sirainen hash_table_insert(ctx->prev_args, prev_arg, prev_arg);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic bool mail_search_args_merge_flags(struct mail_search_simplify_ctx *ctx,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (!((!args->match_not && ctx->parent_and) ||
7b64db32b95286235612eebb5d37d296a49306f7Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen (*prev_argp)->value.flags |= args->value.flags;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenstatic bool mail_search_args_merge_set(struct mail_search_simplify_ctx *ctx,
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (!((!args->match_not && ctx->parent_and) ||
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen seq_range_array_merge(&(*prev_argp)->value.seqset,
326c86b1cdb555957b236958e17142e82e34074eTimo Sirainenstatic bool mail_search_args_merge_time(struct mail_search_simplify_ctx *ctx,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen struct mail_search_arg **prev_argp, *prev_arg;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen mask.bin_mask.date_type = args->value.date_type;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
7b64db32b95286235612eebb5d37d296a49306f7Timo Sirainen if (prev_arg->value.time < args->value.time) {
7b64db32b95286235612eebb5d37d296a49306f7Timo Sirainen /* prev_arg < 5 AND arg < 10 */
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen /* prev_arg < 10 AND arg < 5 */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (prev_arg->value.time < args->value.time) {
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen /* prev_arg < 5 OR arg < 10 */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* prev_arg < 10 OR arg < 5 */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (prev_arg->value.time < args->value.time) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* prev_arg >= 5 AND arg >= 10 */
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen /* prev_arg >= 10 AND arg >= 5 */
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (prev_arg->value.time < args->value.time) {
8cca3b43b28365cfee4dc733c00caaeab8ecd2adTimo Sirainen /* prev_arg >= 5 OR arg >= 10 */
1ae5d61ec366fdb2f3c5b150ca378d6141b0f4bdTimo Sirainen /* prev_arg >= 10 OR arg >= 5 */
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainenstatic bool mail_search_args_merge_size(struct mail_search_simplify_ctx *ctx,
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen struct mail_search_arg **prev_argp, *prev_arg;
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (prev_arg->value.size < args->value.size) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* prev_arg < 5 AND arg < 10 */
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen /* prev_arg < 10 AND arg < 5 */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (prev_arg->value.size < args->value.size) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* prev_arg < 5 OR arg < 10 */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* prev_arg < 10 OR arg < 5 */
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen if (prev_arg->value.size < args->value.size) {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen /* prev_arg >= 5 AND arg >= 10 */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* prev_arg >= 10 AND arg >= 5 */
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen if (prev_arg->value.size < args->value.size) {
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen /* prev_arg >= 5 OR arg >= 10 */
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen /* prev_arg >= 10 OR arg >= 5 */
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainenstatic bool mail_search_args_merge_text(struct mail_search_simplify_ctx *ctx,
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen mask.hdr_field_name_mask = args->hdr_field_name;
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask);
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainen /* duplicate search word. */
acfda38b75d0f0e899ef692fef01593bd56ed85eTimo Sirainenmail_search_args_have_equal(const struct mail_search_arg *args,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (mail_search_arg_one_equals(arg, wanted_arg))
d23dfc385f22d7a2c466d29501c9e0ce5a243deeTimo Sirainenmail_search_args_remove_equal(struct mail_search_arg *parent_arg,
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen for (argp = &parent_arg->value.subargs; (*argp) != NULL; ) {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (mail_search_arg_one_equals(*argp, wanted_arg)) {
4654f788834c9d7920a351306b89cf5d1c21772eTimo Sirainen if (!mail_search_args_remove_equal(*argp, wanted_arg, FALSE)) {
94ce7e7700cda14a8342cb08e7285507b4b531daTimo Sirainen /* we already verified that this should have
311d3dd2078c1b711a0cef013ba43a94078c115cTimo Sirainenmail_search_args_have_all_equal(struct mail_search_arg *parent_arg,
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen for (arg = wanted_args; arg != NULL; arg = arg->next) {
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainen if (!mail_search_args_have_equal(parent_arg->value.subargs, arg))
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainenstatic unsigned int
b06633c63fde22b6c8837ae70b2f95fe60075b0aTimo Sirainenmail_search_args_count(const struct mail_search_arg *args)
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen unsigned int count;
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenmail_search_args_simplify_or_drop_redundent_args(struct mail_search_arg *parent_arg)
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen struct mail_search_arg *arg, **argp, one_arg, *lowest_arg = NULL;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* find the arg which has the lowest number of child args */
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen for (arg = parent_arg->value.subargs; arg != NULL; arg = arg->next) {
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen count = mail_search_args_count(arg->value.subargs);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* if there are any args that include lowest_arg, drop the arg since
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen it's redundant. (non-SUB duplicates are dropped elsewhere.) */
9f10cc61ec303351b43e54155c86699ef53cb8beTimo Sirainen for (argp = &parent_arg->value.subargs; *argp != NULL; ) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (*argp != lowest_arg && (*argp)->type == SEARCH_SUB &&
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen mail_search_args_have_all_equal(*argp, lowest_arg)) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenmail_search_args_simplify_extract_common_and(struct mail_search_arg *parent_arg,
326c86b1cdb555957b236958e17142e82e34074eTimo Sirainen struct mail_search_arg *arg, *sub_arg, *sub_next;
326c86b1cdb555957b236958e17142e82e34074eTimo Sirainen struct mail_search_arg *or_arg, *common_args = NULL;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* find the first SEARCH_SUB */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen for (arg = parent_arg->value.subargs; arg != NULL; arg = arg->next) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen for (sub_arg = arg->value.subargs; sub_arg != NULL; sub_arg = sub_next) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen /* check if sub_arg is found from all the args */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen for (arg = parent_arg->value.subargs; arg != NULL; arg = arg->next) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (mail_search_arg_one_equals(arg, sub_arg)) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen /* the whole arg matches */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen mail_search_args_have_equal(arg->value.subargs, sub_arg)) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen /* exists as subarg */
117a55d4260651770705ecb96f68be2dab03b99bTimo Sirainen /* extract the arg and put it to common_args */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen mail_search_args_remove_equal(parent_arg, sub_arg, TRUE);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen /* there are only common args */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen /* replace OR arg with AND(common_args, OR(non_common_args)) */
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen or_arg = p_new(pool, struct mail_search_arg, 1);
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainenmail_search_args_simplify_sub(struct mailbox *box, pool_t pool,
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen struct mail_search_arg *args, bool parent_and)
287b5ba23f182fd98e7a6ba3a63669c1572f2ca4Timo Sirainen ctx.pool = pool_alloconly_create("mail search args simplify", 1024);
287b5ba23f182fd98e7a6ba3a63669c1572f2ca4Timo Sirainen hash_table_create(&ctx.prev_args, ctx.pool, 0,
527c2b071dca35b91648344e867ab1af9c988281Baofeng Wang if (args->match_not && (args->type == SEARCH_SUB ||
527c2b071dca35b91648344e867ab1af9c988281Baofeng Wang /* neg(p and q and ..) == neg(p) or neg(q) or ..
527c2b071dca35b91648344e867ab1af9c988281Baofeng Wang neg(p or q or ..) == neg(p) and neg(q) and .. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if ((args->type == SEARCH_SUB && parent_and) ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ((args->type == SEARCH_SUB || args->type == SEARCH_OR) &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* p and (q and ..) == p and q and ..
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p or (q or ..) == p or q or ..
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (mail_search_args_simplify_or_drop_redundent_args(args))
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (mail_search_args_simplify_extract_common_and(args, pool))
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (mail_search_args_simplify_sub(box, pool, args->value.subargs,
cb17980a661554ebb3fd099c77e92a5be4d304ecTimo Sirainen /* try to merge arguments */
d2c853636ec2d99c9f96da877ff520a3b86a18baTimo Sirainen merged = mail_search_args_merge_flags(&ctx, args);
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen merged = mail_search_args_merge_set(&ctx, args);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen merged = mail_search_args_merge_time(&ctx, args);
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen merged = mail_search_args_merge_size(&ctx, args);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen merged = mail_search_args_merge_text(&ctx, args);
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainenmail_search_args_unnest_inthreads(struct mail_search_args *args,
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen struct mail_search_arg *arg, *thread_arg, *or_arg;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen bool child_inthreads = FALSE, non_inthreads = FALSE;
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen for (arg = *argp; arg != NULL; arg = arg->next) {
87ca4b209c10954826b878da165d303d9b4dc5a2Timo Sirainen /* children converted to SEARCH_INTHREADs */
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen if (!parent_inthreads || !child_inthreads || !non_inthreads)
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen /* put all non-INTHREADs under a single INTHREAD */
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen thread_arg = p_new(args->pool, struct mail_search_arg, 1);
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen /* not an INTHREAD or a SUB/OR with only INTHREADs */
9f7441a47863d44ec303c7980b499b46b3d1671bTimo Sirainen /* We want to OR the args */
9f7441a47863d44ec303c7980b499b46b3d1671bTimo Sirainen or_arg = p_new(args->pool, struct mail_search_arg, 1);
1e40531c1de45bc87e72a9d5866ff2af79b63cebTimo Sirainen or_arg->value.subargs = thread_arg->value.subargs;
1701b354e81ff1dfd0b6c7bb4412b8d9c2b9f986Timo Sirainenvoid mail_search_args_simplify(struct mail_search_args *args)
1701b354e81ff1dfd0b6c7bb4412b8d9c2b9f986Timo Sirainen removals = mail_search_args_simplify_sub(args->box, args->pool, args->args, TRUE);
1701b354e81ff1dfd0b6c7bb4412b8d9c2b9f986Timo Sirainen if (mail_search_args_unnest_inthreads(args, &args->args,
1701b354e81ff1dfd0b6c7bb4412b8d9c2b9f986Timo Sirainen /* we may have added some extra SUBs that could be dropped */
1701b354e81ff1dfd0b6c7bb4412b8d9c2b9f986Timo Sirainen if (mail_search_args_simplify_sub(args->box, args->pool, args->args, TRUE))