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