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