summaryrefslogtreecommitdiffstats
path: root/src/lib-smtp/smtp-client.c
blob: 653dd0ef189dd251ad3a90c29ad4fda1adb5fd80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
#include "connection.h"
#include "dns-lookup.h"
#include "iostream-rawlog.h"
#include "iostream-ssl.h"

#include "smtp-client-private.h"

#define SMTP_DEFAULT_PORT 80
#define SSMTP_DEFAULT_PORT 465

static struct event_category event_category_smtp_client = {
	.name = "smtp-client"
};

/*
 * Client
 */

struct smtp_client *smtp_client_init(const struct smtp_client_settings *set)
{
	struct smtp_client *client;
	pool_t pool;

	pool = pool_alloconly_create("smtp client", 1024);
	client = p_new(pool, struct smtp_client, 1);
	client->pool = pool;

	client->set.my_ip = set->my_ip;
	client->set.my_hostname = p_strdup(pool, set->my_hostname);

	client->set.forced_capabilities = set->forced_capabilities;
	if (set->extra_capabilities != NULL) {
		client->set.extra_capabilities =
			p_strarray_dup(pool, set->extra_capabilities);
	}

	client->set.dns_client = set->dns_client;
	client->set.dns_client_socket_path =
		p_strdup(pool, set->dns_client_socket_path);
	client->set.rawlog_dir = p_strdup_empty(pool, set->rawlog_dir);

	if (set->ssl != NULL) {
		client->set.ssl =
			ssl_iostream_settings_dup(client->pool, set->ssl);
	}

	client->set.master_user = p_strdup_empty(pool, set->master_user);
	client->set.username = p_strdup_empty(pool, set->username);
	client->set.sasl_mech = set->sasl_mech;
	if (set->sasl_mech == NULL) {
		client->set.sasl_mechanisms =
			p_strdup(pool, set->sasl_mechanisms);
	}

	client->set.connect_timeout_msecs = set->connect_timeout_msecs != 0 ?
		set->connect_timeout_msecs :
		SMTP_DEFAULT_CONNECT_TIMEOUT_MSECS;
	client->set.command_timeout_msecs = set->command_timeout_msecs != 0 ?
		set->command_timeout_msecs :
		SMTP_DEFAULT_COMMAND_TIMEOUT_MSECS;
	client->set.max_reply_size = set->max_reply_size != 0 ?
		set->max_reply_size : SMTP_DEFAULT_MAX_REPLY_SIZE;
	client->set.max_data_chunk_size = set->max_data_chunk_size != 0 ?
		set->max_data_chunk_size : SMTP_DEFAULT_MAX_DATA_CHUNK_SIZE;
	client->set.max_data_chunk_pipeline = set->max_data_chunk_pipeline != 0 ?
		set->max_data_chunk_pipeline : SMTP_DEFAULT_MAX_DATA_CHUNK_PIPELINE;

	client->set.socket_send_buffer_size = set->socket_send_buffer_size;
	client->set.socket_recv_buffer_size = set->socket_recv_buffer_size;
	client->set.debug = set->debug;
	client->set.verbose_user_errors = set->verbose_user_errors;

	smtp_proxy_data_merge(pool, &client->set.proxy_data, &set->proxy_data);

	client->conn_list = smtp_client_connection_list_init();

	/* There is no event log prefix added here, since the client itself does
	   not log anything and the prefix is protocol-dependent. */
	client->event = event_create(set->event_parent);
	event_add_category(client->event, &event_category_smtp_client);
	event_set_forced_debug(client->event, set->debug);

	return client;
}

void smtp_client_deinit(struct smtp_client **_client)
{
	struct smtp_client *client = *_client;

	connection_list_deinit(&client->conn_list);

	if (client->ssl_ctx != NULL)
		ssl_iostream_context_unref(&client->ssl_ctx);
	event_unref(&client->event);
	pool_unref(&client->pool);
	*_client = NULL;
}

void smtp_client_switch_ioloop(struct smtp_client *client)
{
	struct connection *_conn = client->conn_list->connections;

	/* move connections */
	for (; _conn != NULL; _conn = _conn->next) {
		struct smtp_client_connection *conn =
			(struct smtp_client_connection *)_conn;

		smtp_client_connection_switch_ioloop(conn);
	}
}

int smtp_client_init_ssl_ctx(struct smtp_client *client, const char **error_r)
{
	const char *error;

	if (client->ssl_ctx != NULL)
		return 0;

	if (client->set.ssl == NULL) {
		*error_r = "Requested SSL connection, but no SSL settings given";
		return -1;
	}
	if (ssl_iostream_client_context_cache_get(client->set.ssl,
		&client->ssl_ctx, &error) < 0) {
		*error_r = t_strdup_printf("Couldn't initialize SSL context: %s",
					   error);
		return -1;
	}
	return 0;
}

// FIXME: Implement smtp_client_run()