]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added support for mail search input parsers. doveadm now uses command line parser.
authorTimo Sirainen <tss@iki.fi>
Tue, 20 Apr 2010 11:57:19 +0000 (14:57 +0300)
committerTimo Sirainen <tss@iki.fi>
Tue, 20 Apr 2010 11:57:19 +0000 (14:57 +0300)
--HG--
branch : HEAD

15 files changed:
src/doveadm/Makefile.am
src/doveadm/doveadm-mail-fetch.c
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-parser-cmdline.c [new file with mode: 0644]
src/lib-storage/mail-search-parser-imap.c [new file with mode: 0644]
src/lib-storage/mail-search-parser-private.h [new file with mode: 0644]
src/lib-storage/mail-search-parser.c [new file with mode: 0644]
src/lib-storage/mail-search-parser.h [new file with mode: 0644]
src/lib-storage/mail-search-register-human.c
src/lib-storage/mail-search-register-imap.c
src/lib-storage/mail-search-register.h
src/plugins/virtual/virtual-config.c

index 546e73f59507412840a2d95509c6489b7ec5f302..50719ce7f9c35bc52351184b2dbd2b768efc6fa7 100644 (file)
@@ -20,7 +20,8 @@ AM_CPPFLAGS = \
 if !BUILD_SHARED_LIBS
 unused_objects = \
        ../lib/mountpoint.o \
-       ../lib-imap/imap-util.o
+       ../lib-imap/imap-util.o \
+       ../lib-storage/mail-search-parser-imap.o
 endif
 
 cmd_pw_libs = \
index ad099c3aad3ef16737068278d035b7210a806ad4..b431a7a49aab927de60d5aca73a5e3ea3b671476 100644 (file)
@@ -6,60 +6,25 @@
 #include "base64.h"
 #include "randgen.h"
 #include "str.h"
-#include "imap-quote.h"
-#include "imap-parser.h"
 #include "mail-storage.h"
 #include "mail-search-build.h"
+#include "mail-search-parser.h"
 #include "doveadm-mail.h"
 
-static struct mail_search_args *search_args_from_str(const char *str)
+static struct mail_search_args *build_search_args(const char *const args[])
 {
-       struct istream *input;
-       struct imap_parser *parser;
-       const struct imap_arg *args;
+       struct mail_search_parser *parser;
        struct mail_search_args *sargs;
        const char *error;
-       bool fatal;
-       int ret;
-
-       input = i_stream_create_from_data(str, strlen(str));
-       (void)i_stream_read(input);
 
-       parser = imap_parser_create(input, NULL, (size_t)-1);
-       ret = imap_parser_finish_line(parser, 0,  0, &args);
-       if (ret < 0)
-               i_fatal("%s", imap_parser_get_error(parser, &fatal));
-       if (mail_search_build_from_imap_args(mail_search_register_human,
-                                            args, "UTF-8", &sargs, &error) < 0)
+       parser = mail_search_parser_init_cmdline(args);
+       if (mail_search_build(mail_search_register_human, parser, "UTF-8",
+                             &sargs, &error) < 0)
                i_fatal("%s", error);
-
-       imap_parser_destroy(&parser);
-       i_stream_destroy(&input);
+       mail_search_parser_deinit(&parser);
        return sargs;
 }
 
