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