bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "lib.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "ioloop.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "net.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "istream.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "ostream.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "str.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "strescape.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include "dsync-client.h"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#include <unistd.h>
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#define DSYNC_FAIL_TIMEOUT_MSECS (1000*5)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen#define DOVEADM_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n"
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstruct dsync_client {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen char *path;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen int fd;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen struct io *io;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen struct istream *input;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen struct ostream *output;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen struct timeout *to;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen char *dsync_params;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen char *username;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen char *state;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen enum dsync_type sync_type;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback_t *callback;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen void *context;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen time_t last_connect_failure;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool handshaked:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool cmd_sent:1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen};
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainenstruct dsync_client *
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainendsync_client_init(const char *path, const char *dsync_params)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen struct dsync_client *client;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client = i_new(struct dsync_client, 1);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->path = i_strdup(path);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->fd = -1;
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen client->dsync_params = i_strdup(dsync_params);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return client;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic void dsync_callback(struct dsync_client *client,
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen const char *state, enum dsync_reply reply)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback_t *callback = client->callback;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen void *context = client->context;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&client->to);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->callback = NULL;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->context = NULL;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen /* make sure callback doesn't try to reuse this connection, since
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen we can't currently handle it */
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_assert(!client->cmd_sent);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->cmd_sent = TRUE;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen callback(reply, state, context);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->cmd_sent = FALSE;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic void dsync_close(struct dsync_client *client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
e7d75716b5ece1ac741f3717d4eb2359723e4e24Timo Sirainen client->cmd_sent = FALSE;
e7d75716b5ece1ac741f3717d4eb2359723e4e24Timo Sirainen client->handshaked = FALSE;
e7d75716b5ece1ac741f3717d4eb2359723e4e24Timo Sirainen i_free_and_null(client->state);
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen i_free_and_null(client->username);
e7d75716b5ece1ac741f3717d4eb2359723e4e24Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->fd == -1)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen io_remove(&client->io);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen o_stream_destroy(&client->output);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_stream_destroy(&client->input);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (close(client->fd) < 0)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_error("close(dsync) failed: %m");
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->fd = -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic void dsync_disconnect(struct dsync_client *client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_close(client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->callback != NULL)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback(client, "", DSYNC_REPLY_FAIL);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenvoid dsync_client_deinit(struct dsync_client **_client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen struct dsync_client *client = *_client;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen *_client = NULL;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_disconnect(client);
deab624f18dc0c1631c9edcffb106714ad2dbfe0Timo Sirainen i_free(client->dsync_params);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_free(client->path);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_free(client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic int dsync_input_line(struct dsync_client *client, const char *line)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen const char *state;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (!client->handshaked) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (strcmp(line, "+") != 0) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_error("%s: Unexpected handshake: %s",
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->path, line);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->handshaked = TRUE;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return 0;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->callback == NULL) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_error("%s: Unexpected input: %s", client->path, line);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->state == NULL) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->state = i_strdup(t_strcut(line, '\t'));
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return 0;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen state = t_strdup(client->state);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen line = t_strdup(line);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_close(client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (line[0] == '+')
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback(client, state, DSYNC_REPLY_OK);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen else if (line[0] == '-') {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (strcmp(line+1, "NOUSER") == 0)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback(client, "", DSYNC_REPLY_NOUSER);
c62d29c66b504ad3676deaefdf9e95f54e4f8eecAki Tuomi else if (strcmp(line+1, "NOREPLICATE") == 0)
c62d29c66b504ad3676deaefdf9e95f54e4f8eecAki Tuomi dsync_callback(client, "", DSYNC_REPLY_NOREPLICATE);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen else
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback(client, "", DSYNC_REPLY_FAIL);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen } else {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_error("%s: Invalid input: %s", client->path, line);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen /* FIXME: disconnect after each request for now.
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen doveadm server's getopt() handling seems to break otherwise.
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen also with multiple UIDs doveadm-server fails because setid() fails */
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic void dsync_input(struct dsync_client *client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen const char *line;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen while ((line = i_stream_read_next_line(client->input)) != NULL) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (dsync_input_line(client, line) < 0) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_disconnect(client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->input->eof)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_disconnect(client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic int dsync_connect(struct dsync_client *client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->fd != -1)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return 0;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->last_connect_failure == ioloop_time)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->fd = net_connect_unix(client->path);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (client->fd == -1) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_error("net_connect_unix(%s) failed: %m", client->path);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->last_connect_failure = ioloop_time;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return -1;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->last_connect_failure = 0;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->io = io_add(client->fd, IO_READ, dsync_input, client);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->input = i_stream_create_fd(client->fd, (size_t)-1);
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi client->output = o_stream_create_fd(client->fd, (size_t)-1);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen o_stream_set_no_error_handling(client->output, TRUE);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen o_stream_nsend_str(client->output, DOVEADM_HANDSHAKE);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return 0;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenstatic void dsync_fail_timeout(struct dsync_client *client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_disconnect(client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenvoid dsync_client_sync(struct dsync_client *client,
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen const char *username, const char *state, bool full,
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_callback_t *callback, void *context)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen string_t *cmd;
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen unsigned int pos;
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen char *p;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_assert(callback != NULL);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_assert(!dsync_client_is_busy(client));
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen client->username = i_strdup(username);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->cmd_sent = TRUE;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->callback = callback;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->context = context;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen if (full)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen client->sync_type = DSYNC_TYPE_FULL;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen else if (state != NULL && state[0] != '\0')
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen client->sync_type = DSYNC_TYPE_INCREMENTAL;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen else
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen client->sync_type = DSYNC_TYPE_NORMAL;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (dsync_connect(client) < 0) {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen i_assert(client->to == NULL);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen client->to = timeout_add(DSYNC_FAIL_TIMEOUT_MSECS,
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen dsync_fail_timeout, client);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen } else {
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen /* <flags> <username> <command> [<args>] */
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen cmd = t_str_new(256);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen str_append_c(cmd, '\t');
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen str_append_tabescaped(cmd, username);
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen str_append(cmd, "\tsync\t");
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen pos = str_len(cmd);
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen /* insert the parameters. we can do it simply by converting
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen spaces into tabs, it's unlikely we'll ever need anything
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen more complex here. */
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen str_append(cmd, client->dsync_params);
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen p = str_c_modifiable(cmd) + pos;
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen for (; *p != '\0'; p++) {
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen if (*p == ' ')
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen *p = '\t';
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (full)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen str_append(cmd, "\t-f");
36757b426f4761dbd837bdddc8998e22d09dc869Timo Sirainen str_append(cmd, "\t-s\t");
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen if (state != NULL)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen str_append(cmd, state);
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen str_append_c(cmd, '\n');
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen o_stream_nsend(client->output, str_data(cmd), str_len(cmd));
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen }
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainenbool dsync_client_is_busy(struct dsync_client *client)
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen{
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen return client->cmd_sent;
cc116e6d7a2515f0089a449c22a3d61d9ec14642Timo Sirainen}
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainenconst char *dsync_client_get_username(struct dsync_client *conn)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen{
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return conn->username;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen}
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainenenum dsync_type dsync_client_get_type(struct dsync_client *conn)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen{
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return conn->sync_type;
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen}
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainenconst char *dsync_client_get_state(struct dsync_client *conn)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen{
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen if (conn->fd == -1) {
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen if (conn->last_connect_failure == 0)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return "Not connected";
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return t_strdup_printf("Failed to connect to '%s' - last attempt %ld secs ago", conn->path,
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen (long)(ioloop_time - conn->last_connect_failure));
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen }
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen if (!dsync_client_is_busy(conn))
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return "Idle";
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen if (!conn->handshaked)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return "Waiting for handshake";
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen if (conn->state == NULL)
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return "Waiting for dsync to finish";
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen else
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen return "Waiting for dsync to finish (second line)";
2e08b126fd1a168c993b1c8c0d1211da236ff604Timo Sirainen}