bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "submission-common.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "array.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "ioloop.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "base64.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "str.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "llist.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "net.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "istream.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "ostream.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "iostream-ssl.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "hostpid.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "var-expand.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "settings-parser.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "master-service.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "master-service-settings.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "mail-namespace.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "mail-storage.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "mail-storage-service.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "raw-storage.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "imap-urlauth.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "smtp-client.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "smtp-client-connection.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "submission-commands.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include "submission-settings.h"
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#include <unistd.h>
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* max. length of input command line */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#define MAX_INBUF_SIZE 4096
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* Stop reading input when output buffer has this many bytes. Once the buffer
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch size has dropped to half of it, start reading input again. */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#define OUTBUF_THROTTLE_SIZE 4096
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* Disconnect client when it sends too many bad commands in a row */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#define CLIENT_MAX_BAD_COMMANDS 20
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* Disconnect client after idling this many milliseconds */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch#define CLIENT_IDLE_TIMEOUT_MSECS (10*60*1000)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstruct client *submission_clients;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschunsigned int submission_client_count;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const struct smtp_server_callbacks smtp_callbacks;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch/* try to proxy pipelined commands in a similarly pipelined fashion */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_input_pre(void *context)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0cce67356125083a0affed3ca9cb4f278258e5beJosef 'Jeff' Sipek struct client *client = context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->proxy_conn != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_cork(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_input_post(void *context)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0cce67356125083a0affed3ca9cb4f278258e5beJosef 'Jeff' Sipek struct client *client = context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->proxy_conn != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_uncork(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const char *client_remote_id(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *addr = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->user->conn.remote_ip != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch addr = net_ip2addr(client->user->conn.remote_ip);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (addr == NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch addr = "local";
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return addr;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_proxy_ready_cb(const struct smtp_reply *reply,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch void *context)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0cce67356125083a0affed3ca9cb4f278258e5beJosef 'Jeff' Sipek struct client *client = context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch enum smtp_capability caps;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* check proxy status */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if ((reply->status / 100) != 2) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_error("Failed to establish relay connection: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_reply_log(reply));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_destroy(client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "4.4.0", "Failed to establish relay connection");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* propagate capabilities */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch caps = smtp_client_connection_get_capabilities(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch caps |= SMTP_CAPABILITY_AUTH | SMTP_CAPABILITY_PIPELINING |
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_SIZE | SMTP_CAPABILITY_ENHANCEDSTATUSCODES |
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_CHUNKING | SMTP_CAPABILITY_BURL |
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CAPABILITY_VRFY;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_set_capabilities(client->conn, caps);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
d63fbcb367b6de01f5e39d72a825f03a832e308fStephan Bosch /* now that we know our capabilities, commence server protocol dialog */
d63fbcb367b6de01f5e39d72a825f03a832e308fStephan Bosch smtp_server_connection_resume(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_proxy_create(struct client *client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct submission_settings *set)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct mail_user *user = client->user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct ssl_iostream_settings ssl_set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_client_settings smtp_set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch enum smtp_client_connection_ssl_mode ssl_mode;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_zero(&ssl_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_init_ssl_client_settings(user, &ssl_set);
3a862c8c9e358b976c965f77bcfd867637700ae3Stephan Bosch if (set->submission_relay_ssl_verify)
3a862c8c9e358b976c965f77bcfd867637700ae3Stephan Bosch ssl_set.verbose_invalid_cert = TRUE;
3a862c8c9e358b976c965f77bcfd867637700ae3Stephan Bosch else
3a862c8c9e358b976c965f77bcfd867637700ae3Stephan Bosch ssl_set.allow_invalid_cert = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* make proxy connection */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_zero(&smtp_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.my_hostname = set->hostname;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.ssl = &ssl_set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.debug = user->mail_debug;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.rawlog_dir =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_home_expand(user,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch set->submission_relay_rawlog_dir);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (set->submission_relay_trusted) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.peer_trusted = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (user->conn.remote_ip != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.proxy_data.source_ip =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch *user->conn.remote_ip;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.proxy_data.source_port =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch user->conn.remote_port;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.proxy_data.login = user->username;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.username = set->submission_relay_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.master_user = set->submission_relay_master_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.password = set->submission_relay_password;
3f64825cfa1b6e8f7cf917e00d939da3124d98bbStephan Bosch smtp_set.connect_timeout_msecs =
3f64825cfa1b6e8f7cf917e00d939da3124d98bbStephan Bosch set->submission_relay_connect_timeout;
3f64825cfa1b6e8f7cf917e00d939da3124d98bbStephan Bosch smtp_set.command_timeout_msecs =
3f64825cfa1b6e8f7cf917e00d939da3124d98bbStephan Bosch set->submission_relay_command_timeout;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (strcmp(set->submission_relay_ssl, "smtps") == 0)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ssl_mode = SMTP_CLIENT_SSL_MODE_IMMEDIATE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch else if (strcmp(set->submission_relay_ssl, "starttls") == 0)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ssl_mode = SMTP_CLIENT_SSL_MODE_STARTTLS;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch else
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ssl_mode = SMTP_CLIENT_SSL_MODE_NONE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->proxy_conn = smtp_client_connection_create(smtp_client,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_PROTOCOL_SMTP, set->submission_relay_host,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch set->submission_relay_port, ssl_mode, &smtp_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_connect(client->proxy_conn,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_proxy_ready_cb, client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_init_urlauth(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch static const char *access_apps[] = { "submit+", NULL };
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct imap_urlauth_config config;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_zero(&config);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.url_host = client->set->imap_urlauth_host;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.url_port = client->set->imap_urlauth_port;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.socket_path = t_strconcat(client->user->set->base_dir,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "/"IMAP_URLAUTH_SOCKET_NAME, NULL);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.session_id = client->session_id;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.access_anonymous = client->user->anonymous;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.access_user = client->user->username;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.access_service = "submission";
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch config.access_applications = access_apps;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->urlauth_ctx = imap_urlauth_init(client->user, &config);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstruct client *client_create(int fd_in, int fd_out,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *session_id, struct mail_user *user,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct mail_storage_service_user *service_user,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct submission_settings *set,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *helo,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const unsigned char *pdata, unsigned int pdata_len)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct mail_storage_settings *mail_set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_settings smtp_set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *ident;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct client *client;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* always use nonblocking I/O */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch net_set_nonblock(fd_in, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch net_set_nonblock(fd_out, TRUE);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client = i_new(struct client, 1);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->user = user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->service_user = service_user;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->set = set;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->session_id = i_strdup(session_id);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_zero(&smtp_set);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.hostname = set->hostname;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.login_greeting = set->login_greeting;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.max_recipients = set->submission_max_recipients;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_set.debug = user->mail_debug;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->conn = smtp_server_connection_create(smtp_server,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch fd_in, fd_out, user->conn.remote_ip, user->conn.remote_port,
40a926a1aeae93b3d4944b56eacb013d3059b549Stephan Bosch FALSE, &smtp_set, &smtp_callbacks, client);
a731e3b18f93735c222460e44692ca0bfac91688Stephan Bosch
a731e3b18f93735c222460e44692ca0bfac91688Stephan Bosch client_proxy_create(client, set);
a731e3b18f93735c222460e44692ca0bfac91688Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_login(client->conn,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->user->username, helo,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch pdata, pdata_len, user->conn.ssl_secured);
d63fbcb367b6de01f5e39d72a825f03a832e308fStephan Bosch smtp_server_connection_start_pending(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_set = mail_user_set_get_storage_set(user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (*set->imap_urlauth_host != '\0' &&
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch *mail_set->mail_attribute_dict != '\0') {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Enable BURL capability only when urlauth dict is
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch configured correctly */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_init_urlauth(client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch submission_client_count++;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch DLLIST_PREPEND(&submission_clients, client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ident = mail_user_get_anvil_userip_ident(client->user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (ident != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch master_service_anvil_send(master_service, t_strconcat(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "CONNECT\t", my_pid, "\tsubmission/",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch ident, "\n", NULL));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->anvil_sent = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (hook_client_created != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch hook_client_created(&client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch submission_refresh_proctitle();
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return client;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_state_reset(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_stream_unref(&client->state.data_input);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_zero(&client->state);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid client_destroy(struct client *client, const char *prefix,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *reason)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->destroyed)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->destroyed = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_disconnect(client, prefix, reason);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch submission_client_count--;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch DLLIST_REMOVE(&submission_clients, client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->proxy_conn != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_close(&client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->anvil_sent) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch master_service_anvil_send(master_service, t_strconcat(
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "DISCONNECT\t", my_pid, "\tsubmission/",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_get_anvil_userip_ident(client->user),
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "\n", NULL));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->urlauth_ctx != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch imap_urlauth_deinit(&client->urlauth_ctx);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_unref(&client->user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_storage_service_user_unref(&client->service_user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_state_reset(client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_free(client->session_id);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_free(client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch master_service_client_connection_destroyed(master_service);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch submission_refresh_proctitle();
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschclient_connection_trans_free(void *context,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_transaction *trans ATTR_UNUSED)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0cce67356125083a0affed3ca9cb4f278258e5beJosef 'Jeff' Sipek struct client *client = context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_state_reset(client);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschclient_connection_state_changed(void *context ATTR_UNUSED,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch enum smtp_server_state newstate ATTR_UNUSED)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (submission_client_count == 1)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch submission_refresh_proctitle();
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_connection_disconnect(void *context, const char *reason)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0cce67356125083a0affed3ca9cb4f278258e5beJosef 'Jeff' Sipek struct client *client = context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_connection *conn = client->conn;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct smtp_server_stats *stats;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (conn != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch stats = smtp_server_connection_get_stats(conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->stats = *stats;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->last_state = smtp_server_connection_get_state(conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_disconnect(client, NULL, reason);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic void client_connection_destroy(void *context)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
0cce67356125083a0affed3ca9cb4f278258e5beJosef 'Jeff' Sipek struct client *client = context;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_destroy(client, NULL, NULL);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschconst char *client_state_get_name(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch enum smtp_server_state state;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->conn == NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch state = client->last_state;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch else
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch state = smtp_server_connection_get_state(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return smtp_server_state_names[state];
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const char *client_stats(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *trans_id = (client->conn == NULL ? "" :
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_get_transaction_id(client->conn));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct var_expand_table logout_tab[] = {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { 'i', dec2str(client->stats.input), "input" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { 'o', dec2str(client->stats.output), "output" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', dec2str(client->stats.command_count), "command_count" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', dec2str(client->stats.reply_count), "reply_count" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', client->session_id, "session" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', trans_id, "transaction_id" },
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch { '\0', NULL, NULL }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch };
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct var_expand_table *user_tab =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch mail_user_var_expand_table(client->user);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct var_expand_table *tab =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch t_var_expand_merge_tables(logout_tab, user_tab);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch string_t *str;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *error;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch str = t_str_new(128);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (var_expand_with_funcs(str, client->set->submission_logout_format,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch tab, mail_user_var_expand_func_table,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->user, &error) < 0) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_error("Failed to expand submission_logout_format=%s: %s",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->set->submission_logout_format, error);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return str_c(str);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid client_disconnect(struct client *client, const char *enh_code,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const char *reason)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch struct smtp_server_connection *conn;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->disconnected)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->disconnected = TRUE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
961a5c472495203d4714a059a192fb0bf72d56d5Stephan Bosch timeout_remove(&client->to_quit);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->proxy_conn != NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_client_connection_close(&client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->conn != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch const struct smtp_server_stats *stats =
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_get_stats(client->conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->stats = *stats;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (reason == NULL)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch reason = "Connection closed";
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch i_info("Disconnect from %s: %s %s (state = %s)",
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_remote_id(client),
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch reason, client_stats(client),
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_state_get_name(client));
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch conn = client->conn;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->conn = NULL;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (conn != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client->last_state = smtp_server_connection_get_state(conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch smtp_server_connection_terminate(&conn,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch (enh_code == NULL ? "4.0.0" : enh_code), reason);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschbool client_proxy_is_ready(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return (smtp_client_connection_get_state(client->proxy_conn) ==
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CLIENT_CONNECTION_STATE_READY);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschbool client_proxy_is_disconnected(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return (smtp_client_connection_get_state(client->proxy_conn) ==
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch SMTP_CLIENT_CONNECTION_STATE_DISCONNECTED);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschuoff_t client_get_max_mail_size(struct client *client)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch uoff_t max_size;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch /* Account for the backend server's SIZE limit and calculate our own
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch relative to it. */
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = smtp_client_connection_get_size_capability(client->proxy_conn);
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (max_size == 0 || max_size <= SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = client->set->submission_max_mail_size;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch } else {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = max_size - SUBMISSION_MAX_ADDITIONAL_MAIL_SIZE;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch if (client->set->submission_max_mail_size > 0 &&
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size > client->set->submission_max_mail_size)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch max_size = client->set->submission_max_mail_size;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch return max_size;
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschvoid clients_destroy_all(void)
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch{
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch while (submission_clients != NULL) {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch client_destroy(submission_clients,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch "4.3.2", "Shutting down");
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch }
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch}
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Boschstatic const struct smtp_server_callbacks smtp_callbacks = {
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_helo = cmd_helo,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_mail = cmd_mail,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_rcpt = cmd_rcpt,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_rset = cmd_rset,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_data_begin = cmd_data_begin,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_data_continue = cmd_data_continue,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_vrfy = cmd_vrfy,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_noop = cmd_noop,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_quit = cmd_quit,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_input_pre = client_input_pre,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_cmd_input_post = client_input_post,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_trans_free = client_connection_trans_free,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_state_changed = client_connection_state_changed,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_disconnect = client_connection_disconnect,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch .conn_destroy = client_connection_destroy,
2cbbe9b4829adb184c83dbf780316f4144559054Stephan Bosch};