savemail.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:36k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #ifndef lint
  14. static char id[] = "@(#)$Id: savemail.c,v 8.209 1999/11/29 18:40:59 gshapiro Exp $";
  15. #endif /* ! lint */
  16. #include <sendmail.h>
  17. static void errbody __P((MCI *, ENVELOPE *, char *));
  18. static bool pruneroute __P((char *));
  19. /*
  20. **  SAVEMAIL -- Save mail on error
  21. **
  22. ** If mailing back errors, mail it back to the originator
  23. ** together with an error message; otherwise, just put it in
  24. ** dead.letter in the user's home directory (if he exists on
  25. ** this machine).
  26. **
  27. ** Parameters:
  28. ** e -- the envelope containing the message in error.
  29. ** sendbody -- if TRUE, also send back the body of the
  30. ** message; otherwise just send the header.
  31. **
  32. ** Returns:
  33. ** none
  34. **
  35. ** Side Effects:
  36. ** Saves the letter, by writing or mailing it back to the
  37. ** sender, or by putting it in dead.letter in her home
  38. ** directory.
  39. */
  40. /* defines for state machine */
  41. #define ESM_REPORT 0 /* report to sender's terminal */
  42. #define ESM_MAIL 1 /* mail back to sender */
  43. #define ESM_QUIET 2 /* mail has already been returned */
  44. #define ESM_DEADLETTER 3 /* save in ~/dead.letter */
  45. #define ESM_POSTMASTER 4 /* return to postmaster */
  46. #define ESM_DEADLETTERDROP 5 /* save in DeadLetterDrop */
  47. #define ESM_PANIC 6 /* call loseqfile() */
  48. #define ESM_DONE 7 /* message is successfully delivered */
  49. void
  50. savemail(e, sendbody)
  51. register ENVELOPE *e;
  52. bool sendbody;
  53. {
  54. register struct passwd *pw;
  55. register FILE *fp;
  56. int state;
  57. auto ADDRESS *q = NULL;
  58. register char *p;
  59. MCI mcibuf;
  60. int flags;
  61. long sff;
  62. char buf[MAXLINE + 1];
  63. if (tTd(6, 1))
  64. {
  65. dprintf("nsavemail, errormode = %c, id = %s, ExitStat = %dn  e_from=",
  66. e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
  67. ExitStat);
  68. printaddr(&e->e_from, FALSE);
  69. }
  70. if (e->e_id == NULL)
  71. {
  72. /* can't return a message with no id */
  73. return;
  74. }
  75. /*
  76. **  In the unhappy event we don't know who to return the mail
  77. **  to, make someone up.
  78. */
  79. if (e->e_from.q_paddr == NULL)
  80. {
  81. e->e_sender = "Postmaster";
  82. if (parseaddr(e->e_sender, &e->e_from,
  83.       RF_COPYPARSE|RF_SENDERADDR, '', NULL, e) == NULL)
  84. {
  85. syserr("553 5.3.5 Cannot parse Postmaster!");
  86. finis(TRUE, EX_SOFTWARE);
  87. }
  88. }
  89. e->e_to = NULL;
  90. /*
  91. **  Basic state machine.
  92. **
  93. ** This machine runs through the following states:
  94. **
  95. ** ESM_QUIET Errors have already been printed iff the
  96. ** sender is local.
  97. ** ESM_REPORT Report directly to the sender's terminal.
  98. ** ESM_MAIL Mail response to the sender.
  99. ** ESM_DEADLETTER Save response in ~/dead.letter.
  100. ** ESM_POSTMASTER Mail response to the postmaster.
  101. ** ESM_DEADLETTERDROP
  102. ** If DeadLetterDrop set, save it there.
  103. ** ESM_PANIC Save response anywhere possible.
  104. */
  105. /* determine starting state */
  106. switch (e->e_errormode)
  107. {
  108.   case EM_WRITE:
  109. state = ESM_REPORT;
  110. break;
  111.   case EM_BERKNET:
  112.   case EM_MAIL:
  113. state = ESM_MAIL;
  114. break;
  115.   case EM_PRINT:
  116.   case '':
  117. state = ESM_QUIET;
  118. break;
  119.   case EM_QUIET:
  120. /* no need to return anything at all */
  121. return;
  122.   default:
  123. syserr("554 5.3.0 savemail: bogus errormode x%xn",
  124.        e->e_errormode);
  125. state = ESM_MAIL;
  126. break;
  127. }
  128. /* if this is already an error response, send to postmaster */
  129. if (bitset(EF_RESPONSE, e->e_flags))
  130. {
  131. if (e->e_parent != NULL &&
  132.     bitset(EF_RESPONSE, e->e_parent->e_flags))
  133. {
  134. /* got an error sending a response -- can it */
  135. return;
  136. }
  137. state = ESM_POSTMASTER;
  138. }
  139. while (state != ESM_DONE)
  140. {
  141. if (tTd(6, 5))
  142. dprintf("  state %dn", state);
  143. switch (state)
  144. {
  145.   case ESM_QUIET:
  146. if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
  147. state = ESM_DEADLETTER;
  148. else
  149. state = ESM_MAIL;
  150. break;
  151.   case ESM_REPORT:
  152. /*
  153. **  If the user is still logged in on the same terminal,
  154. **  then write the error messages back to hir (sic).
  155. */
  156. p = ttypath();
  157. if (p == NULL || freopen(p, "w", stdout) == NULL)
  158. {
  159. state = ESM_MAIL;
  160. break;
  161. }
  162. expand("201n", buf, sizeof buf, e);
  163. printf("rnMessage from %s...rn", buf);
  164. printf("Errors occurred while sending mail.rn");
  165. if (e->e_xfp != NULL)
  166. {
  167. (void) bfrewind(e->e_xfp);
  168. printf("Transcript follows:rn");
  169. while (fgets(buf, sizeof buf, e->e_xfp) != NULL &&
  170.        !ferror(stdout))
  171. (void) fputs(buf, stdout);
  172. }
  173. else
  174. {
  175. syserr("Cannot open %s", queuename(e, 'x'));
  176. printf("Transcript of session is unavailable.rn");
  177. }
  178. printf("Original message will be saved in dead.letter.rn");
  179. state = ESM_DEADLETTER;
  180. break;
  181.   case ESM_MAIL:
  182. /*
  183. **  If mailing back, do it.
  184. ** Throw away all further output.  Don't alias,
  185. ** since this could cause loops, e.g., if joe
  186. ** mails to joe@x, and for some reason the network
  187. ** for @x is down, then the response gets sent to
  188. ** joe@x, which gives a response, etc.  Also force
  189. ** the mail to be delivered even if a version of
  190. ** it has already been sent to the sender.
  191. **
  192. **  If this is a configuration or local software
  193. ** error, send to the local postmaster as well,
  194. ** since the originator can't do anything
  195. ** about it anyway.  Note that this is a full
  196. ** copy of the message (intentionally) so that
  197. ** the Postmaster can forward things along.
  198. */
  199. if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
  200. {
  201. (void) sendtolist("postmaster",
  202.   NULLADDR, &e->e_errorqueue, 0, e);
  203. }
  204. if (!emptyaddr(&e->e_from))
  205. {
  206. char from[TOBUFSIZE];
  207. if (strlen(e->e_from.q_paddr) >= sizeof from)
  208. {
  209. state = ESM_POSTMASTER;
  210. break;
  211. }
  212. (void) strlcpy(from, e->e_from.q_paddr,
  213.        sizeof from);
  214. if (!DontPruneRoutes && pruneroute(from))
  215. {
  216. ADDRESS *a;
  217. for (a = e->e_errorqueue; a != NULL;
  218.      a = a->q_next)
  219. {
  220. if (sameaddr(a, &e->e_from))
  221. a->q_state = QS_DUPLICATE;
  222. }
  223. }
  224. (void) sendtolist(from, NULLADDR,
  225.   &e->e_errorqueue, 0, e);
  226. }
  227. /*
  228. **  Deliver a non-delivery report to the
  229. **  Postmaster-designate (not necessarily
  230. **  Postmaster).  This does not include the
  231. **  body of the message, for privacy reasons.
  232. **  You really shouldn't need this.
  233. */
  234. e->e_flags |= EF_PM_NOTIFY;
  235. /* check to see if there are any good addresses */
  236. for (q = e->e_errorqueue; q != NULL; q = q->q_next)
  237. {
  238. if (QS_IS_SENDABLE(q->q_state))
  239. break;
  240. }
  241. if (q == NULL)
  242. {
  243. /* this is an error-error */
  244. state = ESM_POSTMASTER;
  245. break;
  246. }
  247. if (returntosender(e->e_message, e->e_errorqueue,
  248.    sendbody ? RTSF_SEND_BODY
  249.     : RTSF_NO_BODY,
  250.    e) == 0)
  251. {
  252. state = ESM_DONE;
  253. break;
  254. }
  255. /* didn't work -- return to postmaster */
  256. state = ESM_POSTMASTER;
  257. break;
  258.   case ESM_POSTMASTER:
  259. /*
  260. **  Similar to previous case, but to system postmaster.
  261. */
  262. q = NULL;
  263. expand(DoubleBounceAddr, buf, sizeof buf, e);
  264. if (sendtolist(buf, NULLADDR, &q, 0, e) <= 0)
  265. {
  266. syserr("553 5.3.0 cannot parse %s!", buf);
  267. ExitStat = EX_SOFTWARE;
  268. state = ESM_DEADLETTERDROP;
  269. break;
  270. }
  271. flags = RTSF_PM_BOUNCE;
  272. if (sendbody)
  273. flags |= RTSF_SEND_BODY;
  274. if (returntosender(e->e_message, q, flags, e) == 0)
  275. {
  276. state = ESM_DONE;
  277. break;
  278. }
  279. /* didn't work -- last resort */
  280. state = ESM_DEADLETTERDROP;
  281. break;
  282.   case ESM_DEADLETTER:
  283. /*
  284. **  Save the message in dead.letter.
  285. ** If we weren't mailing back, and the user is
  286. ** local, we should save the message in
  287. ** ~/dead.letter so that the poor person doesn't
  288. ** have to type it over again -- and we all know
  289. ** what poor typists UNIX users are.
  290. */
  291. p = NULL;
  292. if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
  293. {
  294. if (e->e_from.q_home != NULL)
  295. p = e->e_from.q_home;
  296. else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
  297. p = pw->pw_dir;
  298. }
  299. if (p == NULL || e->e_dfp == NULL)
  300. {
  301. /* no local directory or no data file */
  302. state = ESM_MAIL;
  303. break;
  304. }
  305. /* we have a home directory; write dead.letter */
  306. define('z', p, e);
  307. /* get the sender for the UnixFromLine */
  308. p = macvalue('g', e);
  309. define('g', e->e_sender, e);
  310. expand("201z/dead.letter", buf, sizeof buf, e);
  311. sff = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
  312. if (RealUid == 0)
  313. sff |= SFF_ROOTOK;
  314. e->e_to = buf;
  315. if (writable(buf, NULL, sff) &&
  316.     mailfile(buf, FileMailer, NULL, sff, e) == EX_OK)
  317. {
  318. int oldverb = Verbose;
  319. if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
  320. Verbose = 1;
  321. if (Verbose > 0)
  322. message("Saved message in %s", buf);
  323. Verbose = oldverb;
  324. define('g', p, e);
  325. state = ESM_DONE;
  326. break;
  327. }
  328. define('g', p, e);
  329. state = ESM_MAIL;
  330. break;
  331.   case ESM_DEADLETTERDROP:
  332. /*
  333. **  Log the mail in DeadLetterDrop file.
  334. */
  335. if (e->e_class < 0)
  336. {
  337. state = ESM_DONE;
  338. break;
  339. }
  340. if ((SafeFileEnv != NULL && SafeFileEnv[0] != '') ||
  341.     DeadLetterDrop == NULL ||
  342.     DeadLetterDrop[0] == '')
  343. {
  344. state = ESM_PANIC;
  345. break;
  346. }
  347. sff = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
  348. if (!writable(DeadLetterDrop, NULL, sff) ||
  349.     (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
  350.     FileMode, sff)) == NULL)
  351. {
  352. state = ESM_PANIC;
  353. break;
  354. }
  355. memset(&mcibuf, '', sizeof mcibuf);
  356. mcibuf.mci_out = fp;
  357. mcibuf.mci_mailer = FileMailer;
  358. if (bitnset(M_7BITS, FileMailer->m_flags))
  359. mcibuf.mci_flags |= MCIF_7BIT;
  360. /* get the sender for the UnixFromLine */
  361. p = macvalue('g', e);
  362. define('g', e->e_sender, e);
  363. putfromline(&mcibuf, e);
  364. (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
  365. (*e->e_putbody)(&mcibuf, e, NULL);
  366. putline("n", &mcibuf);
  367. (void) fflush(fp);
  368. if (ferror(fp) ||
  369.     fclose(fp) < 0)
  370. state = ESM_PANIC;
  371. else
  372. {
  373. int oldverb = Verbose;
  374. if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
  375. Verbose = 1;
  376. if (Verbose > 0)
  377. message("Saved message in %s",
  378. DeadLetterDrop);
  379. Verbose = oldverb;
  380. if (LogLevel > 3)
  381. sm_syslog(LOG_NOTICE, e->e_id,
  382.   "Saved message in %s",
  383.   DeadLetterDrop);
  384. state = ESM_DONE;
  385. }
  386. define('g', p, e);
  387. break;
  388.   default:
  389. syserr("554 5.3.5 savemail: unknown state %d", state);
  390. /* FALLTHROUGH */
  391.   case ESM_PANIC:
  392. /* leave the locked queue & transcript files around */
  393. loseqfile(e, "savemail panic");
  394. syserr("!554 savemail: cannot save rejected email anywhere");
  395. }
  396. }
  397. }
  398. /*
  399. **  RETURNTOSENDER -- return a message to the sender with an error.
  400. **
  401. ** Parameters:
  402. ** msg -- the explanatory message.
  403. ** returnq -- the queue of people to send the message to.
  404. ** flags -- flags tweaking the operation:
  405. ** RTSF_SENDBODY -- include body of message (otherwise
  406. ** just send the header).
  407. ** RTSF_PMBOUNCE -- this is a postmaster bounce.
  408. ** e -- the current envelope.
  409. **
  410. ** Returns:
  411. ** zero -- if everything went ok.
  412. ** else -- some error.
  413. **
  414. ** Side Effects:
  415. ** Returns the current message to the sender via
  416. ** mail.
  417. */
  418. #define MAXRETURNS 6 /* max depth of returning messages */
  419. #define ERRORFUDGE 100 /* nominal size of error message text */
  420. int
  421. returntosender(msg, returnq, flags, e)
  422. char *msg;
  423. ADDRESS *returnq;
  424. int flags;
  425. register ENVELOPE *e;
  426. {
  427. register ENVELOPE *ee;
  428. ENVELOPE *oldcur = CurEnv;
  429. ENVELOPE errenvelope;
  430. static int returndepth = 0;
  431. register ADDRESS *q;
  432. char *p;
  433. char buf[MAXNAME + 1];
  434. if (returnq == NULL)
  435. return -1;
  436. if (msg == NULL)
  437. msg = "Unable to deliver mail";
  438. if (tTd(6, 1))
  439. {
  440. dprintf("n*** Return To Sender: msg="%s", depth=%d, e=%lx, returnq=",
  441. msg, returndepth, (u_long) e);
  442. printaddr(returnq, TRUE);
  443. if (tTd(6, 20))
  444. {
  445. dprintf("Sendq=");
  446. printaddr(e->e_sendqueue, TRUE);
  447. }
  448. }
  449. if (++returndepth >= MAXRETURNS)
  450. {
  451. if (returndepth != MAXRETURNS)
  452. syserr("554 5.3.0 returntosender: infinite recursion on %s",
  453.        returnq->q_paddr);
  454. /* don't "unrecurse" and fake a clean exit */
  455. /* returndepth--; */
  456. return 0;
  457. }
  458. define('g', e->e_sender, e);
  459. define('u', NULL, e);
  460. /* initialize error envelope */
  461. ee = newenvelope(&errenvelope, e);
  462. define('a', "201b", ee);
  463. define('r', "", ee);
  464. define('s', "localhost", ee);
  465. define('_', "localhost", ee);
  466. ee->e_puthdr = putheader;
  467. ee->e_putbody = errbody;
  468. ee->e_flags |= EF_RESPONSE|EF_METOO;
  469. if (!bitset(EF_OLDSTYLE, e->e_flags))
  470. ee->e_flags &= ~EF_OLDSTYLE;
  471. if (bitset(EF_DONT_MIME, e->e_flags))
  472. {
  473. ee->e_flags |= EF_DONT_MIME;
  474. /*
  475. **  If we can't convert to MIME and we don't pass
  476. **  8-bit, we can't send the body.
  477. */
  478. if (bitset(EF_HAS8BIT, e->e_flags) &&
  479.     !bitset(MM_PASS8BIT, MimeMode))
  480. flags &= ~RTSF_SEND_BODY;
  481. }
  482. ee->e_sendqueue = returnq;
  483. ee->e_msgsize = ERRORFUDGE;
  484. if (bitset(RTSF_SEND_BODY, flags) &&
  485.     !bitset(PRIV_NOBODYRETN, PrivacyFlags))
  486. ee->e_msgsize += e->e_msgsize;
  487. else
  488. ee->e_flags |= EF_NO_BODY_RETN;
  489. initsys(ee);
  490. #if NAMED_BIND
  491. _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
  492. _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
  493. #endif /* NAMED_BIND */
  494. for (q = returnq; q != NULL; q = q->q_next)
  495. {
  496. if (QS_IS_BADADDR(q->q_state))
  497. continue;
  498. q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
  499. q->q_flags |= QPINGONFAILURE;
  500. if (!QS_IS_DEAD(q->q_state))
  501. ee->e_nrcpts++;
  502. if (q->q_alias == NULL)
  503. addheader("To", q->q_paddr, &ee->e_header);
  504. }
  505. if (LogLevel > 5)
  506. {
  507. if (bitset(EF_RESPONSE, e->e_flags))
  508. p = "return to sender";
  509. else if (bitset(EF_WARNING, e->e_flags))
  510. p = "sender notify";
  511. else if (bitset(RTSF_PM_BOUNCE, flags))
  512. p = "postmaster notify";
  513. else
  514. p = "DSN";
  515. sm_syslog(LOG_INFO, e->e_id,
  516.   "%s: %s: %s",
  517.   ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
  518. }
  519. if (SendMIMEErrors)
  520. {
  521. addheader("MIME-Version", "1.0", &ee->e_header);
  522. (void) snprintf(buf, sizeof buf, "%s.%ld/%.100s",
  523. ee->e_id, curtime(), MyHostName);
  524. ee->e_msgboundary = newstr(buf);
  525. (void) snprintf(buf, sizeof buf,
  526. #if DSN
  527. "multipart/report; report-type=delivery-status;ntboundary="%s"",
  528. #else /* DSN */
  529. "multipart/mixed; boundary="%s"",
  530. #endif /* DSN */
  531. ee->e_msgboundary);
  532. addheader("Content-Type", buf, &ee->e_header);
  533. p = hvalue("Content-Transfer-Encoding", e->e_header);
  534. if (p != NULL && strcasecmp(p, "binary") != 0)
  535. p = NULL;
  536. if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
  537. p = "8bit";
  538. if (p != NULL)
  539. addheader("Content-Transfer-Encoding",
  540.   p, &ee->e_header);
  541. }
  542. if (strncmp(msg, "Warning:", 8) == 0)
  543. {
  544. addheader("Subject", msg, &ee->e_header);
  545. p = "warning-timeout";
  546. }
  547. else if (strncmp(msg, "Postmaster warning:", 19) == 0)
  548. {
  549. addheader("Subject", msg, &ee->e_header);
  550. p = "postmaster-warning";
  551. }
  552. else if (strcmp(msg, "Return receipt") == 0)
  553. {
  554. addheader("Subject", msg, &ee->e_header);
  555. p = "return-receipt";
  556. }
  557. else if (bitset(RTSF_PM_BOUNCE, flags))
  558. {
  559. snprintf(buf, sizeof buf,
  560.  "Postmaster notify: see transcript for details");
  561. addheader("Subject", buf, &ee->e_header);
  562. p = "postmaster-notification";
  563. }
  564. else
  565. {
  566. snprintf(buf, sizeof buf,
  567.  "Returned mail: see transcript for details");
  568. addheader("Subject", buf, &ee->e_header);
  569. p = "failure";
  570. }
  571. (void) snprintf(buf, sizeof buf, "auto-generated (%s)", p);
  572. addheader("Auto-Submitted", buf, &ee->e_header);
  573. /* fake up an address header for the from person */
  574. expand("201n", buf, sizeof buf, e);
  575. if (parseaddr(buf, &ee->e_from,
  576.       RF_COPYALL|RF_SENDERADDR, '', NULL, e) == NULL)
  577. {
  578. syserr("553 5.3.5 Can't parse myself!");
  579. ExitStat = EX_SOFTWARE;
  580. returndepth--;
  581. return -1;
  582. }
  583. ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
  584. ee->e_from.q_flags |= QPINGONFAILURE;
  585. ee->e_sender = ee->e_from.q_paddr;
  586. /* push state into submessage */
  587. CurEnv = ee;
  588. define('f', "201n", ee);
  589. define('x', "Mail Delivery Subsystem", ee);
  590. eatheader(ee, TRUE);
  591. /* mark statistics */
  592. markstats(ee, NULLADDR, FALSE);
  593. /* actually deliver the error message */
  594. sendall(ee, SM_DELIVER);
  595. /* restore state */
  596. dropenvelope(ee, TRUE);
  597. CurEnv = oldcur;
  598. returndepth--;
  599. /* check for delivery errors */
  600. if (ee->e_parent == NULL ||
  601.     !bitset(EF_RESPONSE, ee->e_parent->e_flags))
  602. return 0;
  603. for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
  604. {
  605. if (QS_IS_ATTEMPTED(q->q_state))
  606. return 0;
  607. }
  608. return -1;
  609. }
  610. /*
  611. **  ERRBODY -- output the body of an error message.
  612. **
  613. ** Typically this is a copy of the transcript plus a copy of the
  614. ** original offending message.
  615. **
  616. ** Parameters:
  617. ** mci -- the mailer connection information.
  618. ** e -- the envelope we are working in.
  619. ** separator -- any possible MIME separator.
  620. **
  621. ** Returns:
  622. ** none
  623. **
  624. ** Side Effects:
  625. ** Outputs the body of an error message.
  626. */
  627. /* ARGSUSED2 */
  628. static void
  629. errbody(mci, e, separator)
  630. register MCI *mci;
  631. register ENVELOPE *e;
  632. char *separator;
  633. {
  634. bool printheader;
  635. bool sendbody;
  636. bool pm_notify;
  637. int save_errno;
  638. register FILE *xfile;
  639. char *p;
  640. register ADDRESS *q = NULL;
  641. char buf[MAXLINE];
  642. if (bitset(MCIF_INHEADER, mci->mci_flags))
  643. {
  644. putline("", mci);
  645. mci->mci_flags &= ~MCIF_INHEADER;
  646. }
  647. if (e->e_parent == NULL)
  648. {
  649. syserr("errbody: null parent");
  650. putline("   ----- Original message lost -----n", mci);
  651. return;
  652. }
  653. /*
  654. **  Output MIME header.
  655. */
  656. if (e->e_msgboundary != NULL)
  657. {
  658. putline("This is a MIME-encapsulated message", mci);
  659. putline("", mci);
  660. (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
  661. putline(buf, mci);
  662. putline("", mci);
  663. }
  664. /*
  665. **  Output introductory information.
  666. */
  667. pm_notify = FALSE;
  668. p = hvalue("subject", e->e_header);
  669. if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
  670. pm_notify = TRUE;
  671. else
  672. {
  673. for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
  674. {
  675. if (QS_IS_BADADDR(q->q_state))
  676. break;
  677. }
  678. }
  679. if (!pm_notify && q == NULL &&
  680.     !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
  681. {
  682. putline("    **********************************************",
  683. mci);
  684. putline("    **      THIS IS A WARNING MESSAGE ONLY      **",
  685. mci);
  686. putline("    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **",
  687. mci);
  688. putline("    **********************************************",
  689. mci);
  690. putline("", mci);
  691. }
  692. snprintf(buf, sizeof buf, "The original message was received at %s",
  693.  arpadate(ctime(&e->e_parent->e_ctime)));
  694. putline(buf, mci);
  695. expand("from 201_", buf, sizeof buf, e->e_parent);
  696. putline(buf, mci);
  697. /* include id in postmaster copies */
  698. if (pm_notify && e->e_parent->e_id != NULL)
  699. {
  700. snprintf(buf, sizeof buf, "with id %s", e->e_parent->e_id);
  701. putline(buf, mci);
  702. }
  703. putline("", mci);
  704. /*
  705. **  Output error message header (if specified and available).
  706. */
  707. if (ErrMsgFile != NULL &&
  708.     !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
  709. {
  710. if (*ErrMsgFile == '/')
  711. {
  712. long sff = SFF_ROOTOK|SFF_REGONLY;
  713. if (DontLockReadFiles)
  714. sff |= SFF_NOLOCK;
  715. if (!bitnset(DBS_ERRORHEADERINUNSAFEDIRPATH,
  716.      DontBlameSendmail))
  717. sff |= SFF_SAFEDIRPATH;
  718. xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
  719. if (xfile != NULL)
  720. {
  721. while (fgets(buf, sizeof buf, xfile) != NULL)
  722. {
  723. translate_dollars(buf);
  724. expand(buf, buf, sizeof buf, e);
  725. putline(buf, mci);
  726. }
  727. (void) fclose(xfile);
  728. putline("n", mci);
  729. }
  730. }
  731. else
  732. {
  733. expand(ErrMsgFile, buf, sizeof buf, e);
  734. putline(buf, mci);
  735. putline("", mci);
  736. }
  737. }
  738. /*
  739. **  Output message introduction
  740. */
  741. printheader = TRUE;
  742. for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
  743. {
  744. if (!QS_IS_BADADDR(q->q_state) ||
  745.     !bitset(QPINGONFAILURE, q->q_flags))
  746. continue;
  747. if (printheader)
  748. {
  749. putline("   ----- The following addresses had permanent fatal errors -----",
  750. mci);
  751. printheader = FALSE;
  752. }
  753. snprintf(buf, sizeof buf, "%s",
  754.  shortenstring(q->q_paddr, MAXSHORTSTR));
  755. putline(buf, mci);
  756. if (q->q_rstatus != NULL)
  757. {
  758. snprintf(buf, sizeof buf, "    (reason: %s)",
  759.  shortenstring(exitstat(q->q_rstatus),
  760.        MAXSHORTSTR));
  761. putline(buf, mci);
  762. }
  763. if (q->q_alias != NULL)
  764. {
  765. snprintf(buf, sizeof buf, "    (expanded from: %s)",
  766.  shortenstring(q->q_alias->q_paddr,
  767.        MAXSHORTSTR));
  768. putline(buf, mci);
  769. }
  770. }
  771. if (!printheader)
  772. putline("", mci);
  773. printheader = TRUE;
  774. for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
  775. {
  776. if (QS_IS_BADADDR(q->q_state) ||
  777.     !bitset(QPRIMARY, q->q_flags) ||
  778.     !bitset(QDELAYED, q->q_flags))
  779. continue;
  780. if (printheader)
  781. {
  782. putline("   ----- The following addresses had transient non-fatal errors -----",
  783. mci);
  784. printheader = FALSE;
  785. }
  786. snprintf(buf, sizeof buf, "%s",
  787.  shortenstring(q->q_paddr, MAXSHORTSTR));
  788. putline(buf, mci);
  789. if (q->q_alias != NULL)
  790. {
  791. snprintf(buf, sizeof buf, "    (expanded from: %s)",
  792.  shortenstring(q->q_alias->q_paddr,
  793.        MAXSHORTSTR));
  794. putline(buf, mci);
  795. }
  796. }
  797. if (!printheader)
  798. putline("", mci);
  799. printheader = TRUE;
  800. for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
  801. {
  802. if (QS_IS_BADADDR(q->q_state) ||
  803.     !bitset(QPRIMARY, q->q_flags) ||
  804.     bitset(QDELAYED, q->q_flags))
  805. continue;
  806. else if (!bitset(QPINGONSUCCESS, q->q_flags))
  807. continue;
  808. else if (bitset(QRELAYED, q->q_flags))
  809. p = "relayed to non-DSN-aware mailer";
  810. else if (bitset(QDELIVERED, q->q_flags))
  811. {
  812. if (bitset(QEXPANDED, q->q_flags))
  813. p = "successfully delivered to mailing list";
  814. else
  815. p = "successfully delivered to mailbox";
  816. }
  817. else if (bitset(QEXPANDED, q->q_flags))
  818. p = "expanded by alias";
  819. else
  820. continue;
  821. if (printheader)
  822. {
  823. putline("   ----- The following addresses had successful delivery notifications -----",
  824. mci);
  825. printheader = FALSE;
  826. }
  827. snprintf(buf, sizeof buf, "%s  (%s)",
  828.  shortenstring(q->q_paddr, MAXSHORTSTR), p);
  829. putline(buf, mci);
  830. if (q->q_alias != NULL)
  831. {
  832. snprintf(buf, sizeof buf, "    (expanded from: %s)",
  833.  shortenstring(q->q_alias->q_paddr,
  834.        MAXSHORTSTR));
  835. putline(buf, mci);
  836. }
  837. }
  838. if (!printheader)
  839. putline("", mci);
  840. /*
  841. **  Output transcript of errors
  842. */
  843. (void) fflush(stdout);
  844. if (e->e_parent->e_xfp == NULL)
  845. {
  846. putline("   ----- Transcript of session is unavailable -----n",
  847. mci);
  848. }
  849. else
  850. {
  851. printheader = TRUE;
  852. (void) bfrewind(e->e_parent->e_xfp);
  853. if (e->e_xfp != NULL)
  854. (void) fflush(e->e_xfp);
  855. while (fgets(buf, sizeof buf, e->e_parent->e_xfp) != NULL)
  856. {
  857. if (printheader)
  858. putline("   ----- Transcript of session follows -----n",
  859. mci);
  860. printheader = FALSE;
  861. putline(buf, mci);
  862. }
  863. }
  864. errno = 0;
  865. #if DSN
  866. /*
  867. **  Output machine-readable version.
  868. */
  869. if (e->e_msgboundary != NULL)
  870. {
  871. putline("", mci);
  872. (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
  873. putline(buf, mci);
  874. putline("Content-Type: message/delivery-status", mci);
  875. putline("", mci);
  876. /*
  877. **  Output per-message information.
  878. */
  879. /* original envelope id from MAIL FROM: line */
  880. if (e->e_parent->e_envid != NULL)
  881. {
  882. (void) snprintf(buf, sizeof buf,
  883. "Original-Envelope-Id: %.800s",
  884. xuntextify(e->e_parent->e_envid));
  885. putline(buf, mci);
  886. }
  887. /* Reporting-MTA: is us (required) */
  888. (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName);
  889. putline(buf, mci);
  890. /* DSN-Gateway: not relevant since we are not translating */
  891. /* Received-From-MTA: shows where we got this message from */
  892. if (RealHostName != NULL)
  893. {
  894. /* XXX use $s for type? */
  895. if (e->e_parent->e_from.q_mailer == NULL ||
  896.     (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
  897. p = "dns";
  898. (void) snprintf(buf, sizeof buf,
  899. "Received-From-MTA: %s; %.800s",
  900. p, RealHostName);
  901. putline(buf, mci);
  902. }
  903. /* Arrival-Date: -- when it arrived here */
  904. (void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
  905. arpadate(ctime(&e->e_parent->e_ctime)));
  906. putline(buf, mci);
  907. /*
  908. **  Output per-address information.
  909. */
  910. for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
  911. {
  912. register ADDRESS *r;
  913. char *action;
  914. if (QS_IS_BADADDR(q->q_state))
  915. action = "failed";
  916. else if (!bitset(QPRIMARY, q->q_flags))
  917. continue;
  918. else if (bitset(QDELIVERED, q->q_flags))
  919. {
  920. if (bitset(QEXPANDED, q->q_flags))
  921. action = "delivered (to mailing list)";
  922. else
  923. action = "delivered (to mailbox)";
  924. }
  925. else if (bitset(QRELAYED, q->q_flags))
  926. action = "relayed (to non-DSN-aware mailer)";
  927. else if (bitset(QEXPANDED, q->q_flags))
  928. action = "expanded (to multi-recipient alias)";
  929. else if (bitset(QDELAYED, q->q_flags))
  930. action = "delayed";
  931. else
  932. continue;
  933. putline("", mci);
  934. /* Original-Recipient: -- passed from on high */
  935. if (q->q_orcpt != NULL)
  936. {
  937. (void) snprintf(buf, sizeof buf,
  938. "Original-Recipient: %.800s",
  939. q->q_orcpt);
  940. putline(buf, mci);
  941. }
  942. /* Final-Recipient: -- the name from the RCPT command */
  943. p = e->e_parent->e_from.q_mailer->m_addrtype;
  944. if (p == NULL)
  945. p = "rfc822";
  946. for (r = q; r->q_alias != NULL; r = r->q_alias)
  947. continue;
  948. if (strcasecmp(p, "rfc822") != 0)
  949. {
  950. (void) snprintf(buf, sizeof buf,
  951. "Final-Recipient: %s; %.800s",
  952. r->q_mailer->m_addrtype,
  953. r->q_user);
  954. }
  955. else if (strchr(r->q_user, '@') != NULL)
  956. {
  957. (void) snprintf(buf, sizeof buf,
  958. "Final-Recipient: %s; %.800s",
  959. p, r->q_user);
  960. }
  961. else if (strchr(r->q_paddr, '@') != NULL)
  962. {
  963. char *qp;
  964. bool b;
  965. qp = r->q_paddr;
  966. /* strip brackets from address */
  967. b = FALSE;
  968. if (*qp == '<')
  969. {
  970. b = qp[strlen(qp) - 1]  == '>';
  971. if (b)
  972. qp[strlen(qp) - 1] = '';
  973. qp++;
  974. }
  975. (void) snprintf(buf, sizeof buf,
  976. "Final-Recipient: %s; %.800s",
  977. p, qp);
  978. /* undo damage */
  979. if (b)
  980. qp[strlen(qp)] = '>';
  981. }
  982. else
  983. {
  984. (void) snprintf(buf, sizeof buf,
  985. "Final-Recipient: %s; %.700s@%.100s",
  986. p, r->q_user, MyHostName);
  987. }
  988. putline(buf, mci);
  989. /* X-Actual-Recipient: -- the real problem address */
  990. if (r != q && q->q_user[0] != '')
  991. {
  992. if (q->q_mailer != NULL &&
  993.     q->q_mailer->m_addrtype != NULL)
  994. p = q->q_mailer->m_addrtype;
  995. else
  996. p = "rfc822";
  997. if (strcasecmp(p, "rfc822") == 0 &&
  998.     strchr(q->q_user, '@') == NULL)
  999. {
  1000. (void) snprintf(buf, sizeof buf,
  1001. "X-Actual-Recipient: %s; %.700s@%.100s",
  1002. p, q->q_user,
  1003. MyHostName);
  1004. }
  1005. else
  1006. {
  1007. (void) snprintf(buf, sizeof buf,
  1008. "X-Actual-Recipient: %s; %.800s",
  1009. p, q->q_user);
  1010. }
  1011. putline(buf, mci);
  1012. }
  1013. /* Action: -- what happened? */
  1014. snprintf(buf, sizeof buf, "Action: %s", action);
  1015. putline(buf, mci);
  1016. /* Status: -- what _really_ happened? */
  1017. if (q->q_status != NULL)
  1018. p = q->q_status;
  1019. else if (QS_IS_BADADDR(q->q_state))
  1020. p = "5.0.0";
  1021. else if (QS_IS_QUEUEUP(q->q_state))
  1022. p = "4.0.0";
  1023. else
  1024. p = "2.0.0";
  1025. snprintf(buf, sizeof buf, "Status: %s", p);
  1026. putline(buf, mci);
  1027. /* Remote-MTA: -- who was I talking to? */
  1028. if (q->q_statmta != NULL)
  1029. {
  1030. if (q->q_mailer == NULL ||
  1031.     (p = q->q_mailer->m_mtatype) == NULL)
  1032. p = "dns";
  1033. (void) snprintf(buf, sizeof buf,
  1034. "Remote-MTA: %s; %.800s",
  1035. p, q->q_statmta);
  1036. p = &buf[strlen(buf) - 1];
  1037. if (*p == '.')
  1038. *p = '';
  1039. putline(buf, mci);
  1040. }
  1041. /* Diagnostic-Code: -- actual result from other end */
  1042. if (q->q_rstatus != NULL)
  1043. {
  1044. p = q->q_mailer->m_diagtype;
  1045. if (p == NULL)
  1046. p = "smtp";
  1047. (void) snprintf(buf, sizeof buf,
  1048. "Diagnostic-Code: %s; %.800s",
  1049. p, q->q_rstatus);
  1050. putline(buf, mci);
  1051. }
  1052. /* Last-Attempt-Date: -- fine granularity */
  1053. if (q->q_statdate == (time_t) 0L)
  1054. q->q_statdate = curtime();
  1055. (void) snprintf(buf, sizeof buf,
  1056. "Last-Attempt-Date: %s",
  1057. arpadate(ctime(&q->q_statdate)));
  1058. putline(buf, mci);
  1059. /* Will-Retry-Until: -- for delayed messages only */
  1060. if (QS_IS_QUEUEUP(q->q_state))
  1061. {
  1062. time_t xdate;
  1063. xdate = e->e_parent->e_ctime +
  1064. TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
  1065. snprintf(buf, sizeof buf,
  1066.  "Will-Retry-Until: %s",
  1067.  arpadate(ctime(&xdate)));
  1068. putline(buf, mci);
  1069. }
  1070. }
  1071. }
  1072. #endif /* DSN */
  1073. /*
  1074. **  Output text of original message
  1075. */
  1076. putline("", mci);
  1077. if (bitset(EF_HAS_DF, e->e_parent->e_flags))
  1078. {
  1079. sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
  1080.    !bitset(EF_NO_BODY_RETN, e->e_flags);
  1081. if (e->e_msgboundary == NULL)
  1082. {
  1083. if (sendbody)
  1084. putline("   ----- Original message follows -----n", mci);
  1085. else
  1086. putline("   ----- Message header follows -----n", mci);
  1087. }
  1088. else
  1089. {
  1090. (void) snprintf(buf, sizeof buf, "--%s",
  1091. e->e_msgboundary);
  1092. putline(buf, mci);
  1093. (void) snprintf(buf, sizeof buf, "Content-Type: %s",
  1094. sendbody ? "message/rfc822"
  1095.  : "text/rfc822-headers");
  1096. putline(buf, mci);
  1097. p = hvalue("Content-Transfer-Encoding",
  1098.    e->e_parent->e_header);
  1099. if (p != NULL && strcasecmp(p, "binary") != 0)
  1100. p = NULL;
  1101. if (p == NULL &&
  1102.     bitset(EF_HAS8BIT, e->e_parent->e_flags))
  1103. p = "8bit";
  1104. if (p != NULL)
  1105. {
  1106. (void) snprintf(buf, sizeof buf,
  1107. "Content-Transfer-Encoding: %s",
  1108. p);
  1109. putline(buf, mci);
  1110. }
  1111. }
  1112. putline("", mci);
  1113. save_errno = errno;
  1114. putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
  1115. errno = save_errno;
  1116. if (sendbody)
  1117. putbody(mci, e->e_parent, e->e_msgboundary);
  1118. else if (e->e_msgboundary == NULL)
  1119. {
  1120. putline("", mci);
  1121. putline("   ----- Message body suppressed -----", mci);
  1122. }
  1123. }
  1124. else if (e->e_msgboundary == NULL)
  1125. {
  1126. putline("  ----- No message was collected -----n", mci);
  1127. }
  1128. if (e->e_msgboundary != NULL)
  1129. {
  1130. putline("", mci);
  1131. (void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
  1132. putline(buf, mci);
  1133. }
  1134. putline("", mci);
  1135. (void) fflush(mci->mci_out);
  1136. /*
  1137. **  Cleanup and exit
  1138. */
  1139. if (errno != 0)
  1140. syserr("errbody: I/O error");
  1141. }
  1142. /*
  1143. **  SMTPTODSN -- convert SMTP to DSN status code
  1144. **
  1145. ** Parameters:
  1146. ** smtpstat -- the smtp status code (e.g., 550).
  1147. **
  1148. ** Returns:
  1149. ** The DSN version of the status code.
  1150. */
  1151. char *
  1152. smtptodsn(smtpstat)
  1153. int smtpstat;
  1154. {
  1155. if (smtpstat < 0)
  1156. return "4.4.2";
  1157. switch (smtpstat)
  1158. {
  1159.   case 450: /* Req mail action not taken: mailbox unavailable */
  1160. return "4.2.0";
  1161.   case 451: /* Req action aborted: local error in processing */
  1162. return "4.3.0";
  1163.   case 452: /* Req action not taken: insufficient sys storage */
  1164. return "4.3.1";
  1165.   case 500: /* Syntax error, command unrecognized */
  1166. return "5.5.2";
  1167.   case 501: /* Syntax error in parameters or arguments */
  1168. return "5.5.4";
  1169.   case 502: /* Command not implemented */
  1170. return "5.5.1";
  1171.   case 503: /* Bad sequence of commands */
  1172. return "5.5.1";
  1173.   case 504: /* Command parameter not implemented */
  1174. return "5.5.4";
  1175.   case 550: /* Req mail action not taken: mailbox unavailable */
  1176. return "5.2.0";
  1177.   case 551: /* User not local; please try <...> */
  1178. return "5.1.6";
  1179.   case 552: /* Req mail action aborted: exceeded storage alloc */
  1180. return "5.2.2";
  1181.   case 553: /* Req action not taken: mailbox name not allowed */
  1182. return "5.1.0";
  1183.   case 554: /* Transaction failed */
  1184. return "5.0.0";
  1185. }
  1186. if ((smtpstat / 100) == 2)
  1187. return "2.0.0";
  1188. if ((smtpstat / 100) == 4)
  1189. return "4.0.0";
  1190. return "5.0.0";
  1191. }
  1192. /*
  1193. **  XTEXTIFY -- take regular text and turn it into DSN-style xtext
  1194. **
  1195. ** Parameters:
  1196. ** t -- the text to convert.
  1197. ** taboo -- additional characters that must be encoded.
  1198. **
  1199. ** Returns:
  1200. ** The xtext-ified version of the same string.
  1201. */
  1202. char *
  1203. xtextify(t, taboo)
  1204. register char *t;
  1205. char *taboo;
  1206. {
  1207. register char *p;
  1208. int l;
  1209. int nbogus;
  1210. static char *bp = NULL;
  1211. static int bplen = 0;
  1212. if (taboo == NULL)
  1213. taboo = "";
  1214. /* figure out how long this xtext will have to be */
  1215. nbogus = l = 0;
  1216. for (p = t; *p != ''; p++)
  1217. {
  1218. register int c = (*p & 0xff);
  1219. /* ASCII dependence here -- this is the way the spec words it */
  1220. if (c < '!' || c > '~' || c == '+' || c == '\' || c == '(' ||
  1221.     strchr(taboo, c) != NULL)
  1222. nbogus++;
  1223. l++;
  1224. }
  1225. if (nbogus == 0)
  1226. return t;
  1227. l += nbogus * 2 + 1;
  1228. /* now allocate space if necessary for the new string */
  1229. if (l > bplen)
  1230. {
  1231. if (bp != NULL)
  1232. free(bp);
  1233. bp = xalloc(l);
  1234. bplen = l;
  1235. }
  1236. /* ok, copy the text with byte expansion */
  1237. for (p = bp; *t != ''; )
  1238. {
  1239. register int c = (*t++ & 0xff);
  1240. /* ASCII dependence here -- this is the way the spec words it */
  1241. if (c < '!' || c > '~' || c == '+' || c == '\' || c == '(' ||
  1242.     strchr(taboo, c) != NULL)
  1243. {
  1244. *p++ = '+';
  1245. *p++ = "0123456789abcdef"[c >> 4];
  1246. *p++ = "0123456789abcdef"[c & 0xf];
  1247. }
  1248. else
  1249. *p++ = c;
  1250. }
  1251. *p = '';
  1252. return bp;
  1253. }
  1254. /*
  1255. **  XUNTEXTIFY -- take xtext and turn it into plain text
  1256. **
  1257. ** Parameters:
  1258. ** t -- the xtextified text.
  1259. **
  1260. ** Returns:
  1261. ** The decoded text.  No attempt is made to deal with
  1262. ** null strings in the resulting text.
  1263. */
  1264. char *
  1265. xuntextify(t)
  1266. register char *t;
  1267. {
  1268. register char *p;
  1269. int l;
  1270. static char *bp = NULL;
  1271. static int bplen = 0;
  1272. /* heuristic -- if no plus sign, just return the input */
  1273. if (strchr(t, '+') == NULL)
  1274. return t;
  1275. /* xtext is always longer than decoded text */
  1276. l = strlen(t);
  1277. if (l > bplen)
  1278. {
  1279. if (bp != NULL)
  1280. free(bp);
  1281. bp = xalloc(l);
  1282. bplen = l;
  1283. }
  1284. /* ok, copy the text with byte compression */
  1285. for (p = bp; *t != ''; t++)
  1286. {
  1287. register int c = *t & 0xff;
  1288. if (c != '+')
  1289. {
  1290. *p++ = c;
  1291. continue;
  1292. }
  1293. c = *++t & 0xff;
  1294. if (!isascii(c) || !isxdigit(c))
  1295. {
  1296. /* error -- first digit is not hex */
  1297. usrerr("bogus xtext: +%c", c);
  1298. t--;
  1299. continue;
  1300. }
  1301. if (isdigit(c))
  1302. c -= '0';
  1303. else if (isupper(c))
  1304. c -= 'A' - 10;
  1305. else
  1306. c -= 'a' - 10;
  1307. *p = c << 4;
  1308. c = *++t & 0xff;
  1309. if (!isascii(c) || !isxdigit(c))
  1310. {
  1311. /* error -- second digit is not hex */
  1312. usrerr("bogus xtext: +%x%c", *p >> 4, c);
  1313. t--;
  1314. continue;
  1315. }
  1316. if (isdigit(c))
  1317. c -= '0';
  1318. else if (isupper(c))
  1319. c -= 'A' - 10;
  1320. else
  1321. c -= 'a' - 10;
  1322. *p++ |= c;
  1323. }
  1324. *p = '';
  1325. return bp;
  1326. }
  1327. /*
  1328. **  XTEXTOK -- check if a string is legal xtext
  1329. **
  1330. ** Xtext is used in Delivery Status Notifications.  The spec was
  1331. ** taken from RFC 1891, ``SMTP Service Extension for Delivery
  1332. ** Status Notifications''.
  1333. **
  1334. ** Parameters:
  1335. ** s -- the string to check.
  1336. **
  1337. ** Returns:
  1338. ** TRUE -- if 's' is legal xtext.
  1339. ** FALSE -- if it has any illegal characters in it.
  1340. */
  1341. bool
  1342. xtextok(s)
  1343. char *s;
  1344. {
  1345. int c;
  1346. while ((c = *s++) != '')
  1347. {
  1348. if (c == '+')
  1349. {
  1350. c = *s++;
  1351. if (!isascii(c) || !isxdigit(c))
  1352. return FALSE;
  1353. c = *s++;
  1354. if (!isascii(c) || !isxdigit(c))
  1355. return FALSE;
  1356. }
  1357. else if (c < '!' || c > '~' || c == '=')
  1358. return FALSE;
  1359. }
  1360. return TRUE;
  1361. }
  1362. /*
  1363. **  PRUNEROUTE -- prune an RFC-822 source route
  1364. **
  1365. ** Trims down a source route to the last internet-registered hop.
  1366. ** This is encouraged by RFC 1123 section 5.3.3.
  1367. **
  1368. ** Parameters:
  1369. ** addr -- the address
  1370. **
  1371. ** Returns:
  1372. ** TRUE -- address was modified
  1373. ** FALSE -- address could not be pruned
  1374. **
  1375. ** Side Effects:
  1376. ** modifies addr in-place
  1377. */
  1378. static bool
  1379. pruneroute(addr)
  1380. char *addr;
  1381. {
  1382. #if NAMED_BIND
  1383. char *start, *at, *comma;
  1384. char c;
  1385. int rcode;
  1386. int i;
  1387. char hostbuf[BUFSIZ];
  1388. char *mxhosts[MAXMXHOSTS + 1];
  1389. /* check to see if this is really a route-addr */
  1390. if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
  1391. return FALSE;
  1392. start = strchr(addr, ':');
  1393. at = strrchr(addr, '@');
  1394. if (start == NULL || at == NULL || at < start)
  1395. return FALSE;
  1396. /* slice off the angle brackets */
  1397. i = strlen(at + 1);
  1398. if (i >= (SIZE_T) sizeof hostbuf)
  1399. return FALSE;
  1400. (void) strlcpy(hostbuf, at + 1, sizeof hostbuf);
  1401. hostbuf[i - 1] = '';
  1402. while (start)
  1403. {
  1404. if (getmxrr(hostbuf, mxhosts, NULL, FALSE, &rcode) > 0)
  1405. {
  1406. (void) strlcpy(addr + 1, start + 1, strlen(addr) - 1);
  1407. return TRUE;
  1408. }
  1409. c = *start;
  1410. *start = '';
  1411. comma = strrchr(addr, ',');
  1412. if (comma != NULL && comma[1] == '@' &&
  1413.     strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
  1414. (void) strlcpy(hostbuf, comma + 2, sizeof hostbuf);
  1415. else
  1416. comma = NULL;
  1417. *start = c;
  1418. start = comma;
  1419. }
  1420. #endif /* NAMED_BIND */
  1421. return FALSE;
  1422. }