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); }
static void proxy_input(struct client *client) { struct istream *input; struct ostream *output; const char *line; unsigned int duration; if (client->login_proxy == NULL) { /* we're just freeing the proxy */ return; } input = login_proxy_get_istream(client->login_proxy); if (input == NULL) { if (client->destroyed) { /* we came here from client_destroy() */ return; } /* failed for some reason, probably server disconnected */ client_proxy_failed(client, TRUE); return; } i_assert(!client->destroyed); switch (i_stream_read(input)) { case -2: client_log_err(client, "proxy: Remote input buffer full"); client_proxy_failed(client, TRUE); return; case -1: line = i_stream_next_line(input); duration = ioloop_time - client->created; client_log_err(client, t_strdup_printf( "proxy: Remote %s:%u disconnected: %s " "(state=%u, duration=%us)%s", login_proxy_get_host(client->login_proxy), login_proxy_get_port(client->login_proxy), get_disconnect_reason(input), client->proxy_state, duration, line == NULL ? "" : t_strdup_printf( " - BUG: line not read: %s", line))); client_proxy_failed(client, TRUE); return; } output = client->output; o_stream_ref(output); o_stream_cork(output); while ((line = i_stream_next_line(input)) != NULL) { if (client->v.proxy_parse_line(client, line) != 0) break; } o_stream_uncork(output); o_stream_unref(&output); }
static bool cmd_append_continue_message(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_append_context *ctx = cmd->context; int ret = 0; if (cmd->cancel) { /* cancel the command immediately (disconnection) */ cmd_append_finish(ctx); return TRUE; } if (ctx->save_ctx != NULL) { while (ctx->litinput->v_offset != ctx->literal_size) { ret = i_stream_read(ctx->litinput); if (mailbox_save_continue(ctx->save_ctx) < 0) { /* we still have to finish reading the message from client */ mailbox_save_cancel(&ctx->save_ctx); break; } if (ret == -1 || ret == 0) break; } } if (ctx->save_ctx == NULL) { /* saving has already failed, we're just eating away the literal */ (void)i_stream_read(ctx->litinput); i_stream_skip(ctx->litinput, i_stream_get_data_size(ctx->litinput)); } if (ctx->litinput->eof || client->input->closed) { uoff_t lit_offset = ctx->litinput->v_offset; /* finished - do one more read, to make sure istream-chain unreferences its stream, which is needed for litinput's unreferencing to seek the client->input to correct position. the seek is needed to avoid trying to seek backwards in the ctx->input's parent stream. */ i_stream_seek(ctx->input, ctx->input->v_offset); (void)i_stream_read(ctx->input); i_stream_unref(&ctx->litinput); if (ctx->failed) { if (ctx->save_ctx != NULL) mailbox_save_cancel(&ctx->save_ctx); } else if (ctx->save_ctx == NULL) { /* failed above */ client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } else if (lit_offset != ctx->literal_size) { /* client disconnected before it finished sending the whole message. */ ctx->failed = TRUE; mailbox_save_cancel(&ctx->save_ctx); client_disconnect(client, get_disconnect_reason(ctx, lit_offset)); } else if (ctx->catenate) { /* CATENATE isn't finished yet */ } else if (mailbox_save_finish(&ctx->save_ctx) < 0) { client_send_box_error(cmd, ctx->box); ctx->failed = TRUE; } if (client->input->closed) { cmd_append_finish(ctx); return TRUE; } /* prepare for the next message (or its part with catenate) */ ctx->message_input = FALSE; imap_parser_reset(ctx->save_parser); if (ctx->catenate) { cmd->func = cmd_append_continue_catenate; return cmd_append_continue_catenate(cmd); } i_stream_unref(&ctx->input); cmd->func = cmd_append_parse_new_msg; return cmd_append_parse_new_msg(cmd); } return FALSE; }