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

#include "lib.h"
#include "module-dir.h"
#include "str.h"
#include "hash.h"
#include "dict.h"
#include "imap-match.h"
#include "expire-set.h"
#include "mail-search.h"
#include "doveadm-settings.h"
#include "doveadm-mail.h"

#define DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(obj) \
	MODULE_CONTEXT(obj, doveadm_expire_mail_cmd_module)

struct expire_query {
	const char *mailbox;
	struct imap_match_glob *glob;
	time_t before_time;
};

struct doveadm_expire_mail_cmd_context {
	union doveadm_mail_cmd_module_context module_ctx;

	struct dict *dict;
	struct dict_transaction_context *trans;
	struct dict_iterate_context *iter;

	struct hash_table *seen_users;
	ARRAY_DEFINE(queries, struct expire_query);
	time_t oldest_before_time;
};

const char *doveadm_expire_plugin_version = DOVECOT_VERSION;

void doveadm_expire_plugin_init(struct module *module);
void doveadm_expire_plugin_deinit(void);

static MODULE_CONTEXT_DEFINE_INIT(doveadm_expire_mail_cmd_module,
				  &doveadm_mail_cmd_module_register);
static void (*next_hook_doveadm_mail_init)(struct doveadm_mail_cmd_context *ctx);

static bool
doveadm_expire_mail_match_mailbox(struct doveadm_expire_mail_cmd_context *ectx,
				  const char *mailbox, time_t oldest_savedate)
{
	const struct expire_query *query;

	array_foreach(&ectx->queries, query) {
		if (oldest_savedate >= query->before_time)
			continue;

		if (query->glob == NULL) {
			if (strcmp(query->mailbox, mailbox) == 0)
				return TRUE;
		} else {
			if (imap_match(query->glob, mailbox) == IMAP_MATCH_YES)
				return TRUE;
		}
	}
	return FALSE;
}

static bool
doveadm_expire_mail_want(struct doveadm_mail_cmd_context *ctx,
			 const char *key, time_t stamp, const char **username_r)
{
	struct doveadm_expire_mail_cmd_context *ectx =
		DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx);
	const char *username, *mailbox;
	char *username_dup;

	/* key = DICT_EXPIRE_PREFIX<user>/<mailbox> */
	username = key + strlen(DICT_EXPIRE_PREFIX);
	mailbox = strchr(username, '/');
	if (mailbox == NULL) {
		/* invalid record, ignore */
		return FALSE;
	}
	username = t_strdup_until(username, mailbox++);

	if (hash_table_lookup(ectx->seen_users, username) != NULL) {
		/* seen this user already, skip the record */
		return FALSE;
	}

	if (!doveadm_expire_mail_match_mailbox(ectx, mailbox, stamp)) {
		/* this mailbox doesn't have any matching messages */
		return FALSE;
	}
	username_dup = p_strdup(ctx->pool, username);
	hash_table_insert(ectx->seen_users, username_dup, username_dup);

	*username_r = username_dup;
	return TRUE;
}

