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