void client_destroy(struct client *client, const char *prefix, const char *reason) { if (client->destroyed) return; client->destroyed = TRUE; client_disconnect(client, prefix, reason); submission_client_count--; DLLIST_REMOVE(&submission_clients, client); if (client->proxy_conn != NULL) smtp_client_connection_close(&client->proxy_conn); if (client->anvil_sent) { master_service_anvil_send(master_service, t_strconcat( "DISCONNECT\t", my_pid, "\tsubmission/", mail_user_get_anvil_userip_ident(client->user), "\n", NULL)); } if (client->urlauth_ctx != NULL) imap_urlauth_deinit(&client->urlauth_ctx); mail_user_unref(&client->user); mail_storage_service_user_unref(&client->service_user); client_state_reset(client); i_free(client->session_id); i_free(client); master_service_client_connection_destroyed(master_service); submission_refresh_proctitle(); }
struct client *client_create(int fd_in, int fd_out, const char *session_id, struct mail_user *user, struct mail_storage_service_user *service_user, const struct imap_settings *set) { const struct mail_storage_settings *mail_set; struct client *client; const char *ident; pool_t pool; bool explicit_capability = FALSE; /* always use nonblocking I/O */ net_set_nonblock(fd_in, TRUE); net_set_nonblock(fd_out, TRUE); pool = pool_alloconly_create("imap client", 2048); client = p_new(pool, struct client, 1); client->pool = pool; client->v = imap_client_vfuncs; client->set = set; client->service_user = service_user; client->session_id = p_strdup(pool, session_id); client->fd_in = fd_in; client->fd_out = fd_out; client->input = i_stream_create_fd(fd_in, set->imap_max_line_length, FALSE); client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE); o_stream_set_no_error_handling(client->output, TRUE); i_stream_set_name(client->input, "<imap client>"); o_stream_set_name(client->output, "<imap client>"); o_stream_set_flush_callback(client->output, client_output, client); p_array_init(&client->module_contexts, client->pool, 5); client->io = io_add_istream(client->input, client_input, client); client->last_input = ioloop_time; client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS, client_idle_timeout, client); client->command_pool = pool_alloconly_create(MEMPOOL_GROWING"client command", 1024*2); client->user = user; client->notify_count_changes = TRUE; client->notify_flag_changes = TRUE; mail_namespaces_set_storage_callbacks(user->namespaces, &mail_storage_callbacks, client); client->capability_string = str_new(client->pool, sizeof(CAPABILITY_STRING)+64); if (*set->imap_capability == '\0') str_append(client->capability_string, CAPABILITY_STRING); else if (*set->imap_capability != '+') { explicit_capability = TRUE; str_append(client->capability_string, set->imap_capability); } else { str_append(client->capability_string, CAPABILITY_STRING); str_append_c(client->capability_string, ' '); str_append(client->capability_string, set->imap_capability + 1); } if (user->fuzzy_search && !explicit_capability) { /* Enable FUZZY capability only when it actually has a chance of working */ str_append(client->capability_string, " SEARCH=FUZZY"); } mail_set = mail_user_set_get_storage_set(user); if (mail_set->mailbox_list_index && !explicit_capability) { /* NOTIFY is enabled only when mailbox list indexes are enabled, although even that doesn't necessarily guarantee it always */ str_append(client->capability_string, " NOTIFY"); } if (*set->imap_urlauth_host != '\0' && *mail_set->mail_attribute_dict != '\0') { /* Enable URLAUTH capability only when dict is configured correctly */ client_init_urlauth(client); if (!explicit_capability) str_append(client->capability_string, " URLAUTH URLAUTH=BINARY"); } if (set->imap_metadata && *mail_set->mail_attribute_dict != '\0') { client->imap_metadata_enabled = TRUE; if (!explicit_capability) str_append(client->capability_string, " METADATA"); } if (!explicit_capability && user_has_special_use_mailboxes(user)) { /* Advertise SPECIAL-USE only if there are actually some SPECIAL-USE flags in mailbox configuration. */ str_append(client->capability_string, " SPECIAL-USE"); } ident = mail_user_get_anvil_userip_ident(client->user); if (ident != NULL) { master_service_anvil_send(master_service, t_strconcat( "CONNECT\t", my_pid, "\timap/", ident, "\n", NULL)); client->anvil_sent = TRUE; } imap_client_count++; DLLIST_PREPEND(&imap_clients, client); if (hook_client_created != NULL) hook_client_created(&client); imap_refresh_proctitle(); return client; }
static void client_default_destroy(struct client *client, const char *reason) { struct client_command_context *cmd; const char *cmd_status = ""; i_assert(!client->destroyed); client->destroyed = TRUE; if (!client->disconnected) { client->disconnected = TRUE; if (reason == NULL) { reason = io_stream_get_disconnect_reason(client->input, client->output); cmd_status = client_get_commands_status(client); } i_info("%s%s %s", reason, cmd_status, client_stats(client)); } i_stream_close(client->input); o_stream_close(client->output); /* finish off all the queued commands. */ if (client->output_cmd_lock != NULL) client_command_cancel(&client->output_cmd_lock); while (client->command_queue != NULL) { cmd = client->command_queue; client_command_cancel(&cmd); } /* handle the input_lock command last. it might have been waiting on other queued commands (although we probably should just drop the command at that point since it hasn't started running. but this may change in future). */ if (client->input_lock != NULL) client_command_cancel(&client->input_lock); if (client->mailbox != NULL) { client_search_updates_free(client); mailbox_free(&client->mailbox); } if (client->notify_ctx != NULL) imap_notify_deinit(&client->notify_ctx); if (client->urlauth_ctx != NULL) imap_urlauth_deinit(&client->urlauth_ctx); if (client->anvil_sent) { master_service_anvil_send(master_service, t_strconcat( "DISCONNECT\t", my_pid, "\timap/", mail_user_get_anvil_userip_ident(client->user), "\n", NULL)); } mail_user_unref(&client->user); if (client->free_parser != NULL) imap_parser_unref(&client->free_parser); if (client->io != NULL) io_remove(&client->io); if (client->to_idle_output != NULL) timeout_remove(&client->to_idle_output); if (client->to_delayed_input != NULL) timeout_remove(&client->to_delayed_input); timeout_remove(&client->to_idle); i_stream_destroy(&client->input); o_stream_destroy(&client->output); net_disconnect(client->fd_in); if (client->fd_in != client->fd_out) net_disconnect(client->fd_out); if (array_is_created(&client->search_saved_uidset)) array_free(&client->search_saved_uidset); if (array_is_created(&client->search_updates)) array_free(&client->search_updates); pool_unref(&client->command_pool); mail_storage_service_user_free(&client->service_user); imap_client_count--; DLLIST_REMOVE(&imap_clients, client); pool_unref(&client->pool); master_service_client_connection_destroyed(master_service); imap_refresh_proctitle(); }
struct client *client_create(int fd_in, int fd_out, const char *session_id, struct mail_user *user, struct mail_storage_service_user *service_user, const struct submission_settings *set, const char *helo, const unsigned char *pdata, unsigned int pdata_len) { const struct mail_storage_settings *mail_set; struct smtp_server_settings smtp_set; const char *ident; struct client *client; /* always use nonblocking I/O */ net_set_nonblock(fd_in, TRUE); net_set_nonblock(fd_out, TRUE); client = i_new(struct client, 1); client->user = user; client->service_user = service_user; client->set = set; client->session_id = i_strdup(session_id); i_zero(&smtp_set); smtp_set.hostname = set->hostname; smtp_set.login_greeting = set->login_greeting; smtp_set.max_recipients = set->submission_max_recipients; smtp_set.max_client_idle_time_msecs = CLIENT_IDLE_TIMEOUT_MSECS; smtp_set.debug = user->mail_debug; client->conn = smtp_server_connection_create(smtp_server, fd_in, fd_out, user->conn.remote_ip, user->conn.remote_port, FALSE, &smtp_set, &smtp_callbacks, client); client_proxy_create(client, set); smtp_server_connection_login(client->conn, client->user->username, helo, pdata, pdata_len, user->conn.ssl_secured); smtp_server_connection_start_pending(client->conn); mail_set = mail_user_set_get_storage_set(user); if (*set->imap_urlauth_host != '\0' && *mail_set->mail_attribute_dict != '\0') { /* Enable BURL capability only when urlauth dict is configured correctly */ client_init_urlauth(client); } submission_client_count++; DLLIST_PREPEND(&submission_clients, client); ident = mail_user_get_anvil_userip_ident(client->user); if (ident != NULL) { master_service_anvil_send(master_service, t_strconcat( "CONNECT\t", my_pid, "\tsubmission/", ident, "\n", NULL)); client->anvil_sent = TRUE; } if (hook_client_created != NULL) hook_client_created(&client); submission_refresh_proctitle(); return client; }