Lines Matching refs:conn
51 struct imapc_connection *conn;
98 int (*input_callback)(struct imapc_connection *conn);
148 static int imapc_connection_output(struct imapc_connection *conn);
149 static int imapc_connection_ssl_init(struct imapc_connection *conn);
151 static void imapc_command_send_more(struct imapc_connection *conn);
153 imapc_login_callback(struct imapc_connection *conn,
157 imapc_auth_ok(struct imapc_connection *conn)
159 if (conn->client->set.debug)
160 i_debug("imapc(%s): Authenticated successfully", conn->name);
162 if (conn->client->state_change_callback == NULL)
165 conn->client->state_change_callback(conn->client->state_change_context,
170 imapc_auth_failed(struct imapc_connection *conn, const struct imapc_command_reply *_reply,
179 i_error("imapc(%s): %s", conn->name, reply.text_full);
180 imapc_login_callback(conn, &reply);
182 if (conn->client->state_change_callback == NULL)
185 conn->client->state_change_callback(conn->client->state_change_context,
195 struct imapc_connection *conn;
197 conn = i_new(struct imapc_connection, 1);
198 conn->refcount = 1;
199 conn->client = client;
200 conn->login_callback = login_callback;
201 conn->login_context = login_context;
202 conn->fd = -1;
203 conn->name = i_strdup_printf("%s:%u", client->set.host,
205 conn->literal.fd = -1;
206 conn->reconnect_ok = (client->set.connect_retry_count>0);
207 i_array_init(&conn->cmd_send_queue, 8);
208 i_array_init(&conn->cmd_wait_list, 32);
209 i_array_init(&conn->literal_files, 4);
210 i_array_init(&conn->aborted_cmd_tags, 8);
213 i_debug("imapc(%s): Created new connection", conn->name);
216 return conn;
219 static void imapc_connection_ref(struct imapc_connection *conn)
221 i_assert(conn->refcount > 0);
223 conn->refcount++;
228 struct imapc_connection *conn = *_conn;
230 i_assert(conn->refcount > 0);
233 if (--conn->refcount > 0)
236 i_assert(conn->disconnect_reason == NULL);
238 if (conn->capabilities_list != NULL)
239 p_strsplit_free(default_pool, conn->capabilities_list);
240 array_free(&conn->cmd_send_queue);
241 array_free(&conn->cmd_wait_list);
242 array_free(&conn->literal_files);
243 array_free(&conn->aborted_cmd_tags);
244 imapc_client_unref(&conn->client);
245 i_free(conn->ips);
246 i_free(conn->name);
247 i_free(conn);
256 void imapc_connection_ioloop_changed(struct imapc_connection *conn)
258 if (conn->io != NULL)
259 conn->io = io_loop_move_io(&conn->io);
260 if (conn->to != NULL)
261 conn->to = io_loop_move_timeout(&conn->to);
262 if (conn->to_throttle != NULL)
263 conn->to_throttle = io_loop_move_timeout(&conn->to_throttle);
264 if (conn->to_throttle_shrink != NULL)
265 conn->to_throttle_shrink = io_loop_move_timeout(&conn->to_throttle_shrink);
266 if (conn->output != NULL)
267 o_stream_switch_ioloop(conn->output);
268 if (conn->dns_lookup != NULL)
269 dns_lookup_switch_ioloop(conn->dns_lookup);
271 if (conn->client->ioloop == NULL && conn->to_output != NULL) {
275 conn->to_output = io_loop_move_timeout(&conn->to_output);
320 void imapc_connection_abort_commands(struct imapc_connection *conn,
329 imapc_connection_abort_commands_array(&conn->cmd_wait_list, &tmp_array,
331 imapc_connection_abort_commands_array(&conn->cmd_send_queue, &tmp_array,
334 if (array_count(&conn->cmd_wait_list) > 0 && only_box == NULL) {
336 array_append_array(&conn->cmd_wait_list,
337 &conn->cmd_send_queue);
338 array_clear(&conn->cmd_send_queue);
339 array_append_array(&conn->cmd_send_queue,
340 &conn->cmd_wait_list);
341 array_clear(&conn->cmd_wait_list);
358 if (cmd->sent && conn->state == IMAPC_CONNECTION_STATE_DONE) {
361 seq_range_array_add(&conn->aborted_cmd_tags, cmd->tag);
366 timeout_remove(&conn->to);
370 imapc_login_callback(struct imapc_connection *conn,
373 if (conn->login_callback != NULL)
374 conn->login_callback(reply, conn->login_context);
377 static void imapc_connection_set_state(struct imapc_connection *conn,
382 conn->state = state;
389 if (conn->disconnect_reason != NULL) {
391 reply.text_full, conn->disconnect_reason);
392 i_free_and_null(conn->disconnect_reason);
395 if (!conn->reconnecting) {
396 imapc_login_callback(conn, &reply);
397 i_free(conn->ips);
398 conn->ips_count = 0;
400 array_clear(&conn->aborted_cmd_tags);
401 conn->idling = FALSE;
402 conn->idle_plus_waiting = FALSE;
403 conn->idle_stopping = FALSE;
405 conn->select_waiting_reply = FALSE;
406 conn->selecting_box = NULL;
407 conn->selected_box = NULL;
412 if (conn->client->stop_on_state_finish && !conn->reconnecting)
413 imapc_client_stop(conn->client);
420 static void imapc_connection_lfiles_free(struct imapc_connection *conn)
424 array_foreach_modifiable(&conn->literal_files, lfile) {
428 array_clear(&conn->literal_files);
441 void imapc_connection_disconnect_full(struct imapc_connection *conn,
445 timeout_remove(&conn->to);
446 conn->reconnecting = reconnecting;
448 if (conn->state == IMAPC_CONNECTION_STATE_DISCONNECTED)
451 if (conn->client->set.debug)
452 i_debug("imapc(%s): Disconnected", conn->name);
454 if (conn->dns_lookup != NULL)
455 dns_lookup_abort(&conn->dns_lookup);
456 imapc_connection_lfiles_free(conn);
457 imapc_connection_literal_reset(&conn->literal);
458 timeout_remove(&conn->to_output);
459 timeout_remove(&conn->to_throttle);
460 timeout_remove(&conn->to_throttle_shrink);
461 if (conn->parser != NULL)
462 imap_parser_unref(&conn->parser);
463 io_remove(&conn->io);
464 if (conn->ssl_iostream != NULL)
465 ssl_iostream_unref(&conn->ssl_iostream);
466 if (conn->fd != -1) {
467 i_stream_destroy(&conn->input);
468 o_stream_destroy(&conn->output);
469 net_disconnect(conn->fd);
470 conn->fd = -1;
476 conn->capabilities = 0;
477 if (conn->capabilities_list != NULL) {
478 p_strsplit_free(default_pool, conn->capabilities_list);
479 conn->capabilities_list = NULL;
482 imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED);
483 imapc_connection_abort_commands(conn, NULL, reconnecting);
486 imapc_client_try_stop(conn->client);
490 void imapc_connection_set_no_reconnect(struct imapc_connection *conn)
492 conn->reconnect_ok = FALSE;
495 void imapc_connection_disconnect(struct imapc_connection *conn)
497 imapc_connection_disconnect_full(conn, FALSE);
500 static void imapc_connection_set_disconnected(struct imapc_connection *conn)
502 imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DISCONNECTED);
503 imapc_connection_abort_commands(conn, NULL, FALSE);
506 static bool imapc_connection_can_reconnect(struct imapc_connection *conn)
508 if (conn->client->logging_out)
510 if (conn->client->set.connect_retry_count == 0 ||
511 (conn->client->set.connect_retry_count < UINT_MAX &&
512 conn->reconnect_count >= conn->client->set.connect_retry_count))
515 if (conn->selected_box != NULL)
516 return imapc_client_mailbox_can_reconnect(conn->selected_box);
518 return conn->reconnect_command_count == 0 &&
519 conn->reconnect_ok;
523 static void imapc_connection_reconnect(struct imapc_connection *conn)
525 conn->reconnect_ok = FALSE;
526 conn->reconnect_waiting = FALSE;
528 if (conn->selected_box != NULL) {
529 i_assert(!conn->selected_box->reconnecting);
530 conn->selected_box->reconnecting = TRUE;
534 conn->selected_box->reconnect_ok = FALSE;
536 imapc_connection_disconnect_full(conn, TRUE);
537 imapc_connection_connect(conn);
540 void imapc_connection_try_reconnect(struct imapc_connection *conn,
546 if (conn->prev_connect_idx + 1 < conn->ips_count && connect_error) {
547 i_warning("imapc(%s): %s - trying the next IP", conn->name, errstr);
548 conn->reconnect_ok = TRUE;
549 imapc_connection_disconnect_full(conn, TRUE);
550 imapc_connection_connect(conn);
554 if (!imapc_connection_can_reconnect(conn)) {
555 i_error("imapc(%s): %s - disconnecting", conn->name, errstr);
556 imapc_connection_disconnect(conn);
558 conn->reconnecting = TRUE;
559 i_warning("imapc(%s): %s - reconnecting (delay %u ms)", conn->name, errstr, delay_msecs);
561 imapc_connection_reconnect(conn);
563 imapc_connection_disconnect_full(conn, TRUE);
564 conn->to = timeout_add(delay_msecs, imapc_connection_reconnect, conn);
565 conn->reconnect_count++;
566 conn->reconnect_waiting = TRUE;
572 imapc_connection_input_error(struct imapc_connection *conn,
579 conn->name, t_strdup_vprintf(fmt, va));
580 imapc_connection_disconnect(conn);
606 imapc_connection_read_literal_init(struct imapc_connection *conn, uoff_t size,
613 i_assert(conn->literal.fd == -1);
621 conn->literal.fd = imapc_client_create_temp_fd(conn->client, &path);
622 if (conn->literal.fd == -1)
624 conn->literal.temp_path = i_strdup(path);
625 conn->literal.bytes_left = size;
626 conn->literal.parent_arg = parent_arg;
627 conn->literal.list_idx = idx;
631 static int imapc_connection_read_literal(struct imapc_connection *conn)
637 if (conn->literal.bytes_left == 0)
640 data = i_stream_get_data(conn->input, &size);
641 if (size > conn->literal.bytes_left)
642 size = conn->literal.bytes_left;
644 if (write_full(conn->literal.fd, data, size) < 0) {
646 conn->name, conn->literal.temp_path);
647 imapc_connection_disconnect(conn);
650 i_stream_skip(conn->input, size);
651 conn->literal.bytes_left -= size;
653 if (conn->literal.bytes_left > 0)
657 lfile = array_append_space(&conn->literal_files);
658 lfile->fd = conn->literal.fd;
659 lfile->parent_arg = conn->literal.parent_arg;
660 lfile->list_idx = conn->literal.list_idx;
662 conn->literal.fd = -1;
663 imapc_connection_literal_reset(&conn->literal);
668 imapc_connection_read_line_more(struct imapc_connection *conn,
674 if ((ret = imapc_connection_read_literal(conn)) <= 0)
677 ret = imap_parser_read_args(conn->parser, 0,
688 const char *err_msg = imap_parser_get_error(conn->parser, &parser_error);
690 imapc_connection_input_error(conn, "Error parsing input: %s", err_msg);
696 if (imap_parser_get_literal_size(conn->parser, &literal_size)) {
697 if (imapc_connection_read_literal_init(conn, literal_size,
699 imap_parser_read_last_literal(conn->parser);
702 return imapc_connection_read_line_more(conn, imap_args_r);
708 imapc_connection_read_line(struct imapc_connection *conn,
715 while ((ret = imapc_connection_read_line_more(conn, imap_args_r)) == 2)
719 data = i_stream_get_data(conn->input, &size);
721 i_stream_skip(conn->input, 2);
723 i_stream_skip(conn->input, 1);
727 data = i_stream_get_data(conn->input, &size);
730 i_stream_skip(conn->input, (lf - data) + 1);
736 imapc_connection_parse_capability(struct imapc_connection *conn,
742 if (conn->client->set.debug) {
744 conn->name, value);
747 conn->capabilities = 0;
748 if (conn->capabilities_list != NULL)
749 p_strsplit_free(default_pool, conn->capabilities_list);
750 conn->capabilities_list = p_strsplit(default_pool, value, " ");
758 conn->capabilities |= cap->capability;
764 if ((conn->capabilities & IMAPC_CAPABILITY_IMAP4REV1) == 0) {
765 imapc_connection_input_error(conn,
773 imapc_connection_handle_resp_text_code(struct imapc_connection *conn,
777 if (imapc_connection_parse_capability(conn, value) < 0)
782 if (conn->selecting_box != NULL) {
783 conn->selected_box = conn->selecting_box;
784 conn->selecting_box = NULL;
791 imapc_connection_handle_resp_text(struct imapc_connection *conn,
801 imapc_connection_input_error(conn, "Missing ']' in resp-text");
813 return imapc_connection_handle_resp_text_code(conn, *key_r, *value_r);
817 imapc_connection_handle_imap_resp_text(struct imapc_connection *conn,
829 imapc_connection_input_error(conn,
835 return imapc_connection_handle_resp_text(conn, text, key_r, value_r);
851 static void imapc_connection_input_reset(struct imapc_connection *conn)
853 conn->input_state = IMAPC_INPUT_STATE_NONE;
854 conn->cur_tag = 0;
855 conn->cur_num = 0;
856 if (conn->parser != NULL)
857 imap_parser_reset(conn->parser);
858 imapc_connection_lfiles_free(conn);
862 imapc_connection_auth_finish(struct imapc_connection *conn,
866 imapc_auth_failed(conn, reply, reply->text_full);
867 imapc_connection_disconnect(conn);
871 imapc_auth_ok(conn);
873 timeout_remove(&conn->to);
874 imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_DONE);
875 imapc_login_callback(conn, reply);
877 imapc_command_send_more(conn);
883 struct imapc_connection *conn = context;
885 imapc_connection_auth_finish(conn, reply);
892 struct imapc_connection *conn = context;
893 const struct imapc_client_settings *set = &conn->client->set;
897 cmd = imapc_connection_cmd(conn, imapc_connection_login_cb,
898 conn);
901 imapc_command_send_more(conn);
903 imapc_connection_auth_finish(conn, reply);
911 struct imapc_connection *conn = context;
918 dsasl_client_free(&conn->sasl_client);
919 imapc_connection_auth_finish(conn, reply);
926 imapc_auth_failed(conn, reply,
929 } else if (dsasl_client_input(conn->sasl_client, buf->data, buf->used, &error) < 0) {
930 imapc_auth_failed(conn, reply, error);
931 } else if (dsasl_client_output(conn->sasl_client, &sasl_output,
933 imapc_auth_failed(conn, reply, error);
939 o_stream_nsend(conn->output, str_data(imap_output),
943 imapc_connection_disconnect(conn);
946 static bool imapc_connection_have_auth(struct imapc_connection *conn,
951 for (capa = conn->capabilities_list; *capa != NULL; capa++) {
960 imapc_connection_get_sasl_mech(struct imapc_connection *conn,
964 const struct imapc_client_settings *set = &conn->client->set;
970 if (imapc_connection_have_auth(conn, *mechanisms)) {
985 static void imapc_connection_authenticate(struct imapc_connection *conn)
987 const struct imapc_client_settings *set = &conn->client->set;
993 if (conn->client->set.debug) {
996 conn->name, set->username);
999 conn->name, set->master_user, set->username);
1004 if (imapc_connection_get_sasl_mech(conn, &sasl_mech, &error) < 0) {
1009 imapc_auth_failed(conn, &reply, error);
1010 imapc_connection_disconnect(conn);
1017 cmd = imapc_connection_cmd(conn, imapc_connection_proxyauth_login_cb,
1018 conn);
1027 (conn->capabilities & IMAPC_CAPABILITY_AUTH_PLAIN) == 0)) {
1029 cmd = imapc_connection_cmd(conn, imapc_connection_login_cb,
1030 conn);
1048 conn->sasl_client = dsasl_client_new(sasl_mech, &sasl_set);
1050 cmd = imapc_connection_cmd(conn, imapc_connection_authenticate_cb, conn);
1054 if ((conn->capabilities & IMAPC_CAPABILITY_SASL_IR) != 0) {
1060 if (dsasl_client_output(conn->sasl_client, &sasl_output,
1063 conn->name, error);
1064 imapc_connection_disconnect(conn);
1083 struct imapc_connection *conn = context;
1087 imapc_connection_input_error(conn, "STARTTLS failed: %s",
1092 if (imapc_connection_ssl_init(conn) < 0)
1093 imapc_connection_disconnect(conn);
1096 cmd = imapc_connection_cmd(conn, imapc_connection_capability_cb,
1097 conn);
1109 static void imapc_connection_send_id(struct imapc_connection *conn)
1114 if ((conn->capabilities & IMAPC_CAPABILITY_ID) == 0 ||
1115 conn->client->set.session_id_prefix == NULL)
1118 cmd = imapc_connection_cmd(conn, imapc_connection_id_callback, conn);
1122 conn->client->set.session_id_prefix, ++global_id_counter));
1125 static void imapc_connection_starttls(struct imapc_connection *conn)
1129 if (conn->client->set.ssl_mode == IMAPC_CLIENT_SSL_MODE_STARTTLS &&
1130 conn->ssl_iostream == NULL) {
1131 if ((conn->capabilities & IMAPC_CAPABILITY_STARTTLS) == 0) {
1134 conn->name);
1135 imapc_connection_disconnect(conn);
1138 cmd = imapc_connection_cmd(conn, imapc_connection_starttls_cb,
1139 conn);
1144 imapc_connection_send_id(conn);
1145 imapc_connection_authenticate(conn);
1152 struct imapc_connection *conn = context;
1155 imapc_connection_input_error(conn,
1157 } else if (conn->capabilities == 0) {
1158 imapc_connection_input_error(conn,
1161 imapc_connection_starttls(conn);
1165 static int imapc_connection_input_banner(struct imapc_connection *conn)
1172 if ((ret = imapc_connection_read_line(conn, &imap_args)) <= 0)
1178 if (imapc_connection_handle_imap_resp_text(conn, imap_args,
1181 imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_AUTHENTICATING);
1183 if (conn->capabilities == 0) {
1185 cmd = imapc_connection_cmd(conn, imapc_connection_capability_cb,
1186 conn);
1190 imapc_connection_starttls(conn);
1192 conn->input_callback = NULL;
1193 imapc_connection_input_reset(conn);
1197 static int imapc_connection_input_untagged(struct imapc_connection *conn)
1207 if (conn->state == IMAPC_CONNECTION_STATE_CONNECTING) {
1209 data = i_stream_get_data(conn->input, &size);
1213 imapc_connection_input_error(conn,
1218 conn->input_callback = imapc_connection_input_banner;
1222 if ((ret = imapc_connection_read_line(conn, &imap_args)) == 0)
1225 imapc_connection_input_reset(conn);
1229 imapc_connection_input_error(conn, "Invalid untagged reply");
1234 if (conn->input_state == IMAPC_INPUT_STATE_UNTAGGED &&
1235 str_to_uint32(name, &conn->cur_num) == 0) {
1237 conn->input_state = IMAPC_INPUT_STATE_UNTAGGED_NUM;
1239 imapc_connection_input_error(conn,
1248 if (imapc_connection_handle_imap_resp_text(conn, imap_args,
1254 if (imapc_connection_parse_capability(conn, value) < 0)
1257 i_free(conn->disconnect_reason);
1258 conn->disconnect_reason = i_strdup(imap_args_to_str(imap_args));
1262 reply.num = conn->cur_num;
1264 reply.file_args = array_get(&conn->literal_files,
1267 if (conn->selected_box != NULL) {
1269 conn->selected_box->untagged_box_context;
1273 parser = conn->parser;
1275 conn->client->untagged_callback(&reply, conn->client->untagged_context);
1277 imapc_connection_input_reset(conn);
1281 static int imapc_connection_input_plus(struct imapc_connection *conn)
1287 if ((line = i_stream_next_line(conn->input)) == NULL)
1290 cmds = array_get(&conn->cmd_send_queue, &cmds_count);
1291 if (conn->idle_plus_waiting) {
1293 conn->idle_plus_waiting = FALSE;
1294 conn->idling = TRUE;
1296 if (conn->to != NULL && !conn->idle_stopping)
1297 timeout_remove(&conn->to);
1301 imapc_command_send_more(conn);
1303 cmds = array_get(&conn->cmd_wait_list, &cmds_count);
1313 imapc_connection_input_error(conn, "Unexpected '+': %s", line);
1318 imapc_connection_input_reset(conn);
1323 imapc_connection_throttle_shrink_timeout(struct imapc_connection *conn)
1325 if (conn->throttle_msecs <= 1)
1326 conn->throttle_msecs = 0;
1328 conn->throttle_msecs = conn->throttle_msecs*3 / 4;
1330 if (conn->throttle_shrink_msecs <= conn->client->set.throttle_set.shrink_min_msecs)
1331 conn->throttle_shrink_msecs = 0;
1333 conn->throttle_shrink_msecs = conn->throttle_shrink_msecs*3 / 4;
1335 timeout_remove(&conn->to_throttle_shrink);
1336 if (conn->throttle_shrink_msecs > 0) {
1337 conn->to_throttle_shrink =
1338 timeout_add(conn->throttle_shrink_msecs,
1339 imapc_connection_throttle_shrink_timeout, conn);
1344 imapc_connection_throttle(struct imapc_connection *conn,
1347 timeout_remove(&conn->to_throttle);
1354 if (conn->throttle_msecs == 0)
1355 conn->throttle_msecs = conn->client->set.throttle_set.init_msecs;
1356 else if (conn->throttle_msecs < conn->last_successful_throttle_msecs)
1357 conn->throttle_msecs = conn->last_successful_throttle_msecs;
1359 conn->throttle_msecs *= 2;
1360 if (conn->throttle_msecs > conn->client->set.throttle_set.max_msecs)
1361 conn->throttle_msecs = conn->client->set.throttle_set.max_msecs;
1363 if (conn->throttle_shrink_msecs == 0)
1364 conn->throttle_shrink_msecs = conn->client->set.throttle_set.shrink_min_msecs;
1366 conn->throttle_shrink_msecs *= 2;
1367 if (conn->to_throttle_shrink != NULL)
1368 timeout_reset(conn->to_throttle_shrink);
1370 if (conn->throttle_shrink_msecs > 0 &&
1371 conn->to_throttle_shrink == NULL) {
1372 conn->to_throttle_shrink =
1373 timeout_add(conn->throttle_shrink_msecs,
1374 imapc_connection_throttle_shrink_timeout, conn);
1376 conn->last_successful_throttle_msecs = conn->throttle_msecs;
1379 if (conn->throttle_msecs > 0) {
1380 conn->throttle_end_timeval = ioloop_timeval;
1381 timeval_add_msecs(&conn->throttle_end_timeval,
1382 conn->throttle_msecs);
1383 conn->throttle_pending = TRUE;
1395 static int imapc_connection_input_tagged(struct imapc_connection *conn)
1403 line = i_stream_next_line(conn->input);
1426 imapc_connection_input_error(conn,
1428 conn->cur_tag, line, reply.text_full);
1434 if (imapc_connection_handle_resp_text(conn, reply.text_full,
1449 if (!conn->throttle_pending)
1450 imapc_connection_throttle(conn, &reply);
1454 cmds = array_get(&conn->cmd_send_queue, &count);
1455 if (count > 0 && cmds[0]->tag == conn->cur_tag) {
1457 array_delete(&conn->cmd_send_queue, 0, 1);
1459 cmds = array_get(&conn->cmd_wait_list, &count);
1461 if (cmds[i]->tag == conn->cur_tag) {
1463 array_delete(&conn->cmd_wait_list, i, 1);
1468 if (array_count(&conn->cmd_wait_list) == 0 &&
1469 array_count(&conn->cmd_send_queue) == 0 &&
1470 conn->state == IMAPC_CONNECTION_STATE_DONE && conn->to != NULL)
1471 timeout_remove(&conn->to);
1474 if (seq_range_exists(&conn->aborted_cmd_tags, conn->cur_tag)) {
1476 seq_range_array_remove(&conn->aborted_cmd_tags,
1477 conn->cur_tag);
1478 imapc_connection_input_reset(conn);
1481 imapc_connection_input_error(conn,
1483 conn->cur_tag, line, reply.text_full);
1487 conn->select_waiting_reply = FALSE;
1491 conn->name, imapc_command_get_readable(cmd),
1492 conn->cur_tag, reply.text_full);
1493 imapc_connection_disconnect(conn);
1498 conn->selected_box != NULL) {
1500 imapc_connection_unselect(conn->selected_box);
1503 if (conn->reconnect_command_count > 0 &&
1505 i_assert(conn->reconnect_command_count > 0);
1506 if (--conn->reconnect_command_count == 0) {
1511 if (conn->selected_box != NULL)
1512 conn->selected_box->reconnect_ok = TRUE;
1515 if (conn->reconnect_command_count == 0) {
1517 conn->reconnect_ok = TRUE;
1519 imapc_connection_input_reset(conn);
1521 imapc_command_send_more(conn);
1525 static int imapc_connection_input_one(struct imapc_connection *conn)
1530 if (conn->input_callback != NULL)
1531 return conn->input_callback(conn);
1533 switch (conn->input_state) {
1535 tag = imap_parser_read_word(conn->parser);
1540 conn->input_state = IMAPC_INPUT_STATE_UNTAGGED;
1541 conn->cur_num = 0;
1542 ret = imapc_connection_input_untagged(conn);
1544 conn->input_state = IMAPC_INPUT_STATE_PLUS;
1545 ret = imapc_connection_input_plus(conn);
1547 conn->input_state = IMAPC_INPUT_STATE_TAGGED;
1548 if (str_to_uint(tag, &conn->cur_tag) < 0 ||
1549 conn->cur_tag == 0) {
1550 imapc_connection_input_error(conn,
1554 ret = imapc_connection_input_tagged(conn);
1559 ret = imapc_connection_input_plus(conn);
1563 ret = imapc_connection_input_untagged(conn);
1566 ret = imapc_connection_input_tagged(conn);
1572 static void imapc_connection_input(struct imapc_connection *conn)
1580 imapc_connection_ref(conn);
1581 while (conn->input != NULL && (ret = i_stream_read(conn->input)) > 0)
1582 imapc_connection_input_pending(conn);
1584 if (ret < 0 && conn->client->logging_out &&
1585 conn->disconnect_reason != NULL) {
1590 if (conn->disconnect_reason != NULL) {
1592 conn->disconnect_reason);
1596 i_stream_get_data_size(conn->input));
1597 } else if (conn->ssl_iostream == NULL) {
1598 errstr = conn->input->stream_errno == 0 ? "EOF" :
1599 i_stream_get_error(conn->input);
1603 errstr = ssl_iostream_get_last_error(conn->ssl_iostream);
1605 errstr = conn->input->stream_errno == 0 ? "EOF" :
1606 i_stream_get_error(conn->input);
1611 imapc_connection_try_reconnect(conn, str_c(str), 0, FALSE);
1613 imapc_connection_unref(&conn);
1618 struct imapc_connection *conn = context;
1621 if (ssl_iostream_check_cert_validity(conn->ssl_iostream,
1622 conn->client->set.host, &error) == 0) {
1623 if (conn->client->set.debug) {
1625 conn->name);
1628 } else if (!conn->client->set.ssl_verify) {
1629 if (conn->client->set.debug) {
1632 conn->name, error);
1641 static int imapc_connection_ssl_init(struct imapc_connection *conn)
1646 if (conn->client->ssl_ctx == NULL) {
1647 i_error("imapc(%s): No SSL context", conn->name);
1652 if (conn->client->set.ssl_verify) {
1658 if (conn->client->set.debug)
1659 i_debug("imapc(%s): Starting SSL handshake", conn->name);
1661 if (conn->raw_input != conn->input) {
1663 i_stream_ref(conn->raw_input);
1664 o_stream_ref(conn->raw_output);
1665 i_stream_destroy(&conn->input);
1666 o_stream_destroy(&conn->output);
1667 conn->input = conn->raw_input;
1668 conn->output = conn->raw_output;
1671 io_remove(&conn->io);
1672 if (io_stream_create_ssl_client(conn->client->ssl_ctx,
1673 conn->client->set.host,
1674 &ssl_set, &conn->input, &conn->output,
1675 &conn->ssl_iostream, &error) < 0) {
1677 conn->name, error);
1680 conn->io = io_add_istream(conn->input, imapc_connection_input, conn);
1681 ssl_iostream_set_handshake_callback(conn->ssl_iostream,
1683 conn);
1684 if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
1685 i_error("imapc(%s): SSL handshake failed: %s", conn->name,
1686 ssl_iostream_get_last_error(conn->ssl_iostream));
1690 if (*conn->client->set.rawlog_dir != '\0') {
1691 iostream_rawlog_create(conn->client->set.rawlog_dir,
1692 &conn->input, &conn->output);
1695 imap_parser_set_streams(conn->parser, conn->input, NULL);
1699 static void imapc_connection_connected(struct imapc_connection *conn)
1701 const struct ip_addr *ip = &conn->ips[conn->prev_connect_idx];
1705 io_remove(&conn->io);
1707 err = net_geterror(conn->fd);
1709 imapc_connection_try_reconnect(conn, t_strdup_printf(
1711 net_ip2addr(ip), conn->client->set.port,
1712 strerror(err)), conn->client->set.connect_retry_interval_msecs, TRUE);
1715 if (net_getsockname(conn->fd, &local_ip, &local_port) < 0)
1717 i_info("imapc(%s): Connected to %s:%u (local %s:%u)", conn->name,
1718 net_ip2addr(ip), conn->client->set.port,
1720 conn->io = io_add(conn->fd, IO_READ, imapc_connection_input, conn);
1722 if (conn->client->set.ssl_mode == IMAPC_CLIENT_SSL_MODE_IMMEDIATE) {
1723 if (imapc_connection_ssl_init(conn) < 0)
1724 imapc_connection_disconnect(conn);
1728 static void imapc_connection_timeout(struct imapc_connection *conn)
1730 const struct ip_addr *ip = &conn->ips[conn->prev_connect_idx];
1734 switch (conn->state) {
1737 net_ip2addr(ip), conn->client->set.port,
1738 conn->client->set.connect_timeout_msecs/1000);
1743 conn->client->set.connect_timeout_msecs/1000);
1748 imapc_connection_try_reconnect(conn, errstr, 0, connect_error);
1761 struct imapc_connection *conn = context;
1763 imapc_connection_idle(conn);
1766 static void imapc_connection_reset_idle(struct imapc_connection *conn)
1770 if (conn->idling)
1771 cmd = imapc_connection_cmd(conn, imapc_reidle_callback, conn);
1772 else if (array_count(&conn->cmd_wait_list) == 0)
1773 cmd = imapc_connection_cmd(conn, imapc_noop_callback, NULL);
1781 static void imapc_connection_connect_next_ip(struct imapc_connection *conn)
1787 i_assert(conn->client->set.max_idle_time > 0);
1789 for (i = 0; i<conn->ips_count;) {
1790 conn->prev_connect_idx = (conn->prev_connect_idx+1) % conn->ips_count;
1791 ip = &conn->ips[conn->prev_connect_idx];
1792 fd = net_connect_ip(ip, conn->client->set.port, NULL);
1800 net_ip2addr(ip), conn->client->set.port);
1801 if (conn->prev_connect_idx+1 == conn->ips_count) {
1802 imapc_connection_try_reconnect(conn, "No more IP address(es) to try",
1803 conn->client->set.connect_retry_interval_msecs, TRUE);
1810 conn->fd = fd;
1811 conn->input = conn->raw_input =
1812 i_stream_create_fd(fd, conn->client->set.max_line_length);
1813 conn->output = conn->raw_output = o_stream_create_fd(fd, (size_t)-1);
1814 o_stream_set_no_error_handling(conn->output, TRUE);
1816 if (*conn->client->set.rawlog_dir != '\0' &&
1817 conn->client->set.ssl_mode != IMAPC_CLIENT_SSL_MODE_IMMEDIATE) {
1818 iostream_rawlog_create(conn->client->set.rawlog_dir,
1819 &conn->input, &conn->output);
1822 o_stream_set_flush_callback(conn->output, imapc_connection_output,
1823 conn);
1824 conn->io = io_add(fd, IO_WRITE, imapc_connection_connected, conn);
1825 conn->parser = imap_parser_create(conn->input, NULL,
1826 conn->client->set.max_line_length);
1827 conn->to = timeout_add(conn->client->set.connect_timeout_msecs,
1828 imapc_connection_timeout, conn);
1829 conn->to_output = timeout_add(conn->client->set.max_idle_time*1000,
1830 imapc_connection_reset_idle, conn);
1831 if (conn->client->set.debug) {
1832 i_debug("imapc(%s): Connecting to %s:%u", conn->name,
1833 net_ip2addr(ip), conn->client->set.port);
1839 struct imapc_connection *conn)
1841 conn->dns_lookup = NULL;
1845 conn->name, conn->client->set.host, result->error);
1846 imapc_connection_set_disconnected(conn);
1851 conn->ips_count = result->ips_count;
1852 conn->ips = i_new(struct ip_addr, conn->ips_count);
1853 memcpy(conn->ips, result->ips, sizeof(*conn->ips) * conn->ips_count);
1854 conn->prev_connect_idx = conn->ips_count - 1;
1856 imapc_connection_connect_next_ip(conn);
1859 void imapc_connection_connect(struct imapc_connection *conn)
1866 if (conn->fd != -1 || conn->dns_lookup != NULL)
1868 if (conn->reconnect_waiting) {
1874 conn->reconnecting = FALSE;
1877 conn->reconnect_command_count = array_count(&conn->cmd_wait_list) +
1878 array_count(&conn->cmd_send_queue);
1880 imapc_connection_input_reset(conn);
1881 conn->last_connect = ioloop_timeval;
1883 if (conn->client->set.debug) {
1885 "(reconnect_ok=%s, last_connect=%ld)", conn->name,
1886 (conn->reconnect_ok ? "true" : "false"),
1887 (long)conn->last_connect.tv_sec);
1892 conn->client->set.dns_client_socket_path;
1893 dns_set.timeout_msecs = conn->client->set.connect_timeout_msecs;
1895 imapc_connection_set_state(conn, IMAPC_CONNECTION_STATE_CONNECTING);
1896 if (conn->ips_count > 0) {
1898 } else if (net_addr2ip(conn->client->set.host, &ip) == 0) {
1899 conn->ips_count = 1;
1900 conn->ips = i_new(struct ip_addr, conn->ips_count);
1901 conn->ips[0] = ip;
1903 ret = net_gethostbyname(conn->client->set.host,
1907 conn->name, conn->client->set.host,
1909 imapc_connection_set_disconnected(conn);
1912 conn->ips_count = ips_count;
1913 conn->ips = i_new(struct ip_addr, ips_count);
1914 memcpy(conn->ips, ips, ips_count * sizeof(*ips));
1916 (void)dns_lookup(conn->client->set.host, &dns_set,
1917 imapc_connection_dns_callback, conn,
1918 &conn->dns_lookup);
1921 imapc_connection_connect_next_ip(conn);
1924 void imapc_connection_input_pending(struct imapc_connection *conn)
1928 if (conn->input == NULL)
1931 if (conn->to != NULL && !conn->idle_stopping)
1932 timeout_reset(conn->to);
1934 o_stream_cork(conn->output);
1935 while (ret > 0 && conn->input != NULL) {
1937 ret = imapc_connection_input_one(conn);
1941 if (conn->output != NULL)
1942 o_stream_uncork(conn->output);
1991 static void imapc_command_timeout(struct imapc_connection *conn)
1996 cmds = array_get(&conn->cmd_wait_list, &count);
1999 imapc_connection_try_reconnect(conn, t_strdup_printf(
2028 static void imapc_command_send_finished(struct imapc_connection *conn,
2034 conn->idle_plus_waiting = TRUE;
2038 cmdp = array_idx(&conn->cmd_send_queue, 0);
2040 array_delete(&conn->cmd_send_queue, 0, 1);
2041 array_append(&conn->cmd_wait_list, &cmd, 1);
2044 imapc_command_send_more(conn);
2061 static int imapc_command_try_send_stream(struct imapc_connection *conn,
2072 o_stream_set_max_buffer_size(conn->output, 0);
2073 res = o_stream_send_istream(conn->output, stream->input);
2074 o_stream_set_max_buffer_size(conn->output, (size_t)-1);
2105 struct imapc_connection *conn = box->conn;
2107 i_assert(conn->selecting_box == NULL);
2109 if (conn->selected_box != NULL &&
2110 (conn->capabilities & IMAPC_CAPABILITY_QRESYNC) != 0) {
2113 conn->selecting_box = box;
2117 conn->selected_box = box;
2119 conn->select_waiting_reply = TRUE;
2122 static bool imapc_connection_is_throttled(struct imapc_connection *conn)
2124 timeout_remove(&conn->to_throttle);
2126 if (conn->throttle_msecs == 0) {
2130 if (array_count(&conn->cmd_wait_list) > 0) {
2135 if (timeval_cmp(&ioloop_timeval, &conn->throttle_end_timeval) >= 0) {
2137 conn->throttle_pending = FALSE;
2142 conn->to_throttle = timeout_add_absolute(&conn->throttle_end_timeval,
2143 imapc_command_send_more, conn);
2147 static void imapc_command_send_more(struct imapc_connection *conn)
2156 if (imapc_connection_is_throttled(conn))
2159 cmds = array_get(&conn->cmd_send_queue, &count);
2165 conn->state != IMAPC_CONNECTION_STATE_DONE) {
2170 array_count(&conn->cmd_wait_list) > 0) {
2174 if (conn->select_waiting_reply) {
2201 array_delete(&conn->cmd_send_queue, 0, 1);
2203 imapc_command_send_more(conn);
2211 timeout_remove(&conn->to);
2212 conn->to = timeout_add(IMAPC_LOGOUT_TIMEOUT_MSECS,
2213 imapc_command_timeout, conn);
2214 } else if (conn->to == NULL) {
2215 conn->to = timeout_add(conn->client->set.cmd_timeout_msecs,
2216 imapc_command_timeout, conn);
2219 timeout_reset(conn->to_output);
2220 if ((ret = imapc_command_try_send_stream(conn, cmd)) == 0)
2227 array_delete(&conn->cmd_send_queue, 0, 1);
2229 imapc_command_send_more(conn);
2257 o_stream_nsend(conn->output, data, size);
2263 imapc_command_send_finished(conn, cmd);
2269 static void imapc_connection_send_idle_done(struct imapc_connection *conn)
2271 if ((conn->idling || conn->idle_plus_waiting) && !conn->idle_stopping) {
2272 conn->idle_stopping = TRUE;
2273 o_stream_nsend_str(conn->output, "DONE\r\n");
2274 if (conn->to == NULL) {
2275 conn->to = timeout_add(conn->client->set.cmd_timeout_msecs,
2276 imapc_command_timeout, conn);
2283 struct imapc_connection *conn = cmd->conn;
2287 imapc_connection_send_idle_done(conn);
2292 conn->state == IMAPC_CONNECTION_STATE_AUTHENTICATING) {
2294 array_insert(&conn->cmd_send_queue, 0, &cmd, 1);
2295 imapc_command_send_more(conn);
2300 cmds = array_get(&conn->cmd_send_queue, &count);
2305 array_insert(&conn->cmd_send_queue, i, &cmd, 1);
2306 imapc_command_send_more(conn);
2309 static int imapc_connection_output(struct imapc_connection *conn)
2315 if (conn->to != NULL)
2316 timeout_reset(conn->to);
2318 if ((ret = o_stream_flush(conn->output)) < 0)
2321 imapc_connection_ref(conn);
2322 cmds = array_get(&conn->cmd_send_queue, &count);
2327 imapc_command_send_more(conn);
2330 imapc_connection_unref(&conn);
2335 imapc_connection_cmd(struct imapc_connection *conn,
2341 cmd->conn = conn;
2359 return cmd->conn->selected_box != NULL ||
2360 cmd->conn->selecting_box != NULL;
2426 else if ((cmd->conn->capabilities &
2453 imapc_connection_get_state(struct imapc_connection *conn)
2455 return conn->state;
2459 imapc_connection_get_capabilities(struct imapc_connection *conn)
2461 return conn->capabilities;
2466 struct imapc_connection *conn = box->conn;
2468 if (conn->selected_box != NULL || conn->selecting_box != NULL) {
2469 i_assert(conn->selected_box == box ||
2470 conn->selecting_box == box);
2472 conn->selected_box = NULL;
2473 conn->selecting_box = NULL;
2475 imapc_connection_send_idle_done(conn);
2476 imapc_connection_abort_commands(conn, box, FALSE);
2480 imapc_connection_get_mailbox(struct imapc_connection *conn)
2482 if (conn->selecting_box != NULL)
2483 return conn->selecting_box;
2484 return conn->selected_box;
2491 struct imapc_connection *conn = context;
2493 conn->idling = FALSE;
2494 conn->idle_plus_waiting = FALSE;
2495 conn->idle_stopping = FALSE;
2498 void imapc_connection_idle(struct imapc_connection *conn)
2502 if (array_count(&conn->cmd_send_queue) != 0 ||
2503 array_count(&conn->cmd_wait_list) != 0 ||
2504 conn->idling || conn->idle_plus_waiting ||
2505 (conn->capabilities & IMAPC_CAPABILITY_IDLE) == 0)
2508 cmd = imapc_connection_cmd(conn, imapc_connection_idle_callback, conn);