diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c index f2cc0ece24bed7e71cb992f93765a1e49688c36e..25d2c162728d4960f3edad0bce6446c8749608de 100644 --- a/src/lib-sieve/cmd-redirect.c +++ b/src/lib-sieve/cmd-redirect.c @@ -559,8 +559,7 @@ act_redirect_execute(const struct sieve_action_exec_env *aenv, struct mail *mail = (action->mail != NULL ? action->mail : sieve_message_get_mail(msgctx)); const struct sieve_message_data *msgdata = eenv->msgdata; - const struct sieve_script_env *senv = eenv->scriptenv; - bool loop_detected = FALSE; + bool duplicate, loop_detected = FALSE; int ret; /* @@ -583,8 +582,19 @@ act_redirect_execute(const struct sieve_action_exec_env *aenv, i_assert(trans->dupeid != NULL); /* Check whether we've seen this message before */ - if (sieve_action_duplicate_check(senv, trans->dupeid, - strlen(trans->dupeid))) { + ret = sieve_action_duplicate_check(aenv, trans->dupeid, + strlen(trans->dupeid), + &duplicate); + if (ret < SIEVE_EXEC_OK) { + sieve_result_critical( + aenv, "failed to check for duplicate forward", + "failed to check for duplicate forward to <%s>%s", + smtp_address_encode(ctx->to_address), + (ret == SIEVE_EXEC_TEMP_FAILURE ? + " (temporaty failure)" : "")); + return ret; + } + if (duplicate) { sieve_result_global_log( aenv, "discarded duplicate forward to <%s>", smtp_address_encode(ctx->to_address)); @@ -624,7 +634,6 @@ act_redirect_commit(const struct sieve_action_exec_env *aenv, void *tr_context) struct mail *mail = (action->mail != NULL ? action->mail : sieve_message_get_mail(msgctx)); struct act_redirect_transaction *trans = tr_context; - const struct sieve_script_env *senv = eenv->scriptenv; int ret; if (trans->skip_redirect) @@ -639,7 +648,7 @@ act_redirect_commit(const struct sieve_action_exec_env *aenv, void *tr_context) /* Mark this message id as forwarded to the specified destination */ sieve_action_duplicate_mark( - senv, trans->dupeid, strlen(trans->dupeid), + aenv, trans->dupeid, strlen(trans->dupeid), ioloop_time + svinst->redirect_duplicate_period); eenv->exec_status->significant_action_executed = TRUE; diff --git a/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c b/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c index 7f10560c2240c8d8d0fc206aa3dd69b8c88631f1..c4e9159b3f1438c15c4cb294e2fd22e859474c03 100644 --- a/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c +++ b/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c @@ -109,7 +109,6 @@ act_duplicate_mark_finish(const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, int status) { const struct sieve_execute_env *eenv = aenv->exec_env; - const struct sieve_script_env *senv = eenv->scriptenv; struct act_duplicate_mark_data *data = (struct act_duplicate_mark_data *)aenv->action->context; @@ -120,7 +119,7 @@ act_duplicate_mark_finish(const struct sieve_action_exec_env *aenv, * message. */ eenv->exec_status->significant_action_executed = TRUE; - sieve_action_duplicate_mark(senv, data->hash, sizeof(data->hash), + sieve_action_duplicate_mark(aenv, data->hash, sizeof(data->hash), ioloop_time + data->period); } @@ -168,11 +167,10 @@ ext_duplicate_hash(string_t *handle, const char *value, size_t value_len, int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, const char *value, size_t value_len, - sieve_number_t period, bool last) + sieve_number_t period, bool last, bool *duplicate_r) { const struct sieve_execute_env *eenv = renv->exec_env; const struct sieve_extension *this_ext = renv->oprtn->ext; - const struct sieve_script_env *senv = eenv->scriptenv; struct ext_duplicate_context *rctx; bool duplicate = FALSE; pool_t msg_pool = NULL, result_pool = NULL; @@ -180,16 +178,19 @@ int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, struct ext_duplicate_hash *hash_record = NULL; struct ext_duplicate_handle *handle_record = NULL; struct act_duplicate_mark_data *act; + int ret; - if (!sieve_action_duplicate_check_available(senv)) { + *duplicate_r = FALSE; + + if (!sieve_execute_duplicate_check_available(eenv)) { sieve_runtime_warning( renv, NULL, "duplicate test: " "duplicate checking not available in this context"); - return 0; + return SIEVE_EXEC_OK; } if (value == NULL) - return 0; + return SIEVE_EXEC_OK; /* Create hash */ ext_duplicate_hash(handle, value, value_len, last, hash); @@ -221,7 +222,9 @@ int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, (handle == NULL ? NULL : str_c(handle)); if (null_strcmp(rhandle->handle, handle_str) == 0 && rhandle->last == last) - return (rhandle->duplicate ? 1 : 0); + return (rhandle->duplicate ? + SIEVE_DUPLICATE_CHECK_RESULT_EXISTS : + SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND); } } @@ -234,15 +237,25 @@ int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, act->last = last; /* Check duplicate */ - duplicate = sieve_action_duplicate_check(senv, hash, sizeof(hash)); - if (!duplicate && last) { + ret = sieve_execute_duplicate_check(eenv, hash, sizeof(hash), + &duplicate); + if (ret >= SIEVE_EXEC_OK && !duplicate && last) { unsigned char no_last_hash[MD5_RESULTLEN]; /* Check for entry without :last */ ext_duplicate_hash(handle, value, value_len, FALSE, no_last_hash); - sieve_action_duplicate_check(senv, no_last_hash, - sizeof(no_last_hash)); + ret = sieve_execute_duplicate_check( + eenv, no_last_hash, sizeof(no_last_hash), + &duplicate); + } + if (ret < SIEVE_EXEC_OK) { + sieve_runtime_critical( + renv, NULL, "failed to check for duplicate", + "failed to check for duplicate%s", + (ret == SIEVE_EXEC_TEMP_FAILURE ? + " (temporary failure)" : "")); + return ret; } /* We may only mark the message as duplicate when Sieve script executes @@ -253,7 +266,7 @@ int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, if (sieve_result_add_action(renv, NULL, NULL, &act_duplicate_mark, NULL, (void *) act, 0, FALSE) < 0) - return -1; + return SIEVE_EXEC_FAILURE; } /* Cache result */ @@ -273,6 +286,8 @@ int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, handle_record->last = last; handle_record->duplicate = duplicate; - return ( duplicate ? 1 : 0 ); + *duplicate_r = duplicate; + + return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h b/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h index 0bbb6b5a372520d4695345a526a41702ea9571aa..c802b0856da7d074ab635c0146682aa3612a3cd8 100644 --- a/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h +++ b/src/lib-sieve/plugins/duplicate/ext-duplicate-common.h @@ -36,6 +36,6 @@ extern const struct sieve_operation_def tst_duplicate_operation; int ext_duplicate_check(const struct sieve_runtime_env *renv, string_t *handle, const char *value, size_t value_len, - sieve_number_t period, bool last); + sieve_number_t period, bool last, bool *duplicate_r); #endif diff --git a/src/lib-sieve/plugins/duplicate/tst-duplicate.c b/src/lib-sieve/plugins/duplicate/tst-duplicate.c index 2a000de2bd960eff01a6b5aa9282730ba223a4a4..d211e0411d18755dc205aa84f3e022fb522c834d 100644 --- a/src/lib-sieve/plugins/duplicate/tst-duplicate.c +++ b/src/lib-sieve/plugins/duplicate/tst-duplicate.c @@ -428,10 +428,10 @@ tst_duplicate_operation_execute(const struct sieve_runtime_env *renv, if (val == NULL) { duplicate = FALSE; } else { - if ((ret = ext_duplicate_check(renv, handle, val, val_len, - seconds, last)) < 0) - return SIEVE_EXEC_FAILURE; - duplicate = (ret > 0); + ret = ext_duplicate_check(renv, handle, val, val_len, + seconds, last, &duplicate); + if (ret < SIEVE_EXEC_OK) + return ret; } /* Trace */ diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c index 4367e64d0cc879b4aa367a81f8069471fdde2d37..ddc14be3b036ae9eb3f07dbe74ec0de341b8d347 100644 --- a/src/lib-sieve/plugins/vacation/cmd-vacation.c +++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c @@ -1233,7 +1233,6 @@ act_vacation_commit(const struct sieve_action_exec_env *aenv, struct sieve_instance *svinst = eenv->svinst; const struct ext_vacation_config *config = (const struct ext_vacation_config *)ext->context; - const struct sieve_script_env *senv = eenv->scriptenv; struct act_vacation_context *ctx = (struct act_vacation_context *)action->context; unsigned char dupl_hash[MD5_RESULTLEN]; @@ -1302,12 +1301,23 @@ act_vacation_commit(const struct sieve_action_exec_env *aenv, } /* Did whe respond to this user before? */ - if (sieve_action_duplicate_check_available(senv)) { + if (sieve_action_duplicate_check_available(aenv)) { + bool duplicate; + act_vacation_hash(ctx, smtp_address_encode(sender), dupl_hash); - if (sieve_action_duplicate_check(senv, dupl_hash, - sizeof(dupl_hash))) - { + ret = sieve_action_duplicate_check(aenv, dupl_hash, + sizeof(dupl_hash), + &duplicate); + if (ret < SIEVE_EXEC_OK) { + sieve_result_critical( + aenv, "failed to check for duplicate vacation response", + "failed to check for duplicate vacation response%s", + (ret == SIEVE_EXEC_TEMP_FAILURE ? + " (temporaty failure)" : "")); + return ret; + } + if (duplicate) { sieve_result_global_log( aenv, "discarded duplicate vacation response to <%s>", @@ -1554,7 +1564,7 @@ act_vacation_commit(const struct sieve_action_exec_env *aenv, /* Mark as replied */ if (seconds > 0) { - sieve_action_duplicate_mark(senv, dupl_hash, + sieve_action_duplicate_mark(aenv, dupl_hash, sizeof(dupl_hash), ioloop_time + seconds); } diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c index 7c775312ff23b1f27c141bd57b411f963ccf1a0e..86c9954eb8d16a8d12709eae3959d028e3fde854 100644 --- a/src/lib-sieve/sieve-actions.c +++ b/src/lib-sieve/sieve-actions.c @@ -927,39 +927,6 @@ int sieve_act_redirect_add_to_result(const struct sieve_runtime_env *renv, * Action utility functions */ -/* Checking for duplicates */ - -bool sieve_action_duplicate_check_available( - const struct sieve_script_env *senv) -{ - return (senv->duplicate_check != NULL && senv->duplicate_mark != NULL); -} - -bool sieve_action_duplicate_check(const struct sieve_script_env *senv, - const void *id, size_t id_size) -{ - if (senv->duplicate_check == NULL || senv->duplicate_mark == NULL) - return FALSE; - - return senv->duplicate_check(senv, id, id_size); -} - -void sieve_action_duplicate_mark(const struct sieve_script_env *senv, - const void *id, size_t id_size, time_t time) -{ - if (senv->duplicate_check == NULL || senv->duplicate_mark == NULL) - return; - - senv->duplicate_mark(senv, id, id_size, time); -} - -void sieve_action_duplicate_flush(const struct sieve_script_env *senv) -{ - if (senv->duplicate_flush == NULL) - return; - senv->duplicate_flush(senv); -} - /* Rejecting the mail */ static int diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h index e3faa2df3b1d1f6eb9eabfe5fa389fbd32c3944d..f1a447fc3bc245392e9905ca27ed52371394c2dc 100644 --- a/src/lib-sieve/sieve-actions.h +++ b/src/lib-sieve/sieve-actions.h @@ -260,18 +260,40 @@ int sieve_act_redirect_add_to_result(const struct sieve_runtime_env *renv, const struct smtp_address *to_address); /* - * Action utility functions + * Checking for duplicates */ -/* Checking for duplicates */ +static inline bool +sieve_action_duplicate_check_available(const struct sieve_action_exec_env *aenv) +{ + const struct sieve_execute_env *eenv = aenv->exec_env; + + return sieve_execute_duplicate_check_available(eenv); +} + +static inline int +sieve_action_duplicate_check(const struct sieve_action_exec_env *aenv, + const void *id, size_t id_size, + bool *duplicate_r) +{ + const struct sieve_execute_env *eenv = aenv->exec_env; + + return sieve_execute_duplicate_check(eenv, id, id_size, + duplicate_r); +} + +static inline void +sieve_action_duplicate_mark(const struct sieve_action_exec_env *aenv, + const void *id, size_t id_size, time_t time) +{ + const struct sieve_execute_env *eenv = aenv->exec_env; + + return sieve_execute_duplicate_mark(eenv, id, id_size, time); +} -bool sieve_action_duplicate_check_available( - const struct sieve_script_env *senv); -bool sieve_action_duplicate_check(const struct sieve_script_env *senv, - const void *id, size_t id_size); -void sieve_action_duplicate_mark(const struct sieve_script_env *senv, - const void *id, size_t id_size, time_t time); -void sieve_action_duplicate_flush(const struct sieve_script_env *senv); +/* + * Action utility functions + */ /* Rejecting mail */ diff --git a/src/lib-sieve/sieve-execute.c b/src/lib-sieve/sieve-execute.c index 6b7b1cf99c225f126f754a8dc9a39933e0bb4558..a395cc6becff05b5de95fa17a06f09150ee40176 100644 --- a/src/lib-sieve/sieve-execute.c +++ b/src/lib-sieve/sieve-execute.c @@ -5,11 +5,34 @@ #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, @@ -35,6 +58,8 @@ void sieve_execute_init(struct sieve_execute_env *eenv, 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); @@ -42,9 +67,96 @@ void sieve_execute_init(struct sieve_execute_env *eenv, 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); +} diff --git a/src/lib-sieve/sieve-execute.h b/src/lib-sieve/sieve-execute.h index cff050462914f4953d8329b4801217e7dafe396a..8af182b43061b4b1cfe10276145c041f65584f6d 100644 --- a/src/lib-sieve/sieve-execute.h +++ b/src/lib-sieve/sieve-execute.h @@ -3,6 +3,8 @@ #include "sieve-common.h" +struct sieve_execute_state; + struct sieve_execute_env { struct sieve_instance *svinst; pool_t pool; @@ -13,6 +15,7 @@ struct sieve_execute_env { const struct sieve_message_data *msgdata; const struct sieve_script_env *scriptenv; + struct sieve_execute_state *state; struct sieve_exec_status *exec_status; }; @@ -21,6 +24,19 @@ void sieve_execute_init(struct sieve_execute_env *eenv, const struct sieve_message_data *msgdata, const struct sieve_script_env *senv, enum sieve_execute_flags flags); +void sieve_execute_finish(struct sieve_execute_env *eenv, int status); void sieve_execute_deinit(struct sieve_execute_env *eenv); +/* + * Checking for duplicates + */ + +bool sieve_execute_duplicate_check_available( + const struct sieve_execute_env *eenv); +int sieve_execute_duplicate_check(const struct sieve_execute_env *eenv, + const void *id, size_t id_size, + bool *duplicate_r); +void sieve_execute_duplicate_mark(const struct sieve_execute_env *eenv, + const void *id, size_t id_size, time_t time); + #endif diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index effd6f28e823c9e8dbf8144d71b337cd3db0a8ce..447ccee7de22b090dd200e2b477db9acee55ea3b 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -930,7 +930,6 @@ struct sieve_result_execution { struct sieve_action_execution *keep_equiv_action; int keep_status; - bool dup_flushed:1; bool keep_success:1; bool keep_explicit:1; bool keep_implicit:1; @@ -1076,9 +1075,6 @@ static int sieve_result_action_start(struct sieve_result_execution *rexec, struct sieve_action_execution *aexec) { - const struct sieve_action_exec_env *aenv = &rexec->action_env; - const struct sieve_execute_env *eenv = aenv->exec_env; - const struct sieve_script_env *senv = eenv->scriptenv; struct sieve_result_action *rac = aexec->action; struct sieve_action *act = &rac->action; int status = SIEVE_EXEC_OK; @@ -1093,12 +1089,6 @@ sieve_result_action_start(struct sieve_result_execution *rexec, if (act->def == NULL) return status; - if ((act->def->flags & SIEVE_ACTFLAG_MAIL_STORAGE) != 0 && - !rexec->dup_flushed) { - sieve_action_duplicate_flush(senv); - rexec->dup_flushed = TRUE; - } - if (act->def->start != NULL) { sieve_action_execution_pre(rexec, aexec); status = act->def->start(&rexec->action_env, @@ -1753,7 +1743,6 @@ static int sieve_result_transaction_start(struct sieve_result_execution *rexec) e_debug(rexec->event, "Starting execution of actions"); - rexec->dup_flushed = FALSE; aexec = rexec->actions_head; while (status == SIEVE_EXEC_OK && aexec != NULL) { status = sieve_result_action_start(rexec, aexec); diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h index ed51e967a8eef0a162dcca5a8ef22472a84844e2..a9fcadc7a5e6ca6f123ec2e09e6faac69d758813 100644 --- a/src/lib-sieve/sieve-result.h +++ b/src/lib-sieve/sieve-result.h @@ -110,6 +110,9 @@ struct sieve_result_execution * sieve_result_execution_create(struct sieve_result *result, pool_t pool); void sieve_result_execution_destroy(struct sieve_result_execution **_rexec); +void *sieve_result_execution_get_dup_transaction( + struct sieve_result_execution *rexec); + int sieve_result_execute(struct sieve_result_execution *rexec, int status, bool commit, struct sieve_error_handler *ehandler, bool *keep_r); diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index f2e64a4cda3c0786f87c8420c354e99079666e10..439b26ed7c46cd45b0cdb71f71586ec2ce6184ac 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -188,6 +188,17 @@ struct sieve_trace_config { unsigned int flags; }; +/* + * Duplicate checking + */ + +enum sieve_duplicate_check_result { + SIEVE_DUPLICATE_CHECK_RESULT_EXISTS = 1, + SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND = 0, + SIEVE_DUPLICATE_CHECK_RESULT_FAILURE = -1, + SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE = -2, +}; + /* * Script environment * @@ -229,13 +240,17 @@ struct sieve_script_env { const char **error_r); /* Interface for marking and checking duplicates */ - bool (*duplicate_check) - (const struct sieve_script_env *senv, const void *id, size_t id_size); - void (*duplicate_mark) - (const struct sieve_script_env *senv, const void *id, size_t id_size, - time_t time); - void (*duplicate_flush) - (const struct sieve_script_env *senv); + void *(*duplicate_transaction_begin)( + const struct sieve_script_env *senv); + void (*duplicate_transaction_commit)(void **_dup_trans); + void (*duplicate_transaction_rollback)(void **_dup_trans); + + enum sieve_duplicate_check_result + (*duplicate_check)(void *dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size); + void (*duplicate_mark)(void *dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time); /* Interface for rejecting mail */ int (*reject_mail)(const struct sieve_script_env *senv, diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 59ea41766b250449e92a2ddcdea0ac693f2a5342..69827a93765003a6e5eed4b1851a21fef8b6e327 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -671,6 +671,7 @@ int sieve_execute(struct sieve_binary *sbin, /* Cleanup */ if (result != NULL) sieve_result_unref(&result); + sieve_execute_finish(&eenv, ret); sieve_execute_deinit(&eenv); pool_unref(&pool); @@ -934,6 +935,8 @@ int sieve_multiscript_finish(struct sieve_multiscript **_mscript, sieve_execution_exitcode_to_str(status), (mscript->keep ? "yes" : "no")); + sieve_execute_finish(&mscript->exec_env, status); + /* Cleanup */ sieve_multiscript_destroy(&mscript); diff --git a/src/plugins/imap-filter-sieve/imap-filter-sieve.c b/src/plugins/imap-filter-sieve/imap-filter-sieve.c index fe6e4a81e128fcbddab3e85ff5f3bdd78a8a88d6..62519f4c70ccf52a3d3f8cb3e394aaa4b7ce80a0 100644 --- a/src/plugins/imap-filter-sieve/imap-filter-sieve.c +++ b/src/plugins/imap-filter-sieve/imap-filter-sieve.c @@ -627,38 +627,66 @@ imap_filter_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, * Duplicate checking */ -static bool -imap_filter_sieve_duplicate_check(const struct sieve_script_env *senv, - const void *id, size_t id_size) +static void * +imap_filter_sieve_duplicate_transaction_begin( + const struct sieve_script_env *senv) { struct imap_filter_sieve_context *sctx = senv->script_context; struct imap_filter_sieve_user *ifsuser = IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user); - return mail_duplicate_check(ifsuser->dup_db, - id, id_size, senv->user->username); + return mail_duplicate_transaction_begin(ifsuser->dup_db); } -static void -imap_filter_sieve_duplicate_mark(const struct sieve_script_env *senv, - const void *id, size_t id_size, time_t time) +static void imap_filter_sieve_duplicate_transaction_commit(void **_dup_trans) { - struct imap_filter_sieve_context *sctx = senv->script_context; - struct imap_filter_sieve_user *ifsuser = - IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user); + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; - mail_duplicate_mark(ifsuser->dup_db, - id, id_size, senv->user->username, time); + mail_duplicate_transaction_commit(&dup_trans); +} + +static void imap_filter_sieve_duplicate_transaction_rollback(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + + mail_duplicate_transaction_rollback(&dup_trans); +} + +static enum sieve_duplicate_check_result +imap_filter_sieve_duplicate_check(void *_dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + switch (mail_duplicate_check(dup_trans, id, id_size, + senv->user->username)) { + case MAIL_DUPLICATE_CHECK_RESULT_EXISTS: + return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS; + case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND: + return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND; + case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK: + case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT: + return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE; + case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR: + case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS: + break; + } + return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE; } static void -imap_filter_sieve_duplicate_flush(const struct sieve_script_env *senv) +imap_filter_sieve_duplicate_mark(void *_dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time) { - struct imap_filter_sieve_context *sctx = senv->script_context; - struct imap_filter_sieve_user *ifsuser = - IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user); + struct mail_duplicate_transaction *dup_trans = _dup_trans; - mail_duplicate_db_flush(ifsuser->dup_db); + mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time); } /* @@ -943,9 +971,14 @@ int imap_sieve_filter_run_init(struct imap_filter_sieve_context *sctx) scriptenv->smtp_send = imap_filter_sieve_smtp_send; scriptenv->smtp_abort = imap_filter_sieve_smtp_abort; scriptenv->smtp_finish = imap_filter_sieve_smtp_finish; + scriptenv->duplicate_transaction_begin = + imap_filter_sieve_duplicate_transaction_begin; + scriptenv->duplicate_transaction_commit = + imap_filter_sieve_duplicate_transaction_commit; + scriptenv->duplicate_transaction_rollback = + imap_filter_sieve_duplicate_transaction_rollback; scriptenv->duplicate_mark = imap_filter_sieve_duplicate_mark; scriptenv->duplicate_check = imap_filter_sieve_duplicate_check; - scriptenv->duplicate_flush = imap_filter_sieve_duplicate_flush; scriptenv->script_context = sctx; return 0; } diff --git a/src/plugins/imapsieve/imap-sieve.c b/src/plugins/imapsieve/imap-sieve.c index e5b08947bda1c785c541c6d1fce8f64574fdaeba..e6cc24a51fb569661261c56e485f9b93264e3f28 100644 --- a/src/plugins/imapsieve/imap-sieve.c +++ b/src/plugins/imapsieve/imap-sieve.c @@ -219,32 +219,60 @@ imap_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, * Duplicate checking */ -static bool -imap_sieve_duplicate_check(const struct sieve_script_env *senv, const void *id, - size_t id_size) +static void * +imap_sieve_duplicate_transaction_begin(const struct sieve_script_env *senv) { struct imap_sieve_context *isctx = senv->script_context; - return mail_duplicate_check(isctx->isieve->dup_db, id, id_size, - senv->user->username); + return mail_duplicate_transaction_begin(isctx->isieve->dup_db); } -static void -imap_sieve_duplicate_mark(const struct sieve_script_env *senv, const void *id, - size_t id_size, time_t time) +static void imap_sieve_duplicate_transaction_commit(void **_dup_trans) { - struct imap_sieve_context *isctx = senv->script_context; + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + mail_duplicate_transaction_commit(&dup_trans); +} + +static void imap_sieve_duplicate_transaction_rollback(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; - mail_duplicate_mark(isctx->isieve->dup_db, id, id_size, - senv->user->username, time); + *_dup_trans = NULL; + mail_duplicate_transaction_rollback(&dup_trans); +} + +static enum sieve_duplicate_check_result +imap_sieve_duplicate_check(void *_dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + switch (mail_duplicate_check(dup_trans, id, id_size, + senv->user->username)) { + case MAIL_DUPLICATE_CHECK_RESULT_EXISTS: + return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS; + case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND: + return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND; + case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK: + case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT: + return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE; + case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR: + case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS: + break; + } + return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE; } static void -imap_sieve_duplicate_flush(const struct sieve_script_env *senv) +imap_sieve_duplicate_mark(void *_dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time) { - struct imap_sieve_context *isctx = senv->script_context; + struct mail_duplicate_transaction *dup_trans = _dup_trans; - mail_duplicate_db_flush(isctx->isieve->dup_db); + mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time); } /* @@ -884,9 +912,14 @@ int imap_sieve_run_mail(struct imap_sieve_run *isrun, struct mail *mail, scriptenv.smtp_send = imap_sieve_smtp_send; scriptenv.smtp_abort = imap_sieve_smtp_abort; scriptenv.smtp_finish = imap_sieve_smtp_finish; + scriptenv.duplicate_transaction_begin = + imap_sieve_duplicate_transaction_begin; + scriptenv.duplicate_transaction_commit = + imap_sieve_duplicate_transaction_commit; + scriptenv.duplicate_transaction_rollback = + imap_sieve_duplicate_transaction_rollback; scriptenv.duplicate_mark = imap_sieve_duplicate_mark; scriptenv.duplicate_check = imap_sieve_duplicate_check; - scriptenv.duplicate_flush = imap_sieve_duplicate_flush; scriptenv.result_amend_log_message = imap_sieve_result_amend_log_message; scriptenv.trace_log = trace_log; diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index 60b3b18856921d4fd31e02641348763d550f05d0..4e79c1f1b58b711acd868a47eb2c0e7402ab6344 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -148,34 +148,60 @@ lda_sieve_reject_mail(const struct sieve_script_env *senv, * Duplicate checking */ -static bool -lda_sieve_duplicate_check(const struct sieve_script_env *senv, - const void *id, size_t id_size) +static void * +lda_sieve_duplicate_transaction_begin(const struct sieve_script_env *senv) { struct mail_deliver_context *dctx = (struct mail_deliver_context *)senv->script_context; - return mail_duplicate_check(dctx->dup_db, id, id_size, - senv->user->username); + return mail_duplicate_transaction_begin(dctx->dup_db); } -static void -lda_sieve_duplicate_mark(const struct sieve_script_env *senv, const void *id, - size_t id_size, time_t time) +static void lda_sieve_duplicate_transaction_commit(void **_dup_trans) { - struct mail_deliver_context *dctx = - (struct mail_deliver_context *)senv->script_context; + struct mail_duplicate_transaction *dup_trans = *_dup_trans; - mail_duplicate_mark(dctx->dup_db, - id, id_size, senv->user->username, time); + *_dup_trans = NULL; + mail_duplicate_transaction_commit(&dup_trans); } -static void lda_sieve_duplicate_flush(const struct sieve_script_env *senv) +static void lda_sieve_duplicate_transaction_rollback(void **_dup_trans) { - struct mail_deliver_context *dctx = - (struct mail_deliver_context *)senv->script_context; + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + mail_duplicate_transaction_rollback(&dup_trans); +} + +static enum sieve_duplicate_check_result +lda_sieve_duplicate_check(void *_dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + switch (mail_duplicate_check(dup_trans, id, id_size, + senv->user->username)) { + case MAIL_DUPLICATE_CHECK_RESULT_EXISTS: + return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS; + case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND: + return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND; + case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK: + case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT: + return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE; + case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR: + case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS: + break; + } + return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE; +} + +static void +lda_sieve_duplicate_mark(void *_dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; - mail_duplicate_db_flush(dctx->dup_db); + mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time); } /* @@ -984,9 +1010,14 @@ lda_sieve_execute(struct lda_sieve_run_context *srctx, scriptenv.smtp_send = lda_sieve_smtp_send; scriptenv.smtp_abort = lda_sieve_smtp_abort; scriptenv.smtp_finish = lda_sieve_smtp_finish; + scriptenv.duplicate_transaction_begin = + lda_sieve_duplicate_transaction_begin; + scriptenv.duplicate_transaction_commit = + lda_sieve_duplicate_transaction_commit; + scriptenv.duplicate_transaction_rollback = + lda_sieve_duplicate_transaction_rollback; scriptenv.duplicate_mark = lda_sieve_duplicate_mark; scriptenv.duplicate_check = lda_sieve_duplicate_check; - scriptenv.duplicate_flush = lda_sieve_duplicate_flush; scriptenv.reject_mail = lda_sieve_reject_mail; scriptenv.result_amend_log_message = lda_sieve_result_amend_log_message; scriptenv.script_context = (void *) mdctx; diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 5a4235c099a9861643b3a8a94fd4ff569a246a04..e7345be886393d84ac0e139c4ca2a569e86523f6 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -107,17 +107,34 @@ sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, void *handle, * Dummy duplicate check implementation */ -static bool -duplicate_check(const struct sieve_script_env *senv, const void *id ATTR_UNUSED, - size_t id_size ATTR_UNUSED) +static void * +duplicate_transaction_begin(const struct sieve_script_env *senv ATTR_UNUSED) +{ + return NULL; +} + +static void duplicate_transaction_commit(void **_dup_trans ATTR_UNUSED) +{ +} + +static void duplicate_transaction_rollback(void **_dup_trans ATTR_UNUSED) +{ +} + +static int +duplicate_check(void *_dup_trans ATTR_UNUSED, + const struct sieve_script_env *senv, + const void *id ATTR_UNUSED, size_t id_size ATTR_UNUSED) { i_info("checked duplicate for user %s.\n", senv->user->username); return 0; } static void -duplicate_mark(const struct sieve_script_env *senv, const void *id ATTR_UNUSED, - size_t id_size ATTR_UNUSED, time_t time ATTR_UNUSED) +duplicate_mark(void *_dup_trans ATTR_UNUSED, + const struct sieve_script_env *senv, + const void *id ATTR_UNUSED, size_t id_size ATTR_UNUSED, + time_t time ATTR_UNUSED) { i_info("marked duplicate for user %s.\n", senv->user->username); } @@ -342,6 +359,12 @@ int main(int argc, char **argv) scriptenv.smtp_send = sieve_smtp_send; scriptenv.smtp_abort = sieve_smtp_abort; scriptenv.smtp_finish = sieve_smtp_finish; + scriptenv.duplicate_transaction_begin = + duplicate_transaction_begin; + scriptenv.duplicate_transaction_commit = + duplicate_transaction_commit; + scriptenv.duplicate_transaction_rollback = + duplicate_transaction_rollback; scriptenv.duplicate_mark = duplicate_mark; scriptenv.duplicate_check = duplicate_check; scriptenv.result_amend_log_message = result_amend_log_message; diff --git a/src/testsuite/testsuite-script.c b/src/testsuite/testsuite-script.c index 7c89ecd24374cb06443d75bcd787a9d7985fd755..b6edd9b14356c9383d9b712696a7aaec5af5fc13 100644 --- a/src/testsuite/testsuite-script.c +++ b/src/testsuite/testsuite-script.c @@ -147,8 +147,9 @@ bool testsuite_script_run(const struct sieve_runtime_env *renv) } ret = sieve_interpreter_run(interp, result); - sieve_interpreter_free(&interp); + + sieve_execute_finish(&exec_env, ret); sieve_execute_deinit(&exec_env); return (ret > 0 ||