<commit_before>/* Copyright (c) 2006-2013 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "buffer.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "execv-const.h"
#include "istream.h"
#include "ostream.h"
#include "master-service.h"
#include "lmtp-client.h"
#include "lda-settings.h"
#include "mail-deliver.h"
#include "smtp-client.h"

#include <unistd.h>
#include <sys/wait.h>
#include <sysexits.h>

#define DEFAULT_SUBMISSION_PORT 25

struct smtp_client {
	struct ostream *output;
	buffer_t *buf;
	int temp_fd;
	pid_t pid;

	bool use_smtp;
	bool success;
	bool finished;

	const struct lda_settings *set;
	char *temp_path;
	char *destination;
	char *return_path;
};

static struct smtp_client *smtp_client_devnull(struct ostream **output_r)
{
	struct smtp_client *client;
	
	client = i_new(struct smtp_client, 1);
	client->buf = buffer_create_dynamic(default_pool, 1);
	client->output = o_stream_create_buffer(client->buf);
	o_stream_close(client->output);
	client->pid = (pid_t)-1;

	*output_r = client->output;
	return client;
}

static void ATTR_NORETURN
smtp_client_run_sendmail(const struct lda_settings *set,
			 const char *destination,
			 const char *return_path, int fd)
{
	const char *argv[7], *sendmail_path;

	/* deliver_set's contents may point to environment variables.
	   deliver_env_clean() cleans them up, so they have to be copied. */
	sendmail_path = t_strdup(set->sendmail_path);

	argv[0] = sendmail_path;
	argv[1] = "-i"; /* ignore dots */
	argv[2] = "-f";
	argv[3] = return_path != NULL && *return_path != '\0' ?
		return_path : "<>";
	argv[4] = "--";
	argv[5] = destination;
	argv[6] = NULL;

	if (dup2(fd, STDIN_FILENO) < 0)
		i_fatal("dup2() failed: %m");

	master_service_env_clean();

	execv_const(sendmail_path, argv);
}

static struct smtp_client *
smtp_client_open_sendmail(const struct lda_settings *set,
			  const char *destination, const char *return_path,
			  struct ostream **output_r)
{
	struct smtp_client *client;
	int fd[2];
	pid_t pid;

	if (pipe(fd) < 0) {
		i_error("pipe() failed: %m");
		return smtp_client_devnull(output_r);
	}

	if ((pid = fork()) == (pid_t)-1) {
		i_error("fork() failed: %m");
		i_close_fd(&fd[0]); i_close_fd(&fd[1]);
		return smtp_client_devnull(output_r);
	}
	if (pid == 0) {
		/* child */
		i_close_fd(&fd[1]);
		smtp_client_run_sendmail(set, destination, return_path, fd[0]);
	}
	i_close_fd(&fd[0]);

	client = i_new(struct smtp_client, 1);
	client->output = o_stream_create_fd(fd[1], IO_BLOCK_SIZE, TRUE);
	client->pid = pid;

	*output_r = client->output;
	return client;
}

static int create_temp_file(const char **path_r)
{
	string_t *path;
	int fd;

	path = t_str_new(128);
	str_append(path, "/tmp/dovecot.");
	str_append(path, master_service_get_name(master_service));
	str_append_c(path, '.');

	fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
	if (fd == -1) {
		i_error("safe_mkstemp(%s) failed: %m", str_c(path));
		return -1;
	}

	/* we just want the fd, unlink it */
	if (unlink(str_c(path)) < 0) {
		/* shouldn't happen.. */
		i_error("unlink(%s) failed: %m", str_c(path));
		i_close_fd(&fd);
		return -1;
	}

	*path_r = str_c(path);
	return fd;
}

