]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Added hooks that can be run always before/after any command handler.
authorTimo Sirainen <tss@iki.fi>
Fri, 26 Aug 2011 02:08:42 +0000 (05:08 +0300)
committerTimo Sirainen <tss@iki.fi>
Fri, 26 Aug 2011 02:08:42 +0000 (05:08 +0300)
src/imap/cmd-append.c
src/imap/cmd-uid.c
src/imap/imap-client.c
src/imap/imap-commands.c
src/imap/imap-commands.h

index 04b8aabefa64ab33ca351d05ec35a714530c9868..d4f61693ac92f038d2a01a46ada281c8e2f8379e 100644 (file)
@@ -98,7 +98,7 @@ static void client_input_append(struct client_command_context *cmd)
        }
 
        o_stream_cork(client->output);
-       finished = cmd->func(cmd);
+       finished = command_exec(cmd);
        if (!finished && cmd->state != CLIENT_COMMAND_STATE_DONE)
                (void)client_handle_unfinished_cmd(cmd);
        else
index bc30eef7592010b071230615ea5d637ac1edfed2..3d1c38e5db7319424b9af7cdebfe54cb07329039 100644 (file)
@@ -24,5 +24,5 @@ bool cmd_uid(struct client_command_context *cmd)
        cmd->cmd_flags = command->flags;
        cmd->func = command->func;
        cmd->uid = TRUE;
-       return cmd->func(cmd);
+       return command_exec(cmd);
 }
index d1204cc208c9049515c49c7ef4d9d1f8f66936d0..4e1402494acfd6122ce96290102ac55c26749b7a 100644 (file)
@@ -123,7 +123,8 @@ void client_command_cancel(struct client_command_context **_cmd)
                i_unreached();
        }
 
-       cmd_ret = !cmd->cancel || cmd->func == NULL ? TRUE : cmd->func(cmd);
+       cmd_ret = !cmd->cancel || cmd->func == NULL ? TRUE :
+               command_exec(cmd);
        if (!cmd_ret && cmd->state != CLIENT_COMMAND_STATE_DONE) {
                if (cmd->client->output->closed)
                        i_panic("command didn't cancel itself: %s", cmd->name);
@@ -669,7 +670,8 @@ static bool client_command_input(struct client_command_context *cmd)
 
         if (cmd->func != NULL) {
                /* command is being executed - continue it */
-               if (cmd->func(cmd) || cmd->state == CLIENT_COMMAND_STATE_DONE) {
+               if (command_exec(cmd) ||
+                   cmd->state == CLIENT_COMMAND_STATE_DONE) {
                        /* command execution was finished */
                        client_command_free(&cmd);
                        client_add_missing_io(client);
@@ -837,7 +839,7 @@ static void client_output_cmd(struct client_command_context *cmd)
        bool finished;
 
        /* continue processing command */
-       finished = cmd->func(cmd) || cmd->state == CLIENT_COMMAND_STATE_DONE;
+       finished = command_exec(cmd) || cmd->state == CLIENT_COMMAND_STATE_DONE;
 
        if (!finished)
                (void)client_handle_unfinished_cmd(cmd);
index e637d8ae65894bf9e6c69e7d1a23db4c26a5ada9..a0715da6d508c68f1626b3a79d8eaa5e9ad9675e 100644 (file)
@@ -7,6 +7,11 @@
 
 #include <stdlib.h>
 
+struct command_hook {
+       command_hook_callback_t *pre;
+       command_hook_callback_t *post;
+};
+
 static const struct command imap4rev1_commands[] = {
        { "CAPABILITY",         cmd_capability,  0 },
        { "LOGOUT",             cmd_logout,      COMMAND_FLAG_BREAKS_MAILBOX },
@@ -60,6 +65,7 @@ static const struct command imap_ext_commands[] = {
 
 ARRAY_TYPE(command) imap_commands;
 static bool commands_unsorted;
+static ARRAY_DEFINE(command_hooks, struct command_hook);
 
 void command_register(const char *name, command_func_t *func,
                      enum command_flags flags)
@@ -105,6 +111,45 @@ void command_unregister_array(const struct command *cmdarr, unsigned int count)
        }
 }
 
+void command_hook_register(command_hook_callback_t *pre,
+                          command_hook_callback_t *post)
+{
+       struct command_hook hook;
+
+       hook.pre = pre;
+       hook.post = post;
+       array_append(&command_hooks, &hook, 1);
+}
+
+void command_hook_unregister(command_hook_callback_t *pre,
+                            command_hook_callback_t *post)
+{
+       const struct command_hook *hooks;
+       unsigned int i, count;
+
+       hooks = array_get(&command_hooks, &count);
+       for (i = 0; i < count; i++) {
+               if (hooks[i].pre == pre && hooks[i].post == post) {
+                       array_delete(&command_hooks, i, 1);
+                       return;
+               }
+       }
+       i_panic("command_hook_unregister(): hook not registered");
+}
+
+bool command_exec(struct client_command_context *cmd)
+{
+       const struct command_hook *hook;
+       bool ret;
+
+       array_foreach(&command_hooks, hook)
+               hook->pre(cmd);
+       ret = cmd->func(cmd);
+       array_foreach(&command_hooks, hook)
+               hook->post(cmd);
+       return ret;
+}
+
 static int command_cmp(const struct command *c1, const struct command *c2)
 {
        return strcasecmp(c1->name, c2->name);
@@ -128,6 +173,7 @@ struct command *command_find(const char *name)
 void commands_init(void)
 {
        i_array_init(&imap_commands, 64);
+       i_array_init(&command_hooks, 4);
        commands_unsorted = FALSE;
 
         command_register_array(imap4rev1_commands, IMAP4REV1_COMMANDS_COUNT);
@@ -139,4 +185,5 @@ void commands_deinit(void)
         command_unregister_array(imap4rev1_commands, IMAP4REV1_COMMANDS_COUNT);
         command_unregister_array(imap_ext_commands, IMAP_EXT_COMMANDS_COUNT);
        array_free(&imap_commands);
+       array_free(&command_hooks);
 }
index dc6391c8194401f0c4cf78e9af07f061e2f1530a..d66106b49b5f3f93f5e36598dcaa4926551272ce 100644 (file)
@@ -10,6 +10,7 @@ struct client_command_context;
 #include "imap-commands-util.h"
 
 typedef bool command_func_t(struct client_command_context *cmd);
+typedef void command_hook_callback_t(struct client_command_context *ctx);
 
 enum command_flags {
        /* Command uses sequences as its input parameters */
@@ -52,6 +53,14 @@ void command_unregister(const char *name);
 void command_register_array(const struct command *cmdarr, unsigned int count);
 void command_unregister_array(const struct command *cmdarr, unsigned int count);
 
+/* Register hook callbacks that are called before and after all commands */
+void command_hook_register(command_hook_callback_t *pre,
+                          command_hook_callback_t *post);
+void command_hook_unregister(command_hook_callback_t *pre,
+                            command_hook_callback_t *post);
+/* Execute command and hooks */
+bool command_exec(struct client_command_context *cmd);
+
 struct command *command_find(const char *name);
 
 void commands_init(void);