<commit_before>/* Copyright (C) 2002 <NAME> */

#include "common.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "mail-storage.h"
#include "commands.h"
#include "mail-search.h"

#include <stdlib.h>

/* max. length of input command line (spec says 512) */
#define MAX_INBUF_SIZE 2048

/* Stop reading input when output buffer has this many bytes. Once the buffer
   size has dropped to half of it, start reading input again. */
#define OUTBUF_THROTTLE_SIZE 4096

/* If we can't send anything for a minute, disconnect the client */
#define CLIENT_OUTPUT_TIMEOUT (60*1000)

/* Disconnect client when it sends too many bad commands in a row */
#define CLIENT_MAX_BAD_COMMANDS 20

/* Disconnect client after idling this many seconds */
#define CLIENT_IDLE_TIMEOUT (60*30)

extern struct mail_storage_callbacks mail_storage_callbacks;

static struct client *my_client; /* we don't need more than one currently */
static struct timeout *to_idle;

static void client_input(void *context);
static void client_output(void *context);

static int sync_mailbox(struct mailbox *box)
{
	struct mailbox_sync_context *ctx;
        struct mailbox_sync_rec sync_rec;
	struct mailbox_status status;

	ctx = mailbox_sync_init(box, MAILBOX_SYNC_FLAG_FULL_READ);
	while (mailbox_sync_next(ctx, &sync_rec) > 0)
		;
	return mailbox_sync_deinit(ctx, &status);
}

static int init_mailbox(struct client *client)
{
	struct mail_search_arg search_arg;
        struct mailbox_transaction_context *t;
	struct mail_search_context *ctx;
	struct mail *mail;
	struct mailbox_status status;
	int i, failed;

	memset(&search_arg, 0, sizeof(search_arg));
	search_arg.type = SEARCH_ALL;

	for (i = 0; i < 2; i++) {
		if (sync_mailbox(client->mailbox) < 0) {
			client_send_storage_error(client);
			return FALSE;
		}
		if (mailbox_get_status(client->mailbox, STATUS_MESSAGES,
				       &status) < 0) {
			client_send_storage_error(client);
			return FALSE;
		}

		client->last_seen = 0;
		client->messages_count = status.messages;
		client->total_size = 0;
		client->deleted_size = 0;

		if (client->messages_count == 0)
			return TRUE;

		i_free(client->message_sizes);
		client->message_sizes = i_new(uoff_t, client->messages_count);

		t = mailbox_transaction_begin(client->mailbox, FALSE);
		ctx = mailbox_search_init(t, NULL, &search_arg, NULL,
					  MAIL_FETCH_VIRTUAL_SIZE, NULL);
		if (ctx == NULL) {
			client_send_storage_error(client);
                        mailbox_transaction_rollback(t);
			return FALSE;
		}

		failed = FALSE;
		while ((mail = mailbox_search_next(ctx)) != NULL) {
			uoff_t size = mail->get_virtual_size(mail);
			const struct mail_full_flags *flags;

			flags = mail->get_flags(mail);

			if (flags == NULL || size == (uoff_t)-1) {
				failed = TRUE;
				break;
			}

			if ((flags->flags & MAIL_SEEN) != 0)
				client->last_seen = mail->seq;
                        client->total_size += size;

			i_assert(mail->seq <= client->messages_count);
			client->message_sizes[mail->seq-1] = size;
		}

		if (mailbox_search_deinit(ctx) < 0) {
			client_send_storage_error(client);
                        mailbox_transaction_rollback(t);
			return FALSE;
		}

		if (!failed) {
			mailbox_transaction_commit(t, 0);
			return TRUE;
		}

		/* well, sync and try again */
		mailbox_transaction_rollback(t);
	}

	client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox.");
	return FALSE;
}

struct client *client_create(int hin, int hout, struct mail_storage *storage)
{
	struct client *client;
        enum mailbox_open_flags flags;
	int syntax_error;