-static const char *params_to_imap_args_string(const char *const args[])
-{
-       string_t *str;
-       const char *p;
-
-       str = t_str_new(256);
-       for (; *args != NULL; args++) {
-               for (p = *args; *p != '\0'; p++) {
-                       if (IS_ATOM_SPECIAL_INPUT(*p))
-                               break;
-               }
-               if (*p == '\0' ||
-                   strcmp(*args, "(") == 0 ||
-                   strcmp(*args, ")") == 0)
-                       str_append(str, *args);
-               else
-                       imap_dquote_append(str, *args);
-               str_append_c(str, ' ');
-       }
-       return str_c(str);
-}
-
 void cmd_fetch(struct mail_user *user, const char *const args[])
 {
        const char *mailbox = args[0];
@@ -77,7 +42,7 @@ void cmd_fetch(struct mail_user *user, const char *const args[])
 
        if (mailbox == NULL || args[1] == NULL)
                doveadm_mail_help_name("fetch");
-       search_args = search_args_from_str(params_to_imap_args_string(args+1));
+       search_args = build_search_args(args+1);
 
        random_fill_weak(prefix_buf, sizeof(prefix_buf));
        prefix = t_str_new(32);
index 1980bc106040e6dfc66154a8682f4cd3e249823f..fcbc3ce9caacc1504b205d4398cb1013f29f52bb 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "imap-common.h"
 #include "mail-storage.h"
+#include "mail-search-parser.h"
 #include "mail-search-build.h"
 #include "imap-search-args.h"
 #include "imap-parser.h"
@@ -39,17 +40,21 @@ int imap_search_args_build(struct client_command_context *cmd,
                           const struct imap_arg *args, const char *charset,
                           struct mail_search_args **search_args_r)
 {
+       struct mail_search_parser *parser;
        struct mail_search_args *sargs;
        const char *error;
+       int ret;
 
        if (IMAP_ARG_IS_EOL(args)) {
                client_send_command_error(cmd, "Missing search parameters");
                return -1;
        }
 
-       if (mail_search_build_from_imap_args(mail_search_register_imap,
-                                            args, charset,
-                                            &sargs, &error) < 0) {
+       parser = mail_search_parser_init_imap(args);
+       ret = mail_search_build(mail_search_register_imap, parser, charset,
+                               &sargs, &error);
+       mail_search_parser_deinit(&parser);
+       if (ret < 0) {
                client_send_command_error(cmd, error);
                return -1;
        }
index 472fbf83eb636b4727dfbb98eebefdfc65296a10..01813737af1a06a528d2a1449386c750f242a4c1 100644 (file)
@@ -22,6 +22,9 @@ libstorage_la_SOURCES = \
        mail-namespace.c \
        mail-search.c \
        mail-search-build.c \
+       mail-search-parser.c \
+       mail-search-parser-imap.c \
+       mail-search-parser-cmdline.c \
        mail-search-register.c \
        mail-search-register-human.c \
        mail-search-register-imap.c \
@@ -47,6 +50,8 @@ headers = \
        mail-search-register.h \
        mail-thread.h \
        mail-storage.h \
+       mail-search-parser.h \
+       mail-search-parser-private.h \
        mail-storage-private.h \
        mail-storage-hooks.h \
        mail-storage-service.h \
index 35bcb90ff9a68109b9fd78c2c10b93ee2bf19a3f..8b1f998a7c6390317e1e649dd7fdafb428c003a4 100644 (file)
@@ -1,29 +1,15 @@
 /* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
-#include "imap-arg.h"
 #include "mail-storage-private.h"
 #include "mail-search-register.h"
+#include "mail-search-parser.h"
 #include "mail-search-build.h"
 
 #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;
-}
+static int mail_search_build_list(struct mail_search_build_context *ctx,
+                                 struct mail_search_arg **arg_r);
 
 struct mail_search_arg *
 mail_search_build_new(struct mail_search_build_context *ctx,
@@ -38,93 +24,88 @@ mail_search_build_new(struct mail_search_build_context *ctx,
 
 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)
+       if (mail_search_parse_string(ctx->parser, &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)
+static int
+mail_search_build_key_int(struct mail_search_build_context *ctx,
+                         struct mail_search_arg *parent,
+                         struct mail_search_arg **arg_r)
 {
        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;
+       int ret;
 
        ctx->parent = parent;
 
-       if (IMAP_ARG_IS_EOL(*imap_args)) {
-               ctx->error = "Missing argument";
-               return NULL;
-       }
-
-       if ((*imap_args)->type == IMAP_ARG_NIL) {
-               /* NIL not allowed */
-               ctx->error = "NIL not allowed";
-               return NULL;
-       }
-
-       if (imap_arg_get_list(*imap_args, &listargs)) {
-               if (IMAP_ARG_IS_EOL(listargs)) {
-                       ctx->error = "Empty list not allowed";
-                       return NULL;
-               }
+       if ((ret = mail_search_parse_key(ctx->parser, &key)) <= 0)
+               return ret;
 
-               sarg = mail_search_build_list(ctx, listargs);
-               *imap_args += 1;
+       if (strcmp(key, MAIL_SEARCH_PARSER_KEY_LIST) == 0) {
+               if (mail_search_build_list(ctx, &sarg) < 0)
+                       return -1;
+               i_assert(sarg->value.subargs != NULL);
                ctx->parent = old_parent;
-               return sarg;
+               *arg_r = sarg;
+               return 1;
        }
-
-       /* string argument - get the name and jump to next */
-       key = imap_arg_as_astring(*imap_args);
-       *imap_args += 1;
        key = t_str_ucase(key);
 
        reg_arg = mail_search_register_find(ctx->reg, key);
        if (reg_arg != NULL)
-               sarg = reg_arg->build(ctx, imap_args);
+               sarg = reg_arg->build(ctx);
        else if (mail_search_register_get_fallback(ctx->reg, &fallback))
-               sarg = fallback(ctx, key, imap_args);
+               sarg = fallback(ctx, key);
        else {
                sarg = NULL;
-               ctx->error = p_strconcat(ctx->pool, "Unknown argument ",
-                                        key, NULL);
+               ctx->_error = p_strconcat(ctx->pool, "Unknown argument ",
+                                         key, NULL);
        }
 
        ctx->parent = old_parent;
-       return sarg;
+       *arg_r = sarg;
+       return sarg == NULL ? -1 : 1;
 }
 
-struct mail_search_arg *
-mail_search_build_list(struct mail_search_build_context *ctx,
-                      const struct imap_arg *imap_args)
+int mail_search_build_key(struct mail_search_build_context *ctx,
+                         struct mail_search_arg *parent,
+                         struct mail_search_arg **arg_r)
+{
+       int ret;
+
+       ret = mail_search_build_key_int(ctx, parent, arg_r);
+       if (ret <= 0) {
+               if (ret == 0)
+                       ctx->_error = "Missing argument";
+               return -1;
+       }
+       return 0;
+}
+
+static int mail_search_build_list(struct mail_search_build_context *ctx,
+                                 struct mail_search_arg **arg_r)
 {
        struct mail_search_arg *sarg, **subargs;
        enum mail_search_arg_type cur_type = SEARCH_SUB;
+       int ret;
 
        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;
-
+       while ((ret = mail_search_build_key_int(ctx, sarg, subargs)) > 0) {
                if (cur_type == sarg->type) {
                        /* expected type */
                } else if (cur_type == SEARCH_SUB) {
@@ -132,21 +113,24 @@ mail_search_build_list(struct mail_search_build_context *ctx,
                           belong to this type. */
                        cur_type = sarg->type;
                } else {
-                       ctx->error = cur_type == SEARCH_OR ?
+                       ctx->_error = cur_type == SEARCH_OR ?
                                "Use parenthesis when using ORs" :
                                "Use parenthesis when mixing subtypes";
-                       return NULL;
+                       return -1;
                }
                subargs = &(*subargs)->next;
+               sarg->type = SEARCH_SUB;
        }
-       return sarg;
+       if (ret < 0)
+               return -1;
+       sarg->type = cur_type;
+       *arg_r = sarg;
+       return 0;
 }
 
-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)
+int mail_search_build(struct mail_search_register *reg,
+                     struct mail_search_parser *parser, const char *charset,
+                     struct mail_search_args **args_r, const char **error_r)
 {
         struct mail_search_build_context ctx;
        struct mail_search_args *args;
@@ -161,10 +145,11 @@ int mail_search_build_from_imap_args(struct mail_search_register *reg,
        memset(&ctx, 0, sizeof(ctx));
        ctx.pool = args->pool;
        ctx.reg = reg;
+       ctx.parser = parser;
 
-       root = mail_search_build_list(&ctx, imap_args);
-       if (root == NULL) {
-               *error_r = t_strdup(ctx.error);
+       if (mail_search_build_list(&ctx, &root) < 0) {
+               *error_r = ctx._error != NULL ? t_strdup(ctx._error) :
+                       t_strdup(mail_search_parser_get_error(parser));
                pool_unref(&args->pool);
                return -1;
        }
index 2fd7a6b625496668a253e08cf4b089972300a283..bfddf15ad16a592a75d772d9f639e3d6f719bdbc 100644 (file)
@@ -4,15 +4,16 @@
 #include "mail-search.h"
 #include "mail-search-register.h"
 
-struct imap_arg;
 struct mailbox;
 
 struct mail_search_build_context {
        pool_t pool;
        struct mail_search_register *reg;
+       struct mail_search_parser *parser;
 
        struct mail_search_arg *parent;
-       const char *error;
+       /* error is either here or in parser */
+       const char *_error;
 };
 
 /* Start building a new search query. Use mail_search_args_unref() to
@@ -20,11 +21,9 @@ 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(struct mail_search_register *reg,
-                                    const struct imap_arg *imap_args,
-                                    const char *charset,
-                                    struct mail_search_args **args_r,
-                                    const char **error_r);
+int mail_search_build(struct mail_search_register *reg,
+                     struct mail_search_parser *parser, const char *charset,
+                     struct mail_search_args **args_r, const char **error_r);
 
 /* Add SEARCH_ALL to search args. */
 void mail_search_build_add_all(struct mail_search_args *args);
@@ -32,23 +31,15 @@ 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);
+/* Returns 0 if arg is returned, -1 if error. */
+int mail_search_build_key(struct mail_search_build_context *ctx,
+                         struct mail_search_arg *parent,
+                         struct mail_search_arg **arg_r);
 
 #endif
diff --git a/src/lib-storage/mail-search-parser-cmdline.c b/src/lib-storage/mail-search-parser-cmdline.c
new file mode 100644 (file)
index 0000000..02cd23c
--- /dev/null
@@ -0,0 +1,98 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "mail-search-parser-private.h"
+
+struct cmdline_mail_search_parser {
+       struct mail_search_parser parser;
+
+       const char *const *args;
+       unsigned int list_level;
+};
+
+static int cmdline_search_parse_key(struct mail_search_parser *_parser,
+                                   const char **key_r)
+{
+       struct cmdline_mail_search_parser *parser =
+               (struct cmdline_mail_search_parser *)_parser;
+
+       if (parser->args[0] == NULL) {
+               if (parser->list_level != 0) {
+                       _parser->error = "Missing ')'";
+                       return -1;
+               }
+               return 0;
+       }
+
+       if (strcmp(parser->args[0], "(") == 0) {
+               parser->list_level++;
+               parser->args++;
+               *key_r = MAIL_SEARCH_PARSER_KEY_LIST;
+               return 1;
+       } else if (strcmp(parser->args[0], ")") == 0) {
+               if (parser->list_level == 0) {
+                       _parser->error = "Unexpected ')'";
+                       return -1;
+               }
+               parser->list_level--;
+               parser->args++;
+               *key_r = MAIL_SEARCH_PARSER_KEY_LIST;
+               return 0;
+       } else {
+               *key_r = parser->args[0];
+               parser->args++;
+               return 1;
+       }
+}
+
+static int cmdline_search_parse_string(struct mail_search_parser *_parser,
+                                      const char **value_r)
+{
+       struct cmdline_mail_search_parser *parser =
+               (struct cmdline_mail_search_parser *)_parser;
+
+       if (parser->args[0] == NULL) {
+               _parser->error = "Missing parameter for search key";
+               return -1;
+       }
+       *value_r = parser->args[0];
+
+       parser->args++;
+       return 1;
+}
+
+static bool
+cmdline_search_parse_skip_next(struct mail_search_parser *_parser,
+                              const char *str)
+{
+       struct cmdline_mail_search_parser *parser =
+               (struct cmdline_mail_search_parser *)_parser;
+
+       if (parser->args[0] == NULL)
+               return FALSE;
+       if (strcasecmp(parser->args[0], str) != 0)
+               return FALSE;
+
+       parser->args++;
+       return TRUE;
+}
+
+static const struct mail_search_parser_vfuncs mail_search_parser_cmdline_vfuncs = {
+       cmdline_search_parse_key,
+       cmdline_search_parse_string,
+       cmdline_search_parse_skip_next
+};
+
+struct mail_search_parser *
+mail_search_parser_init_cmdline(const char *const args[])
+{
+       struct cmdline_mail_search_parser *parser;
+       pool_t pool;
+
+       pool = pool_alloconly_create("cmdline search parser", 1024);
+       parser = p_new(pool, struct cmdline_mail_search_parser, 1);
+       parser->parser.pool = pool;
+       parser->parser.v = mail_search_parser_cmdline_vfuncs;
+       parser->args = args;
+       return &parser->parser;
+}
diff --git a/src/lib-storage/mail-search-parser-imap.c b/src/lib-storage/mail-search-parser-imap.c
new file mode 100644 (file)
index 0000000..342de8f
--- /dev/null
@@ -0,0 +1,122 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "imap-arg.h"
+#include "mail-search-parser-private.h"
+
+struct imap_arg_stack {
+       struct imap_arg_stack *prev;
+
+       const struct imap_arg *args;
+};
+
+struct imap_mail_search_parser {
+       struct mail_search_parser parser;
+
+       struct imap_arg_stack root, *cur;
+};
+
+static int imap_search_parse_key(struct mail_search_parser *_parser,
+                                const char **key_r)
+{
+       struct imap_mail_search_parser *parser =
+               (struct imap_mail_search_parser *)_parser;
+       const struct imap_arg *arg = parser->cur->args;
+       struct imap_arg_stack *stack;
+
+       switch (arg->type) {
+       case IMAP_ARG_NIL:
+               _parser->error = "Unexpected NIL";
+               return -1;
+       case IMAP_ARG_ATOM:
+               *key_r = imap_arg_as_astring(arg);
+               break;
+       case IMAP_ARG_STRING:
+       case IMAP_ARG_LITERAL:
+               _parser->error = t_strconcat(
+                       "Unexpected string as search key: ",
+                       imap_arg_as_astring(arg), NULL);
+               return -1;
+       case IMAP_ARG_LIST:
+               stack = p_new(_parser->pool, struct imap_arg_stack, 1);
+               stack->prev = parser->cur;
+               stack->args = imap_arg_as_list(arg);
+               *key_r = MAIL_SEARCH_PARSER_KEY_LIST;
+               break;
+       case IMAP_ARG_EOL:
+               parser->cur = parser->cur->prev;
+               return 0;
+       case IMAP_ARG_LITERAL_SIZE:
+       case IMAP_ARG_LITERAL_SIZE_NONSYNC:
+               i_unreached();
+       }
+       parser->cur->args++;
+       return 1;
+}
+
+static int imap_search_parse_string(struct mail_search_parser *_parser,
+                                   const char **value_r)
+{
+       struct imap_mail_search_parser *parser =
+               (struct imap_mail_search_parser *)_parser;
+       const struct imap_arg *arg = parser->cur->args;
+
+       switch (arg->type) {
+       case IMAP_ARG_NIL:
+               _parser->error = "Unexpected NIL";
+               return -1;
+       case IMAP_ARG_ATOM:
+       case IMAP_ARG_STRING:
+       case IMAP_ARG_LITERAL:
+               *value_r = imap_arg_as_astring(arg);
+               break;
+       case IMAP_ARG_LIST:
+               _parser->error = "Unexpected (";
+               return -1;
+       case IMAP_ARG_EOL:
+               _parser->error = "Missing parameter for search key";
+               return -1;
+       case IMAP_ARG_LITERAL_SIZE:
+       case IMAP_ARG_LITERAL_SIZE_NONSYNC:
+               i_unreached();
+       }
+       parser->cur->args++;
+       return 1;
+}
+
+static bool
+imap_search_parse_skip_next(struct mail_search_parser *_parser, const char *str)
+{
+       struct imap_mail_search_parser *parser =
+               (struct imap_mail_search_parser *)_parser;
+       const char *arg;
+
+       if (!imap_arg_get_astring(parser->cur->args, &arg))
+               return FALSE;
+       if (strcasecmp(arg, str) != 0)
+               return FALSE;
+
+       parser->cur->args++;
+       return TRUE;
+}
+
+static const struct mail_search_parser_vfuncs mail_search_parser_imap_vfuncs = {
+       imap_search_parse_key,
+       imap_search_parse_string,
+       imap_search_parse_skip_next
+};
+
+struct mail_search_parser *
+mail_search_parser_init_imap(const struct imap_arg *args)
+{
+       struct imap_mail_search_parser *parser;
+       pool_t pool;
+
+       pool = pool_alloconly_create("imap search parser", 1024);
+       parser = p_new(pool, struct imap_mail_search_parser, 1);
+       parser->parser.pool = pool;
+       parser->parser.v = mail_search_parser_imap_vfuncs;
+       parser->root.args = args;
+       parser->cur = &parser->root;
+       return &parser->parser;
+}
diff --git a/src/lib-storage/mail-search-parser-private.h b/src/lib-storage/mail-search-parser-private.h
new file mode 100644 (file)
index 0000000..1e7af1f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef MAIL_SEARCH_PARSER_PRIVATE_H
+#define MAIL_SEARCH_PARSER_PRIVATE_H
+
+#include "mail-search-parser.h"
+
+struct mail_search_parser_vfuncs {
+       int (*parse_key)(struct mail_search_parser *parser, const char **key_r);
+       int (*parse_string)(struct mail_search_parser *parser,
+                           const char **value_r);
+       bool (*parse_skip_next)(struct mail_search_parser *parser,
+                               const char *str);
+};
+
+struct mail_search_parser {
+       struct mail_search_parser_vfuncs v;
+
+       pool_t pool;
+       const char *cur_key;
+       const char *error;
+};
+
+#endif
diff --git a/src/lib-storage/mail-search-parser.c b/src/lib-storage/mail-search-parser.c
new file mode 100644 (file)
index 0000000..7aebb8f
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "mail-search-parser-private.h"
+
+void mail_search_parser_deinit(struct mail_search_parser **_parser)
+{
+       struct mail_search_parser *parser = *_parser;
+
+       *_parser = NULL;
+       pool_unref(&parser->pool);
+}
+
+int mail_search_parse_key(struct mail_search_parser *parser,
+                         const char **key_r)
+{
+       int ret;
+
+       if ((ret = parser->v.parse_key(parser, key_r)) <= 0)
+               return ret;
+
+       parser->cur_key = *key_r;
+       return 1;
+}
+
+int mail_search_parse_string(struct mail_search_parser *parser,
+                            const char **value_r)
+{
+       int ret;
+
+       ret = parser->v.parse_string(parser, value_r);
+       if (ret < 0 && parser->cur_key != NULL) {
+               parser->error = p_strdup_printf(parser->pool,
+                       "%s (for search key: %s)",
+                       parser->error, t_str_ucase(parser->cur_key));
+       }
+       return ret;
+}
+
+bool mail_search_parse_skip_next(struct mail_search_parser *parser,
+                                const char *str)
+{
+       return parser->v.parse_skip_next(parser, str);
+}
+
+const char *mail_search_parser_get_error(struct mail_search_parser *parser)
+{
+       return parser->error;
+}
diff --git a/src/lib-storage/mail-search-parser.h b/src/lib-storage/mail-search-parser.h
new file mode 100644 (file)
index 0000000..0535587
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef MAIL_SEARCH_PARSER_H
+#define MAIL_SEARCH_PARSER_H
+
+#define MAIL_SEARCH_PARSER_KEY_LIST "("
+
+struct imap_arg;
+
+/* Build a parser parsing the given imap args. NOTE: args must not be freed
+   until this parser is destroyed. */
+struct mail_search_parser *
+mail_search_parser_init_imap(const struct imap_arg *args);
+/* Build a parser parsing the given command line args. */
+struct mail_search_parser *
+mail_search_parser_init_cmdline(const char *const args[]);
+
+void mail_search_parser_deinit(struct mail_search_parser **parser);
+
+/* Key is set to the next search key, or MAIL_SEARCH_PARSER_KEY_LIST for
+   beginning of a list. Returns 1 if ok, 0 if no more keys in this
+   list/query, -1 if parsing error. */
+int mail_search_parse_key(struct mail_search_parser *parser,
+                         const char **key_r);
+/* Get the next string. Returns 0 if ok, -1 if parsing error. */
+int mail_search_parse_string(struct mail_search_parser *parser,
+                            const char **value_r);
+/* If next parameter equals to the given string case-insensitively, skip over
+   it and return TRUE. Otherwise do nothing and return FALSE. */
+bool mail_search_parse_skip_next(struct mail_search_parser *parser,
+                                const char *str);
+
+/* Returns the reason string for parsing error. */
+const char *mail_search_parser_get_error(struct mail_search_parser *parser);
+
+#endif
index c652d10a63d91a4168c2d9cfc882dabedbbe50dd..6f2b5aca935408a7240b9a44ad16caad30061e96 100644 (file)
@@ -6,6 +6,7 @@
 #include "settings-parser.h"
 #include "imap-date.h"
 #include "mail-search-register.h"
+#include "mail-search-parser.h"
 #include "mail-search-build.h"
 
 #include <time.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)
+human_search_or(struct mail_search_build_context *ctx)
 {
+       struct mail_search_arg *sarg;
+
        /* 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);
+       if (mail_search_build_key(ctx, ctx->parent, &sarg) < 0)
+               return NULL;
+       return sarg;
 }
 
 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)
 {
@@ -35,7 +38,7 @@ arg_new_human_date(struct mail_search_build_context *ctx,
        int tz;
 
        sarg = mail_search_build_new(ctx, type);
-       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return NULL;
 
        /* a) yyyy-mm-dd
@@ -61,7 +64,7 @@ arg_new_human_date(struct mail_search_build_context *ctx,
        sarg->value.search_flags = MAIL_SEARCH_ARG_FLAG_USE_TZ;
 
        if (sarg->value.time == (time_t)-1) {
-               ctx->error = p_strconcat(ctx->pool,
+               ctx->_error = p_strconcat(ctx->pool,
                        "Invalid search date parameter: ", value, NULL);
                return NULL;
        }
@@ -71,10 +74,9 @@ arg_new_human_date(struct mail_search_build_context *ctx,
 
 #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) \
+human_search_##_func(struct mail_search_build_context *ctx) \
 { \
-       return arg_new_human_date(ctx, imap_args, _type, _date_type); \
+       return arg_new_human_date(ctx, _type, _date_type); \
 }
 CALLBACK_DATE(before, SEARCH_BEFORE, MAIL_SEARCH_DATE_TYPE_RECEIVED);
 CALLBACK_DATE(on, SEARCH_ON, MAIL_SEARCH_DATE_TYPE_RECEIVED);
@@ -90,49 +92,44 @@ 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)
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return NULL;
 
        if (settings_get_size(value, &sarg->value.size, &error) < 0) {
-               ctx->error = p_strdup(ctx->pool, error);
+               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)
+human_search_larger(struct mail_search_build_context *ctx)
 { 
-       return arg_new_human_size(ctx, imap_args, SEARCH_LARGER);
+       return arg_new_human_size(ctx, SEARCH_LARGER);
 }
 
 static struct mail_search_arg *
-human_search_smaller(struct mail_search_build_context *ctx,
-                    const struct imap_arg **imap_args)
+human_search_smaller(struct mail_search_build_context *ctx)
 { 
-       return arg_new_human_size(ctx, imap_args, SEARCH_SMALLER);
+       return arg_new_human_size(ctx, SEARCH_SMALLER);
 }
 
 static struct mail_search_arg *
-human_search_guid(struct mail_search_build_context *ctx,
-                 const struct imap_arg **imap_args)
+human_search_guid(struct mail_search_build_context *ctx)
 {
-       return mail_search_build_str(ctx, imap_args, SEARCH_GUID);
+       return mail_search_build_str(ctx, SEARCH_GUID);
 }
 
 static struct mail_search_arg *
-human_search_mailbox(struct mail_search_build_context *ctx,
-                    const struct imap_arg **imap_args)
+human_search_mailbox(struct mail_search_build_context *ctx)
 {
-       return mail_search_build_str(ctx, imap_args, SEARCH_MAILBOX);
+       return mail_search_build_str(ctx, SEARCH_MAILBOX);
 }
 
 static const struct mail_search_register_arg human_register_args[] = {
index 233ba0cbca21e711d28ab1fbd9f6f455a8643849..49a5f78af78494c2d919de95ad37ded6cc07dcff 100644 (file)
@@ -2,11 +2,12 @@
 
 #include "lib.h"
 #include "ioloop.h"
+#include "array.h"
 #include "imap-date.h"
-#include "imap-arg.h"
 #include "imap-seqset.h"
 #include "imap-util.h"
 #include "mail-search-register.h"
+#include "mail-search-parser.h"
 #include "mail-search-build.h"
 
 #include <stdlib.h>
@@ -15,8 +16,7 @@ struct mail_search_register *mail_search_register_imap;
 
 static struct mail_search_arg *
 imap_search_fallback(struct mail_search_build_context *ctx,
-                    const char *key,
-                    const struct imap_arg **imap_args ATTR_UNUSED)
+                    const char *key)
 {
        struct mail_search_arg *sarg;
 
@@ -25,30 +25,29 @@ imap_search_fallback(struct mail_search_build_context *ctx,
                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";
+                       ctx->_error = "Invalid messageset";
                        return NULL;
                }
                return sarg;
        }
-       ctx->error = p_strconcat(ctx->pool, "Unknown argument ", key, NULL);
+       ctx->_error = p_strconcat(ctx->pool, "Unknown argument ", key, NULL);
        return NULL;
 }
 
 static struct mail_search_arg *
-imap_search_not(struct mail_search_build_context *ctx,
-               const struct imap_arg **imap_args)
+imap_search_not(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
-       sarg = mail_search_build_next(ctx, ctx->parent, imap_args);
-       if (sarg != NULL)
-               sarg->not = !sarg->not;
+       if (mail_search_build_key(ctx, ctx->parent, &sarg) < 0)
+               return NULL;
+
+       sarg->not = !sarg->not;
        return sarg;
 }
 
 static struct mail_search_arg *
-imap_search_or(struct mail_search_build_context *ctx,
-              const struct imap_arg **imap_args)
+imap_search_or(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg, **subargs;
 
@@ -56,48 +55,39 @@ imap_search_or(struct mail_search_build_context *ctx,
        sarg = mail_search_build_new(ctx, SEARCH_OR);
 
        subargs = &sarg->value.subargs;
-       for (;;) {
-               *subargs = mail_search_build_next(ctx, sarg, imap_args);
-               if (*subargs == NULL)
+       do {
+               if (mail_search_build_key(ctx, sarg, subargs) < 0)
                        return NULL;
                subargs = &(*subargs)->next;
 
                /* <key> OR <key> OR ... <key> - put them all
                   under one SEARCH_OR list. */
-               if (!imap_arg_atom_equals(*imap_args, "OR"))
-                       break;
+       } while (mail_search_parse_skip_next(ctx->parser, "OR"));
 
-               *imap_args += 1;
-       }
-
-       *subargs = mail_search_build_next(ctx, sarg, imap_args);
-       if (*subargs == NULL)
+       if (mail_search_build_key(ctx, sarg, subargs) < 0)
                return NULL;
        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) \
+imap_search_##_func(struct mail_search_build_context *ctx) \
 { \
-       return mail_search_build_str(ctx, imap_args, _type); \
+       return mail_search_build_str(ctx, _type); \
 }
 static struct mail_search_arg *
-imap_search_all(struct mail_search_build_context *ctx,
-               const struct imap_arg **imap_args ATTR_UNUSED)
+imap_search_all(struct mail_search_build_context *ctx)
 { 
        return mail_search_build_new(ctx, SEARCH_ALL);
 }
 
 static struct mail_search_arg *
-imap_search_uid(struct mail_search_build_context *ctx,
-               const struct imap_arg **imap_args ATTR_UNUSED)
+imap_search_uid(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
        /* <message set> */
-       sarg = mail_search_build_str(ctx, imap_args, SEARCH_UIDSET);
+       sarg = mail_search_build_str(ctx, SEARCH_UIDSET);
        if (sarg == NULL)
                return NULL;
 
@@ -107,7 +97,7 @@ imap_search_uid(struct mail_search_build_context *ctx,
        } else {
                if (imap_seq_set_parse(sarg->value.str,
                                       &sarg->value.seqset) < 0) {
-                       ctx->error = "Invalid UID messageset";
+                       ctx->_error = "Invalid UID messageset";
                        return NULL;
                }
        }
@@ -116,8 +106,7 @@ imap_search_uid(struct mail_search_build_context *ctx,
 
 #define CALLBACK_FLAG(_func, _flag, _not) \
 static struct mail_search_arg *\
-imap_search_##_func(struct mail_search_build_context *ctx, \
-                    const struct imap_arg **imap_args ATTR_UNUSED) \
+imap_search_##_func(struct mail_search_build_context *ctx) \
 { \
        struct mail_search_arg *sarg; \
        sarg = mail_search_build_new(ctx, SEARCH_FLAGS); \
@@ -139,27 +128,25 @@ CALLBACK_FLAG(recent, MAIL_RECENT, FALSE);
 CALLBACK_FLAG(old, MAIL_RECENT, TRUE);
 
 static struct mail_search_arg *
-imap_search_new(struct mail_search_build_context *ctx,
-               const struct imap_arg **imap_args ATTR_UNUSED)
+imap_search_new(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
        /* NEW == (RECENT UNSEEN) */
        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);
+       sarg->value.subargs = imap_search_recent(ctx);
+       sarg->value.subargs->next = imap_search_unseen(ctx);
        return sarg;
 }
 
 CALLBACK_STR(keyword, SEARCH_KEYWORDS);
 
 static struct mail_search_arg *
-imap_search_unkeyword(struct mail_search_build_context *ctx,
-                     const struct imap_arg **imap_args)
+imap_search_unkeyword(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
-       sarg = imap_search_keyword(ctx, imap_args);
+       sarg = imap_search_keyword(ctx);
        if (sarg != NULL)
                sarg->not = TRUE;
        return sarg;
@@ -167,7 +154,6 @@ imap_search_unkeyword(struct mail_search_build_context *ctx,
 
 static struct mail_search_arg *
 arg_new_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)
 {
@@ -175,10 +161,10 @@ arg_new_date(struct mail_search_build_context *ctx,
        const char *value;
 
        sarg = mail_search_build_new(ctx, type);
-       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return NULL;
        if (!imap_parse_date(value, &sarg->value.time)) {
-               ctx->error = "Invalid search date parameter";
+               ctx->_error = "Invalid search date parameter";
                return NULL;
        }
        sarg->value.date_type = date_type;
@@ -187,10 +173,9 @@ arg_new_date(struct mail_search_build_context *ctx,
 
 #define CALLBACK_DATE(_func, _type, _date_type) \
 static struct mail_search_arg *\
-imap_search_##_func(struct mail_search_build_context *ctx, \
-                    const struct imap_arg **imap_args) \
+imap_search_##_func(struct mail_search_build_context *ctx) \
 { \
-       return arg_new_date(ctx, imap_args, _type, _date_type); \
+       return arg_new_date(ctx, _type, _date_type); \
 }
 CALLBACK_DATE(before, SEARCH_BEFORE, MAIL_SEARCH_DATE_TYPE_RECEIVED);
 CALLBACK_DATE(on, SEARCH_ON, MAIL_SEARCH_DATE_TYPE_RECEIVED);
@@ -206,47 +191,43 @@ CALLBACK_DATE(x_savedsince, SEARCH_SINCE, MAIL_SEARCH_DATE_TYPE_SAVED);
 
 static struct mail_search_arg *
 arg_new_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;
 
        sarg = mail_search_build_new(ctx, type);
-       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return NULL;
 
        if (str_to_uoff(value, &sarg->value.size) < 0) {
-               ctx->error = "Invalid search size parameter";
+               ctx->_error = "Invalid search size parameter";
                return NULL;
        }
        return sarg;
 }
 
 static struct mail_search_arg *
-imap_search_larger(struct mail_search_build_context *ctx,
-                  const struct imap_arg **imap_args)
+imap_search_larger(struct mail_search_build_context *ctx)
 { 
-       return arg_new_size(ctx, imap_args, SEARCH_LARGER);
+       return arg_new_size(ctx, SEARCH_LARGER);
 }
 
 static struct mail_search_arg *
-imap_search_smaller(struct mail_search_build_context *ctx,
-                   const struct imap_arg **imap_args)
+imap_search_smaller(struct mail_search_build_context *ctx)
 { 
-       return arg_new_size(ctx, imap_args, SEARCH_SMALLER);
+       return arg_new_size(ctx, SEARCH_SMALLER);
 }
 
 static struct mail_search_arg *
 arg_new_header(struct mail_search_build_context *ctx,
-              const struct imap_arg **imap_args,
               enum mail_search_arg_type type, const char *hdr_name)
 {
        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)
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return NULL;
 
        sarg->hdr_field_name = p_strdup(ctx->pool, hdr_name);
@@ -256,10 +237,9 @@ arg_new_header(struct mail_search_build_context *ctx,
 
 #define CALLBACK_HDR(_name, _type) \
 static struct mail_search_arg *\
-imap_search_##_name(struct mail_search_build_context *ctx, \
-                    const struct imap_arg **imap_args) \
+imap_search_##_name(struct mail_search_build_context *ctx) \
 { \
-       return arg_new_header(ctx, imap_args, _type, #_name); \
+       return arg_new_header(ctx, _type, #_name); \
 }
 CALLBACK_HDR(bcc, SEARCH_HEADER_ADDRESS);
 CALLBACK_HDR(cc, SEARCH_HEADER_ADDRESS);
@@ -268,38 +248,26 @@ CALLBACK_HDR(to, SEARCH_HEADER_ADDRESS);
 CALLBACK_HDR(subject, SEARCH_HEADER_COMPRESS_LWSP);
 
 static struct mail_search_arg *
-imap_search_header(struct mail_search_build_context *ctx,
-                  const struct imap_arg **imap_args)
+imap_search_header(struct mail_search_build_context *ctx)
 {
-       const char *value;
+       const char *hdr_name;
 
-       /* <field-name> <string> */
-       if (IMAP_ARG_IS_EOL(*imap_args)) {
-               ctx->error = "Missing parameter for HEADER";
-               return NULL;
-       }
-       if (!imap_arg_get_astring(*imap_args, &value)) {
-               ctx->error = "Invalid parameter for HEADER";
+       /* <hdr-name> <string> */
+       if (mail_search_parse_string(ctx->parser, &hdr_name) < 0)
                return NULL;
-       }
 
-       *imap_args += 1;
-       return arg_new_header(ctx, imap_args, SEARCH_HEADER,
-                             t_str_ucase(value));
+       return arg_new_header(ctx, SEARCH_HEADER, t_str_ucase(hdr_name));
 }
 
 #define CALLBACK_BODY(_func, _type) \
 static struct mail_search_arg *\
-imap_search_##_func(struct mail_search_build_context *ctx, \
-                    const struct imap_arg **imap_args) \
+imap_search_##_func(struct mail_search_build_context *ctx) \
 { \
-       const char *value; \
-       if (imap_arg_get_astring(*imap_args, &value) && *value == '\0') { \
+       if (mail_search_parse_skip_next(ctx->parser, "")) { \
                /* optimization: BODY "" matches everything */ \
-               *imap_args += 1; \
                return mail_search_build_new(ctx, SEARCH_ALL); \
        } \
-       return mail_search_build_str(ctx, imap_args, _type); \
+       return mail_search_build_str(ctx, _type); \
 }
 CALLBACK_BODY(body, SEARCH_BODY);
 CALLBACK_BODY(text, SEARCH_TEXT);
@@ -308,7 +276,6 @@ CALLBACK_BODY(x_text_fast, SEARCH_TEXT_FAST);
 
 static struct mail_search_arg *
 arg_new_interval(struct mail_search_build_context *ctx,
-                const struct imap_arg **imap_args,
                 enum mail_search_arg_type type)
 {
        struct mail_search_arg *sarg;
@@ -316,11 +283,11 @@ arg_new_interval(struct mail_search_build_context *ctx,
        uint32_t interval;
 
        sarg = mail_search_build_new(ctx, type);
-       if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return NULL;
 
        if (str_to_uint32(value, &interval) < 0 || interval == 0) {
-               ctx->error = "Invalid search interval parameter";
+               ctx->_error = "Invalid search interval parameter";
                return NULL;
        }
        sarg->value.search_flags = MAIL_SEARCH_ARG_FLAG_USE_TZ;
@@ -329,102 +296,102 @@ arg_new_interval(struct mail_search_build_context *ctx,
 }
 
 static struct mail_search_arg *
-imap_search_older(struct mail_search_build_context *ctx,
-                 const struct imap_arg **imap_args)
+imap_search_older(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
-       sarg = arg_new_interval(ctx, imap_args, SEARCH_BEFORE);
+       sarg = arg_new_interval(ctx, SEARCH_BEFORE);
        /* we need to match also equal, but SEARCH_BEFORE compares with "<" */
        sarg->value.time++;
        return sarg;
 }
 
 static struct mail_search_arg *
-imap_search_younger(struct mail_search_build_context *ctx,
-                   const struct imap_arg **imap_args)
+imap_search_younger(struct mail_search_build_context *ctx)
 {
-       return arg_new_interval(ctx, imap_args, SEARCH_SINCE);
+       return arg_new_interval(ctx, SEARCH_SINCE);
 }
 
 static int
-arg_modseq_set_name(struct mail_search_build_context *ctx,
-                   struct mail_search_arg *sarg, const char *name)
+arg_modseq_set_type(struct mail_search_build_context *ctx,
+                   struct mail_search_modseq *modseq, const char *name)
 {
-       name = t_str_lcase(name);
-       if (strncmp(name, "/flags/", 7) != 0) {
-               ctx->error = "Invalid MODSEQ entry";
+       if (strcasecmp(name, "all") == 0)
+               modseq->type = MAIL_SEARCH_MODSEQ_TYPE_ANY;
+       else if (strcasecmp(name, "priv") == 0)
+               modseq->type = MAIL_SEARCH_MODSEQ_TYPE_PRIVATE;
+       else if (strcasecmp(name, "shared") == 0)
+               modseq->type = MAIL_SEARCH_MODSEQ_TYPE_SHARED;
+       else {
+               ctx->_error = "Invalid MODSEQ type";
                return -1;
        }
+       return 0;
+}
+
+static int
+arg_modseq_set_ext(struct mail_search_build_context *ctx,
+                  struct mail_search_arg *sarg, const char *name)
+{
+       const char *value;
+
+       name = t_str_lcase(name);
+       if (strncmp(name, "/flags/", 7) != 0)
+               return 0;
        name += 7;
 
+       /* set name */
        if (*name == '\\') {
                /* system flag */
                sarg->value.flags = imap_parse_system_flag(name);
                if (sarg->value.flags == 0 ||
                    sarg->value.flags == MAIL_RECENT) {
-                       ctx->error = "Invalid MODSEQ system flag";
+                       ctx->_error = "Invalid MODSEQ system flag";
                        return -1;
                }
-               return 0;
+       } else {
+               sarg->value.str = p_strdup(ctx->pool, name);
        }
-       sarg->value.str = p_strdup(ctx->pool, name);
-       return 0;
-}
 
-static int
-arg_modseq_set_type(struct mail_search_build_context *ctx,
-                   struct mail_search_modseq *modseq, const char *name)
-{
-       if (strcasecmp(name, "all") == 0)
-               modseq->type = MAIL_SEARCH_MODSEQ_TYPE_ANY;
-       else if (strcasecmp(name, "priv") == 0)
-               modseq->type = MAIL_SEARCH_MODSEQ_TYPE_PRIVATE;
-       else if (strcasecmp(name, "shared") == 0)
-               modseq->type = MAIL_SEARCH_MODSEQ_TYPE_SHARED;
-       else {
-               ctx->error = "Invalid MODSEQ type";
+       /* set type */
+       if (mail_search_parse_string(ctx->parser, &value) < 0)
                return -1;
-       }
-       return 0;
+       if (arg_modseq_set_type(ctx, sarg->value.modseq, value) < 0)
+               return -1;
+       return 1;
 }
 
 static struct mail_search_arg *
-imap_search_modseq(struct mail_search_build_context *ctx,
-                  const struct imap_arg **imap_args)
+imap_search_modseq(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
        const char *value;
+       int ret;
 
        /* [<name> <type>] <modseq> */
        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);
-       if ((*imap_args)[-1].type == IMAP_ARG_STRING) {
-               /* <name> <type> */
-               if (arg_modseq_set_name(ctx, sarg, value) < 0)
-                       return NULL;
 
-               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 (mail_search_parse_string(ctx->parser, &value) < 0)
+               return NULL;
 
-               if (mail_search_build_next_astring(ctx, imap_args, &value) < 0)
+       if ((ret = arg_modseq_set_ext(ctx, sarg, value)) < 0)
+               return NULL;
+       if (ret > 0) {
+               /* extension data used */
+               if (mail_search_parse_string(ctx->parser, &value) < 0)
                        return NULL;
        }
+
        if (str_to_uint64(value, &sarg->value.modseq->modseq) < 0) {
-               ctx->error = "Invalid MODSEQ value";
+               ctx->_error = "Invalid MODSEQ value";
                return NULL;
        }
        return sarg;
 }
 
 static struct mail_search_arg *
-imap_search_last_result(struct mail_search_build_context *ctx,
-                       const struct imap_arg **imap_args ATTR_UNUSED)
+imap_search_last_result(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
@@ -436,8 +403,7 @@ imap_search_last_result(struct mail_search_build_context *ctx,
 }
 
 static struct mail_search_arg *
-imap_search_inthread(struct mail_search_build_context *ctx,
-                    const struct imap_arg **imap_args)
+imap_search_inthread(struct mail_search_build_context *ctx)
 {
        struct mail_search_arg *sarg;
 
@@ -445,21 +411,16 @@ imap_search_inthread(struct mail_search_build_context *ctx,
        enum mail_thread_type thread_type;
        const char *algorithm;
 
-       if (!imap_arg_get_atom(*imap_args, &algorithm)) {
-               ctx->error = "Invalid parameter for INTHREAD";
+       if (mail_search_parse_string(ctx->parser, &algorithm) < 0)
                return NULL;
-       }
-
        if (!mail_thread_type_parse(algorithm, &thread_type)) {
-               ctx->error = "Unknown thread algorithm";
+               ctx->_error = "Unknown thread algorithm";
                return NULL;
        }
-       *imap_args += 1;
 
        sarg = mail_search_build_new(ctx, SEARCH_INTHREAD);
        sarg->value.thread_type = thread_type;
-       sarg->value.subargs = mail_search_build_next(ctx, sarg, imap_args);
-       if (sarg->value.subargs == NULL)
+       if (mail_search_build_key(ctx, sarg, &sarg->value.subargs) < 0)
                return NULL;
        return sarg;
 }
index b6e0dbb0ced6dd99ee46d083c697cc47a15f7c5b..e5446d43b6dfa4fead050b03bf50eb90817b607d 100644 (file)
@@ -1,18 +1,15 @@
 #ifndef MAIL_SEARCH_REGISTER_H
 #define MAIL_SEARCH_REGISTER_H
 
-struct imap_arg;
 struct mail_search_arg;
 struct mail_search_build_context;
 
 struct mail_search_register_arg {
        const char *key;
 
-       /* read wanted parameters from imap_arg, returns parsed arg or NULL if
-          error. error message is set to ctx. */
+       /* returns parsed arg or NULL if error. error message is set to ctx. */
        struct mail_search_arg *
-               (*build)(struct mail_search_build_context *ctx,
-                        const struct imap_arg **imap_args);
+               (*build)(struct mail_search_build_context *ctx);
 };
 
 extern struct mail_search_register *mail_search_register_imap;
@@ -20,8 +17,7 @@ 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,
-                               const struct imap_arg **imap_args);
+                               const char *key);
 
 struct mail_search_register *mail_search_register_init(void);
 void mail_search_register_deinit(struct mail_search_register **reg);
index a03a34616df6d74eaa3115c9dceb29061514e623..c39d7bab10013942018c2fe13a5c9f0291ed54e1 100644 (file)
@@ -8,6 +8,7 @@
 #include "imap-parser.h"
 #include "imap-match.h"
 #include "mail-search-build.h"
+#include "mail-search-parser.h"
 #include "virtual-storage.h"
 #include "virtual-plugin.h"
 
@@ -30,8 +31,9 @@ static struct mail_search_args *
 virtual_search_args_parse(const string_t *rule, const char **error_r)
 {
        struct istream *input;
-       struct imap_parser *parser;
+       struct imap_parser *imap_parser;
        const struct imap_arg *args;
+       struct mail_search_parser *parser;
        struct mail_search_args *sargs;
        bool fatal;
        int ret;
@@ -45,17 +47,20 @@ virtual_search_args_parse(const string_t *rule, const char **error_r)
        input = i_stream_create_from_data(str_data(rule), str_len(rule));
        (void)i_stream_read(input);
 
-       parser = imap_parser_create(input, NULL, (size_t)-1);
-       ret = imap_parser_finish_line(parser, 0,  0, &args);
+       imap_parser = imap_parser_create(input, NULL, (size_t)-1);
+       ret = imap_parser_finish_line(imap_parser, 0,  0, &args);
        if (ret < 0) {
                sargs = NULL;
-               *error_r = t_strdup(imap_parser_get_error(parser, &fatal));
-       } else if (mail_search_build_from_imap_args(mail_search_register_imap,
-                                                   args, "UTF-8", &sargs,
-                                                   error_r) < 0)
-               sargs = NULL;
+               *error_r = t_strdup(imap_parser_get_error(imap_parser, &fatal));
+       } else {
+               parser = mail_search_parser_init_imap(args);
+               if (mail_search_build(mail_search_register_imap, parser, "UTF-8",
+                                     &sargs, error_r) < 0)
+                       sargs = NULL;
+               mail_search_parser_deinit(&parser);
+       }
 
-       imap_parser_destroy(&parser);
+       imap_parser_destroy(&imap_parser);
        i_stream_destroy(&input);
        return sargs;
 }