static int
doveadm_expire_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx,
				      const char **username_r)
{
	struct doveadm_expire_mail_cmd_context *ectx =
		DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx);
	const char *key, *value;
	unsigned long stamp;
	bool ret;

	while (dict_iterate(ectx->iter, &key, &value)) {
		if (str_to_ulong(value, &stamp) < 0) {
			/* invalid record */
			continue;
		}
		if ((time_t)stamp > ectx->oldest_before_time)
			break;

		T_BEGIN {
			ret = doveadm_expire_mail_want(ctx, key, stamp,<commit_msg>doveadm expire: Added more error and debug messages.<commit_after>/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "module-dir.h"
#include "str.h"
#include "hash.h"
#include "dict.h"
#include "imap-match.h"
#include "expire-set.h"
#include "mail-search.h"
#include "doveadm-settings.h"
#include "doveadm-mail.h"

#define DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(obj) \
	MODULE_CONTEXT(obj, doveadm_expire_mail_cmd_module)

struct expire_query {
	const char *mailbox;
	struct imap_match_glob *glob;
	time_t before_time;
};

struct doveadm_expire_mail_cmd_context {
	union doveadm_mail_cmd_module_context module_ctx;

	struct dict *dict;
	struct dict_transaction_context *trans;
	struct dict_iterate_context *iter;

	struct hash_table *seen_users;
	ARRAY_DEFINE(queries, struct expire_query);
	time_t oldest_before_time;
};

const char *doveadm_expire_plugin_version = DOVECOT_VERSION;

void doveadm_expire_plugin_init(struct module *module);
void doveadm_expire_plugin_deinit(void);

static MODULE_CONTEXT_DEFINE_INIT(doveadm_expire_mail_cmd_module,
				  &doveadm_mail_cmd_module_register);
static void (*next_hook_doveadm_mail_init)(struct doveadm_mail_cmd_context *ctx);

static bool
doveadm_expire_mail_match_mailbox(struct doveadm_expire_mail_cmd_context *ectx,
				  const char *mailbox, time_t oldest_savedate)
{
	const struct expire_query *query;

	array_foreach(&ectx->queries, query) {
		if (oldest_savedate >= query->before_time)
			continue;

		if (query->glob == NULL) {
			if (strcmp(query->mailbox, mailbox) == 0)
				return TRUE;
		} else {
			if (imap_match(query->glob, mailbox) == IMAP_MATCH_YES)
				return TRUE;
		}
	}
	return FALSE;
}

static bool
doveadm_expire_mail_want(struct doveadm_mail_cmd_context *ctx,
			 const char *key, time_t oldest_savedate,
			 const char **username_r)
{
	struct doveadm_expire_mail_cmd_context *ectx =
		DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx);
	const char *username, *mailbox;
	char *username_dup;

	/* key = DICT_EXPIRE_PREFIX<user>/<mailbox> */
	username = key + strlen(DICT_EXPIRE_PREFIX);
	mailbox = strchr(username, '/');
	if (mailbox == NULL) {
		/* invalid record, ignore */
		i_error("expire: Invalid key: %s", key);
		return FALSE;
	}
	username = t_strdup_until(username, mailbox++);

	if (hash_table_lookup(ectx->seen_users, username) != NULL) {
		/* seen this user already, skip the record */
		return FALSE;
	}

	if (!doveadm_expire_mail_match_mailbox(ectx, mailbox,
					       oldest_savedate)) {
		/* this mailbox doesn't have any matching messages */
		return FALSE;
	}
	username_dup = p_strdup(ctx->pool, username);
	hash_table_insert(ectx->seen_users, username_dup, username_dup);

	*username_r = username_dup;
	return TRUE;
}

static int
doveadm_expire_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx,
				      const char **username_r)
{
	struct doveadm_expire_mail_cmd_context *ectx =
		DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx);
	const char *key, *value;
	unsigned long oldest_savedate;
	bool ret;

	while (dict_iterate(ectx->iter, &key, &value)) {
		if (str_to_ulong(value, &oldest_savedate) < 0) {
			/* invalid record */
			i_error("expire: Invalid timestamp: %s", value);
			continue;
		}
		if ((time_t)oldest_savedate > ectx->oldest_before_time) {
			if (doveadm_debug) {
				i_debug("expire: Stopping iteration on key %s "
					"(%lu > %ld)", key, oldest_savedate,
					(long)ectx->oldest_before_time);
			}
			break;
		}

		T_BEGIN {
			ret = doveadm_expire_mail_want(ctx, key,
						       oldest_savedate,
{'fraction_non_alphanumeric': 0.10803945008965929, 'fraction_numerical': 0.002988643156007173, 'mean_word_length': 5.308199811498587, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 33, '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': '5756052', 'n_tokens_mistral': 2701, 'n_tokens_neox': 2477, 'n_words': 511}