bool client_handle_input(struct client *client) { bool ret, remove_io, handled_commands = FALSE; i_assert(!client->disconnected); client->handling_input = TRUE; do { T_BEGIN { ret = client_handle_next_command(client, &remove_io); } T_END; if (ret) handled_commands = TRUE; } while (ret && !client->disconnected && client->io != NULL); client->handling_input = FALSE; if (remove_io) io_remove(&client->io); else client_add_missing_io(client); if (!handled_commands) return FALSE; if (client->input_lock == NULL) cmd_sync_delayed(client); return TRUE; }
int client_output(struct client *client) { int ret; i_assert(!client->destroyed); client->last_output = ioloop_time; timeout_reset(client->to_idle); if (client->to_idle_output != NULL) timeout_reset(client->to_idle_output); o_stream_cork(client->output); if ((ret = o_stream_flush(client->output)) < 0) { client_destroy(client, NULL); return 1; } client_output_commands(client); (void)cmd_sync_delayed(client); o_stream_uncork(client->output); imap_refresh_proctitle(); if (client->disconnected) client_destroy(client, NULL); else client_continue_pending_input(client); return ret; }
void client_continue_pending_input(struct client *client) { i_assert(!client->handling_input); if (client->input_lock != NULL) { /* there's a command that has locked the input */ struct client_command_context *cmd = client->input_lock; if (cmd->state != CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY) return; /* the command is waiting for existing ambiguity causing commands to finish. */ if (client_command_is_ambiguous(cmd)) { /* we could be waiting for existing sync to finish */ if (!cmd_sync_delayed(client)) return; if (client_command_is_ambiguous(cmd)) return; } cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT; } client_add_missing_io(client); /* if there's unread data in buffer, handle it. */ if (i_stream_get_data_size(client->input) > 0 && !client->disconnected) { if (client_handle_input(client)) client_continue_pending_input(client); } }
static void client_input_append(struct client_command_context *cmd) { struct cmd_append_context *ctx = cmd->context; struct client *client = cmd->client; const char *reason; bool finished; uoff_t lit_offset; i_assert(!client->destroyed); client->last_input = ioloop_time; timeout_reset(client->to_idle); switch (i_stream_read(client->input)) { case -1: /* disconnected */ lit_offset = ctx->litinput == NULL ? 0 : ctx->litinput->v_offset; reason = get_disconnect_reason(ctx, lit_offset); cmd_append_finish(cmd->context); /* Reset command so that client_destroy() doesn't try to call cmd_append_continue_message() anymore. */ client_command_free(&cmd); client_destroy(client, reason); return; case -2: if (ctx->message_input) { /* message data, this is handled internally by mailbox_save_continue() */ break; } cmd_append_finish(cmd->context); /* parameter word is longer than max. input buffer size. this is most likely an error, so skip the new data until newline is found. */ client->input_skip_line = TRUE; if (!ctx->failed) client_send_command_error(cmd, "Too long argument."); cmd->param_error = TRUE; client_command_free(&cmd); return; } o_stream_cork(client->output); finished = command_exec(cmd); if (!finished) (void)client_handle_unfinished_cmd(cmd); else client_command_free(&cmd); cmd_sync_delayed(client); o_stream_uncork(client->output); if (client->disconnected) client_destroy(client, NULL); else client_continue_pending_input(client); }