/*++ /* NAME /* smtp_rcpt 3 /* SUMMARY /* application-specific recipient list operations /* SYNOPSIS /* #include /* /* 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; /* /* void smtp_rcpt_done(state, reply, rcpt) /* SMTP_STATE *state; /* const char *reply; /* 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_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 /*--*/ /* System library. */ #include #include /* smtp_rcpt_cleanup */ /* Utility library. */ #include /* Global library. */ #include /* smtp_rcpt_done */ #include /* smtp_rcpt_done */ #include /* smtp_rcpt_done */ /* Application-specific. */ #include /* smtp_rcpt_done - mark recipient as done or else */ void smtp_rcpt_done(SMTP_STATE *state, const char *reply, RECIPIENT *rcpt) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; int status; /* * Report success and delete the recipient from the delivery request. * Defer if the success can't be reported. */ status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, rcpt->orig_addr, rcpt->address, rcpt->offset, session->namaddr, request->arrival_time, "%s", reply); 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)->status - ((RECIPIENT *) b)->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->status = 0; state->rcpt_drop = state->rcpt_keep = 0; }