From: Timo Sirainen Date: Fri, 26 Aug 2011 02:08:42 +0000 (+0300) Subject: imap: Added hooks that can be run always before/after any command handler. X-Git-Tag: 2.1.alpha1~52 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b69f4d33ffd8a505e2e6472a395026dc43f538ee;p=thirdparty%2Fdovecot%2Fcore.git imap: Added hooks that can be run always before/after any command handler. --- diff --git a/src/imap/cmd-append.c b/src/imap/cmd-append.c index 04b8aabefa..d4f61693ac 100644 --- a/src/imap/cmd-append.c +++ b/src/imap/cmd-append.c @@ -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 diff --git a/src/imap/cmd-uid.c b/src/imap/cmd-uid.c index bc30eef759..3d1c38e5db 100644 --- a/src/imap/cmd-uid.c +++ b/src/imap/cmd-uid.c @@ -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); } diff --git a/src/imap/imap-client.c b/src/imap/imap-client.c index d1204cc208..4e1402494a 100644 --- a/src/imap/imap-client.c +++ b/src/imap/imap-client.c @@ -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); diff --git a/src/imap/imap-commands.c b/src/imap/imap-commands.c index e637d8ae65..a0715da6d5 100644 --- a/src/imap/imap-commands.c +++ b/src/imap/imap-commands.c @@ -7,6 +7,11 @@ #include +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); } diff --git a/src/imap/imap-commands.h b/src/imap/imap-commands.h index dc6391c819..d66106b49b 100644 --- a/src/imap/imap-commands.h +++ b/src/imap/imap-commands.h @@ -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);