summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/lib-sieve/sieve-execute.c
blob: a395cc6becff05b5de95fa17a06f09150ee40176 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
 */

#include "lib.h"

#include "sieve-execute.h"

struct sieve_execute_state {
	void *dup_trans;
};

struct event_category event_category_sieve_execute = {
	.parent = &event_category_sieve,
	.name = "sieve-execute",
};

static struct sieve_execute_state *
sieve_execute_state_create(struct sieve_execute_env *eenv)
{
	return p_new(eenv->pool, struct sieve_execute_state, 1);
}

static void
sieve_execute_state_free(struct sieve_execute_state **_estate,
			 struct sieve_execute_env *eenv)
{
	struct sieve_execute_state *estate = *_estate;
	const struct sieve_script_env *senv = eenv->scriptenv;

	*_estate = NULL;

	if (senv->duplicate_transaction_rollback != NULL)
		senv->duplicate_transaction_rollback(&estate->dup_trans);
}

void sieve_execute_init(struct sieve_execute_env *eenv,
			struct sieve_instance *svinst, pool_t pool,
			const struct sieve_message_data *msgdata,
			const struct sieve_script_env *senv,
			enum sieve_execute_flags flags)
{
	i_zero(eenv);
	eenv->svinst = svinst;
	eenv->pool = pool;
	eenv->flags = flags;
	eenv->msgdata = msgdata;
	eenv->scriptenv = senv;

	pool_ref(pool);
	eenv->event = event_create(svinst->event);
	event_add_category(eenv->event, &event_category_sieve_execute);
	event_add_str(eenv->event, "message_id", msgdata->id);
	if ((flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0) {
		/* Make sure important envelope fields are available */
		event_add_str(eenv->event, "mail_from",
			smtp_address_encode(msgdata->envelope.mail_from));
		event_add_str(eenv->event, "rcpt_to",
			smtp_address_encode(msgdata->envelope.rcpt_to));
	}

	eenv->state = sieve_execute_state_create(eenv);

	eenv->exec_status = senv->exec_status;
	if (eenv->exec_status == NULL)
		eenv->exec_status = p_new(pool, struct sieve_exec_status, 1);
	else
		i_zero(eenv->exec_status);
}

void sieve_execute_finish(struct sieve_execute_env *eenv, int status)
{
	const struct sieve_script_env *senv = eenv->scriptenv;

	if (status == SIEVE_EXEC_OK) {
		if (senv->duplicate_transaction_commit != NULL) {
			senv->duplicate_transaction_commit(
				&eenv->state->dup_trans);
		}
	} else {
		if (senv->duplicate_transaction_rollback != NULL) {
			senv->duplicate_transaction_rollback(
				&eenv->state->dup_trans);
		}
	}
}

void sieve_execute_deinit(struct sieve_execute_env *eenv)
{
	sieve_execute_state_free(&eenv->state, eenv);
	event_unref(&eenv->event);
	pool_unref(&eenv->pool);
}

/*
 * Checking for duplicates
 */

static void *
sieve_execute_get_dup_transaction(const struct sieve_execute_env *eenv)
{
	const struct sieve_script_env *senv = eenv->scriptenv;

	if (senv->duplicate_transaction_begin == NULL)
		return NULL;
	if (eenv->state->dup_trans == NULL) {
		eenv->state->dup_trans =
			senv->duplicate_transaction_begin(senv);
	}
	return eenv->state->dup_trans;
}

bool sieve_execute_duplicate_check_available(
	const struct sieve_execute_env *eenv)
{
	const struct sieve_script_env *senv = eenv->scriptenv;

	return (senv->duplicate_transaction_begin != NULL);
}

int sieve_execute_duplicate_check(const struct sieve_execute_env *eenv,
				  const void *id, size_t id_size,
				  bool *duplicate_r)
{
	const struct sieve_script_env *senv = eenv->scriptenv;
	void *dup_trans = sieve_execute_get_dup_transaction(eenv);
	int ret;

	*duplicate_r = FALSE;

	if (senv->duplicate_check == NULL)
		return SIEVE_EXEC_OK;

	e_debug(eenv->svinst->event, "Check duplicate ID");

	ret = senv->duplicate_check(dup_trans, senv, id, id_size);
	switch (ret) {
	case SIEVE_DUPLICATE_CHECK_RESULT_EXISTS:
		*duplicate_r = TRUE;
		break;
	case SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND:
		break;
	case SIEVE_DUPLICATE_CHECK_RESULT_FAILURE:
		return SIEVE_EXEC_FAILURE;
	case SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE:
		return SIEVE_EXEC_TEMP_FAILURE;
	}
	return SIEVE_EXEC_OK;
}

void sieve_execute_duplicate_mark(const struct sieve_execute_env *eenv,
				  const void *id, size_t id_size, time_t time)
{
	const struct sieve_script_env *senv = eenv->scriptenv;
	void *dup_trans = sieve_execute_get_dup_transaction(eenv);

	if (senv->duplicate_mark == NULL)
		return;

	e_debug(eenv->svinst->event, "Mark ID as duplicate");

	senv->duplicate_mark(dup_trans, senv, id, id_size, time);
}