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