changeset 13179:09eb79247e71

doveadm-server: Many fixes to make it actually work properly.
author Timo Sirainen <tss@iki.fi>
date Sun, 07 Aug 2011 22:11:20 +0300
parents 4babc93e87ea
children c0b7dde5b193
files src/doveadm/client-connection.c src/doveadm/doveadm-mail-server.c src/doveadm/doveadm-mail.c src/doveadm/doveadm-mail.h src/doveadm/doveadm-print-server.c src/doveadm/server-connection.c
diffstat 6 files changed, 82 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/client-connection.c	Sun Aug 07 22:10:23 2011 +0300
+++ b/src/doveadm/client-connection.c	Sun Aug 07 22:11:20 2011 +0300
@@ -60,6 +60,8 @@
 		service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG;
 
 	ctx = doveadm_mail_cmd_init(cmd, set);
+	ctx->full_args = (const void *)argv;
+
 	getopt_args = t_strconcat("Au:", ctx->getopt_args, NULL);
 	while ((c = getopt(argc, argv, getopt_args)) > 0) {
 		switch (c) {
@@ -83,7 +85,7 @@
 		}
 	}
 
-	argv += optind-1;
+	argv += optind;
 	optind = 1;
 
 	if (argv[0] != NULL && cmd->usage_args == NULL) {
@@ -153,8 +155,9 @@
 	flags = args[0];
 	input.username = args[1];
 	cmd_name = args[2];
-	args += 3;
-	argc -= 3;
+	/* leave the command name as args[0] so getopt() works */
+	args += 2;
+	argc -= 2;
 
 	doveadm_debug = FALSE;
 	doveadm_verbose = FALSE;
@@ -264,10 +267,13 @@
 	}
 	if (!conn->authenticated) {
 		if ((ret = client_connection_authenticate(conn)) <= 0) {
-			if (ret < 0)
+			if (ret < 0) {
+				o_stream_send(conn->output, "-\n", 2);
 				client_connection_destroy(&conn);
+			}
 			return;
 		}
+		o_stream_send(conn->output, "+\n", 2);
 		conn->authenticated = TRUE;
 	}
 
--- a/src/doveadm/doveadm-mail-server.c	Sun Aug 07 22:10:23 2011 +0300
+++ b/src/doveadm/doveadm-mail-server.c	Sun Aug 07 22:11:20 2011 +0300
@@ -125,9 +125,9 @@
 	str_tabescape_write(cmd, username);
 	str_append_c(cmd, '\t');
 	str_tabescape_write(cmd, cmd_ctx->cmd->name);
-	for (i = 0; cmd_ctx->args[i] != NULL; i++) {
+	for (i = 0; cmd_ctx->full_args[i] != NULL; i++) {
 		str_append_c(cmd, '\t');
-		str_tabescape_write(cmd, cmd_ctx->args[i]);
+		str_tabescape_write(cmd, cmd_ctx->full_args[i]);
 	}
 	str_append_c(cmd, '\n');
 	server_connection_cmd(conn, str_c(cmd), doveadm_cmd_callback, conn);
--- a/src/doveadm/doveadm-mail.c	Sun Aug 07 22:10:23 2011 +0300
+++ b/src/doveadm/doveadm-mail.c	Sun Aug 07 22:11:20 2011 +0300
@@ -366,6 +366,7 @@
 		service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG;
 
 	ctx = doveadm_mail_cmd_init(cmd, doveadm_settings);
+	ctx->full_args = (const void *)argv;
 
 	getopt_args = t_strconcat("AS:u:", ctx->getopt_args, NULL);
 	username = getenv("USER");
--- a/src/doveadm/doveadm-mail.h	Sun Aug 07 22:10:23 2011 +0300
+++ b/src/doveadm/doveadm-mail.h	Sun Aug 07 22:11:20 2011 +0300
@@ -37,6 +37,8 @@
 	pool_t pool;
 	const struct doveadm_mail_cmd *cmd;
 	const char *const *args;
+	/* args including -options */
+	const char *const *full_args;
 
 	const char *getopt_args;
 	const struct doveadm_settings *set;
--- a/src/doveadm/doveadm-print-server.c	Sun Aug 07 22:10:23 2011 +0300
+++ b/src/doveadm/doveadm-print-server.c	Sun Aug 07 22:11:20 2011 +0300
@@ -65,6 +65,9 @@
 
 static void doveadm_print_server_flush(void)
 {
+	if (doveadm_client == NULL)
+		return;
+
 	o_stream_send(client_connection_get_output(doveadm_client),
 		      str_data(ctx.str), str_len(ctx.str));
 	str_truncate(ctx.str, 0);
--- a/src/doveadm/server-connection.c	Sun Aug 07 22:10:23 2011 +0300
+++ b/src/doveadm/server-connection.c	Sun Aug 07 22:11:20 2011 +0300
@@ -9,6 +9,9 @@
 #include "ostream.h"
 #include "str.h"
 #include "strescape.h"
+#include "master-service.h"
+#include "master-service-settings.h"
+#include "settings-parser.h"
 #include "doveadm-print.h"
 #include "doveadm-util.h"
 #include "doveadm-server.h"
@@ -28,11 +31,15 @@
 struct server_connection {
 	struct doveadm_server *server;
 
+	pool_t pool;
+	struct doveadm_settings *set;
+
 	int fd;
 	struct io *io;
 	struct istream *input;
 	struct ostream *output;
 
+	const char *delayed_cmd;
 	server_cmd_callback_t *callback;
 	void *context;
 
@@ -157,21 +164,26 @@
 	string_t *plain = t_str_new(128);
 	string_t *cmd = t_str_new(128);
 
-	if (*doveadm_settings->doveadm_password == '\0') {
-		i_error("doveadm_password not set, can't authenticate");
+	if (*conn->set->doveadm_password == '\0') {
+		i_error("doveadm_password not set, "
+			"can't authenticate to remote server");
 		return -1;
 	}
 
 	str_append_c(plain, '\0');
 	str_append(plain, "doveadm");
 	str_append_c(plain, '\0');
-	str_append(plain, doveadm_settings->doveadm_password);
+	str_append(plain, conn->set->doveadm_password);
 
 	str_append(cmd, "PLAIN\t");
 	base64_encode(plain->data, plain->used, cmd);
 	str_append_c(cmd, '\n');
 
 	o_stream_send(conn->output, cmd->data, cmd->used);
+	if (conn->delayed_cmd != NULL) {
+		o_stream_send_str(conn->output, conn->delayed_cmd);
+		conn->delayed_cmd = NULL;
+	}
 	return 0;
 }
 
@@ -209,12 +221,9 @@
 		server_connection_destroy(&conn);
 		return;
 	}
-	data = i_stream_get_data(conn->input, &size);
-	if (size == 0)
-		return;
 
 	if (!conn->authenticated) {
-		if ((line = i_stream_next_line(conn->input)) != NULL)
+		if ((line = i_stream_next_line(conn->input)) == NULL)
 			return;
 		if (strcmp(line, "+") == 0)
 			conn->authenticated = TRUE;
@@ -225,6 +234,10 @@
 		}
 	}
 
+	data = i_stream_get_data(conn->input, &size);
+	if (size == 0)
+		return;
+
 	switch (conn->state) {
 	case SERVER_REPLY_STATE_DONE:
 		i_error("doveadm server sent unexpected input");
@@ -243,22 +256,53 @@
 			server_connection_callback(conn, SERVER_CMD_REPLY_OK);
 		else if (data[0] == '-' && data[1] == '\n')
 			server_connection_callback(conn, SERVER_CMD_REPLY_FAIL);
-		else {
+		else
 			i_error("doveadm server sent broken input");
-			server_connection_destroy(&conn);
-			return;
-		}
+		/* we're finished, close the connection */
+		server_connection_destroy(&conn);
 		break;
 	}
 }
 
