]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: cmd-list - Add infrastructure for dynamically adding support for new RETURN...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 16 Sep 2018 10:55:24 +0000 (12:55 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Tue, 25 Feb 2025 11:24:51 +0000 (11:24 +0000)
This is needed for the new IMAP LIST-MYRIGHTS capability (RFC 8440).

src/imap/cmd-list.c
src/imap/imap-list.c
src/imap/imap-list.h
src/imap/main.c

index 1c9437b3977491be72b57fd99a12377b67adccf4..7930fd0aadd0f28d759652c9b01f52b38d0ede7f 100644 (file)
 #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, &params);
+                               list_send_options(ctx, &params);
                        } T_END;
                }
                if (ret == 0) {
index 38a81ba5d6b4ed84a201af506628f88472ede2a9..bf4bf51bc950fa6a895a47cc136b21cbef998349 100644 (file)
@@ -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);
+}
index 2dbbce3279bbf94c434a6ff99fae6c9708a487eb..4c3e8b9388f7834aaa1b005a05abd63f168a44d1 100644 (file)
@@ -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
index 06535cba54328ad213f2004a281a7083a4e62807..fa2fbe309e6aadcae067cbdfcaf11bdaede577f8 100644 (file)
@@ -25,6 +25,7 @@
 #include "imap-commands.h"
 #include "imap-feature.h"
 #include "imap-fetch.h"
+#include "imap-list.h"
 
 #include <stdio.h>
 #include <unistd.h>
@@ -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();