smtp_rcpt.c revision 1.1
1/* $NetBSD: smtp_rcpt.c,v 1.1 2009/06/23 10:08:54 tron Exp $ */ 2 3/*++ 4/* NAME 5/* smtp_rcpt 3 6/* SUMMARY 7/* application-specific recipient list operations 8/* SYNOPSIS 9/* #include <smtp.h> 10/* 11/* SMTP_RCPT_INIT(state) 12/* SMTP_STATE *state; 13/* 14/* SMTP_RCPT_DROP(state, rcpt) 15/* SMTP_STATE *state; 16/* RECIPIENT *rcpt; 17/* 18/* SMTP_RCPT_KEEP(state, rcpt) 19/* SMTP_STATE *state; 20/* RECIPIENT *rcpt; 21/* 22/* SMTP_RCPT_ISMARKED(rcpt) 23/* RECIPIENT *rcpt; 24/* 25/* void smtp_rcpt_cleanup(SMTP_STATE *state) 26/* SMTP_STATE *state; 27/* 28/* int SMTP_RCPT_LEFT(state) 29/* SMTP_STATE *state; 30/* 31/* void smtp_rcpt_done(state, resp, rcpt) 32/* SMTP_STATE *state; 33/* SMTP_RESP *resp; 34/* RECIPIENT *rcpt; 35/* DESCRIPTION 36/* This module implements application-specific mark and sweep 37/* operations on recipient lists. Operation is as follows: 38/* .IP \(bu 39/* In the course of a delivery attempt each recipient is 40/* marked either as DROP (remove from recipient list) or KEEP 41/* (deliver to alternate mail server). 42/* .IP \(bu 43/* After a delivery attempt any recipients marked DROP are deleted 44/* from the request, and the left-over recipients are unmarked. 45/* .PP 46/* The mark/sweep algorithm is implemented in a redundant manner, 47/* and ensures that all recipients are explicitly accounted for. 48/* 49/* Operations with upper case names are implemented by macros 50/* whose arguments may be evaluated more than once. 51/* 52/* SMTP_RCPT_INIT() initializes application-specific recipient 53/* information and must be called before the first delivery attempt. 54/* 55/* SMTP_RCPT_DROP() marks the specified recipient as DROP (remove 56/* from recipient list). It is an error to mark an already marked 57/* recipient. 58/* 59/* SMTP_RCPT_KEEP() marks the specified recipient as KEEP (deliver 60/* to alternate mail server). It is an error to mark an already 61/* marked recipient. 62/* 63/* SMTP_RCPT_ISMARKED() returns non-zero when the specified 64/* recipient is marked. 65/* 66/* SMTP_RCPT_LEFT() returns the number of left_over recipients 67/* (the total number of marked and non-marked recipients). 68/* 69/* smtp_rcpt_cleanup() cleans up the in-memory recipient list. 70/* It removes the recipients marked DROP from the left-over 71/* recipients, unmarks the left-over recipients, and enforces 72/* the requirement that all recipients are marked upon entry. 73/* 74/* smtp_rcpt_done() logs that a recipient is completed and upon 75/* success it marks the recipient as done in the queue file. 76/* Finally, it marks the in-memory recipient as DROP. 77/* 78/* Note: smtp_rcpt_done() may change the order of the recipient 79/* list. 80/* DIAGNOSTICS 81/* Panic: interface violation. 82/* 83/* When a recipient can't be logged as completed, the recipient is 84/* logged as deferred instead. 85/* BUGS 86/* The single recipient list abstraction dates from the time 87/* that the SMTP client would give up after one SMTP session, 88/* so that each recipient was either bounced, delivered or 89/* deferred. Implicitly, all recipients were marked as DROP. 90/* 91/* This abstraction is less convenient when an SMTP client 92/* must be able to deliver left-over recipients to a backup 93/* host. It might be more natural to have an input list with 94/* recipients to deliver, and an output list with left-over 95/* recipients. 96/* LICENSE 97/* .ad 98/* .fi 99/* The Secure Mailer license must be distributed with this software. 100/* AUTHOR(S) 101/* Wietse Venema 102/* IBM T.J. Watson Research 103/* P.O. Box 704 104/* Yorktown Heights, NY 10598, USA 105/*--*/ 106 107/* System library. */ 108 109#include <sys_defs.h> 110#include <stdlib.h> /* smtp_rcpt_cleanup */ 111#include <string.h> 112 113/* Utility library. */ 114 115#include <msg.h> 116#include <stringops.h> 117#include <mymalloc.h> 118 119/* Global library. */ 120 121#include <mail_params.h> 122#include <deliver_request.h> /* smtp_rcpt_done */ 123#include <deliver_completed.h> /* smtp_rcpt_done */ 124#include <sent.h> /* smtp_rcpt_done */ 125#include <dsn_mask.h> /* smtp_rcpt_done */ 126 127/* Application-specific. */ 128 129#include <smtp.h> 130 131/* smtp_rcpt_done - mark recipient as done or else */ 132 133void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt) 134{ 135 DELIVER_REQUEST *request = state->request; 136 SMTP_SESSION *session = state->session; 137 DSN_BUF *why = state->why; 138 const char *dsn_action = "relayed"; 139 int status; 140 141 /* 142 * Assume this was intermediate delivery when the server announced DSN 143 * support, and don't send a DSN "SUCCESS" notification. 144 */ 145 if (session->features & SMTP_FEATURE_DSN) 146 rcpt->dsn_notify &= ~DSN_NOTIFY_SUCCESS; 147 148 /* 149 * Assume this was final delivery when the LMTP server announced no DSN 150 * support. In backwards compatibility mode, send a "relayed" instead of 151 * a "delivered" DSN "SUCCESS" notification. Do not attempt to "simplify" 152 * the expression. The redundancy is for clarity. It is trivially 153 * eliminated by the compiler. There is no need to sacrifice clarity for 154 * the sake of "performance". 155 */ 156 if ((session->features & SMTP_FEATURE_DSN) == 0 157 && (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) != 0 158 && var_lmtp_assume_final != 0) 159 dsn_action = "delivered"; 160 161 /* 162 * Report success and delete the recipient from the delivery request. 163 * Defer if the success can't be reported. 164 * 165 * Note: the DSN action is ignored in case of address probes. 166 */ 167 dsb_update(why, resp->dsn, dsn_action, DSB_MTYPE_DNS, session->host, 168 DSB_DTYPE_SMTP, resp->str, "%s", resp->str); 169 170 status = sent(DEL_REQ_TRACE_FLAGS(request->flags), 171 request->queue_id, &request->msg_stats, rcpt, 172 session->namaddrport, DSN_FROM_DSN_BUF(why)); 173 if (status == 0) 174 if (request->flags & DEL_REQ_FLAG_SUCCESS) 175 deliver_completed(state->src, rcpt->offset); 176 SMTP_RCPT_DROP(state, rcpt); 177 state->status |= status; 178} 179 180/* smtp_rcpt_cleanup_callback - qsort callback */ 181 182static int smtp_rcpt_cleanup_callback(const void *a, const void *b) 183{ 184 return (((RECIPIENT *) a)->u.status - ((RECIPIENT *) b)->u.status); 185} 186 187/* smtp_rcpt_cleanup - purge completed recipients from request */ 188 189void smtp_rcpt_cleanup(SMTP_STATE *state) 190{ 191 RECIPIENT_LIST *rcpt_list = &state->request->rcpt_list; 192 RECIPIENT *rcpt; 193 194 /* 195 * Sanity checks. 196 */ 197 if (state->rcpt_drop + state->rcpt_keep != state->rcpt_left) 198 msg_panic("smtp_rcpt_cleanup: recipient count mismatch: %d+%d!=%d", 199 state->rcpt_drop, state->rcpt_keep, state->rcpt_left); 200 201 /* 202 * Recipients marked KEEP sort before recipients marked DROP. Skip the 203 * sorting in the common case that all recipients are marked the same. 204 */ 205 if (state->rcpt_drop > 0 && state->rcpt_keep > 0) 206 qsort((void *) rcpt_list->info, state->rcpt_left, 207 sizeof(rcpt_list->info[0]), smtp_rcpt_cleanup_callback); 208 209 /* 210 * Truncate the recipient list and unmark the left-over recipients. 211 */ 212 state->rcpt_left = state->rcpt_keep; 213 for (rcpt = rcpt_list->info; rcpt < rcpt_list->info + state->rcpt_left; rcpt++) 214 rcpt->u.status = 0; 215 state->rcpt_drop = state->rcpt_keep = 0; 216} 217