1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include "lib.h"
5 
6 #include "sieve-execute.h"
7 
8 struct sieve_execute_state {
9 	void *dup_trans;
10 };
11 
12 struct event_category event_category_sieve_execute = {
13 	.parent = &event_category_sieve,
14 	.name = "sieve-execute",
15 };
16 
17 static struct sieve_execute_state *
sieve_execute_state_create(struct sieve_execute_env * eenv)18 sieve_execute_state_create(struct sieve_execute_env *eenv)
19 {
20 	return p_new(eenv->pool, struct sieve_execute_state, 1);
21 }
22 
23 static void
sieve_execute_state_free(struct sieve_execute_state ** _estate,struct sieve_execute_env * eenv)24 sieve_execute_state_free(struct sieve_execute_state **_estate,
25 			 struct sieve_execute_env *eenv)
26 {
27 	struct sieve_execute_state *estate = *_estate;
28 	const struct sieve_script_env *senv = eenv->scriptenv;
29 
30 	*_estate = NULL;
31 
32 	if (senv->duplicate_transaction_rollback != NULL)
33 		senv->duplicate_transaction_rollback(&estate->dup_trans);
34 }
35 
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)36 void sieve_execute_init(struct sieve_execute_env *eenv,
37 			struct sieve_instance *svinst, pool_t pool,
38 			const struct sieve_message_data *msgdata,
39 			const struct sieve_script_env *senv,
40 			enum sieve_execute_flags flags)
41 {
42 	i_zero(eenv);
43 	eenv->svinst = svinst;
44 	eenv->pool = pool;
45 	eenv->flags = flags;
46 	eenv->msgdata = msgdata;
47 	eenv->scriptenv = senv;
48 
49 	pool_ref(pool);
50 	eenv->event = event_create(svinst->event);
51 	event_add_category(eenv->event, &event_category_sieve_execute);
52 	event_add_str(eenv->event, "message_id", msgdata->id);
53 	if ((flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0) {
54 		/* Make sure important envelope fields are available */
55 		event_add_str(eenv->event, "mail_from",
56 			smtp_address_encode(msgdata->envelope.mail_from));
57 		event_add_str(eenv->event, "rcpt_to",
58 			smtp_address_encode(msgdata->envelope.rcpt_to));
59 	}
60 
61 	eenv->state = sieve_execute_state_create(eenv);
62 
63 	eenv->exec_status = senv->exec_status;
64 	if (eenv->exec_status == NULL)
65 		eenv->exec_status = p_new(pool, struct sieve_exec_status, 1);
66 	else
67 		i_zero(eenv->exec_status);
68 }
69 
sieve_execute_finish(struct sieve_execute_env * eenv,int status)70 void sieve_execute_finish(struct sieve_execute_env *eenv, int status)
71 {
72 	const struct sieve_script_env *senv = eenv->scriptenv;
73 
74 	if (status == SIEVE_EXEC_OK) {
75 		if (senv->duplicate_transaction_commit != NULL) {
76 			senv->duplicate_transaction_commit(
77 				&eenv->state->dup_trans);
78 		}
79 	} else {
80 		if (senv->duplicate_transaction_rollback != NULL) {
81 			senv->duplicate_transaction_rollback(
82 				&eenv->state->dup_trans);
83 		}
84 	}
85 }
86 
sieve_execute_deinit(struct sieve_execute_env * eenv)87 void sieve_execute_deinit(struct sieve_execute_env *eenv)
88 {
89 	sieve_execute_state_free(&eenv->state, eenv);
90 	event_unref(&eenv->event);
91 	pool_unref(&eenv->pool);
92 }
93 
94 /*
95  * Checking for duplicates
96  */
97 
98 static void *
sieve_execute_get_dup_transaction(const struct sieve_execute_env * eenv)99 sieve_execute_get_dup_transaction(const struct sieve_execute_env *eenv)
100 {
101 	const struct sieve_script_env *senv = eenv->scriptenv;
102 
103 	if (senv->duplicate_transaction_begin == NULL)
104 		return NULL;
105 	if (eenv->state->dup_trans == NULL) {
106 		eenv->state->dup_trans =
107 			senv->duplicate_transaction_begin(senv);
108 	}
109 	return eenv->state->dup_trans;
110 }
111 
sieve_execute_duplicate_check_available(const struct sieve_execute_env * eenv)112 bool sieve_execute_duplicate_check_available(
113 	const struct sieve_execute_env *eenv)
114 {
115 	const struct sieve_script_env *senv = eenv->scriptenv;
116 
117 	return (senv->duplicate_transaction_begin != NULL);
118 }
119 
sieve_execute_duplicate_check(const struct sieve_execute_env * eenv,const void * id,size_t id_size,bool * duplicate_r)120 int sieve_execute_duplicate_check(const struct sieve_execute_env *eenv,
121 				  const void *id, size_t id_size,
122 				  bool *duplicate_r)
123 {
124 	const struct sieve_script_env *senv = eenv->scriptenv;
125 	void *dup_trans = sieve_execute_get_dup_transaction(eenv);
126 	int ret;
127 
128 	*duplicate_r = FALSE;
129 
130 	if (senv->duplicate_check == NULL)
131 		return SIEVE_EXEC_OK;
132 
133 	e_debug(eenv->svinst->event, "Check duplicate ID");
134 
135 	ret = senv->duplicate_check(dup_trans, senv, id, id_size);
136 	switch (ret) {
137 	case SIEVE_DUPLICATE_CHECK_RESULT_EXISTS:
138 		*duplicate_r = TRUE;
139 		break;
140 	case SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND:
141 		break;
142 	case SIEVE_DUPLICATE_CHECK_RESULT_FAILURE:
143 		return SIEVE_EXEC_FAILURE;
144 	case SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE:
145 		return SIEVE_EXEC_TEMP_FAILURE;
146 	}
147 	return SIEVE_EXEC_OK;
148 }
149 
sieve_execute_duplicate_mark(const struct sieve_execute_env * eenv,const void * id,size_t id_size,time_t time)150 void sieve_execute_duplicate_mark(const struct sieve_execute_env *eenv,
151 				  const void *id, size_t id_size, time_t time)
152 {
153 	const struct sieve_script_env *senv = eenv->scriptenv;
154 	void *dup_trans = sieve_execute_get_dup_transaction(eenv);
155 
156 	if (senv->duplicate_mark == NULL)
157 		return;
158 
159 	e_debug(eenv->svinst->event, "Mark ID as duplicate");
160 
161 	senv->duplicate_mark(dup_trans, senv, id, id_size, time);
162 }
163