bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschconst char *const smtp_client_connection_state_names[] = {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "disconnected",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "connecting",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "handshaking",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "authenticating",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "transaction"
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_ssl_init(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char **error_r);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_handshake(struct smtp_client_connection *conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_established(struct smtp_client_connection *conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_start_transaction(struct smtp_client_connection *conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch * Capabilities
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_get_capabilities(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschuoff_t smtp_client_connection_get_size_capability(
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmpt_client_connection_label(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_debug(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char *format, ...)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_warning(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char *format, ...)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_error(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char *format, ...)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_commands_abort(struct smtp_client_connection *conn)
2dd20833b86743fe1e45c5af06d9c5f2549126e3Stephan Bosch smtp_client_commands_list_abort(conn->cmd_wait_list_head,
2dd20833b86743fe1e45c5af06d9c5f2549126e3Stephan Bosch smtp_client_commands_list_abort(conn->cmd_send_queue_head,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_commands_fail_reply(struct smtp_client_connection *conn,
bd06411e6f2ffc9e0122824ba4edb774bb40c26fStephan Bosch smtp_client_commands_list_fail_reply(conn->cmd_wait_list_head,
bd06411e6f2ffc9e0122824ba4edb774bb40c26fStephan Bosch smtp_client_commands_list_fail_reply(conn->cmd_send_queue_head,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_commands_fail(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_commands_fail_reply(conn, &reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_login_callback(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_command_callback_t *callback = conn->login_callback;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_login_fail(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_login_callback(conn, &reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_set_state(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_cork(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_uncork(struct smtp_client_connection *conn)
326301f0d478de2d0dd4bf40dda7099ef015ee3eStephan Bosch if (o_stream_uncork_flush(conn->conn.output) < 0) {
326301f0d478de2d0dd4bf40dda7099ef015ee3eStephan Bosch smtp_client_connection_handle_output_error(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_get_state(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_command_timeout(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Command timed out, disconnecting");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Command timed out");
7501ff318cd45e2b1fc63bafa713c2f0974780f3Stephan Bosch unsigned int msecs = conn->set.command_timeout_msecs;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state != SMTP_CLIENT_CONNECTION_STATE_READY) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* pre-login uses connect timeout */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* no timeout configured */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* no commands pending */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Start timeout");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_update_cmd_timeout(
7501ff318cd45e2b1fc63bafa713c2f0974780f3Stephan Bosch unsigned int msecs = conn->set.command_timeout_msecs;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state != SMTP_CLIENT_CONNECTION_STATE_READY) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* pre-login uses connect timeout */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* no timeout configured */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "No commands pending; stop timeout");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Reset timeout");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_start_cmd_timeout(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_fail_reply(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Connection failed: %s", smtp_reply_log(reply));
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_login_callback(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_commands_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct smtp_client_transaction *trans_next = trans->next;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_transaction_connection_result(trans, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_fail(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, &reply);
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Boschvoid smtp_client_connection_handle_output_error(
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch "Connection lost: write(%s) failed: %s",
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch "Lost connection to remote server: "
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch "Write failure");
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch "Connection lost: Remote disconnected");
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch "Lost connection to remote server: "
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch "Remote closed connection unexpectedly");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstatic void stmp_client_connection_ready(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Connection ready");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_login_callback(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_update_cmd_timeout(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_start_transaction(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_clear_password(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch safe_memset(conn->password, 0, strlen(conn->password));
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_auth_cb(const struct smtp_reply *reply,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication failed: "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Server returned multi-line reply: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication protocol error");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch buf = buffer_create_dynamic(pool_datastack_create(),
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch (reply->text_lines[0], input_len, NULL, buf) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication failed: "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Server sent non-base64 input for AUTH: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch } else if (dsasl_client_input(conn->sasl_client,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch } else if (dsasl_client_output(conn->sasl_client,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch &sasl_output, &sasl_output_len, &error) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication failed");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication failed: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authenticated successfully");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_get_sasl_mech(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char **error_r)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const struct smtp_client_settings *set = &conn->set;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char *mech = dsasl_client_mech_get_name(set->sasl_mech);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (!str_array_icase_find(conn->cap_auth_mechanisms, mech)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Server doesn't support `%s' SASL mechanism",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* find one of the specified SASL mechanisms */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch mechanisms = t_strsplit_spaces(set->sasl_mechanisms, ", ");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (str_array_icase_find(conn->cap_auth_mechanisms,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch *mech_r = dsasl_client_mech_find(*mechanisms);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Support for SASL mechanism `%s' is missing",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Server doesn't support any of "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "the requested SASL mechanisms: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_authenticate(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const struct smtp_client_settings *set = &conn->set;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const struct dsasl_client_mech *sasl_mech = NULL;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->username == NULL && set->sasl_mech == NULL)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if ((conn->capabilities & SMTP_CAPABILITY_AUTH) == 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication not supported");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authenticating as %s for user %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authenticating");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (smtp_client_connection_get_sasl_mech(conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Server authentication mechanisms incompatible");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->sasl_client = dsasl_client_new(sasl_mech, &sasl_set);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (dsasl_client_output(conn->sasl_client, &sasl_output,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Failed to create initial %s SASL reply: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch dsasl_client_mech_get_name(sasl_mech), error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Internal authentication failure");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch base64_encode(sasl_output, sasl_output_len, sasl_output_base64);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* RFC 4954, Section 4:
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch If the client is transmitting an initial response of zero
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch length, it MUST instead transmit the response as a single
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch equals sign ("="). This indicates that the response is
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch present, but contains no data. */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch init_resp = (str_len(sasl_output_base64) == 0 ?
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch dsasl_client_mech_get_name(sasl_mech), init_resp);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_xclient_cb(const struct smtp_reply *reply,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Received XCLIENT handshake reply: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state == SMTP_CLIENT_CONNECTION_STATE_DISCONNECTED)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_send_xclient(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char **xclient_args = conn->cap_xclient_args;
fbd0a83db9f2c380dd281e243ecfff40b7acfcfdStephan Bosch if ((conn->capabilities & SMTP_CAPABILITY_XCLIENT) == 0 ||
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* Older versions of Dovecot LMTP don't quite follow Postfix'
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch specification of the XCLIENT command regarding IPv6
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch addresses: the "IPV6:" prefix is omitted. For now, we
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch maintain this deviation for LMTP. Newer versions of Dovecot
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch LMTP can work with or without the prefix. */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch str_append(str, net_ip2addr(&xclient->source_ip));
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch str_printfa(str, " PORT=%u", xclient->source_port);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (str_array_icase_find(xclient_args, "PROTO")) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch str_array_icase_find(xclient_args, "LOGIN")) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch str_printfa(str, " TTL=%u", xclient->ttl_plus_1-1);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch str_array_icase_find(xclient_args, "TIMEOUT"))
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch str_printfa(str, " TIMEOUT=%u", xclient->timeout_secs);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Sending XCLIENT handshake");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_init_xclient(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return smtp_client_connection_authenticate(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_starttls_cb(const struct smtp_reply *reply,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Received STARTTLS reply: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (smtp_client_connection_ssl_init(conn, &error) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED, error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_starttls(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->ssl_mode == SMTP_CLIENT_SSL_MODE_STARTTLS &&
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if ((conn->capabilities & SMTP_CAPABILITY_STARTTLS) == 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Requested STARTTLS, "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "but server doesn't support it");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "STARTTLS not supported");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Starting TLS");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch return smtp_client_connection_init_xclient(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_handshake_cb(const struct smtp_reply *reply,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch unsigned int j;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Received handshake reply");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* check reply status */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* RFC 5321, Section 3.2:
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch For a particular connection attempt, if the server returns a
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "command not recognized" response to EHLO, the client SHOULD
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch be able to fall back and send HELO. */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->protocol == SMTP_PROTOCOL_SMTP && !conn->old_smtp &&
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch (reply->status == 500 || reply->status == 502)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* try HELO */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* reset capabilities */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Invalid handshake reply");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* greeting line */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* capability lines */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const struct smtp_capability_name *cap = NULL;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Received invalid EHLO response line: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch for (j = 0; smtp_capability_names[j].name != NULL; j++) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (str_to_uoff(*params, &conn->cap_size) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Received invalid SIZE capability "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "in EHLO response line");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Received server capabilities");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_handshake(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_command_write(cmd, conn->set.my_hostname);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_input_reply(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* initial greeting? */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state == SMTP_CLIENT_CONNECTION_STATE_CONNECTING) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Received greeting from server: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Received inappropriate greeting");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* unexpected reply? */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Unexpected reply: %s", smtp_reply_log(reply));
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch SMTP_CLIENT_COMMAND_ERROR_CONNECTION_CLOSED) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_fail_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Got unexpected reply");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* command reply */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ret = smtp_client_command_input_reply(conn->cmd_wait_list_head, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state == SMTP_CLIENT_CONNECTION_STATE_DISCONNECTED ||
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstatic void smtp_client_connection_input(struct connection *_conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch !ssl_iostream_is_handshaked(conn->ssl_iostream)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* finish SSL negotiation by reading from input stream */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch while ((ret=i_stream_read(conn->conn.input)) > 0 || ret == -2) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (ssl_iostream_is_handshaked(conn->ssl_iostream))
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* failed somehow */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "SSL handshaking with %s failed: "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "connect(%s) failed: %s", _conn->name, error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch SMTP_CLIENT_COMMAND_ERROR_CONNECT_FAILED, error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (!ssl_iostream_is_handshaked(conn->ssl_iostream)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* not finished */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* ready for SMTP handshake */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if ((ret=smtp_reply_parse_ehlo(conn->reply_parser,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if ((ret=smtp_reply_parse_next(conn->reply_parser,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ret = smtp_client_connection_input_reply(conn, reply);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->conn.output != NULL && !conn->corked)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (ret < 0 || (ret == 0 && conn->conn.input->eof)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->conn.input->stream_errno == ENOBUFS) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Command reply line too long");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch } else if (conn->conn.input->stream_errno != 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "read(%s) failed: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Lost connection to remote server "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "(read failure)");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch } else if (!i_stream_have_bytes_left(conn->conn.input)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Lost connection to remote server "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "(disconnected in input)");
326301f0d478de2d0dd4bf40dda7099ef015ee3eStephan Bosch if (ret >= 0 && conn->conn.output != NULL && !conn->corked) {
326301f0d478de2d0dd4bf40dda7099ef015ee3eStephan Bosch if (o_stream_uncork_flush(conn->conn.output) < 0)
326301f0d478de2d0dd4bf40dda7099ef015ee3eStephan Bosch smtp_client_connection_handle_output_error(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstatic int smtp_client_connection_output(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if ((ret=o_stream_flush(conn->conn.output)) <= 0) {
a02b8d9eed3636518cc5ffce8d1045f9808f24e4Stephan Bosch smtp_client_connection_handle_output_error(conn);
ce19176ce2fcb6db22d2d2f650d16fcc3e53a868Stephan Bosch if (ret >= 0 && conn->conn.output != NULL && !conn->corked) {
ce19176ce2fcb6db22d2d2f650d16fcc3e53a868Stephan Bosch if (o_stream_uncork_flush(conn->conn.output) < 0)
ce19176ce2fcb6db22d2d2f650d16fcc3e53a868Stephan Bosch smtp_client_connection_handle_output_error(conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_trigger_output(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch o_stream_set_flush_pending(conn->conn.output, TRUE);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstatic void smtp_client_connection_destroy(struct connection *_conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Connection deinit");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "connect(%s) failed: Connection timed out",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Connect timed out");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch error = _conn->input == NULL ? "Connection lost" :
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch SMTP_CLIENT_COMMAND_ERROR_CONNECTION_LOST, error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_established(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* set flush callback */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_ssl_handshaked(const char **error_r, void *context)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct smtp_client_connection *conn = context;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (ssl_iostream_check_cert_validity(conn->ssl_iostream,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "SSL handshake successful");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch } else if (conn->set.ssl->allow_invalid_cert) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "SSL handshake successful, "
3da7cb6c60e6a82661c9b763383d3944a911f6a4Stephan Boschsmtp_client_connection_streams_changed(struct smtp_client_connection *conn)
3da7cb6c60e6a82661c9b763383d3944a911f6a4Stephan Bosch smtp_reply_parser_set_stream(conn->reply_parser,
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Boschsmtp_client_connection_init_ssl_ctx(struct smtp_client_connection *conn,
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch const char **error_r)
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch if (smtp_client_init_ssl_ctx(client, error_r) < 0)
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch *error_r = "Requested SSL connection, but no SSL settings given";
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch if (ssl_iostream_client_context_cache_get(conn->set.ssl,
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch *error_r = t_strdup_printf("Couldn't initialize SSL context: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_ssl_init(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const char **error_r)
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch if (smtp_client_connection_init_ssl_ctx(conn, &error) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Starting SSL handshake");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* recreate rawlog after STARTTLS */
5db9891a9dee031ee3e4dfb74c95d5136c5f771aStephan Bosch if (io_stream_create_ssl_client(conn->ssl_ctx,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Couldn't initialize SSL client for %s: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ssl_iostream_set_handshake_callback(conn->ssl_iostream,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch *error_r = t_strdup_printf("SSL handshake to %s failed: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ssl_iostream_get_last_error(conn->ssl_iostream));
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (ssl_iostream_is_handshaked(conn->ssl_iostream)) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* wait for handshake to complete; connection input handler
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch does the rest by reading from the input stream */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch o_stream_set_flush_callback(conn->conn.output,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_delayed_connect_failure(
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Delayed connect failure");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Failed to connect to remote server");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_connected(struct connection *_conn, bool success)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch const struct smtp_client_settings *set = &conn->set;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_delayed_connect_failure, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Connected");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch (void)net_set_tcp_nodelay(_conn->fd_out, TRUE);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch i_error("net_set_send_buffer_size(%"PRIuSIZE_T") failed: %m",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch i_error("net_set_recv_buffer_size(%"PRIuSIZE_T") failed: %m",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->ssl_mode == SMTP_CLIENT_SSL_MODE_IMMEDIATE) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (smtp_client_connection_ssl_init(conn, &error) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "connect(%s) failed: %s", _conn->name, error);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_delayed_connect_failure,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_connect_timeout(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "connect(%s) failed: "
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Connection timed out after %u seconds",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Connect timed out");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch case SMTP_CLIENT_CONNECTION_STATE_HANDSHAKING:
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "SMTP handshake timed out after %u seconds",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Handshake timed out");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch case SMTP_CLIENT_CONNECTION_STATE_AUTHENTICATING:
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication timed out after %u seconds",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Authentication timed out");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_do_connect(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (connection_client_connect(&conn->conn) < 0) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_connected(&conn->conn, FALSE);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* don't use connection.h timeout because we want this timeout
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch to include also the SSL handshake */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_connect_timeout, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_connect_next_ip(struct smtp_client_connection *conn)
b136a381ac64c99b7341830ae664ae70c726c08fStephan Bosch const struct ip_addr *ip, *my_ip = &conn->set.my_ip;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->prev_connect_idx = (conn->prev_connect_idx+1) % conn->ips_count;
b136a381ac64c99b7341830ae664ae70c726c08fStephan Bosch "Connecting to %s:%u (from %s)",
b136a381ac64c99b7341830ae664ae70c726c08fStephan Bosch net_ip2addr(ip), conn->port, net_ip2addr(my_ip));
b136a381ac64c99b7341830ae664ae70c726c08fStephan Bosch "Connecting to %s:%u",
b136a381ac64c99b7341830ae664ae70c726c08fStephan Bosch connection_init_client_ip_from(conn->client->conn_list,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_delayed_host_lookup_failure(
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Delayed host lookup failure");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Failed to lookup remote server");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_dns_callback(const struct dns_lookup_result *result,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "dns_lookup(%s) failed: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_delayed_host_lookup_failure, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "DNS lookup successful; got %d IPs",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->ips = i_new(struct ip_addr, conn->ips_count);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch memcpy(conn->ips, result->ips, sizeof(*conn->ips) * conn->ips_count);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_connect(struct smtp_client_connection *conn,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_command_callback_t login_callback, void *login_context)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state != SMTP_CLIENT_CONNECTION_STATE_DISCONNECTED) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Looking up IP address");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* IP address */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->ips = i_new(struct ip_addr, conn->ips_count);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Performing asynchronous DNS lookup");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch (void)dns_client_lookup(conn->set.dns_client, conn->host,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch } else if (conn->set.dns_client_socket_path != NULL) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch dns_set.timeout_msecs = conn->set.connect_timeout_msecs;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Performing asynchronous DNS lookup");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* no dns-conn, use blocking lookup */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch ret = net_gethostbyname(conn->host, &ips, &ips_count);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "net_gethostbyname(%s) failed: %s",
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_delayed_host_lookup_failure, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "DNS lookup successful; got %d IPs", ips_count);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch memcpy(conn->ips, ips, ips_count * sizeof(*ips));
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* always work asynchronously */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_connect_next_ip, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstatic const struct connection_settings smtp_client_connection_set = {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschstatic const struct connection_vfuncs smtp_client_connection_vfuncs = {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch .client_connected = smtp_client_connection_connected
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch (&smtp_client_connection_set, &smtp_client_connection_vfuncs);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_disconnect(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state == SMTP_CLIENT_CONNECTION_STATE_DISCONNECTED)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Disconnected");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->conn.output != NULL && !conn->sent_quit &&
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* Close the connection gracefully if possible */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch o_stream_send_str(conn->conn.output, "QUIT\r\n");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Disconnected from server");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Disconnected from server");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_create(struct smtp_client *client,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch enum smtp_protocol protocol, const char *host, in_port_t port,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch enum smtp_client_connection_ssl_mode ssl_mode,
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch pool = pool_alloconly_create("smtp client connection", 512);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn = p_new(pool, struct smtp_client_connection, 1);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->conn.name = p_strdup_printf(conn->pool, "%s:%u", host, port);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->my_hostname != NULL && *set->my_hostname != '\0')
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.my_hostname = p_strdup(pool, set->my_hostname);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0')
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir);
68d51078686e3d0b305f91e400c29e581343aeb1Stephan Bosch conn->set.ssl = ssl_iostream_settings_dup(pool, set->ssl);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->master_user != NULL && *set->master_user != '\0')
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.master_user = p_strdup_empty(pool, set->master_user);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->username != NULL && *set->username != '\0')
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.username = p_strdup_empty(pool, set->username);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (set->password != NULL && *set->password != '\0') {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->password = p_strdup(pool, set->password);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.remember_password = set->remember_password;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.command_timeout_msecs = set->command_timeout_msecs;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.connect_timeout_msecs = set->connect_timeout_msecs;
c26c060e415eb0047b6eb71470ac4ec2e0736b31Stephan Bosch conn->set.max_reply_size = set->max_reply_size;
c26c060e415eb0047b6eb71470ac4ec2e0736b31Stephan Bosch conn->set.max_data_chunk_size = set->max_data_chunk_size;
c26c060e415eb0047b6eb71470ac4ec2e0736b31Stephan Bosch conn->set.max_data_chunk_pipeline = set->max_data_chunk_pipeline;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.socket_send_buffer_size = set->socket_send_buffer_size;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.socket_recv_buffer_size = set->socket_recv_buffer_size;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.debug = conn->set.debug || set->debug;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.proxy_data.source_ip = set->proxy_data.source_ip;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.proxy_data.source_port = set->proxy_data.source_port;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.proxy_data.ttl_plus_1 = set->proxy_data.ttl_plus_1;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->set.proxy_data.timeout_secs = set->proxy_data.timeout_secs;
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch connection_init(conn->client->conn_list, &conn->conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Connection created");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_ref(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_unref(struct smtp_client_connection **_conn)
a56840e419fb37d98df754153118ff6f213f8233Stephan Bosch /* could have been created while already disconnected */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Destroy");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_reply_parser_deinit(&conn->reply_parser);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_close(struct smtp_client_connection **_conn)
a56840e419fb37d98df754153118ff6f213f8233Stephan Bosch /* could have been created while already disconnected */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschvoid smtp_client_connection_switch_ioloop(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->to_connect = io_loop_move_timeout(&conn->to_connect);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->to_trans = io_loop_move_timeout(&conn->to_trans);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch conn->to_commands = io_loop_move_timeout(&conn->to_commands);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch struct smtp_client_connection *conn ATTR_UNUSED)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* nothing */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_reset(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch "Submitting RSET command");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Boschsmtp_client_connection_start_transaction(struct smtp_client_connection *conn)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state != SMTP_CLIENT_CONNECTION_STATE_READY)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_debug(conn, "Start next transaction");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_reply_init(&reply, 200, "Connection ready");
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_connect(conn, NULL, NULL);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state == SMTP_CLIENT_CONNECTION_STATE_READY) {
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_start_transaction, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch bool was_first = (trans == conn->transactions_head);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch i_assert(conn->state != SMTP_CLIENT_CONNECTION_STATE_READY);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state != SMTP_CLIENT_CONNECTION_STATE_TRANSACTION)
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch /* transaction messed up; protocol state needs to be reset for
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch next transaction */
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch smtp_client_connection_start_transaction, conn);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch i_assert(conn->state != SMTP_CLIENT_CONNECTION_STATE_READY);
b3888944586654b4aa069e0db31f998e0ed8b414Stephan Bosch if (conn->state != SMTP_CLIENT_CONNECTION_STATE_TRANSACTION)