Postfix3.3.1
cleanup_envelope.c
[詳解]
1 /*++
2 /* NAME
3 /* cleanup_envelope 3
4 /* SUMMARY
5 /* process envelope segment
6 /* SYNOPSIS
7 /* #include <cleanup.h>
8 /*
9 /* void cleanup_envelope(state, type, buf, len)
10 /* CLEANUP_STATE *state;
11 /* int type;
12 /* const char *buf;
13 /* ssize_t len;
14 /* DESCRIPTION
15 /* This module processes envelope records and writes the result
16 /* to the queue file. It validates the message structure, rewrites
17 /* sender/recipient addresses to canonical form, and expands recipients
18 /* according to entries in the virtual table. This routine absorbs but
19 /* does not emit the envelope to content boundary record.
20 /*
21 /* Arguments:
22 /* .IP state
23 /* Queue file and message processing state. This state is updated
24 /* as records are processed and as errors happen.
25 /* .IP type
26 /* Record type.
27 /* .IP buf
28 /* Record content.
29 /* .IP len
30 /* Record content length.
31 /* LICENSE
32 /* .ad
33 /* .fi
34 /* The Secure Mailer license must be distributed with this software.
35 /* AUTHOR(S)
36 /* Wietse Venema
37 /* IBM T.J. Watson Research
38 /* P.O. Box 704
39 /* Yorktown Heights, NY 10598, USA
40 /*
41 /* Wietse Venema
42 /* Google, Inc.
43 /* 111 8th Avenue
44 /* New York, NY 10011, USA
45 /*--*/
46 
47 /* System library. */
48 
49 #include <sys_defs.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <stdio.h> /* ssscanf() */
53 #include <ctype.h>
54 
55 /* Utility library. */
56 
57 #include <msg.h>
58 #include <vstring.h>
59 #include <vstream.h>
60 #include <mymalloc.h>
61 #include <stringops.h>
62 #include <nvtable.h>
63 
64 /* Global library. */
65 
66 #include <record.h>
67 #include <rec_type.h>
68 #include <cleanup_user.h>
69 #include <qmgr_user.h>
70 #include <mail_params.h>
71 #include <verp_sender.h>
72 #include <mail_proto.h>
73 #include <dsn_mask.h>
74 #include <rec_attr_map.h>
75 #include <smtputf8.h>
76 #include <deliver_request.h>
77 
78 /* Application-specific. */
79 
80 #include "cleanup.h"
81 
82 #define STR vstring_str
83 #define STREQ(x,y) (strcmp((x), (y)) == 0)
84 
85 static void cleanup_envelope_process(CLEANUP_STATE *, int, const char *, ssize_t);
86 
87 /* cleanup_envelope - initialize message envelope */
88 
89 void cleanup_envelope(CLEANUP_STATE *state, int type,
90  const char *str, ssize_t len)
91 {
92 
93  /*
94  * The message size and count record goes first, so it can easily be
95  * updated in place. This information takes precedence over any size
96  * estimate provided by the client. It's all in one record, data size
97  * first, for backwards compatibility reasons.
98  */
100  (REC_TYPE_SIZE_CAST1) 0, /* extra offs - content offs */
101  (REC_TYPE_SIZE_CAST2) 0, /* content offset */
102  (REC_TYPE_SIZE_CAST3) 0, /* recipient count */
103  (REC_TYPE_SIZE_CAST4) 0, /* qmgr options */
104  (REC_TYPE_SIZE_CAST5) 0, /* content length */
105  (REC_TYPE_SIZE_CAST6) 0); /* smtputf8 */
106 
107  /*
108  * Pass control to the actual envelope processing routine.
109  */
110  state->action = cleanup_envelope_process;
111  cleanup_envelope_process(state, type, str, len);
112 }
113 
114 /* cleanup_envelope_process - process one envelope record */
115 
116 static void cleanup_envelope_process(CLEANUP_STATE *state, int type,
117  const char *buf, ssize_t len)
118 {
119  const char *myname = "cleanup_envelope_process";
120  char *attr_name;
121  char *attr_value;
122  const char *error_text;
123  int extra_opts;
124  int junk;
125  int mapped_type = type;
126  const char *mapped_buf = buf;
127  int milter_count;
128 
129 #ifdef DELAY_ACTION
130  int defer_delay;
131 
132 #endif
133 
134  if (msg_verbose)
135  msg_info("initial envelope %c %.*s", type, (int) len, buf);
136 
137  if (type == REC_TYPE_FLGS) {
138  /* Not part of queue file format. */
139  extra_opts = atoi(buf);
140  if (extra_opts & ~CLEANUP_FLAG_MASK_EXTRA)
141  msg_warn("%s: ignoring bad extra flags: 0x%x",
142  state->queue_id, extra_opts);
143  else
144  state->flags |= extra_opts;
145  return;
146  }
147 #ifdef DELAY_ACTION
148  if (type == REC_TYPE_DELAY) {
149  /* Not part of queue file format. */
150  defer_delay = atoi(buf);
151  if (defer_delay <= 0)
152  msg_warn("%s: ignoring bad delay time: %s", state->queue_id, buf);
153  else
154  state->defer_delay = defer_delay;
155  return;
156  }
157 #endif
158 
159  /*
160  * XXX We instantiate a MILTERS structure even when the filter count is
161  * zero (for example, all filters are in ACCEPT state, or the SMTP server
162  * sends a dummy MILTERS structure without any filters), otherwise the
163  * cleanup server would apply the non_smtpd_milters setting
164  * inappropriately.
165  */
166  if (type == REC_TYPE_MILT_COUNT) {
167  /* Not part of queue file format. */
168  if ((milter_count = atoi(buf)) >= 0)
169  cleanup_milter_receive(state, milter_count);
170  return;
171  }
172 
173  /*
174  * Map DSN attribute name to pseudo record type so that we don't have to
175  * pollute the queue file with records that are incompatible with past
176  * Postfix versions. Preferably, people should be able to back out from
177  * an upgrade without losing mail.
178  */
179  if (type == REC_TYPE_ATTR) {
180  vstring_strcpy(state->attr_buf, buf);
181  error_text = split_nameval(STR(state->attr_buf), &attr_name, &attr_value);
182  if (error_text != 0) {
183  msg_warn("%s: message rejected: malformed attribute: %s: %.100s",
184  state->queue_id, error_text, buf);
185  state->errs |= CLEANUP_STAT_BAD;
186  return;
187  }
188  /* Zero-length values are place holders for unavailable values. */
189  if (*attr_value == 0) {
190  msg_warn("%s: spurious null attribute value for \"%s\" -- ignored",
191  state->queue_id, attr_name);
192  return;
193  }
194  if ((junk = rec_attr_map(attr_name)) != 0) {
195  mapped_buf = attr_value;
196  mapped_type = junk;
197  }
198  }
199 
200  /*
201  * Sanity check.
202  */
203  if (strchr(REC_TYPE_ENVELOPE, type) == 0) {
204  msg_warn("%s: message rejected: unexpected record type %d in envelope",
205  state->queue_id, type);
206  state->errs |= CLEANUP_STAT_BAD;
207  return;
208  }
209 
210  /*
211  * Although recipient records appear at the end of the initial or
212  * extracted envelope, the code for processing recipient records is first
213  * because there can be lots of them.
214  *
215  * Recipient records may be mixed with other information (such as FILTER or
216  * REDIRECT actions from SMTPD). In that case the queue manager needs to
217  * examine all queue file records before it can start delivery. This is
218  * not a problem when SMTPD recipient lists are small.
219  *
220  * However, if recipient records are not mixed with other records
221  * (typically, mailing list mail) then we can make an optimization: the
222  * queue manager does not need to examine every envelope record before it
223  * can start deliveries. This can help with very large mailing lists.
224  */
225 
226  /*
227  * On the transition from non-recipient records to recipient records,
228  * emit some records and do some sanity checks.
229  *
230  * XXX Moving the envelope sender (and the test for its presence) to the
231  * extracted segment can reduce qmqpd memory requirements because it no
232  * longer needs to read the entire message into main memory.
233  */
234  if ((state->flags & CLEANUP_FLAG_INRCPT) == 0
235  && strchr(REC_TYPE_ENV_RECIPIENT, type) != 0) {
236  if (state->sender == 0) {
237  msg_warn("%s: message rejected: missing sender envelope record",
238  state->queue_id);
239  state->errs |= CLEANUP_STAT_BAD;
240  return;
241  }
242  if (state->arrival_time.tv_sec == 0) {
243  msg_warn("%s: message rejected: missing time envelope record",
244  state->queue_id);
245  state->errs |= CLEANUP_STAT_BAD;
246  return;
247  }
248 
249  /*
250  * XXX This works by accident, because the sender is recorded at the
251  * beginning of the envelope segment.
252  */
253  if ((state->flags & CLEANUP_FLAG_WARN_SEEN) == 0
254  && state->sender && *state->sender
255  && var_delay_warn_time > 0) {
257  REC_TYPE_WARN_ARG(state->arrival_time.tv_sec
259  }
260  state->flags |= CLEANUP_FLAG_INRCPT;
261  }
262 
263  /*
264  * Initial envelope recipient record processing.
265  */
266  if (type == REC_TYPE_RCPT) {
267  if (state->sender == 0) { /* protect showq */
268  msg_warn("%s: message rejected: envelope recipient precedes sender",
269  state->queue_id);
270  state->errs |= CLEANUP_STAT_BAD;
271  return;
272  }
273  if (state->orig_rcpt == 0)
274  state->orig_rcpt = mystrdup(buf);
275  cleanup_addr_recipient(state, buf);
276  if (cleanup_milters != 0
277  && state->milters == 0
278  && CLEANUP_MILTER_OK(state))
280  myfree(state->orig_rcpt);
281  state->orig_rcpt = 0;
282  if (state->dsn_orcpt != 0) {
283  myfree(state->dsn_orcpt);
284  state->dsn_orcpt = 0;
285  }
286  state->dsn_notify = 0;
287  return;
288  }
289  if (type == REC_TYPE_DONE || type == REC_TYPE_DRCP) {
290  if (state->orig_rcpt != 0) {
291  myfree(state->orig_rcpt);
292  state->orig_rcpt = 0;
293  }
294  if (state->dsn_orcpt != 0) {
295  myfree(state->dsn_orcpt);
296  state->dsn_orcpt = 0;
297  }
298  state->dsn_notify = 0;
299  return;
300  }
301  if (mapped_type == REC_TYPE_DSN_ORCPT) {
302  if (state->dsn_orcpt) {
303  msg_warn("%s: ignoring out-of-order DSN original recipient record <%.200s>",
304  state->queue_id, state->dsn_orcpt);
305  myfree(state->dsn_orcpt);
306  }
307  state->dsn_orcpt = mystrdup(mapped_buf);
308  return;
309  }
310  if (mapped_type == REC_TYPE_DSN_NOTIFY) {
311  if (state->dsn_notify) {
312  msg_warn("%s: ignoring out-of-order DSN notify record <%d>",
313  state->queue_id, state->dsn_notify);
314  state->dsn_notify = 0;
315  }
316  if (!alldig(mapped_buf) || (junk = atoi(mapped_buf)) == 0
317  || DSN_NOTIFY_OK(junk) == 0)
318  msg_warn("%s: ignoring malformed DSN notify record <%.200s>",
319  state->queue_id, buf);
320  else
321  state->qmgr_opts |=
322  QMGR_READ_FLAG_FROM_DSN(state->dsn_notify = junk);
323  return;
324  }
325  if (type == REC_TYPE_ORCP) {
326  if (state->orig_rcpt != 0) {
327  msg_warn("%s: ignoring out-of-order original recipient record <%.200s>",
328  state->queue_id, state->orig_rcpt);
329  myfree(state->orig_rcpt);
330  }
331  state->orig_rcpt = mystrdup(buf);
332  return;
333  }
334  if (type == REC_TYPE_MESG) {
335  state->action = cleanup_message;
336  if (state->flags & CLEANUP_FLAG_INRCPT) {
337  if (state->milters || cleanup_milters) {
338  /* Make room to append recipient. */
339  if ((state->append_rcpt_pt_offset = vstream_ftell(state->dst)) < 0)
340  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
342  if ((state->append_rcpt_pt_target = vstream_ftell(state->dst)) < 0)
343  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
344  }
345  state->flags &= ~CLEANUP_FLAG_INRCPT;
346  }
347  return;
348  }
349 
350  /*
351  * Initial envelope non-recipient record processing.
352  *
353  * If the message was requeued with "postsuper -r" use their
354  * SMTPUTF8_REQUESTED flag.
355  */
356  if (state->flags & CLEANUP_FLAG_INRCPT)
357  /* Tell qmgr that recipient records are mixed with other information. */
359  if (type == REC_TYPE_SIZE) {
360  /* Use our own SIZE record, except for the SMTPUTF8_REQUESTED flag. */
361  (void) sscanf(buf, "%*s $*s %*s %*s %*s %d", &state->smtputf8);
363  return;
364  }
365  if (mapped_type == REC_TYPE_CTIME)
366  /* Use our own expiration time base record instead. */
367  return;
368  if (type == REC_TYPE_TIME) {
369  /* First instance wins. */
370  if (state->arrival_time.tv_sec == 0) {
371  REC_TYPE_TIME_SCAN(buf, state->arrival_time);
372  cleanup_out(state, type, buf, len);
373  }
374  /* Generate our own expiration time base record. */
375  cleanup_out_format(state, REC_TYPE_ATTR, "%s=%ld",
376  MAIL_ATTR_CREATE_TIME, (long) time((time_t *) 0));
377  return;
378  }
379  if (type == REC_TYPE_FULL) {
380  /* First instance wins. */
381  if (state->fullname == 0) {
382  state->fullname = mystrdup(buf);
383  cleanup_out(state, type, buf, len);
384  }
385  return;
386  }
387  if (type == REC_TYPE_FROM) {
388  off_t after_sender_offs;
389 
390  /* Allow only one instance. */
391  if (state->sender != 0) {
392  msg_warn("%s: message rejected: multiple envelope sender records",
393  state->queue_id);
394  state->errs |= CLEANUP_STAT_BAD;
395  return;
396  }
397  if (state->milters || cleanup_milters) {
398  /* Remember the sender record offset. */
399  if ((state->sender_pt_offset = vstream_ftell(state->dst)) < 0)
400  msg_fatal("%s: vstream_ftell %s: %m:", myname, cleanup_path);
401  }
402  after_sender_offs = cleanup_addr_sender(state, buf);
403  if (state->milters || cleanup_milters) {
404  /* Remember the after-sender record offset. */
405  state->sender_pt_target = after_sender_offs;
406  }
407  if (cleanup_milters != 0
408  && state->milters == 0
409  && CLEANUP_MILTER_OK(state))
411  return;
412  }
413  if (mapped_type == REC_TYPE_DSN_ENVID) {
414  /* Don't break "postsuper -r" after Milter overrides ENVID. */
415  if (!allprint(mapped_buf)) {
416  msg_warn("%s: message rejected: bad DSN envelope ID record",
417  state->queue_id);
418  state->errs |= CLEANUP_STAT_BAD;
419  return;
420  }
421  if (state->dsn_envid != 0)
422  myfree(state->dsn_envid);
423  state->dsn_envid = mystrdup(mapped_buf);
424  cleanup_out(state, type, buf, len);
425  return;
426  }
427  if (mapped_type == REC_TYPE_DSN_RET) {
428  /* Don't break "postsuper -r" after Milter overrides RET. */
429  if (!alldig(mapped_buf) || (junk = atoi(mapped_buf)) == 0
430  || DSN_RET_OK(junk) == 0) {
431  msg_warn("%s: message rejected: bad DSN RET record <%.200s>",
432  state->queue_id, buf);
433  state->errs |= CLEANUP_STAT_BAD;
434  return;
435  }
436  state->dsn_ret = junk;
437  cleanup_out(state, type, buf, len);
438  return;
439  }
440  if (type == REC_TYPE_WARN) {
441  /* First instance wins. */
442  if ((state->flags & CLEANUP_FLAG_WARN_SEEN) == 0) {
443  state->flags |= CLEANUP_FLAG_WARN_SEEN;
444  cleanup_out(state, type, buf, len);
445  }
446  return;
447  }
448  /* XXX Needed for cleanup_bounce(); sanity check usage. */
449  if (type == REC_TYPE_VERP) {
450  if (state->verp_delims == 0) {
451  if (state->sender == 0 || state->sender[0] == 0) {
452  msg_warn("%s: ignoring VERP request for null sender",
453  state->queue_id);
454  } else if (verp_delims_verify(buf) != 0) {
455  msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
456  state->queue_id, buf);
457  } else {
458  state->verp_delims = mystrdup(buf);
459  cleanup_out(state, type, buf, len);
460  }
461  }
462  return;
463  }
464  if (type == REC_TYPE_ATTR) {
465  if (state->attr->used >= var_qattr_count_limit) {
466  msg_warn("%s: message rejected: attribute count exceeds limit %d",
468  state->errs |= CLEANUP_STAT_BAD;
469  return;
470  }
471  if (strcmp(attr_name, MAIL_ATTR_RWR_CONTEXT) == 0) {
472  /* Choose header rewriting context. See also cleanup_addr.c. */
473  if (STREQ(attr_value, MAIL_ATTR_RWR_LOCAL)) {
475  } else if (STREQ(attr_value, MAIL_ATTR_RWR_REMOTE)) {
476  state->hdr_rewrite_context =
478  } else {
479  msg_warn("%s: message rejected: bad rewriting context: %.100s",
480  state->queue_id, attr_value);
481  state->errs |= CLEANUP_STAT_BAD;
482  return;
483  }
484  }
485  if (strcmp(attr_name, MAIL_ATTR_TRACE_FLAGS) == 0) {
486  if (!alldig(attr_value)) {
487  msg_warn("%s: message rejected: bad TFLAG record <%.200s>",
488  state->queue_id, buf);
489  state->errs |= CLEANUP_STAT_BAD;
490  return;
491  }
492  if (state->tflags == 0)
493  state->tflags = DEL_REQ_TRACE_FLAGS(atoi(attr_value));
494  }
495  nvtable_update(state->attr, attr_name, attr_value);
496  cleanup_out(state, type, buf, len);
497  return;
498  } else {
499  cleanup_out(state, type, buf, len);
500  return;
501  }
502 }
int msg_verbose
Definition: msg.c:177
#define REC_TYPE_DELAY
Definition: rec_type.h:54
char * orig_rcpt
Definition: cleanup.h:61
void myfree(void *ptr)
Definition: mymalloc.c:207
#define QMGR_READ_FLAG_MIXED_RCPT_OTHER
Definition: qmgr_user.h:25
#define MAIL_ATTR_TRACE_FLAGS
Definition: mail_proto.h:149
int smtputf8
Definition: cleanup.h:134
void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
Definition: cleanup_out.c:155
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define REC_TYPE_SIZE_CAST3
Definition: rec_type.h:130
char * recip
Definition: cleanup.h:60
#define MAIL_ATTR_CREATE_TIME
Definition: mail_proto.h:144
char * fullname
Definition: cleanup.h:58
NVTABLE_INFO * nvtable_update(NVTABLE *table, const char *key, const char *value)
Definition: nvtable.c:111
off_t vstream_ftell(VSTREAM *stream)
Definition: vstream.c:1157
off_t cleanup_addr_sender(CLEANUP_STATE *, const char *)
Definition: cleanup_addr.c:111
void cleanup_milter_emul_mail(CLEANUP_STATE *, MILTERS *, const char *)
int tflags
Definition: cleanup.h:67
ssize_t used
Definition: htable.h:27
#define REC_TYPE_SIZE_CAST2
Definition: rec_type.h:129
off_t sender_pt_target
Definition: cleanup.h:81
off_t append_rcpt_pt_target
Definition: cleanup.h:83
#define REC_TYPE_VERP
Definition: rec_type.h:68
#define REC_TYPE_SIZE
Definition: rec_type.h:37
MILTERS * milters
Definition: cleanup.h:109
#define MAIL_ATTR_RWR_CONTEXT
Definition: mail_proto.h:163
void cleanup_message(CLEANUP_STATE *, int, const char *, ssize_t)
#define MAIL_ATTR_RWR_LOCAL
Definition: mail_proto.h:166
#define REC_TYPE_DSN_ENVID
Definition: rec_type.h:71
#define REC_TYPE_FROM
Definition: rec_type.h:43
#define MAIL_ATTR_RWR_REMOTE
Definition: mail_proto.h:167
struct timeval arrival_time
Definition: cleanup.h:57
#define CLEANUP_MILTER_OK(s)
Definition: cleanup.h:327
#define DSN_RET_OK(v)
Definition: dsn_mask.h:24
int alldig(const char *string)
Definition: alldig.c:38
char * cleanup_path
Definition: cleanup_init.c:111
#define REC_TYPE_SIZE_FORMAT
Definition: rec_type.h:127
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define REC_TYPE_DSN_NOTIFY
Definition: rec_type.h:73
#define CLEANUP_FLAG_INRCPT
Definition: cleanup.h:140
#define REC_TYPE_MILT_COUNT
Definition: rec_type.h:75
char * dsn_envid
Definition: cleanup.h:97
int var_qattr_count_limit
Definition: cleanup_init.c:143
#define DEL_REQ_TRACE_FLAGS(f)
NVTABLE * attr
Definition: cleanup.h:91
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
#define SMTPUTF8_FLAG_REQUESTED
Definition: smtputf8.h:97
void cleanup_envelope(CLEANUP_STATE *state, int type, const char *str, ssize_t len)
#define REC_TYPE_DSN_RET
Definition: rec_type.h:70
#define REC_TYPE_DRCP
Definition: rec_type.h:47
int dsn_notify
Definition: cleanup.h:99
#define REC_TYPE_DSN_ORCPT
Definition: rec_type.h:72
#define REC_TYPE_PTR_FORMAT
Definition: rec_type.h:179
off_t append_rcpt_pt_offset
Definition: cleanup.h:82
void cleanup_milter_emul_rcpt(CLEANUP_STATE *, MILTERS *, const char *)
char * sender
Definition: cleanup.h:59
char * dsn_orcpt
Definition: cleanup.h:100
#define REC_TYPE_RCPT
Definition: rec_type.h:45
off_t sender_pt_offset
Definition: cleanup.h:80
#define REC_TYPE_MESG
Definition: rec_type.h:56
#define CLEANUP_FLAG_MASK_EXTRA
Definition: cleanup_user.h:46
#define REC_TYPE_PTR
Definition: rec_type.h:67
char * hdr_rewrite_context
Definition: cleanup.h:94
void msg_warn(const char *fmt,...)
Definition: msg.c:215
void(* action)(struct CLEANUP_STATE *, int, const char *, ssize_t)
Definition: cleanup.h:75
#define REC_TYPE_WARN_ARG(tv)
Definition: rec_type.h:141
VSTRING * attr_buf
Definition: cleanup.h:48
#define REC_TYPE_WARN
Definition: rec_type.h:48
char * queue_id
Definition: cleanup.h:56
#define STREQ(x, y)
int rec_attr_map(const char *attr_name)
Definition: rec_attr_map.c:39
int var_delay_warn_time
Definition: bounce.c:192
const char * verp_delims_verify(const char *delims)
Definition: verp_sender.c:104
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
void cleanup_milter_receive(CLEANUP_STATE *, int)
#define REC_TYPE_WARN_FORMAT
Definition: rec_type.h:140
VSTREAM * dst
Definition: cleanup.h:53
#define CLEANUP_STAT_BAD
Definition: cleanup_user.h:57
#define STR
#define CLEANUP_FLAG_WARN_SEEN
Definition: cleanup.h:141
int dsn_ret
Definition: cleanup.h:98
#define QMGR_READ_FLAG_FROM_DSN(x)
Definition: qmgr_user.h:26
#define DSN_NOTIFY_OK(v)
Definition: dsn_mask.h:63
int allprint(const char *string)
Definition: allprint.c:39
char * verp_delims
Definition: cleanup.h:101
#define REC_TYPE_ATTR
Definition: rec_type.h:49
#define REC_TYPE_SIZE_CAST4
Definition: rec_type.h:131
#define REC_TYPE_TIME
Definition: rec_type.h:38
void cleanup_out(CLEANUP_STATE *, int, const char *, ssize_t)
Definition: cleanup_out.c:102
MILTERS * cleanup_milters
Definition: cleanup_init.c:279
#define REC_TYPE_CTIME
Definition: rec_type.h:39
#define REC_TYPE_SIZE_CAST1
Definition: rec_type.h:128
#define REC_TYPE_SIZE_CAST5
Definition: rec_type.h:132
#define REC_TYPE_DONE
Definition: rec_type.h:44
#define REC_TYPE_SIZE_CAST6
Definition: rec_type.h:133
#define REC_TYPE_ORCP
Definition: rec_type.h:46
char * var_remote_rwr_domain
Definition: cleanup_init.c:149
#define REC_TYPE_TIME_SCAN(cp, tv)
Definition: rec_type.h:150
int qmgr_opts
Definition: cleanup.h:68
#define REC_TYPE_FLGS
Definition: rec_type.h:53
#define REC_TYPE_FULL
Definition: rec_type.h:40
#define REC_TYPE_ENV_RECIPIENT
Definition: rec_type.h:89
void cleanup_addr_recipient(CLEANUP_STATE *, const char *)
Definition: cleanup_addr.c:190
void msg_info(const char *fmt,...)
Definition: msg.c:199
#define REC_TYPE_ENVELOPE
Definition: rec_type.h:106