/* Central switching station for email on its
* way to be delivered. From here we call out
* to the sorting module, if applicable, to
* give additional information on what to do
* with a message.
*
* (c) 2004-2006 Aaron Stone <aaron@serendpity.cx>
*
* $Id: $
*/
#include "dbmail.h"
/* Figure out where to deliver the message, then deliver it.
* */
dsn_class_t sort_and_deliver(struct DbmailMessage *message,
const char *destination, u64_t useridnr,
const char *mailbox, mailbox_source_t source)
{
int cancelkeep = 0;
int reject = 0;
dsn_class_t ret;
field_t val;
/* This is the only condition when called from pipe.c, actually. */
if (! mailbox) {
mailbox = "INBOX";
source = BOX_DEFAULT;
}
/* Subaddress. */
config_get_value("SUBADDRESS", "DELIVERY", val);
if (strcasecmp(val, "yes") == 0) {
int res;
size_t sublen, subpos;
char *subaddress;
// FIXME: Where can I get access to the address?
res = find_bounded((char *)destination, '+', '@', &subaddress, &sublen, &subpos);
if (res == 0 && sublen > 0) {
// FIXME: I forget who frees the mailbox.
mailbox = subaddress;
source = BOX_ADDRESSPART;
trace(TRACE_INFO, "%s, %s: Setting BOX_ADDRESSPART mailbox to [%s]",
__FILE__, __func__, mailbox);
}
}
/* Give Sieve access to the envelope recipient. */
dbmail_message_set_envelope_recipient(message, destination);
/* Sieve. */
config_get_value("SIEVE", "DELIVERY", val);
if (strcasecmp(val, "yes") == 0
&& db_check_sievescript_active(useridnr) == 0) {
trace(TRACE_INFO, "%s, %s: Calling for a Sieve sort",
__FILE__, __func__);
sort_result_t *sort_result;
sort_result = sort_process(useridnr, message);
if (sort_result) {
cancelkeep = sort_get_cancelkeep(sort_result);
reject = sort_get_reject(sort_result);
sort_free_result(sort_result);
}
}
/* Sieve actions:
* (m = must implement, s = should implement, e = extension)
* m Keep - implicit default action.
* m Discard - requires us to skip the default action.
* m Redirect - add to the forwarding list.
* s Fileinto - change the destination mailbox.
* s Reject - nope, sorry. we killed bounce().
* e Vacation - share with the auto reply code.
*/
if (cancelkeep) {
// The implicit keep has been cancelled.
// This may necessarily imply that the message
// is being discarded -- dropped flat on the floor.
ret = DSN_CLASS_OK;
trace(TRACE_INFO, "%s, %s: Keep was cancelled. Message may be discarded.",
__FILE__, __func__);
} else {
ret = sort_deliver_to_mailbox(message, useridnr, mailbox, source, NULL);
trace(TRACE_INFO, "%s, %s: Keep was not cancelled. Message will be delivered by default.",
__FILE__, __func__);
}
/* Reject probably implies cancelkeep,
* but we'll not assume that and instead
* just test this as a separate block. */
if (reject) {
trace(TRACE_INFO, "%s, %s: Message will be rejected.",
__FILE__, __func__);
ret = DSN_CLASS_FAIL;
}
return ret;
}
dsn_class_t sort_deliver_to_mailbox(struct DbmailMessage *message,
u64_t useridnr, const char *mailbox, mailbox_source_t source,
int *msgflags)
{
u64_t mboxidnr, newmsgidnr;
size_t msgsize = (u64_t)dbmail_message_get_size(message, FALSE);
trace(TRACE_INFO,"%s,%s: useridnr [%llu] mailbox [%s]",
__FILE__, __func__, useridnr, mailbox);
if (db_find_create_mailbox(mailbox, source, useridnr, &mboxidnr) != 0) {
trace(TRACE_ERROR, "%s,%s: mailbox [%s] not found",
__FILE__, __func__,
mailbox);
return DSN_CLASS_FAIL;
}
switch (db_copymsg(message->id, mboxidnr, useridnr, &newmsgidnr)) {
case -2:
trace(TRACE_DEBUG, "%s, %s: error copying message to user [%llu],"
"maxmail exceeded",
__FILE__, __func__,
useridnr);
return DSN_CLASS_QUOTA;
case -1:
trace(TRACE_ERROR, "%s, %s: error copying message to user [%llu]",
__FILE__, __func__, useridnr);
return DSN_CLASS_TEMP;
default:
trace(TRACE_MESSAGE, "%s, %s: message id=%llu, size=%d is inserted",
__FILE__, __func__, newmsgidnr, msgsize);
if (msgflags) {
trace(TRACE_MESSAGE, "%s, %s: message id=%llu, setting imap flags",
__FILE__, __func__, newmsgidnr);
db_set_msgflag(newmsgidnr, mboxidnr, msgflags, IMAPFA_ADD);
}
message->id = newmsgidnr;
return DSN_CLASS_OK;
}
}
syntax highlighted by Code2HTML, v. 0.9.1