This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / usr.sbin / sendmail / src / savemail.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1983 Eric P. Allman
6f14531a
RG
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
6f14531a 36static char sccsid[] = "@(#)savemail.c 8.1 (Berkeley) 6/7/93";
15637ed4
RG
37#endif /* not lint */
38
15637ed4
RG
39# include <pwd.h>
40# include "sendmail.h"
41
42/*
43** SAVEMAIL -- Save mail on error
44**
45** If mailing back errors, mail it back to the originator
46** together with an error message; otherwise, just put it in
47** dead.letter in the user's home directory (if he exists on
48** this machine).
49**
50** Parameters:
51** e -- the envelope containing the message in error.
52**
53** Returns:
54** none
55**
56** Side Effects:
57** Saves the letter, by writing or mailing it back to the
58** sender, or by putting it in dead.letter in her home
59** directory.
60*/
61
62/* defines for state machine */
63# define ESM_REPORT 0 /* report to sender's terminal */
64# define ESM_MAIL 1 /* mail back to sender */
65# define ESM_QUIET 2 /* messages have already been returned */
66# define ESM_DEADLETTER 3 /* save in ~/dead.letter */
67# define ESM_POSTMASTER 4 /* return to postmaster */
68# define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */
69# define ESM_PANIC 6 /* leave the locked queue/transcript files */
70# define ESM_DONE 7 /* the message is successfully delivered */
71
72
73savemail(e)
74 register ENVELOPE *e;
75{
76 register struct passwd *pw;
77 register FILE *fp;
78 int state;
6f14531a 79 auto ADDRESS *q = NULL;
15637ed4
RG
80 char buf[MAXLINE+1];
81 extern struct passwd *getpwnam();
82 register char *p;
83 extern char *ttypath();
84 typedef int (*fnptr)();
85
86 if (tTd(6, 1))
6f14531a
RG
87 {
88 printf("\nsavemail, errormode = %c, id = %s\n e_from=",
89 e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id);
90 printaddr(&e->e_from, FALSE);
91 }
15637ed4 92
6f14531a 93 if (e->e_id == NULL)
15637ed4 94 {
6f14531a 95 /* can't return a message with no id */
15637ed4
RG
96 return;
97 }
6f14531a 98
15637ed4
RG
99 e->e_flags &= ~EF_FATALERRS;
100
101 /*
102 ** In the unhappy event we don't know who to return the mail
103 ** to, make someone up.
104 */
105
106 if (e->e_from.q_paddr == NULL)
107 {
6f14531a
RG
108 e->e_sender = "Postmaster";
109 if (parseaddr(e->e_sender, &e->e_from, 0, '\0', NULL, e) == NULL)
15637ed4 110 {
6f14531a 111 syserr("553 Cannot parse Postmaster!");
15637ed4
RG
112 ExitStat = EX_SOFTWARE;
113 finis();
114 }
115 }
116 e->e_to = NULL;
117
118 /*
119 ** Basic state machine.
120 **
121 ** This machine runs through the following states:
122 **
123 ** ESM_QUIET Errors have already been printed iff the
124 ** sender is local.
125 ** ESM_REPORT Report directly to the sender's terminal.
126 ** ESM_MAIL Mail response to the sender.
127 ** ESM_DEADLETTER Save response in ~/dead.letter.
128 ** ESM_POSTMASTER Mail response to the postmaster.
129 ** ESM_PANIC Save response anywhere possible.
130 */
131
132 /* determine starting state */
6f14531a 133 switch (e->e_errormode)
15637ed4
RG
134 {
135 case EM_WRITE:
136 state = ESM_REPORT;
137 break;
138
139 case EM_BERKNET:
140 /* mail back, but return o.k. exit status */
141 ExitStat = EX_OK;
142
143 /* fall through.... */
144
145 case EM_MAIL:
146 state = ESM_MAIL;
147 break;
148
149 case EM_PRINT:
150 case '\0':
151 state = ESM_QUIET;
152 break;
153
154 case EM_QUIET:
155 /* no need to return anything at all */
156 return;
157
158 default:
6f14531a 159 syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
15637ed4
RG
160 state = ESM_MAIL;
161 break;
162 }
163
6f14531a
RG
164 /* if this is already an error response, send to postmaster */
165 if (bitset(EF_RESPONSE, e->e_flags))
166 {
167 if (e->e_parent != NULL &&
168 bitset(EF_RESPONSE, e->e_parent->e_flags))
169 {
170 /* got an error sending a response -- can it */
171 return;
172 }
173 state = ESM_POSTMASTER;
174 }
175
15637ed4
RG
176 while (state != ESM_DONE)
177 {
178 if (tTd(6, 5))
179 printf(" state %d\n", state);
180
181 switch (state)
182 {
183 case ESM_QUIET:
184 if (e->e_from.q_mailer == LocalMailer)
185 state = ESM_DEADLETTER;
186 else
187 state = ESM_MAIL;
188 break;
189
190 case ESM_REPORT:
191
192 /*
193 ** If the user is still logged in on the same terminal,
194 ** then write the error messages back to hir (sic).
195 */
196
197 p = ttypath();
198 if (p == NULL || freopen(p, "w", stdout) == NULL)
199 {
200 state = ESM_MAIL;
201 break;
202 }
203
6f14531a 204 expand("\201n", buf, &buf[sizeof buf - 1], e);
15637ed4
RG
205 printf("\r\nMessage from %s...\r\n", buf);
206 printf("Errors occurred while sending mail.\r\n");
207 if (e->e_xfp != NULL)
208 {
209 (void) fflush(e->e_xfp);
210 fp = fopen(queuename(e, 'x'), "r");
211 }
212 else
213 fp = NULL;
214 if (fp == NULL)
215 {
216 syserr("Cannot open %s", queuename(e, 'x'));
217 printf("Transcript of session is unavailable.\r\n");
218 }
219 else
220 {
221 printf("Transcript follows:\r\n");
222 while (fgets(buf, sizeof buf, fp) != NULL &&
223 !ferror(stdout))
224 fputs(buf, stdout);
6f14531a 225 (void) xfclose(fp, "savemail transcript", e->e_id);
15637ed4
RG
226 }
227 printf("Original message will be saved in dead.letter.\r\n");
228 state = ESM_DEADLETTER;
229 break;
230
231 case ESM_MAIL:
15637ed4
RG
232 /*
233 ** If mailing back, do it.
234 ** Throw away all further output. Don't alias,
235 ** since this could cause loops, e.g., if joe
236 ** mails to joe@x, and for some reason the network
237 ** for @x is down, then the response gets sent to
238 ** joe@x, which gives a response, etc. Also force
239 ** the mail to be delivered even if a version of
240 ** it has already been sent to the sender.
241 */
242
6f14531a
RG
243 if (strcmp(e->e_from.q_paddr, "<>") != 0)
244 (void) sendtolist(e->e_from.q_paddr,
245 (ADDRESS *) NULL,
246 &e->e_errorqueue, e);
247
248 /* deliver a cc: to the postmaster if desired */
249 if (PostMasterCopy != NULL)
15637ed4 250 {
6f14531a
RG
251 auto ADDRESS *rlist = NULL;
252
253 (void) sendtolist(PostMasterCopy,
254 (ADDRESS *) NULL,
255 &rlist, e);
256 (void) returntosender(e->e_message,
257 rlist, FALSE, e);
15637ed4 258 }
6f14531a
RG
259 q = e->e_errorqueue;
260 if (q == NULL)
15637ed4 261 {
6f14531a
RG
262 /* this is an error-error */
263 state = ESM_POSTMASTER;
264 break;
15637ed4 265 }
6f14531a
RG
266 if (returntosender(e->e_message,
267 q, (e->e_class >= 0), e) == 0)
15637ed4
RG
268 {
269 state = ESM_DONE;
270 break;
271 }
272
6f14531a
RG
273 /* didn't work -- return to postmaster */
274 state = ESM_POSTMASTER;
275 break;
276
277 case ESM_POSTMASTER:
278 /*
279 ** Similar to previous case, but to system postmaster.
280 */
281
282 q = NULL;
283 if (sendtolist("postmaster", NULL, &q, e) <= 0)
284 {
285 syserr("553 cannot parse postmaster!");
286 ExitStat = EX_SOFTWARE;
287 state = ESM_USRTMP;
288 break;
289 }
290 if (returntosender(e->e_message,
291 q, (e->e_class >= 0), e) == 0)
292 {
293 state = ESM_DONE;
294 break;
295 }
296
297 /* didn't work -- last resort */
298 state = ESM_USRTMP;
15637ed4
RG
299 break;
300
301 case ESM_DEADLETTER:
302 /*
303 ** Save the message in dead.letter.
304 ** If we weren't mailing back, and the user is
305 ** local, we should save the message in
306 ** ~/dead.letter so that the poor person doesn't
307 ** have to type it over again -- and we all know
308 ** what poor typists UNIX users are.
309 */
310
311 p = NULL;
312 if (e->e_from.q_mailer == LocalMailer)
313 {
314 if (e->e_from.q_home != NULL)
315 p = e->e_from.q_home;
316 else if ((pw = getpwnam(e->e_from.q_user)) != NULL)
317 p = pw->pw_dir;
318 }
319 if (p == NULL)
320 {
6f14531a 321 /* no local directory */
15637ed4
RG
322 state = ESM_MAIL;
323 break;
324 }
325 if (e->e_dfp != NULL)
326 {
15637ed4
RG
327 bool oldverb = Verbose;
328
329 /* we have a home directory; open dead.letter */
330 define('z', p, e);
6f14531a 331 expand("\201z/dead.letter", buf, &buf[sizeof buf - 1], e);
15637ed4 332 Verbose = TRUE;
6f14531a 333 message("Saving message in %s", buf);
15637ed4
RG
334 Verbose = oldverb;
335 e->e_to = buf;
336 q = NULL;
6f14531a 337 (void) sendtolist(buf, &e->e_from, &q, e);
15637ed4
RG
338 if (deliver(e, q) == 0)
339 state = ESM_DONE;
340 else
341 state = ESM_MAIL;
342 }
343 else
344 {
345 /* no data file -- try mailing back */
346 state = ESM_MAIL;
347 }
348 break;
349
350 case ESM_USRTMP:
351 /*
352 ** Log the mail in /usr/tmp/dead.letter.
353 */
354
6f14531a
RG
355 if (e->e_class < 0)
356 {
357 state = ESM_DONE;
358 break;
359 }
360
361 fp = dfopen("/usr/tmp/dead.letter",
362 O_WRONLY|O_CREAT|O_APPEND, FileMode);
15637ed4
RG
363 if (fp == NULL)
364 {
365 state = ESM_PANIC;
366 break;
367 }
368
6f14531a
RG
369 putfromline(fp, FileMailer, e);
370 (*e->e_puthdr)(fp, FileMailer, e);
371 putline("\n", fp, FileMailer);
372 (*e->e_putbody)(fp, FileMailer, e, NULL);
373 putline("\n", fp, FileMailer);
15637ed4
RG
374 (void) fflush(fp);
375 state = ferror(fp) ? ESM_PANIC : ESM_DONE;
6f14531a 376 (void) xfclose(fp, "savemail", "/usr/tmp/dead.letter");
15637ed4
RG
377 break;
378
379 default:
6f14531a 380 syserr("554 savemail: unknown state %d", state);
15637ed4
RG
381
382 /* fall through ... */
383
384 case ESM_PANIC:
15637ed4 385 /* leave the locked queue & transcript files around */
6f14531a 386 syserr("554 savemail: cannot save rejected email anywhere");
15637ed4
RG
387 exit(EX_SOFTWARE);
388 }
389 }
390}
391\f/*
392** RETURNTOSENDER -- return a message to the sender with an error.
393**
394** Parameters:
395** msg -- the explanatory message.
396** returnq -- the queue of people to send the message to.
397** sendbody -- if TRUE, also send back the body of the
398** message; otherwise just send the header.
6f14531a 399** e -- the current envelope.
15637ed4
RG
400**
401** Returns:
402** zero -- if everything went ok.
403** else -- some error.
404**
405** Side Effects:
406** Returns the current message to the sender via
407** mail.
408*/
409
410static bool SendBody;
411
412#define MAXRETURNS 6 /* max depth of returning messages */
6f14531a 413#define ERRORFUDGE 100 /* nominal size of error message text */
15637ed4 414
6f14531a 415returntosender(msg, returnq, sendbody, e)
15637ed4
RG
416 char *msg;
417 ADDRESS *returnq;
418 bool sendbody;
6f14531a 419 register ENVELOPE *e;
15637ed4
RG
420{
421 char buf[MAXNAME];
422 extern putheader(), errbody();
423 register ENVELOPE *ee;
6f14531a 424 ENVELOPE *oldcur = CurEnv;
15637ed4
RG
425 ENVELOPE errenvelope;
426 static int returndepth;
427 register ADDRESS *q;
428
6f14531a
RG
429 if (returnq == NULL)
430 return (-1);
431
432 if (msg == NULL)
433 msg = "Unable to deliver mail";
434
15637ed4
RG
435 if (tTd(6, 1))
436 {
6f14531a
RG
437 printf("Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=",
438 msg, returndepth, e);
15637ed4
RG
439 printaddr(returnq, TRUE);
440 }
441
442 if (++returndepth >= MAXRETURNS)
443 {
444 if (returndepth != MAXRETURNS)
6f14531a 445 syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
15637ed4
RG
446 /* don't "unrecurse" and fake a clean exit */
447 /* returndepth--; */
448 return (0);
449 }
450
451 SendBody = sendbody;
6f14531a
RG
452 define('g', e->e_from.q_paddr, e);
453 ee = newenvelope(&errenvelope, e);
454 define('a', "\201b", ee);
455 define('r', "internal", ee);
456 define('s', "localhost", ee);
457 define('_', "localhost", ee);
15637ed4
RG
458 ee->e_puthdr = putheader;
459 ee->e_putbody = errbody;
460 ee->e_flags |= EF_RESPONSE;
6f14531a 461 if (!bitset(EF_OLDSTYLE, e->e_flags))
15637ed4
RG
462 ee->e_flags &= ~EF_OLDSTYLE;
463 ee->e_sendqueue = returnq;
6f14531a 464 ee->e_msgsize = e->e_msgsize + ERRORFUDGE;
15637ed4
RG
465 openxscript(ee);
466 for (q = returnq; q != NULL; q = q->q_next)
467 {
6f14531a
RG
468 if (bitset(QBADADDR, q->q_flags))
469 continue;
470
471 if (!bitset(QDONTSEND, q->q_flags))
472 ee->e_nrcpts++;
473
474 if (!DontPruneRoutes && pruneroute(q->q_paddr))
475 parseaddr(q->q_paddr, q, 0, '\0', NULL, e);
476
15637ed4 477 if (q->q_alias == NULL)
6f14531a 478 addheader("To", q->q_paddr, ee);
15637ed4
RG
479 }
480
6f14531a
RG
481# ifdef LOG
482 if (LogLevel > 5)
483 syslog(LOG_INFO, "%s: %s: return to sender: %s",
484 e->e_id, ee->e_id, msg);
485# endif
486
15637ed4 487 (void) sprintf(buf, "Returned mail: %s", msg);
6f14531a
RG
488 addheader("Subject", buf, ee);
489 if (SendMIMEErrors)
490 {
491 addheader("MIME-Version", "1.0", ee);
492 (void) sprintf(buf, "%s.%ld/%s",
493 ee->e_id, curtime(), MyHostName);
494 ee->e_msgboundary = newstr(buf);
495 (void) sprintf(buf, "multipart/mixed; boundary=\"%s\"",
496 ee->e_msgboundary);
497 addheader("Content-Type", buf, ee);
498 }
15637ed4
RG
499
500 /* fake up an address header for the from person */
6f14531a
RG
501 expand("\201n", buf, &buf[sizeof buf - 1], e);
502 if (parseaddr(buf, &ee->e_from, 1, '\0', NULL, e) == NULL)
15637ed4 503 {
6f14531a 504 syserr("553 Can't parse myself!");
15637ed4
RG
505 ExitStat = EX_SOFTWARE;
506 returndepth--;
507 return (-1);
508 }
6f14531a 509 ee->e_sender = ee->e_from.q_paddr;
15637ed4
RG
510
511 /* push state into submessage */
512 CurEnv = ee;
6f14531a 513 define('f', "\201n", ee);
15637ed4 514 define('x', "Mail Delivery Subsystem", ee);
6f14531a 515 eatheader(ee, TRUE);
15637ed4
RG
516
517 /* actually deliver the error message */
518 sendall(ee, SM_DEFAULT);
519
520 /* restore state */
521 dropenvelope(ee);
6f14531a 522 CurEnv = oldcur;
15637ed4
RG
523 returndepth--;
524
525 /* should check for delivery errors here */
526 return (0);
527}
528\f/*
529** ERRBODY -- output the body of an error message.
530**
531** Typically this is a copy of the transcript plus a copy of the
532** original offending message.
533**
534** Parameters:
535** fp -- the output file.
536** m -- the mailer to output to.
537** e -- the envelope we are working in.
538**
539** Returns:
540** none
541**
542** Side Effects:
543** Outputs the body of an error message.
544*/
545
546errbody(fp, m, e)
547 register FILE *fp;
548 register struct mailer *m;
549 register ENVELOPE *e;
550{
551 register FILE *xfile;
15637ed4 552 char *p;
6f14531a
RG
553 register ADDRESS *q;
554 bool printheader;
555 char buf[MAXLINE];
556
557 if (e->e_parent == NULL)
558 {
559 syserr("errbody: null parent");
560 putline(" ----- Original message lost -----\n", fp, m);
561 return;
562 }
563
564 /*
565 ** Output MIME header.
566 */
567
568 if (e->e_msgboundary != NULL)
569 {
570 putline("This is a MIME-encapsulated message", fp, m);
571 putline("", fp, m);
572 (void) sprintf(buf, "--%s", e->e_msgboundary);
573 putline(buf, fp, m);
574 putline("", fp, m);
575 }
576
577 /*
578 ** Output error message header (if specified and available).
579 */
580
581 if (ErrMsgFile != NULL)
582 {
583 if (*ErrMsgFile == '/')
584 {
585 xfile = fopen(ErrMsgFile, "r");
586 if (xfile != NULL)
587 {
588 while (fgets(buf, sizeof buf, xfile) != NULL)
589 {
590 expand(buf, buf, &buf[sizeof buf - 1], e);
591 putline(buf, fp, m);
592 }
593 (void) fclose(xfile);
594 putline("\n", fp, m);
595 }
596 }
597 else
598 {
599 expand(ErrMsgFile, buf, &buf[sizeof buf - 1], e);
600 putline(buf, fp, m);
601 putline("", fp, m);
602 }
603 }
604
605 /*
606 ** Output message introduction
607 */
608
609 printheader = TRUE;
610 for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
611 {
612 if (bitset(QBADADDR, q->q_flags))
613 {
614 if (printheader)
615 {
616 putline(" ----- The following addresses failed -----",
617 fp, m);
618 printheader = FALSE;
619 }
620 if (q->q_alias != NULL)
621 putline(q->q_alias->q_paddr, fp, m);
622 else
623 putline(q->q_paddr, fp, m);
624 }
625 }
626 if (!printheader)
627 putline("\n", fp, m);
15637ed4
RG
628
629 /*
630 ** Output transcript of errors
631 */
632
633 (void) fflush(stdout);
634 p = queuename(e->e_parent, 'x');
635 if ((xfile = fopen(p, "r")) == NULL)
636 {
637 syserr("Cannot open %s", p);
6f14531a 638 putline(" ----- Transcript of session is unavailable -----\n", fp, m);
15637ed4
RG
639 }
640 else
641 {
6f14531a 642 putline(" ----- Transcript of session follows -----\n", fp, m);
15637ed4
RG
643 if (e->e_xfp != NULL)
644 (void) fflush(e->e_xfp);
645 while (fgets(buf, sizeof buf, xfile) != NULL)
646 putline(buf, fp, m);
6f14531a 647 (void) xfclose(xfile, "errbody xscript", p);
15637ed4
RG
648 }
649 errno = 0;
650
651 /*
652 ** Output text of original message
653 */
654
655 if (NoReturn)
6f14531a
RG
656 SendBody = FALSE;
657 putline("", fp, m);
658 if (e->e_parent->e_df != NULL)
15637ed4
RG
659 {
660 if (SendBody)
15637ed4 661 putline(" ----- Unsent message follows -----\n", fp, m);
15637ed4 662 else
6f14531a
RG
663 putline(" ----- Message header follows -----\n", fp, m);
664 (void) fflush(fp);
665
666 if (e->e_msgboundary != NULL)
15637ed4 667 {
6f14531a
RG
668 putline("", fp, m);
669 (void) sprintf(buf, "--%s", e->e_msgboundary);
670 putline(buf, fp, m);
671 putline("Content-Type: message/rfc822", fp, m);
672 putline("", fp, m);
15637ed4 673 }
6f14531a
RG
674 putheader(fp, m, e->e_parent);
675 putline("", fp, m);
676 if (SendBody)
677 putbody(fp, m, e->e_parent, e->e_msgboundary);
678 else
679 putline(" ----- Message body suppressed -----", fp, m);
15637ed4
RG
680 }
681 else
682 {
15637ed4 683 putline(" ----- No message was collected -----\n", fp, m);
15637ed4
RG
684 }
685
6f14531a
RG
686 if (e->e_msgboundary != NULL)
687 {
688 putline("", fp, m);
689 (void) sprintf(buf, "--%s--", e->e_msgboundary);
690 putline(buf, fp, m);
691 }
692 putline("", fp, m);
693
15637ed4
RG
694 /*
695 ** Cleanup and exit
696 */
697
698 if (errno != 0)
699 syserr("errbody: I/O error");
700}
6f14531a
RG
701\f/*
702** PRUNEROUTE -- prune an RFC-822 source route
703**
704** Trims down a source route to the last internet-registered hop.
705** This is encouraged by RFC 1123 section 5.3.3.
706**
707** Parameters:
708** addr -- the address
709**
710** Returns:
711** TRUE -- address was modified
712** FALSE -- address could not be pruned
713**
714** Side Effects:
715** modifies addr in-place
716*/
717
718pruneroute(addr)
719 char *addr;
720{
721#ifdef NAMED_BIND
722 char *start, *at, *comma;
723 char c;
724 int rcode;
725 char hostbuf[BUFSIZ];
726 char *mxhosts[MAXMXHOSTS + 1];
727
728 /* check to see if this is really a route-addr */
729 if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
730 return FALSE;
731 start = strchr(addr, ':');
732 at = strrchr(addr, '@');
733 if (start == NULL || at == NULL || at < start)
734 return FALSE;
735
736 /* slice off the angle brackets */
737 strcpy(hostbuf, at + 1);
738 hostbuf[strlen(hostbuf) - 1] = '\0';
739
740 while (start)
741 {
742 if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
743 {
744 strcpy(addr + 1, start + 1);
745 return TRUE;
746 }
747 c = *start;
748 *start = '\0';
749 comma = strrchr(addr, ',');
750 if (comma && comma[1] == '@')
751 strcpy(hostbuf, comma + 2);
752 else
753 comma = 0;
754 *start = c;
755 start = comma;
756 }
757#endif
758 return FALSE;
759}