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 = \
#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];
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);
#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"
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;
}
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 \
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 \
/* 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,
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) {
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;
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;
}
#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
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);
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+#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
--- /dev/null
+/* 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;
+}
--- /dev/null
+#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
#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)
{
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
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;
}
#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);
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[] = {
#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>
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;
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;
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;
} 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;
}
}
#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); \
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;
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)
{
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;
#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);
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);
#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);
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);
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;
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;
}
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;
}
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;
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;
}
#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;
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);
#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"
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;
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;
}