	/* always use nonblocking I/O */
	net_set_nonblock(hin, TRUE);
	net_set_nonblock(hout, TRUE);

	client = i_new(struct client, 1);
	client->input = i_stream_create_file(hin, default_pool,
					     MAX_INBUF_SIZE, FALSE);
	client->output = o_stream_create_file(hout, default_pool,
					      (size_t)-1, FALSE);
	o_stream_set_flush_callback(client->output, client_output, client);

	client->io = io_add(hin, IO_READ, client_input, client);
        client->last_input = ioloop_time;
	client->storage = storage;

	mail_storage_set_callbacks(storage, &mail_storage_callbacks, client);

	flags = 0;
	if (getenv("POP3_MAILS_KEEP_RECENT") != NULL)
		flags |= MAILBOX_OPEN_KEEP_RECENT;
	client->mailbox = mailbox_open(storage, "INBOX", flags);
	if (client->mailbox == NULL) {
		i_error("Couldn't open INBOX: %s",
			mail_storage_get_last_error(storage, &syntax_error));
		client_send_line(client, "-ERR No INBOX for user.");
		client_destroy(client);
		return NULL;
	}

	if (!init_mailbox(client)) {
		client_destroy(client);
		return NULL;
	}

	i_assert(my_client == NULL);
	my_client = client;

	if (hook_client_created != NULL)
		hook_client_created(&client);
	return client;
}

