From: Stephan Bosch Date: Sun, 16 Sep 2018 10:55:24 +0000 (+0200) Subject: imap: cmd-list - Add infrastructure for dynamically adding support for new RETURN... X-Git-Tag: 2.4.1~157 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=444de47a2b34d5e436d630347346139527b992fa;p=thirdparty%2Fdovecot%2Fcore.git imap: cmd-list - Add infrastructure for dynamically adding support for new RETURN flags This is needed for the new IMAP LIST-MYRIGHTS capability (RFC 8440). --- diff --git a/src/imap/cmd-list.c b/src/imap/cmd-list.c index 1c9437b397..7930fd0aad 100644 --- a/src/imap/cmd-list.c +++ b/src/imap/cmd-list.c @@ -11,12 +11,19 @@ #include "imap-commands.h" #include "imap-list.h" +struct cmd_list_return_flag { + const struct imap_list_return_flag *flag; + + void *context; +}; + struct cmd_list_context { struct client_command_context *cmd; struct mail_user *user; enum mailbox_list_iter_flags list_flags; struct imap_status_items status_items; + ARRAY(struct cmd_list_return_flag) return_flags; struct mailbox_list_iterate_context *list_iter; @@ -121,6 +128,9 @@ parse_return_flags(struct cmd_list_context *ctx, const struct imap_arg *args) enum mailbox_list_iter_flags list_flags = 0; const struct imap_arg *list_args; const char *str; + const struct imap_list_return_flag *flag; + void *flag_context; + int ret; while (!IMAP_ARG_IS_EOL(args)) { if (!imap_arg_get_atom(args, &str)) { @@ -142,6 +152,19 @@ parse_return_flags(struct cmd_list_context *ctx, const struct imap_arg *args) return FALSE; ctx->used_status = TRUE; args++; + } else if ((ret = imap_list_return_flag_parse( + ctx->cmd, str, &args, &flag, &flag_context)) > 0) { + struct cmd_list_return_flag *flag_data; + + if (!array_is_created(&ctx->return_flags)) { + p_array_init(&ctx->return_flags, + ctx->cmd->pool, 8); + } + flag_data = array_append_space(&ctx->return_flags); + flag_data->flag = flag; + flag_data->context = flag_context; + } else if (ret < 0) { + return FALSE; } else { /* skip also optional list value */ client_send_command_error(ctx->cmd, @@ -208,6 +231,33 @@ list_send_status(struct cmd_list_context *ctx, &ctx->status_items, &result); } +static bool +list_has_options(struct cmd_list_context *ctx) +{ + if (ctx->used_status) + return TRUE; + return array_is_created(&ctx->return_flags); +} + +static void +list_send_options(struct cmd_list_context *ctx, + const struct imap_list_return_flag_params *params) +{ + struct client_command_context *cmd = ctx->cmd; + + if (ctx->used_status) + list_send_status(ctx, params); + + if (array_is_created(&ctx->return_flags)) { + const struct cmd_list_return_flag *rflag; + + array_foreach(&ctx->return_flags, rflag) { + imap_list_return_flag_send(cmd, rflag->flag, + rflag->context, params); + } + } +} + static bool cmd_list_continue(struct client_command_context *cmd) { struct cmd_list_context *ctx = cmd->context; @@ -255,8 +305,8 @@ static bool cmd_list_continue(struct client_command_context *cmd) if (ret < 0) return TRUE; - /* send STATUS response */ - if (ctx->used_status) { + /* send optional responses (if any) */ + if (list_has_options(ctx)) { struct imap_list_return_flag_params params = { .name = name, .mutf7_name = str_c(mutf7_name), @@ -271,7 +321,7 @@ static bool cmd_list_continue(struct client_command_context *cmd) params.name); T_BEGIN { - list_send_status(ctx, ¶ms); + list_send_options(ctx, ¶ms); } T_END; } if (ret == 0) { diff --git a/src/imap/imap-list.c b/src/imap/imap-list.c index 38a81ba5d6..bf4bf51bc9 100644 --- a/src/imap/imap-list.c +++ b/src/imap/imap-list.c @@ -4,6 +4,65 @@ #include "str.h" #include "imap-list.h" +static ARRAY(const struct imap_list_return_flag *) return_flags; + +void imap_list_return_flag_register(const struct imap_list_return_flag *rflag) +{ + array_push_back(&return_flags, &rflag); +} + +void imap_list_return_flag_unregister(const struct imap_list_return_flag *rflag) +{ + unsigned int i; + + if (array_lsearch_ptr_idx(&return_flags, rflag, &i)) { + array_delete(&return_flags, i, 1); + return; + } + + i_panic("Trying to unregister unknown IMAP LIST RETURN flag '%s'", + rflag->identifier); +} + +int imap_list_return_flag_parse(struct client_command_context *cmd, + const char *flag, const struct imap_arg **args, + const struct imap_list_return_flag **rflag_r, + void **context_r) +{ + const struct imap_list_return_flag *const *rflags; + unsigned int i, count; + + rflags = array_get(&return_flags, &count); + for (i = 0; i < count; i++) { + if (strcasecmp(rflags[i]->identifier, flag) == 0) + break; + } + + if (i == count) + return 0; + + *context_r = NULL; + if (rflags[i]->parse != NULL) { + const struct imap_arg *list_args = NULL; + + if (imap_arg_get_list(*args, &list_args)) + (*args)++; + if (rflags[i]->parse(cmd, list_args, context_r) < 0) + return -1; + } + + *rflag_r = rflags[i]; + return 1; +} + +void imap_list_return_flag_send( + struct client_command_context *cmd, + const struct imap_list_return_flag *rflag, void *context, + const struct imap_list_return_flag_params *params) +{ + rflag->send(cmd, context, params); +} + bool imap_mailbox_flags2str(string_t *str, enum mailbox_info_flags flags) { size_t orig_len = str_len(str); @@ -33,3 +92,13 @@ bool imap_mailbox_flags2str(string_t *str, enum mailbox_info_flags flags) str_truncate(str, str_len(str)-1); return TRUE; } + +void imap_list_init(void) +{ + i_array_init(&return_flags, 8); +} + +void imap_list_deinit(void) +{ + array_free(&return_flags); +} diff --git a/src/imap/imap-list.h b/src/imap/imap-list.h index 2dbbce3279..4c3e8b9388 100644 --- a/src/imap/imap-list.h +++ b/src/imap/imap-list.h @@ -12,7 +12,31 @@ struct imap_list_return_flag_params { struct mail_namespace *ns; }; +struct imap_list_return_flag { + const char *identifier; + + int (*parse)(struct client_command_context *cmd, + const struct imap_arg *args, void **context_r); + void (*send)(struct client_command_context *cmd, void *context, + const struct imap_list_return_flag_params *params); +}; + +void imap_list_return_flag_register(const struct imap_list_return_flag *rflag); +void imap_list_return_flag_unregister(const struct imap_list_return_flag *rflag); + +int imap_list_return_flag_parse(struct client_command_context *cmd, + const char *flag, const struct imap_arg **args, + const struct imap_list_return_flag **rflag_r, + void **context_r); +void imap_list_return_flag_send( + struct client_command_context *cmd, + const struct imap_list_return_flag *rflag, void *context, + const struct imap_list_return_flag_params *params); + /* Returns TRUE if anything was added to the string. */ bool imap_mailbox_flags2str(string_t *str, enum mailbox_info_flags flags); +void imap_list_init(void); +void imap_list_deinit(void); + #endif diff --git a/src/imap/main.c b/src/imap/main.c index 06535cba54..fa2fbe309e 100644 --- a/src/imap/main.c +++ b/src/imap/main.c @@ -25,6 +25,7 @@ #include "imap-commands.h" #include "imap-feature.h" #include "imap-fetch.h" +#include "imap-list.h" #include #include @@ -553,6 +554,7 @@ int main(int argc, char *argv[]) imap_features_init(); clients_init(); imap_master_clients_init(); + imap_list_init(); /* this is needed before settings are read */ verbose_proctitle = !IS_STANDALONE() && getenv(MASTER_VERBOSE_PROCTITLE_ENV) != NULL; @@ -599,6 +601,7 @@ int main(int argc, char *argv[]) login_server_deinit(&login_server); mail_storage_service_deinit(&storage_service); + imap_list_deinit(); imap_fetch_handlers_deinit(); imap_features_deinit();