#include "imap-resp-code.h"
#include "imapc-client.h"
-#define IMAP_DEFAULT_PORT 143
-#define IMAPS_DEFAULT_PORT 993
#define DNS_CLIENT_SOCKET_NAME "dns-client"
-struct imap_passdb_module {
- struct passdb_module module;
- struct imapc_settings set;
- bool set_have_vars;
-};
-
struct imap_auth_request {
struct imapc_client *client;
struct auth_request *auth_request;
static void
passdb_imap_verify_plain(struct auth_request *auth_request,
- const char *password,
+ const char *password ATTR_UNUSED,
verify_plain_callback_t *callback)
{
- struct passdb_module *_module = auth_request->passdb->passdb;
- struct imap_passdb_module *module =
- (struct imap_passdb_module *)_module;
struct imap_auth_request *request;
- struct imapc_settings set;
struct imapc_parameters params = {};
- const char *error;
- string_t *str;
-
- set = module->set;
- set.dns_client_socket_path =
- t_strconcat(auth_request->set->base_dir, "/",
- DNS_CLIENT_SOCKET_NAME, NULL);
- set.imapc_password = password;
- set.imapc_max_idle_time = IMAPC_DEFAULT_MAX_IDLE_TIME;
-
- if (module->set_have_vars) {
- str = t_str_new(128);
- if (auth_request_var_expand(str, set.imapc_user, auth_request,
- NULL, &error) <= 0) {
- e_error(authdb_event(auth_request),
- "Failed to expand username=%s: %s",
- set.imapc_user, error);
- callback(PASSDB_RESULT_INTERNAL_FAILURE, auth_request);
- return;
- }
- set.imapc_user = t_strdup(str_c(str));
-
- str_truncate(str, 0);
- if (auth_request_var_expand(str, set.imapc_host, auth_request,
- NULL, &error) <= 0) {
- e_error(authdb_event(auth_request),
- "Failed to expand host=%s: %s",
- set.imapc_host, error);
- callback(PASSDB_RESULT_INTERNAL_FAILURE, auth_request);
- return;
- }
- set.imapc_host = t_strdup(str_c(str));
- }
- e_debug(authdb_event(auth_request),
- "lookup host=%s port=%d", set.imapc_host, set.imapc_port);
request = p_new(auth_request->pool, struct imap_auth_request, 1);
- request->client = imapc_client_init(&set, ¶ms, authdb_event(auth_request));
+ request->client = imapc_client_init(¶ms, authdb_event(auth_request));
request->auth_request = auth_request;
request->verify_callback = callback;
imapc_client_login(request->client);
}
-static struct passdb_module *
-passdb_imap_preinit(pool_t pool, const char *args)
-{
- struct imap_passdb_module *module;
- char **tmp;
- const char *key, *value;
- bool port_set = FALSE;
-
- module = p_new(pool, struct imap_passdb_module, 1);
- module->module.default_pass_scheme = "PLAIN";
- module->set.imapc_port = IMAP_DEFAULT_PORT;
- module->set.imapc_ssl = "no";
- module->set.imapc_user = "%u";
- module->set.imapc_rawlog_dir = "";
-
- for (tmp = p_strsplit(pool, args, " "); *tmp != NULL; tmp++) {
- key = *tmp;
- value = strchr(key, '=');
- if (value == NULL)
- value = "";
- else
- key = t_strdup_until(key, value++);
- if (strcmp(key, "host") == 0)
- module->set.imapc_host = value;
- else if (strcmp(key, "port") == 0) {
- if (net_str2port(value, &module->set.imapc_port) < 0)
- i_fatal("passdb imap: Invalid port: %s", value);
- port_set = TRUE;
- } else if (strcmp(key, "username") == 0)
- module->set.imapc_user = value;
- else if (strcmp(key, "rawlog_dir") == 0)
- module->set.imapc_rawlog_dir = value;
- else if (strcmp(key, "ssl") == 0) {
- if (strcmp(value, "imaps") == 0) {
- if (!port_set)
- module->set.imapc_port = IMAPS_DEFAULT_PORT;
- module->set.imapc_ssl = "imaps";
- } else if (strcmp(value, "starttls") == 0) {
- module->set.imapc_ssl = "starttls";
- } else {
- i_fatal("passdb imap: Invalid ssl mode: %s",
- value);
- }
- } else {
- i_fatal("passdb imap: Unknown parameter: %s", key);
- }
- }
-
- if (module->set.imapc_host == NULL)
- i_fatal("passdb imap: Missing host parameter");
-
- module->set_have_vars =
- strchr(module->set.imapc_user, '%') != NULL ||
- strchr(module->set.imapc_host, '%') != NULL;
- return &module->module;
-}
-
static struct passdb_module_interface passdb_imap_plugin = {
.name = "imap",
- .preinit_legacy = passdb_imap_preinit,
.verify_plain = passdb_imap_verify_plain,
};
#define IMAPC_CLIENT_PRIVATE_H
#include "imapc-client.h"
+#include "imapc-settings.h"
#define IMAPC_CLIENT_IDLE_SEND_DELAY_MSECS 100
+enum imapc_client_ssl_mode {
+ IMAPC_CLIENT_SSL_MODE_NONE,
+ IMAPC_CLIENT_SSL_MODE_IMMEDIATE,
+ IMAPC_CLIENT_SSL_MODE_STARTTLS
+};
+
struct imapc_client_connection {
struct imapc_connection *conn;
struct imapc_client *client;
#include "imapc-msgmap.h"
#include "imapc-connection.h"
#include "imapc-client-private.h"
+#include "imapc-settings.h"
#include <unistd.h>
}
struct imapc_client *
-imapc_client_init(const struct imapc_settings *set,
- const struct imapc_parameters *params,
+imapc_client_init(const struct imapc_parameters *params,
struct event *event_parent)
{
struct imapc_client *client;
pool_t pool;
- i_assert(set->imapc_connection_retry_count == 0 ||
- set->imapc_connection_retry_interval > 0);
-
pool = pool_alloconly_create("imapc client", 1024);
client = p_new(pool, struct imapc_client, 1);
client->pool = pool;
client->refcount = 1;
client->event = event_create(event_parent);
- event_set_append_log_prefix(client->event, t_strdup_printf(
- "imapc(%s:%u): ", set->imapc_host, set->imapc_port));
-
- client->set = p_new(pool, struct imapc_settings, 1);
- client->set->imapc_host = p_strdup(pool, set->imapc_host);
- client->set->imapc_port = set->imapc_port;
- client->set->imapc_master_user = p_strdup_empty(pool, set->imapc_master_user);
- client->set->imapc_user = p_strdup(pool, set->imapc_user);
- client->set->imapc_password = p_strdup(pool, set->imapc_password);
- client->set->imapc_sasl_mechanisms = p_strdup(pool, set->imapc_sasl_mechanisms);
- client->set->parsed_features = set->parsed_features;
- client->set->dns_client_socket_path =
- p_strdup(pool, set->dns_client_socket_path);
- client->set->imapc_rawlog_dir = p_strdup(pool, set->imapc_rawlog_dir);
- client->set->imapc_max_idle_time = set->imapc_max_idle_time;
- client->set->imapc_connection_timeout_interval = set->imapc_connection_timeout_interval != 0 ?
- set->imapc_connection_timeout_interval :
- IMAPC_DEFAULT_CONNECT_TIMEOUT_MSECS;
- client->set->imapc_connection_retry_count = set->imapc_connection_retry_count;
- client->set->imapc_connection_retry_interval = set->imapc_connection_retry_interval;
- client->set->imapc_cmd_timeout = set->imapc_cmd_timeout != 0 ?
- (set->imapc_cmd_timeout * 1000) : IMAPC_DEFAULT_COMMAND_TIMEOUT_MSECS;
- client->set->imapc_max_line_length = set->imapc_max_line_length != 0 ?
- set->imapc_max_line_length : IMAPC_DEFAULT_MAX_LINE_LENGTH;
- client->set->imapc_ssl = p_strdup(pool, set->imapc_ssl);
- client->set->imapc_ssl_verify = set->imapc_ssl_verify;
-
- client->set->throttle_init_msecs = set->throttle_init_msecs != 0 ?
- set->throttle_init_msecs : IMAPC_THROTTLE_DEFAULT_INIT_MSECS;
- client->set->throttle_max_msecs = set->throttle_max_msecs != 0 ?
- set->throttle_max_msecs : IMAPC_THROTTLE_DEFAULT_MAX_MSECS;
- client->set->throttle_shrink_min_msecs = set->throttle_shrink_min_msecs != 0 ?
- set->throttle_shrink_min_msecs : IMAPC_THROTTLE_DEFAULT_SHRINK_MIN_MSECS;
+ client->untagged_callback = default_untagged_callback;
+ /* Explicitly cast to drop const modifier. */
+ client->set = (struct imapc_settings *) settings_get_or_fatal(
+ client->event, &imapc_setting_parser_info);
client->params.session_id_prefix =
p_strdup(pool, params->session_id_prefix);
client->params.temp_path_prefix =
client->set->imapc_rawlog_dir =
p_strdup(pool, params->override_rawlog_dir);
- client->untagged_callback = default_untagged_callback;
+ event_set_append_log_prefix(client->event, t_strdup_printf(
+ "imapc(%s:%u): ", client->set->imapc_host, client->set->imapc_port));
client->ssl_mode = IMAPC_CLIENT_SSL_MODE_NONE;
- if (strcmp(set->imapc_ssl, "imaps") == 0) {
+ if (strcmp(client->set->imapc_ssl, "imaps") == 0) {
client->ssl_mode = IMAPC_CLIENT_SSL_MODE_IMMEDIATE;
- } else if (strcmp(set->imapc_ssl, "starttls") == 0) {
+ } else if (strcmp(client->set->imapc_ssl, "starttls") == 0) {
client->ssl_mode = IMAPC_CLIENT_SSL_MODE_STARTTLS;
}
if (--client->refcount > 0)
return;
+ settings_free(client->set);
+
event_unref(&client->event);
pool_unref(&client->pool);
}
#include "iostream-ssl.h"
#include "imapc-settings.h"
-/* IMAP RFC defines this to be at least 30 minutes. */
-#define IMAPC_DEFAULT_MAX_IDLE_TIME (60*29)
-
enum imapc_command_state {
IMAPC_COMMAND_STATE_OK = 0,
IMAPC_COMMAND_STATE_NO,
IMAPC_COMMAND_FLAG_RECONNECTED = 0x10
};
-enum imapc_client_ssl_mode {
- IMAPC_CLIENT_SSL_MODE_NONE,
- IMAPC_CLIENT_SSL_MODE_IMMEDIATE,
- IMAPC_CLIENT_SSL_MODE_STARTTLS
-};
-
-#define IMAPC_DEFAULT_CONNECT_TIMEOUT_MSECS (1000*30)
-#define IMAPC_DEFAULT_COMMAND_TIMEOUT_MSECS (1000*60*5)
-#define IMAPC_DEFAULT_MAX_LINE_LENGTH (SIZE_MAX)
-
struct imapc_throttling_settings {
unsigned int init_msecs;
unsigned int max_msecs;
const char *dns_client_socket_path;
const char *temp_path_prefix;
- enum imapc_client_ssl_mode ssl_mode;
bool ssl_allow_invalid_cert;
const char *rawlog_dir;
const char *error);
struct imapc_client *
-imapc_client_init(const struct imapc_settings *set,
- const struct imapc_parameters *params,
+imapc_client_init(const struct imapc_parameters *params,
struct event *event_parent);
void imapc_client_disconnect(struct imapc_client *client);
void imapc_client_deinit(struct imapc_client **client);
const struct dsasl_client_mech *sasl_mech = NULL;
const char *error;
- if (set->imapc_master_user == NULL) {
+ if (*set->imapc_master_user == '\0') {
e_debug(conn->event, "Authenticating as %s", set->imapc_user);
} else {
e_debug(conn->event, "Authenticating as %s for user %s",
}
if ((set->parsed_features & IMAPC_FEATURE_PROXYAUTH) != 0 &&
- set->imapc_master_user != NULL) {
+ *set->imapc_master_user != '\0') {
/* We can use LOGIN command */
cmd = imapc_connection_cmd(conn, imapc_connection_proxyauth_login_cb,
conn);
return;
}
if (sasl_mech == NULL &&
- ((set->imapc_master_user == NULL &&
+ ((*set->imapc_master_user == '\0' &&
!need_literal(set->imapc_user) && !need_literal(set->imapc_password)) ||
(conn->capabilities & IMAPC_CAPABILITY_AUTH_PLAIN) == 0)) {
/* We can use LOGIN command */
}
i_zero(&sasl_set);
- if (set->imapc_master_user == NULL)
+ if (*set->imapc_master_user == '\0')
sasl_set.authid = set->imapc_user;
else {
sasl_set.authid = set->imapc_master_user;
conn->to = timeout_add(IMAPC_LOGOUT_TIMEOUT_MSECS,
imapc_command_timeout, conn);
} else if (conn->to == NULL) {
- conn->to = timeout_add(conn->client->set->imapc_cmd_timeout,
+ conn->to = timeout_add(conn->client->set->imapc_cmd_timeout * 1000,
imapc_command_timeout, conn);
}
conn->idle_stopping = TRUE;
o_stream_nsend_str(conn->output, "DONE\r\n");
if (conn->to == NULL) {
- conn->to = timeout_add(conn->client->set->imapc_cmd_timeout,
- imapc_command_timeout, conn);
+ conn->to = timeout_add(
+ conn->client->set->imapc_cmd_timeout * 1000,
+ imapc_command_timeout, conn);
}
}
}
.imapc_rawlog_dir = "",
.imapc_list_prefix = "",
.imapc_cmd_timeout = 5*60,
- .imapc_max_idle_time = 60*29,
+ .imapc_max_idle_time = IMAPC_DEFAULT_MAX_IDLE_TIME,
.imapc_connection_timeout_interval = 1000*30,
.imapc_connection_retry_count = 1,
.imapc_connection_retry_interval = 1000,
- .imapc_max_line_length = 0,
+ .imapc_max_line_length = SET_SIZE_UNLIMITED,
.pop3_deleted_flag = "",
#include "net.h"
+/* IMAP RFC defines this to be at least 30 minutes. */
+#define IMAPC_DEFAULT_MAX_IDLE_TIME (60*29)
+
/* <settings checks> */
enum imapc_features {
IMAPC_FEATURE_NO_FETCH_SIZE = 0x01,
#include "test-common.h"
#include "test-subprocess.h"
#include "imapc-client-private.h"
+#include "settings.h"
#include <stdio.h>
#include <unistd.h>
static ARRAY(enum imapc_command_state) imapc_cmd_last_replies;
static bool debug = FALSE;
+static struct settings_simple test_set;
+
static void main_deinit(void);
/*
* Test client
*/
-static struct imapc_settings test_imapc_default_settings = {
- .imapc_host = "127.0.0.1",
- .imapc_user = "testuser",
- .imapc_password = "testpass",
-
- .dns_client_socket_path = "",
- .imapc_rawlog_dir = "",
+static const char **
+test_generate_settings(const char *port, const char *connection_timeout_interval)
+{
+ static const char *settings[] = {
+ "imapc_host", "127.0.0.1",
+ "imapc_port", "",
+ "imapc_user", "testuser",
+ "imapc_password", "testpass",
+ "imapc_connection_timeout_interval", "5s",
+ "imapc_connection_retry_count", "3",
+ "imapc_connection_retry_interval", "10ms",
+ "imapc_max_idle_time", "10s",
- .imapc_connection_timeout_interval = 5000,
- .imapc_connection_retry_count = 3,
- .imapc_connection_retry_interval = 10,
+ NULL,
+ };
+ if (port != NULL)
+ settings[3] = port;
+ if (connection_timeout_interval != NULL)
+ settings[9] = connection_timeout_interval;
- .imapc_max_idle_time = 10000,
- .imapc_ssl = "no",
-};
+ return settings;
+}
static const struct imapc_parameters imapc_params = {
.temp_path_prefix = ".test-tmp/",
i_close_fd(&server.fd_listen);
main_deinit();
+
+ /* Cleanup the test settings in the server process as well.
+ See test_run_client_server() for the appropriate cleanup call in the
+ main process. */
+ settings_simple_deinit(&test_set);
return 0;
}
static void
-test_run_client(struct imapc_settings *client_set,
- test_client_init_t *client_test)
+test_run_client(test_client_init_t *client_test)
{
struct ioloop *ioloop;
i_sleep_msecs(100); /* wait a little for server setup */
ioloop = io_loop_create();
- imapc_client = imapc_client_init(client_set, &imapc_params, NULL);
+ imapc_client = imapc_client_init(&imapc_params, test_set.event);
client_test();
imapc_client_logout(imapc_client);
test_assert(array_count(&imapc_cmd_last_replies) == 0);
}
static void
-test_run_client_server(struct imapc_settings *client_set,
- test_client_init_t *client_test,
- test_server_init_t *server_test)
+test_run_client_server(test_client_init_t *client_test,
+ test_server_init_t *server_test,
+ bool reduce_timeout)
{
- struct imapc_settings client_set_copy = *client_set;
const char *error;
imapc_client_cmd_tag_counter = 0;
server.pid = (pid_t)-1;
server.fd = -1;
server.fd_listen = test_open_server_fd(&server.port);
- client_set_copy.imapc_port = server.port;
+
+ const char **settings = test_generate_settings(dec2str(server.port),
+ reduce_timeout ? "500ms" : "5s");
+ settings_simple_init(&test_set, settings);
if (mkdir(imapc_params.temp_path_prefix, 0700) < 0 && errno != EEXIST)
i_fatal("mkdir(%s) failed: %m", imapc_params.temp_path_prefix);
i_close_fd(&server.fd_listen);
/* Run client */
- test_run_client(&client_set_copy, client_test);
+ test_run_client(client_test);
i_unset_failure_prefix();
test_subprocess_kill_all(SERVER_KILL_TIMEOUT_SECS);
if (unlink_directory(imapc_params.temp_path_prefix,
UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
i_fatal("%s", error);
+
+ /* Cleanup the test settings in the main process.
+ Note: This needs to be called as well in the server process,
+ otherwise it will leak it's event and the looked up settings
+ struct. See test_run_server() for the appropriate cleanup call in
+ the server process. */
+ settings_simple_deinit(&test_set);
}
/*
static void test_imapc_connect_failed(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc connect failed");
- test_run_client_server(&set, test_imapc_connect_failed_client, NULL);
+ test_run_client_server(test_imapc_connect_failed_client, NULL, FALSE);
test_end();
}
static void test_imapc_banner_hangs(void)
{
- struct imapc_settings set = test_imapc_default_settings;
- set.imapc_connection_timeout_interval = 500;
-
test_begin("imapc banner hangs");
- test_run_client_server(&set, test_imapc_banner_hangs_client,
- test_imapc_banner_hangs_server);
+ test_run_client_server(test_imapc_banner_hangs_client,
+ test_imapc_banner_hangs_server,
+ TRUE);
test_end();
}
static void test_imapc_login_hangs(void)
{
- struct imapc_settings set = test_imapc_default_settings;
- set.imapc_connection_timeout_interval = 500;
-
test_begin("imapc login hangs");
- test_run_client_server(&set, test_imapc_login_hangs_client,
- test_imapc_login_hangs_server);
+ test_run_client_server(test_imapc_login_hangs_client,
+ test_imapc_login_hangs_server,
+ TRUE);
test_end();
}
static void test_imapc_login_fails(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc login fails");
- test_run_client_server(&set, test_imapc_login_fails_client,
- test_imapc_login_fails_server);
+ test_run_client_server(test_imapc_login_fails_client,
+ test_imapc_login_fails_server,
+ FALSE);
test_end();
}
static void test_imapc_reconnect(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc reconnect");
- test_run_client_server(&set, test_imapc_reconnect_client,
- test_imapc_reconnect_server);
+ test_run_client_server(test_imapc_reconnect_client,
+ test_imapc_reconnect_server,
+ FALSE);
test_end();
}
static void test_imapc_reconnect_resend_commands(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc reconnect resend commands");
- test_run_client_server(&set, test_imapc_reconnect_resend_cmds_client,
- test_imapc_reconnect_resend_cmds_server);
+ test_run_client_server(test_imapc_reconnect_resend_cmds_client,
+ test_imapc_reconnect_resend_cmds_server,
+ FALSE);
test_end();
}
static void test_imapc_reconnect_resend_commands_failed(void)
{
- struct imapc_settings set = test_imapc_default_settings;
- set.imapc_connection_timeout_interval = 500;
-
test_begin("imapc reconnect resend commands failed");
- test_run_client_server(&set, test_imapc_reconnect_resend_cmds_failed_client,
- test_imapc_reconnect_resend_cmds_failed_server);
+ test_run_client_server(test_imapc_reconnect_resend_cmds_failed_client,
+ test_imapc_reconnect_resend_cmds_failed_server,
+ TRUE);
test_end();
}
static void test_imapc_reconnect_mailbox(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc reconnect mailbox");
- test_run_client_server(&set, test_imapc_reconnect_mailbox_client,
- test_imapc_reconnect_mailbox_server);
+ test_run_client_server(test_imapc_reconnect_mailbox_client,
+ test_imapc_reconnect_mailbox_server,
+ FALSE);
test_end();
}
static void test_imapc_client_get_capabilities(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc_client_get_capabilities()");
- test_run_client_server(&set, test_imapc_client_get_capabilities_client,
- test_imapc_client_get_capabilities_server);
+ test_run_client_server(test_imapc_client_get_capabilities_client,
+ test_imapc_client_get_capabilities_server,
+ FALSE);
test_end();
}
static void test_imapc_client_get_capabilities_reconnected(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc_client_get_capabilities() reconnected");
test_run_client_server(
- &set, test_imapc_client_get_capabilities_reconnected_client,
- test_imapc_client_get_capabilities_reconnected_server);
+ test_imapc_client_get_capabilities_reconnected_client,
+ test_imapc_client_get_capabilities_reconnected_server,
+ FALSE);
test_end();
}
static void test_imapc_client_get_capabilities_disconnected(void)
{
- struct imapc_settings set = test_imapc_default_settings;
-
test_begin("imapc_client_get_capabilities() disconnected");
test_run_client_server(
- &set, test_imapc_client_get_capabilities_disconnected_client,
- test_imapc_client_get_capabilities_disconnected_server);
+ test_imapc_client_get_capabilities_disconnected_client,
+ test_imapc_client_get_capabilities_disconnected_server,
+ FALSE);
test_end();
}
client->refcount = 1;
client->set = imapc_set;
i_array_init(&client->untagged_callbacks, 16);
- client->client = imapc_client_init(client->set, ¶ms, list->event);
+ client->client = imapc_client_init(¶ms, list->event);
imapc_client_register_untagged(client->client,
imapc_storage_client_untagged_cb, client);