mail-search-args-simplify.c revision df8046c9a4f6bc2a478ad1e74504d50f3110c906
/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "hash.h"
#include "mail-search.h"
struct mail_search_simplify_prev_arg {
struct {
enum mail_search_arg_type type;
bool match_not;
bool fuzzy;
} bin_mask;
const char *hdr_field_name_mask;
const char *str_mask;
struct mail_search_arg *prev_arg;
};
struct mail_search_simplify_ctx {
/* arg mask => prev_arg */
HASH_TABLE(struct mail_search_simplify_prev_arg *,
struct mail_search_simplify_prev_arg *) prev_args;
bool parent_and;
bool removals;
};
static int
const struct mail_search_simplify_prev_arg *arg2)
{
int ret;
if (ret == 0)
if (ret == 0)
return ret;
}
static unsigned int
{
unsigned int hash;
return hash;
}
struct mail_search_simplify_prev_arg *mask_r)
{
}
static struct mail_search_arg **
const struct mail_search_simplify_prev_arg *mask)
{
struct mail_search_simplify_prev_arg *prev_arg;
}
}
struct mail_search_arg *args)
{
struct mail_search_simplify_prev_arg mask;
struct mail_search_arg **prev_argp;
return FALSE;
return FALSE;
} else {
return TRUE;
}
}
{
unsigned int count;
/* invert the set to drop the NOT */
}
/* 1:* is the same as ALL. */
} else if (count == 0) {
/* empty set is the same as NOT ALL. this is mainly coming
from mail_search_args_merge_set() intersection. */
}
}
struct mail_search_arg *args)
{
struct mail_search_simplify_prev_arg mask;
struct mail_search_arg **prev_argp;
return FALSE;
} else if (ctx->parent_and) {
return TRUE;
} else {
return TRUE;
}
}
struct mail_search_arg *args)
{
struct mail_search_simplify_prev_arg mask;
return FALSE;
}
case SEARCH_BEFORE:
if (ctx->parent_and) {
/* prev_arg < 5 AND arg < 10 */
} else {
/* prev_arg < 10 AND arg < 5 */
}
} else {
/* prev_arg < 5 OR arg < 10 */
} else {
/* prev_arg < 10 OR arg < 5 */
}
}
return TRUE;
case SEARCH_ON:
return TRUE;
return FALSE;
case SEARCH_SINCE:
if (ctx->parent_and) {
/* prev_arg >= 5 AND arg >= 10 */
} else {
/* prev_arg >= 10 AND arg >= 5 */
}
} else {
/* prev_arg >= 5 OR arg >= 10 */
} else {
/* prev_arg >= 10 OR arg >= 5 */
}
}
return TRUE;
default:
break;
}
return FALSE;
}
struct mail_search_arg *args)
{
struct mail_search_simplify_prev_arg mask;
return FALSE;
}
case SEARCH_SMALLER:
if (ctx->parent_and) {
/* prev_arg < 5 AND arg < 10 */
} else {
/* prev_arg < 10 AND arg < 5 */
}
} else {
/* prev_arg < 5 OR arg < 10 */
} else {
/* prev_arg < 10 OR arg < 5 */
}
}
return TRUE;
case SEARCH_LARGER:
if (ctx->parent_and) {
/* prev_arg >= 5 AND arg >= 10 */
} else {
/* prev_arg >= 10 AND arg >= 5 */
}
} else {
/* prev_arg >= 5 OR arg >= 10 */
} else {
/* prev_arg >= 10 OR arg >= 5 */
}
}
return TRUE;
default:
break;
}
return FALSE;
}
struct mail_search_arg *args)
{
struct mail_search_simplify_prev_arg mask;
struct mail_search_arg **prev_argp;
return FALSE;
}
/* duplicate search word. */
return TRUE;
}
static bool
const struct mail_search_arg *wanted_arg)
{
const struct mail_search_arg *arg;
return TRUE;
}
return FALSE;
}
static bool
const struct mail_search_arg *wanted_arg,
bool check_subs)
{
struct mail_search_arg **argp;
} else if (check_subs) {
/* we already verified that this should have
existed. */
i_unreached();
}
else
} else {
}
}
return found;
}
static bool
const struct mail_search_arg *wanted_args)
{
const struct mail_search_arg *arg;
return FALSE;
}
return TRUE;
}
static unsigned int
{
unsigned int count;
return count;
}
static bool
bool and_arg)
{
return FALSE;
/* find the arg which has the lowest number of child args */
lowest_arg = &one_arg;
break;
}
if (count < lowest_count) {
}
}
/* if there are any args that include lowest_arg, drop the arg since
it's redundant. (non-SUB duplicates are dropped elsewhere.) */
} else {
}
}
return ret;
}
static bool
{
/* Simple SUB example:
(a AND b) OR (a AND c) -> a AND (b OR c)
More complicated example:
(c1 AND c2 AND u1 AND u2) OR (c1 AND c2 AND u3 AND u4) ->
c1 AND c2 AND ((u1 AND u2) OR (u3 AND u4))
Similarly for ORs:
(a OR b) AND (a OR c) -> a OR (b AND c)
(c1 OR c2 OR u1 OR u2) AND (c1 OR c2 OR u3 OR u4) ->
c1 OR c2 OR ((u1 OR u2) AND (u3 OR u4))
*/
/* single arg, nothing to extract */
return FALSE;
}
/* find the first arg with child_subargs_type */
break;
}
return FALSE;
/* check if sub_arg is found from all the args */
/* the whole arg matches */
/* exists as subarg */
} else {
break;
}
}
continue;
/* extract the arg and put it to common_args */
}
if (common_args == NULL)
return FALSE;
/* there are only common args */
} else {
/* replace OR arg with AND(OR(non_common_args), common_args)
or
replace AND arg with OR(AND(non_common_args), common_args) */
}
return TRUE;
}
static bool
{
struct mail_search_simplify_ctx ctx;
bool merged;
/* neg(p and q and ..) == neg(p) or neg(q) or ..
neg(p or q or ..) == neg(p) and neg(q) and .. */
do {
}
/* p and (q and ..) == p and q and ..
p or (q or ..) == p or q or ..
(p) = p */
continue;
}
}
}
/* try to merge arguments */
case SEARCH_ALL: {
/* this arg has no siblings - no merging */
break;
}
/* .. AND ALL ..
.. OR NOT ALL ..
This arg is irrelevant -> drop */
break;
}
/* .. AND NOT ALL ..
.. OR ALL ..
The other args are irrelevant -> drop them */
break;
}
case SEARCH_FLAGS:
break;
case SEARCH_SEQSET:
case SEARCH_UIDSET:
break;
case SEARCH_BEFORE:
case SEARCH_ON:
case SEARCH_SINCE:
break;
case SEARCH_SMALLER:
case SEARCH_LARGER:
break;
case SEARCH_BODY:
case SEARCH_TEXT:
/* BODY "" and TEXT "" matches everything */
break;
}
/* fall through */
case SEARCH_HEADER:
case SEARCH_HEADER_ADDRESS:
break;
default:
break;
}
if (merged) {
continue;
}
}
}
static bool
struct mail_search_arg **argp,
bool parent_inthreads, bool parent_and)
{
case SEARCH_SUB:
case SEARCH_OR:
} else {
}
break;
case SEARCH_INTHREAD:
/* children converted to SEARCH_INTHREADs */
}
break;
default:
break;
}
}
return FALSE;
/* put all non-INTHREADs under a single INTHREAD */
}
}
if (!parent_and) {
/* We want to OR the args */
}
return TRUE;
}
{
bool removals;
/* we may have added some extra SUBs that could be dropped */
}
for (;;) {
if (!removals)
break;
}
}