From 0441d265f2bb9da249c7abf333f0f771fadb4ab5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 19:36:47 +0200 Subject: Adding upstream version 1:2.3.21+dfsg1. Signed-off-by: Daniel Baumann --- src/lib-storage/mail-search-mime-register.c | 547 ++++++++++++++++++++++++++++ 1 file changed, 547 insertions(+) create mode 100644 src/lib-storage/mail-search-mime-register.c (limited to 'src/lib-storage/mail-search-mime-register.c') diff --git a/src/lib-storage/mail-search-mime-register.c b/src/lib-storage/mail-search-mime-register.c new file mode 100644 index 0000000..c0bda3d --- /dev/null +++ b/src/lib-storage/mail-search-mime-register.c @@ -0,0 +1,547 @@ +/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "ioloop.h" +#include "array.h" +#include "str.h" +#include "imap-date.h" +#include "imap-seqset.h" +#include "imap-utf7.h" +#include "imap-util.h" +#include "mail-search-parser.h" +#include "mail-search-mime-register.h" +#include "mail-search-mime-build.h" +#include "mail-search-mime.h" + +struct mail_search_mime_register { + ARRAY(struct mail_search_mime_register_arg) args; + + bool args_sorted:1; +}; + +struct mail_search_mime_register *mail_search_mime_register = NULL; + +static void +mail_search_register_add_default(void); + +/* + * Register + */ + +static struct mail_search_mime_register * +mail_search_mime_register_init(void) +{ + struct mail_search_mime_register *reg = + mail_search_mime_register; + if (reg == NULL) { + reg = i_new(struct mail_search_mime_register, 1); + i_array_init(®->args, 64); + + mail_search_mime_register = reg; + mail_search_register_add_default(); + } + + return reg; +} + +void mail_search_mime_register_deinit(void) +{ + struct mail_search_mime_register *reg = + mail_search_mime_register; + + mail_search_mime_register = NULL; + if (reg == NULL) + return; + + array_free(®->args); + i_free(reg); +} + +void mail_search_mime_register_add( + const struct mail_search_mime_register_arg *arg, + unsigned int count) +{ + struct mail_search_mime_register *reg = + mail_search_mime_register_init(); + + array_append(®->args, arg, count); + reg->args_sorted = FALSE; +} + +static int +mail_search_mime_register_arg_cmp( + const struct mail_search_mime_register_arg *arg1, + const struct mail_search_mime_register_arg *arg2) +{ + return strcmp(arg1->key, arg2->key); +} + +const struct mail_search_mime_register_arg * +mail_search_mime_register_get(unsigned int *count_r) +{ + struct mail_search_mime_register *reg = + mail_search_mime_register_init(); + + if (!reg->args_sorted) { + array_sort(®->args, mail_search_mime_register_arg_cmp); + reg->args_sorted = TRUE; + } + + return array_get(®->args, count_r); +} + +const struct mail_search_mime_register_arg * +mail_search_mime_register_find(const char *key) +{ + struct mail_search_mime_register_arg arg; + struct mail_search_mime_register *reg = + mail_search_mime_register_init(); + + if (!reg->args_sorted) { + array_sort(®->args, mail_search_mime_register_arg_cmp); + reg->args_sorted = TRUE; + } + + arg.key = key; + return array_bsearch(®->args, &arg, mail_search_mime_register_arg_cmp); +} + +/* + * Default MIMEPART args + */ + +static struct mail_search_mime_arg * +mail_search_mime_not(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg; + + if (mail_search_mime_build_key(ctx, ctx->parent, &smarg) < 0) + return NULL; + + smarg->match_not = !smarg->match_not; + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_or(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg, **subargs; + + /* */ + smarg = mail_search_mime_build_new(ctx, SEARCH_MIME_OR); + + subargs = &smarg->value.subargs; + do { + if (mail_search_mime_build_key(ctx, smarg, subargs) < 0) + return NULL; + subargs = &(*subargs)->next; + + /* OR OR ... - put them all + under one SEARCH_MIME_OR list. */ + } while (mail_search_parse_skip_next(ctx->ctx->parser, "OR")); + + if (mail_search_mime_build_key(ctx, smarg, subargs) < 0) + return NULL; + return smarg; +} + +#define CALLBACK_STR(_func, _type) \ +static struct mail_search_mime_arg *\ +mail_search_mime_##_func(struct mail_search_mime_build_context *ctx) \ +{ \ + return mail_search_mime_build_str(ctx, _type); \ +} + +static struct mail_search_mime_arg * +arg_new_date(struct mail_search_mime_build_context *ctx, + enum mail_search_mime_arg_type type) +{ + struct mail_search_mime_arg *smarg; + const char *value; + + smarg = mail_search_mime_build_new(ctx, type); + if (mail_search_parse_string(ctx->ctx->parser, &value) < 0) + return NULL; + if (!imap_parse_date(value, &smarg->value.time)) { + ctx->ctx->_error = "Invalid search date parameter"; + return NULL; + } + return smarg; +} + +#define CALLBACK_DATE(_func, _type) \ +static struct mail_search_mime_arg *\ +mail_search_mime_##_func(struct mail_search_mime_build_context *ctx) \ +{ \ + return arg_new_date(ctx, _type); \ +} +CALLBACK_DATE(sentbefore, SEARCH_MIME_SENTBEFORE) +CALLBACK_DATE(senton, SEARCH_MIME_SENTON) +CALLBACK_DATE(sentsince, SEARCH_MIME_SENTSINCE) + +static struct mail_search_mime_arg * +mail_search_mime_size(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg; + enum mail_search_mime_arg_type type; + const char *key, *value; + uoff_t size; + + if (mail_search_parse_key(ctx->ctx->parser, &key) <= 0) { + ctx->ctx->_error = "Invalid MIMEPART SIZE key type"; + return NULL; + } + + key = t_str_ucase(key); + if (strcmp(key, "LARGER") == 0) + type = SEARCH_MIME_SIZE_LARGER; + else if (strcmp(key, "SMALLER") == 0) + type = SEARCH_MIME_SIZE_SMALLER; + else { + type = SEARCH_MIME_SIZE_EQUAL; + value = key; + } + + if (type != SEARCH_MIME_SIZE_EQUAL && + mail_search_parse_string(ctx->ctx->parser, &value) < 0) { + ctx->ctx->_error = "Invalid MIMEPART SIZE value"; + return NULL; + } + + if (str_to_uoff(value, &size) < 0) { + ctx->ctx->_error = "Invalid MIMEPART SIZE value"; + return NULL; + } + + smarg = mail_search_mime_build_new(ctx, type); + smarg->value.size = size; + return smarg; +} + +CALLBACK_STR(description, SEARCH_MIME_DESCRIPTION) +CALLBACK_STR(encoding, SEARCH_MIME_ENCODING) +CALLBACK_STR(id, SEARCH_MIME_ID) +CALLBACK_STR(language, SEARCH_MIME_LANGUAGE) +CALLBACK_STR(location, SEARCH_MIME_LOCATION) +CALLBACK_STR(md5, SEARCH_MIME_MD5) + +CALLBACK_STR(type, SEARCH_MIME_TYPE) +CALLBACK_STR(subtype, SEARCH_MIME_SUBTYPE) + +CALLBACK_STR(bcc, SEARCH_MIME_BCC) +CALLBACK_STR(cc, SEARCH_MIME_CC) +CALLBACK_STR(from, SEARCH_MIME_FROM) +CALLBACK_STR(in_reply_to, SEARCH_MIME_IN_REPLY_TO) +CALLBACK_STR(message_id, SEARCH_MIME_MESSAGE_ID) +CALLBACK_STR(reply_to, SEARCH_MIME_REPLY_TO) +CALLBACK_STR(sender, SEARCH_MIME_SENDER) +CALLBACK_STR(subject, SEARCH_MIME_SUBJECT) +CALLBACK_STR(to, SEARCH_MIME_TO) + +static struct mail_search_mime_arg * +arg_new_field(struct mail_search_mime_build_context *ctx, + enum mail_search_mime_arg_type type) +{ + struct mail_search_mime_arg *smarg; + const char *field_name, *value; + + /* */ + if (mail_search_parse_string(ctx->ctx->parser, &field_name) < 0) + return NULL; + if (mail_search_build_get_utf8(ctx->ctx, field_name, &field_name) < 0) + return NULL; + if (mail_search_parse_string(ctx->ctx->parser, &value) < 0) + return NULL; + if (mail_search_build_get_utf8(ctx->ctx, value, &value) < 0) + return NULL; + + smarg = mail_search_mime_build_new(ctx, type); + smarg->field_name = str_ucase(p_strdup(ctx->ctx->pool, field_name)); + smarg->value.str = value; + + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_param(struct mail_search_mime_build_context *ctx) +{ + return arg_new_field + (ctx, SEARCH_MIME_PARAM); +} + +static struct mail_search_mime_arg * +mail_search_mime_header(struct mail_search_mime_build_context *ctx) +{ + return arg_new_field + (ctx, SEARCH_MIME_HEADER); +} + +static struct mail_search_mime_arg * +arg_new_body(struct mail_search_mime_build_context *ctx, + enum mail_search_mime_arg_type type) +{ + struct mail_search_mime_arg *smarg; + + smarg = mail_search_mime_build_str(ctx, type); + if (smarg == NULL) + return NULL; + + if (mail_search_build_get_utf8(ctx->ctx, smarg->value.str, + &smarg->value.str) < 0) + return NULL; + return smarg; +} + +#define CALLBACK_BODY(_func, _type) \ +static struct mail_search_mime_arg *\ +mail_search_mime_##_func(struct mail_search_mime_build_context *ctx) \ +{ \ + return arg_new_body(ctx, _type); \ +} +CALLBACK_BODY(body, SEARCH_MIME_BODY) +CALLBACK_BODY(text, SEARCH_MIME_TEXT) + +static struct mail_search_mime_arg * +mail_search_mime_disposition(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg; + const char *key, *value; + + if (mail_search_parse_key(ctx->ctx->parser, &key) <= 0) { + ctx->ctx->_error = "Invalid MIMEPART DISPOSITION key type"; + return NULL; + } + + key = t_str_ucase(key); + if (strcmp(key, "TYPE") == 0) { + if (mail_search_parse_string(ctx->ctx->parser, &value) < 0) { + ctx->ctx->_error = "Invalid MIMEPART DISPOSITION TYPE value"; + return NULL; + } + smarg = mail_search_mime_build_new + (ctx, SEARCH_MIME_DISPOSITION_TYPE); + smarg->value.str = p_strdup(ctx->ctx->pool, value); + return smarg; + } else if (strcmp(key, "PARAM") == 0) { + return arg_new_field + (ctx, SEARCH_MIME_DISPOSITION_PARAM); + } + + ctx->ctx->_error = "Invalid MIMEPART DISPOSITION key type"; + return NULL; +} + +static struct mail_search_mime_arg * +mail_search_mime_depth(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg; + enum mail_search_mime_arg_type type; + const char *key, *value; + unsigned int depth; + + if (mail_search_parse_key(ctx->ctx->parser, &key) <= 0) { + ctx->ctx->_error = "Invalid MIMEPART DEPTH key"; + return NULL; + } + + key = t_str_ucase(key); + if (strcmp(key, "MIN") == 0) + type = SEARCH_MIME_DEPTH_MIN; + else if (strcmp(key, "MAX") == 0) + type = SEARCH_MIME_DEPTH_MAX; + else { + type = SEARCH_MIME_DEPTH_EQUAL; + value = key; + } + + if (type != SEARCH_MIME_DEPTH_EQUAL && + mail_search_parse_string(ctx->ctx->parser, &value) < 0) { + ctx->ctx->_error = "Invalid MIMEPART DEPTH value"; + return NULL; + } + + if (str_to_uint(value, &depth) < 0) { + ctx->ctx->_error = "Invalid MIMEPART DEPTH level"; + return NULL; + } + + smarg = mail_search_mime_build_new(ctx, type); + smarg->value.number = depth; + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_index(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg; + const char *value; + unsigned int index; + + if (mail_search_parse_string(ctx->ctx->parser, &value) < 0) { + ctx->ctx->_error = "Invalid MIMEPART INDEX value"; + return NULL; + } + + if (str_to_uint(value, &index) < 0) { + ctx->ctx->_error = "Invalid MIMEPART INDEX number"; + return NULL; + } + + smarg = mail_search_mime_build_new + (ctx, SEARCH_MIME_INDEX); + smarg->value.number = index; + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_filename(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg; + enum mail_search_mime_arg_type type; + const char *key, *value; + + if (mail_search_parse_key(ctx->ctx->parser, &key) <= 0) { + ctx->ctx->_error = "Invalid MIMEPART FILENAME match type"; + return NULL; + } + + key = t_str_ucase(key); + if (strcmp(key, "IS") == 0) + type = SEARCH_MIME_FILENAME_IS; + else if (strcmp(key, "CONTAINS") == 0) + type = SEARCH_MIME_FILENAME_CONTAINS; + else if (strcmp(key, "BEGINS") == 0) + type = SEARCH_MIME_FILENAME_BEGINS; + else if (strcmp(key, "ENDS") == 0) + type = SEARCH_MIME_FILENAME_ENDS; + else { + ctx->ctx->_error = "Invalid MIMEPART FILENAME match type"; + return NULL; + } + + if (mail_search_parse_string(ctx->ctx->parser, &value) < 0) { + ctx->ctx->_error = "Invalid MIMEPART FILENAME string value"; + return NULL; + } + + if (mail_search_build_get_utf8(ctx->ctx, value, &value) < 0) { + ctx->ctx->_error = "Invalid MIMEPART FILENAME stromg value"; + return NULL; + } + + smarg = mail_search_mime_build_new(ctx, type); + smarg->value.str = value; + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_parent(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg, *subargs; + + smarg = mail_search_mime_build_new(ctx, SEARCH_MIME_PARENT); + if (mail_search_mime_build_key(ctx, smarg, &subargs) < 0) + return NULL; + if (subargs == smarg) + smarg->value.subargs = NULL; + else if (subargs->type == SEARCH_MIME_SUB) + smarg->value.subargs = subargs->value.subargs; + else + smarg->value.subargs = subargs; + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_child(struct mail_search_mime_build_context *ctx) +{ + struct mail_search_mime_arg *smarg, *subargs; + + smarg = mail_search_mime_build_new(ctx, SEARCH_MIME_CHILD); + if (mail_search_mime_build_key(ctx, smarg, &subargs) < 0) + return NULL; + if (subargs == smarg) + smarg->value.subargs = NULL; + else if (subargs->type == SEARCH_MIME_SUB) + smarg->value.subargs = subargs->value.subargs; + else + smarg->value.subargs = subargs; + return smarg; +} + +static struct mail_search_mime_arg * +mail_search_mime_exists(struct mail_search_mime_build_context *ctx) +{ + if (ctx->parent == NULL || + (ctx->parent->type != SEARCH_MIME_PARENT && + ctx->parent->type != SEARCH_MIME_CHILD)) { + ctx->ctx->_error = "EXISTS key can only be used with PARENT or CHILD"; + return NULL; + } + return ctx->parent; +} + +static const struct mail_search_mime_register_arg +mime_register_args[] = { + /* argument set operations */ + { "NOT", mail_search_mime_not }, + { "OR", mail_search_mime_or }, + + /* dates */ + { "SENTBEFORE", mail_search_mime_sentbefore }, + { "SENTON", mail_search_mime_senton }, + { "SENTSINCE", mail_search_mime_sentsince }, + + /* size */ + { "SIZE", mail_search_mime_size }, + + /* part properties */ + { "DESCRIPTION", mail_search_mime_description }, + { "DISPOSITION", mail_search_mime_disposition }, + { "ENCODING", mail_search_mime_encoding }, + { "ID", mail_search_mime_id }, + { "LANGUAGE", mail_search_mime_language }, + { "LOCATION", mail_search_mime_location }, + { "MD5", mail_search_mime_md5 }, + + /* content-type */ + { "TYPE", mail_search_mime_type }, + { "SUBTYPE", mail_search_mime_subtype }, + { "PARAM", mail_search_mime_param }, + + /* headers */ + { "HEADER", mail_search_mime_header }, + + /* message */ + { "BCC", mail_search_mime_bcc }, + { "CC", mail_search_mime_cc }, + { "FROM", mail_search_mime_from }, + { "IN-REPLY-TO", mail_search_mime_in_reply_to }, + { "MESSAGE-ID", mail_search_mime_message_id }, + { "REPLY-TO", mail_search_mime_reply_to }, + { "SENDER", mail_search_mime_sender }, + { "SUBJECT", mail_search_mime_subject }, + { "TO", mail_search_mime_to }, + + /* body */ + { "BODY", mail_search_mime_body }, + { "TEXT", mail_search_mime_text }, + + /* position */ + { "DEPTH", mail_search_mime_depth }, + { "INDEX", mail_search_mime_index }, + + /* relations */ + { "PARENT", mail_search_mime_parent }, + { "CHILD", mail_search_mime_child }, + { "EXISTS", mail_search_mime_exists }, + + /* filename */ + { "FILENAME", mail_search_mime_filename }, +}; + +static void +mail_search_register_add_default(void) +{ + mail_search_mime_register_add(mime_register_args, + N_ELEMENTS(mime_register_args)); +} -- cgit v1.2.3