Mercurial > dovecot > core-2.2
changeset 21965:8ec0f067fab1
lib-storage: mail_search_args_simplify() - deduplicate flags
This needs to be done in a bit more complicated way because multiple
SEARCH_FLAGS parameters are wanted to be merged together using a single
shared value.flags. Move this merging last after all the deduplication is
done.
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Thu, 13 Apr 2017 15:13:19 +0300 |
parents | ffeadb7ead57 |
children | 44eb00aedb43 |
files | src/lib-storage/mail-search-args-simplify.c src/lib-storage/test-mail-search-args-simplify.c |
diffstat | 2 files changed, 57 insertions(+), 20 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/mail-search-args-simplify.c Thu Apr 13 15:09:19 2017 +0300 +++ b/src/lib-storage/mail-search-args-simplify.c Thu Apr 13 15:13:19 2017 +0300 @@ -10,6 +10,7 @@ enum mail_search_arg_type type; enum mail_search_arg_flag search_flags; enum mail_search_date_type date_type; + enum mail_flags mail_flags; bool match_not; bool fuzzy; } bin_mask; @@ -108,23 +109,10 @@ struct mail_search_arg *args) { struct mail_search_simplify_prev_arg mask; - struct mail_search_arg **prev_argp; - - if (!((!args->match_not && ctx->parent_and) || - (args->match_not && !ctx->parent_and))) - return FALSE; mail_search_arg_get_base_mask(args, &mask); - mask.bin_mask.match_not = args->match_not; - prev_argp = mail_search_args_simplify_get_prev_argp(ctx, &mask); - - if (*prev_argp == NULL) { - *prev_argp = args; - return FALSE; - } else { - (*prev_argp)->value.flags |= args->value.flags; - return TRUE; - } + mask.bin_mask.mail_flags = args->value.flags; + return mail_search_args_merge_mask(ctx, args, &mask); } static bool @@ -664,6 +652,42 @@ } static bool +mail_search_args_simplify_merge_flags(struct mail_search_arg **argsp, + bool parent_and) +{ + struct mail_search_arg *prev_flags = NULL; + bool removals = FALSE; + + while (*argsp != NULL) { + struct mail_search_arg *args = *argsp; + + if (args->type == SEARCH_SUB || + args->type == SEARCH_OR || + args->type == SEARCH_INTHREAD) { + if (mail_search_args_simplify_merge_flags(&args->value.subargs, + args->type != SEARCH_OR)) + removals = TRUE; + } else if (args->type != SEARCH_FLAGS) { + /* ignore non-flags */ + } else if (!((!args->match_not && parent_and) || + (args->match_not && !parent_and))) { + /* can't merge these flags args */ + } else if (prev_flags == NULL) { + /* first flags arg */ + prev_flags = args; + } else { + /* merge to previous arg */ + prev_flags->value.flags |= args->value.flags; + *argsp = args->next; + removals = TRUE; + continue; + } + argsp = &args->next; + } + return removals; +} + +static bool mail_search_args_unnest_inthreads(struct mail_search_args *args, struct mail_search_arg **argp, bool parent_inthreads, bool parent_and) @@ -742,13 +766,18 @@ if (mail_search_args_simplify_sub(args->box, args->pool, &args->args, TRUE)) removals = TRUE; } - for (;;) { + do { if (mail_search_args_simplify_drop_redundant_args(&args->args, TRUE)) removals = TRUE; if (mail_search_args_simplify_extract_common(&args->args, args->pool, TRUE)) removals = TRUE; - if (!removals) - break; - removals = mail_search_args_simplify_sub(args->box, args->pool, &args->args, TRUE); - } + if (removals) + removals = mail_search_args_simplify_sub(args->box, args->pool, &args->args, TRUE); + /* do the flag merging into a single arg only at the end. + up until then they're treated as any other search args, + which simplifies their handling. after the flags merging is + done, further simplifications are still possible. */ + if (mail_search_args_simplify_merge_flags(&args->args, TRUE)) + removals = TRUE; + } while (removals); }
--- a/src/lib-storage/test-mail-search-args-simplify.c Thu Apr 13 15:09:19 2017 +0300 +++ b/src/lib-storage/test-mail-search-args-simplify.c Thu Apr 13 15:13:19 2017 +0300 @@ -51,6 +51,14 @@ { "OR NOT ANSWERED NOT SEEN", "NOT (ANSWERED SEEN)" }, { "OR NOT ANSWERED OR NOT SEEN TEXT foo", "(OR NOT (ANSWERED SEEN) TEXT foo)" }, + { "ANSWERED ANSWERED", "ANSWERED" }, + { "ANSWERED NOT ANSWERED", "NOT ALL" }, + { "ANSWERED ANSWERED NOT ANSWERED", "NOT ALL" }, + { "ANSWERED NOT ANSWERED ANSWERED NOT ANSWERED", "NOT ALL" }, + { "NOT ANSWERED NOT ANSWERED", "NOT ANSWERED" }, + { "NOT SEEN NOT ANSWERED NOT ANSWERED", "NOT SEEN NOT ANSWERED" }, + { "OR NOT SEEN OR NOT ANSWERED NOT ANSWERED", "NOT (ANSWERED SEEN)" }, + { "KEYWORD foo", "KEYWORD foo" }, { "KEYWORD foo KEYWORD bar", "KEYWORD foo KEYWORD bar" }, { "NOT KEYWORD foo", "NOT KEYWORD foo" },