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