From: Timo Sirainen Date: Tue, 20 Apr 2010 11:57:19 +0000 (+0300) Subject: Added support for mail search input parsers. doveadm now uses command line parser. X-Git-Tag: 2.0.beta5~99 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5c2d695acf9f95ae0dcdda89c4d2391ceda4d672;p=thirdparty%2Fdovecot%2Fcore.git Added support for mail search input parsers. doveadm now uses command line parser. --HG-- branch : HEAD --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index 546e73f595..50719ce7f9 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -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 = \ diff --git a/src/doveadm/doveadm-mail-fetch.c b/src/doveadm/doveadm-mail-fetch.c index ad099c3aad..b431a7a49a 100644 --- a/src/doveadm/doveadm-mail-fetch.c +++ b/src/doveadm/doveadm-mail-fetch.c @@ -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); diff --git a/src/imap/imap-search-args.c b/src/imap/imap-search-args.c index 1980bc1060..fcbc3ce9ca 100644 --- a/src/imap/imap-search-args.c +++ b/src/imap/imap-search-args.c @@ -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; } diff --git a/src/lib-storage/Makefile.am b/src/lib-storage/Makefile.am index 472fbf83eb..01813737af 100644 --- a/src/lib-storage/Makefile.am +++ b/src/lib-storage/Makefile.am @@ -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 \ diff --git a/src/lib-storage/mail-search-build.c b/src/lib-storage/mail-search-build.c index 35bcb90ff9..8b1f998a7c 100644 --- a/src/lib-storage/mail-search-build.c +++ b/src/lib-storage/mail-search-build.c @@ -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 -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; } diff --git a/src/lib-storage/mail-search-build.h b/src/lib-storage/mail-search-build.h index 2fd7a6b625..bfddf15ad1 100644 --- a/src/lib-storage/mail-search-build.h +++ b/src/lib-storage/mail-search-build.h @@ -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 index 0000000000..02cd23cefd --- /dev/null +++ b/src/lib-storage/mail-search-parser-cmdline.c @@ -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 index 0000000000..342de8f27d --- /dev/null +++ b/src/lib-storage/mail-search-parser-imap.c @@ -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 index 0000000000..1e7af1f2e5 --- /dev/null +++ b/src/lib-storage/mail-search-parser-private.h @@ -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 index 0000000000..7aebb8f0e9 --- /dev/null +++ b/src/lib-storage/mail-search-parser.c @@ -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 index 0000000000..0535587c4c --- /dev/null +++ b/src/lib-storage/mail-search-parser.h @@ -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 diff --git a/src/lib-storage/mail-search-register-human.c b/src/lib-storage/mail-search-register-human.c index c652d10a63..6f2b5aca93 100644 --- a/src/lib-storage/mail-search-register-human.c +++ b/src/lib-storage/mail-search-register-human.c @@ -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 @@ -14,17 +15,19 @@ 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[] = { diff --git a/src/lib-storage/mail-search-register-imap.c b/src/lib-storage/mail-search-register-imap.c index 233ba0cbca..49a5f78af7 100644 --- a/src/lib-storage/mail-search-register-imap.c +++ b/src/lib-storage/mail-search-register-imap.c @@ -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 @@ -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; /* OR OR ... - 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; /* */ - 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; - /* */ - 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"; + /* */ + 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; /* [ ] */ 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) { - /* */ - 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; } diff --git a/src/lib-storage/mail-search-register.h b/src/lib-storage/mail-search-register.h index b6e0dbb0ce..e5446d43b6 100644 --- a/src/lib-storage/mail-search-register.h +++ b/src/lib-storage/mail-search-register.h @@ -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); diff --git a/src/plugins/virtual/virtual-config.c b/src/plugins/virtual/virtual-config.c index a03a34616d..c39d7bab10 100644 --- a/src/plugins/virtual/virtual-config.c +++ b/src/plugins/virtual/virtual-config.c @@ -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; }