Mercurial > dovecot > core-2.2
view src/lib-lda/mail-deliver.c @ 9101:2e20a1a9bcd4 HEAD
Changed MAILBOX_OPEN_FAST meaning a bit. Don't use it where it's unnecessary.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 13 Apr 2009 20:06:40 -0400 |
parents | e4832f128738 |
children | b16ec327b266 |
line wrap: on
line source
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "ioloop.h" #include "str.h" #include "str-sanitize.h" #include "var-expand.h" #include "message-address.h" #include "lda-settings.h" #include "mail-storage.h" #include "mail-namespace.h" #include "mail-deliver.h" deliver_mail_func_t *deliver_mail = NULL; const char *mail_deliver_get_address(struct mail_deliver_context *ctx, const char *header) { struct message_address *addr; const char *str; if (mail_get_first_header(ctx->src_mail, header, &str) <= 0) return NULL; addr = message_address_parse(pool_datastack_create(), (const unsigned char *)str, strlen(str), 1, FALSE); return addr == NULL || addr->mailbox == NULL || addr->domain == NULL || *addr->mailbox == '\0' || *addr->domain == '\0' ? NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL); } static const struct var_expand_table * get_log_var_expand_table(struct mail_deliver_context *ctx, const char *message) { static struct var_expand_table static_tab[] = { { '$', NULL, NULL }, { 'm', NULL, "msgid" }, { 's', NULL, "subject" }, { 'f', NULL, "from" }, { '\0', NULL, NULL } }; struct var_expand_table *tab; unsigned int i; tab = t_malloc(sizeof(static_tab)); memcpy(tab, static_tab, sizeof(static_tab)); tab[0].value = message; (void)mail_get_first_header(ctx->src_mail, "Message-ID", &tab[1].value); (void)mail_get_first_header(ctx->src_mail, "Subject", &tab[2].value); tab[3].value = mail_deliver_get_address(ctx, "From"); for (i = 1; tab[i].key != '\0'; i++) tab[i].value = str_sanitize(tab[i].value, 80); return tab; } void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...) { va_list args; string_t *str; const char *msg; va_start(args, fmt); msg = t_strdup_vprintf(fmt, args); str = t_str_new(256); var_expand(str, ctx->set->deliver_log_format, get_log_var_expand_table(ctx, msg)); i_info("%s", str_c(str)); va_end(args); } static struct mailbox * mailbox_open_or_create_synced(struct mail_deliver_context *ctx, struct mail_storage **storage_r, const char *name) { struct mail_namespace *ns; struct mailbox *box; enum mail_error error; enum mailbox_open_flags open_flags = MAILBOX_OPEN_KEEP_RECENT | MAILBOX_OPEN_SAVEONLY | MAILBOX_OPEN_POST_SESSION; if (strcasecmp(name, "INBOX") == 0) { /* deliveries to INBOX must always succeed, regardless of ACLs */ open_flags |= MAILBOX_OPEN_IGNORE_ACLS; } ns = mail_namespace_find(ctx->dest_user->namespaces, &name); if (ns == NULL) { *storage_r = NULL; return NULL; } *storage_r = ns->storage; if (*name == '\0') { /* delivering to a namespace prefix means we actually want to deliver to the INBOX instead */ return NULL; } box = mailbox_open(storage_r, name, NULL, open_flags); if (box != NULL || !ctx->set->lda_mailbox_autocreate) return box; (void)mail_storage_get_last_error(*storage_r, &error); if (error != MAIL_ERROR_NOTFOUND) return NULL; /* try creating it. */ if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0) return NULL; if (ctx->set->lda_mailbox_autosubscribe) { /* (try to) subscribe to it */ (void)mailbox_list_set_subscribed(ns->list, name, TRUE); } /* and try opening again */ box = mailbox_open(storage_r, name, NULL, open_flags); if (box == NULL) return NULL; if (mailbox_sync(box, 0, 0, NULL) < 0) { mailbox_close(&box); return NULL; } return box; } int mail_deliver_save(struct mail_deliver_context *ctx, const char *mailbox, enum mail_flags flags, const char *const *keywords, struct mail_storage **storage_r) { struct mail_namespace *ns; struct mailbox *box; struct mailbox_transaction_context *t; struct mail_save_context *save_ctx; struct mail_keywords *kw; enum mail_error error; const char *mailbox_name; bool default_save; int ret = 0; default_save = strcmp(mailbox, ctx->dest_mailbox_name) == 0; if (default_save) ctx->tried_default_save = TRUE; mailbox_name = str_sanitize(mailbox, 80); box = mailbox_open_or_create_synced(ctx, storage_r, mailbox); if (box == NULL) { if (*storage_r == NULL) { mail_deliver_log(ctx, "save failed to %s: Unknown namespace", mailbox_name); return -1; } ns = mail_storage_get_namespace(*storage_r); if (default_save && strcmp(ns->prefix, mailbox) == 0) { /* silently store to the INBOX instead */ return -1; } mail_deliver_log(ctx, "save failed to %s: %s", mailbox_name, mail_storage_get_last_error(*storage_r, &error)); return -1; } t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); kw = str_array_length(keywords) == 0 ? NULL : mailbox_keywords_create_valid(box, keywords); save_ctx = mailbox_save_alloc(t); mailbox_save_set_flags(save_ctx, flags, kw); if (mailbox_copy(&save_ctx, ctx->src_mail) < 0) ret = -1; mailbox_keywords_free(box, &kw); if (ret < 0) mailbox_transaction_rollback(&t); else ret = mailbox_transaction_commit(&t); if (ret == 0) { ctx->saved_mail = TRUE; mail_deliver_log(ctx, "saved mail to %s", mailbox_name); } else { mail_deliver_log(ctx, "save failed to %s: %s", mailbox_name, mail_storage_get_last_error(*storage_r, &error)); } mailbox_close(&box); return ret; } const char *mail_deliver_get_return_address(struct mail_deliver_context *ctx) { if (ctx->src_envelope_sender != NULL) return ctx->src_envelope_sender; return mail_deliver_get_address(ctx, "Return-Path"); } const char *mail_deliver_get_new_message_id(struct mail_deliver_context *ctx) { static int count = 0; return t_strdup_printf("<dovecot-%s-%s-%d@%s>", dec2str(ioloop_timeval.tv_sec), dec2str(ioloop_timeval.tv_usec), count++, ctx->set->hostname); } int mail_deliver(struct mail_deliver_context *ctx, struct mail_storage **storage_r) { int ret; *storage_r = NULL; if (deliver_mail == NULL) ret = -1; else { if (deliver_mail(ctx, storage_r) <= 0) { /* if message was saved, don't bounce it even though the script failed later. */ ret = ctx->saved_mail ? 0 : -1; } else { /* success. message may or may not have been saved. */ ret = 0; } } if (ret < 0 && !ctx->tried_default_save) { /* plugins didn't handle this. save into the default mailbox. */ ret = mail_deliver_save(ctx, ctx->dest_mailbox_name, 0, NULL, storage_r); } if (ret < 0 && strcasecmp(ctx->dest_mailbox_name, "INBOX") != 0) { /* still didn't work. try once more to save it to INBOX. */ ret = mail_deliver_save(ctx, "INBOX", 0, NULL, storage_r); } return ret; }