diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c index 45d51ae592b81195271715e170a43e6176b94d2b..fb7a67caddc736099a854470e921f9c4b8fe0d5c 100644 --- a/src/lib-sieve/sieve-actions.c +++ b/src/lib-sieve/sieve-actions.c @@ -271,15 +271,18 @@ static bool act_store_start const struct sieve_action_exec_env *aenv, void *context, void **tr_context) { struct act_store_context *ctx = (struct act_store_context *) context; + const struct sieve_script_env *senv = aenv->scriptenv; + const struct sieve_message_data *msgdata = aenv->msgdata; struct act_store_transaction *trans; struct mail_namespace *ns = NULL; struct mailbox *box = NULL; pool_t pool = sieve_result_pool(aenv->result); + bool disabled = FALSE, redundant = FALSE; /* If context is NULL, the store action is the result of (implicit) keep */ if ( ctx == NULL ) { ctx = p_new(pool, struct act_store_context, 1); - ctx->folder = p_strdup(pool, SIEVE_SCRIPT_DEFAULT_MAILBOX(aenv->scriptenv)); + ctx->folder = p_strdup(pool, SIEVE_SCRIPT_DEFAULT_MAILBOX(senv)); } /* Open the requested mailbox */ @@ -287,20 +290,36 @@ static bool act_store_start /* NOTE: The caller of the sieve library is allowed to leave namespaces set * to NULL. This implementation will then skip actually storing the message. */ - if ( aenv->scriptenv->namespaces != NULL ) { + if ( senv->namespaces != NULL ) { box = act_store_mailbox_open(aenv, &ctx->folder, &ns); + + /* Check whether we are trying to store the message in the folder it + * originates from. In that case skip + */ + if ( box != NULL && mailbox_backends_equal(box, msgdata->mail->box) ) { + mailbox_close(&box); + box = NULL; + ns = NULL; + redundant = TRUE; + } + } else { + disabled = TRUE; } /* Create transaction context */ trans = p_new(pool, struct act_store_transaction, 1); + trans->context = ctx; trans->namespace = ns; trans->box = box; trans->flags = 0; + + trans->disabled = disabled; + trans->redundant = redundant; *tr_context = (void *)trans; - return ( (aenv->scriptenv->namespaces == NULL) || (box != NULL) ); + return ( disabled || redundant || (box != NULL) ); } static bool act_store_execute @@ -311,17 +330,19 @@ static bool act_store_execute (struct act_store_transaction *) tr_context; struct mail_keywords *keywords = NULL; struct mail_save_context *save_ctx; + bool result = TRUE; /* Verify transaction */ if ( trans == NULL ) return FALSE; - /* Exit early if namespace is not available */ - if ( trans->namespace == NULL ) { - if ( aenv->scriptenv->namespaces == NULL ) - return TRUE; + /* Check whether we need to do anything */ + if ( trans->disabled || trans->redundant ) return TRUE; + /* Exit early if namespace or mailbox are not available */ + if ( trans->namespace == NULL ) + return FALSE; + else if ( trans->box == NULL ) return FALSE; - } else if ( trans->box == NULL ) return FALSE; /* Mark attempt to store in default mailbox */ if ( strcmp(trans->context->folder, @@ -349,7 +370,6 @@ static bool act_store_execute kwds = array_idx(&trans->keywords, 0); /* FIXME: Do we need to clear duplicates? */ - if ( mailbox_keywords_create(trans->box, kwds, &keywords) < 0) { sieve_result_error(aenv, "invalid keywords set for stored message"); keywords = NULL; @@ -362,14 +382,15 @@ static bool act_store_execute mailbox_save_set_dest_mail(save_ctx, trans->dest_mail); if ( mailbox_copy(&save_ctx, aenv->msgdata->mail) < 0 ) { act_store_get_storage_error(aenv, trans); - return FALSE; + result = FALSE; } + /* Deallocate keywords */ if ( keywords != NULL ) { mailbox_keywords_unref(trans->box, &keywords); } - return TRUE; + return result; } static void act_store_log_status @@ -380,30 +401,40 @@ static void act_store_log_status mailbox_name = str_sanitize(trans->context->folder, 128); - if ( trans->namespace == NULL ) { - if ( aenv->scriptenv->namespaces == NULL ) - sieve_result_log(aenv, "store into mailbox '%s' skipped", mailbox_name); + /* Store disabled? */ + if ( trans->disabled ) { + sieve_result_log(aenv, "store into mailbox '%s' skipped", mailbox_name); + + /* Store redundant? */ + } else if ( trans->redundant ) { + sieve_result_log(aenv, "left message in mailbox '%s'", mailbox_name); + + /* Namespace not set? */ + } else if ( trans->namespace == NULL ) { + sieve_result_error + (aenv, "failed to find namespace for mailbox '%s'", mailbox_name); + + /* Store failed? */ + } else if ( !status ) { + const char *errstr; + enum mail_error error; + + if ( trans->error != NULL ) + errstr = trans->error; else - sieve_result_error - (aenv, "failed to find namespace for mailbox '%s'", mailbox_name); - } else { - if ( !rolled_back && status ) { - sieve_result_log(aenv, "stored mail into mailbox '%s'", mailbox_name); - } else { - const char *errstr; - enum mail_error error; - - if ( trans->error != NULL ) - errstr = trans->error; - else - errstr = mail_storage_get_last_error(trans->namespace->storage, &error); - - if ( status ) - sieve_result_log(aenv, "store into mailbox '%s' aborted", mailbox_name); - else - sieve_result_error(aenv, "failed to store into mailbox '%s': %s", - mailbox_name, errstr); - } + errstr = mail_storage_get_last_error(trans->namespace->storage, &error); + + sieve_result_error(aenv, "failed to store into mailbox '%s': %s", + mailbox_name, errstr); + + /* Store aborted? */ + } else if ( rolled_back ) { + sieve_result_log(aenv, "store into mailbox '%s' aborted", mailbox_name); + + /* Succeeded */ + } else { + sieve_result_log(aenv, "stored mail into mailbox '%s'", mailbox_name); + } } @@ -418,16 +449,21 @@ static bool act_store_commit /* Verify transaction */ if ( trans == NULL ) return FALSE; - /* Exit early if namespace is not available */ - if ( trans->namespace == NULL ) { - if ( aenv->scriptenv->namespaces == NULL ) { - act_store_log_status(trans, aenv, FALSE, status); - *keep = FALSE; - return TRUE; - } + /* Check whether we need to do anything */ + if ( trans->disabled ) { + act_store_log_status(trans, aenv, FALSE, status); + *keep = FALSE; + return TRUE; + } else if ( trans->redundant ) { + act_store_log_status(trans, aenv, FALSE, status); + return TRUE; + } + /* Exit early if namespace is not available */ + if ( trans->namespace == NULL ) + return FALSE; + else if ( trans->box == NULL ) return FALSE; - } else if ( trans->box == NULL ) return FALSE; /* Mark attempt to use storage. Can only get here when all previous actions * succeeded. @@ -439,7 +475,7 @@ static bool act_store_commit mail_free(&trans->dest_mail); /* Commit mailbox transaction */ - status = mailbox_transaction_commit(&trans->mail_trans) == 0; + status = ( mailbox_transaction_commit(&trans->mail_trans) == 0 ); /* Note the fact that the message was stored at least once */ if ( status ) diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h index fe6c9cbc028a68644e77c5e3e61f15f297df74d4..81b32fc13f66ff14d9f4a37916d5ab1ff8bdb5e6 100644 --- a/src/lib-sieve/sieve-actions.h +++ b/src/lib-sieve/sieve-actions.h @@ -200,6 +200,9 @@ struct act_store_transaction { enum mail_flags flags; ARRAY_DEFINE(keywords, const char *); + + unsigned int disabled:1; + unsigned int redundant:1; }; int sieve_act_store_add_to_result