Before, much of that was handled by the respective callers (LDA and LMTP).
static int
lda_do_deliver(struct mail_deliver_context *ctx, bool stderr_rejection)
{
- struct mail_storage *storage;
- enum mail_error error_code;
+ enum mail_deliver_error error_code;
const char *error;
int ret;
- if (mail_deliver(ctx, &storage) >= 0)
+ if (mail_deliver(ctx, &error_code, &error) >= 0)
return EX_OK;
- if (ctx->tempfail_error != NULL) {
- error = ctx->tempfail_error;
- error_code = MAIL_ERROR_TEMP;
- } else if (storage != NULL) {
- error = mail_storage_get_last_error(storage, &error_code);
- } else {
+ if (error_code == MAIL_DELIVER_ERROR_INTERNAL) {
/* This shouldn't happen */
- i_error("BUG: Saving failed to unknown storage");
return EX_TEMPFAIL;
}
fprintf(stderr, "%s\n", error);
}
- if (error_code != MAIL_ERROR_NOQUOTA ||
- ctx->set->quota_full_tempfail) {
- /* Saving to INBOX should always work unless
- we're over quota. If it didn't, it's probably a
- configuration problem. */
+ switch (error_code) {
+ case MAIL_DELIVER_ERROR_NONE:
+ i_unreached();
+ case MAIL_DELIVER_ERROR_TEMPORARY:
return EX_TEMPFAIL;
+ case MAIL_DELIVER_ERROR_NOQUOTA:
+ if (ctx->set->quota_full_tempfail)
+ return EX_TEMPFAIL;
+ ctx->mailbox_full = TRUE;
+ break;
+ case MAIL_DELIVER_ERROR_INTERNAL:
+ i_unreached();
}
- ctx->mailbox_full = TRUE;
+
+ /* Rejected */
+
ctx->dsn = TRUE;
/* we'll have to reply with permanent failure */
}
int mail_deliver(struct mail_deliver_context *ctx,
- struct mail_storage **storage_r)
+ enum mail_deliver_error *error_code_r,
+ const char **error_r)
{
struct mail_deliver_user *muser =
MAIL_DELIVER_USER_CONTEXT(ctx->rcpt_user);
struct event_passthrough *e;
+ struct mail_storage *storage = NULL;
+ enum mail_deliver_error error_code = MAIL_DELIVER_ERROR_NONE;
+ const char *error = NULL;
int ret;
i_assert(muser->deliver_ctx == NULL);
set_name("mail_delivery_started");
e_debug(e->event(), "Local delivery started");
- ret = mail_do_deliver(ctx, storage_r);
+ ret = mail_do_deliver(ctx, &storage);
+
+ if (ret >= 0)
+ i_assert(ret == 0); /* ret > 0 has no defined meaning */
+ else if (ctx->tempfail_error != NULL) {
+ error = ctx->tempfail_error;
+ error_code = MAIL_DELIVER_ERROR_TEMPORARY;
+ } else if (storage != NULL) {
+ enum mail_error mail_error;
+
+ error = mail_storage_get_last_error(storage, &mail_error);
+ if (mail_error == MAIL_ERROR_NOQUOTA) {
+ error_code = MAIL_DELIVER_ERROR_NOQUOTA;
+ } else {
+ error_code = MAIL_DELIVER_ERROR_TEMPORARY;
+ }
+ } else {
+ /* This shouldn't happen */
+ e_error(ctx->event, "BUG: Saving failed to unknown storage");
+ error = "Temporary internal error";
+ error_code = MAIL_DELIVER_ERROR_INTERNAL;
+ }
e = event_create_passthrough(ctx->event)->
set_name("mail_delivery_finished");
muser->deliver_ctx = NULL;
+ *error_code_r = error_code;
+ *error_r = error;
return ret;
}
struct mail_save_context;
struct mailbox;
+enum mail_deliver_error {
+ MAIL_DELIVER_ERROR_NONE = 0,
+
+ /* Temporary error */
+ MAIL_DELIVER_ERROR_TEMPORARY,
+ /* Out of storage quota for mailbox or user */
+ MAIL_DELIVER_ERROR_NOQUOTA,
+ /* Internal error (BUG) */
+ MAIL_DELIVER_ERROR_INTERNAL,
+};
+
struct mail_deliver_session {
pool_t pool;
struct mail_save_context *save_ctx);
int mail_deliver(struct mail_deliver_context *ctx,
- struct mail_storage **storage_r);
+ enum mail_deliver_error *error_code_r,
+ const char **error_r);
/* Sets the deliver_mail hook and returns the previous hook,
which the new_hook should call if it's non-NULL. */
struct mail_deliver_context *dctx)
{
struct smtp_server_recipient *rcpt = llrcpt->rcpt->rcpt;
- struct mail_storage *storage;
- enum mail_error mail_error;
+ enum mail_deliver_error error_code;
const char *error;
- if (mail_deliver(dctx, &storage) == 0) {
+ if (mail_deliver(dctx, &error_code, &error) == 0) {
if (dctx->dest_mail != NULL) {
i_assert(local->first_saved_mail == NULL);
local->first_saved_mail = dctx->dest_mail;
return 0;
}
- if (dctx->tempfail_error != NULL) {
- smtp_server_recipient_reply(rcpt, 451, "4.2.0", "%s",
- dctx->tempfail_error);
- } else if (storage != NULL) {
- error = mail_storage_get_last_error(storage, &mail_error);
- if (mail_error == MAIL_ERROR_NOQUOTA) {
- lmtp_local_rcpt_reply_overquota(llrcpt, error);
- } else {
- smtp_server_recipient_reply(rcpt, 451, "4.2.0", "%s",
- error);
- }
- } else {
+ switch (error_code) {
+ case MAIL_DELIVER_ERROR_NONE:
+ i_unreached();
+ case MAIL_DELIVER_ERROR_TEMPORARY:
+ smtp_server_recipient_reply(rcpt, 451, "4.2.0", "%s", error);
+ break;
+ case MAIL_DELIVER_ERROR_NOQUOTA:
+ lmtp_local_rcpt_reply_overquota(llrcpt, error);
+ break;
+ case MAIL_DELIVER_ERROR_INTERNAL:
/* This shouldn't happen */
- e_error(rcpt->event, "BUG: Saving failed to unknown storage");
- smtp_server_recipient_reply(rcpt, 451, "4.3.0",
- "Temporary internal error");
+ smtp_server_recipient_reply(rcpt, 451, "4.3.0", "%s", error);
+ break;
}
+
return -1;
}