void client_destroy(struct client *client)
{
	if (client->cmd != NULL) {
		/* deinitialize command */
		i_stream_close(client->input);
		o_stream_close(client->output);
		client->cmd(client);
	}
	if (client->mailbox != NULL)
		mailbox_close(client->mailbox);
	mail_storage_destroy(client->storage);

	i_free(client->message_sizes);
	i_free(client->deleted_bitmask);

	if (client->io != NULL)
		io_remove(client->io);<commit_msg>assert<commit_after>/* Copyright (C) 2002 <NAME> */

#include "common.h"
#include "ioloop.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "str.h"
#include "mail-storage.h"
#include "commands.h"
#include "mail-search.h"

#include <stdlib.h>

/* max. length of input command line (spec says 512) */
#define MAX_INBUF_SIZE 2048

/* Stop reading input when output buffer has this many bytes. Once the buffer
   size has dropped to half of it, start reading input again. */
#define OUTBUF_THROTTLE_SIZE 4096

/* If we can't send anything for a minute, disconnect the client */
#define CLIENT_OUTPUT_TIMEOUT (60*1000)

/* Disconnect client when it sends too many bad commands in a row */
#define CLIENT_MAX_BAD_COMMANDS 20

/* Disconnect client after idling this many seconds */
#define CLIENT_IDLE_TIMEOUT (60*30)

extern struct mail_storage_callbacks mail_storage_callbacks;

static struct client *my_client; /* we don't need more than one currently */
static struct timeout *to_idle;

static void client_input(void *context);
static void client_output(void *context);

static int sync_mailbox(struct mailbox *box)
{
	struct mailbox_sync_context *ctx;
        struct mailbox_sync_rec sync_rec;
	struct mailbox_status status;

	ctx = mailbox_sync_init(box, MAILBOX_SYNC_FLAG_FULL_READ);
	while (mailbox_sync_next(ctx, &sync_rec) > 0)
		;
	return mailbox_sync_deinit(ctx, &status);
}

static int init_mailbox(struct client *client)
{
	struct mail_search_arg search_arg;
        struct mailbox_transaction_context *t;
	struct mail_search_context *ctx;
	struct mail *mail;
	struct mailbox_status status;
	int i, failed;

	memset(&search_arg, 0, sizeof(search_arg));
	search_arg.type = SEARCH_ALL;

	for (i = 0; i < 2; i++) {
		if (sync_mailbox(client->mailbox) < 0) {
			client_send_storage_error(client);
			return FALSE;
		}
		if (mailbox_get_status(client->mailbox, STATUS_MESSAGES,
				       &status) < 0) {
			client_send_storage_error(client);
			return FALSE;
		}

		client->last_seen = 0;
		client->messages_count = status.messages;
		client->total_size = 0;
		client->deleted_size = 0;

		if (client->messages_count == 0)
			return TRUE;

		i_free(client->message_sizes);
		client->message_sizes = i_new(uoff_t, client->messages_count);

		t = mailbox_transaction_begin(client->mailbox, FALSE);
		ctx = mailbox_search_init(t, NULL, &search_arg, NULL,
					  MAIL_FETCH_VIRTUAL_SIZE, NULL);
		if (ctx == NULL) {
			client_send_storage_error(client);
                        mailbox_transaction_rollback(t);
			return FALSE;
		}

		failed = FALSE;
		while ((mail = mailbox_search_next(ctx)) != NULL) {
			uoff_t size = mail->get_virtual_size(mail);
			const struct mail_full_flags *flags;

			flags = mail->get_flags(mail);

			if (flags == NULL || size == (uoff_t)-1) {
				failed = TRUE;
				break;
			}

			if ((flags->flags & MAIL_SEEN) != 0)
				client->last_seen = mail->seq;
                        client->total_size += size;

			i_assert(mail->seq <= client->messages_count);
			client->message_sizes[mail->seq-1] = size;
		}

		if (mailbox_search_deinit(ctx) < 0) {
			client_send_storage_error(client);
                        mailbox_transaction_rollback(t);
			return FALSE;
		}

		if (!failed) {
			mailbox_transaction_commit(t, 0);
			return TRUE;
		}

		/* well, sync and try again */
		mailbox_transaction_rollback(t);
	}

	client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox.");
	return FALSE;
}

struct client *client_create(int hin, int hout, struct mail_storage *storage)
{
	struct client *client;
        enum mailbox_open_flags flags;
	int syntax_error;

	/* always use nonblocking I/O */
	net_set_nonblock(hin, TRUE);
	net_set_nonblock(hout, TRUE);

	client = i_new(struct client, 1);
	client->input = i_stream_create_file(hin, default_pool,
					     MAX_INBUF_SIZE, FALSE);
	client->output = o_stream_create_file(hout, default_pool,
					      (size_t)-1, FALSE);
	o_stream_set_flush_callback(client->output, client_output, client);

	client->io = io_add(hin, IO_READ, client_input, client);
        client->last_input = ioloop_time;
	client->storage = storage;

	mail_storage_set_callbacks(storage, &mail_storage_callbacks, client);

	flags = 0;
	if (getenv("POP3_MAILS_KEEP_RECENT") != NULL)
		flags |= MAILBOX_OPEN_KEEP_RECENT;
	client->mailbox = mailbox_open(storage, "INBOX", flags);
	if (client->mailbox == NULL) {
		i_error("Couldn't open INBOX: %s",
			mail_storage_get_last_error(storage, &syntax_error));
		client_send_line(client, "-ERR No INBOX for user.");
		client_destroy(client);
		return NULL;
	}

	if (!init_mailbox(client)) {
		client_destroy(client);
		return NULL;
	}

	i_assert(my_client == NULL);
	my_client = client;

	if (hook_client_created != NULL)
		hook_client_created(&client);
	return client;
}

void client_destroy(struct client *client)
{
	if (client->cmd != NULL) {
		/* deinitialize command */
		i_stream_close(client->input);
		o_stream_close(client->output);
		client->cmd(client);
		i_assert(client->cmd == NULL);
	}
	if (client->mailbox != NULL)
		mailbox_close(client->mailbox);
	mail_storage_destroy(client->storage);

	i_free(client->message_sizes);
	i_free(client->deleted_bitmask);

	if (client->io != NULL)
		io_remove(client->io);
{'fraction_non_alphanumeric': 0.12083811710677382, 'fraction_numerical': 0.008802143130501339, 'mean_word_length': 4.292658227848102, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 90, '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': '870933', 'n_tokens_mistral': 3970, 'n_tokens_neox': 3610, 'n_words': 839}