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

#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "base64.h"
#include "hostpid.h"
#include "randgen.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "write-full.h"
#include "istream-header-filter.h"
#include "istream-crlf.h"
#include "istream-concat.h"
#include "message-parser.h"
#include "mail-user.h"
#include "index-mail.h"
#include "mbox-storage.h"
#include "mbox-file.h"
#include "mbox-from.h"
#include "mbox-lock.h"
#include "mbox-md5.h"
#include "mbox-sync-private.h"

#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <utime.h>

#define MBOX_DELIVERY_ID_RAND_BYTES (64/8)

struct mbox_save_context {
	struct mail_save_context ctx;

	struct mbox_mailbox *mbox;
	struct mail_index_transaction *trans;
	struct mail *mail;
	uoff_t append_offset, mail_offset;
	time_t orig_atime;

	string_t *headers;
	size_t space_end_idx;
	uint32_t seq, next_uid, uid_validity;

	struct istream *input;
	struct ostream *output;
	uoff_t extra_hdr_offset, eoh_offset;
	char last_char;

	struct mbox_md5_context *mbox_md5_ctx;
	char *x_delivery_id_header;

	unsigned int synced:1;
	unsigned int failed:1;
	unsigned int finished:1;
};

static int write_error(struct mbox_save_context *ctx)
{
	mbox_set_syscall_error(ctx->mbox, "write()");
	ctx->failed = TRUE;
	return -1;
}

static int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
{
	struct stat st;
	char ch;
	int fd;

	if (ctx->mbox->mbox_writeonly) {
		*offset = 0;
		return 0;
	}

	fd = ctx->mbox->mbox_fd;
	if (fstat(fd, &st) < 0)
                return mbox_set_syscall_error(ctx->mbox, "fstat()");

	ctx->orig_atime = st.st_atime;

	*offset = (uoff_t)st.st_size;
	if (st.st_size == 0)
		return 0;

	if (lseek(fd, st.st_size-1, SEEK_SET) < 0)
                return mbox_set_syscall_error(ctx->mbox, "lseek()");

	if (read(fd, &ch, 1) != 1)
		return mbox_set_syscall_error(ctx->mbox, "read()");

	if (ch != '\n') {
		if (write_full(fd, "\n", 1) < 0)
			return write_error(ctx);
		*offset += 1;
	}

	return 0;
}

static int mbox_append_lf(struct mbox_save_context *ctx)
{
	if (o_stream_send(ctx->output, "\n", 1) < 0)
		return write_error(ctx);

	return 0;
}

static int write_from_line(struct mbox_save_context *ctx, time_t received_date,
			   const char *from_envelope)
{
	int ret;

	T_BEGIN {
		const char *line;

		if (from_envelope == NULL) {
			struct mail_storage *storage =
				&ctx->mbox->storage->storage;

			from_envelope = t_strconcat(storage->user->username,
						    "@", my_hostdomain(), NULL);
		}

		/* save in local timezone, no matter what it was given with */
		line = mbox_from_create(from_envelope, received_date);

		if ((ret = o_stream_send_str(ctx->output, line)) < 0)
			write_error(ctx);
	} T_END;
	return ret;
}

static int mbox_write_content_length(struct mbox_save_context *ctx)
{
	uoff_t end_offset;
	const char *str;
	size_t len;

	i_assert(ctx->eoh_offset != (uoff_t)-1);

	if (ctx->mbox->mbox_writeonly) {
		/* we can't seek, don't set Content-Length */<commit_msg>mbox: When generating envelope to From_-line, don't append a second @owndomain if username already has one.<commit_after>/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "base64.h"
#include "hostpid.h"
#include "randgen.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "write-full.h"
#include "istream-header-filter.h"
#include "istream-crlf.h"
#include "istream-concat.h"
#include "message-parser.h"
#include "mail-user.h"
#include "index-mail.h"
#include "mbox-storage.h"
#include "mbox-file.h"
#include "mbox-from.h"
#include "mbox-lock.h"
#include "mbox-md5.h"
#include "mbox-sync-private.h"

#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <utime.h>

#define MBOX_DELIVERY_ID_RAND_BYTES (64/8)

struct mbox_save_context {
	struct mail_save_context ctx;

	struct mbox_mailbox *mbox;
	struct mail_index_transaction *trans;
	struct mail *mail;
	uoff_t append_offset, mail_offset;
	time_t orig_atime;

	string_t *headers;
	size_t space_end_idx;
	uint32_t seq, next_uid, uid_validity;

	struct istream *input;
	struct ostream *output;
	uoff_t extra_hdr_offset, eoh_offset;
	char last_char;

	struct mbox_md5_context *mbox_md5_ctx;
	char *x_delivery_id_header;

	unsigned int synced:1;
	unsigned int failed:1;
	unsigned int finished:1;
};

static int write_error(struct mbox_save_context *ctx)
{
	mbox_set_syscall_error(ctx->mbox, "write()");
	ctx->failed = TRUE;
	return -1;
}

static int mbox_seek_to_end(struct mbox_save_context *ctx, uoff_t *offset)
{
	struct stat st;
	char ch;
	int fd;

	if (ctx->mbox->mbox_writeonly) {
		*offset = 0;
		return 0;
	}

	fd = ctx->mbox->mbox_fd;
	if (fstat(fd, &st) < 0)
                return mbox_set_syscall_error(ctx->mbox, "fstat()");

	ctx->orig_atime = st.st_atime;

	*offset = (uoff_t)st.st_size;
	if (st.st_size == 0)
		return 0;

	if (lseek(fd, st.st_size-1, SEEK_SET) < 0)
                return mbox_set_syscall_error(ctx->mbox, "lseek()");

	if (read(fd, &ch, 1) != 1)
		return mbox_set_syscall_error(ctx->mbox, "read()");

	if (ch != '\n') {
		if (write_full(fd, "\n", 1) < 0)
			return write_error(ctx);
		*offset += 1;
	}

	return 0;
}

static int mbox_append_lf(struct mbox_save_context *ctx)
{
	if (o_stream_send(ctx->output, "\n", 1) < 0)
		return write_error(ctx);

	return 0;
}

static int write_from_line(struct mbox_save_context *ctx, time_t received_date,
			   const char *from_envelope)
{
	int ret;

	T_BEGIN {
		const char *line;

		if (from_envelope == NULL) {
			struct mail_storage *storage =
				&ctx->mbox->storage->storage;

			from_envelope =
				strchr(storage->user->username, '@') != NULL ?
				storage->user->username :
				t_strconcat(storage->user->username,
					    "@", my_hostdomain(), NULL);
		}

		/* save in local timezone, no matter what it was given with */
		line = mbox_from_create(from_envelope, received_date);

		if ((ret = o_stream_send_str(ctx->output, line)) < 0)
			write_error(ctx);
	} T_END;
	return ret;
}

static int mbox_write_content_length(struct mbox_save_context *ctx)
{
	uoff_t end_offset;
	const char *str;
	size_t len;

	i_assert(ctx->eoh_offset != (uoff_t)-1);

	if (ctx->mbox->mbox_writeonly) {
		/* we can't seek, don't set Content-Length */
{'fraction_non_alphanumeric': 0.14320987654320988, 'fraction_numerical': 0.012345679012345678, 'mean_word_length': 4.365066225165563, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 59, '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': '3615490', 'n_tokens_mistral': 2780, 'n_tokens_neox': 2570, 'n_words': 592}