| File: | src/usr.sbin/smtpd/smtpd/../bounce.c |
| Warning: | line 296, column 7 Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len' |
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) |
Although the value stored to 'len' is used in the enclosing expression, the value is never actually read from 'len' | |
| 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 == IMSG_QUEUE_DELIVERY_TEMPFAIL) { |
| 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); }; |