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