diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c index cf4c9265c679f701c264cf6f742b7d95fd957246..8afa7b2b6c40fadc007b36a3502acdc5bd5a3788 100644 --- a/src/lib-sieve/cmd-discard.c +++ b/src/lib-sieve/cmd-discard.c @@ -58,7 +58,7 @@ const struct sieve_operation_def cmd_discard_operation = { static void act_discard_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_discard_commit +static int act_discard_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -128,7 +128,7 @@ static void act_discard_print *keep = FALSE; } -static bool act_discard_commit +static int act_discard_commit (const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep) @@ -138,6 +138,6 @@ static bool act_discard_commit "(discard action)"); *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c index f1785b900dfc7218a5ef15566ea2c232926724ab..d3a27352d20136608c9d82b9e24b84a437b55590 100644 --- a/src/lib-sieve/cmd-redirect.c +++ b/src/lib-sieve/cmd-redirect.c @@ -87,7 +87,7 @@ static int act_redirect_check_duplicate static void act_redirect_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_redirect_commit +static int act_redirect_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -307,7 +307,7 @@ static void act_redirect_print *keep = FALSE; } -static bool act_redirect_send +static int act_redirect_send (const struct sieve_action_exec_env *aenv, struct mail *mail, struct act_redirect_context *ctx) { @@ -326,11 +326,11 @@ static bool act_redirect_send if ( !sieve_smtp_available(senv) ) { sieve_result_global_warning (aenv, "redirect action has no means to send mail."); - return TRUE; + return SIEVE_EXEC_FAILURE; } if (mail_get_stream(mail, NULL, NULL, &input) < 0) - return FALSE; + return SIEVE_EXEC_TEMP_FAILURE; /* Open SMTP transport */ smtp_handle = sieve_smtp_open(senv, ctx->to_address, sender, &output); @@ -359,13 +359,13 @@ static bool act_redirect_send "failed to redirect message to <%s> " "(refer to server log for more information)", str_sanitize(ctx->to_address, 80)); - return FALSE; + return SIEVE_EXEC_FAILURE; } - return TRUE; + return SIEVE_EXEC_OK; } -static bool act_redirect_commit +static int act_redirect_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep) @@ -378,6 +378,7 @@ static bool act_redirect_commit const struct sieve_script_env *senv = aenv->scriptenv; const char *orig_recipient = sieve_message_get_orig_recipient(aenv->msgctx); const char *dupeid; + int ret; /* Prevent mail loops if possible */ dupeid = msgdata->id == NULL ? NULL : t_strdup_printf @@ -388,12 +389,12 @@ static bool act_redirect_commit sieve_result_global_log(aenv, "discarded duplicate forward to <%s>", str_sanitize(ctx->to_address, 128)); *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } } /* Try to forward the message */ - if ( act_redirect_send(aenv, mail, ctx) ) { + if ( (ret=act_redirect_send(aenv, mail, ctx)) == SIEVE_EXEC_OK) { /* Mark this message id as forwarded to the specified destination */ if (dupeid != NULL) { @@ -410,10 +411,10 @@ static bool act_redirect_commit /* Cancel implicit keep */ *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } - return FALSE; + return ret; } diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c index 4532677aa796dbb295e21df221e7c9cd262496d2..025e4de6d735fb1d38f47fa99f36e37bcb07f025 100644 --- a/src/lib-sieve/ext-reject.c +++ b/src/lib-sieve/ext-reject.c @@ -181,7 +181,7 @@ int act_reject_check_conflict static void act_reject_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_reject_commit +static int act_reject_commit (const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -379,7 +379,7 @@ static void act_reject_print *keep = FALSE; } -static bool act_reject_commit +static int act_reject_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep) { @@ -391,7 +391,7 @@ static bool act_reject_commit if ( recipient == NULL ) { sieve_result_global_warning(aenv, "reject action aborted: envelope recipient is <>"); - return TRUE; + return SIEVE_EXEC_OK; } if ( rj_ctx->reason == NULL ) { @@ -399,14 +399,14 @@ static bool act_reject_commit "not sending reject message (would cause second response to sender)"); *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } if ( sender == NULL ) { sieve_result_global_log(aenv, "not sending reject message to <>"); *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } if ( sieve_action_reject_mail(aenv, sender, recipient, rj_ctx->reason) ) { @@ -415,10 +415,10 @@ static bool act_reject_commit ( rj_ctx->ereject ? "ereject" : "reject" )); *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } - return FALSE; + return SIEVE_EXEC_FAILURE; } diff --git a/src/lib-sieve/plugins/enotify/cmd-notify.c b/src/lib-sieve/plugins/enotify/cmd-notify.c index 488fc18b96d3fcad06d682a3f0f90cce9f94dd20..993f95224125ce76ac718eac5fabf33b1343742a 100644 --- a/src/lib-sieve/plugins/enotify/cmd-notify.c +++ b/src/lib-sieve/plugins/enotify/cmd-notify.c @@ -136,7 +136,7 @@ static int act_notify_check_duplicate static void act_notify_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_notify_commit +static int act_notify_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -566,7 +566,7 @@ static void act_notify_print /* Result execution */ -static bool act_notify_commit +static int act_notify_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep ATTR_UNUSED) { @@ -593,7 +593,7 @@ static bool act_notify_commit sieve_error_handler_unref(&nenv.ehandler); } - return result; + return ( result ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE ); } diff --git a/src/lib-sieve/plugins/imap4flags/tag-flags.c b/src/lib-sieve/plugins/imap4flags/tag-flags.c index 001f69c72fc4c890f906f8b021e2d02366229e20..6c64c11936f9a79d10670a4b8e22b6ac3bfc60b6 100644 --- a/src/lib-sieve/plugins/imap4flags/tag-flags.c +++ b/src/lib-sieve/plugins/imap4flags/tag-flags.c @@ -70,7 +70,7 @@ static int seff_flags_merge static void seff_flags_print (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool seff_flags_pre_execute +static int seff_flags_pre_execute (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void **context, void *tr_context); @@ -383,7 +383,7 @@ static void seff_flags_print /* Result execution */ -static bool seff_flags_pre_execute +static int seff_flags_pre_execute (const struct sieve_side_effect *seffect, const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void **context, void *tr_context) @@ -402,7 +402,7 @@ static bool seff_flags_pre_execute sieve_act_store_add_flags(aenv, tr_context, keywords, ctx->flags); - return TRUE; + return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c b/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c index 9e3dbfdade5f4321aa88a46bb1642928f6770071..f1745b067013f47b44bada21e2d41effb369c11a 100644 --- a/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c +++ b/src/lib-sieve/plugins/mailbox/tag-mailbox-create.c @@ -41,7 +41,7 @@ const struct sieve_argument_def mailbox_create_tag = { static void seff_mailbox_create_print (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool seff_mailbox_create_pre_execute +static int seff_mailbox_create_pre_execute (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void **se_context, void *tr_context); @@ -113,7 +113,7 @@ static void seff_mailbox_create_print sieve_result_seffect_printf(rpenv, "create mailbox if it does not exist"); } -static bool seff_mailbox_create_pre_execute +static int seff_mailbox_create_pre_execute (const struct sieve_side_effect *seffect ATTR_UNUSED, const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv ATTR_UNUSED, @@ -126,17 +126,22 @@ static bool seff_mailbox_create_pre_execute /* Check whether creation is necessary */ if ( trans->box == NULL || trans->disabled ) - return TRUE; + return SIEVE_EXEC_OK; /* Check whether creation has a chance of working */ - if ( trans->error_code != MAIL_ERROR_NONE && - trans->error_code != MAIL_ERROR_NOTFOUND ) - return FALSE; + switch ( trans->error_code ) { + case MAIL_ERROR_NONE: + case MAIL_ERROR_NOTFOUND: + break; + case MAIL_ERROR_TEMP: + return SIEVE_EXEC_TEMP_FAILURE; + default: + return SIEVE_EXEC_FAILURE; + } trans->error = NULL; trans->error_code = MAIL_ERROR_NONE; - *storage = mailbox_get_storage(trans->box); /* Create mailbox */ @@ -144,7 +149,8 @@ static bool seff_mailbox_create_pre_execute (void)mail_storage_get_last_error(*storage, &error); if ( error != MAIL_ERROR_EXISTS ) { sieve_act_store_get_storage_error(aenv, trans); - return FALSE; + return ( trans->error_code == MAIL_ERROR_TEMP ? + SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE ); } } @@ -159,10 +165,11 @@ static bool seff_mailbox_create_pre_execute if ( mailbox_open(trans->box) < 0 ) { /* Failed definitively */ sieve_act_store_get_storage_error(aenv, trans); - return FALSE; + return ( trans->error_code == MAIL_ERROR_TEMP ? + SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE ); } - return TRUE; + return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c index 849662373eb37ba7362820eb5f3cde487fea2023..d77d8bd00c73f3674d37728599155e0340776ea5 100644 --- a/src/lib-sieve/plugins/notify/cmd-notify.c +++ b/src/lib-sieve/plugins/notify/cmd-notify.c @@ -146,7 +146,7 @@ static int act_notify_check_duplicate static void act_notify_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_notify_commit +static int act_notify_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -789,7 +789,7 @@ static bool act_notify_send return TRUE; } -static bool act_notify_commit +static int act_notify_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep ATTR_UNUSED) { @@ -820,7 +820,7 @@ static bool act_notify_commit result = act_notify_send(aenv, act); } T_END; - return result; + return ( result ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE ); } diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c index e7196d1f884d6afc76e46ab6b8e0a79cd82f5c8c..098525a11cbe12adeb51205e81cfc315f4ffa803 100644 --- a/src/lib-sieve/plugins/vacation/cmd-vacation.c +++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c @@ -190,7 +190,7 @@ int act_vacation_check_conflict static void act_vacation_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_vacation_commit +static int act_vacation_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -1018,7 +1018,7 @@ static void act_vacation_hash md5_final(&ctx, hash_r); } -static bool act_vacation_commit +static int act_vacation_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep ATTR_UNUSED) { @@ -1043,14 +1043,14 @@ static bool act_vacation_commit if ( recipient == NULL ) { sieve_result_global_warning (aenv, "vacation action aborted: envelope recipient is <>"); - return TRUE; + return SIEVE_EXEC_OK; } /* Is the return path unset ? */ if ( sender == NULL ) { sieve_result_global_log(aenv, "discarded vacation reply to <>"); - return TRUE; + return SIEVE_EXEC_OK; } /* Are we perhaps trying to respond to ourselves ? @@ -1059,7 +1059,7 @@ static bool act_vacation_commit sieve_result_global_log(aenv, "discarded vacation reply to own address <%s>", str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } /* Are we perhaps trying to respond to one of our alternative :addresses? @@ -1073,7 +1073,7 @@ static bool act_vacation_commit "discarded vacation reply to own address <%s> " "(as specified using :addresses argument)", str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } alt_address++; } @@ -1088,7 +1088,7 @@ static bool act_vacation_commit sieve_result_global_log(aenv, "discarded duplicate vacation response to <%s>", str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } } @@ -1101,7 +1101,7 @@ static bool act_vacation_commit sieve_result_global_log(aenv, "discarding vacation response to mailinglist recipient <%s>", str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } hdsp++; } @@ -1116,7 +1116,7 @@ static bool act_vacation_commit sieve_result_global_log(aenv, "discarding vacation response to auto-submitted message from <%s>", str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } hdsp++; } @@ -1133,7 +1133,7 @@ static bool act_vacation_commit sieve_result_global_log(aenv, "discarding vacation response to precedence=%s message from <%s>", *hdsp, str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } hdsp++; } @@ -1144,7 +1144,7 @@ static bool act_vacation_commit sieve_result_global_log(aenv, "not sending vacation response to system address <%s>", str_sanitize(sender, 128)); - return TRUE; + return SIEVE_EXEC_OK; } /* Fetch original recipient if necessary */ @@ -1213,7 +1213,7 @@ static bool act_vacation_commit str_sanitize(recipient, 128), original_recipient, (ctx->addresses == NULL ? " no" : "")); - return TRUE; + return SIEVE_EXEC_OK; } } @@ -1243,7 +1243,7 @@ static bool act_vacation_commit } } - return TRUE; + return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c b/src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c index 836baafb6382c38812cbf9dea954ce1ab0936378..fb10e3f9177b8b1d14d27bc4f2aa9aefef3b76e7 100644 --- a/src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c +++ b/src/lib-sieve/plugins/vnd.dovecot/duplicate/ext-duplicate-common.c @@ -77,7 +77,7 @@ struct act_duplicate_mark_data { static void act_duplicate_mark_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_duplicate_mark_commit +static int act_duplicate_mark_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -106,7 +106,7 @@ static void act_duplicate_mark_print } } -static bool act_duplicate_mark_commit +static int act_duplicate_mark_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep ATTR_UNUSED) @@ -121,7 +121,7 @@ static bool act_duplicate_mark_commit sieve_action_duplicate_mark (senv, data->hash, sizeof(data->hash), ioloop_time + data->period); - return TRUE; + return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c index e39db4935a7f87ad18fac7b380d8634446a42db6..7ae4ca2978d10446cc0521c9e0b3529092a1b076 100644 --- a/src/lib-sieve/sieve-actions.c +++ b/src/lib-sieve/sieve-actions.c @@ -190,13 +190,13 @@ static void act_store_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_store_start +static int act_store_start (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void **tr_context); -static bool act_store_execute +static int act_store_execute (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context); -static bool act_store_commit +static int act_store_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); static void act_store_rollback @@ -283,16 +283,6 @@ void sieve_act_store_add_flags trans->flags_altered = TRUE; } -void sieve_act_store_get_storage_error -(const struct sieve_action_exec_env *aenv, struct act_store_transaction *trans) -{ - pool_t pool = sieve_result_pool(aenv->result); - - trans->error = p_strdup(pool, - mail_storage_get_last_error(mailbox_get_storage(trans->box), - &trans->error_code)); -} - /* Equality */ static bool act_store_equals @@ -353,6 +343,17 @@ static void act_store_print /* Action implementation */ +void sieve_act_store_get_storage_error +(const struct sieve_action_exec_env *aenv, + struct act_store_transaction *trans) +{ + pool_t pool = sieve_result_pool(aenv->result); + + trans->error = p_strdup(pool, + mail_storage_get_last_error(mailbox_get_storage(trans->box), + &trans->error_code)); +} + static bool act_store_mailbox_open (const struct sieve_action_exec_env *aenv, const char *mailbox, struct mailbox **box_r, enum mail_error *error_code_r, const char **error_r) @@ -384,7 +385,7 @@ static bool act_store_mailbox_open return TRUE; } -static bool act_store_start +static int act_store_start (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void **tr_context) { @@ -434,8 +435,17 @@ static bool act_store_start *tr_context = (void *)trans; - return ( trans->error_code == MAIL_ERROR_NONE || - trans->error_code == MAIL_ERROR_NOTFOUND ); + switch ( trans->error_code ) { + case MAIL_ERROR_NONE: + case MAIL_ERROR_NOTFOUND: + return SIEVE_EXEC_OK; + case MAIL_ERROR_TEMP: + return SIEVE_EXEC_TEMP_FAILURE; + default: + break; + } + + return SIEVE_EXEC_FAILURE; } static struct mail_keywords *act_store_keywords_create @@ -461,7 +471,7 @@ static struct mail_keywords *act_store_keywords_create return box_keywords; } -static bool act_store_execute +static int act_store_execute (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context) { @@ -472,17 +482,27 @@ static bool act_store_execute struct mail *real_mail = mail_get_real_mail(mail); struct mail_save_context *save_ctx; struct mail_keywords *keywords = NULL; - bool result = TRUE; + int status = SIEVE_EXEC_OK; /* Verify transaction */ - if ( trans == NULL ) return FALSE; + if ( trans == NULL ) return SIEVE_EXEC_FAILURE; /* Check whether we need to do anything */ - if ( trans->disabled ) return TRUE; + if ( trans->disabled ) return SIEVE_EXEC_OK; /* Exit early if mailbox is not available */ - if ( trans->box == NULL || trans->error_code != MAIL_ERROR_NONE ) - return FALSE; + if ( trans->box == NULL ) + return SIEVE_EXEC_FAILURE; + + /* Exit early if transaction already failed */ + switch ( trans->error_code ) { + case MAIL_ERROR_NONE: + break; + case MAIL_ERROR_TEMP: + return SIEVE_EXEC_TEMP_FAILURE; + default: + return SIEVE_EXEC_FAILURE; + } /* If the message originates from the target mailbox, only update the flags * and keywords (if not read-only) @@ -504,7 +524,7 @@ static bool act_store_execute mail_update_flags(mail, MODIFY_REPLACE, trans->flags); } - return TRUE; + return SIEVE_EXEC_OK; /* If the message is modified, only store it in the source mailbox when it is * not opened read-only. Mail structs of modified messages have their own @@ -516,7 +536,7 @@ static bool act_store_execute && ( mailbox_backends_equal(trans->box, aenv->msgdata->mail->box) ) ) { trans->redundant = TRUE; - return TRUE; + return SIEVE_EXEC_OK; } /* Mark attempt to store in default mailbox */ @@ -551,7 +571,8 @@ static bool act_store_execute if ( mailbox_copy(&save_ctx, mail) < 0 ) { sieve_act_store_get_storage_error(aenv, trans); - result = FALSE; + status = ( trans->error_code == MAIL_ERROR_TEMP ? + SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE ); } /* Deallocate keywords */ @@ -559,7 +580,7 @@ static bool act_store_execute mailbox_keywords_unref(&keywords); } - return result; + return status; } static void act_store_log_status @@ -597,13 +618,11 @@ static void act_store_log_status const char *errstr; enum mail_error error_code; - if ( trans->error != NULL ) { - errstr = trans->error; - error_code = trans->error_code; - } else { - errstr = mail_storage_get_last_error - (mailbox_get_storage(trans->box), &error_code); - } + if ( trans->error == NULL ) + sieve_act_store_get_storage_error(aenv, trans); + + errstr = trans->error; + error_code = trans->error_code; if ( error_code == MAIL_ERROR_NOTFOUND || error_code == MAIL_ERROR_PARAMS ) { @@ -629,7 +648,7 @@ static void act_store_log_status } } -static bool act_store_commit +static int act_store_commit (const struct sieve_action *action ATTR_UNUSED, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep) { @@ -638,7 +657,7 @@ static bool act_store_commit bool status = TRUE; /* Verify transaction */ - if ( trans == NULL ) return FALSE; + if ( trans == NULL ) return SIEVE_EXEC_FAILURE; /* Check whether we need to do anything */ if ( trans->disabled ) { @@ -646,14 +665,14 @@ static bool act_store_commit *keep = FALSE; if ( trans->box != NULL ) mailbox_free(&trans->box); - return TRUE; + return SIEVE_EXEC_OK; } else if ( trans->redundant ) { act_store_log_status(trans, aenv, FALSE, status); aenv->exec_status->keep_original = TRUE; aenv->exec_status->message_saved = TRUE; if ( trans->box != NULL ) mailbox_free(&trans->box); - return TRUE; + return SIEVE_EXEC_OK; } /* Mark attempt to use storage. Can only get here when all previous actions @@ -682,7 +701,11 @@ static bool act_store_commit if ( trans->box != NULL ) mailbox_free(&trans->box); - return status; + if (status) + return SIEVE_EXEC_OK; + + return ( trans->error_code == MAIL_ERROR_TEMP ? + SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE ); } static void act_store_rollback diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h index f932228f9b40ddcb8d36d8c792675cb91b6176ca..3b76274c486dd07c6836d94ebe116f28ae002ae7 100644 --- a/src/lib-sieve/sieve-actions.h +++ b/src/lib-sieve/sieve-actions.h @@ -69,13 +69,13 @@ struct sieve_action_def { /* Result execution */ - bool (*start) + int (*start) (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void **tr_context); - bool (*execute) + int (*execute) (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context); - bool (*commit) + int (*commit) (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); void (*rollback) @@ -138,11 +138,11 @@ struct sieve_side_effect_def { /* Result execution */ - bool (*pre_execute) + int (*pre_execute) (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void **context, void *tr_context); - bool (*post_execute) + int (*post_execute) (const struct sieve_side_effect *seffect, const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context); void (*post_commit) diff --git a/src/lib-sieve/sieve-binary-file.c b/src/lib-sieve/sieve-binary-file.c index 0f68b37eb73d1d0820eb063f659aa75f6eaf8ec5..555c776e552539773130b09868fb15a0c3045129 100644 --- a/src/lib-sieve/sieve-binary-file.c +++ b/src/lib-sieve/sieve-binary-file.c @@ -301,13 +301,13 @@ int sieve_binary_save "binary save: failed to create temporary file: %s", eacces_error_get_creating("open", str_c(temp_path))); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; } else { sieve_sys_error(sbin->svinst, "binary save: failed to create temporary file: open(%s) failed: %m", str_c(temp_path)); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; } return -1; } @@ -318,7 +318,7 @@ int sieve_binary_save if ( !_sieve_binary_save(sbin, stream) ) { result = -1; if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; } o_stream_destroy(&stream); @@ -335,12 +335,12 @@ int sieve_binary_save sieve_sys_error(sbin->svinst, "binary save: failed to save binary: %s", eacces_error_get_creating("rename", path)); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; } else { sieve_sys_error(sbin->svinst, "binary save: failed to save binary: " "rename(%s, %s) failed: %m", str_c(temp_path), path); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; } result = -1; } @@ -386,13 +386,13 @@ bool sieve_binary_file_open sieve_sys_error(svinst, "binary open: failed to open: %s", eacces_error_get("open", path)); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_sys_error(svinst, "binary open: failed to open: " "open(%s) failed: %m", path); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } return FALSE; diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c index a67dc4e77679fbb9968ffbef6f5a23ff08eb37ac..0198f370daa0345497dd6f0b0ae2c45e6e565679 100644 --- a/src/lib-sieve/sieve-result.c +++ b/src/lib-sieve/sieve-result.c @@ -93,6 +93,8 @@ struct sieve_result { HASH_TABLE(const struct sieve_action_def *, struct sieve_result_action_context *) action_contexts; + + unsigned int executed:1; }; struct sieve_result *sieve_result_create @@ -925,11 +927,11 @@ static void _sieve_result_prepare_execution(struct sieve_result *result) } } -static bool _sieve_result_implicit_keep +static int _sieve_result_implicit_keep (struct sieve_result *result, bool rollback) { struct sieve_result_action *rac; - bool success = TRUE; + int status = SIEVE_EXEC_OK; struct sieve_result_side_effect *rsef, *rsef_first = NULL; void *tr_context = NULL; struct sieve_action act_keep; @@ -943,7 +945,7 @@ static bool _sieve_result_implicit_keep } /* If keep is a non-action, return right away */ - if ( act_keep.def == NULL ) return TRUE; + if ( act_keep.def == NULL ) return SIEVE_EXEC_OK; /* Scan for execution of keep-equal actions */ rac = result->first_action; @@ -952,7 +954,7 @@ static bool _sieve_result_implicit_keep act_keep.def->equals (result->action_env.scriptenv, NULL, &rac->action) && rac->action.executed ) - return TRUE; + return SIEVE_EXEC_OK; rac = rac->next; } @@ -970,42 +972,42 @@ static bool _sieve_result_implicit_keep /* Start keep action */ if ( act_keep.def->start != NULL ) - success = act_keep.def->start + status = act_keep.def->start (&act_keep, &result->action_env, &tr_context); /* Execute keep action */ - if ( success ) { + if ( status == SIEVE_EXEC_OK ) { rsef = rsef_first; - while ( success && rsef != NULL ) { + while ( status == SIEVE_EXEC_OK && rsef != NULL ) { struct sieve_side_effect *sef = &rsef->seffect; if ( sef->def->pre_execute != NULL ) - success = success && sef->def->pre_execute + status = sef->def->pre_execute (sef, &act_keep, &result->action_env, &sef->context, tr_context); rsef = rsef->next; } - if ( act_keep.def->execute != NULL ) - success = success && act_keep.def->execute + if ( status == SIEVE_EXEC_OK && act_keep.def->execute != NULL ) + status = act_keep.def->execute (&act_keep, &result->action_env, tr_context); rsef = rsef_first; - while ( success && rsef != NULL ) { + while ( status == SIEVE_EXEC_OK && rsef != NULL ) { struct sieve_side_effect *sef = &rsef->seffect; if ( sef->def->post_execute != NULL ) - success = success && sef->def->post_execute + status = sef->def->post_execute (sef, &act_keep, &result->action_env, tr_context); rsef = rsef->next; } } /* Finish keep action */ - if ( success ) { + if ( status == SIEVE_EXEC_OK ) { bool dummy = TRUE; if ( act_keep.def->commit != NULL ) - success = act_keep.def->commit + status = act_keep.def->commit (&act_keep, &result->action_env, tr_context, &dummy); rsef = rsef_first; @@ -1019,18 +1021,18 @@ static bool _sieve_result_implicit_keep rsef = rsef->next; } - return success; + return status; } /* Failed, rollback */ if ( act_keep.def->rollback != NULL ) - act_keep.def->rollback - (&act_keep, &result->action_env, tr_context, success); + act_keep.def->rollback(&act_keep, + &result->action_env, tr_context, ( status == SIEVE_EXEC_OK )); - return FALSE; + return status; } -bool sieve_result_implicit_keep +int sieve_result_implicit_keep (struct sieve_result *result) { _sieve_result_prepare_execution(result); @@ -1055,13 +1057,20 @@ void sieve_result_mark_executed(struct sieve_result *result) } } + +bool sieve_result_executed(struct sieve_result *result) +{ + return result->executed; +} + int sieve_result_execute (struct sieve_result *result, bool *keep) { - bool implicit_keep = TRUE; - bool success = TRUE, commit_ok; + bool implicit_keep = TRUE, executed = result->executed; + int status = SIEVE_EXEC_OK, commit_status; struct sieve_result_action *rac, *first_action; struct sieve_result_action *last_attempted; + int ret; if ( keep != NULL ) *keep = FALSE; @@ -1080,7 +1089,7 @@ int sieve_result_execute */ rac = first_action; - while ( success && rac != NULL ) { + while ( status == SIEVE_EXEC_OK && rac != NULL ) { struct sieve_action *act = &rac->action; /* Skip non-actions (inactive keep) and executed ones */ @@ -1090,9 +1099,9 @@ int sieve_result_execute } if ( act->def->start != NULL ) { - rac->success = act->def->start + status = act->def->start (act, &result->action_env, &rac->tr_context); - success = success && rac->success; + rac->success = ( status == SIEVE_EXEC_OK ); } rac = rac->next; @@ -1104,7 +1113,7 @@ int sieve_result_execute last_attempted = rac; rac = first_action; - while ( success && rac != NULL ) { + while ( status == SIEVE_EXEC_OK && rac != NULL ) { struct sieve_action *act = &rac->action; struct sieve_result_side_effect *rsef; struct sieve_side_effect *sef; @@ -1117,27 +1126,28 @@ int sieve_result_execute /* Execute pre-execute event of side effects */ rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL; - while ( success && rsef != NULL ) { + while ( status == SIEVE_EXEC_OK && rsef != NULL ) { sef = &rsef->seffect; if ( sef->def != NULL && sef->def->pre_execute != NULL ) - success = success & sef->def->pre_execute + status = sef->def->pre_execute (sef, act, &result->action_env, &sef->context, rac->tr_context); rsef = rsef->next; } /* Execute the action itself */ - if ( success && act->def != NULL && act->def->execute != NULL ) { - rac->success = act->def->execute + if ( status == SIEVE_EXEC_OK && act->def != NULL && + act->def->execute != NULL ) { + status = act->def->execute (act, &result->action_env, rac->tr_context); - success = success && rac->success; + rac->success = ( status == SIEVE_EXEC_OK ); } /* Execute post-execute event of side effects */ rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL; - while ( success && rsef != NULL ) { + while ( status == SIEVE_EXEC_OK && rsef != NULL ) { sef = &rsef->seffect; if ( sef->def != NULL && sef->def->post_execute != NULL ) - success = success && sef->def->post_execute + status = sef->def->post_execute (sef, act, &result->action_env, rac->tr_context); rsef = rsef->next; } @@ -1149,15 +1159,16 @@ int sieve_result_execute * Transaction commit/rollback */ - commit_ok = success; + commit_status = status; rac = first_action; while ( rac != NULL && rac != last_attempted ) { struct sieve_action *act = &rac->action; struct sieve_result_side_effect *rsef; struct sieve_side_effect *sef; - if ( success ) { + if ( status == SIEVE_EXEC_OK ) { bool impl_keep = TRUE; + int cstatus = SIEVE_EXEC_OK; if ( rac->keep && keep != NULL ) *keep = TRUE; @@ -1168,19 +1179,35 @@ int sieve_result_execute } if ( act->def->commit != NULL ) { - act->executed = act->def->commit + cstatus = act->def->commit (act, &result->action_env, rac->tr_context, &impl_keep); - commit_ok = act->executed && commit_ok; + if ( cstatus == SIEVE_EXEC_OK ) { + act->executed = TRUE; + result->executed = TRUE; + executed = TRUE; + } else { + /* This is bad; try to salvage as much as possible */ + if (commit_status == SIEVE_EXEC_OK) { + commit_status = cstatus; + if (!executed) { + /* We haven't executed anything yet; continue as rollback */ + status = cstatus; + } + } + impl_keep = TRUE; + } } - /* Execute post_commit event of side effects */ - rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL; - while ( rsef != NULL ) { - sef = &rsef->seffect; - if ( sef->def->post_commit != NULL ) - sef->def->post_commit - (sef, act, &result->action_env, rac->tr_context, &impl_keep); - rsef = rsef->next; + if ( cstatus == SIEVE_EXEC_OK ) { + /* Execute post_commit event of side effects */ + rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL; + while ( rsef != NULL ) { + sef = &rsef->seffect; + if ( sef->def->post_commit != NULL ) + sef->def->post_commit + (sef, act, &result->action_env, rac->tr_context, &impl_keep); + rsef = rsef->next; + } } implicit_keep = implicit_keep && impl_keep; @@ -1191,9 +1218,10 @@ int sieve_result_execute continue; } - if ( act->def->rollback != NULL ) + if ( act->def->rollback != NULL ) { act->def->rollback (act, &result->action_env, rac->tr_context, rac->success); + } /* Rollback side effects */ rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL; @@ -1217,19 +1245,28 @@ int sieve_result_execute * though. */ + if ( !executed && commit_status == SIEVE_EXEC_TEMP_FAILURE ) + return commit_status; + /* Execute implicit keep if the transaction failed or when the implicit keep * was not canceled during transaction. */ - if ( !commit_ok || implicit_keep ) { - if ( !_sieve_result_implicit_keep(result, !commit_ok) ) + if ( commit_status != SIEVE_EXEC_OK || implicit_keep ) { + switch ((ret=_sieve_result_implicit_keep + (result, ( commit_status != SIEVE_EXEC_OK ))) ) { + case SIEVE_EXEC_OK: + break; + case SIEVE_EXEC_TEMP_FAILURE: + if (!executed) + return ret; + default: return SIEVE_EXEC_KEEP_FAILED; + } - return ( commit_ok ? - SIEVE_EXEC_OK /* Success */ : - SIEVE_EXEC_FAILURE /* Implicit keep executed */ ); + return commit_status; } - /* Unconditional success */ + /* success */ return SIEVE_EXEC_OK; } diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h index 804bdc6a30353e0b9dda1ba34d4ae5cf86c5b61d..f52f132cff232897861731d74e23cd4bb2fb973c 100644 --- a/src/lib-sieve/sieve-result.h +++ b/src/lib-sieve/sieve-result.h @@ -141,12 +141,14 @@ void sieve_result_set_failure_action * Result execution */ -bool sieve_result_implicit_keep(struct sieve_result *result); +int sieve_result_implicit_keep(struct sieve_result *result); void sieve_result_mark_executed(struct sieve_result *result); int sieve_result_execute(struct sieve_result *result, bool *keep); +bool sieve_result_executed(struct sieve_result *result); + /* * Result evaluation */ diff --git a/src/lib-sieve/sieve-script-dict.c b/src/lib-sieve/sieve-script-dict.c index 62605281955e7baa5594b44a604cd01bd7f590a7..14358662d53e21157792aba5a3f6988adefb65ce 100644 --- a/src/lib-sieve/sieve-script-dict.c +++ b/src/lib-sieve/sieve-script-dict.c @@ -80,7 +80,7 @@ static int sieve_dict_script_open } else { sieve_critical(svinst, ehandler, NULL, "failed to open sieve script", "sieve dict backend: invalid option `%s'", option); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } @@ -96,7 +96,7 @@ static int sieve_dict_script_open if ( svinst->username == NULL ) { sieve_critical(svinst, ehandler, name, "failed to open sieve script", "sieve dict backend: no username specified"); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } username = svinst->username; @@ -106,7 +106,7 @@ static int sieve_dict_script_open sieve_critical(svinst, ehandler, name, "failed to open sieve script", "sieve dict backend: BUG: Sieve interpreter is initialized without " "a base_dir"); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } @@ -122,7 +122,7 @@ static int sieve_dict_script_open sieve_critical(svinst, ehandler, name, "failed to open sieve script", "sieve dict backend: failed to initialize dict with data `%s' " "for user `%s': %s", data, username, error); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } @@ -135,7 +135,7 @@ static int sieve_dict_script_open if ( ret < 0 ) { sieve_critical(svinst, ehandler, name, "failed to open sieve script", "sieve dict backend: failed to lookup script id from path %s", path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; } else { if ( svinst->debug ) { sieve_sys_debug(svinst, "sieve dict backend: " @@ -193,7 +193,7 @@ static int sieve_dict_script_get_stream "sieve dict backend: data with id `%s' for script `%s' " "not found at path %s", script->data_id, name, path); } - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } diff --git a/src/lib-sieve/sieve-script-file.c b/src/lib-sieve/sieve-script-file.c index 18df9fb3957340c4dd45c617092215ac12aa29eb..eee6f5082199b79b7551439ed0ad9873e815976b 100644 --- a/src/lib-sieve/sieve-script-file.c +++ b/src/lib-sieve/sieve-script-file.c @@ -72,12 +72,12 @@ static void sieve_file_script_handle_error case EACCES: sieve_critical(svinst, ehandler, name, "failed to open sieve script", "failed to stat sieve script: %s", eacces_error_get("stat", path)); - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_critical(svinst, ehandler, name, "failed to open sieve script", "failed to stat sieve script: stat(%s) failed: %m", path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } } @@ -133,7 +133,7 @@ static int sieve_file_script_open sieve_critical(svinst, ehandler, NULL, "failed to open sieve script", "sieve file backend: invalid option `%s'", option); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } @@ -153,7 +153,7 @@ static int sieve_file_script_open "failed to open sieve script", "sieve script file path %s is relative to home directory, " "but home directory is not available.", path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; success = FALSE; } } @@ -165,7 +165,7 @@ static int sieve_file_script_open sieve_critical(svinst, ehandler, NULL, "failed to open sieve script", "sieve script file path '%s' is a directory.", path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; success = FALSE; } else { /* Extend path with filename */ @@ -211,7 +211,7 @@ static int sieve_file_script_open sieve_critical(svinst, ehandler, name, "failed to open sieve script", "sieve script file '%s' is not a regular file.", path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; success = FALSE; } } @@ -269,7 +269,7 @@ static int sieve_file_script_get_stream sieve_critical(svinst, ehandler, name, "failed to open sieve script", "failed to open sieve script: fstat(fd=%s) failed: %m", script->path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; result = NULL; } else { /* Re-check the file type just to be sure */ @@ -277,7 +277,7 @@ static int sieve_file_script_get_stream sieve_critical(svinst, ehandler, name, "failed to open sieve script", "sieve script file '%s' is not a regular file", script->path); - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; result = NULL; } else { result = i_stream_create_fd(fd, SIEVE_FILE_READ_BLOCK_SIZE, TRUE); diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c index ced71c99971af329c3862de348d679bfca8c3f67..19869483b330614b6aaadb7ac333d219aa6e3220 100644 --- a/src/lib-sieve/sieve-script.c +++ b/src/lib-sieve/sieve-script.c @@ -234,7 +234,7 @@ struct sieve_script *sieve_script_create if ( script_class == NULL ) { if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return NULL; } @@ -265,7 +265,7 @@ int sieve_script_open "failed to access sieve script", "failed to parse script location: %s", parse_error); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return -1; } diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h index 375a0f7ca193a4780d507a1e059f8f38dbe88641..33f2f27a5004ab4c0bfc4f1d121883d59836a39c 100644 --- a/src/lib-sieve/sieve-types.h +++ b/src/lib-sieve/sieve-types.h @@ -83,13 +83,13 @@ enum sieve_error { SIEVE_ERROR_NONE = 0, /* Temporary internal error */ - SIEVE_ERROR_TEMP_FAIL, + SIEVE_ERROR_TEMP_FAILURE, /* It's not possible to do the wanted operation */ SIEVE_ERROR_NOT_POSSIBLE, /* Invalid parameters (eg. script name not valid) */ SIEVE_ERROR_BAD_PARAMS, /* No permission to do the request */ - SIEVE_ERROR_NO_PERM, + SIEVE_ERROR_NO_PERMISSION, /* Out of disk space */ SIEVE_ERROR_NO_SPACE, /* Out of disk space */ @@ -235,10 +235,11 @@ struct sieve_exec_status { */ enum sieve_execution_exitcode { - SIEVE_EXEC_OK = 1, - SIEVE_EXEC_FAILURE = 0, - SIEVE_EXEC_BIN_CORRUPT = -1, - SIEVE_EXEC_KEEP_FAILED = -2 + SIEVE_EXEC_OK = 1, + SIEVE_EXEC_FAILURE = 0, + SIEVE_EXEC_TEMP_FAILURE = -1, + SIEVE_EXEC_BIN_CORRUPT = -2, + SIEVE_EXEC_KEEP_FAILED = -3 }; #endif /* __SIEVE_TYPES_H */ diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index c7bfd0ad9c7f313ffc827f96a1ce3b9ca0b4c9e7..f3ae31f9699b503642ef6de6a59e9be894c950e7 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -385,7 +385,6 @@ struct sieve_binary *sieve_open_script } else { sbin = sieve_compile_script(script, ehandler, flags, error_r); - /* Save the binary if compile was successful */ if ( sbin != NULL ) { if ( svinst->debug ) sieve_sys_debug(svinst, "script `%s' from %s successfully compiled", @@ -535,12 +534,17 @@ int sieve_execute if ( ret > 0 ) { /* Execute result */ ret = sieve_result_execute(result, keep); - } else if ( ret == 0 ) { + } else if ( ret == SIEVE_EXEC_FAILURE ) { /* Perform implicit keep if script failed with a normal runtime error */ - if ( !sieve_result_implicit_keep(result) ) { - ret = SIEVE_EXEC_KEEP_FAILED; - } else { + switch ( sieve_result_implicit_keep(result) ) { + case SIEVE_EXEC_OK: if ( keep != NULL ) *keep = TRUE; + break; + case SIEVE_EXEC_TEMP_FAILURE: + ret = SIEVE_EXEC_TEMP_FAILURE; + break; + default: + ret = SIEVE_EXEC_KEEP_FAILED; } } @@ -674,6 +678,39 @@ int sieve_multiscript_status(struct sieve_multiscript *mscript) return mscript->status; } +int sieve_multiscript_tempfail(struct sieve_multiscript **mscript, + struct sieve_error_handler *ehandler) +{ + struct sieve_result *result = (*mscript)->result; + int ret = (*mscript)->status; + + if ( ehandler != NULL ) + sieve_result_set_error_handler(result, ehandler); + + if ( (*mscript)->active ) { + ret = SIEVE_EXEC_TEMP_FAILURE; + + if ( !(*mscript)->teststream && sieve_result_executed(result) ) { + /* Part of the result is already executed, need to fall back to + * to implicit keep (FIXME) + */ + switch ( sieve_result_implicit_keep(result) ) { + case SIEVE_EXEC_OK: + ret = SIEVE_EXEC_FAILURE; + break; + default: + ret = SIEVE_EXEC_KEEP_FAILED; + } + } + } + + /* Cleanup */ + sieve_result_unref(&result); + *mscript = NULL; + + return ret; +} + int sieve_multiscript_finish(struct sieve_multiscript **mscript, struct sieve_error_handler *ehandler, bool *keep) { @@ -681,7 +718,7 @@ int sieve_multiscript_finish(struct sieve_multiscript **mscript, int ret = (*mscript)->status; if ( ehandler != NULL ) - sieve_result_set_error_handler((*mscript)->result, ehandler); + sieve_result_set_error_handler(result, ehandler); if ( (*mscript)->active ) { ret = SIEVE_EXEC_FAILURE; @@ -689,10 +726,19 @@ int sieve_multiscript_finish(struct sieve_multiscript **mscript, if ( (*mscript)->teststream ) { (*mscript)->keep = TRUE; } else { - if ( !sieve_result_implicit_keep((*mscript)->result) ) - ret = SIEVE_EXEC_KEEP_FAILED; - else + switch ( sieve_result_implicit_keep(result) ) { + case SIEVE_EXEC_OK: (*mscript)->keep = TRUE; + break; + case SIEVE_EXEC_TEMP_FAILURE: + if (!sieve_result_executed(result)) { + ret = SIEVE_EXEC_TEMP_FAILURE; + break; + } + /* fall through */ + default: + ret = SIEVE_EXEC_KEEP_FAILED; + } } } @@ -760,7 +806,7 @@ struct sieve_directory *sieve_directory_open "sieve dir path %s is relative to home directory, " "but home directory is not available.", path); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return NULL; } } @@ -776,13 +822,13 @@ struct sieve_directory *sieve_directory_open sieve_sys_error(svinst, "failed to open sieve dir: %s", eacces_error_get("stat", path)); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_sys_error(svinst, "failed to open sieve dir: stat(%s) failed: %m", path); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } return NULL; @@ -801,13 +847,13 @@ struct sieve_directory *sieve_directory_open sieve_sys_error(svinst, "failed to open sieve dir: %s", eacces_error_get("opendir", path)); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_sys_error(svinst, "failed to open sieve dir: opendir(%s) failed: " "%m", path); if ( error_r != NULL ) - *error_r = SIEVE_ERROR_TEMP_FAIL; + *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } return NULL; diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index b756c1dc57af6e1106a9fc0905c36275510f81b8..b2b2601684e886bb5d1759c679c05b43fba6c094 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -191,6 +191,8 @@ bool sieve_multiscript_run int sieve_multiscript_status(struct sieve_multiscript *mscript); +int sieve_multiscript_tempfail(struct sieve_multiscript **mscript, + struct sieve_error_handler *ehandler); int sieve_multiscript_finish (struct sieve_multiscript **mscript, struct sieve_error_handler *ehandler, bool *keep); diff --git a/src/lib-sievestorage/sieve-storage.c b/src/lib-sievestorage/sieve-storage.c index eb6a4a43d9232ea52bfec3695aed22c138024ef4..fb1d65c8e8cdff2afbc66ebf3d6cb14d5f32b94b 100644 --- a/src/lib-sievestorage/sieve-storage.c +++ b/src/lib-sievestorage/sieve-storage.c @@ -596,7 +596,7 @@ static void ATTR_FORMAT(4, 0) sieve_storage_verror if (fmt != NULL) { storage->error = i_strdup_vprintf(fmt, args); } - storage->error_code = SIEVE_ERROR_TEMP_FAIL; + storage->error_code = SIEVE_ERROR_TEMP_FAILURE; } void sieve_storage_clear_error(struct sieve_storage *storage) @@ -631,7 +631,7 @@ void sieve_storage_set_critical sieve_storage_clear_error(storage); if (fmt != NULL) { i_free(storage->error); - storage->error_code = SIEVE_ERROR_TEMP_FAIL; + storage->error_code = SIEVE_ERROR_TEMP_FAILURE; if ( (storage->flags & SIEVE_STORAGE_FLAG_SYNCHRONIZING) == 0 ) { struct tm *tm; diff --git a/src/managesieve/managesieve-client.c b/src/managesieve/managesieve-client.c index de97723c63d67c581595504f1aeb7ba87ce6f4e7..2e9b9610212c5bb7d697f0b96f5e6d481edd177d 100644 --- a/src/managesieve/managesieve-client.c +++ b/src/managesieve/managesieve-client.c @@ -382,7 +382,7 @@ void client_send_storage_error error = sieve_storage_get_last_error(storage, &error_code); switch ( error_code ) { - case SIEVE_ERROR_TEMP_FAIL: + case SIEVE_ERROR_TEMP_FAILURE: client_send_noresp(client, "TRYLATER", error); break; diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index 77a185082870756acad58fdc2efc4cd6a8e0eec5..bf1ea939b1e31a7854dfaa2aac212612d3978d8a 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -128,6 +128,7 @@ struct lda_sieve_run_context { struct sieve_instance *svinst; struct mail_deliver_context *mdctx; + const char *home_dir; struct sieve_script **scripts; unsigned int script_count; @@ -183,18 +184,18 @@ static const char *lda_sieve_get_default_location static int lda_sieve_multiscript_get_scripts (struct sieve_instance *svinst, const char *label, const char *location, - struct sieve_error_handler *ehandler, ARRAY_TYPE(sieve_scripts) *scripts) + struct sieve_error_handler *ehandler, ARRAY_TYPE(sieve_scripts) *scripts, + enum sieve_error *error_r) { struct sieve_directory *sdir; - enum sieve_error error; ARRAY_TYPE(const_string) script_files; const char *const *files; unsigned int count, i; const char *file; // FIXME: make this a generic iteration API - if ( (sdir=sieve_directory_open(svinst, location, &error)) == NULL ) - return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); + if ( (sdir=sieve_directory_open(svinst, location, error_r)) == NULL ) + return ( *error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); t_array_init(&script_files, 16); @@ -218,19 +219,23 @@ static int lda_sieve_multiscript_get_scripts files = array_get(&script_files, &count); for ( i = 0; i < count; i++ ) { struct sieve_script *script = sieve_script_create_open - (svinst, files[i], NULL, ehandler, &error); + (svinst, files[i], NULL, ehandler, error_r); if ( script == NULL ) { - switch ( error ) { + switch ( *error_r ) { case SIEVE_ERROR_NOT_FOUND: /* Shouldn't normally happen, but the script could have disappeared */ - sieve_sys_warning - (svinst, "%s script %s doesn't exist", label, files[i]); + sieve_sys_warning(svinst, + "%s script %s doesn't exist", label, files[i]); break; - + case SIEVE_ERROR_TEMP_FAILURE: + sieve_sys_error(svinst, + "failed to access %s script %s (temporary failure)", + label, files[i]); + return -1; default: - sieve_sys_error - (svinst, "failed to access %s script %s", label, files[i]); + sieve_sys_error(svinst, + "failed to access %s script %s", label, files[i]); break; } @@ -240,6 +245,7 @@ static int lda_sieve_multiscript_get_scripts array_append(scripts, &script, 1); } + *error_r = SIEVE_ERROR_NONE; return 1; } @@ -251,7 +257,7 @@ static void lda_sieve_binary_save /* Save binary when compiled */ if ( sieve_save(sbin, FALSE, &error) < 0 && - error == SIEVE_ERROR_NO_PERM && script != srctx->user_script ) { + error == SIEVE_ERROR_NO_PERMISSION && script != srctx->user_script ) { /* Cannot save binary for global script */ sieve_sys_error(srctx->svinst, @@ -264,105 +270,76 @@ static void lda_sieve_binary_save static struct sieve_binary *lda_sieve_open (struct lda_sieve_run_context *srctx, struct sieve_script *script, - enum sieve_compile_flags cpflags, enum sieve_error *error_r) + enum sieve_compile_flags cpflags, bool recompile, enum sieve_error *error_r) { struct sieve_instance *svinst = srctx->svinst; struct sieve_error_handler *ehandler; struct sieve_binary *sbin; bool debug = srctx->mdctx->dest_user->mail_debug; + const char *compile_name = "compile"; + + if ( recompile ) { + /* Warn */ + sieve_sys_warning(svinst, + "encountered corrupt binary: re-compiling script %s", + sieve_script_location(script)); + compile_name = "re-compile"; + } else if ( debug ) { + sieve_sys_debug(svinst, + "loading script %s", sieve_script_location(script)); + } if ( script == srctx->user_script ) ehandler = srctx->user_ehandler; else ehandler = srctx->master_ehandler; - if ( debug ) - sieve_sys_debug(svinst, "loading script %s", sieve_script_location(script)); - sieve_error_handler_reset(ehandler); + if ( recompile ) + sbin = sieve_compile_script(script, ehandler, cpflags, error_r); + else + sbin = sieve_open_script(script, ehandler, cpflags, error_r); + /* Load or compile the sieve script */ - if ( (sbin=sieve_open_script(script, ehandler, cpflags, error_r)) == NULL ) { + if ( sbin == NULL ) { switch ( *error_r ) { /* Script not found */ case SIEVE_ERROR_NOT_FOUND: if ( debug ) { - sieve_sys_debug(svinst, "script file %s is missing", - sieve_script_location(script)); + sieve_sys_debug(svinst, "script file %s is missing for %s", + sieve_script_location(script), compile_name); } break; + /* Temporary failure */ + case SIEVE_ERROR_TEMP_FAILURE: + sieve_sys_error(svinst, + "failed to open script %s for %s (temporary failure)", + sieve_script_location(script), compile_name); + break; /* Compile failed */ case SIEVE_ERROR_NOT_VALID: if (script == srctx->user_script && srctx->userlog != NULL ) { - sieve_sys_info(svinst, "failed to compile script %s " + sieve_sys_info(svinst, "failed to %s script %s " "(view user logfile %s for more information)", - sieve_script_location(script), srctx->userlog); + compile_name, sieve_script_location(script), srctx->userlog); break; } - /* Fall through */ + sieve_sys_error(svinst, "failed to %s script %s", + compile_name, sieve_script_location(script)); + break; /* Something else */ default: - sieve_sys_error(svinst, "failed to open script %s", - sieve_script_location(script)); - break; - } - - return NULL; - } - - lda_sieve_binary_save(srctx, sbin, script); - return sbin; -} - -static struct sieve_binary *lda_sieve_recompile -(struct lda_sieve_run_context *srctx, struct sieve_script *script, - enum sieve_compile_flags cpflags, enum sieve_error *error_r) -{ - struct sieve_instance *svinst = srctx->svinst; - struct sieve_error_handler *ehandler; - struct sieve_binary *sbin; - bool debug = srctx->mdctx->dest_user->mail_debug; - - /* Warn */ - - sieve_sys_warning(svinst, - "encountered corrupt binary: re-compiling script %s", - sieve_script_location(script)); - - /* Recompile */ - - if ( script == srctx->user_script ) - ehandler = srctx->user_ehandler; - else - ehandler = srctx->master_ehandler; - - if ( (sbin=sieve_compile_script(script, ehandler, cpflags, error_r)) - == NULL ) { - - switch ( *error_r ) { - case SIEVE_ERROR_NOT_FOUND: - if ( debug ) { - sieve_sys_debug(svinst, "script file %s is missing for re-compile", - sieve_script_location(script)); - } + sieve_sys_error(svinst, "failed to open script %s for %s", + sieve_script_location(script), compile_name); break; - case SIEVE_ERROR_NOT_VALID: - if ( script == srctx->user_script && srctx->userlog != NULL ) { - sieve_sys_info(svinst, - "failed to re-compile script %s " - "(view user logfile %s for more information)", - sieve_script_location(script), srctx->userlog); - break; - } - /* Fall through */ - default: - sieve_sys_error(svinst, "failed to open script %s for re-compile", - sieve_script_location(script)); } return NULL; } + if (!recompile) + lda_sieve_binary_save(srctx, sbin, script); return sbin; } @@ -370,16 +347,16 @@ static int lda_sieve_handle_exec_status (struct lda_sieve_run_context *srctx, struct sieve_script *script, int status) { struct sieve_instance *svinst = srctx->svinst; + struct mail_deliver_context *mdctx = srctx->mdctx; struct sieve_exec_status *estatus = srctx->scriptenv->exec_status; const char *userlog_notice = ""; sieve_sys_error_func_t error_func, user_error_func; + enum mail_error mail_error = MAIL_ERROR_NONE; int ret; error_func = user_error_func = sieve_sys_error; if ( estatus != NULL && estatus->last_storage != NULL ) { - enum mail_error mail_error; - mail_storage_get_last_error(estatus->last_storage, &mail_error); /* Don't bother administrator too much with benign errors */ @@ -391,7 +368,7 @@ static int lda_sieve_handle_exec_status if ( script == srctx->user_script && srctx->userlog != NULL ) { userlog_notice = t_strdup_printf - (" (user logfile %s should reveal additional details)", srctx->userlog); + (" (user logfile %s may reveal additional details)", srctx->userlog); user_error_func = sieve_sys_info; } @@ -402,6 +379,16 @@ static int lda_sieve_handle_exec_status sieve_script_location(script), userlog_notice); ret = 1; break; + case SIEVE_EXEC_TEMP_FAILURE: + error_func(svinst, + "execution of script %s was aborted due to temporary failure%s", + sieve_script_location(script), userlog_notice); + if ( mail_error != MAIL_ERROR_TEMP && mdctx->tempfail_error == NULL ) { + mdctx->tempfail_error = + "Execution of Sieve filters was aborted due to temporary failure"; + } + ret = -1; + break; case SIEVE_EXEC_BIN_CORRUPT: sieve_sys_error(svinst, "!!BUG!!: binary compiled from %s is still corrupt; " @@ -411,7 +398,7 @@ static int lda_sieve_handle_exec_status break; case SIEVE_EXEC_KEEP_FAILED: error_func(svinst, - "script %s failed with unsuccessful implicit keep%s", + "execution of script %s failed with unsuccessful implicit keep%s", sieve_script_location(script), userlog_notice); ret = -1; break; @@ -447,8 +434,18 @@ static int lda_sieve_singlescript_execute /* Open the script */ - if ( (sbin=lda_sieve_open(srctx, script, cpflags, &error)) == NULL ) - return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); + sbin = lda_sieve_open(srctx, script, cpflags, FALSE, &error); + if ( sbin == NULL ) { + switch ( error ) { + case SIEVE_ERROR_NOT_FOUND: + return 0; + case SIEVE_ERROR_TEMP_FAILURE: + return lda_sieve_handle_exec_status + (srctx, script, SIEVE_EXEC_TEMP_FAILURE); + default: + return -1; + } + } /* Execute */ @@ -467,8 +464,18 @@ static int lda_sieve_singlescript_execute /* Recompile */ - if ( (sbin=lda_sieve_recompile(srctx, script, cpflags, &error)) == NULL ) - return ( error == SIEVE_ERROR_NOT_FOUND ? 0 : -1 ); + sbin = lda_sieve_open(srctx, script, cpflags, TRUE, &error); + if ( sbin == NULL ) { + switch ( error ) { + case SIEVE_ERROR_NOT_FOUND: + return 0; + case SIEVE_ERROR_TEMP_FAILURE: + return lda_sieve_handle_exec_status + (srctx, script, SIEVE_EXEC_TEMP_FAILURE); + default: + return -1; + } + } /* Execute again */ @@ -502,9 +509,9 @@ static int lda_sieve_multiscript_execute bool debug = srctx->mdctx->dest_user->mail_debug; struct sieve_script *last_script = NULL; bool user_script = FALSE, more = TRUE, compile_error = FALSE; - unsigned int i; - int ret = 1; enum sieve_error error; + unsigned int i; + int ret; /* Start execution */ @@ -539,7 +546,8 @@ static int lda_sieve_multiscript_execute sieve_script_location(script)); } - if ( (sbin=lda_sieve_open(srctx, script, cpflags, &error)) == NULL ) { + sbin = lda_sieve_open(srctx, script, cpflags, FALSE, &error); + if ( sbin == NULL ) { compile_error = TRUE; break; } @@ -562,9 +570,11 @@ static int lda_sieve_multiscript_execute /* Recompile */ - sbin=lda_sieve_recompile(srctx, script, cpflags, &error); - if ( sbin == NULL ) + sbin = lda_sieve_open(srctx, script, cpflags, TRUE, &error); + if ( sbin == NULL ) { + compile_error = TRUE; break; + } /* Execute again */ @@ -583,138 +593,129 @@ static int lda_sieve_multiscript_execute } /* Finish execution */ - - ret = sieve_multiscript_finish(&mscript, ehandler, NULL); + if ( compile_error && error == SIEVE_ERROR_TEMP_FAILURE ) + ret = sieve_multiscript_tempfail(&mscript, ehandler); + else + ret = sieve_multiscript_finish(&mscript, ehandler, NULL); /* Don't log additional messages about compile failure */ if ( compile_error && ret == SIEVE_EXEC_FAILURE ) { sieve_sys_info(svinst, - "aborted script execution sequence with successful implicit keep"); + "aborted script execution sequence with successful implicit keep"); return 1; } return lda_sieve_handle_exec_status(srctx, last_script, ret); } -static int lda_sieve_deliver_mail -(struct mail_deliver_context *mdctx, struct mail_storage **storage_r) +static int lda_sieve_find_scripts(struct lda_sieve_run_context *srctx) { - struct lda_sieve_run_context srctx; - struct sieve_environment svenv; - struct sieve_instance *svinst; - struct sieve_message_data msgdata; - struct sieve_script_env scriptenv; - struct sieve_exec_status estatus; - struct sieve_error_handler *master_ehandler; + struct mail_deliver_context *mdctx = srctx->mdctx; + struct sieve_instance *svinst = srctx->svinst; + struct sieve_error_handler *master_ehandler = srctx->master_ehandler; const char *user_location, *default_location, *sieve_before, *sieve_after; const char *setting_name; + enum sieve_error error; ARRAY_TYPE(sieve_scripts) script_sequence; - unsigned int after_index; + struct sieve_script *const *scripts; bool debug = mdctx->dest_user->mail_debug; - enum sieve_error error; - int ret = 0; - - /* Initialize Sieve engine */ - - memset((void*)&svenv, 0, sizeof(svenv)); - svenv.username = mdctx->dest_user->username; - (void)mail_user_get_home(mdctx->dest_user, &svenv.home_dir); - svenv.hostname = mdctx->set->hostname; - svenv.base_dir = mdctx->dest_user->set->base_dir; - svenv.flags = SIEVE_FLAG_HOME_RELATIVE; - svenv.location = SIEVE_ENV_LOCATION_MDA; - svenv.delivery_phase = SIEVE_DELIVERY_PHASE_DURING; - - svinst = sieve_init(&svenv, &lda_sieve_callbacks, mdctx, debug); - - /* Initialize master error handler */ - - master_ehandler = sieve_master_ehandler_create(svinst, mdctx->session_id, 0); - sieve_system_ehandler_set(master_ehandler); - - sieve_error_handler_accept_infolog(master_ehandler, TRUE); - sieve_error_handler_accept_debuglog(master_ehandler, debug); - - *storage_r = NULL; - - /* Find scripts and run them */ - - T_BEGIN { - struct sieve_script *const *scripts; - unsigned int count, i; - - /* Initialize run context */ - - memset(&srctx, 0, sizeof(srctx)); - srctx.svinst = svinst; - srctx.mdctx = mdctx; - srctx.master_ehandler = master_ehandler; + unsigned int after_index, count, i; + int ret = 1; - /* Find the personal script to execute */ + /* Find the personal script to execute */ - user_location = lda_sieve_get_personal_location(svinst, mdctx->dest_user); - if ( user_location != NULL ) { - srctx.user_script = sieve_script_create_open_as - (svinst, user_location, "main script", master_ehandler, &error); + user_location = lda_sieve_get_personal_location(svinst, mdctx->dest_user); + if ( user_location != NULL ) { + srctx->user_script = sieve_script_create_open_as + (svinst, user_location, "main script", master_ehandler, &error); - if ( srctx.user_script == NULL ) { - switch ( error ) { - case SIEVE_ERROR_NOT_FOUND: - if ( debug ) - sieve_sys_debug(svinst, "user's script %s doesn't exist " - "(using default script location instead)", user_location); - break; - default: - sieve_sys_error(svinst, "failed to access user's sieve script %s " - "(using default script location instead)", - user_location); - break; + if ( srctx->user_script == NULL ) { + switch ( error ) { + case SIEVE_ERROR_NOT_FOUND: + if ( debug ) { + sieve_sys_debug(svinst, "user's script %s doesn't exist " + "(trying default script location instead)", user_location); } - } else { - srctx.main_script = srctx.user_script; + break; + case SIEVE_ERROR_TEMP_FAILURE: + sieve_sys_error(svinst, + "failed to access user's Sieve script %s (temporary failure)", + user_location); + ret = -1; + break; + default: + sieve_sys_error(svinst, + "failed to access user's Sieve script %s " + "(trying default script location instead)", + user_location); + break; } + } else { + srctx->main_script = srctx->user_script; } + } - if ( srctx.user_script == NULL ) { - default_location = lda_sieve_get_default_location(mdctx->dest_user); - if ( default_location != NULL ) { - srctx.main_script = sieve_script_create_open_as - (svinst, default_location, "main script", master_ehandler, &error); + if ( ret >= 0 && srctx->user_script == NULL ) { + default_location = lda_sieve_get_default_location(mdctx->dest_user); + if ( default_location != NULL ) { + srctx->main_script = sieve_script_create_open_as + (svinst, default_location, "main script", master_ehandler, &error); - if ( srctx.main_script == NULL && error == SIEVE_ERROR_NOT_FOUND && - debug ) { - sieve_sys_debug(svinst, "default user script %s doesn't exist", + if ( srctx->main_script == NULL ) { + switch ( error ) { + case SIEVE_ERROR_NOT_FOUND: + if ( debug ) { + sieve_sys_debug(svinst, "default user script %s doesn't exist", + default_location); + } + break; + case SIEVE_ERROR_TEMP_FAILURE: + sieve_sys_error(svinst, + "failed to access default user script %s (temporary failure)", default_location); + ret = -1; + break; + default: + sieve_sys_error(svinst, "failed to access default user script %s", + default_location); + break; } - } else { - sieve_sys_debug(svinst, "no default script configured for user"); } + } else { + sieve_sys_debug(svinst, "no default script configured for user"); } + } - if ( debug && srctx.main_script == NULL ) { - sieve_sys_debug(svinst, - "user has no valid location for a personal script"); - } - - /* Compose script array */ + if ( debug && ret >= 0 && srctx->main_script == NULL ) { + sieve_sys_debug(svinst, + "user has no valid location for a personal script"); + } - t_array_init(&script_sequence, 16); + /* Compose script array */ + t_array_init(&script_sequence, 16); + + /* before */ + if ( ret >= 0 ) { i = 2; setting_name = "sieve_before"; sieve_before = mail_user_plugin_getenv(mdctx->dest_user, setting_name); - while ( sieve_before != NULL && *sieve_before != '\0' ) { - if ( lda_sieve_multiscript_get_scripts - (svinst, setting_name, sieve_before, master_ehandler, - &script_sequence) == 0 && debug ) { + while ( ret >= 0 && sieve_before != NULL && *sieve_before != '\0' ) { + ret = lda_sieve_multiscript_get_scripts(svinst, setting_name, + sieve_before, master_ehandler, &script_sequence, &error); + if ( ret < 0 && error == SIEVE_ERROR_TEMP_FAILURE ) { + ret = -1; + break; + } else if (ret == 0 && debug ) { sieve_sys_debug(svinst, "%s location not found: %s", setting_name, sieve_before); } + ret = 0; setting_name = t_strdup_printf("sieve_before%u", i++); sieve_before = mail_user_plugin_getenv(mdctx->dest_user, setting_name); } - if ( debug ) { + if ( ret >= 0 && debug ) { scripts = array_get(&script_sequence, &count); for ( i = 0; i < count; i ++ ) { sieve_sys_debug(svinst, @@ -722,156 +723,229 @@ static int lda_sieve_deliver_mail i+1, sieve_script_location(scripts[i])); } } + } - if ( srctx.main_script != NULL ) { - array_append(&script_sequence, &srctx.main_script, 1); + /* main */ + if ( srctx->main_script != NULL ) { + array_append(&script_sequence, &srctx->main_script, 1); - if ( debug ) { - sieve_sys_debug(svinst, - "using the following location for user's Sieve script: %s", - sieve_script_location(srctx.main_script)); - } + if ( ret >= 0 && debug ) { + sieve_sys_debug(svinst, + "using the following location for user's Sieve script: %s", + sieve_script_location(srctx->main_script)); } + } - after_index = array_count(&script_sequence); + after_index = array_count(&script_sequence); + /* after */ + if ( ret >= 0 ) { i = 2; setting_name = "sieve_after"; sieve_after = mail_user_plugin_getenv(mdctx->dest_user, setting_name); while ( sieve_after != NULL && *sieve_after != '\0' ) { - if ( lda_sieve_multiscript_get_scripts(svinst, setting_name, - sieve_after, master_ehandler, &script_sequence) == 0 && debug ) { + ret = lda_sieve_multiscript_get_scripts(svinst, setting_name, + sieve_after, master_ehandler, &script_sequence, &error); + if ( ret < 0 && error == SIEVE_ERROR_TEMP_FAILURE ) { + ret = -1; + break; + } else if (ret == 0 && debug ) { sieve_sys_debug(svinst, "%s location not found: %s", setting_name, sieve_after); } + ret = 0; setting_name = t_strdup_printf("sieve_after%u", i++); sieve_after = mail_user_plugin_getenv(mdctx->dest_user, setting_name); } - if ( debug ) { + if ( ret >= 0 && debug ) { scripts = array_get(&script_sequence, &count); for ( i = after_index; i < count; i ++ ) { sieve_sys_debug(svinst, "executed after user's Sieve script(%d): %s", i+1, sieve_script_location(scripts[i])); } } + } - srctx.scripts = - array_get_modifiable(&script_sequence, &srctx.script_count); + if (ret < 0) { + mdctx->tempfail_error = + "Temporarily unable to access necessary Sieve scripts"; + } + srctx->scripts = + array_get_modifiable(&script_sequence, &srctx->script_count); + return ret; +} - /* Check whether there are any scripts to execute at all */ +static int lda_sieve_execute +(struct lda_sieve_run_context *srctx, struct mail_storage **storage_r) +{ + struct mail_deliver_context *mdctx = srctx->mdctx; + struct sieve_instance *svinst = srctx->svinst; + struct sieve_message_data msgdata; + struct sieve_script_env scriptenv; + struct sieve_exec_status estatus; + bool debug = mdctx->dest_user->mail_debug; + int ret; - if ( srctx.script_count == 0 ) { - if ( debug ) { - sieve_sys_debug(svinst, - "no scripts to execute: reverting to default delivery."); - } + /* Check whether there are any scripts to execute at all */ - /* No error, but no delivery by this plugin either. A return value of <= 0 - * for a deliver plugin is is considered a failure. In deliver itself, - * saved_mail and tried_default_save remain unset, meaning that deliver - * will then attempt the default delivery. We return 0 to signify the lack - * of a real error. - */ - ret = 0; - } else { - /* Initialize user error handler */ - - if ( srctx.user_script != NULL ) { - const char *log_path = NULL; - - /* Determine user log file path */ - if ( (log_path=mail_user_plugin_getenv - (mdctx->dest_user, "sieve_user_log")) == NULL ) { - const char *path; - - if ( (path=sieve_file_script_get_path(srctx.user_script)) == NULL ) { - /* Default */ - if ( svenv.home_dir != NULL ) { - log_path = t_strconcat - (svenv.home_dir, "/.dovecot.sieve.log", NULL); - } - } else { - /* Use script file as a basic (legacy behavior) */ - log_path = t_strconcat(path, ".log", NULL); - } - } else if ( svenv.home_dir != NULL ) { - /* Expand home dir if necessary */ - if ( log_path[0] == '~' ) { - log_path = home_expand_tilde(log_path, svenv.home_dir); - } else if ( log_path[0] != '/' ) { - log_path = t_strconcat(svenv.home_dir, "/", log_path, NULL); + if ( srctx->script_count == 0 ) { + if ( debug ) { + sieve_sys_debug(svinst, + "no scripts to execute: reverting to default delivery."); + } + + /* No error, but no delivery by this plugin either. A return value of <= 0 + * for a deliver plugin is is considered a failure. In deliver itself, + * saved_mail and tried_default_save remain unset, meaning that deliver + * will then attempt the default delivery. We return 0 to signify the lack + * of a real error. + */ + ret = 0; + } else { + /* Initialize user error handler */ + + if ( srctx->user_script != NULL ) { + const char *log_path = NULL; + + /* Determine user log file path */ + if ( (log_path=mail_user_plugin_getenv + (mdctx->dest_user, "sieve_user_log")) == NULL ) { + const char *path; + + if ( (path=sieve_file_script_get_path(srctx->user_script)) == NULL ) { + /* Default */ + if ( srctx->home_dir != NULL ) { + log_path = t_strconcat + (srctx->home_dir, "/.dovecot.sieve.log", NULL); } + } else { + /* Use script file as a basic (legacy behavior) */ + log_path = t_strconcat(path, ".log", NULL); } - - if ( log_path != NULL ) { - srctx.userlog = log_path; - srctx.user_ehandler = sieve_logfile_ehandler_create - (svinst, srctx.userlog, LDA_SIEVE_MAX_USER_ERRORS); + } else if ( srctx->home_dir != NULL ) { + /* Expand home dir if necessary */ + if ( log_path[0] == '~' ) { + log_path = home_expand_tilde(log_path, srctx->home_dir); + } else if ( log_path[0] != '/' ) { + log_path = t_strconcat(srctx->home_dir, "/", log_path, NULL); } } - /* Collect necessary message data */ + if ( log_path != NULL ) { + srctx->userlog = log_path; + srctx->user_ehandler = sieve_logfile_ehandler_create + (svinst, srctx->userlog, LDA_SIEVE_MAX_USER_ERRORS); + } + } - memset(&msgdata, 0, sizeof(msgdata)); + /* Collect necessary message data */ - msgdata.mail = mdctx->src_mail; - msgdata.return_path = mail_deliver_get_return_address(mdctx); - msgdata.orig_envelope_to = mdctx->dest_addr; - msgdata.final_envelope_to = mdctx->final_dest_addr; - msgdata.auth_user = mdctx->dest_user->username; - (void)mail_get_first_header(msgdata.mail, "Message-ID", &msgdata.id); + memset(&msgdata, 0, sizeof(msgdata)); - srctx.msgdata = &msgdata; + msgdata.mail = mdctx->src_mail; + msgdata.return_path = mail_deliver_get_return_address(mdctx); + msgdata.orig_envelope_to = mdctx->dest_addr; + msgdata.final_envelope_to = mdctx->final_dest_addr; + msgdata.auth_user = mdctx->dest_user->username; + (void)mail_get_first_header(msgdata.mail, "Message-ID", &msgdata.id); - /* Compose script execution environment */ + srctx->msgdata = &msgdata; - memset(&scriptenv, 0, sizeof(scriptenv)); - memset(&estatus, 0, sizeof(estatus)); + /* Compose script execution environment */ - scriptenv.action_log_format = mdctx->set->deliver_log_format; - scriptenv.default_mailbox = mdctx->dest_mailbox_name; - scriptenv.mailbox_autocreate = mdctx->set->lda_mailbox_autocreate; - scriptenv.mailbox_autosubscribe = mdctx->set->lda_mailbox_autosubscribe; - scriptenv.user = mdctx->dest_user; - scriptenv.postmaster_address = mdctx->set->postmaster_address; - scriptenv.smtp_open = lda_sieve_smtp_open; - scriptenv.smtp_close = lda_sieve_smtp_close; - scriptenv.duplicate_mark = lda_sieve_duplicate_mark; - scriptenv.duplicate_check = lda_sieve_duplicate_check; - scriptenv.reject_mail = lda_sieve_reject_mail; - scriptenv.script_context = (void *) mdctx; - scriptenv.exec_status = &estatus; + memset(&scriptenv, 0, sizeof(scriptenv)); + memset(&estatus, 0, sizeof(estatus)); - srctx.scriptenv = &scriptenv; + scriptenv.action_log_format = mdctx->set->deliver_log_format; + scriptenv.default_mailbox = mdctx->dest_mailbox_name; + scriptenv.mailbox_autocreate = mdctx->set->lda_mailbox_autocreate; + scriptenv.mailbox_autosubscribe = mdctx->set->lda_mailbox_autosubscribe; + scriptenv.user = mdctx->dest_user; + scriptenv.postmaster_address = mdctx->set->postmaster_address; + scriptenv.smtp_open = lda_sieve_smtp_open; + scriptenv.smtp_close = lda_sieve_smtp_close; + scriptenv.duplicate_mark = lda_sieve_duplicate_mark; + scriptenv.duplicate_check = lda_sieve_duplicate_check; + scriptenv.reject_mail = lda_sieve_reject_mail; + scriptenv.script_context = (void *) mdctx; + scriptenv.exec_status = &estatus; - /* Execute script(s) */ + srctx->scriptenv = &scriptenv; - if ( srctx.script_count == 1 ) - ret = lda_sieve_singlescript_execute(&srctx); - else - ret = lda_sieve_multiscript_execute(&srctx); + /* Execute script(s) */ - /* Record status */ + if ( srctx->script_count == 1 ) + ret = lda_sieve_singlescript_execute(srctx); + else + ret = lda_sieve_multiscript_execute(srctx); - mdctx->tried_default_save = estatus.tried_default_save; - *storage_r = estatus.last_storage; + /* Record status */ - /* Clean up user error handlers */ + mdctx->tried_default_save = estatus.tried_default_save; + *storage_r = estatus.last_storage; + } - if ( srctx.user_ehandler != NULL ) - sieve_error_handler_unref(&srctx.user_ehandler); - } + return ret; +} - /* Cleanup scripts */ - for ( i = 0; i < srctx.script_count; i++ ) { - sieve_script_unref(&srctx.scripts[i]); - } +static int lda_sieve_deliver_mail +(struct mail_deliver_context *mdctx, struct mail_storage **storage_r) +{ + struct lda_sieve_run_context srctx; + bool debug = mdctx->dest_user->mail_debug; + struct sieve_environment svenv; + unsigned int i; + int ret = 0; + + /* Initialize run context */ + + memset(&srctx, 0, sizeof(srctx)); + srctx.mdctx = mdctx; + (void)mail_user_get_home(mdctx->dest_user, &srctx.home_dir); + + /* Initialize Sieve engine */ + + memset((void*)&svenv, 0, sizeof(svenv)); + svenv.username = mdctx->dest_user->username; + svenv.home_dir = srctx.home_dir; + svenv.hostname = mdctx->set->hostname; + svenv.base_dir = mdctx->dest_user->set->base_dir; + svenv.flags = SIEVE_FLAG_HOME_RELATIVE; + svenv.location = SIEVE_ENV_LOCATION_MDA; + svenv.delivery_phase = SIEVE_DELIVERY_PHASE_DURING; + + srctx.svinst = sieve_init(&svenv, &lda_sieve_callbacks, mdctx, debug); + + /* Initialize master error handler */ + srctx.master_ehandler = + sieve_master_ehandler_create(srctx.svinst, mdctx->session_id, 0); + sieve_system_ehandler_set(srctx.master_ehandler); + + sieve_error_handler_accept_infolog(srctx.master_ehandler, TRUE); + sieve_error_handler_accept_debuglog(srctx.master_ehandler, debug); + + *storage_r = NULL; + + /* Find Sieve scripts and run them */ + + T_BEGIN { + if (lda_sieve_find_scripts(&srctx) < 0) + ret = -1; + else + ret = lda_sieve_execute(&srctx, storage_r); } T_END; - sieve_deinit(&svinst); - sieve_error_handler_unref(&master_ehandler); + /* Clean up */ + + for ( i = 0; i < srctx.script_count; i++ ) + sieve_script_unref(&srctx.scripts[i]); + if ( srctx.user_ehandler != NULL ) + sieve_error_handler_unref(&srctx.user_ehandler); + sieve_error_handler_unref(&srctx.master_ehandler); + sieve_deinit(&srctx.svinst); + return ret; } diff --git a/src/plugins/sieve-extprograms/cmd-pipe.c b/src/plugins/sieve-extprograms/cmd-pipe.c index 94f05cea2488f7b5aafc9a0a2698b727ffca9b6b..fbbdbc81ce23c4f735afa90755b0f18c83a70c7d 100644 --- a/src/plugins/sieve-extprograms/cmd-pipe.c +++ b/src/plugins/sieve-extprograms/cmd-pipe.c @@ -92,7 +92,7 @@ static int act_pipe_check_duplicate static void act_pipe_print (const struct sieve_action *action, const struct sieve_result_print_env *rpenv, bool *keep); -static bool act_pipe_commit +static int act_pipe_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep); @@ -328,7 +328,7 @@ static void act_pipe_print /* Result execution */ -static bool act_pipe_commit +static int act_pipe_commit (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED, bool *keep) { @@ -354,6 +354,9 @@ static bool act_pipe_commit if ( ret > 0 ) { sieve_result_global_log(aenv, "pipe action: " "piped message to program `%s'", str_sanitize(act->program_name, 128)); + + /* Indicate that message was successfully 'forwarded' */ + aenv->exec_status->message_forwarded = TRUE; } else { if ( ret < 0 ) { if ( error == SIEVE_ERROR_NOT_FOUND ) { @@ -371,13 +374,13 @@ static bool act_pipe_commit str_sanitize(act->program_name, 80)); } - if ( act->try ) return TRUE; + if ( act->try ) return SIEVE_EXEC_OK; - return FALSE; + return SIEVE_EXEC_FAILURE; } *keep = FALSE; - return TRUE; + return SIEVE_EXEC_OK; } diff --git a/src/plugins/sieve-extprograms/sieve-extprograms-common.c b/src/plugins/sieve-extprograms/sieve-extprograms-common.c index 59f39f138f758fe93806a9d49ef3c3bde8621803..283bd2a0725b40ef934f3d026d710596ec0d693b 100644 --- a/src/plugins/sieve-extprograms/sieve-extprograms-common.c +++ b/src/plugins/sieve-extprograms/sieve-extprograms-common.c @@ -439,12 +439,12 @@ struct sieve_extprogram *sieve_extprogram_create case EACCES: sieve_sys_error(svinst, "action %s: " "failed to stat socket: %s", action, eacces_error_get("stat", path)); - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; return NULL; default: sieve_sys_error(svinst, "action %s: " "failed to stat socket `%s': %m", action, path); - *error_r = SIEVE_ERROR_NOT_POSSIBLE; + *error_r = SIEVE_ERROR_TEMP_FAILURE; return NULL; } path = NULL; @@ -476,12 +476,12 @@ struct sieve_extprogram *sieve_extprogram_create case EACCES: sieve_sys_error(svinst, "action %s: " "failed to stat program: %s", action, eacces_error_get("stat", path)); - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; break; default: sieve_sys_error(svinst, "action %s: " "failed to stat program `%s': %m", action, path); - *error_r = SIEVE_ERROR_NOT_POSSIBLE; + *error_r = SIEVE_ERROR_TEMP_FAILURE; break; } @@ -496,7 +496,7 @@ struct sieve_extprogram *sieve_extprogram_create sieve_sys_error(svinst, "action %s: " "executable `%s' for program `%s' is world-writable", action, path, program_name); - *error_r = SIEVE_ERROR_NO_PERM; + *error_r = SIEVE_ERROR_NO_PERMISSION; return NULL; } } diff --git a/src/sieve-tools/sieve-filter.c b/src/sieve-tools/sieve-filter.c index af3554f09a7cc8ef7abbeb99116d301b2394e926..d0548068d84262836e5ca50285a1d90ab1dae313 100644 --- a/src/sieve-tools/sieve-filter.c +++ b/src/sieve-tools/sieve-filter.c @@ -218,15 +218,12 @@ static int filter_message sieve_error(ehandler, NULL, "sieve script binary is corrupt"); return -1; case SIEVE_EXEC_FAILURE: + case SIEVE_EXEC_TEMP_FAILURE: case SIEVE_EXEC_KEEP_FAILED: sieve_error(ehandler, NULL, "sieve script execution failed for this message; " "message left in source mailbox"); return 0; - default: - sieve_error(ehandler, NULL, - "sieve execution result: unrecognized return value?!"); - return -1; } return 1; diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 3c78153ce42dc439399871b57fafd4850e50ae2e..63e62e3ddcf0eb46296ce7109b7d5dafc42de19e 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -371,12 +371,12 @@ int main(int argc, char **argv) i_info("final result: failed; resolved with successful implicit keep"); exit_status = EXIT_FAILURE; break; - case SIEVE_EXEC_KEEP_FAILED: - i_info("final result: utter failure"); + case SIEVE_EXEC_TEMP_FAILURE: + i_info("final result: temporary failure"); exit_status = EXIT_FAILURE; break; - default: - i_info("final result: unrecognized return value?!"); + case SIEVE_EXEC_KEEP_FAILED: + i_info("final result: utter failure"); exit_status = EXIT_FAILURE; break; } diff --git a/src/testsuite/testsuite.c b/src/testsuite/testsuite.c index 722ad2a6d7eb02d762a1e85117fac081be76067f..ab2911a94d2e95dcea0b188f726032918157e10a 100644 --- a/src/testsuite/testsuite.c +++ b/src/testsuite/testsuite.c @@ -197,13 +197,12 @@ int main(int argc, char **argv) break; case SIEVE_EXEC_FAILURE: case SIEVE_EXEC_KEEP_FAILED: + case SIEVE_EXEC_TEMP_FAILURE: testsuite_testcase_fail("test script execution aborted due to error"); break; case SIEVE_EXEC_BIN_CORRUPT: testsuite_testcase_fail("compiled test script binary is corrupt"); break; - default: - testsuite_testcase_fail("unknown execution exit code"); } sieve_close(&sbin);