xref: /openbsd/usr.sbin/smtpd/bounce.c (revision 55cc5ba3)
1 /*	$OpenBSD: bounce.c,v 1.83 2020/12/31 08:27:15 martijn Exp $	*/
2 
3 /*
4  * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org>
5  * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
6  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/tree.h>
24 #include <sys/socket.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <event.h>
29 #include <imsg.h>
30 #include <inttypes.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #include <unistd.h>
38 #include <limits.h>
39 
40 #include "smtpd.h"
41 #include "log.h"
42 
43 #define BOUNCE_MAXRUN	2
44 #define BOUNCE_HIWAT	65535
45 
46 enum {
47 	BOUNCE_EHLO,
48 	BOUNCE_MAIL,
49 	BOUNCE_RCPT,
50 	BOUNCE_DATA,
51 	BOUNCE_DATA_NOTICE,
52 	BOUNCE_DATA_MESSAGE,
53 	BOUNCE_DATA_END,
54 	BOUNCE_QUIT,
55 	BOUNCE_CLOSE,
56 };
57 
58 struct bounce_envelope {
59 	TAILQ_ENTRY(bounce_envelope)	 entry;
60 	uint64_t			 id;
61 	struct mailaddr			 dest;
62 	char				*report;
63 	uint8_t				 esc_class;
64 	uint8_t				 esc_code;
65 };
66 
67 struct bounce_message {
68 	SPLAY_ENTRY(bounce_message)	 sp_entry;
69 	TAILQ_ENTRY(bounce_message)	 entry;
70 	uint32_t			 msgid;
71 	struct delivery_bounce		 bounce;
72 	char				*smtpname;
73 	char				*to;
74 	time_t				 timeout;
75 	TAILQ_HEAD(, bounce_envelope)	 envelopes;
76 };
77 
78 struct bounce_session {
79 	char				*smtpname;
80 	struct bounce_message		*msg;
81 	FILE				*msgfp;
82 	int				 state;
83 	struct io			*io;
84 	uint64_t			 boundary;
85 };
86 
87 SPLAY_HEAD(bounce_message_tree, bounce_message);
88 static int bounce_message_cmp(const struct bounce_message *,
89     const struct bounce_message *);
90 SPLAY_PROTOTYPE(bounce_message_tree, bounce_message, sp_entry,
91     bounce_message_cmp);
92 
93 static void bounce_drain(void);
94 static void bounce_send(struct bounce_session *, const char *, ...);
95 static int  bounce_next_message(struct bounce_session *);
96 static int  bounce_next(struct bounce_session *);
97 static void bounce_delivery(struct bounce_message *, int, const char *);
98 static void bounce_status(struct bounce_session *, const char *, ...);
99 static void bounce_io(struct io *, int, void *);
100 static void bounce_timeout(int, short, void *);
101 static void bounce_free(struct bounce_session *);
102 static const char *action_str(const struct delivery_bounce *);
103 
104 static struct tree			wait_fd;
105 static struct bounce_message_tree	messages;
106 static TAILQ_HEAD(, bounce_message)	pending;
107 
108 static int				nmessage = 0;
109 static int				running = 0;
110 static struct event			ev_timer;
111 
112 static void
113 bounce_init(void)
114 {
115 	static int	init = 0;
116 
117 	if (init == 0) {
118 		TAILQ_INIT(&pending);
119 		SPLAY_INIT(&messages);
120 		tree_init(&wait_fd);
121 		evtimer_set(&ev_timer, bounce_timeout, NULL);
122 		init = 1;
123 	}
124 }
125 
126 void
127 bounce_add(uint64_t evpid)
128 {
129 	char			 buf[LINE_MAX], *line;
130 	struct envelope		 evp;
131 	struct bounce_message	 key, *msg;
132 	struct bounce_envelope	*be;
133 
134 	bounce_init();
135 
136 	if (queue_envelope_load(evpid, &evp) == 0) {
137 		m_create(p_scheduler, IMSG_QUEUE_DELIVERY_PERMFAIL, 0, 0, -1);
138 		m_add_evpid(p_scheduler, evpid);
139 		m_close(p_scheduler);
140 		return;
141 	}
142 
143 	if (evp.type != D_BOUNCE)
144 		errx(1, "bounce: evp:%016" PRIx64 " is not of type D_BOUNCE!",
145 		    evp.id);
146 
147 	key.msgid = evpid_to_msgid(evpid);
148 	key.bounce = evp.agent.bounce;
149 	key.smtpname = evp.smtpname;
150 
151 	switch (evp.esc_class) {
152 	case ESC_STATUS_OK:
153 		key.bounce.type = B_DELIVERED;
154 		break;
155 	case ESC_STATUS_TEMPFAIL:
156 		key.bounce.type = B_DELAYED;
157 		break;
158 	default:
159 		key.bounce.type = B_FAILED;
160 	}
161 
162 	key.bounce.dsn_ret = evp.dsn_ret;
163 	key.bounce.ttl = evp.ttl;
164 	msg = SPLAY_FIND(bounce_message_tree, &messages, &key);
165 	if (msg == NULL) {
166 		msg = xcalloc(1, sizeof(*msg));
167 		msg->msgid = key.msgid;
168 		msg->bounce = key.bounce;
169 
170 		TAILQ_INIT(&msg->envelopes);
171 
172 		msg->smtpname = xstrdup(evp.smtpname);
173 		(void)snprintf(buf, sizeof(buf), "%s@%s", evp.sender.user,
174 		    evp.sender.domain);
175 		msg->to = xstrdup(buf);
176 		nmessage += 1;
177 		SPLAY_INSERT(bounce_message_tree, &messages, msg);
178 		log_debug("debug: bounce: new message %08" PRIx32,
179 		    msg->msgid);
180 		stat_increment("bounce.message", 1);
181 	} else
182 		TAILQ_REMOVE(&pending, msg, entry);
183 
184 	line = evp.errorline;
185 	if (strlen(line) > 4 && (*line == '1' || *line == '6'))
186 		line += 4;
187 	(void)snprintf(buf, sizeof(buf), "%s@%s: %s", evp.dest.user,
188 	    evp.dest.domain, line);
189 
190 	be = xmalloc(sizeof *be);
191 	be->id = evpid;
192 	be->report = xstrdup(buf);
193 	(void)strlcpy(be->dest.user, evp.dest.user, sizeof(be->dest.user));
194 	(void)strlcpy(be->dest.domain, evp.dest.domain,
195 	    sizeof(be->dest.domain));
196 	be->esc_class = evp.esc_class;
197 	be->esc_code = evp.esc_code;
198 	TAILQ_INSERT_TAIL(&msg->envelopes, be, entry);
199 	log_debug("debug: bounce: adding report %16"PRIx64": %s", be->id, be->report);
200 
201 	msg->timeout = time(NULL) + 1;
202 	TAILQ_INSERT_TAIL(&pending, msg, entry);
203 
204 	stat_increment("bounce.envelope", 1);
205 	bounce_drain();
206 }
207 
208 void
209 bounce_fd(int fd)
210 {
211 	struct bounce_session	*s;
212 	struct bounce_message	*msg;
213 
214 	log_debug("debug: bounce: got enqueue socket %d", fd);
215 
216 	if (fd == -1 || TAILQ_EMPTY(&pending)) {
217 		log_debug("debug: bounce: cancelling");
218 		if (fd != -1)
219 			close(fd);
220 		running -= 1;
221 		bounce_drain();
222 		return;
223 	}
224 
225 	msg = TAILQ_FIRST(&pending);
226 
227 	s = xcalloc(1, sizeof(*s));
228 	s->smtpname = xstrdup(msg->smtpname);
229 	s->state = BOUNCE_EHLO;
230 	s->io = io_new();
231 	io_set_callback(s->io, bounce_io, s);
232 	io_set_fd(s->io, fd);
233 	io_set_timeout(s->io, 30000);
234 	io_set_read(s->io);
235 	s->boundary = generate_uid();
236 
237 	log_debug("debug: bounce: new session %p", s);
238 	stat_increment("bounce.session", 1);
239 }
240 
241 static void
242 bounce_timeout(int fd, short ev, void *arg)
243 {
244 	log_debug("debug: bounce: timeout");
245 
246 	bounce_drain();
247 }
248 
249 static void
250 bounce_drain()
251 {
252 	struct bounce_message	*msg;
253 	struct timeval		 tv;
254 	time_t			 t;
255 
256 	log_debug("debug: bounce: drain: nmessage=%d running=%d",
257 	    nmessage, running);
258 
259 	while (1) {
260 		if (running >= BOUNCE_MAXRUN) {
261 			log_debug("debug: bounce: max session reached");
262 			return;
263 		}
264 
265 		if (nmessage == 0) {
266 			log_debug("debug: bounce: no more messages");
267 			return;
268 		}
269 
270 		if (running >= nmessage) {
271 			log_debug("debug: bounce: enough sessions running");
272 			return;
273 		}
274 
275 		if ((msg = TAILQ_FIRST(&pending)) == NULL) {
276 			log_debug("debug: bounce: no more pending messages");
277 			return;
278 		}
279 
280 		t = time(NULL);
281 		if (msg->timeout > t) {
282 			log_debug("debug: bounce: next message not ready yet");
283 			if (!evtimer_pending(&ev_timer, NULL)) {
284 				log_debug("debug: bounce: setting timer");
285 				tv.tv_sec = msg->timeout - t;
286 				tv.tv_usec = 0;
287 				evtimer_add(&ev_timer, &tv);
288 			}
289 			return;
290 		}
291 
292 		log_debug("debug: bounce: requesting new enqueue socket...");
293 		m_compose(p_dispatcher, IMSG_QUEUE_SMTP_SESSION, 0, 0, -1, NULL, 0);
294 
295 		running += 1;
296 	}
297 }
298 
299 static void
300 bounce_send(struct bounce_session *s, const char *fmt, ...)
301 {
302 	va_list	 ap;
303 	char	*p;
304 	int	 len;
305 
306 	va_start(ap, fmt);
307 	if ((len = vasprintf(&p, fmt, ap)) == -1)
308 		fatal("bounce: vasprintf");
309 	va_end(ap);
310 
311 	log_trace(TRACE_BOUNCE, "bounce: %p: >>> %s", s, p);
312 
313 	io_xprintf(s->io, "%s\r\n", p);
314 
315 	free(p);
316 }
317 
318 static const char *
319 bounce_duration(long long int d)
320 {
321 	static char buf[32];
322 
323 	if (d < 60) {
324 		(void)snprintf(buf, sizeof buf, "%lld second%s", d,
325 		    (d == 1) ? "" : "s");
326 	} else if (d < 3600) {
327 		d = d / 60;
328 		(void)snprintf(buf, sizeof buf, "%lld minute%s", d,
329 		    (d == 1) ? "" : "s");
330 	}
331 	else if (d < 3600 * 24) {
332 		d = d / 3600;
333 		(void)snprintf(buf, sizeof buf, "%lld hour%s", d,
334 		    (d == 1) ? "" : "s");
335 	}
336 	else {
337 		d = d / (3600 * 24);
338 		(void)snprintf(buf, sizeof buf, "%lld day%s", d,
339 		    (d == 1) ? "" : "s");
340 	}
341 	return (buf);
342 }
343 
344 #define NOTICE_INTRO							    \
345 	"    Hi!\r\n\r\n"						    \
346 	"    This is the MAILER-DAEMON, please DO NOT REPLY to this email.\r\n"
347 
348 const char *notice_error =
349     "    An error has occurred while attempting to deliver a message for\r\n"
350     "    the following list of recipients:\r\n\r\n";
351 
352 const char *notice_warning =
353     "    A message is delayed for more than %s for the following\r\n"
354     "    list of recipients:\r\n\r\n";
355 
356 const char *notice_warning2 =
357     "    Please note that this is only a temporary failure report.\r\n"
358     "    The message is kept in the queue for up to %s.\r\n"
359     "    You DO NOT NEED to re-send the message to these recipients.\r\n\r\n";
360 
361 const char *notice_success =
362     "    Your message was successfully delivered to these recipients.\r\n\r\n";
363 
364 const char *notice_relay =
365     "    Your message was relayed to these recipients.\r\n\r\n";
366 
367 static int
368 bounce_next_message(struct bounce_session *s)
369 {
370 	struct bounce_message	*msg;
371 	char			 buf[LINE_MAX];
372 	int			 fd;
373 	time_t			 now;
374 
375     again:
376 
377 	now = time(NULL);
378 
379 	TAILQ_FOREACH(msg, &pending, entry) {
380 		if (msg->timeout > now)
381 			continue;
382 		if (strcmp(msg->smtpname, s->smtpname))
383 			continue;
384 		break;
385 	}
386 	if (msg == NULL)
387 		return (0);
388 
389 	TAILQ_REMOVE(&pending, msg, entry);
390 	SPLAY_REMOVE(bounce_message_tree, &messages, msg);
391 
392 	if ((fd = queue_message_fd_r(msg->msgid)) == -1) {
393 		bounce_delivery(msg, IMSG_QUEUE_DELIVERY_TEMPFAIL,
394 		    "Could not open message fd");
395 		goto again;
396 	}
397 
398 	if ((s->msgfp = fdopen(fd, "r")) == NULL) {
399 		(void)snprintf(buf, sizeof(buf), "fdopen: %s", strerror(errno));
400 		log_warn("warn: bounce: fdopen");
401 		close(fd);
402 		bounce_delivery(msg, IMSG_QUEUE_DELIVERY_TEMPFAIL, buf);
403 		goto again;
404 	}
405 
406 	s->msg = msg;
407 	return (1);
408 }
409 
410 static int
411 bounce_next(struct bounce_session *s)
412 {
413 	struct bounce_envelope	*evp;
414 	char			*line = NULL;
415 	size_t			 n, sz = 0;
416 	ssize_t			 len;
417 
418 	switch (s->state) {
419 	case BOUNCE_EHLO:
420 		bounce_send(s, "EHLO %s", s->smtpname);
421 		s->state = BOUNCE_MAIL;
422 		break;
423 
424 	case BOUNCE_MAIL:
425 	case BOUNCE_DATA_END:
426 		log_debug("debug: bounce: %p: getting next message...", s);
427 		if (bounce_next_message(s) == 0) {
428 			log_debug("debug: bounce: %p: no more messages", s);
429 			bounce_send(s, "QUIT");
430 			s->state = BOUNCE_CLOSE;
431 			break;
432 		}
433 		log_debug("debug: bounce: %p: found message %08"PRIx32,
434 		    s, s->msg->msgid);
435 		bounce_send(s, "MAIL FROM: <>");
436 		s->state = BOUNCE_RCPT;
437 		break;
438 
439 	case BOUNCE_RCPT:
440 		bounce_send(s, "RCPT TO: <%s>", s->msg->to);
441 		s->state = BOUNCE_DATA;
442 		break;
443 
444 	case BOUNCE_DATA:
445 		bounce_send(s, "DATA");
446 		s->state = BOUNCE_DATA_NOTICE;
447 		break;
448 
449 	case BOUNCE_DATA_NOTICE:
450 		/* Construct an appropriate notice. */
451 
452 		io_xprintf(s->io,
453 		    "Subject: Delivery status notification: %s\r\n"
454 		    "From: Mailer Daemon <MAILER-DAEMON@%s>\r\n"
455 		    "To: %s\r\n"
456 		    "Date: %s\r\n"
457 		    "MIME-Version: 1.0\r\n"
458 		    "Content-Type: multipart/mixed;"
459 		    "boundary=\"%16" PRIu64 "/%s\"\r\n"
460 		    "\r\n"
461 		    "This is a MIME-encapsulated message.\r\n"
462 		    "\r\n",
463 		    action_str(&s->msg->bounce),
464 		    s->smtpname,
465 		    s->msg->to,
466 		    time_to_text(time(NULL)),
467 		    s->boundary,
468 		    s->smtpname);
469 
470 		io_xprintf(s->io,
471 		    "--%16" PRIu64 "/%s\r\n"
472 		    "Content-Description: Notification\r\n"
473 		    "Content-Type: text/plain; charset=us-ascii\r\n"
474 		    "\r\n"
475 		    NOTICE_INTRO
476 		    "\r\n",
477 		    s->boundary, s->smtpname);
478 
479 		switch (s->msg->bounce.type) {
480 		case B_FAILED:
481 			io_xprint(s->io, notice_error);
482 			break;
483 		case B_DELAYED:
484 			io_xprintf(s->io, notice_warning,
485 			    bounce_duration(s->msg->bounce.delay));
486 			break;
487 		case B_DELIVERED:
488 			io_xprint(s->io, s->msg->bounce.mta_without_dsn ?
489 			    notice_relay : notice_success);
490 			break;
491 		default:
492 			log_warn("warn: bounce: unknown bounce_type");
493 		}
494 
495 		TAILQ_FOREACH(evp, &s->msg->envelopes, entry) {
496 			io_xprint(s->io, evp->report);
497 			io_xprint(s->io, "\r\n");
498 		}
499 		io_xprint(s->io, "\r\n");
500 
501 		if (s->msg->bounce.type == B_DELAYED)
502 			io_xprintf(s->io, notice_warning2,
503 			    bounce_duration(s->msg->bounce.ttl));
504 
505 		io_xprintf(s->io,
506 		    "    Below is a copy of the original message:\r\n"
507 		    "\r\n");
508 
509 		io_xprintf(s->io,
510 		    "--%16" PRIu64 "/%s\r\n"
511 		    "Content-Description: Delivery Report\r\n"
512 		    "Content-Type: message/delivery-status\r\n"
513 		    "\r\n",
514 		    s->boundary, s->smtpname);
515 
516 		io_xprintf(s->io,
517 		    "Reporting-MTA: dns; %s\r\n"
518 		    "\r\n",
519 		    s->smtpname);
520 
521 		TAILQ_FOREACH(evp, &s->msg->envelopes, entry) {
522 			io_xprintf(s->io,
523 			    "Final-Recipient: rfc822; %s@%s\r\n"
524 			    "Action: %s\r\n"
525 			    "Status: %s\r\n"
526 			    "\r\n",
527 			    evp->dest.user,
528 			    evp->dest.domain,
529 			    action_str(&s->msg->bounce),
530 			    esc_code(evp->esc_class, evp->esc_code));
531 		}
532 
533 		log_trace(TRACE_BOUNCE, "bounce: %p: >>> [... %zu bytes ...]",
534 		    s, io_queued(s->io));
535 
536 		s->state = BOUNCE_DATA_MESSAGE;
537 		break;
538 
539 	case BOUNCE_DATA_MESSAGE:
540 		io_xprintf(s->io,
541 		    "--%16" PRIu64 "/%s\r\n"
542 		    "Content-Description: Message headers\r\n"
543 		    "Content-Type: text/rfc822-headers\r\n"
544 		    "\r\n",
545 		    s->boundary, s->smtpname);
546 
547 		n = io_queued(s->io);
548 		while (io_queued(s->io) < BOUNCE_HIWAT) {
549 			if ((len = getline(&line, &sz, s->msgfp)) == -1)
550 				break;
551 			if (len == 1 && line[0] == '\n' && /* end of headers */
552 			    s->msg->bounce.type == B_DELIVERED &&
553 			    s->msg->bounce.dsn_ret ==  DSN_RETHDRS) {
554 				free(line);
555 				fclose(s->msgfp);
556 				s->msgfp = NULL;
557 				io_xprintf(s->io,
558 				    "\r\n--%16" PRIu64 "/%s--\r\n", s->boundary,
559 				    s->smtpname);
560 				bounce_send(s, ".");
561 				s->state = BOUNCE_DATA_END;
562 				return (0);
563 			}
564 			line[len - 1] = '\0';
565 			io_xprintf(s->io, "%s%s\r\n",
566 			    (len == 2 && line[0] == '.') ? "." : "", line);
567 		}
568 		free(line);
569 
570 		if (ferror(s->msgfp)) {
571 			fclose(s->msgfp);
572 			s->msgfp = NULL;
573 			bounce_delivery(s->msg, IMSG_QUEUE_DELIVERY_TEMPFAIL,
574 			    "Error reading message");
575 			s->msg = NULL;
576 			return (-1);
577 		}
578 
579 		io_xprintf(s->io,
580 		    "\r\n--%16" PRIu64 "/%s--\r\n", s->boundary, s->smtpname);
581 
582 		log_trace(TRACE_BOUNCE, "bounce: %p: >>> [... %zu bytes ...]",
583 		    s, io_queued(s->io) - n);
584 
585 		if (feof(s->msgfp)) {
586 			fclose(s->msgfp);
587 			s->msgfp = NULL;
588 			bounce_send(s, ".");
589 			s->state = BOUNCE_DATA_END;
590 		}
591 		break;
592 
593 	case BOUNCE_QUIT:
594 		bounce_send(s, "QUIT");
595 		s->state = BOUNCE_CLOSE;
596 		break;
597 
598 	default:
599 		fatalx("bounce: bad state");
600 	}
601 
602 	return (0);
603 }
604 
605 
606 static void
607 bounce_delivery(struct bounce_message *msg, int delivery, const char *status)
608 {
609 	struct bounce_envelope	*be;
610 	struct envelope		 evp;
611 	size_t			 n;
612 	const char		*f;
613 
614 	n = 0;
615 	while ((be = TAILQ_FIRST(&msg->envelopes))) {
616 		if (delivery == IMSG_QUEUE_DELIVERY_TEMPFAIL) {
617 			if (queue_envelope_load(be->id, &evp) == 0) {
618 				fatalx("could not reload envelope!");
619 			}
620 			evp.retry++;
621 			evp.lasttry = msg->timeout;
622 			envelope_set_errormsg(&evp, "%s", status);
623 			queue_envelope_update(&evp);
624 			m_create(p_scheduler, delivery, 0, 0, -1);
625 			m_add_envelope(p_scheduler, &evp);
626 			m_close(p_scheduler);
627 		} else {
628 			m_create(p_scheduler, delivery, 0, 0, -1);
629 			m_add_evpid(p_scheduler, be->id);
630 			m_close(p_scheduler);
631 			queue_envelope_delete(be->id);
632 		}
633 		TAILQ_REMOVE(&msg->envelopes, be, entry);
634 		free(be->report);
635 		free(be);
636 		n += 1;
637 	}
638 
639 
640 	if (delivery == IMSG_QUEUE_DELIVERY_TEMPFAIL)
641 		f = "TempFail";
642 	else if (delivery == IMSG_QUEUE_DELIVERY_PERMFAIL)
643 		f = "PermFail";
644 	else
645 		f = NULL;
646 
647 	if (f)
648 		log_warnx("warn: %s injecting failure report on message %08"
649 		    PRIx32 " to <%s> for %zu envelope%s: %s",
650 		    f, msg->msgid, msg->to, n, n > 1 ? "s":"", status);
651 
652 	nmessage -= 1;
653 	stat_decrement("bounce.message", 1);
654 	stat_decrement("bounce.envelope", n);
655 	free(msg->smtpname);
656 	free(msg->to);
657 	free(msg);
658 }
659 
660 static void
661 bounce_status(struct bounce_session *s, const char *fmt, ...)
662 {
663 	va_list		 ap;
664 	char		*status;
665 	int		 len, delivery;
666 
667 	/* Ignore if there is no message */
668 	if (s->msg == NULL)
669 		return;
670 
671 	va_start(ap, fmt);
672 	if ((len = vasprintf(&status, fmt, ap)) == -1)
673 		fatal("bounce: vasprintf");
674 	va_end(ap);
675 
676 	if (*status == '2')
677 		delivery = IMSG_QUEUE_DELIVERY_OK;
678 	else if (*status == '5' || *status == '6')
679 		delivery = IMSG_QUEUE_DELIVERY_PERMFAIL;
680 	else
681 		delivery = IMSG_QUEUE_DELIVERY_TEMPFAIL;
682 
683 	bounce_delivery(s->msg, delivery, status);
684 	s->msg = NULL;
685 	if (s->msgfp)
686 		fclose(s->msgfp);
687 
688 	free(status);
689 }
690 
691 static void
692 bounce_free(struct bounce_session *s)
693 {
694 	log_debug("debug: bounce: %p: deleting session", s);
695 
696 	io_free(s->io);
697 
698 	free(s->smtpname);
699 	free(s);
700 
701 	running -= 1;
702 	stat_decrement("bounce.session", 1);
703 	bounce_drain();
704 }
705 
706 static void
707 bounce_io(struct io *io, int evt, void *arg)
708 {
709 	struct bounce_session	*s = arg;
710 	const char		*error;
711 	char			*line, *msg;
712 	int			 cont;
713 	size_t			 len;
714 
715 	log_trace(TRACE_IO, "bounce: %p: %s %s", s, io_strevent(evt),
716 	    io_strio(io));
717 
718 	switch (evt) {
719 	case IO_DATAIN:
720 	    nextline:
721 		line = io_getline(s->io, &len);
722 		if (line == NULL && io_datalen(s->io) >= LINE_MAX) {
723 			bounce_status(s, "Input too long");
724 			bounce_free(s);
725 			return;
726 		}
727 
728 		if (line == NULL)
729 			break;
730 
731 		/* Strip trailing '\r' */
732 		if (len && line[len - 1] == '\r')
733 			line[--len] = '\0';
734 
735 		log_trace(TRACE_BOUNCE, "bounce: %p: <<< %s", s, line);
736 
737 		if ((error = parse_smtp_response(line, len, &msg, &cont))) {
738 			bounce_status(s, "Bad response: %s", error);
739 			bounce_free(s);
740 			return;
741 		}
742 		if (cont)
743 			goto nextline;
744 
745 		if (s->state == BOUNCE_CLOSE) {
746 			bounce_free(s);
747 			return;
748 		}
749 
750 		if (line[0] != '2' && line[0] != '3') {		/* fail */
751 			bounce_status(s, "%s", line);
752 			s->state = BOUNCE_QUIT;
753 		} else if (s->state == BOUNCE_DATA_END) {	/* accepted */
754 			bounce_status(s, "%s", line);
755 		}
756 
757 		if (bounce_next(s) == -1) {
758 			bounce_free(s);
759 			return;
760 		}
761 
762 		io_set_write(io);
763 		break;
764 
765 	case IO_LOWAT:
766 		if (s->state == BOUNCE_DATA_MESSAGE)
767 			if (bounce_next(s) == -1) {
768 				bounce_free(s);
769 				return;
770 			}
771 		if (io_queued(s->io) == 0)
772 			io_set_read(io);
773 		break;
774 
775 	default:
776 		bounce_status(s, "442 i/o error %d", evt);
777 		bounce_free(s);
778 		break;
779 	}
780 }
781 
782 static int
783 bounce_message_cmp(const struct bounce_message *a,
784     const struct bounce_message *b)
785 {
786 	int r;
787 
788 	if (a->msgid < b->msgid)
789 		return (-1);
790 	if (a->msgid > b->msgid)
791 		return (1);
792 	if ((r = strcmp(a->smtpname, b->smtpname)))
793 		return (r);
794 
795 	return memcmp(&a->bounce, &b->bounce, sizeof (a->bounce));
796 }
797 
798 static const char *
799 action_str(const struct delivery_bounce *b)
800 {
801 	switch (b->type) {
802 	case B_FAILED:
803 		return ("failed");
804 	case B_DELAYED:
805 		return ("delayed");
806 	case B_DELIVERED:
807 		if (b->mta_without_dsn)
808 			return ("relayed");
809 
810 		return ("delivered");
811 	default:
812 		log_warn("warn: bounce: unknown bounce_type");
813 		return ("");
814 	}
815 }
816 
817 SPLAY_GENERATE(bounce_message_tree, bounce_message, sp_entry,
818     bounce_message_cmp);
819