changeset 13291:6eb42d5d0ce3

imap: Added hooks that can be run always before/after any command handler.
author Timo Sirainen <tss@iki.fi>
date Fri, 26 Aug 2011 05:08:42 +0300
parents d473660bc54d
children 78f9f28b5d24
files 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
diffstat 5 files changed, 63 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-append.c	Fri Aug 26 05:07:53 2011 +0300
+++ b/src/imap/cmd-append.c	Fri Aug 26 05:08:42 2011 +0300
@@ -98,7 +98,7 @@
 	}
 
 	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
--- a/src/imap/cmd-uid.c	Fri Aug 26 05:07:53 2011 +0300
+++ b/src/imap/cmd-uid.c	Fri Aug 26 05:08:42 2011 +0300
@@ -24,5 +24,5 @@
 	cmd->cmd_flags = command->flags;
 	cmd->func = command->func;
 	cmd->uid = TRUE;
-	return cmd->func(cmd);
+	return command_exec(cmd);
 }
--- a/src/imap/imap-client.c	Fri Aug 26 05:07:53 2011 +0300
+++ b/src/imap/imap-client.c	Fri Aug 26 05:08:42 2011 +0300
@@ -123,7 +123,8 @@
 		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 @@
 
         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 @@
 	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);
--- a/src/imap/imap-commands.c	Fri Aug 26 05:07:53 2011 +0300
+++ b/src/imap/imap-commands.c	Fri Aug 26 05:08:42 2011 +0300
@@ -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 @@
 
 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_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 @@
 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 @@
         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);
 }
--- a/src/imap/imap-commands.h	Fri Aug 26 05:07:53 2011 +0300
+++ b/src/imap/imap-commands.h	Fri Aug 26 05:08:42 2011 +0300
@@ -10,6 +10,7 @@
 #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_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);