imap-master-client.c revision 2bc963ea051ddacefe0fa5e26280e8ef853fd6c6
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync/* Copyright (c) 2014-2015 Dovecot authors, see the included COPYING file */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "imap-common.h"
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "connection.h"
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "istream.h"
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "istream-unix.h"
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "ostream.h"
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "base64.h"
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync#include "strescape.h"
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync#include "master-service.h"
92a27575521748a392dcd1b996fce55b87411a00vboxsync#include "mail-storage-service.h"
92a27575521748a392dcd1b996fce55b87411a00vboxsync#include "imap-client.h"
92a27575521748a392dcd1b996fce55b87411a00vboxsync#include "imap-state.h"
92a27575521748a392dcd1b996fce55b87411a00vboxsync#include "imap-master-client.h"
92a27575521748a392dcd1b996fce55b87411a00vboxsync
92a27575521748a392dcd1b996fce55b87411a00vboxsyncstruct imap_master_client {
92a27575521748a392dcd1b996fce55b87411a00vboxsync struct connection conn;
92a27575521748a392dcd1b996fce55b87411a00vboxsync bool imap_client_created;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync};
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstruct imap_master_input {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* input we've already read from the IMAP client. */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync buffer_t *client_input;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync /* output that imap-hibernate was supposed to send to IMAP client,
10cdf5733351fdcd857d439ca32189e812f18682vboxsync but couldn't send it yet. */
10cdf5733351fdcd857d439ca32189e812f18682vboxsync buffer_t *client_output;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync /* IMAP connection state */
10cdf5733351fdcd857d439ca32189e812f18682vboxsync buffer_t *state;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync
10cdf5733351fdcd857d439ca32189e812f18682vboxsync dev_t peer_dev;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync ino_t peer_ino;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
10cdf5733351fdcd857d439ca32189e812f18682vboxsync bool state_import_bad_idle_done;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync bool state_import_idle_continue;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync};
10cdf5733351fdcd857d439ca32189e812f18682vboxsync
10cdf5733351fdcd857d439ca32189e812f18682vboxsyncstatic struct connection_list *master_clients = NULL;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic void imap_master_client_destroy(struct connection *conn)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync{
10cdf5733351fdcd857d439ca32189e812f18682vboxsync struct imap_master_client *client = (struct imap_master_client *)conn;
10cdf5733351fdcd857d439ca32189e812f18682vboxsync
10cdf5733351fdcd857d439ca32189e812f18682vboxsync if (!client->imap_client_created)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_service_client_connection_destroyed(master_service);
10cdf5733351fdcd857d439ca32189e812f18682vboxsync connection_deinit(conn);
10cdf5733351fdcd857d439ca32189e812f18682vboxsync i_free(conn);
10cdf5733351fdcd857d439ca32189e812f18682vboxsync}
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
10cdf5733351fdcd857d439ca32189e812f18682vboxsyncstatic int
10cdf5733351fdcd857d439ca32189e812f18682vboxsyncimap_master_client_parse_input(const char *const *args, pool_t pool,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct mail_storage_service_input *input_r,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct imap_master_input *master_input_r,
10cdf5733351fdcd857d439ca32189e812f18682vboxsync const char **error_r)
10cdf5733351fdcd857d439ca32189e812f18682vboxsync{
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync const char *key, *value;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync unsigned int peer_dev_major = 0, peer_dev_minor = 0;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync memset(input_r, 0, sizeof(*input_r));
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync memset(master_input_r, 0, sizeof(*master_input_r));
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->client_input = buffer_create_dynamic(pool, 64);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->client_output = buffer_create_dynamic(pool, 16);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->state = buffer_create_dynamic(pool, 512);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync input_r->module = input_r->service = "imap";
10cdf5733351fdcd857d439ca32189e812f18682vboxsync /* we never want to do userdb lookup again when restoring the client.
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync we have the userdb_fields cached already. */
10cdf5733351fdcd857d439ca32189e812f18682vboxsync input_r->flags_override_remove = MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (args[0] == NULL) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = "Missing username in input";
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync input_r->username = args[0];
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync for (args++; *args != NULL; args++) {
86abc60770f825f8c2ed4257675b50a08743b687vboxsync value = strchr(*args, '=');
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (value != NULL)
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync key = t_strdup_until(*args, value++);
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync else {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync key = *args;
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync value = "";
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync }
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync if (strcmp(key, "lip") == 0) {
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync if (net_addr2ip(value, &input_r->local_ip) < 0) {
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync *error_r = t_strdup_printf(
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync "Invalid lip value: %s", value);
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync return -1;
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync }
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync } else if (strcmp(key, "rip") == 0) {
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync if (net_addr2ip(value, &input_r->remote_ip) < 0) {
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync *error_r = t_strdup_printf(
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync "Invalid rip value: %s", value);
4a429a59b1a82ce092626ea5f7512466c18f2015vboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync } else if (strcmp(key, "peer_dev_major") == 0) {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync if (str_to_uint(value, &peer_dev_major) < 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = t_strdup_printf(
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync "Invalid peer_dev_major value: %s", value);
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync return -1;
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync }
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync } else if (strcmp(key, "peer_dev_minor") == 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (str_to_uint(value, &peer_dev_minor) < 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = t_strdup_printf(
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "Invalid peer_dev_minor value: %s", value);
86abc60770f825f8c2ed4257675b50a08743b687vboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync } else if (strcmp(key, "peer_ino") == 0) {
86abc60770f825f8c2ed4257675b50a08743b687vboxsync if (str_to_ino(value, &master_input_r->peer_ino) < 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = t_strdup_printf(
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync "Invalid peer_ino value: %s", value);
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync return -1;
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync }
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync } else if (strcmp(key, "session") == 0) {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync input_r->session_id = value;
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync } else if (strcmp(key, "userdb_fields") == 0) {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync input_r->userdb_fields =
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync t_strsplit_tabescaped(value);
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync } else if (strcmp(key, "client_input") == 0) {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync if (base64_decode(value, strlen(value), NULL,
02fb80eb0db13569db21d1ce5e0f3e0d5a6122aavboxsync master_input_r->client_input) < 0) {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync *error_r = t_strdup_printf(
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync "Invalid client_input base64 value: %s", value);
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync return -1;
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync }
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync } else if (strcmp(key, "client_output") == 0) {
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync if (base64_decode(value, strlen(value), NULL,
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync master_input_r->client_output) < 0) {
6967517de4be849f55b0141d6089add0eff2aa7bvboxsync *error_r = t_strdup_printf(
6967517de4be849f55b0141d6089add0eff2aa7bvboxsync "Invalid client_output base64 value: %s", value);
23ee8310386e73ba6760fa30831a7964713d34b6vboxsync return -1;
86abc60770f825f8c2ed4257675b50a08743b687vboxsync }
7b213bb002950f9fcf809f605cc584fa543481advboxsync } else if (strcmp(key, "state") == 0) {
7b213bb002950f9fcf809f605cc584fa543481advboxsync if (base64_decode(value, strlen(value), NULL,
7b213bb002950f9fcf809f605cc584fa543481advboxsync master_input_r->state) < 0) {
7b213bb002950f9fcf809f605cc584fa543481advboxsync *error_r = t_strdup_printf(
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "Invalid state base64 value: %s", value);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync } else if (strcmp(key, "bad-done") == 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->state_import_bad_idle_done = TRUE;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync } else if (strcmp(key, "idle-continue") == 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->state_import_idle_continue = TRUE;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (peer_dev_major != 0 || peer_dev_minor != 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input_r->peer_dev =
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync makedev(peer_dev_major, peer_dev_minor);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return 0;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync}
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic int imap_master_client_verify(const struct imap_master_input *master_input,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync int fd_client, const char **error_r)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync{
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct stat peer_st;
33b5e655c06292a07370c8cf4207da691806a7e4vboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (master_input->peer_ino == 0)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return 0;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* make sure we have the right fd */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (fstat(fd_client, &peer_st) < 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = t_strdup_printf("fstat(peer) failed: %m");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (peer_st.st_ino != master_input->peer_ino ||
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync !CMP_DEV_T(peer_st.st_dev, master_input->peer_dev)) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync *error_r = t_strdup_printf(
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "BUG: Expected peer device=%u,%u inode=%s doesn't match "
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "client fd's actual device=%u,%u inode=%s",
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync major(peer_st.st_dev), minor(peer_st.st_dev), dec2str(peer_st.st_ino),
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync major(master_input->peer_dev),
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync minor(master_input->peer_dev),
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync dec2str(master_input->peer_ino));
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return 0;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync}
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic int
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncimap_master_client_input_args(struct connection *conn, const char *const *args,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync int fd_client, pool_t pool)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync{
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct imap_master_client *client = (struct imap_master_client *)conn;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct client *imap_client;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct mail_storage_service_input input;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct imap_master_input master_input;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync const char *error;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync int ret;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (imap_master_client_parse_input(args, pool, &input, &master_input,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync &error) < 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync i_error("imap-master: Failed to parse client input: %s", error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync o_stream_send_str(conn->output, t_strdup_printf(
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "-Failed to parse client input: %s\n", error));
08a80484275b5172ce23729ecccc934c6a92d201vboxsync i_close_fd(&fd_client);
08a80484275b5172ce23729ecccc934c6a92d201vboxsync return -1;
08a80484275b5172ce23729ecccc934c6a92d201vboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (imap_master_client_verify(&master_input, fd_client, &error) < 0) {
86abc60770f825f8c2ed4257675b50a08743b687vboxsync i_error("imap-master: Failed to verify client input: %s", error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync o_stream_send_str(conn->output, t_strdup_printf(
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync "-Failed to verify client input: %s\n", error));
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync i_close_fd(&fd_client);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync /* NOTE: before client_create_from_input() on failures we need to close
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync fd_client, but afterward it gets closed by client_destroy() */
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync ret = client_create_from_input(&input, fd_client, fd_client,
fc148a6b23d25a87561beaffe0ba06c3ba93bf5avboxsync &imap_client, &error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (ret < 0) {
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_error("imap-master(%s): Failed to create client: %s",
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync input.username, error);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync o_stream_send_str(conn->output, t_strdup_printf(
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync "-Failed to create client: %s\n", error));
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_service_client_connection_destroyed(master_service);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_close_fd(&fd_client);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync return -1;
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync }
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync /* log prefix is set at this point, so we don't need to add the
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync username anymore to the log messages */
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync client->imap_client_created = TRUE;
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync o_stream_nsend(imap_client->output,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_input.client_output->data,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_input.client_output->used);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync if (master_input.client_input->used > 0 &&
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync !i_stream_add_data(imap_client->input,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_input.client_input->data,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_input.client_input->used)) {
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_error("imap-master: Couldn't add %"PRIuSIZE_T
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync " bytes to client's input stream",
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input.client_input->used);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync o_stream_send_str(conn->output,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync "-Couldn't add client input\n");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client_destroy(imap_client, "Client initialization failed");
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync return -1;
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync }
bc8beda7587b16cafe7de7bea19149de1bd4b498vboxsync imap_client->state_import_bad_idle_done =
bc8beda7587b16cafe7de7bea19149de1bd4b498vboxsync master_input.state_import_bad_idle_done;
bc8beda7587b16cafe7de7bea19149de1bd4b498vboxsync imap_client->state_import_idle_continue =
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input.state_import_idle_continue;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync ret = imap_state_import_internal(imap_client, master_input.state->data,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync master_input.state->used, &error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (ret <= 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync i_error("imap-master: Failed to import client state: %s", error);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client_destroy(imap_client, "Client state initialization failed");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* make sure all pending input gets handled */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync i_assert(imap_client->to_delayed_input == NULL);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (master_input.client_input->used > 0) {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync imap_client->to_delayed_input =
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync timeout_add(0, client_input, imap_client);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync o_stream_send_str(conn->output, "+\n");
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync imap_refresh_proctitle();
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync /* we'll always disconnect the client afterwards */
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return -1;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync}
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic int
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncimap_master_client_input_line(struct connection *conn, const char *line)
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync{
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync char *const *args;
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync pool_t pool;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync int fd_client, ret;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (!conn->version_received) {
08a56d5836eceeb24642b61eaa52a4edb0a7b482vboxsync if (connection_verify_version(conn, t_strsplit_tabescaped(line)) < 0)
08a56d5836eceeb24642b61eaa52a4edb0a7b482vboxsync return -1;
08a56d5836eceeb24642b61eaa52a4edb0a7b482vboxsync conn->version_received = TRUE;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return 1;
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync }
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync fd_client = i_stream_unix_get_read_fd(conn->input);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync if (fd_client == -1) {
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_error("imap-master: IMAP client fd not received");
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync return -1;
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync }
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync if (imap_debug)
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_debug("imap-master: Client input: %s", line);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync pool = pool_alloconly_create("imap master client cmd", 1024);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync args = p_strsplit_tabescaped(pool, line);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync ret = imap_master_client_input_args(conn, (void *)args, fd_client, pool);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync pool_unref(&pool);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync return ret;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync}
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncvoid imap_master_client_create(int fd)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync{
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync struct imap_master_client *client;
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client = i_new(struct imap_master_client, 1);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync connection_init_server(master_clients, &client->conn,
42d36464aee6c81b4f206b6c02035587501ff67cvboxsync "imap-master", fd, fd);
c3e38cccf650831700227918a021e6c4097ace82vboxsync
42d36464aee6c81b4f206b6c02035587501ff67cvboxsync i_assert(client->conn.input == NULL);
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync client->conn.input = i_stream_create_unix(fd, (size_t)-1);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync /* read the first file descriptor that we can */
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync i_stream_unix_set_read_fd(client->conn.input);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync}
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsyncstatic struct connection_settings client_set = {
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync .service_name_in = "imap-master",
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .service_name_out = "imap-master",
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .major_version = 1,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync .minor_version = 0,
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .input_max_size = 0, /* don't auto-create istream */
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync .output_max_size = (size_t)-1,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .client = FALSE
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync};
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncstatic const struct connection_vfuncs client_vfuncs = {
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .destroy = imap_master_client_destroy,
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync .input_line = imap_master_client_input_line
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync};
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsyncvoid imap_master_clients_init(void)
db3dbd0ed7eb69f804a8921fa23a1267ea01f46evboxsync{
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync master_clients = connection_list_init(&client_set, &client_vfuncs);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync}
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsyncvoid imap_master_clients_deinit(void)
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync{
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync connection_list_deinit(&master_clients);
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync}
6bac87a5a3b46a6e4abed909c4d4f63a1058abbavboxsync