]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: mail_search_args_simplify() merges now seqsets and uidsets.
authorTimo Sirainen <tss@iki.fi>
Thu, 23 Apr 2015 17:16:54 +0000 (20:16 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 23 Apr 2015 17:16:54 +0000 (20:16 +0300)
src/lib-storage/mail-search-args-simplify.c
src/lib-storage/test-mail-search-args-simplify.c

index dda0901e8191b09154e3f6b6fb783bf4078c8132..76781195ae383a706ddc6856af50a112c3d352e5 100644 (file)
@@ -3,15 +3,58 @@
 #include "lib.h"
 #include "mail-search.h"
 
+struct mail_search_simplify_ctx {
+       struct mail_search_arg *prev_flags, *prev_not_flags;
+       struct mail_search_arg *prev_seqset, *prev_not_seqset;
+       struct mail_search_arg *prev_uidset, *prev_not_uidset;
+       bool removals;
+};
+
+static bool mail_search_args_merge_flags(struct mail_search_simplify_ctx *ctx,
+                                        struct mail_search_arg *args)
+{
+       struct mail_search_arg **prev_argp;
+
+       prev_argp = !args->match_not ? &ctx->prev_flags : &ctx->prev_not_flags;
+       if (*prev_argp == NULL) {
+               *prev_argp = args;
+               return FALSE;
+       } else {
+               (*prev_argp)->value.flags |= args->value.flags;
+               return TRUE;
+       }
+}
+
+static bool mail_search_args_merge_set(struct mail_search_simplify_ctx *ctx,
+                                      struct mail_search_arg *args)
+{
+       struct mail_search_arg **prev_argp;
+
+       if (args->type == SEARCH_SEQSET) {
+               prev_argp = !args->match_not ? &ctx->prev_seqset :
+                       &ctx->prev_not_seqset;
+       } else {
+               prev_argp = !args->match_not ? &ctx->prev_uidset :
+                       &ctx->prev_not_uidset;
+       }
+       if (*prev_argp == NULL) {
+               *prev_argp = args;
+               return FALSE;
+       } else {
+               seq_range_array_merge(&(*prev_argp)->value.seqset,
+                                     &args->value.seqset);
+               return TRUE;
+       }
+}
+
 static bool
 mail_search_args_simplify_sub(struct mailbox *box,
                              struct mail_search_arg *args, bool parent_and)
 {
-       struct mail_search_arg *sub, *prev = NULL;
-       struct mail_search_arg *prev_flags_arg, *prev_not_flags_arg;
-       bool removals;
+       struct mail_search_simplify_ctx ctx;
+       struct mail_search_arg *sub, *prev_arg = NULL;
 
-       prev_flags_arg = prev_not_flags_arg = NULL;
+       memset(&ctx, 0, sizeof(ctx));
        while (args != NULL) {
                if (args->match_not && (args->type == SEARCH_SUB ||
                                        args->type == SEARCH_OR)) {
@@ -46,40 +89,39 @@ mail_search_args_simplify_sub(struct mailbox *box,
                    args->type == SEARCH_INTHREAD) {
                        if (mail_search_args_simplify_sub(box, args->value.subargs,
                                                          args->type != SEARCH_OR))
-                               removals = TRUE;
+                               ctx.removals = TRUE;
                }
 
-               /* merge all flags arguments */
-               if (args->type == SEARCH_FLAGS &&
-                   !args->match_not && parent_and) {
-                       if (prev_flags_arg == NULL)
-                               prev_flags_arg = args;
-                       else {
-                               prev_flags_arg->value.flags |=
-                                       args->value.flags;
-                               prev->next = args->next;
-                               args = args->next;
-                               removals = TRUE;
-                               continue;
+               if ((!args->match_not && parent_and) ||
+                   (args->match_not && !parent_and)) {
+                       /* try to merge arguments */
+                       bool merged;
+
+                       switch (args->type) {
+                       case SEARCH_FLAGS:
+                               merged = mail_search_args_merge_flags(&ctx, args);
+                               break;
+                       case SEARCH_SEQSET:
+                       case SEARCH_UIDSET:
+                               merged = mail_search_args_merge_set(&ctx, args);
+                               break;
+                       case SEARCH_BEFORE:
+                       default:
+                               merged = FALSE;
+                               break;
                        }
-               } else if (args->type == SEARCH_FLAGS && args->match_not &&
-                          !parent_and) {
-                       if (prev_not_flags_arg == NULL)
-                               prev_not_flags_arg = args;
-                       else {
-                               prev_not_flags_arg->value.flags |=
-                                       args->value.flags;
-                               prev->next = args->next;
+                       if (merged) {
+                               prev_arg->next = args->next;
                                args = args->next;
-                               removals = TRUE;
+                               ctx.removals = TRUE;
                                continue;
                        }
                }
 
-               prev = args;
+               prev_arg = args;
                args = args->next;
        }
-       return removals;
+       return ctx.removals;
 }
 
 static bool
index 0d03152158064b0bcd2224d095dc8f389481af63..fd7d77c36c04ec7b98c24903ecae61730a792fe4 100644 (file)
@@ -32,7 +32,24 @@ struct {
        { "OR ( ANSWERED FLAGGED SEEN ) DRAFT", "(OR (ANSWERED FLAGGED SEEN) (DRAFT))" },
        { "ANSWERED TEXT foo FLAGGED SEEN", "(ANSWERED FLAGGED SEEN) TEXT foo" },
        { "NOT ( ANSWERED FLAGGED SEEN )", "NOT (ANSWERED FLAGGED SEEN)" },
-       { "OR NOT ANSWERED OR NOT FLAGGED NOT SEEN", "NOT (ANSWERED FLAGGED SEEN)" }
+       { "OR NOT ANSWERED OR NOT FLAGGED NOT SEEN", "NOT (ANSWERED FLAGGED SEEN)" },
+       { "ANSWERED NOT FLAGGED SEEN NOT DRAFT", "(ANSWERED SEEN) NOT (FLAGGED) NOT (DRAFT)" },
+       { "OR NOT ANSWERED NOT SEEN", "NOT (ANSWERED SEEN)" },
+
+       { "1:5 10:20", "1:5,10:20" },
+       { "1:5 NOT 10:20", "1:5 NOT 10:20" },
+       { "1:5 NOT 10:20 NOT 30:40", "1:5 NOT 10:20 NOT 30:40" },
+       { "OR 1:5 NOT 10:20", "(OR 1:5 NOT 10:20)" },
+       { "OR 1:5 OR NOT 10:20 NOT 30:40", "(OR 1:5 NOT 10:20,30:40)" },
+
+       { "UID 1:5 UID 10:20", "UID 1:5,10:20" },
+       { "UID 1:5 NOT UID 10:20", "UID 1:5 NOT UID 10:20" },
+       { "UID 1:5 NOT UID 10:20 NOT UID 30:40", "UID 1:5 NOT UID 10:20 NOT UID 30:40" },
+       { "OR UID 1:5 NOT UID 10:20", "(OR UID 1:5 NOT UID 10:20)" },
+       { "OR UID 1:5 OR NOT UID 10:20 NOT UID 30:40", "(OR UID 1:5 NOT UID 10:20,30:40)" },
+
+       { "1:5 UID 10:20", "1:5 UID 10:20" },
+       { "1:5 NOT UID 10:20", "1:5 NOT UID 10:20" }
 };
 
 static struct mail_search_args *