struct smtp_client *
smtp_client_open(const struct lda_settings *set, const char *destination,
		 const char *return_path, struct ostream **output_r)
{
	struct smtp_client *client;
	const char *path;
	int fd;

	if (*set->submission_host == '\0') {
		return smtp_client_open_sendmail(set, destination,
						 return_path, output_r);
	}

	if ((fd = create_temp_file(&path)) == -1)
		return smtp_client_devnull(output_r);

	client = i_new(struct smtp_client, 1);
	client->set = set;
	client->temp_path = i_strdup(path);
	client->destination = i_strdup(destination);
	client->return_path = i_strdup(return_path);
	client->temp_fd = fd;
	client->output = o_stream_create_fd(fd, IO_BLOCK_SIZE, TRUE);
	client->use_smtp = TRUE;

	*output_r = client->output;<commit_msg>lib-lda: Assert-crashfix when sending a rejection mail failed.<commit_after>/* Copyright (c) 2006-2013 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "buffer.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "execv-const.h"
#include "istream.h"
#include "ostream.h"
#include "master-service.h"
#include "lmtp-client.h"
#include "lda-settings.h"
#include "mail-deliver.h"
#include "smtp-client.h"

#include <unistd.h>
#include <sys/wait.h>
#include <sysexits.h>

#define DEFAULT_SUBMISSION_PORT 25

struct smtp_client {
	struct ostream *output;
	buffer_t *buf;
	int temp_fd;
	pid_t pid;

	bool use_smtp;
	bool success;
	bool finished;

	const struct lda_settings *set;
	char *temp_path;
	char *destination;
	char *return_path;
};

static struct smtp_client *smtp_client_devnull(struct ostream **output_r)
{
	struct smtp_client *client;
	
	client = i_new(struct smtp_client, 1);
	client->buf = buffer_create_dynamic(default_pool, 1);
	client->output = o_stream_create_buffer(client->buf);
	o_stream_close(client->output);
	client->pid = (pid_t)-1;

	*output_r = client->output;
	return client;
}

static void ATTR_NORETURN
smtp_client_run_sendmail(const struct lda_settings *set,
			 const char *destination,
			 const char *return_path, int fd)
{
	const char *argv[7], *sendmail_path;

	/* deliver_set's contents may point to environment variables.
	   deliver_env_clean() cleans them up, so they have to be copied. */
	sendmail_path = t_strdup(set->sendmail_path);

	argv[0] = sendmail_path;
	argv[1] = "-i"; /* ignore dots */
	argv[2] = "-f";
	argv[3] = return_path != NULL && *return_path != '\0' ?
		return_path : "<>";
	argv[4] = "--";
	argv[5] = destination;
	argv[6] = NULL;

	if (dup2(fd, STDIN_FILENO) < 0)
		i_fatal("dup2() failed: %m");

	master_service_env_clean();

	execv_const(sendmail_path, argv);
}

static struct smtp_client *
smtp_client_open_sendmail(const struct lda_settings *set,
			  const char *destination, const char *return_path,
			  struct ostream **output_r)
{
	struct smtp_client *client;
	int fd[2];
	pid_t pid;

	if (pipe(fd) < 0) {
		i_error("pipe() failed: %m");
		return smtp_client_devnull(output_r);
	}

	if ((pid = fork()) == (pid_t)-1) {
		i_error("fork() failed: %m");
		i_close_fd(&fd[0]); i_close_fd(&fd[1]);
		return smtp_client_devnull(output_r);
	}
	if (pid == 0) {
		/* child */
		i_close_fd(&fd[1]);
		smtp_client_run_sendmail(set, destination, return_path, fd[0]);
	}
	i_close_fd(&fd[0]);

	client = i_new(struct smtp_client, 1);
	client->output = o_stream_create_fd(fd[1], IO_BLOCK_SIZE, TRUE);
	o_stream_set_no_error_handling(client->output, TRUE);
	client->pid = pid;

	*output_r = client->output;
	return client;
}

static int create_temp_file(const char **path_r)
{
	string_t *path;
	int fd;

	path = t_str_new(128);
	str_append(path, "/tmp/dovecot.");
	str_append(path, master_service_get_name(master_service));
	str_append_c(path, '.');

	fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
	if (fd == -1) {
		i_error("safe_mkstemp(%s) failed: %m", str_c(path));
		return -1;
	}

	/* we just want the fd, unlink it */
	if (unlink(str_c(path)) < 0) {
		/* shouldn't happen.. */
		i_error("unlink(%s) failed: %m", str_c(path));
		i_close_fd(&fd);
		return -1;
	}

	*path_r = str_c(path);
	return fd;
}

struct smtp_client *
smtp_client_open(const struct lda_settings *set, const char *destination,
		 const char *return_path, struct ostream **output_r)
{
	struct smtp_client *client;
	const char *path;
	int fd;

	if (*set->submission_host == '\0') {
		return smtp_client_open_sendmail(set, destination,
						 return_path, output_r);
	}

	if ((fd = create_temp_file(&path)) == -1)
		return smtp_client_devnull(output_r);

	client = i_new(struct smtp_client, 1);
	client->set = set;
	client->temp_path = i_strdup(path);
	client->destination = i_strdup(destination);
	client->return_path = i_strdup(return_path);
	client->temp_fd = fd;
	client->output = o_stream_create_fd(fd, IO_BLOCK_SIZE, TRUE);
	o_stream_set_no_error_handling(client->output, TRUE);
	client->use_smtp = TRUE;

	*output_r = client->output;
{'fraction_non_alphanumeric': 0.15228426395939088, 'fraction_numerical': 0.012876067846972886, 'mean_word_length': 4.874909090909091, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3363818', 'n_tokens_mistral': 3363, 'n_tokens_neox': 3164, 'n_words': 696}