Ejemplo 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);
}
Ejemplo n.º 2
0
static void lmtp_client_dns_done(const struct dns_lookup_result *result,
				 struct lmtp_client *client)
{
	if (result->ret != 0) {
		i_error("lmtp client: DNS lookup of %s failed: %s",
			client->host, result->error);
		lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
				 " (DNS lookup)");
	} else {
		client->ip = result->ips[0];
		if (lmtp_client_connect(client) < 0) {
			lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
					 " (connect)");
		}
	}
}
Ejemplo n.º 3
0
static void lmtp_client_connect_timeout(struct lmtp_client *client)
{
	i_error("lmtp client: connect(%s, %u) failed: Timed out in %u secs",
		client->host, client->port, client->set.timeout_secs);
	lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
			 " (connect timeout)");
}
Ejemplo n.º 4
0
static void lmtp_client_timeout(struct lmtp_client *client)
{
	const char *line;

	line = t_strdup_printf(ERRSTR_TEMP_REMOTE_FAILURE
		" (Timed out after %u secs while waiting for reply to %s)",
		client->set.timeout_secs, lmtp_client_state_to_string(client));
	lmtp_client_fail(client, line);
}
Ejemplo n.º 5
0
static int lmtp_client_send_data_cmd(struct lmtp_client *client)
{
	if (client->rcpt_next_receive_idx < array_count(&client->recipients))
		return 0;

	if (client->global_fail_string != NULL || !client->rcpt_to_successes) {
		lmtp_client_fail(client, client->global_fail_string);
		return -1;
	} else {
		client->input_state++;
		o_stream_nsend_str(client->output, "DATA\r\n");
		return 0;
	}
}
Ejemplo n.º 6
0
static void lmtp_client_input(struct lmtp_client *client)
{
	const char *line;

	lmtp_client_ref(client);
	while ((line = i_stream_read_next_line(client->input)) != NULL) {
		if (lmtp_client_input_line(client, line) < 0) {
			lmtp_client_unref(&client);
			return;
		}
	}

	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)");
	}
	lmtp_client_unref(&client);
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
static void lmtp_client_wait_connect(struct lmtp_client *client)
{
	int err;

	err = net_geterror(client->fd);
	if (err != 0) {
		i_error("lmtp client: connect(%s, %u) failed: %s",
			client->host, client->port, strerror(err));
		lmtp_client_fail(client, ERRSTR_TEMP_REMOTE_FAILURE
				 " (connect)");
		return;
	}
	io_remove(&client->io);
	client->io = io_add(client->fd, IO_READ, lmtp_client_input, client);
	lmtp_client_input(client);
}
Ejemplo n.º 9
0
static int lmtp_client_input_line(struct lmtp_client *client, const char *line)
{
	int ret, reply_code = 0;

	if ((ret = lmtp_input_get_reply_code(line, &reply_code,
					     client->input_multiline)) <= 0) {
		if (ret == 0)
			return 0;
		lmtp_client_fail(client, line);
		return -1;
	}

	switch (client->input_state) {
	case LMTP_INPUT_STATE_GREET:
	case LMTP_INPUT_STATE_XCLIENT:
		if (reply_code != 220) {
			lmtp_client_fail(client, line);
			return -1;
		}
		lmtp_client_send_handshake(client);
		client->input_state = LMTP_INPUT_STATE_LHLO;
		break;
	case LMTP_INPUT_STATE_LHLO:
	case LMTP_INPUT_STATE_MAIL_FROM:
		if (reply_code != 250) {
			lmtp_client_fail(client, line);
			return -1;
		}
		str_append(client->input_multiline, line);
		lmtp_client_parse_capabilities(client,
			str_c(client->input_multiline));
		if (client->input_state == LMTP_INPUT_STATE_LHLO &&
		    lmtp_client_send_xclient(client)) {
			client->input_state = LMTP_INPUT_STATE_XCLIENT;
			client->xclient_sent = TRUE;
			break;
		}
		if (client->input_state == LMTP_INPUT_STATE_LHLO) {
			o_stream_nsend_str(client->output,
				t_strdup_printf("MAIL FROM:%s\r\n",
						client->set.mail_from));
		}
		client->input_state++;
		lmtp_client_send_rcpts(client);
		break;
	case LMTP_INPUT_STATE_RCPT_TO:
		lmtp_client_rcpt_next(client, line);
		if (client->data_input == NULL)
			break;
		if (lmtp_client_send_data_cmd(client) < 0)
			return -1;
		break;
	case LMTP_INPUT_STATE_DATA_CONTINUE:
		/* Start sending DATA */
		if (strncmp(line, "354", 3) != 0) {
			lmtp_client_fail(client, line);
			return -1;
		}
		client->input_state++;
		if (client->data_header != NULL)
			o_stream_nsend_str(client->output, client->data_header);
		lmtp_client_send_data(client);
		break;
	case LMTP_INPUT_STATE_DATA:
		/* DATA replies */
		if (lmtp_client_data_next(client, line) < 0)
			return -1;
		break;
	}
	return 1;
}
Ejemplo n.º 10
0
static int lmtp_client_send_data(struct lmtp_client *client)
{
	const unsigned char *data;
	unsigned char add;
	size_t i, size;
	bool sent_bytes = FALSE;
	int ret;

	if (client->output_finished)
		return 0;

	while ((ret = i_stream_read_more(client->data_input, &data, &size)) > 0) {
		add = '\0';
		for (i = 0; i < size; i++) {
			if (data[i] == '\n') {
				if ((i == 0 && client->output_last != '\r') ||
				    (i > 0 && data[i-1] != '\r')) {
					/* missing CR */
					add = '\r';
					break;
				}
			} else if (data[i] == '.' &&
				   ((i == 0 && client->output_last == '\n') ||
				    (i > 0 && data[i-1] == '\n'))) {
				/* escape the dot */
				add = '.';
				break;
			}
		}

		if (i > 0) {
			if (o_stream_send(client->output, data, i) < 0)
				break;
			client->output_last = data[i-1];
			i_stream_skip(client->data_input, i);
			sent_bytes = TRUE;
		}

		if (o_stream_get_buffer_used_size(client->output) >= 4096) {
			if ((ret = o_stream_flush(client->output)) < 0)
				break;
			if (ret == 0) {
				/* continue later */
				o_stream_set_flush_pending(client->output, TRUE);
				return 0;
			}
		}

		if (add != '\0') {
			if (o_stream_send(client->output, &add, 1) < 0)
				break;

			client->output_last = add;
		}
	}
	if (client->data_input->stream_errno != 0) {
		i_error("lmtp client: read(%s) failed: %s",
			i_stream_get_name(client->data_input),
			i_stream_get_error(client->data_input));
		lmtp_client_fail(client,
			"451 4.3.0 Internal failure while reading DATA input");
		return -1;
	}
	if (sent_bytes && client->data_output_callback != NULL)
		client->data_output_callback(client->data_output_context);

	if (ret == 0 || ret == -2) {
		/* -2 can happen with tee istreams */
		return 0;
	}

	if (client->output_last != '\n') {
		/* didn't end with CRLF */
		o_stream_nsend(client->output, "\r\n", 2);
	}
	o_stream_nsend(client->output, ".\r\n", 3);
	client->output_finished = TRUE;
	io_loop_time_refresh();
	client->times.data_sent = ioloop_timeval;
	return 0;
}