File: | src/usr.sbin/smtpd/smtpd/../bounce.c |
Warning: | line 607, column 28 Use of memory after it is freed |
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) | ||||
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
| ||||
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); }; |