void login_proxy_detach(struct login_proxy *proxy) { struct client *client = proxy->client; const unsigned char *data; size_t size; i_assert(proxy->client_fd == -1); i_assert(proxy->server_input != NULL); i_assert(proxy->server_output != NULL); if (proxy->to != NULL) timeout_remove(&proxy->to); proxy->client_fd = i_stream_get_fd(client->input); proxy->client_input = client->input; proxy->client_output = client->output; i_stream_set_persistent_buffers(client->input, FALSE); o_stream_set_max_buffer_size(client->output, (size_t)-1); o_stream_set_flush_callback(client->output, proxy_client_output, proxy); client->input = NULL; client->output = NULL; /* send all pending client input to proxy */ data = i_stream_get_data(proxy->client_input, &size); if (size != 0) o_stream_nsend(proxy->server_output, data, size); /* from now on, just do dummy proxying */ io_remove(&proxy->server_io); proxy->server_io = io_add(proxy->server_fd, IO_READ, server_input, proxy); proxy->client_io = io_add_istream(proxy->client_input, proxy_client_input, proxy); o_stream_set_flush_callback(proxy->server_output, server_output, proxy); i_stream_destroy(&proxy->server_input); if (proxy->notify_refresh_secs != 0) { proxy->to_notify = timeout_add(proxy->notify_refresh_secs * 1000, login_proxy_notify, proxy); } proxy->callback = NULL; if (login_proxy_ipc_server == NULL) { login_proxy_ipc_server = ipc_server_init(LOGIN_PROXY_IPC_PATH, LOGIN_PROXY_IPC_NAME, login_proxy_ipc_cmd); } DLLIST_REMOVE(&login_proxies_pending, proxy); DLLIST_PREPEND(&login_proxies, proxy); client->fd = -1; client->login_proxy = NULL; }
int script_client_run(struct script_client *sclient) { int ret; sclient->ioloop = io_loop_create(); if ( script_client_connect(sclient) >= 0 ) { /* run output */ ret = 1; if ( sclient->script_output != NULL && (ret=o_stream_flush(sclient->script_output)) == 0 ) { o_stream_set_flush_callback (sclient->script_output, script_client_script_output, sclient); } /* run i/o event loop */ if ( ret < 0 ) { sclient->error = SCRIPT_CLIENT_ERROR_IO; } else if ( sclient->io != NULL || ret == 0 ) { io_loop_run(sclient->ioloop); } /* finished */ script_client_disconnect(sclient, FALSE); } io_loop_destroy(&sclient->ioloop); if ( sclient->error != SCRIPT_CLIENT_ERROR_NONE ) return -1; return sclient->exit_code; }
static bool auth_worker_handle_list(struct auth_worker_client *client, unsigned int id, const char *const *args) { struct auth_worker_list_context *ctx; struct auth_userdb *userdb; unsigned int userdb_id; if (str_to_uint(args[0], &userdb_id) < 0) { i_error("BUG: Auth worker server sent us invalid LIST"); return FALSE; } userdb = auth_userdb_find_by_id(client->auth->userdbs, userdb_id); if (userdb == NULL) { i_error("BUG: LIST had invalid userdb ID"); return FALSE; } ctx = i_new(struct auth_worker_list_context, 1); ctx->client = client; ctx->id = id; ctx->userdb = userdb->userdb; io_remove(&ctx->client->io); o_stream_set_flush_callback(ctx->client->output, auth_worker_list_output, ctx); client->refcount++; ctx->iter = ctx->userdb->iface-> iterate_init(userdb->userdb, list_iter_callback, ctx); ctx->userdb->iface->iterate_next(ctx->iter); return TRUE; }
static void cmd_append_finish(struct cmd_append_context *ctx) { if (ctx->save_parser != NULL) imap_parser_unref(&ctx->save_parser); i_assert(ctx->client->input_lock == ctx->cmd); if (ctx->client->io != NULL) io_remove(&ctx->client->io); /* we must put back the original flush callback before beginning to sync (the command is still unfinished at that point) */ o_stream_set_flush_callback(ctx->client->output, client_output, ctx->client); if (ctx->litinput != NULL) i_stream_unref(&ctx->litinput); if (ctx->input != NULL) i_stream_unref(&ctx->input); if (ctx->save_ctx != NULL) mailbox_save_cancel(&ctx->save_ctx); if (ctx->t != NULL) mailbox_transaction_rollback(&ctx->t); if (ctx->box != ctx->cmd->client->mailbox && ctx->box != NULL) mailbox_free(&ctx->box); }
struct ostream *openssl_o_stream_create_ssl(struct ssl_iostream *ssl_io) { struct ssl_ostream *sstream; ssl_io->refcount++; sstream = i_new(struct ssl_ostream, 1); sstream->ssl_io = ssl_io; sstream->ostream.max_buffer_size = ssl_io->plain_output->real_stream->max_buffer_size; sstream->ostream.iostream.close = o_stream_ssl_close; sstream->ostream.iostream.destroy = o_stream_ssl_destroy; sstream->ostream.sendv = o_stream_ssl_sendv; sstream->ostream.flush = o_stream_ssl_flush; sstream->ostream.switch_ioloop = o_stream_ssl_switch_ioloop; sstream->ostream.flush_pending = o_stream_ssl_flush_pending; sstream->ostream.iostream.set_max_buffer_size = o_stream_ssl_set_max_buffer_size; sstream->ostream.callback = ssl_io->plain_output->real_stream->callback; sstream->ostream.context = ssl_io->plain_output->real_stream->context; o_stream_set_flush_callback(ssl_io->plain_output, plain_flush_callback, sstream); return o_stream_create(&sstream->ostream, NULL, o_stream_get_fd(ssl_io->plain_output)); }
void client_cmd_starttls(struct client *client) { if (client->tls) { client->v.notify_starttls(client, FALSE, "TLS is already active."); return; } if (!client_is_tls_enabled(client)) { client->v.notify_starttls(client, FALSE, "TLS support isn't enabled."); return; } /* remove input handler, SSL proxy gives us a new fd. we also have to remove it in case we have to wait for buffer to be flushed */ if (client->io != NULL) io_remove(&client->io); client->v.notify_starttls(client, TRUE, "Begin TLS negotiation now."); /* uncork the old fd */ o_stream_uncork(client->output); if (o_stream_flush(client->output) <= 0) { /* the buffer has to be flushed */ o_stream_set_flush_pending(client->output, TRUE); o_stream_set_flush_callback(client->output, client_output_starttls, client); } else { client_start_tls(client); } }
static int lmtp_client_connect(struct lmtp_client *client) { i_assert(client->fd == -1); client->times.connect_started = ioloop_timeval; client->fd = net_connect_ip(&client->ip, client->port, NULL); if (client->fd == -1) { i_error("lmtp client: connect(%s, %u) failed: %m", client->host, client->port); return -1; } client->input = i_stream_create_fd(client->fd, LMTP_MAX_LINE_LEN); client->output = o_stream_create_fd(client->fd, (size_t)-1); o_stream_set_no_error_handling(client->output, TRUE); o_stream_set_flush_callback(client->output, lmtp_client_output, client); /* we're already sending data in ostream, so can't use IO_WRITE here */ client->io = io_add(client->fd, IO_READ, lmtp_client_wait_connect, client); if (client->set.timeout_secs > 0) { client->to = timeout_add(client->set.timeout_secs*1000, lmtp_client_connect_timeout, client); } return 0; }
static void o_stream_default_set_flush_callback(struct ostream_private *_stream, stream_flush_callback_t *callback, void *context) { if (_stream->parent != NULL) o_stream_set_flush_callback(_stream->parent, callback, context); _stream->callback = callback; _stream->context = context; }
static void cmd_setmetadata_deinit(struct imap_setmetadata_context *ctx) { o_stream_set_flush_callback(ctx->cmd->client->output, client_output, ctx->cmd->client); ctx->cmd->client->input_lock = NULL; imap_parser_unref(&ctx->parser); if (ctx->trans != NULL) imap_metadata_transaction_rollback(&ctx->trans); if (ctx->box != NULL && ctx->box != ctx->cmd->client->mailbox) mailbox_free(&ctx->box); i_free(ctx->entry_name); }
static void cmd_putscript_finish(struct cmd_putscript_context *ctx) { managesieve_parser_destroy(&ctx->save_parser); io_remove(&ctx->client->io); o_stream_set_flush_callback(ctx->client->output, client_output, ctx->client); if (ctx->save_ctx != NULL) { ctx->client->input_skip_line = TRUE; sieve_storage_save_cancel(&ctx->save_ctx); } }
static void client_handle(int fd) { struct ostream *output; output = o_stream_create_fd(fd, (size_t)-1, TRUE); o_stream_send(output, ssl_params->data, ssl_params->used); if (o_stream_get_buffer_used_size(output) == 0) client_deinit(output); else { o_stream_set_flush_callback(output, client_output_flush, output); } }
struct client *client_create(int fd) { struct client *client; client = i_new(struct client, 1); client->fd = fd; client->io = io_add(fd, IO_READ, client_input, client); client->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); client->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(client->output, TRUE); o_stream_set_flush_callback(client->output, client_output, client); client->cmd_pool = pool_alloconly_create("cmd pool", 1024); DLLIST_PREPEND(&clients, client); return client; }
static struct client * client_create_standalone(const char *access_user, const char *const *access_applications, int fd_in, int fd_out, bool debug) { 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); i_array_init(&client->access_apps, 16); client->fd_in = fd_in; client->fd_out = fd_out; client->fd_ctrl = -1; if (access_user != NULL && *access_user != '\0') client->access_user = i_strdup(access_user); else { client->access_user = i_strdup("anonymous"); client->access_anonymous = TRUE; } if (access_applications != NULL) { const char *const *apps = access_applications; for (; *apps != NULL; apps++) { char *app = i_strdup(*apps); array_append(&client->access_apps, &app, 1); } } client->debug = debug; client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE); client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE); client->io = io_add(fd_in, IO_READ, client_input, client); client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS, client_idle_timeout, client); o_stream_set_flush_callback(client->output, client_output, client); imap_urlauth_worker_client_count++; DLLIST_PREPEND(&imap_urlauth_worker_clients, client); i_set_failure_prefix("imap-urlauth[%s](%s): ", my_pid, client->access_user); return client; }
static int lmtp_client_connect(struct lmtp_client *client) { client->fd = net_connect_ip(&client->ip, client->port, NULL); if (client->fd == -1) { i_error("lmtp client: connect(%s, %u) failed: %m", client->host, client->port); return -1; } client->input = i_stream_create_fd(client->fd, LMTP_MAX_LINE_LEN, FALSE); client->output = o_stream_create_fd(client->fd, (size_t)-1, FALSE); o_stream_set_flush_callback(client->output, lmtp_client_output, client); /* we're already sending data in ostream, so can't use IO_WRITE here */ client->io = io_add(client->fd, IO_READ, lmtp_client_wait_connect, client); return 0; }
static void replicator_connection_connect(struct replicator_connection *conn) { unsigned int n; int fd = -1; if (conn->fd != -1) return; if (conn->port == 0) { fd = net_connect_unix(conn->path); if (fd == -1) i_error("net_connect_unix(%s) failed: %m", conn->path); } else { for (n = 0; n < conn->ips_count; n++) { unsigned int idx = conn->ip_idx; conn->ip_idx = (conn->ip_idx + 1) % conn->ips_count; fd = net_connect_ip(&conn->ips[idx], conn->port, NULL); if (fd != -1) break; i_error("connect(%s, %u) failed: %m", net_ip2addr(&conn->ips[idx]), conn->port); } } if (fd == -1) { if (conn->to == NULL) { conn->to = timeout_add(REPLICATOR_RECONNECT_MSECS, replicator_connection_connect, conn); } return; } if (conn->to != NULL) timeout_remove(&conn->to); conn->fd = fd; conn->io = io_add(fd, IO_READ, replicator_input, conn); conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE); conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_no_error_handling(conn->output, TRUE); o_stream_nsend_str(conn->output, REPLICATOR_HANDSHAKE); o_stream_set_flush_callback(conn->output, replicator_output, conn); }
struct auth_worker_client * auth_worker_client_create(struct auth *auth, int fd) { struct auth_worker_client *client; client = i_new(struct auth_worker_client, 1); client->refcount = 1; client->auth = auth; client->fd = fd; client->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH, FALSE); client->output = o_stream_create_fd(fd, (size_t)-1, FALSE); o_stream_set_flush_callback(client->output, auth_worker_output, client); client->io = io_add(fd, IO_READ, auth_worker_input, client); auth_worker_client = client; return client; }
void auth_client_connection_create(struct auth *auth, int fd, bool login_requests, bool token_auth) { static unsigned int connect_uid_counter = 0; struct auth_client_connection *conn; const char *mechanisms; string_t *str; conn = i_new(struct auth_client_connection, 1); conn->auth = auth; conn->refcount = 1; conn->connect_uid = ++connect_uid_counter; conn->login_requests = login_requests; conn->token_auth = token_auth; random_fill(conn->cookie, sizeof(conn->cookie)); conn->fd = fd; conn->input = i_stream_create_fd(fd, AUTH_CLIENT_MAX_LINE_LENGTH); conn->output = o_stream_create_fd(fd, (size_t)-1); o_stream_set_no_error_handling(conn->output, TRUE); o_stream_set_flush_callback(conn->output, auth_client_output, conn); conn->io = io_add(fd, IO_READ, auth_client_input, conn); DLLIST_PREPEND(&auth_client_connections, conn); if (token_auth) { mechanisms = t_strconcat("MECH\t", mech_dovecot_token.mech_name, "\n", NULL); } else { mechanisms = str_c(auth->reg->handshake); } str = t_str_new(128); str_printfa(str, "VERSION\t%u\t%u\n%sSPID\t%s\nCUID\t%u\nCOOKIE\t", AUTH_CLIENT_PROTOCOL_MAJOR_VERSION, AUTH_CLIENT_PROTOCOL_MINOR_VERSION, mechanisms, my_pid, conn->connect_uid); binary_to_hex_append(str, conn->cookie, sizeof(conn->cookie)); str_append(str, "\nDONE\n"); if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0) auth_client_disconnected(&conn); }
static void list_iter_deinit(struct auth_worker_list_context *ctx) { struct auth_worker_client *client = ctx->client; string_t *str; i_assert(client->io == NULL); str = t_str_new(32); if (ctx->userdb->iface->iterate_deinit(ctx->iter) < 0) str_printfa(str, "%u\tFAIL\n", ctx->id); else str_printfa(str, "%u\tOK\n", ctx->id); auth_worker_send_reply(client, str); client->io = io_add(client->fd, IO_READ, auth_worker_input, client); o_stream_set_flush_callback(client->output, auth_worker_output, client); auth_worker_client_unref(&client); i_free(ctx); }
void iostream_pump_start(struct iostream_pump *pump) { i_assert(pump != NULL); i_assert(pump->callback != NULL); /* add flush handler */ if (!pump->output->blocking) { o_stream_set_flush_callback(pump->output, iostream_pump_flush, pump); } /* make IO objects */ if (pump->input->blocking) { i_assert(!pump->output->blocking); o_stream_set_flush_pending(pump->output, TRUE); } else { pump->io = io_add_istream(pump->input, iostream_pump_copy, pump); io_set_pending(pump->io); } }
int program_client_run(struct program_client *pclient) { int ret; /* reset */ pclient->disconnected = FALSE; pclient->exit_code = 1; pclient->error = PROGRAM_CLIENT_ERROR_NONE; pclient->ioloop = io_loop_create(); if ( (ret=program_client_connect(pclient)) >= 0 ) { /* run output */ if ( ret > 0 && pclient->program_output != NULL && (ret=o_stream_flush(pclient->program_output)) == 0 ) { o_stream_set_flush_callback (pclient->program_output, program_client_program_output, pclient); } /* run i/o event loop */ if ( ret < 0 ) { pclient->error = PROGRAM_CLIENT_ERROR_IO; } else if ( !pclient->disconnected && (ret == 0 || program_client_input_pending(pclient)) ) { io_loop_run(pclient->ioloop); } /* finished */ program_client_disconnect(pclient, FALSE); } io_loop_destroy(&pclient->ioloop); if ( pclient->error != PROGRAM_CLIENT_ERROR_NONE ) return -1; return pclient->exit_code; }
int server_connection_create(struct doveadm_server *server, struct server_connection **conn_r) { #define DOVEADM_SERVER_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n" struct server_connection *conn; pool_t pool; pool = pool_alloconly_create("doveadm server connection", 1024*16); conn = p_new(pool, struct server_connection, 1); conn->pool = pool; conn->server = server; conn->fd = doveadm_connect_with_default_port(server->name, doveadm_settings->doveadm_port); net_set_nonblock(conn->fd, TRUE); conn->io = io_add(conn->fd, IO_READ, server_connection_input, conn); conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE); conn->output = o_stream_create_fd(conn->fd, (size_t)-1); o_stream_set_flush_callback(conn->output, server_connection_output, conn); i_stream_set_name(conn->input, server->name); o_stream_set_name(conn->output, server->name); array_append(&conn->server->connections, &conn, 1); if (server_connection_read_settings(conn) < 0 || server_connection_init_ssl(conn) < 0) { server_connection_destroy(&conn); return -1; } o_stream_set_no_error_handling(conn->output, TRUE); conn->state = SERVER_REPLY_STATE_DONE; o_stream_nsend_str(conn->output, DOVEADM_SERVER_HANDSHAKE); *conn_r = conn; return 0; }
int program_client_connected (struct program_client *pclient) { int ret = 1; pclient->start_time = ioloop_time; if (pclient->to != NULL) timeout_remove(&pclient->to); if ( pclient->set.input_idle_timeout_secs != 0 ) { pclient->to = timeout_add(pclient->set.input_idle_timeout_secs*1000, program_client_timeout, pclient); } /* run output */ if ( pclient->program_output != NULL && (ret=program_client_program_output(pclient)) == 0 ) { if ( pclient->program_output != NULL ) { o_stream_set_flush_callback (pclient->program_output, program_client_program_output, pclient); } } return ret; }
int script_client_script_connected (struct script_client *sclient) { int ret = 1; sclient->start_time = ioloop_time; if (sclient->to != NULL) timeout_remove(&sclient->to); if ( sclient->set->input_idle_timeout_secs != 0 ) { sclient->to = timeout_add(sclient->set->input_idle_timeout_secs*1000, script_client_timeout, sclient); } /* run output */ if ( sclient->script_output != NULL && (ret=script_client_script_output(sclient)) == 0 ) { if ( sclient->script_output != NULL ) { o_stream_set_flush_callback (sclient->script_output, script_client_script_output, sclient); } } return ret; }
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_ctrl_input(struct client *client) { const char *const *args; const char *line; int ret; timeout_reset(client->to_idle); if (client->fd_in == -1 || client->fd_out == -1) { if ((ret = client_ctrl_read_fds(client)) <= 0) { if (ret < 0) client_abort(client, "FD Transfer failed"); return; } } switch (i_stream_read(client->ctrl_input)) { case -1: /* disconnected */ client_destroy(client); return; case -2: /* line too long, kill it */ client_abort(client, "Control session aborted: Input line too long"); return; } if (!client->version_received) { if ((line = i_stream_next_line(client->ctrl_input)) == NULL) return; if (!version_string_verify(line, "imap-urlauth-worker", IMAP_URLAUTH_WORKER_PROTOCOL_MAJOR_VERSION)) { i_error("imap-urlauth-worker client not compatible with this server " "(mixed old and new binaries?) %s", line); client_abort(client, "Control session aborted: Version mismatch"); return; } client->version_received = TRUE; if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) { client_destroy(client); return; } } if (client->access_received) { client_abort(client, "Control session aborted: Unexpected input"); return; } if ((line = i_stream_next_line(client->ctrl_input)) == NULL) return; args = t_strsplit_tabescaped(line); if (*args == NULL || strcmp(*args, "ACCESS") != 0) { i_error("Invalid control command: %s", str_sanitize(line, 80)); client_abort(client, "Control session aborted: Invalid command"); return; } args++; if (*args == NULL) { i_error("Invalid ACCESS command: %s", str_sanitize(line, 80)); client_abort(client, "Control session aborted: Invalid command"); return; } i_assert(client->access_user == NULL); if (**args != '\0') { client->access_user = i_strdup(*args); client->access_anonymous = FALSE; } else { client->access_user = i_strdup("anonymous"); client->access_anonymous = TRUE; } i_set_failure_prefix("imap-urlauth[%s](%s): ", my_pid, client->access_user); args++; while (*args != NULL) { /* debug */ if (strcasecmp(*args, "debug") == 0) { client->debug = TRUE; /* apps=<access-application>[,<access-application,...] */ } else if (strncasecmp(*args, "apps=", 5) == 0 && (*args)[5] != '\0') { const char *const *apps = t_strsplit(*args+5, ","); while (*apps != NULL) { char *app = i_strdup(*apps); array_append(&client->access_apps, &app, 1); if (client->debug) { i_debug("User %s has URLAUTH %s access", client->access_user, app); } apps++; } } else { i_error("Invalid ACCESS parameter: %s", str_sanitize(*args, 80)); client_abort(client, "Control session aborted: Invalid command"); return; } args++; } client->access_received = TRUE; if (o_stream_send_str(client->ctrl_output, "OK\n") < 0) { client_destroy(client); return; } client->input = i_stream_create_fd(client->fd_in, MAX_INBUF_SIZE, FALSE); client->output = o_stream_create_fd(client->fd_out, (size_t)-1, FALSE); client->io = io_add(client->fd_in, IO_READ, client_input, client); o_stream_set_flush_callback(client->output, client_output, client); if (client->debug) { i_debug("Worker activated for access by user %s", client->access_user); } }