]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm-server: Many fixes to make it actually work properly.
authorTimo Sirainen <tss@iki.fi>
Sun, 7 Aug 2011 19:11:20 +0000 (22:11 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 7 Aug 2011 19:11:20 +0000 (22:11 +0300)
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

index 4ee66c532dd981a0ed808b9aa1f93ced1f11ad9b..2cf38406bb6834c06fb34a588aa1014dc2783c20 100644 (file)
@@ -60,6 +60,8 @@ doveadm_mail_cmd_server(const char *cmd_name,
                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 @@ doveadm_mail_cmd_server(const char *cmd_name,
                }
        }
 
-       argv += optind-1;
+       argv += optind;
        optind = 1;
 
        if (argv[0] != NULL && cmd->usage_args == NULL) {
@@ -153,8 +155,9 @@ static bool client_handle_command(struct client_connection *conn, char **args)
        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 @@ static void client_connection_input(struct client_connection *conn)
        }
        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;
        }
 
index 873adfbea3faff8aad7a771732c85ad3d6e3d10d..e6fd0f3e2071275d5840edd87a2165b45a18710b 100644 (file)
@@ -125,9 +125,9 @@ static void doveadm_mail_server_handle(struct server_connection *conn,
        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);
index 977be31da437a66995bda50cd2795a933f9ae8bc..513565293fb8d12351b3a5ab1e86c6e7386d3e30 100644 (file)
@@ -366,6 +366,7 @@ doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[])
                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");
index f12c0dada5fc7b8877a030afe3ab848188a132c8..aadea6a02527bb51917dcd7e8980237b36358a1e 100644 (file)
@@ -37,6 +37,8 @@ struct doveadm_mail_cmd_context {
        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;
index 6bd03bbe15bdf71b0bb8cb6b224e5a5624c3233e..57fa7a4d1d15fb40a28dd3c953bf621a6e419f87 100644 (file)
@@ -65,6 +65,9 @@ doveadm_print_server_print_stream(const unsigned char *value, size_t size)
 
 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);
index e264854456ac348a35d1df2fdefc2ee2c5a67062..549ecef6f6617b34ca0f1e13f822f25ea1a225f6 100644 (file)
@@ -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 @@ enum server_reply_state {
 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 @@ server_connection_authenticate(struct server_connection *conn)
        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 @@ static void server_connection_input(struct server_connection *conn)
                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 @@ static void server_connection_input(struct server_connection *conn)
                }
        }
 
+       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 @@ static void server_connection_input(struct server_connection *conn)
                        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 @@ server_connection_create(struct doveadm_server *server)
        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 @@ void server_connection_destroy(struct server_connection **_conn)
                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 @@ server_connection_get_server(struct server_connection *conn)
 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;
 }