Exemplo n.º 1
0
static void lmtp_client_input(struct lmtp_client *client)
{
	const char *line;
	int ret;

	lmtp_client_ref(client);
	o_stream_cork(client->output);
	while ((line = i_stream_read_next_line(client->input)) != NULL) {
		T_BEGIN {
			ret = lmtp_client_input_line(client, line);
		} T_END;
		if (ret < 0) {
			o_stream_uncork(client->output);
			lmtp_client_unref(&client);
			return;
		}
		if (ret > 0)
			str_truncate(client->input_multiline, 0);
	}

	if (client->input->stream_errno == ENOBUFS) {
		lmtp_client_fail(client,
				 "501 5.5.4 Command reply line too long");
	} else if (client->input->stream_errno != 0) {
		errno = client->input->stream_errno;
		i_error("lmtp client: read() failed: %m");
		lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
				 " (read failure)");
	} else if (client->input->eof) {
		lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
				 " (disconnected in input)");
	}
	o_stream_uncork(client->output);
	lmtp_client_unref(&client);
}
Exemplo n.º 2
0
static void
idle_finish(struct cmd_idle_context *ctx, bool done_ok, bool free_cmd)
{
	struct client *client = ctx->client;

	if (ctx->keepalive_to != NULL)
		timeout_remove(&ctx->keepalive_to);

	if (ctx->sync_ctx != NULL) {
		/* we're here only in connection failure cases */
		(void)imap_sync_deinit(ctx->sync_ctx, ctx->cmd);
	}

	o_stream_cork(client->output);
	if (client->io != NULL)
		io_remove(&client->io);

	if (client->mailbox != NULL)
		mailbox_notify_changes_stop(client->mailbox);

	if (done_ok)
		client_send_tagline(ctx->cmd, "OK Idle completed.");
	else
		client_send_tagline(ctx->cmd, "BAD Expected DONE.");

	o_stream_uncork(client->output);
	if (free_cmd)
		client_command_free(&ctx->cmd);
}
Exemplo n.º 3
0
client_auth_result(struct client *client, enum client_auth_result result,
		   const struct client_auth_reply *reply, const char *text)
{
	o_stream_cork(client->output);
	client->v.auth_result(client, result, reply, text);
	o_stream_uncork(client->output);
}
Exemplo n.º 4
0
static void server_input(struct login_proxy *proxy)
{
	unsigned char buf[OUTBUF_THRESHOLD];
	ssize_t ret, ret2;

	proxy->last_io = ioloop_time;
	if (o_stream_get_buffer_used_size(proxy->client_output) >
	    OUTBUF_THRESHOLD) {
		/* client's output buffer is already quite full.
		   don't send more until we're below threshold. */
		io_remove(&proxy->server_io);
		return;
	}

	ret = net_receive(proxy->server_fd, buf, sizeof(buf));
	if (ret < 0) {
		login_proxy_free_errno(&proxy, errno, TRUE);
		return;
	}
	o_stream_cork(proxy->client_output);
	ret2 = o_stream_send(proxy->client_output, buf, ret);
	o_stream_uncork(proxy->client_output);
	if (ret2 != ret)
		login_proxy_free_ostream(&proxy, proxy->client_output, FALSE);
}
Exemplo n.º 5
0
static void client_input(struct client *client)
{
	const char *const *args, *error;
	int ret;

	if (client->to_pending != NULL)
		timeout_remove(&client->to_pending);

	switch (i_stream_read(client->input)) {
	case -2:
		i_error("BUG: Stats client sent too much data");
		client_destroy(&client);
		return;
	case -1:
		client_destroy(&client);
		return;
	}

	o_stream_cork(client->output);
	while ((args = client_read_next_line(client)) != NULL) {
		ret = client_handle_request(client, args, &error);
		if (ret < 0) {
			i_error("Stats client input error: %s", error);
			client_destroy(&client);
			return;
		}
		if (ret == 0) {
			o_stream_set_flush_pending(client->output, TRUE);
			io_remove(&client->io);
			break;
		}
		client->cmd_more = NULL;
	}
	o_stream_uncork(client->output);
}
Exemplo n.º 6
0
static void proxy_client_input(struct login_proxy *proxy)
{
	const unsigned char *data;
	size_t size;
	ssize_t ret;

	proxy->last_io = ioloop_time;
	if (o_stream_get_buffer_used_size(proxy->server_output) >
	    OUTBUF_THRESHOLD) {
		/* proxy's output buffer is already quite full.
		   don't send more until we're below threshold. */
		io_remove(&proxy->client_io);
		return;
	}

	if (i_stream_read_data(proxy->client_input, &data, &size, 0) < 0) {
		const char *errstr = i_stream_get_error(proxy->client_input);
		login_proxy_free_errstr(&proxy, errstr, FALSE);
		return;
	}
	o_stream_cork(proxy->server_output);
	ret = o_stream_send(proxy->server_output, data, size);
	o_stream_uncork(proxy->server_output);
	if (ret != (ssize_t)size)
		login_proxy_free_ostream(&proxy, proxy->server_output, TRUE);
	else
		i_stream_skip(proxy->client_input, ret);
}
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);
	}
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
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);
}
Exemplo n.º 10
0
void lmtp_client_send_more(struct lmtp_client *client)
{
	if (client->input_state == LMTP_INPUT_STATE_DATA) {
		o_stream_cork(client->output);
		lmtp_client_send_data(client);
		o_stream_uncork(client->output);
	}
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
0
static void iostream_pump_copy(struct iostream_pump *pump)
{
	enum ostream_send_istream_result res;
	size_t old_size;

	o_stream_cork(pump->output);
	old_size = o_stream_get_max_buffer_size(pump->output);
	o_stream_set_max_buffer_size(pump->output,
		I_MIN(IO_BLOCK_SIZE,
		      o_stream_get_max_buffer_size(pump->output)));
	res = o_stream_send_istream(pump->output, pump->input);
	o_stream_set_max_buffer_size(pump->output, old_size);
	o_stream_uncork(pump->output);

	switch(res) {
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
		io_remove(&pump->io);
		pump->callback(IOSTREAM_PUMP_STATUS_INPUT_ERROR,
			       pump->context);
		return;
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
		io_remove(&pump->io);
		pump->callback(IOSTREAM_PUMP_STATUS_OUTPUT_ERROR,
			       pump->context);
		return;
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
		i_assert(!pump->output->blocking);
		pump->waiting_output = TRUE;
		io_remove(&pump->io);
		return;
	case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
		pump->waiting_output = FALSE;
		io_remove(&pump->io);
		/* flush it */
		switch (o_stream_flush(pump->output)) {
		case -1:
			pump->callback(IOSTREAM_PUMP_STATUS_OUTPUT_ERROR,
				       pump->context);
			break;
		case 0:
			pump->waiting_output = TRUE;
			pump->completed = TRUE;
			break;
		default:
			pump->callback(IOSTREAM_PUMP_STATUS_INPUT_EOF,
				       pump->context);
			break;
		}
		return;
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
		i_assert(!pump->input->blocking);
		pump->waiting_output = FALSE;
		return;
	}
	i_unreached();
}
Exemplo n.º 13
0
static int
cmd_setmetadata_entry(struct imap_setmetadata_context *ctx,
                      const char *entry_name,
                      const struct imap_arg *entry_value)
{
    struct istream *inputs[2];
    struct mail_attribute_value value;
    string_t *path;
    int ret;

    switch (entry_value->type) {
    case IMAP_ARG_NIL:
    case IMAP_ARG_ATOM:
    case IMAP_ARG_STRING:
        /* we have the value already */
        if (ctx->failed)
            return 1;
        memset(&value, 0, sizeof(value));
        value.value = imap_arg_as_nstring(entry_value);
        ret = imap_metadata_set(ctx->trans, entry_name, &value);
        if (ret < 0) {
            /* delay reporting the failure so we'll finish
               reading the command input */
            ctx->storage_failure = TRUE;
            ctx->failed = TRUE;
        }
        return 1;
    case IMAP_ARG_LITERAL_SIZE:
        o_stream_nsend(ctx->cmd->client->output, "+ OK\r\n", 6);
        o_stream_nflush(ctx->cmd->client->output);
        o_stream_uncork(ctx->cmd->client->output);
        o_stream_cork(ctx->cmd->client->output);
    /* fall through */
    case IMAP_ARG_LITERAL_SIZE_NONSYNC:
        i_free(ctx->entry_name);
        ctx->entry_name = i_strdup(entry_name);
        ctx->entry_value_len = imap_arg_as_literal_size(entry_value);

        inputs[0] = i_stream_create_limit(ctx->cmd->client->input,
                                          ctx->entry_value_len);
        inputs[1] = NULL;

        path = t_str_new(128);
        mail_user_set_get_temp_prefix(path, ctx->cmd->client->user->set);
        ctx->input = i_stream_create_seekable_path(inputs,
                     METADATA_MAX_INMEM_SIZE, str_c(path));
        i_stream_set_name(ctx->input, i_stream_get_name(inputs[0]));
        i_stream_unref(&inputs[0]);
        return cmd_setmetadata_entry_read_stream(ctx);
    case IMAP_ARG_LITERAL:
    case IMAP_ARG_LIST:
    case IMAP_ARG_EOL:
        break;
    }
    i_unreached();
}
Exemplo n.º 14
0
static void o_stream_zlib_cork(struct ostream_private *stream, bool set)
{
	struct zlib_ostream *zstream = (struct zlib_ostream *)stream;

	stream->corked = set;
	if (set)
		o_stream_cork(zstream->output);
	else {
		(void)o_stream_flush(&stream->ostream);
		o_stream_uncork(zstream->output);
	}
}
Exemplo n.º 15
0
static void o_stream_default_cork(struct ostream_private *_stream, bool set)
{
	_stream->corked = set;
	if (set) {
		if (_stream->parent != NULL)
			o_stream_cork(_stream->parent);
	} else {
		(void)o_stream_flush(&_stream->ostream);
		if (_stream->parent != NULL)
			o_stream_uncork(_stream->parent);
	}
}
Exemplo n.º 16
0
static int server_connection_output(struct server_connection *conn)
{
    int ret;

    o_stream_cork(conn->output);
    ret = o_stream_flush(conn->output);
    if (ret > 0 && conn->cmd_input != NULL && conn->delayed_cmd == NULL)
        ret = server_connection_send_cmd_input_more(conn);
    o_stream_uncork(conn->output);
    if (ret < 0)
        server_connection_destroy(&conn);
    return ret;
}
Exemplo n.º 17
0
static bool cmd_append_send_literal_continue(struct cmd_append_context *ctx)
{
	if (ctx->failed) {
		/* tagline was already sent, we can abort here */
		return FALSE;
	}

	o_stream_nsend(ctx->client->output, "+ OK\r\n", 6);
	o_stream_nflush(ctx->client->output);
	o_stream_uncork(ctx->client->output);
	o_stream_cork(ctx->client->output);
	return TRUE;
}
Exemplo n.º 18
0
static bool openssl_iostream_bio_output(struct ssl_iostream *ssl_io)
{
	size_t bytes, max_bytes;
	ssize_t sent;
	unsigned char buffer[IO_BLOCK_SIZE];
	bool bytes_sent = FALSE;
	int ret;

	o_stream_cork(ssl_io->plain_output);
	while ((bytes = BIO_ctrl_pending(ssl_io->bio_ext)) > 0) {
		/* bytes contains how many SSL encrypted bytes we should be
		   sending out */
		max_bytes = o_stream_get_buffer_avail_size(ssl_io->plain_output);
		if (bytes > max_bytes) {
			if (max_bytes == 0) {
				/* wait until output buffer clears */
				o_stream_set_flush_pending(ssl_io->plain_output,
							   TRUE);
				break;
			}
			bytes = max_bytes;
		}
		if (bytes > sizeof(buffer))
			bytes = sizeof(buffer);

		/* BIO_read() is guaranteed to return all the bytes that
		   BIO_ctrl_pending() returned */
		ret = BIO_read(ssl_io->bio_ext, buffer, bytes);
		i_assert(ret == (int)bytes);

		/* we limited number of read bytes to plain_output's
		   available size. this send() is guaranteed to either
		   fully succeed or completely fail due to some error. */
		sent = o_stream_send(ssl_io->plain_output, buffer, bytes);
		if (sent < 0) {
			i_assert(ssl_io->plain_output->closed ||
				 ssl_io->plain_output->stream_errno != 0);
			i_free(ssl_io->plain_stream_errstr);
			ssl_io->plain_stream_errstr =
				i_strdup(o_stream_get_error(ssl_io->plain_output));
			ssl_io->plain_stream_errno =
				ssl_io->plain_output->stream_errno;
			ssl_io->closed = TRUE;
			break;
		}
		i_assert(sent == (ssize_t)bytes);
		bytes_sent = TRUE;
	}
	o_stream_uncork(ssl_io->plain_output);
	return bytes_sent;
}
Exemplo n.º 19
0
static void rawlog_proxy_destroy(struct rawlog_proxy *proxy)
{
	if (proxy->in_output != NULL) {
		o_stream_uncork(proxy->in_output);
		if (o_stream_nfinish(proxy->in_output) < 0) {
			i_error("write(in) failed: %s",
				o_stream_get_error(proxy->in_output));
		}
		o_stream_destroy(&proxy->in_output);
	}
	if (proxy->out_output != NULL) {
		o_stream_uncork(proxy->out_output);
		if (o_stream_nfinish(proxy->out_output) < 0) {
			i_error("write(out) failed: %s",
				o_stream_get_error(proxy->out_output));
		}
		o_stream_destroy(&proxy->out_output);
	}
	if (proxy->client_io != NULL)
		io_remove(&proxy->client_io);
	if (proxy->server_io != NULL)
		io_remove(&proxy->server_io);
	if (proxy->to_flush != NULL)
		timeout_remove(&proxy->to_flush);

	o_stream_destroy(&proxy->client_output);
	o_stream_destroy(&proxy->server_output);

	if (close(proxy->client_in_fd) < 0)
		i_error("close(client_in_fd) failed: %m");
	if (close(proxy->client_out_fd) < 0)
		i_error("close(client_out_fd) failed: %m");
	if (close(proxy->server_fd) < 0)
		i_error("close(server_fd) failed: %m");
	i_free(proxy);

	io_loop_stop(ioloop);
}
Exemplo n.º 20
0
static int lmtp_client_output(struct lmtp_client *client)
{
	int ret;

	lmtp_client_ref(client);
	o_stream_cork(client->output);
	if ((ret = o_stream_flush(client->output)) < 0)
		lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
				 " (disconnected in output)");
	else if (client->input_state == LMTP_INPUT_STATE_DATA)
		lmtp_client_send_data(client);
	o_stream_uncork(client->output);
	lmtp_client_unref(&client);
	return ret;
}
Exemplo n.º 21
0
static void client_add_input(struct client *client, const buffer_t *buf)
{
	struct ostream *output;

	if (buf != NULL && buf->used > 0) {
		if (!i_stream_add_data(client->input, buf->data, buf->used))
			i_panic("Couldn't add client input to stream");
	}

	output = client->output;
	o_stream_ref(output);
	o_stream_cork(output);
	(void)client_handle_input(client);
	o_stream_uncork(output);
	o_stream_unref(&output);
}
Exemplo n.º 22
0
static void dns_client_input(struct dns_client *client)
{
	const char *line;
	int ret = 0;

	o_stream_cork(client->output);
	while ((line = i_stream_read_next_line(client->input)) != NULL) {
		if (dns_client_input_line(client, line) < 0) {
			ret = -1;
			break;
		}
	}
	o_stream_uncork(client->output);

	if (client->input->eof || client->input->stream_errno != 0 || ret < 0)
		dns_client_destroy(&client);
}
Exemplo n.º 23
0
static void test_ostream_file_random(void)
{
	struct ostream *output;
	string_t *path = t_str_new(128);
	char buf[MAX_BUFSIZE*4], buf2[MAX_BUFSIZE*4], randbuf[MAX_BUFSIZE];
	unsigned int i, offset, size;
	ssize_t ret;
	int fd;

	memset(buf, 0, sizeof(buf));
	fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
	if (fd == -1)
		i_fatal("safe_mkstemp(%s) failed: %m", str_c(path));
	if (unlink(str_c(path)) < 0)
		i_fatal("unlink(%s) failed: %m", str_c(path));
	output = o_stream_create_fd(fd, MAX_BUFSIZE, FALSE);
	o_stream_cork(output);

	size = (rand() % MAX_BUFSIZE) + 1;
	random_fill_weak(randbuf, size);
	memcpy(buf, randbuf, size);
	test_assert(o_stream_send(output, buf, size) > 0);

	for (i = 0; i < 10; i++) {
		offset = rand() % (MAX_BUFSIZE*3);
		size = (rand() % MAX_BUFSIZE) + 1;
		random_fill_weak(randbuf, size);
		memcpy(buf + offset, randbuf, size);
		test_assert(o_stream_pwrite(output, randbuf, size, offset) == 0);
		if (rand() % 10 == 0)
			test_assert(o_stream_flush(output) > 0);
	}

	test_assert(o_stream_flush(output) > 0);
	o_stream_uncork(output);
	ret = pread(fd, buf2, sizeof(buf2), 0);
	if (ret < 0)
		i_fatal("pread() failed: %m");
	else {
		i_assert(ret > 0);
		test_assert(memcmp(buf, buf2, ret) == 0);
	}
	o_stream_unref(&output);
	i_close_fd(&fd);
}
Exemplo n.º 24
0
void client_input(struct client *client)
{
	struct client_command_context *cmd;
	struct ostream *output = client->output;
	ssize_t bytes;

	i_assert(client->io != NULL);

	client->last_input = ioloop_time;
	timeout_reset(client->to_idle);

	if (client->to_delayed_input != NULL)
		timeout_remove(&client->to_delayed_input);

	bytes = i_stream_read(client->input);
	if (bytes == -1) {
		/* disconnected */
		client_destroy(client, NULL);
		return;
	}

	o_stream_ref(output);
	o_stream_cork(output);
	if (!client_handle_input(client) && bytes == -2) {
		/* 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;

		cmd = client->input_lock != NULL ? client->input_lock :
			client_command_new(client);
		cmd->param_error = TRUE;
		client_send_command_error(cmd, "Too long argument.");
		client_command_free(&cmd);
	}
	o_stream_uncork(output);
	o_stream_unref(&output);
	imap_refresh_proctitle();

	if (client->disconnected)
		client_destroy(client, NULL);
	else
		client_continue_pending_input(client);
}
Exemplo n.º 25
0
void client_disconnect(struct client *client, const char *reason)
{
	i_assert(reason != NULL);

	if (client->disconnected)
		return;

	i_info("Disconnected: %s %s", reason, client_stats(client));
	client->disconnected = TRUE;
	o_stream_nflush(client->output);
	o_stream_uncork(client->output);

	i_stream_close(client->input);
	o_stream_close(client->output);

	if (client->to_idle != NULL)
		timeout_remove(&client->to_idle);
	client->to_idle = timeout_add(0, client_destroy_timeout, client);
}
Exemplo n.º 26
0
static int client_output(struct client *client)
{
	int ret = 1;

	o_stream_cork(client->output);
	if (o_stream_flush(client->output) < 0) {
		client_destroy(&client);
		return 1;
	}
	if (client->cmd_more != NULL)
		ret = client->cmd_more(client);
	o_stream_uncork(client->output);

	if (ret > 0) {
		client->cmd_more = NULL;
		if (client->io == NULL)
			client_enable_io(client);
	}
	return ret;
}
Exemplo n.º 27
0
void connection_input_default(struct connection *conn)
{
	const char *line;
	struct istream *input;
	struct ostream *output;
	int ret = 0;

	switch (connection_input_read(conn)) {
	case -1:
		return;
	case 0: /* allow calling this function for buffered input */
	case 1:
		break;
	default:
		i_unreached();
	}

	input = conn->input;
	output = conn->output;
	i_stream_ref(input);
	if (output != NULL) {
		o_stream_ref(output);
		o_stream_cork(output);
	}
	while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
		T_BEGIN {
			ret = conn->list->v.input_line(conn, line);
		} T_END;
		if (ret <= 0)
			break;
	}
	if (output != NULL) {
		o_stream_uncork(output);
		o_stream_unref(&output);
	}
	if (ret < 0 && !input->closed) {
		conn->disconnect_reason = CONNECTION_DISCONNECT_DEINIT;
		conn->list->v.destroy(conn);
	}
	i_stream_unref(&input);
}
Exemplo n.º 28
0
static void client_add_input(struct client *client, const buffer_t *buf)
{
	struct ostream *output;
	struct client_input input;

	if (buf != NULL && buf->used > 0) {
		client_parse_input(buf->data, buf->used, &input);
		if (input.input_size > 0 &&
		    !i_stream_add_data(client->input, input.input,
				       input.input_size))
			i_panic("Couldn't add client input to stream");
	} else {
		/* IMAPLOGINTAG environment is compatible with mailfront */
		memset(&input, 0, sizeof(input));
		input.tag = getenv("IMAPLOGINTAG");
	}

	output = client->output;
	o_stream_ref(output);
	o_stream_cork(output);
	if (input.tag == NULL) {
		client_send_line(client, t_strconcat(
			"* PREAUTH [CAPABILITY ",
			str_c(client->capability_string), "] "
			"Logged in as ", client->user->username, NULL));
	} else if (input.send_untagged_capability) {
		/* client doesn't seem to understand tagged capabilities. send
		   untagged instead and hope that it works. */
		client_send_line(client, t_strconcat("* CAPABILITY ",
			str_c(client->capability_string), NULL));
		client_send_line(client,
				 t_strconcat(input.tag, " OK Logged in", NULL));
	} else {
		client_send_line(client, t_strconcat(
			input.tag, " OK [CAPABILITY ",
			str_c(client->capability_string), "] Logged in", NULL));
	}
	(void)client_handle_input(client);
	o_stream_uncork(output);
	o_stream_unref(&output);
}
Exemplo n.º 29
0
static void keepalive_timeout(struct cmd_idle_context *ctx)
{
	if (ctx->client->output_cmd_lock != NULL) {
		/* it's busy sending output */
		return;
	}

	if (o_stream_get_buffer_used_size(ctx->client->output) == 0) {
		/* Sending this keeps NATs/stateful firewalls alive.
		   Sending this also catches dead connections. Don't send
		   anything if there is already data waiting in output
		   buffer. */
		o_stream_cork(ctx->client->output);
		client_send_line(ctx->client, "* OK Still here");
		o_stream_uncork(ctx->client->output);
	}
	/* Make sure idling connections don't get disconnected. There are
	   several clients that really want to IDLE forever and there's not
	   much harm in letting them do so. */
	timeout_reset(ctx->client->to_idle);
	/* recalculate time for the next keepalive timeout */
	idle_add_keepalive_timeout(ctx);
}
Exemplo n.º 30
0
static int client_output(struct client *client)
{
	o_stream_cork(client->output);
	if (o_stream_flush(client->output) < 0) {
		if (client->ctrl_output != NULL)
			(void)o_stream_send_str(client->ctrl_output, "DISCONNECTED\n");
		client_destroy(client);
		return 1;
	}
	timeout_reset(client->to_idle);

	if (client->url != NULL) {
		if (client_run_url(client) < 0) {
			client_destroy(client);
			return 1;
		}

		if (client->url == NULL && client->waiting_input) {
			if (!client_handle_input(client)) {
				/* client got destroyed */
				return 1;
			}
		}
	}

	o_stream_uncork(client->output);
	if (client->url != NULL) {
		/* url not finished yet */
		return 0;
	} else if (client->io == NULL) {
		/* data still in output buffer, get back here to add IO */
		return 0;
	} else {
		return 1;
	}
}