Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / qmgr / qmgr_message.c
blob41fd8853e92907daefd6d3a7ffd8d2918356c17f
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* qmgr_message 3
6 /* SUMMARY
7 /* in-core message structures
8 /* SYNOPSIS
9 /* #include "qmgr.h"
11 /* int qmgr_message_count;
12 /* int qmgr_recipient_count;
14 /* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags, mode)
15 /* const char *class;
16 /* const char *name;
17 /* int qflags;
18 /* mode_t mode;
20 /* QMGR_MESSAGE *qmgr_message_realloc(message)
21 /* QMGR_MESSAGE *message;
23 /* void qmgr_message_free(message)
24 /* QMGR_MESSAGE *message;
26 /* void qmgr_message_update_warn(message)
27 /* QMGR_MESSAGE *message;
29 /* void qmgr_message_kill_record(message, offset)
30 /* QMGR_MESSAGE *message;
31 /* long offset;
32 /* DESCRIPTION
33 /* This module performs en-gross operations on queue messages.
35 /* qmgr_message_count is a global counter for the total number
36 /* of in-core message structures (i.e. the total size of the
37 /* `active' message queue).
39 /* qmgr_recipient_count is a global counter for the total number
40 /* of in-core recipient structures (i.e. the sum of all recipients
41 /* in all in-core message structures).
43 /* qmgr_message_alloc() creates an in-core message structure
44 /* with sender and recipient information taken from the named queue
45 /* file. A null result means the queue file could not be read or
46 /* that the queue file contained incorrect information. A result
47 /* QMGR_MESSAGE_LOCKED means delivery must be deferred. The number
48 /* of recipients read from a queue file is limited by the global
49 /* var_qmgr_rcpt_limit configuration parameter. When the limit
50 /* is reached, the \fIrcpt_offset\fR structure member is set to
51 /* the position where the read was terminated. Recipients are
52 /* run through the resolver, and are assigned to destination
53 /* queues. Recipients that cannot be assigned are deferred or
54 /* bounced. Mail that has bounced twice is silently absorbed.
55 /* A non-zero mode means change the queue file permissions.
57 /* qmgr_message_realloc() resumes reading recipients from the queue
58 /* file, and updates the recipient list and \fIrcpt_offset\fR message
59 /* structure members. A null result means that the file could not be
60 /* read or that the file contained incorrect information. Recipient
61 /* limit imposed this time is based on the position of the message
62 /* job(s) on corresponding transport job list(s). It's considered
63 /* an error to call this when the recipient slots can't be allocated.
65 /* qmgr_message_free() destroys an in-core message structure and makes
66 /* the resources available for reuse. It is an error to destroy
67 /* a message structure that is still referenced by queue entry structures.
69 /* qmgr_message_update_warn() takes a closed message, opens it, updates
70 /* the warning field, and closes it again.
72 /* qmgr_message_kill_record() takes a closed message, opens it, updates
73 /* the record type at the given offset to "killed", and closes the file.
74 /* A killed envelope record is ignored. Killed records are not allowed
75 /* inside the message content.
76 /* DIAGNOSTICS
77 /* Warnings: malformed message file. Fatal errors: out of memory.
78 /* SEE ALSO
79 /* envelope(3) message envelope parser
80 /* LICENSE
81 /* .ad
82 /* .fi
83 /* The Secure Mailer license must be distributed with this software.
84 /* AUTHOR(S)
85 /* Wietse Venema
86 /* IBM T.J. Watson Research
87 /* P.O. Box 704
88 /* Yorktown Heights, NY 10598, USA
90 /* Preemptive scheduler enhancements:
91 /* Patrik Rak
92 /* Modra 6
93 /* 155 00, Prague, Czech Republic
94 /*--*/
96 /* System library. */
98 #include <sys_defs.h>
99 #include <sys/stat.h>
100 #include <stdlib.h>
101 #include <stdio.h> /* sscanf() */
102 #include <fcntl.h>
103 #include <errno.h>
104 #include <unistd.h>
105 #include <string.h>
106 #include <ctype.h>
108 #ifdef STRCASECMP_IN_STRINGS_H
109 #include <strings.h>
110 #endif
112 /* Utility library. */
114 #include <msg.h>
115 #include <mymalloc.h>
116 #include <vstring.h>
117 #include <vstream.h>
118 #include <split_at.h>
119 #include <valid_hostname.h>
120 #include <argv.h>
121 #include <stringops.h>
122 #include <myflock.h>
123 #include <sane_time.h>
125 /* Global library. */
127 #include <dict.h>
128 #include <mail_queue.h>
129 #include <mail_params.h>
130 #include <canon_addr.h>
131 #include <record.h>
132 #include <rec_type.h>
133 #include <sent.h>
134 #include <deliver_completed.h>
135 #include <opened.h>
136 #include <verp_sender.h>
137 #include <mail_proto.h>
138 #include <qmgr_user.h>
139 #include <split_addr.h>
140 #include <dsn_mask.h>
141 #include <rec_attr_map.h>
143 /* Client stubs. */
145 #include <rewrite_clnt.h>
146 #include <resolve_clnt.h>
148 /* Application-specific. */
150 #include "qmgr.h"
152 int qmgr_message_count;
153 int qmgr_recipient_count;
155 /* qmgr_message_create - create in-core message structure */
157 static QMGR_MESSAGE *qmgr_message_create(const char *queue_name,
158 const char *queue_id, int qflags)
160 QMGR_MESSAGE *message;
162 message = (QMGR_MESSAGE *) mymalloc(sizeof(QMGR_MESSAGE));
163 qmgr_message_count++;
164 message->flags = 0;
165 message->qflags = qflags;
166 message->tflags = 0;
167 message->tflags_offset = 0;
168 message->rflags = QMGR_READ_FLAG_DEFAULT;
169 message->fp = 0;
170 message->refcount = 0;
171 message->single_rcpt = 0;
172 message->arrival_time.tv_sec = message->arrival_time.tv_usec = 0;
173 message->create_time = 0;
174 GETTIMEOFDAY(&message->active_time);
175 message->queued_time = sane_time();
176 message->refill_time = 0;
177 message->data_offset = 0;
178 message->queue_id = mystrdup(queue_id);
179 message->queue_name = mystrdup(queue_name);
180 message->encoding = 0;
181 message->sender = 0;
182 message->dsn_envid = 0;
183 message->dsn_ret = 0;
184 message->filter_xport = 0;
185 message->inspect_xport = 0;
186 message->redirect_addr = 0;
187 message->data_size = 0;
188 message->cont_length = 0;
189 message->warn_offset = 0;
190 message->warn_time = 0;
191 message->rcpt_offset = 0;
192 message->verp_delims = 0;
193 message->client_name = 0;
194 message->client_addr = 0;
195 message->client_port = 0;
196 message->client_proto = 0;
197 message->client_helo = 0;
198 message->sasl_method = 0;
199 message->sasl_username = 0;
200 message->sasl_sender = 0;
201 message->rewrite_context = 0;
202 recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE);
203 message->rcpt_count = 0;
204 message->rcpt_limit = var_qmgr_msg_rcpt_limit;
205 message->rcpt_unread = 0;
206 QMGR_LIST_INIT(message->job_list);
207 return (message);
210 /* qmgr_message_close - close queue file */
212 static void qmgr_message_close(QMGR_MESSAGE *message)
214 vstream_fclose(message->fp);
215 message->fp = 0;
218 /* qmgr_message_open - open queue file */
220 static int qmgr_message_open(QMGR_MESSAGE *message)
224 * Sanity check.
226 if (message->fp)
227 msg_panic("%s: queue file is open", message->queue_id);
230 * Open this queue file. Skip files that we cannot open. Back off when
231 * the system appears to be running out of resources.
233 if ((message->fp = mail_queue_open(message->queue_name,
234 message->queue_id,
235 O_RDWR, 0)) == 0) {
236 if (errno != ENOENT)
237 msg_fatal("open %s %s: %m", message->queue_name, message->queue_id);
238 msg_warn("open %s %s: %m", message->queue_name, message->queue_id);
239 return (-1);
241 return (0);
244 /* qmgr_message_oldstyle_scan - support for Postfix < 1.0 queue files */
246 static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message)
248 VSTRING *buf;
249 long orig_offset, extra_offset;
250 int rec_type;
251 char *start;
254 * Initialize. No early returns or we have a memory leak.
256 buf = vstring_alloc(100);
257 if ((orig_offset = vstream_ftell(message->fp)) < 0)
258 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
261 * Rewind to the very beginning to make sure we see all records.
263 if (vstream_fseek(message->fp, 0, SEEK_SET) < 0)
264 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
267 * Scan through the old style queue file. Count the total number of
268 * recipients and find the data/extra sections offsets. Note that the new
269 * queue files require that data_size equals extra_offset - data_offset,
270 * so we set data_size to this as well and ignore the size record itself
271 * completely.
273 message->rcpt_unread = 0;
274 for (;;) {
275 rec_type = rec_get(message->fp, buf, 0);
276 if (rec_type <= 0)
277 /* Report missing end record later. */
278 break;
279 start = vstring_str(buf);
280 if (msg_verbose > 1)
281 msg_info("old-style scan record %c %s", rec_type, start);
282 if (rec_type == REC_TYPE_END)
283 break;
284 if (rec_type == REC_TYPE_DONE
285 || rec_type == REC_TYPE_RCPT
286 || rec_type == REC_TYPE_DRCP) {
287 message->rcpt_unread++;
288 continue;
290 if (rec_type == REC_TYPE_MESG) {
291 if (message->data_offset == 0) {
292 if ((message->data_offset = vstream_ftell(message->fp)) < 0)
293 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
294 if ((extra_offset = atol(start)) <= message->data_offset)
295 msg_fatal("bad extra offset %s file %s",
296 start, VSTREAM_PATH(message->fp));
297 if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0)
298 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
299 message->data_size = extra_offset - message->data_offset;
301 continue;
306 * Clean up.
308 if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0)
309 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
310 vstring_free(buf);
313 * Sanity checks. Verify that all required information was found,
314 * including the queue file end marker.
316 if (message->data_offset == 0 || rec_type != REC_TYPE_END)
317 msg_fatal("%s: envelope records out of order", message->queue_id);
320 /* qmgr_message_read - read envelope records */
322 static int qmgr_message_read(QMGR_MESSAGE *message)
324 VSTRING *buf;
325 int rec_type;
326 long curr_offset;
327 long save_offset = message->rcpt_offset; /* save a flag */
328 int save_unread = message->rcpt_unread; /* save a count */
329 char *start;
330 int recipient_limit;
331 const char *error_text;
332 char *name;
333 char *value;
334 char *orig_rcpt = 0;
335 int count;
336 int dsn_notify = 0;
337 char *dsn_orcpt = 0;
338 int n;
339 int have_log_client_attr = 0;
342 * Initialize. No early returns or we have a memory leak.
344 buf = vstring_alloc(100);
347 * If we re-open this file, skip over on-file recipient records that we
348 * already looked at, and refill the in-core recipient address list.
350 * For the first time, the message recipient limit is calculated from the
351 * global recipient limit. This is to avoid reading little recipients
352 * when the active queue is near empty. When the queue becomes full, only
353 * the necessary amount is read in core. Such priming is necessary
354 * because there are no message jobs yet.
356 * For the next time, the recipient limit is based solely on the message
357 * jobs' positions in the job lists and/or job stacks.
359 if (message->rcpt_offset) {
360 if (message->rcpt_list.len)
361 msg_panic("%s: recipient list not empty on recipient reload",
362 message->queue_id);
363 if (vstream_fseek(message->fp, message->rcpt_offset, SEEK_SET) < 0)
364 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
365 message->rcpt_offset = 0;
366 recipient_limit = message->rcpt_limit - message->rcpt_count;
367 } else {
368 recipient_limit = var_qmgr_rcpt_limit - qmgr_recipient_count;
369 if (recipient_limit < message->rcpt_limit)
370 recipient_limit = message->rcpt_limit;
372 /* Keep interrupt latency in check. */
373 if (recipient_limit > 5000)
374 recipient_limit = 5000;
375 if (recipient_limit <= 0)
376 msg_panic("%s: no recipient slots available", message->queue_id);
377 if (msg_verbose)
378 msg_info("%s: recipient limit %d", message->queue_id, recipient_limit);
381 * Read envelope records. XXX Rely on the front-end programs to enforce
382 * record size limits. Read up to recipient_limit recipients from the
383 * queue file, to protect against memory exhaustion. Recipient records
384 * may appear before or after the message content, so we keep reading
385 * from the queue file until we have enough recipients (rcpt_offset != 0)
386 * and until we know all the non-recipient information.
388 * Note that the total recipient count record is accurate only for fresh
389 * queue files. After some of the recipients are marked as done and the
390 * queue file is deferred, it can be used as upper bound estimate only.
391 * Fortunately, this poses no major problem on the scheduling algorithm,
392 * as the only impact is that the already deferred messages are not
393 * chosen by qmgr_job_candidate() as often as they could.
395 * On the first open, we must examine all non-recipient records.
397 * Optimization: when we know that recipient records are not mixed with
398 * non-recipient records, as is typical with mailing list mail, then we
399 * can avoid having to examine all the queue file records before we can
400 * start deliveries. This avoids some file system thrashing with huge
401 * mailing lists.
403 for (;;) {
404 if ((curr_offset = vstream_ftell(message->fp)) < 0)
405 msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp));
406 if (curr_offset == message->data_offset && curr_offset > 0) {
407 if (vstream_fseek(message->fp, message->data_size, SEEK_CUR) < 0)
408 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
409 curr_offset += message->data_size;
411 rec_type = rec_get_raw(message->fp, buf, 0, REC_FLAG_NONE);
412 start = vstring_str(buf);
413 if (msg_verbose > 1)
414 msg_info("record %c %s", rec_type, start);
415 if (rec_type == REC_TYPE_PTR) {
416 if ((rec_type = rec_goto(message->fp, start)) == REC_TYPE_ERROR)
417 break;
418 /* Need to update curr_offset after pointer jump. */
419 continue;
421 if (rec_type <= 0) {
422 msg_warn("%s: message rejected: missing end record",
423 message->queue_id);
424 break;
426 if (rec_type == REC_TYPE_END) {
427 message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT;
428 break;
432 * Map named attributes to pseudo record types, so that we don't have
433 * to pollute the queue file with records that are incompatible with
434 * past Postfix versions. Preferably, people should be able to back
435 * out from an upgrade without losing mail.
437 if (rec_type == REC_TYPE_ATTR) {
438 if ((error_text = split_nameval(start, &name, &value)) != 0) {
439 msg_warn("%s: ignoring bad attribute: %s: %.200s",
440 message->queue_id, error_text, start);
441 rec_type = REC_TYPE_ERROR;
442 break;
444 if ((n = rec_attr_map(name)) != 0) {
445 start = value;
446 rec_type = n;
451 * Process recipient records.
453 if (rec_type == REC_TYPE_RCPT) {
454 /* See also below for code setting orig_rcpt etc. */
455 if (message->rcpt_offset == 0) {
456 message->rcpt_unread--;
457 recipient_list_add(&message->rcpt_list, curr_offset,
458 dsn_orcpt ? dsn_orcpt : "",
459 dsn_notify ? dsn_notify : 0,
460 orig_rcpt ? orig_rcpt : "", start);
461 if (dsn_orcpt) {
462 myfree(dsn_orcpt);
463 dsn_orcpt = 0;
465 if (orig_rcpt) {
466 myfree(orig_rcpt);
467 orig_rcpt = 0;
469 if (dsn_notify)
470 dsn_notify = 0;
471 if (message->rcpt_list.len >= recipient_limit) {
472 if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
473 msg_fatal("vstream_ftell %s: %m",
474 VSTREAM_PATH(message->fp));
475 if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
476 /* We already examined all non-recipient records. */
477 break;
478 if (message->rflags & QMGR_READ_FLAG_MIXED_RCPT_OTHER)
479 /* Examine all remaining non-recipient records. */
480 continue;
481 /* Optimizations for "pure recipient" record sections. */
482 if (curr_offset > message->data_offset) {
483 /* We already examined all non-recipient records. */
484 message->rflags |= QMGR_READ_FLAG_SEEN_ALL_NON_RCPT;
485 break;
487 /* Examine non-recipient records in extracted segment. */
488 if (vstream_fseek(message->fp, message->data_offset
489 + message->data_size, SEEK_SET) < 0)
490 msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp));
491 continue;
494 continue;
496 if (rec_type == REC_TYPE_DONE || rec_type == REC_TYPE_DRCP) {
497 if (message->rcpt_offset == 0) {
498 message->rcpt_unread--;
499 if (dsn_orcpt) {
500 myfree(dsn_orcpt);
501 dsn_orcpt = 0;
503 if (orig_rcpt) {
504 myfree(orig_rcpt);
505 orig_rcpt = 0;
507 if (dsn_notify)
508 dsn_notify = 0;
510 continue;
512 if (rec_type == REC_TYPE_DSN_ORCPT) {
513 /* See also above for code clearing dsn_orcpt. */
514 if (dsn_orcpt != 0) {
515 msg_warn("%s: ignoring out-of-order DSN original recipient address <%.200s>",
516 message->queue_id, dsn_orcpt);
517 myfree(dsn_orcpt);
518 dsn_orcpt = 0;
520 if (message->rcpt_offset == 0)
521 dsn_orcpt = mystrdup(start);
522 continue;
524 if (rec_type == REC_TYPE_DSN_NOTIFY) {
525 /* See also above for code clearing dsn_notify. */
526 if (dsn_notify != 0) {
527 msg_warn("%s: ignoring out-of-order DSN notify flags <%d>",
528 message->queue_id, dsn_notify);
529 dsn_notify = 0;
531 if (message->rcpt_offset == 0) {
532 if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_NOTIFY_OK(n))
533 msg_warn("%s: ignoring malformed DSN notify flags <%.200s>",
534 message->queue_id, start);
535 else
536 dsn_notify = n;
537 continue;
540 if (rec_type == REC_TYPE_ORCP) {
541 /* See also above for code clearing orig_rcpt. */
542 if (orig_rcpt != 0) {
543 msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
544 message->queue_id, orig_rcpt);
545 myfree(orig_rcpt);
546 orig_rcpt = 0;
548 if (message->rcpt_offset == 0)
549 orig_rcpt = mystrdup(start);
550 continue;
554 * Process non-recipient records.
556 if (message->rflags & QMGR_READ_FLAG_SEEN_ALL_NON_RCPT)
557 /* We already examined all non-recipient records. */
558 continue;
559 if (rec_type == REC_TYPE_SIZE) {
560 if (message->data_offset == 0) {
561 if ((count = sscanf(start, "%ld %ld %d %d %ld",
562 &message->data_size, &message->data_offset,
563 &message->rcpt_unread, &message->rflags,
564 &message->cont_length)) >= 3) {
565 /* Postfix >= 1.0 (a.k.a. 20010228). */
566 if (message->data_offset <= 0 || message->data_size <= 0) {
567 msg_warn("%s: invalid size record: %.100s",
568 message->queue_id, start);
569 rec_type = REC_TYPE_ERROR;
570 break;
572 if (message->rflags & ~QMGR_READ_FLAG_USER) {
573 msg_warn("%s: invalid flags in size record: %.100s",
574 message->queue_id, start);
575 rec_type = REC_TYPE_ERROR;
576 break;
578 } else if (count == 1) {
579 /* Postfix < 1.0 (a.k.a. 20010228). */
580 qmgr_message_oldstyle_scan(message);
581 } else {
582 /* Can't happen. */
583 msg_warn("%s: message rejected: weird size record",
584 message->queue_id);
585 rec_type = REC_TYPE_ERROR;
586 break;
589 /* Postfix < 2.4 compatibility. */
590 if (message->cont_length == 0) {
591 message->cont_length = message->data_size;
592 } else if (message->cont_length < 0) {
593 msg_warn("%s: invalid size record: %.100s",
594 message->queue_id, start);
595 rec_type = REC_TYPE_ERROR;
596 break;
598 continue;
600 if (rec_type == REC_TYPE_TIME) {
601 if (message->arrival_time.tv_sec == 0)
602 REC_TYPE_TIME_SCAN(start, message->arrival_time);
603 continue;
605 if (rec_type == REC_TYPE_CTIME) {
606 if (message->create_time == 0)
607 message->create_time = atol(start);
608 continue;
610 if (rec_type == REC_TYPE_FILT) {
611 if (message->filter_xport != 0)
612 myfree(message->filter_xport);
613 message->filter_xport = mystrdup(start);
614 continue;
616 if (rec_type == REC_TYPE_INSP) {
617 if (message->inspect_xport != 0)
618 myfree(message->inspect_xport);
619 message->inspect_xport = mystrdup(start);
620 continue;
622 if (rec_type == REC_TYPE_RDR) {
623 if (message->redirect_addr != 0)
624 myfree(message->redirect_addr);
625 message->redirect_addr = mystrdup(start);
626 continue;
628 if (rec_type == REC_TYPE_FROM) {
629 if (message->sender == 0) {
630 message->sender = mystrdup(start);
631 opened(message->queue_id, message->sender,
632 message->cont_length, message->rcpt_unread,
633 "queue %s", message->queue_name);
635 continue;
637 if (rec_type == REC_TYPE_DSN_ENVID) {
638 if (message->dsn_envid == 0)
639 message->dsn_envid = mystrdup(start);
641 if (rec_type == REC_TYPE_DSN_RET) {
642 if (message->dsn_ret == 0) {
643 if (!alldig(start) || (n = atoi(start)) == 0 || !DSN_RET_OK(n))
644 msg_warn("%s: ignoring malformed DSN RET flags in queue file record:%.100s",
645 message->queue_id, start);
646 else
647 message->dsn_ret = n;
650 if (rec_type == REC_TYPE_ATTR) {
651 /* Allow extra segment to override envelope segment info. */
652 if (strcmp(name, MAIL_ATTR_ENCODING) == 0) {
653 if (message->encoding != 0)
654 myfree(message->encoding);
655 message->encoding = mystrdup(value);
659 * Backwards compatibility. Before Postfix 2.3, the logging
660 * attributes were called client_name, etc. Now they are called
661 * log_client_name. etc., and client_name is used for the actual
662 * client information. To support old queue files we accept both
663 * names for the purpose of logging; the new name overrides the
664 * old one.
666 * XXX Do not use the "legacy" client_name etc. attribute values for
667 * initializing the logging attributes, when this file already
668 * contains the "modern" log_client_name etc. logging attributes.
669 * Otherwise, logging attributes that are not present in the
670 * queue file would be set with information from the real client.
672 else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_NAME) == 0) {
673 if (have_log_client_attr == 0 && message->client_name == 0)
674 message->client_name = mystrdup(value);
675 } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_ADDR) == 0) {
676 if (have_log_client_attr == 0 && message->client_addr == 0)
677 message->client_addr = mystrdup(value);
678 } else if (strcmp(name, MAIL_ATTR_ACT_CLIENT_PORT) == 0) {
679 if (have_log_client_attr == 0 && message->client_port == 0)
680 message->client_port = mystrdup(value);
681 } else if (strcmp(name, MAIL_ATTR_ACT_PROTO_NAME) == 0) {
682 if (have_log_client_attr == 0 && message->client_proto == 0)
683 message->client_proto = mystrdup(value);
684 } else if (strcmp(name, MAIL_ATTR_ACT_HELO_NAME) == 0) {
685 if (have_log_client_attr == 0 && message->client_helo == 0)
686 message->client_helo = mystrdup(value);
688 /* Original client attributes. */
689 else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_NAME) == 0) {
690 if (message->client_name != 0)
691 myfree(message->client_name);
692 message->client_name = mystrdup(value);
693 have_log_client_attr = 1;
694 } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_ADDR) == 0) {
695 if (message->client_addr != 0)
696 myfree(message->client_addr);
697 message->client_addr = mystrdup(value);
698 have_log_client_attr = 1;
699 } else if (strcmp(name, MAIL_ATTR_LOG_CLIENT_PORT) == 0) {
700 if (message->client_port != 0)
701 myfree(message->client_port);
702 message->client_port = mystrdup(value);
703 have_log_client_attr = 1;
704 } else if (strcmp(name, MAIL_ATTR_LOG_PROTO_NAME) == 0) {
705 if (message->client_proto != 0)
706 myfree(message->client_proto);
707 message->client_proto = mystrdup(value);
708 have_log_client_attr = 1;
709 } else if (strcmp(name, MAIL_ATTR_LOG_HELO_NAME) == 0) {
710 if (message->client_helo != 0)
711 myfree(message->client_helo);
712 message->client_helo = mystrdup(value);
713 have_log_client_attr = 1;
714 } else if (strcmp(name, MAIL_ATTR_SASL_METHOD) == 0) {
715 if (message->sasl_method == 0)
716 message->sasl_method = mystrdup(value);
717 else
718 msg_warn("%s: ignoring multiple %s attribute: %s",
719 message->queue_id, MAIL_ATTR_SASL_METHOD, value);
720 } else if (strcmp(name, MAIL_ATTR_SASL_USERNAME) == 0) {
721 if (message->sasl_username == 0)
722 message->sasl_username = mystrdup(value);
723 else
724 msg_warn("%s: ignoring multiple %s attribute: %s",
725 message->queue_id, MAIL_ATTR_SASL_USERNAME, value);
726 } else if (strcmp(name, MAIL_ATTR_SASL_SENDER) == 0) {
727 if (message->sasl_sender == 0)
728 message->sasl_sender = mystrdup(value);
729 else
730 msg_warn("%s: ignoring multiple %s attribute: %s",
731 message->queue_id, MAIL_ATTR_SASL_SENDER, value);
732 } else if (strcmp(name, MAIL_ATTR_RWR_CONTEXT) == 0) {
733 if (message->rewrite_context == 0)
734 message->rewrite_context = mystrdup(value);
735 else
736 msg_warn("%s: ignoring multiple %s attribute: %s",
737 message->queue_id, MAIL_ATTR_RWR_CONTEXT, value);
741 * Optional tracing flags (verify, sendmail -v, sendmail -bv).
742 * This record is killed after a trace logfile report is sent and
743 * after the logfile is deleted.
745 else if (strcmp(name, MAIL_ATTR_TRACE_FLAGS) == 0) {
746 message->tflags = DEL_REQ_TRACE_FLAGS(atoi(value));
747 if (message->tflags == DEL_REQ_FLAG_RECORD)
748 message->tflags_offset = curr_offset;
749 else
750 message->tflags_offset = 0;
752 continue;
754 if (rec_type == REC_TYPE_WARN) {
755 if (message->warn_offset == 0) {
756 message->warn_offset = curr_offset;
757 REC_TYPE_WARN_SCAN(start, message->warn_time);
759 continue;
761 if (rec_type == REC_TYPE_VERP) {
762 if (message->verp_delims == 0) {
763 if (message->sender == 0 || message->sender[0] == 0) {
764 msg_warn("%s: ignoring VERP request for null sender",
765 message->queue_id);
766 } else if (verp_delims_verify(start) != 0) {
767 msg_warn("%s: ignoring bad VERP request: \"%.100s\"",
768 message->queue_id, start);
769 } else {
770 message->single_rcpt = 1;
771 message->verp_delims = mystrdup(start);
774 continue;
779 * Grr.
781 if (dsn_orcpt != 0) {
782 if (rec_type > 0)
783 msg_warn("%s: ignoring out-of-order DSN original recipient <%.200s>",
784 message->queue_id, dsn_orcpt);
785 myfree(dsn_orcpt);
787 if (orig_rcpt != 0) {
788 if (rec_type > 0)
789 msg_warn("%s: ignoring out-of-order original recipient <%.200s>",
790 message->queue_id, orig_rcpt);
791 myfree(orig_rcpt);
795 * Remember when we have read the last recipient batch. Note that we do
796 * it here after reading as reading might have used considerable amount
797 * of time.
799 message->refill_time = sane_time();
802 * Avoid clumsiness elsewhere in the program. When sending data across an
803 * IPC channel, sending an empty string is more convenient than sending a
804 * null pointer.
806 if (message->dsn_envid == 0)
807 message->dsn_envid = mystrdup("");
808 if (message->encoding == 0)
809 message->encoding = mystrdup(MAIL_ATTR_ENC_NONE);
810 if (message->client_name == 0)
811 message->client_name = mystrdup("");
812 if (message->client_addr == 0)
813 message->client_addr = mystrdup("");
814 if (message->client_port == 0)
815 message->client_port = mystrdup("");
816 if (message->client_proto == 0)
817 message->client_proto = mystrdup("");
818 if (message->client_helo == 0)
819 message->client_helo = mystrdup("");
820 if (message->sasl_method == 0)
821 message->sasl_method = mystrdup("");
822 if (message->sasl_username == 0)
823 message->sasl_username = mystrdup("");
824 if (message->sasl_sender == 0)
825 message->sasl_sender = mystrdup("");
826 if (message->rewrite_context == 0)
827 message->rewrite_context = mystrdup(MAIL_ATTR_RWR_LOCAL);
828 /* Postfix < 2.3 compatibility. */
829 if (message->create_time == 0)
830 message->create_time = message->arrival_time.tv_sec;
833 * Clean up.
835 vstring_free(buf);
838 * Sanity checks. Verify that all required information was found,
839 * including the queue file end marker.
841 if (message->rcpt_unread < 0
842 || (message->rcpt_offset == 0 && message->rcpt_unread != 0)) {
843 msg_warn("%s: rcpt count mismatch (%d)",
844 message->queue_id, message->rcpt_unread);
845 message->rcpt_unread = 0;
847 if (rec_type <= 0) {
848 /* Already logged warning. */
849 } else if (message->arrival_time.tv_sec == 0) {
850 msg_warn("%s: message rejected: missing arrival time record",
851 message->queue_id);
852 } else if (message->sender == 0) {
853 msg_warn("%s: message rejected: missing sender record",
854 message->queue_id);
855 } else if (message->data_offset == 0) {
856 msg_warn("%s: message rejected: missing size record",
857 message->queue_id);
858 } else {
859 return (0);
861 message->rcpt_offset = save_offset; /* restore flag */
862 message->rcpt_unread = save_unread; /* restore count */
863 recipient_list_free(&message->rcpt_list);
864 recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE);
865 return (-1);
868 /* qmgr_message_update_warn - update the time of next delay warning */
870 void qmgr_message_update_warn(QMGR_MESSAGE *message)
874 * XXX eventually this should let us schedule multiple warnings, right
875 * now it just allows for one.
877 if (qmgr_message_open(message)
878 || vstream_fseek(message->fp, message->warn_offset, SEEK_SET) < 0
879 || rec_fprintf(message->fp, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT,
880 REC_TYPE_WARN_ARG(0)) < 0
881 || vstream_fflush(message->fp))
882 msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
883 qmgr_message_close(message);
886 /* qmgr_message_kill_record - mark one message record as killed */
888 void qmgr_message_kill_record(QMGR_MESSAGE *message, long offset)
890 if (offset <= 0)
891 msg_panic("qmgr_message_kill_record: bad offset 0x%lx", offset);
892 if (qmgr_message_open(message)
893 || rec_put_type(message->fp, REC_TYPE_KILL, offset) < 0
894 || vstream_fflush(message->fp))
895 msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp));
896 qmgr_message_close(message);
899 /* qmgr_message_sort_compare - compare recipient information */
901 static int qmgr_message_sort_compare(const void *p1, const void *p2)
903 RECIPIENT *rcpt1 = (RECIPIENT *) p1;
904 RECIPIENT *rcpt2 = (RECIPIENT *) p2;
905 QMGR_QUEUE *queue1;
906 QMGR_QUEUE *queue2;
907 char *at1;
908 char *at2;
909 int result;
912 * Compare most significant to least significant recipient attributes.
913 * The comparison function must be transitive, so NULL values need to be
914 * assigned an ordinal (we set NULL last).
917 queue1 = rcpt1->u.queue;
918 queue2 = rcpt2->u.queue;
919 if (queue1 != 0 && queue2 == 0)
920 return (-1);
921 if (queue1 == 0 && queue2 != 0)
922 return (1);
923 if (queue1 != 0 && queue2 != 0) {
926 * Compare message transport.
928 if ((result = strcmp(queue1->transport->name,
929 queue2->transport->name)) != 0)
930 return (result);
933 * Compare queue name (nexthop or recipient@nexthop).
935 if ((result = strcmp(queue1->name, queue2->name)) != 0)
936 return (result);
940 * Compare recipient domain.
942 at1 = strrchr(rcpt1->address, '@');
943 at2 = strrchr(rcpt2->address, '@');
944 if (at1 == 0 && at2 != 0)
945 return (1);
946 if (at1 != 0 && at2 == 0)
947 return (-1);
948 if (at1 != 0 && at2 != 0
949 && (result = strcasecmp(at1, at2)) != 0)
950 return (result);
953 * Compare recipient address.
955 return (strcmp(rcpt1->address, rcpt2->address));
958 /* qmgr_message_sort - sort message recipient addresses by domain */
960 static void qmgr_message_sort(QMGR_MESSAGE *message)
962 qsort((char *) message->rcpt_list.info, message->rcpt_list.len,
963 sizeof(message->rcpt_list.info[0]), qmgr_message_sort_compare);
964 if (msg_verbose) {
965 RECIPIENT_LIST list = message->rcpt_list;
966 RECIPIENT *rcpt;
968 msg_info("start sorted recipient list");
969 for (rcpt = list.info; rcpt < list.info + list.len; rcpt++)
970 msg_info("qmgr_message_sort: %s", rcpt->address);
971 msg_info("end sorted recipient list");
975 /* qmgr_resolve_one - resolve or skip one recipient */
977 static int qmgr_resolve_one(QMGR_MESSAGE *message, RECIPIENT *recipient,
978 const char *addr, RESOLVE_REPLY *reply)
980 #define QMGR_REDIRECT(rp, tp, np) do { \
981 (rp)->flags = 0; \
982 vstring_strcpy((rp)->transport, (tp)); \
983 vstring_strcpy((rp)->nexthop, (np)); \
984 } while (0)
986 if ((message->tflags & DEL_REQ_FLAG_MTA_VRFY) == 0)
987 resolve_clnt_query_from(message->sender, addr, reply);
988 else
989 resolve_clnt_verify_from(message->sender, addr, reply);
990 if (reply->flags & RESOLVE_FLAG_FAIL) {
991 QMGR_REDIRECT(reply, MAIL_SERVICE_RETRY,
992 "4.3.0 address resolver failure");
993 return (0);
994 } else if (reply->flags & RESOLVE_FLAG_ERROR) {
995 QMGR_REDIRECT(reply, MAIL_SERVICE_ERROR,
996 "5.1.3 bad address syntax");
997 return (0);
998 } else {
999 return (0);
1003 /* qmgr_message_resolve - resolve recipients */
1005 static void qmgr_message_resolve(QMGR_MESSAGE *message)
1007 static ARGV *defer_xport_argv;
1008 RECIPIENT_LIST list = message->rcpt_list;
1009 RECIPIENT *recipient;
1010 QMGR_TRANSPORT *transport = 0;
1011 QMGR_QUEUE *queue = 0;
1012 RESOLVE_REPLY reply;
1013 VSTRING *queue_name;
1014 char *at;
1015 char **cpp;
1016 char *nexthop;
1017 ssize_t len;
1018 int status;
1019 DSN dsn;
1020 MSG_STATS stats;
1021 DSN *saved_dsn;
1023 #define STREQ(x,y) (strcmp(x,y) == 0)
1024 #define STR vstring_str
1025 #define LEN VSTRING_LEN
1027 resolve_clnt_init(&reply);
1028 queue_name = vstring_alloc(1);
1029 for (recipient = list.info; recipient < list.info + list.len; recipient++) {
1032 * Redirect overrides all else. But only once (per entire message).
1033 * For consistency with the remainder of Postfix, rewrite the address
1034 * to canonical form before resolving it.
1036 if (message->redirect_addr) {
1037 if (recipient > list.info) {
1038 recipient->u.queue = 0;
1039 continue;
1041 message->rcpt_offset = 0;
1042 message->rcpt_unread = 0;
1044 rewrite_clnt_internal(REWRITE_CANON, message->redirect_addr,
1045 reply.recipient);
1046 RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1047 if (qmgr_resolve_one(message, recipient,
1048 recipient->address, &reply) < 0)
1049 continue;
1050 if (!STREQ(recipient->address, STR(reply.recipient)))
1051 RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1055 * Content filtering overrides the address resolver.
1057 * XXX Bypass content_filter inspection for user-generated probes
1058 * (sendmail -bv). MTA-generated probes never have the "please filter
1059 * me" bits turned on, but we handle them here anyway for the sake of
1060 * future proofing.
1062 else if (message->filter_xport
1063 && (message->tflags & DEL_REQ_TRACE_ONLY_MASK) == 0) {
1064 reply.flags = 0;
1065 vstring_strcpy(reply.transport, message->filter_xport);
1066 if ((nexthop = split_at(STR(reply.transport), ':')) == 0
1067 || *nexthop == 0)
1068 nexthop = var_myhostname;
1069 vstring_strcpy(reply.nexthop, nexthop);
1070 vstring_strcpy(reply.recipient, recipient->address);
1074 * Resolve the destination to (transport, nexthop, address). The
1075 * result address may differ from the one specified by the sender.
1077 else {
1078 if (qmgr_resolve_one(message, recipient,
1079 recipient->address, &reply) < 0)
1080 continue;
1081 if (!STREQ(recipient->address, STR(reply.recipient)))
1082 RECIPIENT_UPDATE(recipient->address, STR(reply.recipient));
1086 * Bounce null recipients. This should never happen, but is most
1087 * likely the result of a fault in a different program, so aborting
1088 * the queue manager process does not help.
1090 if (recipient->address[0] == 0) {
1091 QMGR_REDIRECT(&reply, MAIL_SERVICE_ERROR,
1092 "5.1.3 null recipient address");
1096 * Discard mail to the local double bounce address here, so this
1097 * system can run without a local delivery agent. They'd still have
1098 * to configure something for mail directed to the local postmaster,
1099 * though, but that is an RFC requirement anyway.
1101 * XXX This lookup should be done in the resolver, and the mail should
1102 * be directed to a general-purpose null delivery agent.
1104 if (reply.flags & RESOLVE_CLASS_LOCAL) {
1105 at = strrchr(STR(reply.recipient), '@');
1106 len = (at ? (at - STR(reply.recipient))
1107 : strlen(STR(reply.recipient)));
1108 if (strncasecmp(STR(reply.recipient), var_double_bounce_sender,
1109 len) == 0
1110 && !var_double_bounce_sender[len]) {
1111 status = sent(message->tflags, message->queue_id,
1112 QMGR_MSG_STATS(&stats, message), recipient,
1113 "none", DSN_SIMPLE(&dsn, "2.0.0",
1114 "undeliverable postmaster notification discarded"));
1115 if (status == 0) {
1116 deliver_completed(message->fp, recipient->offset);
1117 #if 0
1118 /* It's the default verification probe sender address. */
1119 msg_warn("%s: undeliverable postmaster notification discarded",
1120 message->queue_id);
1121 #endif
1122 } else
1123 message->flags |= status;
1124 continue;
1129 * Optionally defer deliveries over specific transports, unless the
1130 * restriction is lifted temporarily.
1132 if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DFXP) == 0) {
1133 if (defer_xport_argv == 0)
1134 defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,");
1135 for (cpp = defer_xport_argv->argv; *cpp; cpp++)
1136 if (strcmp(*cpp, STR(reply.transport)) == 0)
1137 break;
1138 if (*cpp) {
1139 QMGR_REDIRECT(&reply, MAIL_SERVICE_RETRY,
1140 "4.3.2 deferred transport");
1145 * Look up or instantiate the proper transport.
1147 if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) {
1148 if ((transport = qmgr_transport_find(STR(reply.transport))) == 0)
1149 transport = qmgr_transport_create(STR(reply.transport));
1150 queue = 0;
1154 * This message is being flushed. If need-be unthrottle the
1155 * transport.
1157 if ((message->qflags & QMGR_FLUSH_EACH) != 0
1158 && QMGR_TRANSPORT_THROTTLED(transport))
1159 qmgr_transport_unthrottle(transport);
1162 * This transport is dead. Defer delivery to this recipient.
1164 if (QMGR_TRANSPORT_THROTTLED(transport)) {
1165 saved_dsn = transport->dsn;
1166 if ((transport = qmgr_error_transport(MAIL_SERVICE_RETRY)) != 0) {
1167 nexthop = qmgr_error_nexthop(saved_dsn);
1168 vstring_strcpy(reply.nexthop, nexthop);
1169 myfree(nexthop);
1170 queue = 0;
1171 } else {
1172 qmgr_defer_recipient(message, recipient, saved_dsn);
1173 continue;
1178 * The nexthop destination provides the default name for the
1179 * per-destination queue. When the delivery agent accepts only one
1180 * recipient per delivery, give each recipient its own queue, so that
1181 * deliveries to different recipients of the same message can happen
1182 * in parallel, and so that we can enforce per-recipient concurrency
1183 * limits and prevent one recipient from tying up all the delivery
1184 * agent resources. We use recipient@nexthop as queue name rather
1185 * than the actual recipient domain name, so that one recipient in
1186 * multiple equivalent domains cannot evade the per-recipient
1187 * concurrency limit. Split the address on the recipient delimiter if
1188 * one is defined, so that extended addresses don't get extra
1189 * delivery slots.
1191 * Fold the result to lower case so that we don't have multiple queues
1192 * for the same name.
1194 * Important! All recipients in a queue must have the same nexthop
1195 * value. It is OK to have multiple queues with the same nexthop
1196 * value, but only when those queues are named after recipients.
1198 * The single-recipient code below was written for local(8) like
1199 * delivery agents, and assumes that all domains that deliver to the
1200 * same (transport + nexthop) are aliases for $nexthop. Delivery
1201 * concurrency is changed from per-domain into per-recipient, by
1202 * changing the queue name from nexthop into localpart@nexthop.
1204 * XXX This assumption is incorrect when different destinations share
1205 * the same (transport + nexthop). In reality, such transports are
1206 * rarely configured to use single-recipient deliveries. The fix is
1207 * to decouple the per-destination recipient limit from the
1208 * per-destination concurrency.
1210 vstring_strcpy(queue_name, STR(reply.nexthop));
1211 if (strcmp(transport->name, MAIL_SERVICE_ERROR) != 0
1212 && strcmp(transport->name, MAIL_SERVICE_RETRY) != 0
1213 && transport->recipient_limit == 1) {
1214 /* Copy the recipient localpart. */
1215 at = strrchr(STR(reply.recipient), '@');
1216 len = (at ? (at - STR(reply.recipient))
1217 : strlen(STR(reply.recipient)));
1218 vstring_strncpy(queue_name, STR(reply.recipient), len);
1219 /* Remove the address extension from the recipient localpart. */
1220 if (*var_rcpt_delim && split_addr(STR(queue_name), *var_rcpt_delim))
1221 vstring_truncate(queue_name, strlen(STR(queue_name)));
1222 /* Assume the recipient domain is equivalent to nexthop. */
1223 vstring_sprintf_append(queue_name, "@%s", STR(reply.nexthop));
1225 lowercase(STR(queue_name));
1228 * This transport is alive. Find or instantiate a queue for this
1229 * recipient.
1231 if (queue == 0 || !STREQ(queue->name, STR(queue_name))) {
1232 if ((queue = qmgr_queue_find(transport, STR(queue_name))) == 0)
1233 queue = qmgr_queue_create(transport, STR(queue_name),
1234 STR(reply.nexthop));
1238 * This message is being flushed. If need-be unthrottle the queue.
1240 if ((message->qflags & QMGR_FLUSH_EACH) != 0
1241 && QMGR_QUEUE_THROTTLED(queue))
1242 qmgr_queue_unthrottle(queue);
1245 * This queue is dead. Defer delivery to this recipient.
1247 if (QMGR_QUEUE_THROTTLED(queue)) {
1248 saved_dsn = queue->dsn;
1249 if ((queue = qmgr_error_queue(MAIL_SERVICE_RETRY, saved_dsn)) == 0) {
1250 qmgr_defer_recipient(message, recipient, saved_dsn);
1251 continue;
1256 * This queue is alive. Bind this recipient to this queue instance.
1258 recipient->u.queue = queue;
1260 resolve_clnt_free(&reply);
1261 vstring_free(queue_name);
1264 /* qmgr_message_assign - assign recipients to specific delivery requests */
1266 static void qmgr_message_assign(QMGR_MESSAGE *message)
1268 RECIPIENT_LIST list = message->rcpt_list;
1269 RECIPIENT *recipient;
1270 QMGR_ENTRY *entry = 0;
1271 QMGR_QUEUE *queue;
1272 QMGR_JOB *job = 0;
1273 QMGR_PEER *peer = 0;
1276 * Try to bundle as many recipients in a delivery request as we can. When
1277 * the recipient resolves to the same site and transport as an existing
1278 * recipient, do not create a new queue entry, just move that recipient
1279 * to the recipient list of the existing queue entry. All this provided
1280 * that we do not exceed the transport-specific limit on the number of
1281 * recipients per transaction.
1283 #define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit)))
1285 for (recipient = list.info; recipient < list.info + list.len; recipient++) {
1288 * Skip recipients with a dead transport or destination.
1290 if ((queue = recipient->u.queue) == 0)
1291 continue;
1294 * Lookup or instantiate the message job if necessary.
1296 if (job == 0 || queue->transport != job->transport) {
1297 job = qmgr_job_obtain(message, queue->transport);
1298 peer = 0;
1302 * Lookup or instantiate job peer if necessary.
1304 if (peer == 0 || queue != peer->queue)
1305 peer = qmgr_peer_obtain(job, queue);
1308 * Lookup old or instantiate new recipient entry. We try to reuse the
1309 * last existing entry whenever the recipient limit permits.
1311 entry = peer->entry_list.prev;
1312 if (message->single_rcpt || entry == 0
1313 || !LIMIT_OK(queue->transport->recipient_limit, entry->rcpt_list.len))
1314 entry = qmgr_entry_create(peer, message);
1317 * Add the recipient to the current entry and increase all those
1318 * recipient counters accordingly.
1320 recipient_list_add(&entry->rcpt_list, recipient->offset,
1321 recipient->dsn_orcpt, recipient->dsn_notify,
1322 recipient->orig_addr, recipient->address);
1323 job->rcpt_count++;
1324 message->rcpt_count++;
1325 qmgr_recipient_count++;
1329 * Release the message recipient list and reinitialize it for the next
1330 * time.
1332 recipient_list_free(&message->rcpt_list);
1333 recipient_list_init(&message->rcpt_list, RCPT_LIST_INIT_QUEUE);
1336 * Note that even if qmgr_job_obtain() reset the job candidate cache of
1337 * all transports to which we assigned new recipients, this message may
1338 * have other jobs which we didn't touch at all this time. But the number
1339 * of unread recipients affecting the candidate selection might have
1340 * changed considerably, so we must invalidate the caches if it might be
1341 * of some use.
1343 for (job = message->job_list.next; job; job = job->message_peers.next)
1344 if (job->selected_entries < job->read_entries
1345 && job->blocker_tag != job->transport->blocker_tag)
1346 job->transport->candidate_cache_current = 0;
1349 /* qmgr_message_move_limits - recycle unused recipient slots */
1351 static void qmgr_message_move_limits(QMGR_MESSAGE *message)
1353 QMGR_JOB *job;
1355 for (job = message->job_list.next; job; job = job->message_peers.next)
1356 qmgr_job_move_limits(job);
1359 /* qmgr_message_free - release memory for in-core message structure */
1361 void qmgr_message_free(QMGR_MESSAGE *message)
1363 QMGR_JOB *job;
1365 if (message->refcount != 0)
1366 msg_panic("qmgr_message_free: reference len: %d", message->refcount);
1367 if (message->fp)
1368 msg_panic("qmgr_message_free: queue file is open");
1369 while ((job = message->job_list.next) != 0)
1370 qmgr_job_free(job);
1371 myfree(message->queue_id);
1372 myfree(message->queue_name);
1373 if (message->dsn_envid)
1374 myfree(message->dsn_envid);
1375 if (message->encoding)
1376 myfree(message->encoding);
1377 if (message->sender)
1378 myfree(message->sender);
1379 if (message->verp_delims)
1380 myfree(message->verp_delims);
1381 if (message->filter_xport)
1382 myfree(message->filter_xport);
1383 if (message->inspect_xport)
1384 myfree(message->inspect_xport);
1385 if (message->redirect_addr)
1386 myfree(message->redirect_addr);
1387 if (message->client_name)
1388 myfree(message->client_name);
1389 if (message->client_addr)
1390 myfree(message->client_addr);
1391 if (message->client_port)
1392 myfree(message->client_port);
1393 if (message->client_proto)
1394 myfree(message->client_proto);
1395 if (message->client_helo)
1396 myfree(message->client_helo);
1397 if (message->sasl_method)
1398 myfree(message->sasl_method);
1399 if (message->sasl_username)
1400 myfree(message->sasl_username);
1401 if (message->sasl_sender)
1402 myfree(message->sasl_sender);
1403 if (message->rewrite_context)
1404 myfree(message->rewrite_context);
1405 recipient_list_free(&message->rcpt_list);
1406 qmgr_message_count--;
1407 myfree((char *) message);
1410 /* qmgr_message_alloc - create in-core message structure */
1412 QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id,
1413 int qflags, mode_t mode)
1415 const char *myname = "qmgr_message_alloc";
1416 QMGR_MESSAGE *message;
1418 if (msg_verbose)
1419 msg_info("%s: %s %s", myname, queue_name, queue_id);
1422 * Create an in-core message structure.
1424 message = qmgr_message_create(queue_name, queue_id, qflags);
1427 * Extract message envelope information: time of arrival, sender address,
1428 * recipient addresses. Skip files with malformed envelope information.
1430 #define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)
1432 if (qmgr_message_open(message) < 0) {
1433 qmgr_message_free(message);
1434 return (0);
1436 if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) {
1437 msg_info("%s: skipped, still being delivered", queue_id);
1438 qmgr_message_close(message);
1439 qmgr_message_free(message);
1440 return (QMGR_MESSAGE_LOCKED);
1442 if (qmgr_message_read(message) < 0) {
1443 qmgr_message_close(message);
1444 qmgr_message_free(message);
1445 return (0);
1446 } else {
1449 * We have validated the queue file content, so it is safe to modify
1450 * the file properties now.
1452 if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0)
1453 msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp));
1456 * Reset the defer log. This code should not be here, but we must
1457 * reset the defer log *after* acquiring the exclusive lock on the
1458 * queue file and *before* resolving new recipients. Since all those
1459 * operations are encapsulated so nicely by this routine, the defer
1460 * log reset has to be done here as well.
1462 * Note: it is safe to remove the defer logfile from a previous queue
1463 * run of this queue file, because the defer log contains information
1464 * about recipients that still exist in this queue file.
1466 if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
1467 msg_fatal("%s: %s: remove %s %s: %m", myname,
1468 queue_id, MAIL_QUEUE_DEFER, queue_id);
1469 qmgr_message_sort(message);
1470 qmgr_message_resolve(message);
1471 qmgr_message_sort(message);
1472 qmgr_message_assign(message);
1473 qmgr_message_close(message);
1474 if (message->rcpt_offset == 0)
1475 qmgr_message_move_limits(message);
1476 return (message);
1480 /* qmgr_message_realloc - refresh in-core message structure */
1482 QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *message)
1484 const char *myname = "qmgr_message_realloc";
1487 * Sanity checks.
1489 if (message->rcpt_offset <= 0)
1490 msg_panic("%s: invalid offset: %ld", myname, message->rcpt_offset);
1491 if (msg_verbose)
1492 msg_info("%s: %s %s offset %ld", myname, message->queue_name,
1493 message->queue_id, message->rcpt_offset);
1496 * Extract recipient addresses. Skip files with malformed envelope
1497 * information.
1499 if (qmgr_message_open(message) < 0)
1500 return (0);
1501 if (qmgr_message_read(message) < 0) {
1502 qmgr_message_close(message);
1503 return (0);
1504 } else {
1505 qmgr_message_sort(message);
1506 qmgr_message_resolve(message);
1507 qmgr_message_sort(message);
1508 qmgr_message_assign(message);
1509 qmgr_message_close(message);
1510 if (message->rcpt_offset == 0)
1511 qmgr_message_move_limits(message);
1512 return (message);