Postfix3.3.1
qmgr_message.c
[詳解]
1 /*++
2 /* NAME
3 /* qmgr_message 3
4 /* SUMMARY
5 /* in-core message structures
6 /* SYNOPSIS
7 /* #include "qmgr.h"
8 /*
9 /* int qmgr_message_count;
10 /* int qmgr_recipient_count;
11 /* int qmgr_vrfy_pend_count;
12 /*
13 /* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode)
14 /* const char *class;
15 /* const char *name;
16 /* int qflags;
17 /* mode_t mode;
18 /*
19 /* QMGR_MESSAGE *qmgr_message_realloc(message)
20 /* QMGR_MESSAGE *message;
21 /*
22 /* void qmgr_message_free(message)
23 /* QMGR_MESSAGE *message;
24 /*
25 /* void qmgr_message_update_warn(message)
26 /* QMGR_MESSAGE *message;
27 /*
28 /* void qmgr_message_kill_record(message, offset)
29 /* QMGR_MESSAGE *message;
30 /* long offset;
31 /* DESCRIPTION
32 /* This module performs en-gross operations on queue messages.
33 /*
34 /* qmgr_message_count is a global counter for the total number
35 /* of in-core message structures (i.e. the total size of the
36 /* `active' message queue).
37 /*
38 /* qmgr_recipient_count is a global counter for the total number
39 /* of in-core recipient structures (i.e. the sum of all recipients
40 /* in all in-core message structures).
41 /*
42 /* qmgr_vrfy_pend_count is a global counter for the total
43 /* number of in-core message structures that are associated
44 /* with an address verification request. Requests that exceed
45 /* the address_verify_pending_limit are deferred immediately.
46 /* This is a backup mechanism for a more refined enforcement
47 /* mechanism in the verify(8) daemon.
48 /*
49 /* qmgr_message_alloc() creates an in-core message structure
50 /* with sender and recipient information taken from the named queue
51 /* file. A null result means the queue file could not be read or
52 /* that the queue file contained incorrect information. A result
53 /* QMGR_MESSAGE_LOCKED means delivery must be deferred. The number
54 /* of recipients read from a queue file is limited by the global
55 /* var_qmgr_rcpt_limit configuration parameter. When the limit
56 /* is reached, the \fIrcpt_offset\fR structure member is set to
57 /* the position where the read was terminated. Recipients are
58 /* run through the resolver, and are assigned to destination
59 /* queues. Recipients that cannot be assigned are deferred or
60 /* bounced. Mail that has bounced twice is silently absorbed.
61 /* A non-zero mode means change the queue file permissions.
62 /*
63 /* qmgr_message_realloc() resumes reading recipients from the queue
64 /* file, and updates the recipient list and \fIrcpt_offset\fR message
65 /* structure members. A null result means that the file could not be
66 /* read or that the file contained incorrect information. Recipient
67 /* limit imposed this time is based on the position of the message
68 /* job(s) on corresponding transport job list(s). It's considered
69 /* an error to call this when the recipient slots can't be allocated.
70 /*
71 /* qmgr_message_free() destroys an in-core message structure and makes
72 /* the resources available for reuse. It is an error to destroy
73 /* a message structure that is still referenced by queue entry structures.
74 /*
75 /* qmgr_message_update_warn() takes a closed message, opens it, updates
76 /* the warning field, and closes it again.
77 /*
78 /* qmgr_message_kill_record() takes a closed message, opens it, updates
79 /* the record type at the given offset to "killed", and closes the file.
80 /* A killed envelope record is ignored. Killed records are not allowed
81 /* inside the message content.
82 /* DIAGNOSTICS
83 /* Warnings: malformed message file. Fatal errors: out of memory.
84 /* SEE ALSO
85 /* envelope(3) message envelope parser
86 /* LICENSE
87 /* .ad
88 /* .fi
89 /* The Secure Mailer license must be distributed with this software.
90 /* AUTHOR(S)
91 /* Wietse Venema
92 /* IBM T.J. Watson Research
93 /* P.O. Box 704
94 /* Yorktown Heights, NY 10598, USA
95 /*
96 /* Wietse Venema
97 /* Google, Inc.
98 /* 111 8th Avenue
99 /* New York, NY 10011, USA
100 /*
101 /* Preemptive scheduler enhancements:
102 /* Patrik Rak
103 /* Modra 6
104 /* 155 00, Prague, Czech Republic
105 /*--*/
106 
107 /* System library. */
108 
109 #include <sys_defs.h>
110 #include <sys/stat.h>
111 #include <stdlib.h>
112 #include <stdio.h> /* sscanf() */
113 #include <fcntl.h>
114 #include <errno.h>
115 #include <unistd.h>
116 #include <string.h>
117 #include <ctype.h>
118 
119 /* Utility library. */
120 
121 #include <msg.h>
122 #include <mymalloc.h>
123 #include <vstring.h>
124 #include <vstream.h>
125 #include <split_at.h>
126 #include <valid_hostname.h>
127 #include <argv.h>
128 #include <stringops.h>
129 #include <myflock.h>
130 #include <sane_time.h>
131 
132 /* Global library. */
133 
134 #include <dict.h>
135 #include <mail_queue.h>
136 #include <mail_params.h>
137 #include <canon_addr.h>
138 #include <record.h>
139 #include <rec_type.h>
140 #include <sent.h>
141 #include <deliver_completed.h>
142 #include <opened.h>
143 #include <verp_sender.h>
144 #include <mail_proto.h>
145 #include <qmgr_user.h>
146 #include <split_addr.h>
147 #include <dsn_mask.h>
148 #include <rec_attr_map.h>
149 
150 /* Client stubs. */
151 
152 #include <rewrite_clnt.h>
153 #include <resolve_clnt.h>
154 
155 /* Application-specific. */
156 
157 #include "qmgr.h"
158 
162 
163 /* qmgr_message_create - create in-core message structure */
164 
165 static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
166  const char *queue_id, int qflags)
167 {
168  QMGR_MESSAGE *message;
169 
170  message = (QMGR_MESSAGE *) mymalloc(sizeof(QMGR_MESSAGE));
172  message->flags = 0;
173  message->qflags = qflags;
174  message->tflags = 0;
175  message->tflags_offset = 0;
176  message->rflags = QMGR_READ_FLAG_DEFAULT;
177  message->fp = 0;
178  message->refcount = 0;
179  message->single_rcpt = 0;
180  message->arrival_time.tv_sec = message->arrival_time.tv_usec = 0;
181  message->create_time = 0;
182  GETTIMEOFDAY(&message->active_time);
183  message->queued_time = sane_time();
184  message->refill_time = 0;
185  message->data_offset = 0;
186  message->queue_id = mystrdup(queue_id);
187  message->queue_name = mystrdup(queue_name);
188  message->encoding = 0;
189  message->sender = 0;
190  message->dsn_envid = 0;
191  message->dsn_ret = 0;
192  message->smtputf8 = 0;
193  message->filter_xport = 0;
194  message->inspect_xport = 0;
195  message->redirect_addr = 0;
196  message->data_size = 0;
197  message->cont_length = 0;
198  message->warn_offset = 0;
199  message->warn_time = 0;
200  message->rcpt_offset = 0;
201  message->verp_delims = 0;
202  message->client_name = 0;
203  message->client_addr = 0;
204  message->client_port = 0;
205  message->client_proto = 0;
206  message->client_helo = 0;
207  message->sasl_method = 0;
208  message->sasl_username = 0;
209  message->sasl_sender = 0;
210  message->log_ident = 0;
211  message->rewrite_context = 0;
213  message->rcpt_count = 0;
215  message->rcpt_unread = 0;
216  QMGR_LIST_INIT(message->job_list);
217  return (message);
218 }
219 
220 /* qmgr_message_close - close queue file */
221 
222 static void qmgr_message_close(QMGR_MESSAGE *message)
223 {
224  vstream_fclose(message->fp);
225  message->fp = 0;
226 }
227 
228 /* qmgr_message_open - open queue file */
229 
230 static int qmgr_message_open(QMGR_MESSAGE *message)
231 {
232 
233  /*
234  * Sanity check.
235  */
236  if (message->fp)
237  msg_panic("%s: queue file is open", message->queue_id);
238 
239  /*
240  * Open this queue file. Skip files that we cannot open. Back off when
241  * the system appears to be running out of resources.
242  */
243  if ((message->fp = mail_queue_open(message->queue_name,
244  message->queue_id,
245  O_RDWR, 0)) == 0) {
246  if (errno != ENOENT)
247  msg_fatal("open %s %s: %m", message->queue_name, message->queue_id);
248  msg_warn("open %s %s: %m", message->queue_name, message->queue_id);
249  return (-1);
250  }
251  return (0);
252 }
253 
254 /* qmgr_message_oldstyle_scan - support for Postfix < 1.0 queue files */
255 
256 static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message)
257 {
258  VSTRING *buf;
259  long orig_offset, extra_offset;
260  int rec_type;
261  char *start;
262 
263  /*
264  * Initialize. No early returns or we have a memory leak.
265  */
266  buf = vstring_alloc(100);
267  if ((orig_offset = vstream_ftell(message->fp)) < 0)
268  msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
269 
270  /*
271  * Rewind to the very beginning to make sure we see all records.
272  */
273  if (vstream_fseek(message->fp, 0, SEEK_SET) < 0)
274  msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
275 
276  /*
277  * Scan through the old style queue file. Count the total number of
278  * recipients and find the data/extra sections offsets. Note that the new
279  * queue files require that data_size equals extra_offset - data_offset,
280  * so we set data_size to this as well and ignore the size record itself
281  * completely.
282  */
283  message->rcpt_unread = 0;
284  for (;;) {
285  rec_type = rec_get(message->fp, buf, 0);
286  if (rec_type <= 0)
287  /* Report missing end record later. */
288  break;
289  start = vstring_str(buf);
290  if (msg_verbose > 1)
291  msg_info("old-style scan record %c %s", rec_type, start);
292  if (rec_type == REC_TYPE_END)
293  break;
294  if (rec_type == REC_TYPE_DONE
295  || rec_type == REC_TYPE_RCPT
296  || rec_type == REC_TYPE_DRCP) {
297  message->rcpt_unread++;
298  continue;
299  }
300  if (rec_type == REC_TYPE_MESG) {
301  if (message->data_offset == 0) {
302  if ((message->data_offset = vstream_ftell(message->fp)) < 0)
303  msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
304  if ((extra_offset = atol(start)) <= message->data_offset)
305  msg_fatal("bad extra offset %s file %s",
306  start, VSTREAM_PATH(message->fp));
307  if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
308  msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
309  message->data_size = extra_offset - message->data_offset;
310  }
311  continue;
312  }
313  }
314 
315  /*
316  * Clean up.
317  */
318  if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0)
319  msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
320  vstring_free(buf);
321 
322  /*
323  * Sanity checks. Verify that all required information was found,
324  * including the queue file end marker.
325  */
326  if (message->data_offset == 0 || rec_type != REC_TYPE_END)
327  msg_fatal("%s: envelope records out of order", message->queue_id);
328 }
329 
330 /* qmgr_message_read - read envelope records */
331 
332 static int qmgr_message_read(QMGR_MESSAGE *message)
333 {
334  VSTRING *buf;
335  int rec_type;
336  long curr_offset;
337  long save_offset = message->rcpt_offset; /* save a flag */
338  int save_unread = message->rcpt_unread; /* save a count */
339  char *start;
340  int recipient_limit;
341  const char *error_text;
342  char *name;
343  char *value;
344  char *orig_rcpt = 0;
345  int count;
346  int dsn_notify = 0;
347  char *dsn_orcpt = 0;
348  int n;
349  int have_log_client_attr = 0;
350 
351  /*
352  * Initialize. No early returns or we have a memory leak.
353  */
354  buf = vstring_alloc(100);
355 
356  /*
357  * If we re-open this file, skip over on-file recipient records that we
358  * already looked at, and refill the in-core recipient address list.
359  *
360  * For the first time, the message recipient limit is calculated from the
361  * global recipient limit. This is to avoid reading little recipients
362  * when the active queue is near empty. When the queue becomes full, only
363  * the necessary amount is read in core. Such priming is necessary
364  * because there are no message jobs yet.
365  *
366  * For the next time, the recipient limit is based solely on the message
367  * jobs' positions in the job lists and/or job stacks.
368  */
369  if (message->rcpt_offset) {
370  if (message->rcpt_list.len)
371  msg_panic("%s: recipient list not empty on recipient reload",
372  message->queue_id);
373  if (vstream_fseek(message->fp, message->rcpt_offset, SEEK_SET) < 0)
374  msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
375  message->rcpt_offset = 0;
376  recipient_limit = message->rcpt_limit - message->rcpt_count;
377  } else {
378  recipient_limit = var_qmgr_rcpt_limit - qmgr_recipient_count;
379  if (recipient_limit < message->rcpt_limit)
380  recipient_limit = message->rcpt_limit;
381  }
382  /* Keep interrupt latency in check. */
383  if (recipient_limit > 5000)
384  recipient_limit = 5000;
385  if (recipient_limit <= 0)
386  msg_panic("%s: no recipient slots available", message->queue_id);
387  if (msg_verbose)
388  msg_info("%s: recipient limit %d", message->queue_id, recipient_limit);
389 
390  /*
391  * Read envelope records. XXX Rely on the front-end programs to enforce
392  * record size limits. Read up to recipient_limit recipients from the
393  * queue file, to protect against memory exhaustion. Recipient records
394  * may appear before or after the message content, so we keep reading
395  * from the queue file until we have enough recipients (rcpt_offset != 0)
396  * and until we know all the non-recipient information.
397  *
398  * Note that the total recipient count record is accurate only for fresh
399  * queue files. After some of the recipients are marked as done and the
400  * queue file is deferred, it can be used as upper bound estimate only.
401  * Fortunately, this poses no major problem on the scheduling algorithm,
402  * as the only impact is that the already deferred messages are not
403  * chosen by qmgr_job_candidate() as often as they could.
404  *
405  * On the first open, we must examine all non-recipient records.
406  *
407  * Optimization: when we know that recipient records are not mixed with
408  * non-recipient records, as is typical with mailing list mail, then we
409  * can avoid having to examine all the queue file records before we can
410  * start deliveries. This avoids some file system thrashing with huge
411  * mailing lists.
412  */
413  for (;;) {
414  if ((curr_offset = vstream_ftell(message->fp)) < 0)
415  msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
416  if (curr_offset == message->data_offset && curr_offset > 0) {
417  if (vstream_fseek(message->fp, message->data_size, SEEK_CUR) < 0)
418  msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
419  curr_offset += message->data_size;
420  }
421  rec_type = rec_get_raw(message->fp, buf, 0, REC_FLAG_NONE);
422  start = vstring_str(buf);
423  if (msg_verbose > 1)
424  msg_info("record %c %s", rec_type, start);
425  if (rec_type == REC_TYPE_PTR) {
426  if ((rec_type = rec_goto(message->fp, start)) == REC_TYPE_ERROR)
427  break;
428  /* Need to update curr_offset after pointer jump. */
429  continue;
430  }
431  if (rec_type <= 0) {
432  msg_warn("%s: message rejected: missing end record",
433  message->queue_id);
434  break;
435  }
436  if (rec_type == REC_TYPE_END) {
438  break;
439  }
440 
441  /*
442  * Map named attributes to pseudo record types, so that we don't have
443  * to pollute the queue file with records that are incompatible with
444  * past Postfix versions. Preferably, people should be able to back
445  * out from an upgrade without losing mail.
446  */
447  if (rec_type == REC_TYPE_ATTR) {
448  if ((error_text = split_nameval(start, &name, &value)) != 0) {
449  msg_warn("%s: ignoring bad attribute: %s: %.200s",
450  message->queue_id, error_text, start);
451  rec_type = REC_TYPE_ERROR;
452  break;
453  }
454  if ((n = rec_attr_map(name)) != 0) {
455  start = value;
456  rec_type = n;
457  }
458  }
459 
460  /*
461  * Process recipient records.
462  */
463  if (rec_type == REC_TYPE_RCPT) {
464  /* See also below for code setting orig_rcpt etc. */
465  if (message->rcpt_offset == 0) {
466  message->rcpt_unread--;
467  recipient_list_add(&message->rcpt_list, curr_offset,
468  dsn_orcpt ? dsn_orcpt : "",
469  dsn_notify ? dsn_notify : 0,
470  orig_rcpt ? orig_rcpt : "", start);
471  if (dsn_orcpt) {
472  myfree(dsn_orcpt);
473  dsn_orcpt = 0;
474  }
475  if (orig_rcpt) {
476  myfree(orig_rcpt);
477  orig_rcpt = 0;
478  }
479  if (dsn_notify)
480  dsn_notify = 0;
481  if (message->rcpt_list.len >= recipient_limit) {
482  if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
483  msg_fatal("vstream_ftell %s: %m",
484  VSTREAM_PATH(message->fp));
486  /* We already examined all non-recipient records. */
487  break;
489  /* Examine all remaining non-recipient records. */
490  continue;
491  /* Optimizations for "pure recipient" record sections. */
492  if (curr_offset > message->data_offset) {
493  /* We already examined all non-recipient records. */
495  break;
496  }
497  /* Examine non-recipient records in extracted segment. */
498  if (vstream_fseek(message->fp, message->data_offset
499  + message->data_size, SEEK_SET) < 0)
500  msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
501  continue;
502  }
503  }
504  continue;
505  }
506  if (rec_type == REC_TYPE_DONE || rec_type == REC_TYPE_DRCP) {
507  if (message->rcpt_offset == 0) {
508  message->rcpt_unread--;
509  if (dsn_orcpt) {
510  myfree(dsn_orcpt);
511  dsn_orcpt = 0;
512  }
513  if (orig_rcpt) {
514  myfree(orig_rcpt);
515  orig_rcpt = 0;
516  }
517  if (dsn_notify)
518  dsn_notify = 0;
519  }
520  continue;
521  }
522  if (rec_type == REC_TYPE_DSN_ORCPT) {
523  /* See also above for code clearing dsn_orcpt. */
524  if (dsn_orcpt != 0) {
525  msg_warn("%s: ignoring out-of-order DSN original recipient address <%.200s>",
526  message->queue_id, dsn_orcpt);
527  myfree(dsn_orcpt);
528  dsn_orcpt = 0;
529  }
530  if (message->rcpt_offset == 0)
531  dsn_orcpt = mystrdup(start);
532  continue;
533  }
534  if (rec_type == REC_TYPE_DSN_NOTIFY) {
535  /* See also above for code clearing dsn_notify. */
536  if (dsn_notify != 0) {
537  msg_warn("%s: ignoring out-of-order DSN notify flags <%d>",
538  message->queue_id, dsn_notify);
539  dsn_notify = 0;
540  }
541  if (message->rcpt_offset == 0) {
542  if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_NOTIFY_OK(n))
543  msg_warn("%s: ignoring malformed DSN notify flags <%.200s>",
544  message->queue_id, start);
545  else
546  dsn_notify = n;
547  continue;
548  }
549  }
550  if (rec_type == REC_TYPE_ORCP) {
551  /* See also above for code clearing orig_rcpt. */
552  if (orig_rcpt != 0) {
553  msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
554  message->queue_id, orig_rcpt);
555  myfree(orig_rcpt);
556  orig_rcpt = 0;
557  }
558  if (message->rcpt_offset == 0)
559  orig_rcpt = mystrdup(start);
560  continue;
561  }
562 
563  /*
564  * Process non-recipient records.
565  */
567  /* We already examined all non-recipient records. */
568  continue;
569  if (rec_type == REC_TYPE_SIZE) {
570  if (message->data_offset == 0) {
571  if ((count = sscanf(start, "%ld %ld %d %d %ld %d",
572  &message->data_size, &message->data_offset,
573  &message->rcpt_unread, &message->rflags,
574  &message->cont_length,
575  &message->smtputf8)) >= 3) {
576  /* Postfix >= 1.0 (a.k.a. 20010228). */
577  if (message->data_offset <= 0 || message->data_size <= 0) {
578  msg_warn("%s: invalid size record: %.100s",
579  message->queue_id, start);
580  rec_type = REC_TYPE_ERROR;
581  break;
582  }
583  if (message->rflags & ~QMGR_READ_FLAG_USER) {
584  msg_warn("%s: invalid flags in size record: %.100s",
585  message->queue_id, start);
586  rec_type = REC_TYPE_ERROR;
587  break;
588  }
589  } else if (count == 1) {
590  /* Postfix < 1.0 (a.k.a. 20010228). */
591  qmgr_message_oldstyle_scan(message);
592  } else {
593  /* Can't happen. */
594  msg_warn("%s: message rejected: weird size record",
595  message->queue_id);
596  rec_type = REC_TYPE_ERROR;
597  break;
598  }
599  }
600  /* Postfix < 2.4 compatibility. */
601  if (message->cont_length == 0) {
602  message->cont_length = message->data_size;
603  } else if (message->cont_length < 0) {
604  msg_warn("%s: invalid size record: %.100s",
605  message->queue_id, start);
606  rec_type = REC_TYPE_ERROR;
607  break;
608  }
609  continue;
610  }
611  if (rec_type == REC_TYPE_TIME) {
612  if (message->arrival_time.tv_sec == 0)
613  REC_TYPE_TIME_SCAN(start, message->arrival_time);
614  continue;
615  }
616  if (rec_type == REC_TYPE_CTIME) {
617  if (message->create_time == 0)
618  message->create_time = atol(start);
619  continue;
620  }
621  if (rec_type == REC_TYPE_FILT) {
622  if (message->filter_xport != 0)
623  myfree(message->filter_xport);
624  message->filter_xport = mystrdup(start);
625  continue;
626  }
627  if (rec_type == REC_TYPE_INSP) {
628  if (message->inspect_xport != 0)
629  myfree(message->inspect_xport);
630  message->inspect_xport = mystrdup(start);
631  continue;
632  }
633  if (rec_type == REC_TYPE_RDR) {
634  if (message->redirect_addr != 0)
635  myfree(message->redirect_addr);
636  message->redirect_addr = mystrdup(start);
637  continue;
638  }
639  if (rec_type == REC_TYPE_FROM) {
640  if (message->sender == 0) {
641  message->sender = mystrdup(start);
642  opened(message->queue_id, message->sender,
643  message->cont_length, message->rcpt_unread,
644  "queue %s", message->queue_name);
645  }
646  continue;
647  }
648  if (rec_type == REC_TYPE_DSN_ENVID) {
649  /* Allow Milter override. */
650  if (message->dsn_envid != 0)
651  myfree(message->dsn_envid);
652  message->dsn_envid = mystrdup(start);
653  }
654  if (rec_type == REC_TYPE_DSN_RET) {
655  /* Allow Milter override. */
656  if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_RET_OK(n))
657  msg_warn("%s: ignoring malformed DSN RET flags in queue file record:%.100s",
658  message->queue_id, start);
659  else
660  message->dsn_ret = n;
661  }
662  if (rec_type == REC_TYPE_ATTR) {
663  /* Allow extra segment to override envelope segment info. */
664  if (strcmp(name, MAIL_ATTR_ENCODING) == 0) {
665  if (message->encoding != 0)
666  myfree(message->encoding);
667  message->encoding = mystrdup(value);
668  }
669 
670  /*
671  * Backwards compatibility. Before Postfix 2.3, the logging
672  * attributes were called client_name, etc. Now they are called
673  * log_client_name. etc., and client_name is used for the actual
674  * client information. To support old queue files we accept both
675  * names for the purpose of logging; the new name overrides the
676  * old one.
677  *
678  * XXX Do not use the "legacy" client_name etc. attribute values for
679  * initializing the logging attributes, when this file already
680  * contains the "modern" log_client_name etc. logging attributes.
681  * Otherwise, logging attributes that are not present in the
682  * queue file would be set with information from the real client.
683  */
684  else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_NAME) == 0) {
685  if (have_log_client_attr == 0 && message->client_name == 0)
686  message->client_name = mystrdup(value);
687  } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_ADDR) == 0) {
688  if (have_log_client_attr == 0 && message->client_addr == 0)
689  message->client_addr = mystrdup(value);
690  } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_PORT) == 0) {
691  if (have_log_client_attr == 0 && message->client_port == 0)
692  message->client_port = mystrdup(value);
693  } else if (strcmp(name, MAIL_ATTR_ACT_PROTO_NAME) == 0) {
694  if (have_log_client_attr == 0 && message->client_proto == 0)
695  message->client_proto = mystrdup(value);
696  } else if (strcmp(name, MAIL_ATTR_ACT_HELO_NAME) == 0) {
697  if (have_log_client_attr == 0 && message->client_helo == 0)
698  message->client_helo = mystrdup(value);
699  }
700  /* Original client attributes. */
701  else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_NAME) == 0) {
702  if (message->client_name != 0)
703  myfree(message->client_name);
704  message->client_name = mystrdup(value);
705  have_log_client_attr = 1;
706  } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_ADDR) == 0) {
707  if (message->client_addr != 0)
708  myfree(message->client_addr);
709  message->client_addr = mystrdup(value);
710  have_log_client_attr = 1;
711  } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_PORT) == 0) {
712  if (message->client_port != 0)
713  myfree(message->client_port);
714  message->client_port = mystrdup(value);
715  have_log_client_attr = 1;
716  } else if (strcmp(name, MAIL_ATTR_LOG_PROTO_NAME) == 0) {
717  if (message->client_proto != 0)
718  myfree(message->client_proto);
719  message->client_proto = mystrdup(value);
720  have_log_client_attr = 1;
721  } else if (strcmp(name, MAIL_ATTR_LOG_HELO_NAME) == 0) {
722  if (message->client_helo != 0)
723  myfree(message->client_helo);
724  message->client_helo = mystrdup(value);
725  have_log_client_attr = 1;
726  } else if (strcmp(name, MAIL_ATTR_SASL_METHOD) == 0) {
727  if (message->sasl_method == 0)
728  message->sasl_method = mystrdup(value);
729  else
730  msg_warn("%s: ignoring multiple %s attribute: %s",
731  message->queue_id, MAIL_ATTR_SASL_METHOD, value);
732  } else if (strcmp(name, MAIL_ATTR_SASL_USERNAME) == 0) {
733  if (message->sasl_username == 0)
734  message->sasl_username = mystrdup(value);
735  else
736  msg_warn("%s: ignoring multiple %s attribute: %s",
737  message->queue_id, MAIL_ATTR_SASL_USERNAME, value);
738  } else if (strcmp(name, MAIL_ATTR_SASL_SENDER) == 0) {
739  if (message->sasl_sender == 0)
740  message->sasl_sender = mystrdup(value);
741  else
742  msg_warn("%s: ignoring multiple %s attribute: %s",
743  message->queue_id, MAIL_ATTR_SASL_SENDER, value);
744  } else if (strcmp(name, MAIL_ATTR_LOG_IDENT) == 0) {
745  if (message->log_ident == 0)
746  message->log_ident = mystrdup(value);
747  else
748  msg_warn("%s: ignoring multiple %s attribute: %s",
749  message->queue_id, MAIL_ATTR_LOG_IDENT, value);
750  } else if (strcmp(name, MAIL_ATTR_RWR_CONTEXT) == 0) {
751  if (message->rewrite_context == 0)
752  message->rewrite_context = mystrdup(value);
753  else
754  msg_warn("%s: ignoring multiple %s attribute: %s",
755  message->queue_id, MAIL_ATTR_RWR_CONTEXT, value);
756  }
757 
758  /*
759  * Optional tracing flags (verify, sendmail -v, sendmail -bv).
760  * This record is killed after a trace logfile report is sent and
761  * after the logfile is deleted.
762  */
763  else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
764  if (message->tflags == 0) {
765  message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
766  if (message->tflags == DEL_REQ_FLAG_RECORD)
767  message->tflags_offset = curr_offset;
768  else
769  message->tflags_offset = 0;
770  if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) != 0)
772  }
773  }
774  continue;
775  }
776  if (rec_type == REC_TYPE_WARN) {
777  if (message->warn_offset == 0) {
778  message->warn_offset = curr_offset;
779  REC_TYPE_WARN_SCAN(start, message->warn_time);
780  }
781  continue;
782  }
783  if (rec_type == REC_TYPE_VERP) {
784  if (message->verp_delims == 0) {
785  if (message->sender == 0 || message->sender[0] == 0) {
786  msg_warn("%s: ignoring VERP request for null sender",
787  message->queue_id);
788  } else if (verp_delims_verify(start) != 0) {
789  msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
790  message->queue_id, start);
791  } else {
792  if (msg_verbose)
793  msg_info("%s: enabling VERP for sender \"%.100s\"",
794  message->queue_id, message->sender);
795  message->single_rcpt = 1;
796  message->verp_delims = mystrdup(start);
797  }
798  }
799  continue;
800  }
801  }
802 
803  /*
804  * Grr.
805  */
806  if (dsn_orcpt != 0) {
807  if (rec_type > 0)
808  msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
809  message->queue_id, dsn_orcpt);
810  myfree(dsn_orcpt);
811  }
812  if (orig_rcpt != 0) {
813  if (rec_type > 0)
814  msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
815  message->queue_id, orig_rcpt);
816  myfree(orig_rcpt);
817  }
818 
819  /*
820  * After sending a "delayed" warning, request sender notification when
821  * message delivery is completed. While "mail delayed" notifications are
822  * bad enough because they multiply the amount of email traffic, "delay
823  * cleared" notifications are even worse because they come in a sudden
824  * burst when the queue drains after a network outage.
825  */
826  if (var_dsn_delay_cleared && message->warn_time < 0)
827  message->tflags |= DEL_REQ_FLAG_REC_DLY_SENT;
828 
829  /*
830  * Remember when we have read the last recipient batch. Note that we do
831  * it here after reading as reading might have used considerable amount
832  * of time.
833  */
834  message->refill_time = sane_time();
835 
836  /*
837  * Avoid clumsiness elsewhere in the program. When sending data across an
838  * IPC channel, sending an empty string is more convenient than sending a
839  * null pointer.
840  */
841  if (message->dsn_envid == 0)
842  message->dsn_envid = mystrdup("");
843  if (message->encoding == 0)
845  if (message->client_name == 0)
846  message->client_name = mystrdup("");
847  if (message->client_addr == 0)
848  message->client_addr = mystrdup("");
849  if (message->client_port == 0)
850  message->client_port = mystrdup("");
851  if (message->client_proto == 0)
852  message->client_proto = mystrdup("");
853  if (message->client_helo == 0)
854  message->client_helo = mystrdup("");
855  if (message->sasl_method == 0)
856  message->sasl_method = mystrdup("");
857  if (message->sasl_username == 0)
858  message->sasl_username = mystrdup("");
859  if (message->sasl_sender == 0)
860  message->sasl_sender = mystrdup("");
861  if (message->log_ident == 0)
862  message->log_ident = mystrdup("");
863  if (message->rewrite_context == 0)
865  /* Postfix < 2.3 compatibility. */
866  if (message->create_time == 0)
867  message->create_time = message->arrival_time.tv_sec;
868 
869  /*
870  * Clean up.
871  */
872  vstring_free(buf);
873 
874  /*
875  * Sanity checks. Verify that all required information was found,
876  * including the queue file end marker.
877  */
878  if (message->rcpt_unread < 0
879  || (message->rcpt_offset == 0 && message->rcpt_unread != 0)) {
880  msg_warn("%s: rcpt count mismatch (%d)",
881  message->queue_id, message->rcpt_unread);
882  message->rcpt_unread = 0;
883  }
884  if (rec_type <= 0) {
885  /* Already logged warning. */
886  } else if (message->arrival_time.tv_sec == 0) {
887  msg_warn("%s: message rejected: missing arrival time record",
888  message->queue_id);
889  } else if (message->sender == 0) {
890  msg_warn("%s: message rejected: missing sender record",
891  message->queue_id);
892  } else if (message->data_offset == 0) {
893  msg_warn("%s: message rejected: missing size record",
894  message->queue_id);
895  } else {
896  return (0);
897  }
898  message->rcpt_offset = save_offset; /* restore flag */
899  message->rcpt_unread = save_unread; /* restore count */
900  recipient_list_free(&message->rcpt_list);
902  return (-1);
903 }
904 
905 /* qmgr_message_update_warn - update the time of next delay warning */
906 
908 {
909 
910  /*
911  * After the "mail delayed" warning, optionally send a "delay cleared"
912  * notification.
913  */
914  if (qmgr_message_open(message)
915  || vstream_fseek(message->fp, message->warn_offset, SEEK_SET) < 0
917  REC_TYPE_WARN_ARG(-1)) < 0
918  || vstream_fflush(message->fp))
919  msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
920  qmgr_message_close(message);
921 }
922 
923 /* qmgr_message_kill_record - mark one message record as killed */
924 
925 void qmgr_message_kill_record(QMGR_MESSAGE *message, long offset)
926 {
927  if (offset <= 0)
928  msg_panic("qmgr_message_kill_record: bad offset 0x%lx", offset);
929  if (qmgr_message_open(message)
930  || rec_put_type(message->fp, REC_TYPE_KILL, offset) < 0
931  || vstream_fflush(message->fp))
932  msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
933  qmgr_message_close(message);
934 }
935 
936 /* qmgr_message_sort_compare - compare recipient information */
937 
938 static int qmgr_message_sort_compare(const void *p1, const void *p2)
939 {
940  RECIPIENT *rcpt1 = (RECIPIENT *) p1;
941  RECIPIENT *rcpt2 = (RECIPIENT *) p2;
942  QMGR_QUEUE *queue1;
943  QMGR_QUEUE *queue2;
944  char *at1;
945  char *at2;
946  int result;
947 
948  /*
949  * Compare most significant to least significant recipient attributes.
950  * The comparison function must be transitive, so NULL values need to be
951  * assigned an ordinal (we set NULL last).
952  */
953 
954  queue1 = rcpt1->u.queue;
955  queue2 = rcpt2->u.queue;
956  if (queue1 != 0 && queue2 == 0)
957  return (-1);
958  if (queue1 == 0 && queue2 != 0)
959  return (1);
960  if (queue1 != 0 && queue2 != 0) {
961 
962  /*
963  * Compare message transport.
964  */
965  if ((result = strcmp(queue1->transport->name,
966  queue2->transport->name)) != 0)
967  return (result);
968 
969  /*
970  * Compare queue name (nexthop or recipient@nexthop).
971  */
972  if ((result = strcmp(queue1->name, queue2->name)) != 0)
973  return (result);
974  }
975 
976  /*
977  * Compare recipient domain.
978  */
979  at1 = strrchr(rcpt1->address, '@');
980  at2 = strrchr(rcpt2->address, '@');
981  if (at1 == 0 && at2 != 0)
982  return (1);
983  if (at1 != 0 && at2 == 0)
984  return (-1);
985  if (at1 != 0 && at2 != 0
986  && (result = strcasecmp_utf8(at1, at2)) != 0)
987  return (result);
988 
989  /*
990  * Compare recipient address.
991  */
992  return (strcmp(rcpt1->address, rcpt2->address));
993 }
994 
995 /* qmgr_message_sort - sort message recipient addresses by domain */
996 
997 static void qmgr_message_sort(QMGR_MESSAGE *message)
998 {
999  qsort((void *) message->rcpt_list.info, message->rcpt_list.len,
1000  sizeof(message->rcpt_list.info[0]), qmgr_message_sort_compare);
1001  if (msg_verbose) {
1002  RECIPIENT_LIST list = message->rcpt_list;
1003  RECIPIENT *rcpt;
1004 
1005  msg_info("start sorted recipient list");
1006  for (rcpt = list.info; rcpt < list.info + list.len; rcpt++)
1007  msg_info("qmgr_message_sort: %s", rcpt->address);
1008  msg_info("end sorted recipient list");
1009  }
1010 }
1011 
1012 /* qmgr_resolve_one - resolve or skip one recipient */
1013 
1014 static int qmgr_resolve_one(QMGR_MESSAGE *message, RECIPIENT *recipient,
1015  const char *addr, RESOLVE_REPLY *reply)
1016 {
1017 #define QMGR_REDIRECT(rp, tp, np) do { \
1018  (rp)->flags = 0; \
1019  vstring_strcpy((rp)->transport, (tp)); \
1020  vstring_strcpy((rp)->nexthop, (np)); \
1021  } while (0)
1022 
1023  if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) == 0)
1024  resolve_clnt_query_from(message->sender, addr, reply);
1025  else
1026  resolve_clnt_verify_from(message->sender, addr, reply);
1027  if (reply->flags & RESOLVE_FLAG_FAIL) {
1029  "4.3.0 address resolver failure");
1030  return (0);
1031  } else if (reply->flags & RESOLVE_FLAG_ERROR) {
1033  "5.1.3 bad address syntax");
1034  return (0);
1035  } else {
1036  return (0);
1037  }
1038 }
1039 
1040 /* qmgr_message_resolve - resolve recipients */
1041 
1042 static void qmgr_message_resolve(QMGR_MESSAGE *message)
1043 {
1044  static ARGV *defer_xport_argv;
1045  RECIPIENT_LIST list = message->rcpt_list;
1046  RECIPIENT *recipient;
1047  QMGR_TRANSPORT *transport = 0;
1048  QMGR_QUEUE *queue = 0;
1049  RESOLVE_REPLY reply;
1050  VSTRING *queue_name;
1051  char *at;
1052  char **cpp;
1053  char *nexthop;
1054  ssize_t len;
1055  int status;
1056  DSN dsn;
1057  MSG_STATS stats;
1058  DSN *saved_dsn;
1059 
1060 #define STREQ(x,y) (strcmp(x,y) == 0)
1061 #define STR vstring_str
1062 #define LEN VSTRING_LEN
1063 
1064  resolve_clnt_init(&reply);
1065  queue_name = vstring_alloc(1);
1066  for (recipient = list.info; recipient < list.info + list.len; recipient++) {
1067 
1068  /*
1069  * Redirect overrides all else. But only once (per entire message).
1070  * For consistency with the remainder of Postfix, rewrite the address
1071  * to canonical form before resolving it.
1072  */
1073  if (message->redirect_addr) {
1074  if (recipient > list.info) {
1075  recipient->u.queue = 0;
1076  continue;
1077  }
1078  message->rcpt_offset = 0;
1079  message->rcpt_unread = 0;
1080 
1082  reply.recipient);
1083  RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1084  if (qmgr_resolve_one(message, recipient,
1085  recipient->address, &reply) < 0)
1086  continue;
1087  if (!STREQ(recipient->address, STR(reply.recipient)))
1088  RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1089  }
1090 
1091  /*
1092  * Content filtering overrides the address resolver.
1093  *
1094  * XXX Bypass content_filter inspection for user-generated probes
1095  * (sendmail -bv). MTA-generated probes never have the "please filter
1096  * me" bits turned on, but we handle them here anyway for the sake of
1097  * future proofing.
1098  */
1099 #define FILTER_WITHOUT_NEXTHOP(filter, next) \
1100  (((next) = split_at((filter), ':')) == 0 || *(next) == 0)
1101 
1102 #define RCPT_WITHOUT_DOMAIN(rcpt, next) \
1103  ((next = strrchr(rcpt, '@')) == 0 || *++(next) == 0)
1104 
1105  else if (message->filter_xport
1106  && (message->tflags & DEL_REQ_TRACE_ONLY_MASK) == 0) {
1107  reply.flags = 0;
1108  vstring_strcpy(reply.transport, message->filter_xport);
1109  if (FILTER_WITHOUT_NEXTHOP(STR(reply.transport), nexthop)
1110  && *(nexthop = var_def_filter_nexthop) == 0
1111  && RCPT_WITHOUT_DOMAIN(recipient->address, nexthop))
1112  nexthop = var_myhostname;
1113  vstring_strcpy(reply.nexthop, nexthop);
1114  vstring_strcpy(reply.recipient, recipient->address);
1115  }
1116 
1117  /*
1118  * Resolve the destination to (transport, nexthop, address). The
1119  * result address may differ from the one specified by the sender.
1120  */
1121  else {
1122  if (qmgr_resolve_one(message, recipient,
1123  recipient->address, &reply) < 0)
1124  continue;
1125  if (!STREQ(recipient->address, STR(reply.recipient)))
1126  RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1127  }
1128 
1129  /*
1130  * Bounce null recipients. This should never happen, but is most
1131  * likely the result of a fault in a different program, so aborting
1132  * the queue manager process does not help.
1133  */
1134  if (recipient->address[0] == 0) {
1136  "5.1.3 null recipient address");
1137  }
1138 
1139  /*
1140  * Discard mail to the local double bounce address here, so this
1141  * system can run without a local delivery agent. They'd still have
1142  * to configure something for mail directed to the local postmaster,
1143  * though, but that is an RFC requirement anyway.
1144  *
1145  * XXX This lookup should be done in the resolver, and the mail should
1146  * be directed to a general-purpose null delivery agent.
1147  */
1148  if (reply.flags & RESOLVE_CLASS_LOCAL) {
1149  at = strrchr(STR(reply.recipient), '@');
1150  len = (at ? (at - STR(reply.recipient))
1151  : strlen(STR(reply.recipient)));
1152  if (strncasecmp_utf8(STR(reply.recipient),
1153  var_double_bounce_sender, len) == 0
1154  && !var_double_bounce_sender[len]) {
1155  status = sent(message->tflags, message->queue_id,
1156  QMGR_MSG_STATS(&stats, message), recipient,
1157  "none", DSN_SIMPLE(&dsn, "2.0.0",
1158  "undeliverable postmaster notification discarded"));
1159  if (status == 0) {
1160  deliver_completed(message->fp, recipient->offset);
1161 #if 0
1162  /* It's the default verification probe sender address. */
1163  msg_warn("%s: undeliverable postmaster notification discarded",
1164  message->queue_id);
1165 #endif
1166  } else
1167  message->flags |= status;
1168  continue;
1169  }
1170  }
1171 
1172  /*
1173  * Optionally defer deliveries over specific transports, unless the
1174  * restriction is lifted temporarily.
1175  */
1176  if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) {
1177  if (defer_xport_argv == 0)
1178  defer_xport_argv = argv_split(var_defer_xports, CHARS_COMMA_SP);
1179  for (cpp = defer_xport_argv->argv; *cpp; cpp++)
1180  if (strcmp(*cpp, STR(reply.transport)) == 0)
1181  break;
1182  if (*cpp) {
1184  "4.3.2 deferred transport");
1185  }
1186  }
1187 
1188  /*
1189  * Safety: defer excess address verification requests.
1190  */
1191  if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) != 0
1194  "4.3.2 Too many address verification requests");
1195 
1196  /*
1197  * Look up or instantiate the proper transport.
1198  */
1199  if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
1200  if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
1201  transport = qmgr_transport_create(STR(reply.transport));
1202  queue = 0;
1203  }
1204 
1205  /*
1206  * This message is being flushed. If need-be unthrottle the
1207  * transport.
1208  */
1209  if ((message->qflags & QMGR_FLUSH_EACH) != 0
1210  && QMGR_TRANSPORT_THROTTLED(transport))
1211  qmgr_transport_unthrottle(transport);
1212 
1213  /*
1214  * This transport is dead. Defer delivery to this recipient.
1215  */
1216  if (QMGR_TRANSPORT_THROTTLED(transport)) {
1217  saved_dsn = transport->dsn;
1218  if ((transport = qmgr_error_transport(MAIL_SERVICE_RETRY)) != 0) {
1219  nexthop = qmgr_error_nexthop(saved_dsn);
1220  vstring_strcpy(reply.nexthop, nexthop);
1221  myfree(nexthop);
1222  queue = 0;
1223  } else {
1224  qmgr_defer_recipient(message, recipient, saved_dsn);
1225  continue;
1226  }
1227  }
1228 
1229  /*
1230  * The nexthop destination provides the default name for the
1231  * per-destination queue. When the delivery agent accepts only one
1232  * recipient per delivery, give each recipient its own queue, so that
1233  * deliveries to different recipients of the same message can happen
1234  * in parallel, and so that we can enforce per-recipient concurrency
1235  * limits and prevent one recipient from tying up all the delivery
1236  * agent resources. We use recipient@nexthop as queue name rather
1237  * than the actual recipient domain name, so that one recipient in
1238  * multiple equivalent domains cannot evade the per-recipient
1239  * concurrency limit. Split the address on the recipient delimiter if
1240  * one is defined, so that extended addresses don't get extra
1241  * delivery slots.
1242  *
1243  * Fold the result to lower case so that we don't have multiple queues
1244  * for the same name.
1245  *
1246  * Important! All recipients in a queue must have the same nexthop
1247  * value. It is OK to have multiple queues with the same nexthop
1248  * value, but only when those queues are named after recipients.
1249  *
1250  * The single-recipient code below was written for local(8) like
1251  * delivery agents, and assumes that all domains that deliver to the
1252  * same (transport + nexthop) are aliases for $nexthop. Delivery
1253  * concurrency is changed from per-domain into per-recipient, by
1254  * changing the queue name from nexthop into localpart@nexthop.
1255  *
1256  * XXX This assumption is incorrect when different destinations share
1257  * the same (transport + nexthop). In reality, such transports are
1258  * rarely configured to use single-recipient deliveries. The fix is
1259  * to decouple the per-destination recipient limit from the
1260  * per-destination concurrency.
1261  */
1262  vstring_strcpy(queue_name, STR(reply.nexthop));
1263  if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
1264  && strcmp(transport->name, MAIL_SERVICE_RETRY) != 0
1265  && transport->recipient_limit == 1) {
1266  /* Copy the recipient localpart. */
1267  at = strrchr(STR(reply.recipient), '@');
1268  len = (at ? (at - STR(reply.recipient))
1269  : strlen(STR(reply.recipient)));
1270  vstring_strncpy(queue_name, STR(reply.recipient), len);
1271  /* Remove the address extension from the recipient localpart. */
1272  if (*var_rcpt_delim && split_addr(STR(queue_name), var_rcpt_delim))
1273  vstring_truncate(queue_name, strlen(STR(queue_name)));
1274  /* Assume the recipient domain is equivalent to nexthop. */
1275  vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
1276  }
1277  lowercase(STR(queue_name));
1278 
1279  /*
1280  * This transport is alive. Find or instantiate a queue for this
1281  * recipient.
1282  */
1283  if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
1284  if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
1285  queue = qmgr_queue_create(transport, STR(queue_name),
1286  STR(reply.nexthop));
1287  }
1288 
1289  /*
1290  * This message is being flushed. If need-be unthrottle the queue.
1291  */
1292  if ((message->qflags & QMGR_FLUSH_EACH) != 0
1293  && QMGR_QUEUE_THROTTLED(queue))
1294  qmgr_queue_unthrottle(queue);
1295 
1296  /*
1297  * This queue is dead. Defer delivery to this recipient.
1298  */
1299  if (QMGR_QUEUE_THROTTLED(queue)) {
1300  saved_dsn = queue->dsn;
1301  if ((queue = qmgr_error_queue(MAIL_SERVICE_RETRY, saved_dsn)) == 0) {
1302  qmgr_defer_recipient(message, recipient, saved_dsn);
1303  continue;
1304  }
1305  }
1306 
1307  /*
1308  * This queue is alive. Bind this recipient to this queue instance.
1309  */
1310  recipient->u.queue = queue;
1311  }
1312  resolve_clnt_free(&reply);
1313  vstring_free(queue_name);
1314 }
1315 
1316 /* qmgr_message_assign - assign recipients to specific delivery requests */
1317 
1318 static void qmgr_message_assign(QMGR_MESSAGE *message)
1319 {
1320  RECIPIENT_LIST list = message->rcpt_list;
1321  RECIPIENT *recipient;
1322  QMGR_ENTRY *entry = 0;
1323  QMGR_QUEUE *queue;
1324  QMGR_JOB *job = 0;
1325  QMGR_PEER *peer = 0;
1326 
1327  /*
1328  * Try to bundle as many recipients in a delivery request as we can. When
1329  * the recipient resolves to the same site and transport as an existing
1330  * recipient, do not create a new queue entry, just move that recipient
1331  * to the recipient list of the existing queue entry. All this provided
1332  * that we do not exceed the transport-specific limit on the number of
1333  * recipients per transaction.
1334  */
1335 #define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
1336 
1337  for (recipient = list.info; recipient < list.info + list.len; recipient++) {
1338 
1339  /*
1340  * Skip recipients with a dead transport or destination.
1341  */
1342  if ((queue = recipient->u.queue) == 0)
1343  continue;
1344 
1345  /*
1346  * Lookup or instantiate the message job if necessary.
1347  */
1348  if (job == 0 || queue->transport != job->transport) {
1349  job = qmgr_job_obtain(message, queue->transport);
1350  peer = 0;
1351  }
1352 
1353  /*
1354  * Lookup or instantiate job peer if necessary.
1355  */
1356  if (peer == 0 || queue != peer->queue)
1357  peer = qmgr_peer_obtain(job, queue);
1358 
1359  /*
1360  * Lookup old or instantiate new recipient entry. We try to reuse the
1361  * last existing entry whenever the recipient limit permits.
1362  */
1363  entry = peer->entry_list.prev;
1364  if (message->single_rcpt || entry == 0
1365  || !LIMIT_OK(queue->transport->recipient_limit, entry->rcpt_list.len))
1366  entry = qmgr_entry_create(peer, message);
1367 
1368  /*
1369  * Add the recipient to the current entry and increase all those
1370  * recipient counters accordingly.
1371  */
1372  recipient_list_add(&entry->rcpt_list, recipient->offset,
1373  recipient->dsn_orcpt, recipient->dsn_notify,
1374  recipient->orig_addr, recipient->address);
1375  job->rcpt_count++;
1376  message->rcpt_count++;
1377  qmgr_recipient_count++;
1378  }
1379 
1380  /*
1381  * Release the message recipient list and reinitialize it for the next
1382  * time.
1383  */
1384  recipient_list_free(&message->rcpt_list);
1386 
1387  /*
1388  * Note that even if qmgr_job_obtain() reset the job candidate cache of
1389  * all transports to which we assigned new recipients, this message may
1390  * have other jobs which we didn't touch at all this time. But the number
1391  * of unread recipients affecting the candidate selection might have
1392  * changed considerably, so we must invalidate the caches if it might be
1393  * of some use.
1394  */
1395  for (job = message->job_list.next; job; job = job->message_peers.next)
1396  if (job->selected_entries < job->read_entries
1397  && job->blocker_tag != job->transport->blocker_tag)
1399 }
1400 
1401 /* qmgr_message_move_limits - recycle unused recipient slots */
1402 
1403 static void qmgr_message_move_limits(QMGR_MESSAGE *message)
1404 {
1405  QMGR_JOB *job;
1406 
1407  for (job = message->job_list.next; job; job = job->message_peers.next)
1408  qmgr_job_move_limits(job);
1409 }
1410 
1411 /* qmgr_message_free - release memory for in-core message structure */
1412 
1414 {
1415  QMGR_JOB *job;
1416 
1417  if (message->refcount != 0)
1418  msg_panic("qmgr_message_free: reference len: %d", message->refcount);
1419  if (message->fp)
1420  msg_panic("qmgr_message_free: queue file is open");
1421  while ((job = message->job_list.next) != 0)
1422  qmgr_job_free(job);
1423  myfree(message->queue_id);
1424  myfree(message->queue_name);
1425  if (message->dsn_envid)
1426  myfree(message->dsn_envid);
1427  if (message->encoding)
1428  myfree(message->encoding);
1429  if (message->sender)
1430  myfree(message->sender);
1431  if (message->verp_delims)
1432  myfree(message->verp_delims);
1433  if (message->filter_xport)
1434  myfree(message->filter_xport);
1435  if (message->inspect_xport)
1436  myfree(message->inspect_xport);
1437  if (message->redirect_addr)
1438  myfree(message->redirect_addr);
1439  if (message->client_name)
1440  myfree(message->client_name);
1441  if (message->client_addr)
1442  myfree(message->client_addr);
1443  if (message->client_port)
1444  myfree(message->client_port);
1445  if (message->client_proto)
1446  myfree(message->client_proto);
1447  if (message->client_helo)
1448  myfree(message->client_helo);
1449  if (message->sasl_method)
1450  myfree(message->sasl_method);
1451  if (message->sasl_username)
1452  myfree(message->sasl_username);
1453  if (message->sasl_sender)
1454  myfree(message->sasl_sender);
1455  if (message->log_ident)
1456  myfree(message->log_ident);
1457  if (message->rewrite_context)
1458  myfree(message->rewrite_context);
1459  recipient_list_free(&message->rcpt_list);
1461  if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) != 0)
1463  myfree((void *) message);
1464 }
1465 
1466 /* qmgr_message_alloc - create in-core message structure */
1467 
1468 QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id,
1469  int qflags, mode_t mode)
1470 {
1471  const char *myname = "qmgr_message_alloc";
1472  QMGR_MESSAGE *message;
1473 
1474  if (msg_verbose)
1475  msg_info("%s: %s %s", myname, queue_name, queue_id);
1476 
1477  /*
1478  * Create an in-core message structure.
1479  */
1480  message = qmgr_message_create(queue_name, queue_id, qflags);
1481 
1482  /*
1483  * Extract message envelope information: time of arrival, sender address,
1484  * recipient addresses. Skip files with malformed envelope information.
1485  */
1486 #define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
1487 
1488  if (qmgr_message_open(message) < 0) {
1489  qmgr_message_free(message);
1490  return (0);
1491  }
1492  if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) {
1493  msg_info("%s: skipped, still being delivered", queue_id);
1494  qmgr_message_close(message);
1495  qmgr_message_free(message);
1496  return (QMGR_MESSAGE_LOCKED);
1497  }
1498  if (qmgr_message_read(message) < 0) {
1499  qmgr_message_close(message);
1500  qmgr_message_free(message);
1501  return (0);
1502  } else {
1503 
1504  /*
1505  * We have validated the queue file content, so it is safe to modify
1506  * the file properties now.
1507  */
1508  if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0)
1509  msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp));
1510 
1511  /*
1512  * Reset the defer log. This code should not be here, but we must
1513  * reset the defer log *after* acquiring the exclusive lock on the
1514  * queue file and *before* resolving new recipients. Since all those
1515  * operations are encapsulated so nicely by this routine, the defer
1516  * log reset has to be done here as well.
1517  *
1518  * Note: it is safe to remove the defer logfile from a previous queue
1519  * run of this queue file, because the defer log contains information
1520  * about recipients that still exist in this queue file.
1521  */
1522  if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
1523  msg_fatal("%s: %s: remove %s %s: %m", myname,
1524  queue_id, MAIL_QUEUE_DEFER, queue_id);
1525  qmgr_message_sort(message);
1526  qmgr_message_resolve(message);
1527  qmgr_message_sort(message);
1528  qmgr_message_assign(message);
1529  qmgr_message_close(message);
1530  if (message->rcpt_offset == 0)
1531  qmgr_message_move_limits(message);
1532  return (message);
1533  }
1534 }
1535 
1536 /* qmgr_message_realloc - refresh in-core message structure */
1537 
1539 {
1540  const char *myname = "qmgr_message_realloc";
1541 
1542  /*
1543  * Sanity checks.
1544  */
1545  if (message->rcpt_offset <= 0)
1546  msg_panic("%s: invalid offset: %ld", myname, message->rcpt_offset);
1547  if (msg_verbose)
1548  msg_info("%s: %s %s offset %ld", myname, message->queue_name,
1549  message->queue_id, message->rcpt_offset);
1550 
1551  /*
1552  * Extract recipient addresses. Skip files with malformed envelope
1553  * information.
1554  */
1555  if (qmgr_message_open(message) < 0)
1556  return (0);
1557  if (qmgr_message_read(message) < 0) {
1558  qmgr_message_close(message);
1559  return (0);
1560  } else {
1561  qmgr_message_sort(message);
1562  qmgr_message_resolve(message);
1563  qmgr_message_sort(message);
1564  qmgr_message_assign(message);
1565  qmgr_message_close(message);
1566  if (message->rcpt_offset == 0)
1567  qmgr_message_move_limits(message);
1568  return (message);
1569  }
1570 }
int msg_verbose
Definition: msg.c:177
#define REC_TYPE_FILT
Definition: rec_type.h:42
int blocker_tag
Definition: qmgr.h:419
void qmgr_message_free(QMGR_MESSAGE *message)
time_t sane_time(void)
Definition: sane_time.c:61
const char * orig_addr
QMGR_QUEUE * qmgr_error_queue(const char *, DSN *)
Definition: qmgr_error.c:85
#define MAIL_ATTR_ACT_HELO_NAME
Definition: mail_proto.h:219
#define RESOLVE_FLAG_FAIL
Definition: resolve_clnt.h:28
int rec_put_type(VSTREAM *stream, int type, off_t offset)
Definition: record.c:175
void myfree(void *ptr)
Definition: mymalloc.c:207
void qmgr_job_free(QMGR_JOB *)
Definition: qmgr_job.c:412
#define QMGR_READ_FLAG_MIXED_RCPT_OTHER
Definition: qmgr_user.h:25
int qmgr_message_count
Definition: qmgr_message.c:150
int var_vrfy_pend_limit
Definition: qmgr.c:437
#define MAIL_ATTR_TRACE_FLAGS
Definition: mail_proto.h:149
char * queue_id
Definition: qmgr.h:298
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define MAIL_ATTR_ENCODING
Definition: mail_proto.h:202
int smtputf8
Definition: qmgr.h:303
char * client_addr
Definition: qmgr.h:312
#define MAIL_SERVICE_ERROR
Definition: mail_proto.h:52
QMGR_JOB_LIST message_peers
Definition: qmgr.h:411
char * var_defer_xports
Definition: qmgr.c:421
const char * address
#define DSN_SIMPLE(dsn, _status, _reason)
Definition: dsn.h:41
int selected_entries
Definition: qmgr.h:426
Definition: argv.h:17
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
char * client_helo
Definition: qmgr.h:315
#define vstring_str(vp)
Definition: vstring.h:71
off_t vstream_ftell(VSTREAM *stream)
Definition: vstream.c:1157
long data_size
Definition: qmgr.h:308
QMGR_TRANSPORT * qmgr_transport_create(const char *)
struct timeval active_time
Definition: qmgr.h:293
#define FILTER_WITHOUT_NEXTHOP(filter, next)
void deliver_completed(VSTREAM *stream, long offset)
VSTRING * rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
Definition: rewrite_clnt.c:175
int rec_goto(VSTREAM *stream, const char *buf)
Definition: record.c:326
#define REC_TYPE_VERP
Definition: rec_type.h:68
char * sasl_sender
Definition: qmgr.h:318
QMGR_ENTRY * prev
Definition: qmgr.h:194
#define REC_TYPE_SIZE
Definition: rec_type.h:37
QMGR_TRANSPORT * qmgr_error_transport(const char *)
Definition: qmgr_error.c:65
#define REC_FLAG_NONE
Definition: record.h:45
char * redirect_addr
Definition: qmgr.h:307
char ** argv
Definition: argv.h:20
int qmgr_recipient_count
Definition: qmgr_message.c:151
#define MAIL_ATTR_RWR_CONTEXT
Definition: mail_proto.h:163
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
Definition: vstring.c:415
QMGR_MESSAGE * qmgr_message_alloc(const char *queue_name, const char *queue_id, int qflags, mode_t mode)
#define QMGR_LOCK_MODE
void resolve_clnt_free(RESOLVE_REPLY *reply)
Definition: resolve_clnt.c:287
#define split_addr
Definition: split_addr.h:20
#define MAIL_ATTR_RWR_LOCAL
Definition: mail_proto.h:166
#define MAIL_ATTR_ACT_CLIENT_ADDR
Definition: mail_proto.h:216
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
int read_entries
Definition: qmgr.h:428
#define QMGR_TRANSPORT_THROTTLED(t)
Definition: qmgr.h:181
#define REC_TYPE_DSN_ENVID
Definition: rec_type.h:71
QMGR_QUEUE * qmgr_queue_create(QMGR_TRANSPORT *, const char *, const char *)
Definition: qmgr_queue.c:407
#define MAIL_ATTR_SASL_METHOD
Definition: mail_proto.h:156
#define REC_TYPE_FROM
Definition: rec_type.h:43
#define REC_TYPE_END
Definition: rec_type.h:77
#define strcasecmp_utf8(s1, s2)
Definition: stringops.h:75
#define DSN_RET_OK(v)
Definition: dsn_mask.h:24
int alldig(const char *string)
Definition: alldig.c:38
QMGR_MESSAGE * qmgr_message_realloc(QMGR_MESSAGE *message)
char * log_ident
Definition: qmgr.h:319
#define MAIL_ATTR_LOG_HELO_NAME
Definition: mail_proto.h:210
time_t refill_time
Definition: qmgr.h:337
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 MAIL_ATTR_LOG_PROTO_NAME
Definition: mail_proto.h:211
#define DEL_REQ_TRACE_FLAGS(f)
#define QMGR_FLUSH_EACH
Definition: qmgr.h:401
char * client_port
Definition: qmgr.h:313
#define QMGR_LIST_INIT(head)
Definition: qmgr.h:88
#define REC_TYPE_KILL
Definition: rec_type.h:50
#define QMGR_READ_FLAG_SEEN_ALL_NON_RCPT
Definition: qmgr.h:327
int var_qmgr_rcpt_limit
Definition: qmgr.c:416
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
long cont_length
Definition: qmgr.h:309
char * var_rcpt_delim
Definition: mail_params.c:274
long warn_offset
Definition: qmgr.h:294
#define RESOLVE_CLASS_LOCAL
Definition: resolve_clnt.h:30
int rflags
Definition: qmgr.h:287
void qmgr_queue_unthrottle(QMGR_QUEUE *)
Definition: qmgr_queue.c:198
QMGR_JOB_LIST job_list
Definition: qmgr.h:370
#define REC_TYPE_RDR
Definition: rec_type.h:52
#define REC_TYPE_DSN_RET
Definition: rec_type.h:70
int rec_get_raw(VSTREAM *stream, VSTRING *buf, ssize_t maxsize, int flags)
Definition: record.c:236
long tflags_offset
Definition: qmgr.h:286
#define STR
#define REC_TYPE_DRCP
Definition: rec_type.h:47
int flags
Definition: qmgr.h:283
VSTRING * vstring_sprintf_append(VSTRING *vp, const char *format,...)
Definition: vstring.c:624
struct timeval arrival_time
Definition: qmgr.h:291
#define MAIL_ATTR_ACT_CLIENT_PORT
Definition: mail_proto.h:217
#define MAIL_ATTR_ENC_NONE
Definition: mail_proto.h:205
char * queue_name
Definition: qmgr.h:297
QMGR_JOB * qmgr_job_obtain(QMGR_MESSAGE *, QMGR_TRANSPORT *)
Definition: qmgr_job.c:246
#define RESOLVE_FLAG_ERROR
Definition: resolve_clnt.h:27
#define REC_TYPE_INSP
Definition: rec_type.h:41
QMGR_TRANSPORT * qmgr_transport_find(const char *)
#define REC_TYPE_DSN_ORCPT
Definition: rec_type.h:72
void resolve_clnt_init(RESOLVE_REPLY *reply)
Definition: resolve_clnt.c:147
int var_qmgr_msg_rcpt_limit
Definition: qmgr.c:485
char * name
Definition: qmgr.h:200
char * var_double_bounce_sender
Definition: mail_params.c:262
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
void opened(const char *queue_id, const char *sender, long size, int nrcpt, const char *fmt,...)
Definition: opened.c:64
QMGR_PEER * qmgr_peer_obtain(QMGR_JOB *, QMGR_QUEUE *)
Definition: qmgr_peer.c:122
char * rewrite_context
Definition: qmgr.h:320
#define REC_TYPE_RCPT
Definition: rec_type.h:45
VSTREAM * mail_queue_open(const char *queue_name, const char *queue_id, int flags, mode_t mode)
Definition: mail_queue.c:424
#define MAIL_ATTR_SASL_SENDER
Definition: mail_proto.h:158
int rcpt_count
Definition: qmgr.h:429
#define REC_TYPE_MESG
Definition: rec_type.h:56
QMGR_QUEUE * qmgr_queue_find(QMGR_TRANSPORT *, const char *)
Definition: qmgr_queue.c:439
#define REC_TYPE_PTR
Definition: rec_type.h:67
QMGR_ENTRY * qmgr_entry_create(QMGR_QUEUE *, QMGR_MESSAGE *)
Definition: qmgr_entry.c:304
void msg_warn(const char *fmt,...)
Definition: msg.c:215
char * sender
Definition: qmgr.h:300
#define MAIL_ATTR_ACT_CLIENT_NAME
Definition: mail_proto.h:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int myflock(int fd, int lock_style, int operation)
Definition: myflock.c:87
int recipient_limit
Definition: qmgr.h:158
#define RCPT_LIST_INIT_QUEUE
time_t warn_time
Definition: qmgr.h:295
#define STREQ(x, y)
#define RCPT_WITHOUT_DOMAIN(rcpt, next)
long rcpt_offset
Definition: qmgr.h:310
#define REC_TYPE_WARN_ARG(tv)
Definition: rec_type.h:141
#define MAIL_ATTR_LOG_IDENT
Definition: mail_proto.h:162
#define MAIL_ATTR_LOG_CLIENT_ADDR
Definition: mail_proto.h:208
#define REC_TYPE_WARN
Definition: rec_type.h:48
QMGR_TRANSPORT * transport
Definition: qmgr.h:410
char * lowercase(char *string)
Definition: lowercase.c:34
int rec_attr_map(const char *attr_name)
Definition: rec_attr_map.c:39
char * name
Definition: qmgr.h:155
int rcpt_count
Definition: qmgr.h:367
RECIPIENT_LIST rcpt_list
Definition: qmgr.h:321
#define REC_TYPE_WARN_SCAN(cp, tv)
Definition: rec_type.h:142
const char * verp_delims_verify(const char *delims)
Definition: verp_sender.c:104
int qflags
Definition: qmgr.h:284
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
#define QMGR_FLUSH_DFXP
Definition: qmgr.h:400
Definition: qmgr.h:408
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
Definition: vstream.c:1093
#define REC_TYPE_WARN_FORMAT
Definition: rec_type.h:140
VSTRING * recipient
Definition: resolve_clnt.h:46
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
void qmgr_defer_recipient(QMGR_MESSAGE *, RECIPIENT *, DSN *)
Definition: qmgr_defer.c:147
QMGR_TRANSPORT * transport
Definition: qmgr.h:208
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void qmgr_transport_unthrottle(QMGR_TRANSPORT *)
char * var_def_filter_nexthop
Definition: qmgr.c:433
#define MAIL_SERVICE_RETRY
Definition: mail_proto.h:53
int mail_queue_remove(const char *queue_name, const char *queue_id)
Definition: mail_queue.c:274
void recipient_list_init(RECIPIENT_LIST *list, int variant)
ARGV * argv_split(const char *, const char *)
Definition: argv_split.c:63
void qmgr_message_kill_record(QMGR_MESSAGE *message, long offset)
Definition: qmgr_message.c:868
DSN * dsn
Definition: qmgr.h:162
#define MAIL_ATTR_SASL_USERNAME
Definition: mail_proto.h:157
char * sasl_method
Definition: qmgr.h:316
#define QMGR_REDIRECT(rp, tp, np)
#define REWRITE_CANON
Definition: rewrite_clnt.h:28
#define QMGR_READ_FLAG_DEFAULT
Definition: qmgr_user.h:41
#define MAIL_QUEUE_DEFER
Definition: mail_queue.h:34
#define RECIPIENT_UPDATE(ptr, new)
QMGR_QUEUE * queue
Definition: qmgr.h:435
char * client_proto
Definition: qmgr.h:314
#define QMGR_READ_FLAG_USER
Definition: qmgr_user.h:33
long data_offset
Definition: qmgr.h:296
int rcpt_limit
Definition: qmgr.h:368
const char * dsn_orcpt
Definition: dsn.h:17
#define resolve_clnt_verify_from(f, a, r)
Definition: resolve_clnt.h:58
#define strncasecmp_utf8(s1, s2, l)
Definition: stringops.h:77
time_t create_time
Definition: qmgr.h:292
int qmgr_vrfy_pend_count
Definition: qmgr_message.c:152
#define MAIL_ATTR_LOG_CLIENT_NAME
Definition: mail_proto.h:207
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
void recipient_list_free(RECIPIENT_LIST *list)
#define DSN_NOTIFY_OK(v)
Definition: dsn_mask.h:63
char * filter_xport
Definition: qmgr.h:305
RECIPIENT * info
char * client_name
Definition: qmgr.h:311
int single_rcpt
Definition: qmgr.h:290
char * qmgr_error_nexthop(DSN *)
Definition: qmgr_error.c:115
VSTRING * nexthop
Definition: resolve_clnt.h:45
char * inspect_xport
Definition: qmgr.h:306
time_t queued_time
Definition: qmgr.h:335
void qmgr_message_update_warn(QMGR_MESSAGE *message)
Definition: qmgr_message.c:850
VSTRING * transport
Definition: resolve_clnt.h:44
#define REC_TYPE_ATTR
Definition: rec_type.h:49
#define vstream_fileno(vp)
Definition: vstream.h:115
VSTREAM * fp
Definition: qmgr.h:288
#define resolve_clnt_query_from(f, a, r)
Definition: resolve_clnt.h:56
union RECIPIENT::@1 u
struct QMGR_QUEUE * queue
RECIPIENT_LIST rcpt_list
Definition: qmgr.h:265
QMGR_JOB * candidate_cache_current
Definition: qmgr.h:198
int tflags
Definition: qmgr.h:285
#define QMGR_MESSAGE_LOCKED
Definition: qmgr.h:329
#define REC_TYPE_ERROR
Definition: rec_type.h:24
QMGR_JOB * next
Definition: qmgr.h:165
#define REC_TYPE_TIME
Definition: rec_type.h:38
#define MAIL_ATTR_ACT_PROTO_NAME
Definition: mail_proto.h:220
char * var_myhostname
Definition: mail_params.c:223
#define REC_TYPE_CTIME
Definition: rec_type.h:39
int sent(int flags, const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn)
Definition: sent.c:95
char * verp_delims
Definition: qmgr.h:304
#define REC_TYPE_DONE
Definition: rec_type.h:44
#define rec_get(fp, buf, limit)
Definition: record.h:56
void recipient_list_add(RECIPIENT_LIST *list, long offset, const char *dsn_orcpt, int dsn_notify, const char *orig_rcpt, const char *rcpt)
#define REC_TYPE_ORCP
Definition: rec_type.h:46
int rec_fprintf(VSTREAM *stream, int type, const char *format,...)
Definition: record.c:391
VSTRING * vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:445
QMGR_ENTRY_LIST entry_list
Definition: qmgr.h:437
#define REC_TYPE_TIME_SCAN(cp, tv)
Definition: rec_type.h:150
int blocker_tag
Definition: qmgr.h:201
#define LIMIT_OK(limit, count)
int rcpt_unread
Definition: qmgr.h:369
#define DEL_REQ_FLAG_REC_DLY_SENT
void qmgr_job_move_limits(QMGR_JOB *)
Definition: qmgr_job.c:278
DSN * dsn
Definition: qmgr.h:212
int dsn_ret
Definition: qmgr.h:302
#define DEL_REQ_FLAG_MTA_VRFY
int var_dsn_delay_cleared
Definition: qmgr.c:436
#define MAIL_ATTR_LOG_CLIENT_PORT
Definition: mail_proto.h:209
int refcount
Definition: qmgr.h:289
#define QMGR_QUEUE_THROTTLED(q)
Definition: qmgr.h:245
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
char * encoding
Definition: qmgr.h:299
#define DEL_REQ_TRACE_ONLY_MASK
#define DEL_REQ_FLAG_RECORD
void msg_info(const char *fmt,...)
Definition: msg.c:199