]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Added search query building from human-friendly input.
authorTimo Sirainen <tss@iki.fi>
Tue, 13 Apr 2010 17:25:00 +0000 (20:25 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 13 Apr 2010 17:25:00 +0000 (20:25 +0300)
--HG--
branch : HEAD

src/imap/imap-search-args.c
src/lib-storage/Makefile.am
src/lib-storage/mail-search-build.c
src/lib-storage/mail-search-build.h
src/lib-storage/mail-search-register-human.c [new file with mode: 0644]
src/lib-storage/mail-search-register-imap.c
src/lib-storage/mail-search-register.c
src/lib-storage/mail-search-register.h
src/lib-storage/mail-storage-private.h
src/lib-storage/mail-storage.c
src/plugins/virtual/virtual-config.c

index 74326a80b2ddf095f6cecd2829ad4fccb6c2a4a1..1980bc106040e6dfc66154a8682f4cd3e249823f 100644 (file)
@@ -47,7 +47,8 @@ int imap_search_args_build(struct client_command_context *cmd,
                return -1;
        }
 
-       if (mail_search_build_from_imap_args(args, charset,
+       if (mail_search_build_from_imap_args(mail_search_register_imap,
+                                            args, charset,
                                             &sargs, &error) < 0) {
                client_send_command_error(cmd, error);
                return -1;
index 189f0c6c6336f26545168c7683a841a75d8d82af..472fbf83eb636b4727dfbb98eebefdfc65296a10 100644 (file)
@@ -23,6 +23,7 @@ libstorage_la_SOURCES = \
        mail-search.c \
        mail-search-build.c \
        mail-search-register.c \
+       mail-search-register-human.c \
        mail-search-register-imap.c \
        mail-storage.c \
        mail-storage-hooks.c \
index 6eac850bbcb190895e8eab58ce9644744f8d3027..35bcb90ff9a68109b9fd78c2c10b93ee2bf19a3f 100644 (file)
@@ -8,16 +8,63 @@
 
 #include <stdlib.h>
 
+int mail_search_build_next_astring(struct mail_search_build_context *ctx,
+                                  const struct imap_arg **imap_args,
+                                  const char **value_r)
+{
+       if (IMAP_ARG_IS_EOL(*imap_args)) {
+               ctx->error = "Missing parameter for argument";
+               return -1;
+       }
+       if (!imap_arg_get_astring(*imap_args, value_r)) {
+               ctx->error = "Invalid parameter for argument";
+               return -1;
+       }
+
+       *imap_args += 1;
+       return 0;
+}
+
+struct mail_search_arg *
+mail_search_build_new(struct mail_search_build_context *ctx,
+                     enum mail_search_arg_type type)
+{
+       struct mail_search_arg *arg;
+
+       arg = p_new(ctx->pool, struct mail_search_arg, 1);
+       arg->type = type;
+       return arg;
+}
+
+struct mail_search_arg *
+mail_search_build_str(struct mail_search_build_context *ctx,
+                     const struct imap_arg **imap_args,
+                     enum mail_search_arg_type type)
+{
+       struct mail_search_arg *sarg;
+       const char *value;
+
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+               return NULL;
+       sarg->value.str = p_strdup(ctx->pool, value);
+       return sarg;
+}
+
 struct mail_search_arg *
 mail_search_build_next(struct mail_search_build_context *ctx,
+                      struct mail_search_arg *parent,
                       const struct imap_arg **imap_args)
 {
-       struct mail_search_arg **subargs, *sarg;
+       struct mail_search_arg *sarg;
+       struct mail_search_arg *old_parent = ctx->parent;
        const struct imap_arg *listargs;
        const char *key;
        const struct mail_search_register_arg *reg_arg;
        mail_search_register_fallback_t *fallback;
 
+       ctx->parent = parent;
+
        if (IMAP_ARG_IS_EOL(*imap_args)) {
                ctx->error = "Missing argument";
                return NULL;
@@ -35,17 +82,9 @@ mail_search_build_next(struct mail_search_build_context *ctx,
                        return NULL;
                }
 
-               sarg = p_new(ctx->pool, struct mail_search_arg, 1);
-               sarg->type = SEARCH_SUB;
-               subargs = &sarg->value.subargs;
-               while (!IMAP_ARG_IS_EOL(listargs)) {
-                       *subargs = mail_search_build_next(ctx, &listargs);
-                       if (*subargs == NULL)
-                               return NULL;
-                       subargs = &(*subargs)->next;
-               }
-
+               sarg = mail_search_build_list(ctx, listargs);
                *imap_args += 1;
+               ctx->parent = old_parent;
                return sarg;
        }
 
@@ -64,17 +103,54 @@ mail_search_build_next(struct mail_search_build_context *ctx,
                ctx->error = p_strconcat(ctx->pool, "Unknown argument ",
                                         key, NULL);
        }
+
+       ctx->parent = old_parent;
+       return sarg;
+}
+
+struct mail_search_arg *
+mail_search_build_list(struct mail_search_build_context *ctx,
+                      const struct imap_arg *imap_args)
+{
+       struct mail_search_arg *sarg, **subargs;
+       enum mail_search_arg_type cur_type = SEARCH_SUB;
+
+       sarg = p_new(ctx->pool, struct mail_search_arg, 1);
+       sarg->type = cur_type;
+
+       subargs = &sarg->value.subargs;
+       while (!IMAP_ARG_IS_EOL(imap_args)) {
+               sarg->type = SEARCH_SUB;
+               *subargs = mail_search_build_next(ctx, sarg, &imap_args);
+               if (*subargs == NULL)
+                       return NULL;
+
+               if (cur_type == sarg->type) {
+                       /* expected type */
+               } else if (cur_type == SEARCH_SUB) {
+                       /* type changed. everything in this list must now
+                          belong to this type. */
+                       cur_type = sarg->type;
+               } else {
+                       ctx->error = cur_type == SEARCH_OR ?
+                               "Use parenthesis when using ORs" :
+                               "Use parenthesis when mixing subtypes";
+                       return NULL;
+               }
+               subargs = &(*subargs)->next;
+       }
        return sarg;
 }
 
-int mail_search_build_from_imap_args(const struct imap_arg *imap_args,
+int mail_search_build_from_imap_args(struct mail_search_register *reg,
+                                    const struct imap_arg *imap_args,
                                     const char *charset,
                                     struct mail_search_args **args_r,
                                     const char **error_r)
 {
         struct mail_search_build_context ctx;
        struct mail_search_args *args;
-       struct mail_search_arg **sargs;
+       struct mail_search_arg *root;
 
        *args_r = NULL;
        *error_r = NULL;
@@ -84,17 +160,20 @@ int mail_search_build_from_imap_args(const struct imap_arg *imap_args,
 
        memset(&ctx, 0, sizeof(ctx));
        ctx.pool = args->pool;
-       ctx.reg = mail_search_register_imap;
+       ctx.reg = reg;
 
-       sargs = &args->args;
-       while (!IMAP_ARG_IS_EOL(imap_args)) {
-               *sargs = mail_search_build_next(&ctx, &imap_args);
-               if (*sargs == NULL) {
-                       *error_r = t_strdup(ctx.error);
-                       pool_unref(&args->pool);
-                       return -1;
-               }
-               sargs = &(*sargs)->next;
+       root = mail_search_build_list(&ctx, imap_args);
+       if (root == NULL) {
+               *error_r = t_strdup(ctx.error);
+               pool_unref(&args->pool);
+               return -1;
+       }
+
+       if (root->type == SEARCH_SUB && !root->not) {
+               /* simple SUB root */
+               args->args = root->value.subargs;
+       } else {
+               args->args = root;
        }
 
        *args_r = args;
index 880bdf0307ba7e6f33ee5d5b6aa8296d09e798f7..2fd7a6b625496668a253e08cf4b089972300a283 100644 (file)
@@ -2,6 +2,7 @@
 #define MAIL_SEARCH_BUILD_H
 
 #include "mail-search.h"
+#include "mail-search-register.h"
 
 struct imap_arg;
 struct mailbox;
@@ -9,6 +10,8 @@ struct mailbox;
 struct mail_search_build_context {
        pool_t pool;
        struct mail_search_register *reg;
+
+       struct mail_search_arg *parent;
        const char *error;
 };
 
@@ -17,7 +20,8 @@ struct mail_search_build_context {
 struct mail_search_args *mail_search_build_init(void);
 
 /* Convert IMAP SEARCH command compatible parameters to mail_search_args. */
-int mail_search_build_from_imap_args(const struct imap_arg *imap_args,
+int mail_search_build_from_imap_args(struct mail_search_register *reg,
+                                    const struct imap_arg *imap_args,
                                     const char *charset,
                                     struct mail_search_args **args_r,
                                     const char **error_r);
@@ -28,8 +32,23 @@ void mail_search_build_add_all(struct mail_search_args *args);
 void mail_search_build_add_seqset(struct mail_search_args *args,
                                  uint32_t seq1, uint32_t seq2);
 
+int mail_search_build_next_astring(struct mail_search_build_context *ctx,
+                                  const struct imap_arg **imap_args,
+                                  const char **value_r);
+
+struct mail_search_arg *
+mail_search_build_new(struct mail_search_build_context *ctx,
+                     enum mail_search_arg_type type);
+struct mail_search_arg *
+mail_search_build_str(struct mail_search_build_context *ctx,
+                     const struct imap_arg **imap_args,
+                     enum mail_search_arg_type type);
 struct mail_search_arg *
 mail_search_build_next(struct mail_search_build_context *ctx,
+                      struct mail_search_arg *parent,
                       const struct imap_arg **imap_args);
+struct mail_search_arg *
+mail_search_build_list(struct mail_search_build_context *ctx,
+                      const struct imap_arg *imap_args);
 
 #endif
diff --git a/src/lib-storage/mail-search-register-human.c b/src/lib-storage/mail-search-register-human.c
new file mode 100644 (file)
index 0000000..c652d10
--- /dev/null
@@ -0,0 +1,202 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "array.h"
+#include "settings-parser.h"
+#include "imap-date.h"
+#include "mail-search-register.h"
+#include "mail-search-build.h"
+
+#include <time.h>
+#include <ctype.h>
+
+struct mail_search_register *mail_search_register_human;
+
+static struct mail_search_arg *
+human_search_or(struct mail_search_build_context *ctx,
+               const struct imap_arg **imap_args)
+{
+       /* this changes the parent arg to be an OR block instead of AND block */
+       ctx->parent->type = SEARCH_OR;
+       return mail_search_build_next(ctx, ctx->parent, imap_args);
+}
+
+static struct mail_search_arg *
+arg_new_human_date(struct mail_search_build_context *ctx,
+                  const struct imap_arg **imap_args,
+                  enum mail_search_arg_type type,
+                  enum mail_search_date_type date_type)
+{
+       struct mail_search_arg *sarg;
+       const char *value, *error;
+       struct tm tm;
+       unsigned int secs;
+       int tz;
+
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+               return NULL;
+
+       /* a) yyyy-mm-dd
+          b) imap date-time
+          c) interval (e.g. n days) */
+       if (i_isdigit(value[0]) && i_isdigit(value[1]) &&
+           i_isdigit(value[2]) && i_isdigit(value[3]) && value[4] == '-' &&
+           i_isdigit(value[5]) && i_isdigit(value[6]) && value[7] == '-' &&
+           i_isdigit(value[8]) && i_isdigit(value[9]) && value[10] == '\0') {
+               memset(&tm, 0, sizeof(tm));
+               tm.tm_year = (value[0]-'0') * 1000 + (value[1]-'0') * 100 +
+                       (value[2]-'0') * 10 + (value[3]-'0');
+               tm.tm_mon = (value[5]-'0') * 10 + (value[6]-'0') - 1;
+               tm.tm_mday = (value[8]-'0') * 10 + (value[9]-'0');
+               sarg->value.time = mktime(&tm);
+       } else if (imap_parse_datetime(value, &sarg->value.time, &tz)) {
+               /* imap date */
+       } else if (settings_get_time(value, &secs, &error) == 0) {
+               sarg->value.time = ioloop_time - secs;
+       } else {
+               sarg->value.time = (time_t)-1;
+       }
+       sarg->value.search_flags = MAIL_SEARCH_ARG_FLAG_USE_TZ;
+
+       if (sarg->value.time == (time_t)-1) {
+               ctx->error = p_strconcat(ctx->pool,
+                       "Invalid search date parameter: ", value, NULL);
+               return NULL;
+       }
+       sarg->value.date_type = date_type;
+       return sarg;
+}
+
+#define CALLBACK_DATE(_func, _type, _date_type) \
+static struct mail_search_arg *\
+human_search_##_func(struct mail_search_build_context *ctx, \
+                     const struct imap_arg **imap_args) \
+{ \
+       return arg_new_human_date(ctx, imap_args, _type, _date_type); \
+}
+CALLBACK_DATE(before, SEARCH_BEFORE, MAIL_SEARCH_DATE_TYPE_RECEIVED);
+CALLBACK_DATE(on, SEARCH_ON, MAIL_SEARCH_DATE_TYPE_RECEIVED);
+CALLBACK_DATE(since, SEARCH_SINCE, MAIL_SEARCH_DATE_TYPE_RECEIVED);
+
+CALLBACK_DATE(sentbefore, SEARCH_BEFORE, MAIL_SEARCH_DATE_TYPE_SENT);
+CALLBACK_DATE(senton, SEARCH_ON, MAIL_SEARCH_DATE_TYPE_SENT);
+CALLBACK_DATE(sentsince, SEARCH_SINCE, MAIL_SEARCH_DATE_TYPE_SENT);
+
+CALLBACK_DATE(savedbefore, SEARCH_BEFORE, MAIL_SEARCH_DATE_TYPE_SAVED);
+CALLBACK_DATE(savedon, SEARCH_ON, MAIL_SEARCH_DATE_TYPE_SAVED);
+CALLBACK_DATE(savedsince, SEARCH_SINCE, MAIL_SEARCH_DATE_TYPE_SAVED);
+
+static struct mail_search_arg *
+arg_new_human_size(struct mail_search_build_context *ctx,
+                  const struct imap_arg **imap_args,
+                  enum mail_search_arg_type type)
+{
+       struct mail_search_arg *sarg;
+       const char *value, *error;
+
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+               return NULL;
+
+       if (settings_get_size(value, &sarg->value.size, &error) < 0) {
+               ctx->error = p_strdup(ctx->pool, error);
+               return NULL;
+       }
+       return sarg;
+}
+
+static struct mail_search_arg *
+human_search_larger(struct mail_search_build_context *ctx,
+                   const struct imap_arg **imap_args)
+{ 
+       return arg_new_human_size(ctx, imap_args, SEARCH_LARGER);
+}
+
+static struct mail_search_arg *
+human_search_smaller(struct mail_search_build_context *ctx,
+                    const struct imap_arg **imap_args)
+{ 
+       return arg_new_human_size(ctx, imap_args, SEARCH_SMALLER);
+}
+
+static struct mail_search_arg *
+human_search_guid(struct mail_search_build_context *ctx,
+                 const struct imap_arg **imap_args)
+{
+       return mail_search_build_str(ctx, imap_args, SEARCH_GUID);
+}
+
+static struct mail_search_arg *
+human_search_mailbox(struct mail_search_build_context *ctx,
+                    const struct imap_arg **imap_args)
+{
+       return mail_search_build_str(ctx, imap_args, SEARCH_MAILBOX);
+}
+
+static const struct mail_search_register_arg human_register_args[] = {
+       { "OR", human_search_or },
+
+       /* dates */
+       { "BEFORE", human_search_before },
+       { "ON", human_search_on },
+       { "SINCE", human_search_since },
+       { "SENTBEFORE", human_search_sentbefore },
+       { "SENTON", human_search_senton },
+       { "SENTSINCE", human_search_sentsince },
+       { "SAVEDBEFORE", human_search_savedbefore },
+       { "SAVEDON", human_search_savedon },
+       { "SAVEDSINCE", human_search_savedsince },
+       { "X-SAVEDBEFORE", human_search_savedbefore },
+       { "X-SAVEDON", human_search_savedon },
+       { "X-SAVEDSINCE", human_search_savedsince },
+
+       /* sizes */
+       { "LARGER", human_search_larger },
+       { "SMALLER", human_search_smaller },
+
+       /* Other Dovecot extensions: */
+       { "GUID", human_search_guid },
+       { "MAILBOX", human_search_mailbox }
+};
+
+struct mail_search_register *
+mail_search_register_init_human(struct mail_search_register *imap_register)
+{
+       struct mail_search_register *reg;
+       mail_search_register_fallback_t *fallback;
+       ARRAY_DEFINE(copy_args, const struct mail_search_register_arg);
+       const struct mail_search_register_arg *human_args, *imap_args;
+       unsigned int i, j, human_count, imap_count;
+       int ret;
+
+       reg = mail_search_register_init();
+       mail_search_register_add(reg, human_register_args,
+                                N_ELEMENTS(human_register_args));
+
+       /* find and register args in imap that don't exist in human */
+       imap_args = mail_search_register_get(imap_register, &imap_count);
+       human_args = mail_search_register_get(reg, &human_count);
+       t_array_init(&copy_args, imap_count);
+       for (i = j = 0; i < imap_count && j < human_count; ) {
+               ret = strcmp(imap_args[i].key, human_args[j].key);
+               if (ret < 0) {
+                       array_append(&copy_args, &imap_args[i], 1);
+                       i++;
+               } else if (ret > 0) {
+                       j++;
+               } else {
+                       i++; j++;
+               }
+       }
+       for (; i < imap_count; i++)
+               array_append(&copy_args, &imap_args[i], 1);
+
+       imap_args = array_get(&copy_args, &imap_count);
+       mail_search_register_add(reg, imap_args, imap_count);
+
+       if (mail_search_register_get_fallback(imap_register, &fallback))
+               mail_search_register_fallback(reg, fallback);
+       return reg;
+}
index 28864154c978fc51e45697f813c0fa4e7e4266dd..233ba0cbca21e711d28ab1fbd9f6f455a8643849 100644 (file)
 
 #include <stdlib.h>
 
-static struct mail_search_arg *
-search_arg_new(pool_t pool, enum mail_search_arg_type type)
-{
-       struct mail_search_arg *arg;
-
-       arg = p_new(pool, struct mail_search_arg, 1);
-       arg->type = type;
-       return arg;
-}
-
-static int
-arg_get_next(struct mail_search_build_context *ctx,
-            const struct imap_arg **imap_args, const char **value_r)
-{
-       if (IMAP_ARG_IS_EOL(*imap_args)) {
-               ctx->error = "Missing parameter for argument";
-               return -1;
-       }
-       if (!imap_arg_get_astring(*imap_args, value_r)) {
-               ctx->error = "Invalid parameter for argument";
-               return -1;
-       }
-
-       *imap_args += 1;
-       return 0;
-}
+struct mail_search_register *mail_search_register_imap;
 
 static struct mail_search_arg *
 imap_search_fallback(struct mail_search_build_context *ctx,
@@ -47,7 +22,7 @@ imap_search_fallback(struct mail_search_build_context *ctx,
 
        if (*key == '*' || (*key >= '0' && *key <= '9')) {
                /* <message-set> */
-               sarg = search_arg_new(ctx->pool, SEARCH_SEQSET);
+               sarg = mail_search_build_new(ctx, SEARCH_SEQSET);
                p_array_init(&sarg->value.seqset, ctx->pool, 16);
                if (imap_seq_set_parse(key, &sarg->value.seqset) < 0) {
                        ctx->error = "Invalid messageset";
@@ -65,7 +40,7 @@ imap_search_not(struct mail_search_build_context *ctx,
 {
        struct mail_search_arg *sarg;
 
-       sarg = mail_search_build_next(ctx, imap_args);
+       sarg = mail_search_build_next(ctx, ctx->parent, imap_args);
        if (sarg != NULL)
                sarg->not = !sarg->not;
        return sarg;
@@ -78,11 +53,11 @@ imap_search_or(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg, **subargs;
 
        /* <search-key1> <search-key2> */
-       sarg = search_arg_new(ctx->pool, SEARCH_OR);
+       sarg = mail_search_build_new(ctx, SEARCH_OR);
 
        subargs = &sarg->value.subargs;
        for (;;) {
-               *subargs = mail_search_build_next(ctx, imap_args);
+               *subargs = mail_search_build_next(ctx, sarg, imap_args);
                if (*subargs == NULL)
                        return NULL;
                subargs = &(*subargs)->next;
@@ -95,39 +70,24 @@ imap_search_or(struct mail_search_build_context *ctx,
                *imap_args += 1;
        }
 
-       *subargs = mail_search_build_next(ctx, imap_args);
+       *subargs = mail_search_build_next(ctx, sarg, imap_args);
        if (*subargs == NULL)
                return NULL;
        return sarg;
 }
 
-static struct mail_search_arg *
-arg_new_str(struct mail_search_build_context *ctx,
-           const struct imap_arg **imap_args,
-           enum mail_search_arg_type type)
-{
-       struct mail_search_arg *sarg;
-       const char *value;
-
-       sarg = search_arg_new(ctx->pool, type);
-       if (arg_get_next(ctx, imap_args, &value) < 0)
-               return NULL;
-       sarg->value.str = p_strdup(ctx->pool, value);
-       return sarg;
-}
-
 #define CALLBACK_STR(_func, _type) \
 static struct mail_search_arg *\
 imap_search_##_func(struct mail_search_build_context *ctx, \
                     const struct imap_arg **imap_args) \
 { \
-       return arg_new_str(ctx, imap_args, _type); \
+       return mail_search_build_str(ctx, imap_args, _type); \
 }
 static struct mail_search_arg *
 imap_search_all(struct mail_search_build_context *ctx,
                const struct imap_arg **imap_args ATTR_UNUSED)
 { 
-       return search_arg_new(ctx->pool, SEARCH_ALL);
+       return mail_search_build_new(ctx, SEARCH_ALL);
 }
 
 static struct mail_search_arg *
@@ -137,7 +97,8 @@ imap_search_uid(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg;
 
        /* <message set> */
-       if ((sarg = arg_new_str(ctx, imap_args, SEARCH_UIDSET)) == NULL)
+       sarg = mail_search_build_str(ctx, imap_args, SEARCH_UIDSET);
+       if (sarg == NULL)
                return NULL;
 
        p_array_init(&sarg->value.seqset, ctx->pool, 16);
@@ -159,7 +120,7 @@ imap_search_##_func(struct mail_search_build_context *ctx, \
                     const struct imap_arg **imap_args ATTR_UNUSED) \
 { \
        struct mail_search_arg *sarg; \
-       sarg = search_arg_new(ctx->pool, SEARCH_FLAGS); \
+       sarg = mail_search_build_new(ctx, SEARCH_FLAGS); \
        sarg->value.flags = _flag; \
        sarg->not = _not; \
        return sarg; \
@@ -184,7 +145,7 @@ imap_search_new(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg;
 
        /* NEW == (RECENT UNSEEN) */
-       sarg = search_arg_new(ctx->pool, SEARCH_SUB);
+       sarg = mail_search_build_new(ctx, SEARCH_SUB);
        sarg->value.subargs = imap_search_recent(ctx, NULL);
        sarg->value.subargs->next = imap_search_unseen(ctx, NULL);
        return sarg;
@@ -213,8 +174,8 @@ arg_new_date(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg;
        const char *value;
 
-       sarg = search_arg_new(ctx->pool, type);
-       if (arg_get_next(ctx, imap_args, &value) < 0)
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                return NULL;
        if (!imap_parse_date(value, &sarg->value.time)) {
                ctx->error = "Invalid search date parameter";
@@ -251,8 +212,8 @@ arg_new_size(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg;
        const char *value;
 
-       sarg = search_arg_new(ctx->pool, type);
-       if (arg_get_next(ctx, imap_args, &value) < 0)
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                return NULL;
 
        if (str_to_uoff(value, &sarg->value.size) < 0) {
@@ -284,8 +245,8 @@ arg_new_header(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg;
        const char *value;
 
-       sarg = search_arg_new(ctx->pool, type);
-       if (arg_get_next(ctx, imap_args, &value) < 0)
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                return NULL;
 
        sarg->hdr_field_name = p_strdup(ctx->pool, hdr_name);
@@ -336,9 +297,9 @@ imap_search_##_func(struct mail_search_build_context *ctx, \
        if (imap_arg_get_astring(*imap_args, &value) && *value == '\0') { \
                /* optimization: BODY "" matches everything */ \
                *imap_args += 1; \
-               return search_arg_new(ctx->pool, SEARCH_ALL); \
+               return mail_search_build_new(ctx, SEARCH_ALL); \
        } \
-       return arg_new_str(ctx, imap_args, _type); \
+       return mail_search_build_str(ctx, imap_args, _type); \
 }
 CALLBACK_BODY(body, SEARCH_BODY);
 CALLBACK_BODY(text, SEARCH_TEXT);
@@ -354,8 +315,8 @@ arg_new_interval(struct mail_search_build_context *ctx,
        const char *value;
        uint32_t interval;
 
-       sarg = search_arg_new(ctx->pool, type);
-       if (arg_get_next(ctx, imap_args, &value) < 0)
+       sarg = mail_search_build_new(ctx, type);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                return NULL;
 
        if (str_to_uint32(value, &interval) < 0 || interval == 0) {
@@ -436,8 +397,8 @@ imap_search_modseq(struct mail_search_build_context *ctx,
        const char *value;
 
        /* [<name> <type>] <modseq> */
-       sarg = search_arg_new(ctx->pool, SEARCH_MODSEQ);
-       if (arg_get_next(ctx, imap_args, &value) < 0)
+       sarg = mail_search_build_new(ctx, SEARCH_MODSEQ);
+       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                return NULL;
 
        sarg->value.modseq = p_new(ctx->pool, struct mail_search_modseq, 1);
@@ -446,12 +407,12 @@ imap_search_modseq(struct mail_search_build_context *ctx,
                if (arg_modseq_set_name(ctx, sarg, value) < 0)
                        return NULL;
 
-               if (arg_get_next(ctx, imap_args, &value) < 0)
+               if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                        return NULL;
                if (arg_modseq_set_type(ctx, sarg->value.modseq, value) < 0)
                        return NULL;
 
-               if (arg_get_next(ctx, imap_args, &value) < 0)
+               if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
                        return NULL;
        }
        if (str_to_uint64(value, &sarg->value.modseq->modseq) < 0) {
@@ -468,7 +429,7 @@ imap_search_last_result(struct mail_search_build_context *ctx,
        struct mail_search_arg *sarg;
 
        /* SEARCHRES: delay initialization */
-       sarg = search_arg_new(ctx->pool, SEARCH_UIDSET);
+       sarg = mail_search_build_new(ctx, SEARCH_UIDSET);
        sarg->value.str = "$";
        p_array_init(&sarg->value.seqset, ctx->pool, 16);
        return sarg;
@@ -495,9 +456,9 @@ imap_search_inthread(struct mail_search_build_context *ctx,
        }
        *imap_args += 1;
 
-       sarg = search_arg_new(ctx->pool, SEARCH_INTHREAD);
+       sarg = mail_search_build_new(ctx, SEARCH_INTHREAD);
        sarg->value.thread_type = thread_type;
-       sarg->value.subargs = mail_search_build_next(ctx, imap_args);
+       sarg->value.subargs = mail_search_build_next(ctx, sarg, imap_args);
        if (sarg->value.subargs == NULL)
                return NULL;
        return sarg;
@@ -506,7 +467,7 @@ imap_search_inthread(struct mail_search_build_context *ctx,
 CALLBACK_STR(x_guid, SEARCH_GUID);
 CALLBACK_STR(x_mailbox, SEARCH_MAILBOX);
 
-const struct mail_search_register_arg mail_search_register_imap[] = {
+const struct mail_search_register_arg imap_register_args[] = {
        /* argument set operations */
        { "NOT", imap_search_not },
        { "OR", imap_search_or },
@@ -584,8 +545,8 @@ struct mail_search_register *mail_search_register_init_imap(void)
        struct mail_search_register *reg;
 
        reg = mail_search_register_init();
-       mail_search_register_add(reg, mail_search_register_imap,
-                                N_ELEMENTS(mail_search_register_imap));
+       mail_search_register_add(reg, imap_register_args,
+                                N_ELEMENTS(imap_register_args));
        mail_search_register_fallback(reg, imap_search_fallback);
        return reg;
 }
index f62a6fd650c88a64bc7dc9ceef812f016b6ceb1b..8e78be7aacffc0fbd781e64d2e4c5f95a7ffb557 100644 (file)
@@ -31,13 +31,6 @@ void mail_search_register_deinit(struct mail_search_register **_reg)
        i_free(reg);
 }
 
-static int
-mail_search_register_arg_cmp(const struct mail_search_register_arg *arg1,
-                            const struct mail_search_register_arg *arg2)
-{
-       return strcmp(arg1->key, arg2->key);
-}
-
 void mail_search_register_add(struct mail_search_register *reg,
                              const struct mail_search_register_arg *arg,
                              unsigned int count)
@@ -52,6 +45,25 @@ void mail_search_register_fallback(struct mail_search_register *reg,
        reg->fallback = fallback;
 }
 
+static int
+mail_search_register_arg_cmp(const struct mail_search_register_arg *arg1,
+                            const struct mail_search_register_arg *arg2)
+{
+       return strcmp(arg1->key, arg2->key);
+}
+
+const struct mail_search_register_arg *
+mail_search_register_get(struct mail_search_register *reg,
+                        unsigned int *count_r)
+{
+       if (!reg->args_sorted) {
+               array_sort(&reg->args, mail_search_register_arg_cmp);
+               reg->args_sorted = TRUE;
+       }
+
+       return array_get(&reg->args, count_r);
+}
+
 const struct mail_search_register_arg *
 mail_search_register_find(struct mail_search_register *reg, const char *key)
 {
index 8b3b636771262c1a96110c418be3448c149d5cf4..b6e0dbb0ced6dd99ee46d083c697cc47a15f7c5b 100644 (file)
@@ -15,6 +15,9 @@ struct mail_search_register_arg {
                         const struct imap_arg **imap_args);
 };
 
+extern struct mail_search_register *mail_search_register_imap;
+extern struct mail_search_register *mail_search_register_human;
+
 typedef struct mail_search_arg *
 mail_search_register_fallback_t(struct mail_search_build_context *ctx,
                                const char *key,
@@ -31,6 +34,11 @@ void mail_search_register_add(struct mail_search_register *reg,
 void mail_search_register_fallback(struct mail_search_register *reg,
                                   mail_search_register_fallback_t *fallback);
 
+/* Return all registered args sorted. */
+const struct mail_search_register_arg *
+mail_search_register_get(struct mail_search_register *reg,
+                        unsigned int *count_r);
+
 /* Find key's registered arg, or NULL if not found. */
 const struct mail_search_register_arg *
 mail_search_register_find(struct mail_search_register *reg, const char *key);
@@ -40,5 +48,7 @@ bool mail_search_register_get_fallback(struct mail_search_register *reg,
                                       mail_search_register_fallback_t **fallback_r);
 
 struct mail_search_register *mail_search_register_init_imap(void);
+struct mail_search_register *
+mail_search_register_init_human(struct mail_search_register *imap_register);
 
 #endif
index 23c2d73be885f55a15129f904a9d011df913ce28..4012851e65ec748557b1e6e32328cbf0f419b33c 100644 (file)
@@ -445,8 +445,6 @@ extern struct mail_storage_module_register mail_storage_module_register;
 /* Storage's module_id for mail_index. */
 extern struct mail_module_register mail_module_register;
 
-extern struct mail_search_register *mail_search_register_imap;
-
 #define MAIL_STORAGE_CONTEXT(obj) \
        MODULE_CONTEXT(obj, mail_storage_mail_index_module)
 extern MODULE_CONTEXT_DEFINE(mail_storage_mail_index_module,
index 44fccbf763d9961eea22a0b4c2c077dee05ca7a3..827fc73d734a74760e6e6fe273f9caacc6ee8d18 100644 (file)
@@ -25,7 +25,6 @@
 
 struct mail_storage_module_register mail_storage_module_register = { 0 };
 struct mail_module_register mail_module_register = { 0 };
-struct mail_search_register *mail_search_register_imap;
 
 struct mail_storage_mail_index_module mail_storage_mail_index_module =
        MODULE_CONTEXT_INIT(&mail_index_module_register);
@@ -38,10 +37,13 @@ void mail_storage_init(void)
        mail_storage_hooks_init();
        i_array_init(&mail_storage_classes, 8);
        mail_search_register_imap = mail_search_register_init_imap();
+       mail_search_register_human =
+               mail_search_register_init_human(mail_search_register_imap);
 }
 
 void mail_storage_deinit(void)
 {
+       mail_search_register_deinit(&mail_search_register_human);
        mail_search_register_deinit(&mail_search_register_imap);
        if (array_is_created(&mail_storage_classes))
                array_free(&mail_storage_classes);
index b5f17570cd60b7f55f66298ba1290d8918ad6634..a03a34616df6d74eaa3115c9dceb29061514e623 100644 (file)
@@ -50,7 +50,8 @@ virtual_search_args_parse(const string_t *rule, const char **error_r)
        if (ret < 0) {
                sargs = NULL;
                *error_r = t_strdup(imap_parser_get_error(parser, &fatal));
-       } else if (mail_search_build_from_imap_args(args, "UTF-8", &sargs,
+       } else if (mail_search_build_from_imap_args(mail_search_register_imap,
+                                                   args, "UTF-8", &sargs,
                                                    error_r) < 0)
                sargs = NULL;