Postfix3.3.1
qmgr_deliver.c
[詳解]
1 /*++
2 /* NAME
3 /* qmgr_deliver 3
4 /* SUMMARY
5 /* deliver one per-site queue entry to that site
6 /* SYNOPSIS
7 /* #include "qmgr.h"
8 /*
9 /* int qmgr_deliver_concurrency;
10 /*
11 /* int qmgr_deliver(transport, fp)
12 /* QMGR_TRANSPORT *transport;
13 /* VSTREAM *fp;
14 /* DESCRIPTION
15 /* This module implements the client side of the `queue manager
16 /* to delivery agent' protocol. The queue manager uses
17 /* asynchronous I/O so that it can drive multiple delivery
18 /* agents in parallel. Depending on the outcome of a delivery
19 /* attempt, the status of messages, queues and transports is
20 /* updated.
21 /*
22 /* qmgr_deliver_concurrency is a global counter that says how
23 /* many delivery processes are in use. This can be used, for
24 /* example, to control the size of the `active' message queue.
25 /*
26 /* qmgr_deliver() executes when a delivery process announces its
27 /* availability for the named transport. It arranges for delivery
28 /* of a suitable queue entry. The \fIfp\fR argument specifies a
29 /* stream that is connected to a delivery process, or a null
30 /* pointer if the transport accepts no connection. Upon completion
31 /* of delivery (successful or not), the stream is closed, so that the
32 /* delivery process is released.
33 /* DIAGNOSTICS
34 /* LICENSE
35 /* .ad
36 /* .fi
37 /* The Secure Mailer license must be distributed with this software.
38 /* AUTHOR(S)
39 /* Wietse Venema
40 /* IBM T.J. Watson Research
41 /* P.O. Box 704
42 /* Yorktown Heights, NY 10598, USA
43 /*
44 /* Preemptive scheduler enhancements:
45 /* Patrik Rak
46 /* Modra 6
47 /* 155 00, Prague, Czech Republic
48 /*
49 /* Wietse Venema
50 /* Google, Inc.
51 /* 111 8th Avenue
52 /* New York, NY 10011, USA
53 /*--*/
54 
55 /* System library. */
56 
57 #include <sys_defs.h>
58 #include <time.h>
59 #include <string.h>
60 
61 /* Utility library. */
62 
63 #include <msg.h>
64 #include <vstring.h>
65 #include <vstream.h>
66 #include <vstring_vstream.h>
67 #include <events.h>
68 #include <iostuff.h>
69 #include <stringops.h>
70 #include <mymalloc.h>
71 
72 /* Global library. */
73 
74 #include <mail_queue.h>
75 #include <mail_proto.h>
76 #include <recipient_list.h>
77 #include <mail_params.h>
78 #include <deliver_request.h>
79 #include <verp_sender.h>
80 #include <dsn_util.h>
81 #include <dsn_buf.h>
82 #include <dsb_scan.h>
83 #include <rcpt_print.h>
84 #include <smtputf8.h>
85 
86 /* Application-specific. */
87 
88 #include "qmgr.h"
89 
90  /*
91  * Important note on the _transport_rate_delay implementation: after
92  * qmgr_transport_alloc() sets the QMGR_TRANSPORT_STAT_RATE_LOCK flag, all
93  * code paths must directly or indirectly invoke qmgr_transport_unthrottle()
94  * or qmgr_transport_throttle(). Otherwise, transports with non-zero
95  * _transport_rate_delay will become stuck.
96  */
97 
99 
100  /*
101  * Message delivery status codes.
102  */
103 #define DELIVER_STAT_OK 0 /* all recipients delivered */
104 #define DELIVER_STAT_DEFER 1 /* try some recipients later */
105 #define DELIVER_STAT_CRASH 2 /* mailer internal problem */
106 
107 /* qmgr_deliver_initial_reply - retrieve initial delivery process response */
108 
109 static int qmgr_deliver_initial_reply(VSTREAM *stream)
110 {
111  int stat;
112 
113  if (peekfd(vstream_fileno(stream)) < 0) {
114  msg_warn("%s: premature disconnect", VSTREAM_PATH(stream));
115  return (DELIVER_STAT_CRASH);
116  } else if (attr_scan(stream, ATTR_FLAG_STRICT,
118  ATTR_TYPE_END) != 1) {
119  msg_warn("%s: malformed response", VSTREAM_PATH(stream));
120  return (DELIVER_STAT_CRASH);
121  } else {
122  return (stat ? DELIVER_STAT_DEFER : 0);
123  }
124 }
125 
126 /* qmgr_deliver_final_reply - retrieve final delivery process response */
127 
128 static int qmgr_deliver_final_reply(VSTREAM *stream, DSN_BUF *dsb)
129 {
130  int stat;
131 
132  if (peekfd(vstream_fileno(stream)) < 0) {
133  msg_warn("%s: premature disconnect", VSTREAM_PATH(stream));
134  return (DELIVER_STAT_CRASH);
135  } else if (attr_scan(stream, ATTR_FLAG_STRICT,
136  RECV_ATTR_FUNC(dsb_scan, (void *) dsb),
138  ATTR_TYPE_END) != 2) {
139  msg_warn("%s: malformed response", VSTREAM_PATH(stream));
140  return (DELIVER_STAT_CRASH);
141  } else {
142  return (stat ? DELIVER_STAT_DEFER : 0);
143  }
144 }
145 
146 /* qmgr_deliver_send_request - send delivery request to delivery process */
147 
148 static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
149 {
150  RECIPIENT_LIST list = entry->rcpt_list;
151  RECIPIENT *recipient;
152  QMGR_MESSAGE *message = entry->message;
153  VSTRING *sender_buf = 0;
154  MSG_STATS stats;
155  char *sender;
156  int flags;
157  int smtputf8 = message->smtputf8;
158  const char *addr;
159 
160  /*
161  * Todo: integrate with code up-stream that builds the delivery request.
162  */
163  for (recipient = list.info; recipient < list.info + list.len; recipient++)
164  if (var_smtputf8_enable && (addr = recipient->address)[0]
165  && !allascii(addr) && valid_utf8_string(addr, strlen(addr))) {
166  smtputf8 |= SMTPUTF8_FLAG_RECIPIENT;
167  if (message->verp_delims)
168  smtputf8 |= SMTPUTF8_FLAG_SENDER;
169  }
170 
171  /*
172  * If variable envelope return path is requested, change prefix+@origin
173  * into prefix+user=domain@origin. Note that with VERP there is only one
174  * recipient per delivery.
175  */
176  if (message->verp_delims == 0) {
177  sender = message->sender;
178  } else {
179  sender_buf = vstring_alloc(100);
180  verp_sender(sender_buf, message->verp_delims,
181  message->sender, list.info);
182  sender = vstring_str(sender_buf);
183  }
184 
185  flags = message->tflags
186  | entry->queue->dflags
188  (void) QMGR_MSG_STATS(&stats, message);
189  attr_print(stream, ATTR_FLAG_NONE,
201  SEND_ATTR_FUNC(msg_stats_print, (void *) &stats),
202  /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
208  /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
212  /* XXX Ditto if we want to pass TLS certificate info. */
216  ATTR_TYPE_END);
217  if (sender_buf != 0)
218  vstring_free(sender_buf);
219  for (recipient = list.info; recipient < list.info + list.len; recipient++)
220  attr_print(stream, ATTR_FLAG_NONE,
221  SEND_ATTR_FUNC(rcpt_print, (void *) recipient),
222  ATTR_TYPE_END);
223  if (vstream_fflush(stream) != 0) {
224  msg_warn("write to process (%s): %m", entry->queue->transport->name);
225  return (-1);
226  } else {
227  if (msg_verbose)
228  msg_info("qmgr_deliver: site `%s'", entry->queue->name);
229  return (0);
230  }
231 }
232 
233 /* qmgr_deliver_abort - transport response watchdog */
234 
235 static void qmgr_deliver_abort(int unused_event, void *context)
236 {
237  QMGR_ENTRY *entry = (QMGR_ENTRY *) context;
238  QMGR_QUEUE *queue = entry->queue;
239  QMGR_TRANSPORT *transport = queue->transport;
240  QMGR_MESSAGE *message = entry->message;
241 
242  msg_fatal("%s: timeout receiving delivery status from transport: %s",
243  message->queue_id, transport->name);
244 }
245 
246 /* qmgr_deliver_update - process delivery status report */
247 
248 static void qmgr_deliver_update(int unused_event, void *context)
249 {
250  QMGR_ENTRY *entry = (QMGR_ENTRY *) context;
251  QMGR_QUEUE *queue = entry->queue;
252  QMGR_TRANSPORT *transport = queue->transport;
253  QMGR_MESSAGE *message = entry->message;
254  static DSN_BUF *dsb;
255  int status;
256 
257  /*
258  * Release the delivery agent from a "hot" queue entry.
259  */
260 #define QMGR_DELIVER_RELEASE_AGENT(entry) do { \
261  event_disable_readwrite(vstream_fileno(entry->stream)); \
262  (void) vstream_fclose(entry->stream); \
263  entry->stream = 0; \
264  qmgr_deliver_concurrency--; \
265  } while (0)
266 
267  if (dsb == 0)
268  dsb = dsb_create();
269 
270  /*
271  * The message transport has responded. Stop the watchdog timer.
272  */
273  event_cancel_timer(qmgr_deliver_abort, context);
274 
275  /*
276  * Retrieve the delivery agent status report. The numerical status code
277  * indicates if delivery should be tried again. The reason text is sent
278  * only when a site should be avoided for a while, so that the queue
279  * manager can log why it does not even try to schedule delivery to the
280  * affected recipients.
281  */
282  status = qmgr_deliver_final_reply(entry->stream, dsb);
283 
284  /*
285  * The mail delivery process failed for some reason (although delivery
286  * may have been successful). Back off with this transport type for a
287  * while. Dispose of queue entries for this transport that await
288  * selection (the todo lists). Stay away from queue entries that have
289  * been selected (the busy lists), or we would have dangling pointers.
290  * The queue itself won't go away before we dispose of the current queue
291  * entry.
292  */
293  if (status == DELIVER_STAT_CRASH) {
294  message->flags |= DELIVER_STAT_DEFER;
295 #if 0
296  whatsup = concatenate("unknown ", transport->name,
297  " mail transport error", (char *) 0);
298  qmgr_transport_throttle(transport,
299  DSN_SIMPLE(&dsb->dsn, "4.3.0", whatsup));
300  myfree(whatsup);
301 #else
302  qmgr_transport_throttle(transport,
303  DSN_SIMPLE(&dsb->dsn, "4.3.0",
304  "unknown mail transport error"));
305 #endif
306  msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description",
307  transport->name);
308 
309  /*
310  * Assume the worst and write a defer logfile record for each
311  * recipient. This omission was already present in the first queue
312  * manager implementation of 199703, and was fixed 200511.
313  *
314  * To avoid the synchronous qmgr_defer_recipient() operation for each
315  * recipient of this queue entry, release the delivery process and
316  * move the entry back to the todo queue. Let qmgr_defer_transport()
317  * log the recipient asynchronously if possible, and get out of here.
318  * Note: if asynchronous logging is not possible,
319  * qmgr_defer_transport() eventually invokes qmgr_entry_done() and
320  * the entry becomes a dangling pointer.
321  */
323  qmgr_entry_unselect(entry);
324  qmgr_defer_transport(transport, &dsb->dsn);
325  return;
326  }
327 
328  /*
329  * This message must be tried again.
330  *
331  * If we have a problem talking to this site, back off with this site for a
332  * while; dispose of queue entries for this site that await selection
333  * (the todo list); stay away from queue entries that have been selected
334  * (the busy list), or we would have dangling pointers. The queue itself
335  * won't go away before we dispose of the current queue entry.
336  *
337  * XXX Caution: DSN_COPY() will panic on empty status or reason.
338  */
339 #define SUSPENDED "delivery temporarily suspended: "
340 
341  if (status == DELIVER_STAT_DEFER) {
342  message->flags |= DELIVER_STAT_DEFER;
343  if (VSTRING_LEN(dsb->status)) {
344  /* Sanitize the DSN status/reason from the delivery agent. */
345  if (!dsn_valid(vstring_str(dsb->status)))
346  vstring_strcpy(dsb->status, "4.0.0");
347  if (VSTRING_LEN(dsb->reason) == 0)
348  vstring_strcpy(dsb->reason, "unknown error");
349  vstring_prepend(dsb->reason, SUSPENDED, sizeof(SUSPENDED) - 1);
350  if (QMGR_QUEUE_READY(queue)) {
352  if (QMGR_QUEUE_THROTTLED(queue))
353  qmgr_defer_todo(queue, &dsb->dsn);
354  }
355  }
356  }
357 
358  /*
359  * No problems detected. Mark the transport and queue as alive. The queue
360  * itself won't go away before we dispose of the current queue entry.
361  */
362  if (status != DELIVER_STAT_CRASH) {
363  qmgr_transport_unthrottle(transport);
364  if (VSTRING_LEN(dsb->reason) == 0)
365  qmgr_queue_unthrottle(queue);
366  }
367 
368  /*
369  * Release the delivery process, and give some other queue entry a chance
370  * to be delivered. When all recipients for a message have been tried,
371  * decide what to do next with this message: defer, bounce, delete.
372  */
375 }
376 
377 /* qmgr_deliver - deliver one per-site queue entry */
378 
379 void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream)
380 {
381  QMGR_ENTRY *entry;
382  DSN dsn;
383 
384  /*
385  * Find out if this delivery process is really available. Once elected,
386  * the delivery process is supposed to express its happiness. If there is
387  * a problem, wipe the pending deliveries for this transport. This
388  * routine runs in response to an external event, so it does not run
389  * while some other queue manipulation is happening.
390  */
391  if (stream == 0 || qmgr_deliver_initial_reply(stream) != 0) {
392 #if 0
393  whatsup = concatenate(transport->name,
394  " mail transport unavailable", (char *) 0);
395  qmgr_transport_throttle(transport,
396  DSN_SIMPLE(&dsn, "4.3.0", whatsup));
397  myfree(whatsup);
398 #else
399  qmgr_transport_throttle(transport,
400  DSN_SIMPLE(&dsn, "4.3.0",
401  "mail transport unavailable"));
402 #endif
403  qmgr_defer_transport(transport, &dsn);
404  if (stream)
405  (void) vstream_fclose(stream);
406  return;
407  }
408 
409  /*
410  * Find a suitable queue entry. Things may have changed since this
411  * transport was allocated. If no suitable entry is found,
412  * unceremoniously disconnect from the delivery process. The delivery
413  * agent request reading routine is prepared for the queue manager to
414  * change its mind for no apparent reason.
415  */
416  if ((entry = qmgr_job_entry_select(transport)) == 0) {
417  (void) vstream_fclose(stream);
418  return;
419  }
420 
421  /*
422  * Send the queue file info and recipient info to the delivery process.
423  * If there is a problem, wipe the pending deliveries for this transport.
424  * This routine runs in response to an external event, so it does not run
425  * while some other queue manipulation is happening.
426  */
427  if (qmgr_deliver_send_request(entry, stream) < 0) {
428  qmgr_entry_unselect(entry);
429 #if 0
430  whatsup = concatenate(transport->name,
431  " mail transport unavailable", (char *) 0);
432  qmgr_transport_throttle(transport,
433  DSN_SIMPLE(&dsn, "4.3.0", whatsup));
434  myfree(whatsup);
435 #else
436  qmgr_transport_throttle(transport,
437  DSN_SIMPLE(&dsn, "4.3.0",
438  "mail transport unavailable"));
439 #endif
440  qmgr_defer_transport(transport, &dsn);
441  /* warning: entry may be a dangling pointer here */
442  (void) vstream_fclose(stream);
443  return;
444  }
445 
446  /*
447  * If we get this far, go wait for the delivery status report.
448  */
450  entry->stream = stream;
452  qmgr_deliver_update, (void *) entry);
453 
454  /*
455  * Guard against broken systems.
456  */
457  event_request_timer(qmgr_deliver_abort, (void *) entry, var_daemon_timeout);
458 }
int msg_verbose
Definition: msg.c:177
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:729
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
DSN_BUF * dsb_create(void)
Definition: dsn_buf.c:169
size_t dsn_valid(const char *text)
Definition: dsn_util.c:112
char * queue_id
Definition: qmgr.h:298
QMGR_ENTRY * qmgr_job_entry_select(QMGR_TRANSPORT *)
Definition: qmgr_job.c:829
#define MAIL_ATTR_ENCODING
Definition: mail_proto.h:202
int smtputf8
Definition: qmgr.h:303
int msg_stats_print(ATTR_PRINT_MASTER_FN, VSTREAM *, int, void *)
int qmgr_deliver_concurrency
Definition: qmgr_deliver.c:93
char * client_addr
Definition: qmgr.h:312
const char * address
#define DSN_SIMPLE(dsn, _status, _reason)
Definition: dsn.h:41
QMGR_QUEUE * queue
Definition: qmgr.h:266
void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream)
Definition: qmgr_deliver.c:374
char * client_helo
Definition: qmgr.h:315
#define vstring_str(vp)
Definition: vstring.h:71
#define QMGR_DELIVER_RELEASE_AGENT(entry)
#define stat(p, s)
Definition: warn_stat.h:18
#define QMGR_QUEUE_BUSY
Definition: qmgr.h:217
int valid_utf8_string(const char *, ssize_t)
#define MAIL_ATTR_SIZE
Definition: mail_proto.h:139
#define SMTPUTF8_FLAG_SENDER
Definition: smtputf8.h:99
char * sasl_sender
Definition: qmgr.h:318
VSTRING * verp_sender(VSTRING *buf, const char *delimiters, const char *sender, const RECIPIENT *rcpt_info)
Definition: verp_sender.c:67
#define MAIL_ATTR_RWR_CONTEXT
Definition: mail_proto.h:163
DSN dsn
Definition: dsn_buf.h:28
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
int var_smtputf8_enable
Definition: mail_params.c:343
#define MAIL_ATTR_SASL_METHOD
Definition: mail_proto.h:156
char * log_ident
Definition: qmgr.h:319
int dsb_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp, int flags, void *ptr)
Definition: dsb_scan.c:48
#define MAIL_ATTR_LOG_HELO_NAME
Definition: mail_proto.h:210
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define MAIL_ATTR_LOG_PROTO_NAME
Definition: mail_proto.h:211
char * client_port
Definition: qmgr.h:313
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
#define MAIL_ATTR_QUEUE
Definition: mail_proto.h:129
long cont_length
Definition: qmgr.h:309
void qmgr_queue_unthrottle(QMGR_QUEUE *)
Definition: qmgr_queue.c:198
VSTRING * vstring_prepend(VSTRING *vp, const char *buf, ssize_t len)
Definition: vstring.c:545
int flags
Definition: qmgr.h:283
#define attr_print
Definition: attr.h:109
char * queue_name
Definition: qmgr.h:297
#define DSN_FROM_DSN_BUF(dsb)
Definition: dsn_buf.h:68
char * name
Definition: qmgr.h:200
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
char * rewrite_context
Definition: qmgr.h:320
#define MAIL_ATTR_SMTPUTF8
Definition: mail_proto.h:277
#define MAIL_ATTR_SASL_SENDER
Definition: mail_proto.h:158
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * sender
Definition: qmgr.h:300
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MAIL_ATTR_DSN_RET
Definition: mail_proto.h:274
void qmgr_queue_throttle(QMGR_QUEUE *, DSN *)
Definition: qmgr_queue.c:278
int dflags
Definition: qmgr.h:198
void qmgr_entry_unselect(QMGR_QUEUE *, QMGR_ENTRY *)
Definition: qmgr_entry.c:170
#define SUSPENDED
void qmgr_defer_transport(QMGR_TRANSPORT *, DSN *)
Definition: qmgr_defer.c:83
#define MAIL_ATTR_LOG_IDENT
Definition: mail_proto.h:162
#define MAIL_ATTR_DSN_ENVID
Definition: mail_proto.h:273
void qmgr_entry_done(QMGR_ENTRY *, int)
Definition: qmgr_entry.c:212
#define MAIL_ATTR_LOG_CLIENT_ADDR
Definition: mail_proto.h:208
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
char * name
Definition: qmgr.h:155
#define allascii(s)
Definition: stringops.h:66
#define SEND_ATTR_LONG(name, val)
Definition: attr.h:67
char * dsn_envid
Definition: qmgr.h:301
#define QMGR_MSG_STATS(stats, message)
Definition: qmgr.h:341
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
char * sasl_username
Definition: qmgr.h:317
void qmgr_transport_throttle(QMGR_TRANSPORT *, DSN *)
ssize_t peekfd(int)
Definition: peekfd.c:60
QMGR_MESSAGE * message
Definition: qmgr.h:264
#define DELIVER_STAT_DEFER
Definition: qmgr_deliver.c:104
#define MAIL_ATTR_NEXTHOP
Definition: mail_proto.h:148
QMGR_TRANSPORT * transport
Definition: qmgr.h:208
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void qmgr_transport_unthrottle(QMGR_TRANSPORT *)
void qmgr_defer_todo(QMGR_QUEUE *, DSN *)
Definition: qmgr_defer.c:103
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
#define MAIL_ATTR_SASL_USERNAME
Definition: mail_proto.h:157
#define MAIL_ATTR_RCPT_COUNT
Definition: mail_proto.h:132
char * sasl_method
Definition: qmgr.h:316
#define SEND_ATTR_FUNC(func, val)
Definition: attr.h:69
VSTRING * reason
Definition: dsn_buf.h:37
char * client_proto
Definition: qmgr.h:314
long data_offset
Definition: qmgr.h:296
Definition: dsn.h:17
#define MAIL_ATTR_LOG_CLIENT_NAME
Definition: mail_proto.h:207
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
RECIPIENT * info
char * client_name
Definition: qmgr.h:311
char * inspect_xport
Definition: qmgr.h:306
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
#define vstream_fileno(vp)
Definition: vstream.h:115
VSTREAM * stream
Definition: qmgr.h:263
int var_daemon_timeout
Definition: mail_params.c:284
RECIPIENT_LIST rcpt_list
Definition: qmgr.h:265
#define SMTPUTF8_FLAG_RECIPIENT
Definition: smtputf8.h:100
int tflags
Definition: qmgr.h:285
#define RECV_ATTR_FUNC(func, val)
Definition: attr.h:77
int rcpt_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, int flags, void *ptr)
Definition: rcpt_print.c:51
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
char * nexthop
Definition: qmgr.h:201
char * verp_delims
Definition: qmgr.h:304
#define QMGR_QUEUE_READY(q)
Definition: qmgr.h:244
#define attr_scan
Definition: attr.h:111
#define DEL_REQ_FLAG_BOUNCE
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
VSTRING * status
Definition: dsn_buf.h:30
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
int dsn_ret
Definition: qmgr.h:302
#define MAIL_ATTR_LOG_CLIENT_PORT
Definition: mail_proto.h:209
#define DEL_REQ_FLAG_DEFLT
#define MAIL_ATTR_OFFSET
Definition: mail_proto.h:138
#define QMGR_QUEUE_THROTTLED(q)
Definition: qmgr.h:245
char * encoding
Definition: qmgr.h:299
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199
#define DELIVER_STAT_CRASH
Definition: qmgr_deliver.c:105