diff options
Diffstat (limited to 'src/smtp/smtp_rcpt.c')
-rw-r--r-- | src/smtp/smtp_rcpt.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/src/smtp/smtp_rcpt.c b/src/smtp/smtp_rcpt.c new file mode 100644 index 0000000..6608ea8 --- /dev/null +++ b/src/smtp/smtp_rcpt.c @@ -0,0 +1,226 @@ +/*++ +/* NAME +/* smtp_rcpt 3 +/* SUMMARY +/* application-specific recipient list operations +/* SYNOPSIS +/* #include <smtp.h> +/* +/* SMTP_RCPT_INIT(state) +/* SMTP_STATE *state; +/* +/* SMTP_RCPT_DROP(state, rcpt) +/* SMTP_STATE *state; +/* RECIPIENT *rcpt; +/* +/* SMTP_RCPT_KEEP(state, rcpt) +/* SMTP_STATE *state; +/* RECIPIENT *rcpt; +/* +/* SMTP_RCPT_ISMARKED(rcpt) +/* RECIPIENT *rcpt; +/* +/* void smtp_rcpt_cleanup(SMTP_STATE *state) +/* SMTP_STATE *state; +/* +/* int SMTP_RCPT_LEFT(state) +/* SMTP_STATE *state; +/* +/* int SMTP_RCPT_MARK_COUNT(state) +/* SMTP_STATE *state; +/* +/* void smtp_rcpt_done(state, resp, rcpt) +/* SMTP_STATE *state; +/* SMTP_RESP *resp; +/* RECIPIENT *rcpt; +/* DESCRIPTION +/* This module implements application-specific mark and sweep +/* operations on recipient lists. Operation is as follows: +/* .IP \(bu +/* In the course of a delivery attempt each recipient is +/* marked either as DROP (remove from recipient list) or KEEP +/* (deliver to alternate mail server). +/* .IP \(bu +/* After a delivery attempt any recipients marked DROP are deleted +/* from the request, and the left-over recipients are unmarked. +/* .PP +/* The mark/sweep algorithm is implemented in a redundant manner, +/* and ensures that all recipients are explicitly accounted for. +/* +/* Operations with upper case names are implemented by macros +/* whose arguments may be evaluated more than once. +/* +/* SMTP_RCPT_INIT() initializes application-specific recipient +/* information and must be called before the first delivery attempt. +/* +/* SMTP_RCPT_DROP() marks the specified recipient as DROP (remove +/* from recipient list). It is an error to mark an already marked +/* recipient. +/* +/* SMTP_RCPT_KEEP() marks the specified recipient as KEEP (deliver +/* to alternate mail server). It is an error to mark an already +/* marked recipient. +/* +/* SMTP_RCPT_ISMARKED() returns non-zero when the specified +/* recipient is marked. +/* +/* SMTP_RCPT_LEFT() returns the number of left_over recipients +/* (the total number of marked and non-marked recipients). +/* +/* SMTP_RCPT_MARK_COUNT() returns the number of left_over +/* recipients that are marked. +/* +/* smtp_rcpt_cleanup() cleans up the in-memory recipient list. +/* It removes the recipients marked DROP from the left-over +/* recipients, unmarks the left-over recipients, and enforces +/* the requirement that all recipients are marked upon entry. +/* +/* smtp_rcpt_done() logs that a recipient is completed and upon +/* success it marks the recipient as done in the queue file. +/* Finally, it marks the in-memory recipient as DROP. +/* +/* Note: smtp_rcpt_done() may change the order of the recipient +/* list. +/* DIAGNOSTICS +/* Panic: interface violation. +/* +/* When a recipient can't be logged as completed, the recipient is +/* logged as deferred instead. +/* BUGS +/* The single recipient list abstraction dates from the time +/* that the SMTP client would give up after one SMTP session, +/* so that each recipient was either bounced, delivered or +/* deferred. Implicitly, all recipients were marked as DROP. +/* +/* This abstraction is less convenient when an SMTP client +/* must be able to deliver left-over recipients to a backup +/* host. It might be more natural to have an input list with +/* recipients to deliver, and an output list with left-over +/* recipients. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <stdlib.h> /* smtp_rcpt_cleanup */ +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <stringops.h> +#include <mymalloc.h> + +/* Global library. */ + +#include <mail_params.h> +#include <deliver_request.h> /* smtp_rcpt_done */ +#include <deliver_completed.h> /* smtp_rcpt_done */ +#include <sent.h> /* smtp_rcpt_done */ +#include <dsn_mask.h> /* smtp_rcpt_done */ + +/* Application-specific. */ + +#include <smtp.h> + +/* smtp_rcpt_done - mark recipient as done or else */ + +void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt) +{ + DELIVER_REQUEST *request = state->request; + SMTP_SESSION *session = state->session; + SMTP_ITERATOR *iter = state->iterator; + DSN_BUF *why = state->why; + const char *dsn_action = "relayed"; + int status; + + /* + * Assume this was intermediate delivery when the server announced DSN + * support, and don't send a DSN "SUCCESS" notification. + */ + if (session->features & SMTP_FEATURE_DSN) + rcpt->dsn_notify &= ~DSN_NOTIFY_SUCCESS; + + /* + * Assume this was final delivery when the LMTP server announced no DSN + * support. In backwards compatibility mode, send a "relayed" instead of + * a "delivered" DSN "SUCCESS" notification. Do not attempt to "simplify" + * the expression. The redundancy is for clarity. It is trivially + * eliminated by the compiler. There is no need to sacrifice clarity for + * the sake of "performance". + */ + if ((session->features & SMTP_FEATURE_DSN) == 0 + && !smtp_mode + && (smtp_cli_attr.flags & SMTP_CLI_FLAG_FINAL_DELIVERY) != 0) + dsn_action = "delivered"; + + /* + * Report success and delete the recipient from the delivery request. + * Defer if the success can't be reported. + * + * Note: the DSN action is ignored in case of address probes. + */ + dsb_update(why, resp->dsn, dsn_action, DSB_MTYPE_DNS, STR(iter->host), + DSB_DTYPE_SMTP, resp->str, "%s", resp->str); + + status = sent(DEL_REQ_TRACE_FLAGS(request->flags), + request->queue_id, &request->msg_stats, rcpt, + session->namaddrport, DSN_FROM_DSN_BUF(why)); + if (status == 0) + if (request->flags & DEL_REQ_FLAG_SUCCESS) + deliver_completed(state->src, rcpt->offset); + SMTP_RCPT_DROP(state, rcpt); + state->status |= status; +} + +/* smtp_rcpt_cleanup_callback - qsort callback */ + +static int smtp_rcpt_cleanup_callback(const void *a, const void *b) +{ + return (((RECIPIENT *) a)->u.status - ((RECIPIENT *) b)->u.status); +} + +/* smtp_rcpt_cleanup - purge completed recipients from request */ + +void smtp_rcpt_cleanup(SMTP_STATE *state) +{ + RECIPIENT_LIST *rcpt_list = &state->request->rcpt_list; + RECIPIENT *rcpt; + + /* + * Sanity checks. + */ + if (state->rcpt_drop + state->rcpt_keep != state->rcpt_left) + msg_panic("smtp_rcpt_cleanup: recipient count mismatch: %d+%d!=%d", + state->rcpt_drop, state->rcpt_keep, state->rcpt_left); + + /* + * Recipients marked KEEP sort before recipients marked DROP. Skip the + * sorting in the common case that all recipients are marked the same. + */ + if (state->rcpt_drop > 0 && state->rcpt_keep > 0) + qsort((void *) rcpt_list->info, state->rcpt_left, + sizeof(rcpt_list->info[0]), smtp_rcpt_cleanup_callback); + + /* + * Truncate the recipient list and unmark the left-over recipients. + */ + state->rcpt_left = state->rcpt_keep; + for (rcpt = rcpt_list->info; rcpt < rcpt_list->info + state->rcpt_left; rcpt++) + rcpt->u.status = 0; + state->rcpt_drop = state->rcpt_keep = 0; +} |