+static int server_connection_read_settings(struct server_connection *conn)
+{
+	const struct setting_parser_info *set_roots[] = {
+		&doveadm_setting_parser_info,
+		NULL
+	};
+	struct master_service_settings_input input;
+	struct master_service_settings_output output;
+	const char *error;
+	unsigned int port;
+	void *set;
+
+	memset(&input, 0, sizeof(input));
+	input.roots = set_roots;
+	input.service = "doveadm";
+
+	(void)net_getsockname(conn->fd, &input.local_ip, &port);
+	(void)net_getpeername(conn->fd, &input.remote_ip, &port);
+
+	if (master_service_settings_read(master_service, &input,
+					 &output, &error) < 0) {
+		i_error("Error reading configuration: %s", error);
+		return -1;
+	}
+	set = master_service_settings_get_others(master_service)[0];
+	conn->set = settings_dup(&doveadm_setting_parser_info, set, conn->pool);
+	return 0;
+}
+
 struct server_connection *
 server_connection_create(struct doveadm_server *server)
 {
 #define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n"
 	struct server_connection *conn;
+	pool_t pool;
 
-	conn = i_new(struct server_connection, 1);
+	pool = pool_alloconly_create("doveadm server connection", 1024*16);
+	conn = p_new(pool, struct server_connection, 1);
+	conn->pool = pool;
 	conn->server = server;
 	conn->fd = doveadm_connect(server->name);
 	net_set_nonblock(conn->fd, TRUE);
@@ -269,6 +313,7 @@
 	o_stream_send_str(conn->output, DOVEADM_SERVER_HANDSHAKE);
 
 	array_append(&conn->server->connections, &conn, 1);
+	server_connection_read_settings(conn);
 	return conn;
 }
 
@@ -301,7 +346,7 @@
 		io_remove(&conn->io);
 	if (close(conn->fd) < 0)
 		i_error("close(server) failed: %m");
-	i_free(conn);
+	pool_unref(&conn->pool);
 }
 
 struct doveadm_server *
@@ -313,8 +358,13 @@
 void server_connection_cmd(struct server_connection *conn, const char *line,
 			   server_cmd_callback_t *callback, void *context)
 {
+	i_assert(conn->delayed_cmd == NULL);
+
 	conn->state = SERVER_REPLY_STATE_PRINT;
-	o_stream_send_str(conn->output, line);
+	if (conn->authenticated)
+		o_stream_send_str(conn->output, line);
+	else
+		conn->delayed_cmd = p_strdup(conn->pool, line);
 	conn->callback = callback;
 	conn->context = context;
 }