bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "imap-common.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "fdpass.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "net.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "ostream.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "write-full.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "base64.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "str.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "strescape.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "master-service.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "mailbox-watch.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "imap-state.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#include "imap-client.h"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen#include <sys/stat.h>
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define IMAP_HIBERNATE_SOCKET_NAME "imap-hibernate"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define IMAP_HIBERNATE_SEND_TIMEOUT_SECS 10
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen#define IMAP_HIBERNATE_HANDSHAKE "VERSION\timap-hibernate\t1\t0\n"
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int imap_hibernate_handshake(int fd, const char *path)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char buf[1024];
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ssize_t ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (write_full(fd, IMAP_HIBERNATE_HANDSHAKE,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen strlen(IMAP_HIBERNATE_HANDSHAKE)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("write(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if ((ret = read(fd, buf, sizeof(buf)-1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("read(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if (ret > 0 && buf[ret-1] == '\n') {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buf[ret-1] = '\0';
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (version_string_verify(buf, "imap-hibernate", 1))
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("%s sent invalid VERSION handshake: %s", path, buf);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic void imap_hibernate_write_cmd(struct client *client, string_t *cmd,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const buffer_t *state, int fd_notify)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch struct mail_user *user = client->user;
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen struct stat peer_st;
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi const char *tag;
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi tag = client->command_queue == NULL ? NULL : client->command_queue->tag;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_append_tabescaped(cmd, user->username);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_c(cmd, '\t');
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_append_tabescaped(cmd, user->set->mail_log_prefix);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_printfa(cmd, "\tidle_notify_interval=%u",
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen client->set->imap_idle_notify_interval);
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen if (fstat(client->fd_in, &peer_st) == 0) {
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen str_printfa(cmd, "\tpeer_dev_major=%lu\tpeer_dev_minor=%lu\tpeer_ino=%llu",
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen (unsigned long)major(peer_st.st_dev),
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen (unsigned long)minor(peer_st.st_dev),
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen (unsigned long long)peer_st.st_ino);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (client->session_id != NULL) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append(cmd, "\tsession=");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(cmd, client->session_id);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch if (user->session_create_time != 0) {
1e2b3bd82f2d4fbae0963f4a220df30b7b5ae628Timo Sirainen str_printfa(cmd, "\tsession_created=%s",
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch dec2str(user->session_create_time));
1e2b3bd82f2d4fbae0963f4a220df30b7b5ae628Timo Sirainen }
60670187b0dd0e7f23f99a58feab11b862ad77acStephan Bosch if (user->conn.local_ip != NULL)
60670187b0dd0e7f23f99a58feab11b862ad77acStephan Bosch str_printfa(cmd, "\tlip=%s", net_ip2addr(user->conn.local_ip));
60670187b0dd0e7f23f99a58feab11b862ad77acStephan Bosch if (user->conn.remote_ip != NULL)
60670187b0dd0e7f23f99a58feab11b862ad77acStephan Bosch str_printfa(cmd, "\trip=%s", net_ip2addr(user->conn.remote_ip));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (client->userdb_fields != NULL) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen string_t *userdb_fields = t_str_new(256);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int i;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen for (i = 0; client->userdb_fields[i] != NULL; i++) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (i > 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_c(userdb_fields, '\t');
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(userdb_fields, client->userdb_fields[i]);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append(cmd, "\tuserdb_fields=");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(cmd, str_c(userdb_fields));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch if (user->uid != (uid_t)-1)
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_printfa(cmd, "\tuid=%s", dec2str(user->uid));
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch if (user->gid != (gid_t)-1)
8c1199cac76762101a2ca3ae66443b6b0dc28683Stephan Bosch str_printfa(cmd, "\tgid=%s", dec2str(user->gid));
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi if (tag != NULL)
f24edebe360d3effe584a884aa7d119daf3fd371Aki Tuomi str_printfa(cmd, "\ttag=%s", tag);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append(cmd, "\tstats=");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_tabescaped(cmd, client_stats(client));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (client->command_queue != NULL &&
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen strcasecmp(client->command_queue->name, "IDLE") == 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append(cmd, "\tidle-cmd");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (fd_notify != -1)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append(cmd, "\tnotify_fd");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append(cmd, "\tstate=");
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen base64_encode(state->data, state->used, cmd);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen str_append_c(cmd, '\n');
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenimap_hibernate_process_send_cmd(int fd_socket, const char *path,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const string_t *cmd, int fd_client)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ssize_t ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(fd_socket != -1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(str_len(cmd) > 1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (imap_hibernate_handshake(fd_socket, path) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = fd_send(fd_socket, fd_client, str_data(cmd), 1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("fd_send(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = write_full(fd_socket, str_data(cmd)+1, str_len(cmd)-1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("write(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int imap_hibernate_process_read(int fd, const char *path)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen char buf[1024];
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ssize_t ret;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = read(fd, buf, sizeof(buf)-1)) < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("read(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if (ret == 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("%s disconnected", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if (buf[0] != '+') {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buf[ret] = '\0';
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("%s returned failure: %s", path,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret > 0 && buf[0] == '-' ? buf+1 : buf);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenimap_hibernate_process_send(struct client *client,
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen const buffer_t *state, int fd_notify, int *fd_r)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen string_t *cmd = t_str_new(512);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *path;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ssize_t ret = 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen int fd;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_assert(state->used > 0);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen *fd_r = -1;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen path = t_strconcat(client->user->set->base_dir,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen "/"IMAP_HIBERNATE_SOCKET_NAME, NULL);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen fd = net_connect_unix_with_retries(path, 1000);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (fd == -1) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("net_connect_unix(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen net_set_nonblock(fd, FALSE);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen imap_hibernate_write_cmd(client, cmd, state, fd_notify);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen alarm(IMAP_HIBERNATE_SEND_TIMEOUT_SECS);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (imap_hibernate_process_send_cmd(fd, path, cmd, client->fd_in) < 0 ||
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen imap_hibernate_process_read(fd, path) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen else if (fd_notify != -1) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((ret = fd_send(fd, fd_notify, "\n", 1)) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("fd_send(%s) failed: %m", path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen else
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = imap_hibernate_process_read(fd, path);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen alarm(0);
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (ret < 0) {
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen net_disconnect(fd);
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return -1;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen }
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen *fd_r = fd;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen return 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenbool imap_client_hibernate(struct client **_client)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen{
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct client *client = *_client;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buffer_t *state;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *error;
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen int ret, fd_notify = -1, fd_hibernate = -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (client->fd_in != client->fd_out) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* we won't try to hibernate stdio clients */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (o_stream_get_buffer_used_size(client->output) > 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* wait until we've sent the pending output to client */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return FALSE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen state = buffer_create_dynamic(default_pool, 1024);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = imap_state_export_internal(client, state, &error);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ret < 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_error("Couldn't hibernate imap client: "
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen "Couldn't export state: %s (mailbox=%s)", error,
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen client->mailbox == NULL ? "" :
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen mailbox_get_vname(client->mailbox));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if (ret == 0 && client->user->mail_debug) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_debug("Couldn't hibernate imap client: "
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen "Couldn't export state: %s (mailbox=%s)", error,
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen client->mailbox == NULL ? "" :
83228b3f9f6ee8c62a61902e0203af9760f7b9b7Timo Sirainen mailbox_get_vname(client->mailbox));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ret > 0 && client->mailbox != NULL) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen fd_notify = mailbox_watch_extract_notify_fd(client->mailbox,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen &error);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (fd_notify == -1) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (client->user->mail_debug) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen i_debug("Couldn't hibernate imap client: "
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen "Couldn't extract notifications fd: %s",
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen error);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ret > 0) {
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (imap_hibernate_process_send(client, state, fd_notify, &fd_hibernate) < 0)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = -1;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
7b032348d7bbb93ff96188289d3dfc1899b9abb3Josef 'Jeff' Sipek i_close_fd(&fd_notify);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (ret > 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* hide the disconnect log message, because the client didn't
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen actually log out */
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen if (client->user->mail_debug) {
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen i_debug("Successfully hibernated imap client in mailbox %s",
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen client->mailbox == NULL ? "<none>" :
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen mailbox_get_vname(client->mailbox));
f32c6ed9db6f4c535f97a2020401572efc8abf86Timo Sirainen }
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen client->disconnected = TRUE;
b596cac264eaa0fbd6cd74a279d58accccb7405bTimo Sirainen client->hibernated = TRUE;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen client_destroy(client, NULL);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen *_client = NULL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen }
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen /* notify imap-hibernate that we're done by closing the connection.
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen do this only after client is destroyed. this way imap-hibernate
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen won't try to launch another imap process too early and cause
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen problems (like sending duplicate session ID to stats process) */
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen if (fd_hibernate != -1)
f818f91a2e6ee003aaa83323acd74008aa1276d9Timo Sirainen net_disconnect(fd_hibernate);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buffer_free(&state);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return ret > 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen}