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); }; |