client.c revision 31e020ffe023c80d3dc70d3625c0633187620638
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "common.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "buffer.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "hash.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "istream.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ostream.h"
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen#include "process-title.h"
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen#include "safe-memset.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "strescape.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "imap-parser.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "client.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "client-authenticate.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "auth-client.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ssl-proxy.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen/* max. size of one parameter in line */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MAX_INBUF_SIZE 512
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MAX_OUTBUF_SIZE 1024
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* maximum length for IMAP command line. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MAX_IMAP_LINE 8192
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Disconnect client after idling this many seconds */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen#define CLIENT_LOGIN_IDLE_TIMEOUT 60
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen/* Disconnect client when it sends too many bad commands */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen#define CLIENT_MAX_BAD_COMMANDS 10
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen/* When max. number of simultaneous connections is reached, few of the
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen oldest connections are disconnected. Since we have to go through the whole
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen client hash, it's faster if we disconnect multiple clients. */
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#define CLIENT_DESTROY_OLDEST_COUNT 16
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#if CLIENT_LOGIN_IDLE_TIMEOUT >= AUTH_REQUEST_TIMEOUT
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen# error client idle timeout must be smaller than authentication timeout
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen#endif
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic struct hash_table *clients;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenstatic struct timeout *to_idle;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainenstatic void client_set_title(struct imap_client *client)
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen const char *addr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!verbose_proctitle || !process_per_connection)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen return;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen addr = net_ip2addr(&client->common.ip);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (addr == NULL)
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen addr = "??";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen process_title_set(t_strdup_printf(client->tls ? "[%s TLS]" : "[%s]",
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen addr));
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenstatic void client_open_streams(struct imap_client *client, int fd)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen client->input = i_stream_create_file(fd, default_pool,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen MAX_INBUF_SIZE, FALSE);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen client->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen FALSE);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen client->parser = imap_parser_create(client->input, client->output,
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen MAX_IMAP_LINE);
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen/* Skip incoming data until newline is found,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen returns TRUE if newline was found. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic int client_skip_line(struct imap_client *client)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const unsigned char *data;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen size_t i, data_size;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen data = i_stream_get_data(client->input, &data_size);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen for (i = 0; i < data_size; i++) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (data[i] == '\n') {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_stream_skip(client->input, i+1);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return TRUE;
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenstatic int cmd_capability(struct imap_client *client)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const char *capability, *auths;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen auths = client_authenticate_get_capabilities(client->secured);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen capability = t_strconcat("* CAPABILITY " CAPABILITY_STRING,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen (ssl_initialized && !client->tls) ?
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen " STARTTLS" : "",
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen disable_plaintext_auth && !client->secured ?
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen " LOGINDISABLED" : "", auths, NULL);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen client_send_line(client, capability);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_tagline(client, "OK Capability completed.");
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int cmd_starttls(struct imap_client *client)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen int fd_ssl;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (client->tls) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_send_tagline(client, "BAD TLS is already active.");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!ssl_initialized) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_send_tagline(client, "BAD TLS support isn't enabled.");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_send_tagline(client, "OK Begin TLS negotiation now.");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen o_stream_flush(client->output);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* must be removed before ssl_proxy_new(), since it may
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen io_add() the same fd. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (client->common.io != NULL) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen io_remove(client->common.io);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->common.io = NULL;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (fd_ssl != -1) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->tls = TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->secured = TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_set_title(client);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* we skipped it already, so don't ignore next command */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->skip_line = FALSE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->common.fd = fd_ssl;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_stream_unref(client->input);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen o_stream_unref(client->output);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen imap_parser_destroy(client->parser);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_open_streams(client, fd_ssl);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->common.io = io_add(client->common.fd, IO_READ,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_input, client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_line(client, "* BYE TLS initialization failed.");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_destroy(client, "TLS initialization failed.");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int cmd_noop(struct imap_client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_tagline(client, "OK NOOP completed.");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int cmd_logout(struct imap_client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_line(client, "* BYE Logging out");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_tagline(client, "OK Logout completed.");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_destroy(client, "Aborted login");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int client_command_execute(struct imap_client *client, const char *cmd,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct imap_arg *args)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen cmd = str_ucase(t_strdup_noconst(cmd));
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (strcmp(cmd, "LOGIN") == 0)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return cmd_login(client, args);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(cmd, "AUTHENTICATE") == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return cmd_authenticate(client, args);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(cmd, "CAPABILITY") == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return cmd_capability(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(cmd, "STARTTLS") == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return cmd_starttls(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(cmd, "NOOP") == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return cmd_noop(client);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen if (strcmp(cmd, "LOGOUT") == 0)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return cmd_logout(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen return FALSE;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainenstatic int client_handle_input(struct imap_client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen struct imap_arg *args;
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (client->authenticating)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return FALSE; /* wait until authentication is finished */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (client->cmd_finished) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* clear the previous command from memory. don't do this
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen immediately after handling command since we need the
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen cmd_tag to stay some time after authentication commands. */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen client->cmd_tag = NULL;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->cmd_name = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen imap_parser_reset(client->parser);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* remove \r\n */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->skip_line) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!client_skip_line(client))
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->skip_line = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->cmd_finished = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d7ec773d995888b09c4d8c88a4b0b134a2002361Timo Sirainen if (client->cmd_tag == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->cmd_tag = imap_parser_read_word(client->parser);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (client->cmd_tag == NULL)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return FALSE; /* need more data */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (client->cmd_name == NULL) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen client->cmd_name = imap_parser_read_word(client->parser);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (client->cmd_name == NULL)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return FALSE; /* need more data */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen }
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen switch (imap_parser_read_args(client->parser, 0, 0, &args)) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen case -1:
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* error */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_destroy(client, NULL);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen return FALSE;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen case -2:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* not enough data */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->skip_line = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*client->cmd_tag == '\0' ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen !client_command_execute(client, client->cmd_name, args)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_line(client,
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "* BYE Too many invalid IMAP commands.");
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen client_destroy(client, "Disconnected: "
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "Too many invalid commands");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_tagline(client,
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen "BAD Error in IMAP command received by server.");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->cmd_finished = TRUE;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen return TRUE;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenint client_read(struct imap_client *client)
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen switch (i_stream_read(client->input)) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen case -2:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* buffer full */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen client_send_line(client, "* BYE Input buffer full, aborting");
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen client_destroy(client, "Disconnected: Input buffer full");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return FALSE;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen case -1:
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* disconnected */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen client_destroy(client, "Disconnected");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return FALSE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen default:
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* something was read */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen return TRUE;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen}
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenvoid client_input(void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct imap_client *client = context;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen client->last_input = ioloop_time;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (!client_read(client))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (!auth_client_is_connected(auth_client)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we're not yet connected to auth process -
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen don't allow any commands */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen client_send_line(client,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen "* OK Waiting for authentication process to respond..");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->input_blocked = TRUE;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen client_ref(client);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen o_stream_cork(client->output);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen while (client_handle_input(client)) ;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client_unref(client))
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen o_stream_flush(client->output);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void client_hash_destroy_oldest(void *key, void *value __attr_unused__,
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen void *context)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct imap_client *client = key;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct imap_client *const *destroy_clients;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen buffer_t *destroy_buf = context;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen size_t i, count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen destroy_clients = buffer_get_data(destroy_buf, &count);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen count /= sizeof(struct imap_client *);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen for (i = 0; i < count; i++) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if (destroy_clients[i]->created > client->created) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen buffer_insert(destroy_buf,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen i * sizeof(struct imap_client *),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &client, sizeof(struct imap_client *));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen }
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen}
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainenstatic void client_destroy_oldest(void)
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct imap_client *const *destroy_clients;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer_t *destroy_buf;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t i, count;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* find the oldest clients and put them to destroy-buffer */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen destroy_buf = buffer_create_static_hard(data_stack_pool,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sizeof(struct imap_client *) *
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen CLIENT_DESTROY_OLDEST_COUNT);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hash_foreach(clients, client_hash_destroy_oldest, destroy_buf);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* then kill them */
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen destroy_clients = buffer_get_data(destroy_buf, &count);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen count /= sizeof(struct imap_client *);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_destroy(destroy_clients[i],
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Disconnected: Connection queue full");
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen}
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainenstruct client *client_create(int fd, struct ip_addr *ip, int ssl)
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct imap_client *client;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen const char *addr;
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen if (max_logging_users > CLIENT_DESTROY_OLDEST_COUNT &&
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen hash_size(clients) >= max_logging_users) {
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen /* reached max. users count, kill few of the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen oldest connections */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_destroy_oldest();
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen /* always use nonblocking I/O */
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen net_set_nonblock(fd, TRUE);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client = i_new(struct imap_client, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->created = ioloop_time;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->refcount = 1;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen client->tls = ssl;
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen addr = net_ip2addr(ip);
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen client->secured = ssl ||
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen (IPADDR_IS_V4(ip) && strncmp(addr, "127.", 4) == 0) ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (IPADDR_IS_V6(ip) && strcmp(addr, "::1") == 0);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen client->common.ip = *ip;
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen client->common.fd = fd;
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen client_open_streams(client, fd);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->common.io = io_add(fd, IO_READ, client_input, client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->plain_login = buffer_create_dynamic(system_pool, 128, 8192);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen client->last_input = ioloop_time;
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen hash_insert(clients, client, client);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen main_ref();
9aceb071780a949f4e8bf41d3cf80735d9ac7fdfTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_line(client, "* OK " PACKAGE " ready.");
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen client_set_title(client);
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen return &client->common;
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen}
1503ac7619d97193d6690292b5f9523552c5d6ceTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid client_destroy(struct imap_client *client, const char *reason)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->destroyed)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->destroyed = TRUE;
f38485358ffc04c3466b917770575e29deef24c3Timo Sirainen
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen if (reason != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_syslog(client, reason);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen hash_remove(clients, client);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen i_stream_close(client->input);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen o_stream_close(client->output);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (client->common.auth_request != NULL) {
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen auth_client_request_abort(client->common.auth_request);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen client->common.auth_request = NULL;
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen }
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (client->common.master_tag != 0)
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen master_request_abort(&client->common);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen if (client->common.io != NULL) {
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen io_remove(client->common.io);
3c652e7a569c2623d22b4ab30279aebddce4d396Timo Sirainen client->common.io = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (client->common.fd != -1) {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen net_disconnect(client->common.fd);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen client->common.fd = -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen client_unref(client);
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainenvoid client_ref(struct imap_client *client)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen client->refcount++;
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen}
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenint client_unref(struct imap_client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen if (--client->refcount > 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen imap_parser_destroy(client->parser);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen i_stream_unref(client->input);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen o_stream_unref(client->output);
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen
62fc2fe221eccc834ac6b11b94b55335d5027cd1Timo Sirainen buffer_free(client->plain_login);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(client->common.virtual_user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_free(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen main_unref();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid client_send_line(struct imap_client *client, const char *line)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen o_stream_send_str(client->output, line);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen o_stream_send(client->output, "\r\n", 2);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid client_send_tagline(struct imap_client *client, const char *line)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen client_send_line(client, t_strconcat(client->cmd_tag, " ", line, NULL));
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenvoid client_syslog(struct imap_client *client, const char *text)
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen{
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen const char *addr;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen addr = net_ip2addr(&client->common.ip);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen if (addr == NULL)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk addr = "??";
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen i_info("%s [%s]", text, addr);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainenstatic void client_hash_check_idle(void *key, void *value __attr_unused__,
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen void *context __attr_unused__)
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen{
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen struct imap_client *client = key;
02a6291366caff79793db35d479e2a062bec2af4Timo Sirainen
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen if (ioloop_time - client->last_input >= CLIENT_LOGIN_IDLE_TIMEOUT) {
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen client_send_line(client, "* BYE Disconnected for inactivity.");
47e9fdee55c2074425cf0316f4f64fbbb790301cTimo Sirainen client_destroy(client, "Disconnected: Inactivity");
573085b4b25b0bbae8d27969df2c91702eefa23eTimo Sirainen }
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen}
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainenstatic void idle_timeout(void *context __attr_unused__)
0ee3fdb5e94ae6f34cb873ca3c9858342621e55fTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen hash_foreach(clients, client_hash_check_idle, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenunsigned int clients_get_count(void)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return hash_size(clients);
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen}
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen
1b04762685272a53643ac2179939537a44c7c044Timo Sirainenstatic void client_hash_check_io(void *key, void *value __attr_unused__,
1b04762685272a53643ac2179939537a44c7c044Timo Sirainen void *context __attr_unused__)
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen{
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen struct imap_client *client = key;
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen if (client->input_blocked) {
303e375b7e76278f4ec541f49af0476d3e4ee710Timo Sirainen client->input_blocked = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_input(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid clients_notify_auth_connected(void)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen hash_foreach(clients, client_hash_check_io, NULL);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic void client_hash_destroy(void *key, void *value __attr_unused__,
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen void *context __attr_unused__)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen client_destroy(key, NULL);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenvoid clients_destroy_all(void)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen hash_foreach(clients, client_hash_destroy, NULL);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenvoid clients_init(void)
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen clients = hash_create(default_pool, default_pool, 128, NULL, NULL);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen to_idle = timeout_add(1000, idle_timeout, NULL);
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainenvoid clients_deinit(void)
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen{
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen clients_destroy_all();
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen hash_destroy(clients);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen timeout_remove(to_idle);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen}
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen