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

#include "lib.h"
#include "array.h"
#include "istream.h"
#include "home-expand.h"
#include "mail-search.h"
#include "quota-private.h"
#include "quota-plugin.h"
#include "trash-plugin.h"

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define INIT_TRASH_MAILBOX_COUNT 4
#define MAX_RETRY_COUNT 3

struct trash_mailbox {
	const char *name;
	int priority; /* lower number = higher priority */

	struct mail_storage *storage;

	/* temporarily set while cleaning: */
	struct mailbox *box;
	struct mailbox_transaction_context *trans;
        struct mail_search_arg search_arg;
	struct mail_search_context *search_ctx;
	struct mail *mail;

	unsigned int mail_set:1;
};

const char *trash_plugin_version = PACKAGE_VERSION;

static int (*trash_next_quota_test_alloc)(struct quota_transaction_context *,
					  uoff_t, bool *);

static pool_t config_pool;
/* trash_boxes ordered by priority, highest first */
static ARRAY_DEFINE(trash_boxes, struct trash_mailbox);

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

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

static int trash_clean_mailbox_open(struct trash_mailbox *trash)
{
	trash->box = mailbox_open(trash->storage, trash->name, NULL,
				  MAILBOX_OPEN_KEEP_RECENT);
	if (trash->box == NULL)
		return -1;

	if (sync_mailbox(trash->box) < 0)
		return -1;

	trash->trans = mailbox_transaction_begin(trash->box, 0);

	trash->search_ctx = mailbox_search_init(trash->trans, NULL,
						&trash->search_arg, NULL);
	trash->mail = mail_alloc(trash->trans, MAIL_FETCH_PHYSICAL_SIZE |
				 MAIL_FETCH_RECEIVED_DATE, NULL);

	return mailbox_search_next(trash->search_ctx, trash->mail);
}

static int trash_clean_mailbox_get_next(struct trash_mailbox *trash,
					time_t *received_time_r)
{
	int ret;

	if (!trash->mail_set) {
		if (trash->box == NULL)
			ret = trash_clean_mailbox_open(trash);
		else
			ret = mailbox_search_next(trash->search_ctx,
						  trash->mail);
		if (ret <= 0)
			return ret;

		trash->mail_set = TRUE;
	}

	*received_time_r = mail_get_received_date(trash->mail);
	return 1;
}

static int trash_try_clean_mails(struct quota_transaction_context *ctx,
				 uint64_t size_needed)
{
	struct trash_mailbox *trashes;
	unsigned int i, j, count, oldest_idx;
	time_t oldest, received;
	uint64_t size, size_expunged = 0, expunged_count = 0;
	int ret = 0;

	trashes = array_get_modifiable(&trash_boxes, &count);
	for (i = 0; i < count; ) {
		if (trashes[i].storage == NULL) {
			/* FIXME: this is really ugly. it'll do however until
			   we get proper namespace support for lib-storage. */
			struct mail_storage *const *storage;

			storage = array_idx(&quota_set->storages, 0);
			trashes[i].storage = *storage;
		}
		/* expunge oldest mails first in all trash boxes with
		   same priority */
		oldest_idx = count;
		oldest = (time_t)-1;
		for (j = i; j < count; j++) {
			if (trashes[j].priority != trashes[j].priority)
				break;

			ret = trash_clean_mailbox_get_next(&trashes[i],
							   &received);
			if (ret < 0)
				goto __err;
			if (ret > 0) {
				if (oldest == (time_t)-1 ||
				    received < oldest) {
					oldest = received;
					oldest_idx = j;
				}
			}
		}

		if (oldest_idx < count) {
			size = mail_get_physical_size(trashes[oldest_idx].mail);
			if (size == (uoff_t)-1) {
				/* maybe expunged already? */
				trashes[oldest_idx].mail_set = FALSE;
				continue;
			}

			if (mail_expunge(trashes[oldest_idx].mail) < 0)
				break;

			expunged_count++;
			size_expunged += size;
			if (size_expunged >= size_needed)
				break;
			trashes[oldest_idx].mail_set = FALSE;
		} else {<commit_msg>Fixes for handling multiple storages.<commit_after>/* Copyright (C) 2005 <NAME> */

#include "lib.h"
#include "array.h"
#include "istream.h"
#include "home-expand.h"
#include "mail-search.h"
#include "quota-private.h"
#include "quota-plugin.h"
#include "trash-plugin.h"

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define INIT_TRASH_MAILBOX_COUNT 4
#define MAX_RETRY_COUNT 3

struct trash_mailbox {
	const char *name;
	int priority; /* lower number = higher priority */

	struct mail_storage *storage;

	/* temporarily set while cleaning: */
	struct mailbox *box;
	struct mailbox_transaction_context *trans;
        struct mail_search_arg search_arg;
	struct mail_search_context *search_ctx;
	struct mail *mail;

	unsigned int mail_set:1;
};

const char *trash_plugin_version = PACKAGE_VERSION;

static int (*trash_next_quota_test_alloc)(struct quota_transaction_context *,
					  uoff_t, bool *);

static pool_t config_pool;
/* trash_boxes ordered by priority, highest first */
static ARRAY_DEFINE(trash_boxes, struct trash_mailbox);

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

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

static int trash_clean_mailbox_open(struct trash_mailbox *trash)
{
	trash->box = mailbox_open(trash->storage, trash->name, NULL,
				  MAILBOX_OPEN_KEEP_RECENT);
	if (trash->box == NULL)
		return 0;

	if (sync_mailbox(trash->box) < 0)
		return -1;

	trash->trans = mailbox_transaction_begin(trash->box, 0);

	trash->search_ctx = mailbox_search_init(trash->trans, NULL,
						&trash->search_arg, NULL);
	trash->mail = mail_alloc(trash->trans, MAIL_FETCH_PHYSICAL_SIZE |
				 MAIL_FETCH_RECEIVED_DATE, NULL);

	return mailbox_search_next(trash->search_ctx, trash->mail);
}

static int trash_clean_mailbox_get_next(struct trash_mailbox *trash,
					time_t *received_time_r)
{
	int ret;

	if (!trash->mail_set) {
		if (trash->box == NULL)
			ret = trash_clean_mailbox_open(trash);
		else
			ret = mailbox_search_next(trash->search_ctx,
						  trash->mail);
		if (ret <= 0) {
			*received_time_r = 0;
			return ret;
		}
		trash->mail_set = TRUE;
	}

	*received_time_r = mail_get_received_date(trash->mail);
	return 1;
}

static int trash_try_clean_mails(struct quota_transaction_context *ctx,
				 uint64_t size_needed)
{
	struct trash_mailbox *trashes;
	unsigned int i, j, count, oldest_idx;
	time_t oldest, received;
	uint64_t size, size_expunged = 0, expunged_count = 0;
	int ret = 0;

	trashes = array_get_modifiable(&trash_boxes, &count);
	for (i = 0; i < count; ) {
		/* expunge oldest mails first in all trash boxes with
		   same priority */
		oldest_idx = count;
		oldest = (time_t)-1;
		for (j = i; j < count; j++) {
			if (trashes[j].priority != trashes[j].priority)
				break;

			if (trashes[j].storage == NULL) {
				/* FIXME: this is really ugly. it'll do however
				   until we get proper namespace support for
				   lib-storage. */
				struct mail_storage *const *storage;

				storage = array_idx(&quota_set->storages, 0);
				trashes[j].storage = *storage;
			}

			ret = trash_clean_mailbox_get_next(&trashes[j],
							   &received);
			if (ret < 0)
				goto __err;
			if (ret > 0) {
				if (oldest == (time_t)-1 || received < oldest) {
					oldest = received;
					oldest_idx = j;
				}
			}
		}

		if (oldest_idx < count) {
			size = mail_get_physical_size(trashes[oldest_idx].mail);
			if (size == (uoff_t)-1) {
				/* maybe expunged already? */
				trashes[oldest_idx].mail_set = FALSE;
				continue;
			}

			if (mail_expunge(trashes[oldest_idx].mail) < 0)
				break;

			expunged_count++;
			size_expunged += size;
			if (size_expunged >= size_needed)
				break;
			trashes[oldest_idx].mail_set = FALSE;
		} else {
{'fraction_non_alphanumeric': 0.12080624187256177, 'fraction_numerical': 0.007932379713914174, 'mean_word_length': 4.003903708523097, 'pattern_counts': {'":': 0, '<': 27, '<?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': '224971', 'n_tokens_mistral': 3230, 'n_tokens_neox': 2836, 'n_words': 642}