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

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: err.c,v 8.116 1999/11/29 18:12:11 gshapiro Exp $";
  15. #endif /* ! lint */
  16. #include <sendmail.h>
  17. #ifdef LDAPMAP
  18. # include <lber.h>
  19. # include <ldap.h> /* for LDAP error codes */
  20. #endif /* LDAPMAP */
  21. static void putoutmsg __P((char *, bool, bool));
  22. static void puterrmsg __P((char *));
  23. static char *fmtmsg __P((char *, const char *, const char *, const char *,
  24.      int, const char *, va_list));
  25. /*
  26. **  SYSERR -- Print error message.
  27. **
  28. ** Prints an error message via printf to the diagnostic output.
  29. **
  30. ** If the first character of the syserr message is `!' it will
  31. ** log this as an ALERT message and exit immediately.  This can
  32. ** leave queue files in an indeterminate state, so it should not
  33. ** be used lightly.
  34. **
  35. ** Parameters:
  36. ** fmt -- the format string.  If it does not begin with
  37. ** a three-digit SMTP reply code, either 554 or
  38. ** 451 is assumed depending on whether errno
  39. ** is set.
  40. ** (others) -- parameters
  41. **
  42. ** Returns:
  43. ** none
  44. ** Through TopFrame if QuickAbort is set.
  45. **
  46. ** Side Effects:
  47. ** increments Errors.
  48. ** sets ExitStat.
  49. */
  50. char MsgBuf[BUFSIZ*2]; /* text of most recent message */
  51. static char HeldMessageBuf[sizeof MsgBuf]; /* for held messages */
  52. #if NAMED_BIND && !defined(NO_DATA)
  53. # define NO_DATA NO_ADDRESS
  54. #endif /* NAMED_BIND && !defined(NO_DATA) */
  55. void
  56. /*VARARGS1*/
  57. #ifdef __STDC__
  58. syserr(const char *fmt, ...)
  59. #else /* __STDC__ */
  60. syserr(fmt, va_alist)
  61. const char *fmt;
  62. va_dcl
  63. #endif /* __STDC__ */
  64. {
  65. register char *p;
  66. int save_errno = errno;
  67. bool panic;
  68. char *user;
  69. char *enhsc;
  70. char *errtxt;
  71. struct passwd *pw;
  72. char ubuf[80];
  73. VA_LOCAL_DECL
  74. panic = *fmt == '!';
  75. if (panic)
  76. {
  77. fmt++;
  78. HoldErrs = FALSE;
  79. }
  80. /* format and output the error message */
  81. if (save_errno == 0)
  82. {
  83. p = "554";
  84. enhsc = "5.0.0";
  85. }
  86. else
  87. {
  88. p = "451";
  89. enhsc = "4.0.0";
  90. }
  91. VA_START(fmt);
  92. errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
  93. VA_END;
  94. puterrmsg(MsgBuf);
  95. /* save this message for mailq printing */
  96. if (!panic && CurEnv != NULL)
  97. {
  98. if (CurEnv->e_message != NULL)
  99. free(CurEnv->e_message);
  100. CurEnv->e_message = newstr(errtxt);
  101. }
  102. /* determine exit status if not already set */
  103. if (ExitStat == EX_OK)
  104. {
  105. if (save_errno == 0)
  106. ExitStat = EX_SOFTWARE;
  107. else
  108. ExitStat = EX_OSERR;
  109. if (tTd(54, 1))
  110. dprintf("syserr: ExitStat = %dn", ExitStat);
  111. }
  112. pw = sm_getpwuid(getuid());
  113. if (pw != NULL)
  114. user = pw->pw_name;
  115. else
  116. {
  117. user = ubuf;
  118. snprintf(ubuf, sizeof ubuf, "UID%d", (int) getuid());
  119. }
  120. if (LogLevel > 0)
  121. sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
  122.   CurEnv == NULL ? NOQID : CurEnv->e_id,
  123.   "SYSERR(%s): %.900s",
  124.   user, errtxt);
  125. switch (save_errno)
  126. {
  127.   case EBADF:
  128.   case ENFILE:
  129.   case EMFILE:
  130.   case ENOTTY:
  131. #ifdef EFBIG
  132.   case EFBIG:
  133. #endif /* EFBIG */
  134. #ifdef ESPIPE
  135.   case ESPIPE:
  136. #endif /* ESPIPE */
  137. #ifdef EPIPE
  138.   case EPIPE:
  139. #endif /* EPIPE */
  140. #ifdef ENOBUFS
  141.   case ENOBUFS:
  142. #endif /* ENOBUFS */
  143. #ifdef ESTALE
  144.   case ESTALE:
  145. #endif /* ESTALE */
  146. printopenfds(TRUE);
  147. mci_dump_all(TRUE);
  148. break;
  149. }
  150. if (panic)
  151. {
  152. #ifdef XLA
  153. xla_all_end();
  154. #endif /* XLA */
  155. sync_queue_time();
  156. if (tTd(0, 1))
  157. abort();
  158. exit(EX_OSERR);
  159. }
  160. errno = 0;
  161. if (QuickAbort)
  162. longjmp(TopFrame, 2);
  163. }
  164. /*
  165. **  USRERR -- Signal user error.
  166. **
  167. ** This is much like syserr except it is for user errors.
  168. **
  169. ** Parameters:
  170. ** fmt -- the format string.  If it does not begin with
  171. ** a three-digit SMTP reply code, 501 is assumed.
  172. ** (others) -- printf strings
  173. **
  174. ** Returns:
  175. ** none
  176. ** Through TopFrame if QuickAbort is set.
  177. **
  178. ** Side Effects:
  179. ** increments Errors.
  180. */
  181. /*VARARGS1*/
  182. void
  183. #ifdef __STDC__
  184. usrerr(const char *fmt, ...)
  185. #else /* __STDC__ */
  186. usrerr(fmt, va_alist)
  187. const char *fmt;
  188. va_dcl
  189. #endif /* __STDC__ */
  190. {
  191. char *enhsc;
  192. char *errtxt;
  193. VA_LOCAL_DECL
  194. if (fmt[0] == '5' || fmt[0] == '6')
  195. enhsc = "5.0.0";
  196. else if (fmt[0] == '4' || fmt[0] == '8')
  197. enhsc = "4.0.0";
  198. else if (fmt[0] == '2')
  199. enhsc = "2.0.0";
  200. else
  201. enhsc = NULL;
  202. VA_START(fmt);
  203. errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "501", enhsc, 0, fmt, ap);
  204. VA_END;
  205. if (SuprErrs)
  206. return;
  207. /* save this message for mailq printing */
  208. switch (MsgBuf[0])
  209. {
  210.   case '4':
  211.   case '8':
  212. if (CurEnv->e_message != NULL)
  213. break;
  214. /* FALLTHROUGH */
  215.   case '5':
  216.   case '6':
  217. if (CurEnv->e_message != NULL)
  218. free(CurEnv->e_message);
  219. if (MsgBuf[0] == '6')
  220. {
  221. char buf[MAXLINE];
  222. snprintf(buf, sizeof buf, "Postmaster warning: %.*s",
  223. (int) sizeof buf - 22, errtxt);
  224. CurEnv->e_message = newstr(buf);
  225. }
  226. else
  227. {
  228. CurEnv->e_message = newstr(errtxt);
  229. }
  230. break;
  231. }
  232. puterrmsg(MsgBuf);
  233. if (LogLevel > 3 && LogUsrErrs)
  234. sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
  235. if (QuickAbort)
  236. longjmp(TopFrame, 1);
  237. }
  238. /*
  239. **  USRERRENH -- Signal user error.
  240. **
  241. ** Same as usrerr but with enhanced status code.
  242. **
  243. ** Parameters:
  244. ** enhsc -- the enhanced status code.
  245. ** fmt -- the format string.  If it does not begin with
  246. ** a three-digit SMTP reply code, 501 is assumed.
  247. ** (others) -- printf strings
  248. **
  249. ** Returns:
  250. ** none
  251. ** Through TopFrame if QuickAbort is set.
  252. **
  253. ** Side Effects:
  254. ** increments Errors.
  255. */
  256. /*VARARGS1*/
  257. void
  258. #ifdef __STDC__
  259. usrerrenh(char *enhsc, const char *fmt, ...)
  260. #else /* __STDC__ */
  261. usrerrenh(enhsc, fmt, va_alist)
  262. char *enhsc;
  263. const char *fmt;
  264. va_dcl
  265. #endif /* __STDC__ */
  266. {
  267. char *errtxt;
  268. VA_LOCAL_DECL
  269. if (enhsc == NULL || *enhsc == '')
  270. {
  271. if (fmt[0] == '5' || fmt[0] == '6')
  272. enhsc = "5.0.0";
  273. else if (fmt[0] == '4' || fmt[0] == '8')
  274. enhsc = "4.0.0";
  275. else if (fmt[0] == '2')
  276. enhsc = "2.0.0";
  277. }
  278. VA_START(fmt);
  279. errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "501", enhsc, 0, fmt, ap);
  280. VA_END;
  281. if (SuprErrs)
  282. return;
  283. /* save this message for mailq printing */
  284. switch (MsgBuf[0])
  285. {
  286.   case '4':
  287.   case '8':
  288. if (CurEnv->e_message != NULL)
  289. break;
  290. /* FALLTHROUGH */
  291.   case '5':
  292.   case '6':
  293. if (CurEnv->e_message != NULL)
  294. free(CurEnv->e_message);
  295. if (MsgBuf[0] == '6')
  296. {
  297. char buf[MAXLINE];
  298. snprintf(buf, sizeof buf, "Postmaster warning: %.*s",
  299. (int) sizeof buf - 22, errtxt);
  300. CurEnv->e_message = newstr(buf);
  301. }
  302. else
  303. {
  304. CurEnv->e_message = newstr(errtxt);
  305. }
  306. break;
  307. }
  308. puterrmsg(MsgBuf);
  309. if (LogLevel > 3 && LogUsrErrs)
  310. sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
  311. if (QuickAbort)
  312. longjmp(TopFrame, 1);
  313. }
  314. /*
  315. **  MESSAGE -- print message (not necessarily an error)
  316. **
  317. ** Parameters:
  318. ** msg -- the message (printf fmt) -- it can begin with
  319. ** an SMTP reply code.  If not, 050 is assumed.
  320. ** (others) -- printf arguments
  321. **
  322. ** Returns:
  323. ** none
  324. **
  325. ** Side Effects:
  326. ** none.
  327. */
  328. /*VARARGS1*/
  329. void
  330. #ifdef __STDC__
  331. message(const char *msg, ...)
  332. #else /* __STDC__ */
  333. message(msg, va_alist)
  334. const char *msg;
  335. va_dcl
  336. #endif /* __STDC__ */
  337. {
  338. char *errtxt;
  339. VA_LOCAL_DECL
  340. errno = 0;
  341. VA_START(msg);
  342. errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
  343. VA_END;
  344. putoutmsg(MsgBuf, FALSE, FALSE);
  345. /* save this message for mailq printing */
  346. switch (MsgBuf[0])
  347. {
  348.   case '4':
  349.   case '8':
  350. if (CurEnv->e_message != NULL)
  351. break;
  352. /* FALLTHROUGH */
  353.   case '5':
  354. if (CurEnv->e_message != NULL)
  355. free(CurEnv->e_message);
  356. CurEnv->e_message = newstr(errtxt);
  357. break;
  358. }
  359. }
  360. /*
  361. **  NMESSAGE -- print message (not necessarily an error)
  362. **
  363. ** Just like "message" except it never puts the to... tag on.
  364. **
  365. ** Parameters:
  366. ** msg -- the message (printf fmt) -- if it begins
  367. ** with a three digit SMTP reply code, that is used,
  368. ** otherwise 050 is assumed.
  369. ** (others) -- printf arguments
  370. **
  371. ** Returns:
  372. ** none
  373. **
  374. ** Side Effects:
  375. ** none.
  376. */
  377. /*VARARGS1*/
  378. void
  379. #ifdef __STDC__
  380. nmessage(const char *msg, ...)
  381. #else /* __STDC__ */
  382. nmessage(msg, va_alist)
  383. const char *msg;
  384. va_dcl
  385. #endif /* __STDC__ */
  386. {
  387. char *errtxt;
  388. VA_LOCAL_DECL
  389. errno = 0;
  390. VA_START(msg);
  391. errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
  392. (char *) NULL, 0, msg, ap);
  393. VA_END;
  394. putoutmsg(MsgBuf, FALSE, FALSE);
  395. /* save this message for mailq printing */
  396. switch (MsgBuf[0])
  397. {
  398.   case '4':
  399.   case '8':
  400. if (CurEnv->e_message != NULL)
  401. break;
  402. /* FALLTHROUGH */
  403.   case '5':
  404. if (CurEnv->e_message != NULL)
  405. free(CurEnv->e_message);
  406. CurEnv->e_message = newstr(errtxt);
  407. break;
  408. }
  409. }
  410. /*
  411. **  PUTOUTMSG -- output error message to transcript and channel
  412. **
  413. ** Parameters:
  414. ** msg -- message to output (in SMTP format).
  415. ** holdmsg -- if TRUE, don't output a copy of the message to
  416. ** our output channel.
  417. ** heldmsg -- if TRUE, this is a previously held message;
  418. ** don't log it to the transcript file.
  419. **
  420. ** Returns:
  421. ** none.
  422. **
  423. ** Side Effects:
  424. ** Outputs msg to the transcript.
  425. ** If appropriate, outputs it to the channel.
  426. ** Deletes SMTP reply code number as appropriate.
  427. */
  428. static void
  429. putoutmsg(msg, holdmsg, heldmsg)
  430. char *msg;
  431. bool holdmsg;
  432. bool heldmsg;
  433. {
  434. char *errtxt = msg;
  435. char msgcode = msg[0];
  436. /* display for debugging */
  437. if (tTd(54, 8))
  438. dprintf("--- %s%s%sn", msg, holdmsg ? " (hold)" : "",
  439. heldmsg ? " (held)" : "");
  440. /* map warnings to something SMTP can handle */
  441. if (msgcode == '6')
  442. msg[0] = '5';
  443. else if (msgcode == '8')
  444. msg[0] = '4';
  445. /* output to transcript if serious */
  446. if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
  447.     strchr("45", msg[0]) != NULL)
  448. fprintf(CurEnv->e_xfp, "%sn", msg);
  449. if (LogLevel >= 15 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
  450. sm_syslog(LOG_INFO, CurEnv->e_id,
  451.   "--> %s%s",
  452.   msg, holdmsg ? " (held)" : "");
  453. if (msgcode == '8')
  454. msg[0] = '0';
  455. /* output to channel if appropriate */
  456. if (!Verbose && msg[0] == '0')
  457. return;
  458. if (holdmsg)
  459. {
  460. /* save for possible future display */
  461. msg[0] = msgcode;
  462. snprintf(HeldMessageBuf, sizeof HeldMessageBuf, "%s", msg);
  463. return;
  464. }
  465. (void) fflush(stdout);
  466. if (OutChannel == NULL)
  467. return;
  468. /* find actual text of error (after SMTP status codes) */
  469. if (ISSMTPREPLY(errtxt))
  470. {
  471. int l;
  472. errtxt += 4;
  473. l = isenhsc(errtxt, ' ');
  474. if (l <= 0)
  475. l = isenhsc(errtxt, '');
  476. if (l > 0)
  477. errtxt += l + 1;
  478. }
  479. /* if DisConnected, OutChannel now points to the transcript */
  480. if (!DisConnected &&
  481.     (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
  482. fprintf(OutChannel, "%srn", msg);
  483. else
  484. fprintf(OutChannel, "%sn", errtxt);
  485. if (TrafficLogFile != NULL)
  486. fprintf(TrafficLogFile, "%05d >>> %sn", (int) getpid(),
  487. (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : errtxt);
  488. if (msg[3] == ' ')
  489. (void) fflush(OutChannel);
  490. if (!ferror(OutChannel) || DisConnected)
  491. return;
  492. /*
  493. **  Error on output -- if reporting lost channel, just ignore it.
  494. **  Also, ignore errors from QUIT response (221 message) -- some
  495. ** rude servers don't read result.
  496. */
  497. if (InChannel == NULL || feof(InChannel) || ferror(InChannel) ||
  498.     strncmp(msg, "221", 3) == 0)
  499. return;
  500. /* can't call syserr, 'cause we are using MsgBuf */
  501. HoldErrs = TRUE;
  502. if (LogLevel > 0)
  503. sm_syslog(LOG_CRIT, CurEnv->e_id,
  504.   "SYSERR: putoutmsg (%s): error on output channel sending "%s": %s",
  505.   CurHostName == NULL ? "NO-HOST" : CurHostName,
  506.   shortenstring(msg, MAXSHORTSTR), errstring(errno));
  507. }
  508. /*
  509. **  PUTERRMSG -- like putoutmsg, but does special processing for error messages
  510. **
  511. ** Parameters:
  512. ** msg -- the message to output.
  513. **
  514. ** Returns:
  515. ** none.
  516. **
  517. ** Side Effects:
  518. ** Sets the fatal error bit in the envelope as appropriate.
  519. */
  520. static void
  521. puterrmsg(msg)
  522. char *msg;
  523. {
  524. char msgcode = msg[0];
  525. /* output the message as usual */
  526. putoutmsg(msg, HoldErrs, FALSE);
  527. /* be careful about multiple error messages */
  528. if (OnlyOneError)
  529. HoldErrs = TRUE;
  530. /* signal the error */
  531. Errors++;
  532. if (CurEnv == NULL)
  533. return;
  534. if (msgcode == '6')
  535. {
  536. /* notify the postmaster */
  537. CurEnv->e_flags |= EF_PM_NOTIFY;
  538. }
  539. else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
  540. {
  541. /* mark long-term fatal errors */
  542. CurEnv->e_flags |= EF_FATALERRS;
  543. }
  544. }
  545. /*
  546. **  ISENHSC -- check whether a string contains an enhanced status code
  547. **
  548. ** Parameters:
  549. ** s -- string with possible enhanced status code.
  550. ** delim -- delim for enhanced status code.
  551. **
  552. ** Returns:
  553. ** 0  -- no enhanced status code.
  554. ** >4 -- length of enhanced status code.
  555. **
  556. ** Side Effects:
  557. ** none.
  558. */
  559. int
  560. isenhsc(s, delim)
  561. const char *s;
  562. int delim;
  563. {
  564. int l, h;
  565. if (s == NULL)
  566. return 0;
  567. if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
  568. return 0;
  569. h = 0;
  570. l = 2;
  571. while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
  572. ++h;
  573. if (h == 0 || s[l + h] != '.')
  574. return 0;
  575. l += h + 1;
  576. h = 0;
  577. while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
  578. ++h;
  579. if (h == 0 || s[l + h] != delim)
  580. return 0;
  581. return l + h;
  582. }
  583. /*
  584. **  EXTENHSC -- check and extract an enhanced status code
  585. **
  586. ** Parameters:
  587. ** s -- string with possible enhanced status code.
  588. ** delim -- delim for enhanced status code.
  589. ** e -- pointer to storage for enhanced status code.
  590. ** must be != NULL and have space for at least
  591. ** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
  592. **
  593. ** Returns:
  594. ** 0  -- no enhanced status code.
  595. ** >4 -- length of enhanced status code.
  596. **
  597. ** Side Effects:
  598. ** fills e with enhanced status code.
  599. */
  600. int
  601. extenhsc(s, delim, e)
  602. const char *s;
  603. int delim;
  604. char *e;
  605. {
  606. int l, h;
  607. if (s == NULL)
  608. return 0;
  609. if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
  610. return 0;
  611. h = 0;
  612. l = 2;
  613. e[0] = s[0];
  614. e[1] = '.';
  615. while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
  616. {
  617. e[l + h] = s[l + h];
  618. ++h;
  619. }
  620. if (h == 0 || s[l + h] != '.')
  621. return 0;
  622. e[l + h] = '.';
  623. l += h + 1;
  624. h = 0;
  625. while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
  626. {
  627. e[l + h] = s[l + h];
  628. ++h;
  629. }
  630. if (h == 0 || s[l + h] != delim)
  631. return 0;
  632. e[l + h] = '';
  633. return l + h;
  634. }
  635. /*
  636. **  FMTMSG -- format a message into buffer.
  637. **
  638. ** Parameters:
  639. ** eb -- error buffer to get result -- MUST BE MsgBuf.
  640. ** to -- the recipient tag for this message.
  641. ** num -- default three digit SMTP reply code.
  642. ** enhsc -- enhanced status code.
  643. ** en -- the error number to display.
  644. ** fmt -- format of string.
  645. ** ap -- arguments for fmt.
  646. **
  647. ** Returns:
  648. ** pointer to error text beyond status codes.
  649. **
  650. ** Side Effects:
  651. ** none.
  652. */
  653. static char *
  654. fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
  655. register char *eb;
  656. const char *to;
  657. const char *num;
  658. const char *enhsc;
  659. int eno;
  660. const char *fmt;
  661. va_list ap;
  662. {
  663. char del;
  664. int l;
  665. int spaceleft = sizeof MsgBuf;
  666. char *errtxt;
  667. /* output the reply code */
  668. if (ISSMTPCODE(fmt))
  669. {
  670. num = fmt;
  671. fmt += 4;
  672. }
  673. if (num[3] == '-')
  674. del = '-';
  675. else
  676. del = ' ';
  677. (void) snprintf(eb, spaceleft, "%3.3s%c", num, del);
  678. eb += 4;
  679. spaceleft -= 4;
  680. if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
  681. {
  682. /* copy enh.status code including trailing blank */
  683. l++;
  684. (void) strlcpy(eb, fmt, l + 1);
  685. eb += l;
  686. spaceleft -= l;
  687. fmt += l;
  688. }
  689. else if ((l = isenhsc(enhsc, '')) > 0 && l < spaceleft - 4)
  690. {
  691. /* copy enh.status code */
  692. (void) strlcpy(eb, enhsc, l + 1);
  693. eb[l] = ' ';
  694. eb[++l] = '';
  695. eb += l;
  696. spaceleft -= l;
  697. }
  698. errtxt = eb;
  699. /* output the file name and line number */
  700. if (FileName != NULL)
  701. {
  702. (void) snprintf(eb, spaceleft, "%s: line %d: ",
  703. shortenstring(FileName, 83), LineNumber);
  704. eb += (l = strlen(eb));
  705. spaceleft -= l;
  706. }
  707. /* output the "to" person */
  708. if (to != NULL && to[0] != '' &&
  709.     strncmp(num, "551", 3) != 0 &&
  710.     strncmp(num, "251", 3) != 0)
  711. {
  712. (void) snprintf(eb, spaceleft, "%s... ",
  713. shortenstring(to, MAXSHORTSTR));
  714. spaceleft -= strlen(eb);
  715. while (*eb != '')
  716. *eb++ &= 0177;
  717. }
  718. /* output the message */
  719. (void) vsnprintf(eb, spaceleft, fmt, ap);
  720. spaceleft -= strlen(eb);
  721. while (*eb != '')
  722. *eb++ &= 0177;
  723. /* output the error code, if any */
  724. if (eno != 0)
  725. (void) snprintf(eb, spaceleft, ": %s", errstring(eno));
  726. return errtxt;
  727. }
  728. /*
  729. **  BUFFER_ERRORS -- arrange to buffer future error messages
  730. **
  731. ** Parameters:
  732. ** none
  733. **
  734. ** Returns:
  735. ** none.
  736. */
  737. void
  738. buffer_errors()
  739. {
  740. HeldMessageBuf[0] = '';
  741. HoldErrs = TRUE;
  742. }
  743. /*
  744. **  FLUSH_ERRORS -- flush the held error message buffer
  745. **
  746. ** Parameters:
  747. ** print -- if set, print the message, otherwise just
  748. ** delete it.
  749. **
  750. ** Returns:
  751. ** none.
  752. */
  753. void
  754. flush_errors(print)
  755. bool print;
  756. {
  757. if (print && HeldMessageBuf[0] != '')
  758. putoutmsg(HeldMessageBuf, FALSE, TRUE);
  759. HeldMessageBuf[0] = '';
  760. HoldErrs = FALSE;
  761. }
  762. /*
  763. **  ERRSTRING -- return string description of error code
  764. **
  765. ** Parameters:
  766. ** errnum -- the error number to translate
  767. **
  768. ** Returns:
  769. ** A string description of errnum.
  770. **
  771. ** Side Effects:
  772. ** none.
  773. */
  774. const char *
  775. errstring(errnum)
  776. int errnum;
  777. {
  778. char *dnsmsg;
  779. char *bp;
  780. static char buf[MAXLINE];
  781. #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
  782. extern char *sys_errlist[];
  783. extern int sys_nerr;
  784. #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
  785. /*
  786. **  Handle special network error codes.
  787. **
  788. ** These are 4.2/4.3bsd specific; they should be in daemon.c.
  789. */
  790. dnsmsg = NULL;
  791. switch (errnum)
  792. {
  793. #if defined(DAEMON) && defined(ETIMEDOUT)
  794.   case ETIMEDOUT:
  795.   case ECONNRESET:
  796. bp = buf;
  797. # if HASSTRERROR
  798. snprintf(bp, SPACELEFT(buf, bp), "%s", strerror(errnum));
  799. # else /* HASSTRERROR */
  800. if (errnum >= 0 && errnum < sys_nerr)
  801. snprintf(bp, SPACELEFT(buf, bp), "%s", sys_errlist[errnum]);
  802. else
  803. snprintf(bp, SPACELEFT(buf, bp), "Error %d", errnum);
  804. # endif /* HASSTRERROR */
  805. bp += strlen(bp);
  806. if (CurHostName != NULL)
  807. {
  808. if (errnum == ETIMEDOUT)
  809. {
  810. snprintf(bp, SPACELEFT(buf, bp), " with ");
  811. bp += strlen(bp);
  812. }
  813. else
  814. {
  815. bp = buf;
  816. snprintf(bp, SPACELEFT(buf, bp),
  817. "Connection reset by ");
  818. bp += strlen(bp);
  819. }
  820. snprintf(bp, SPACELEFT(buf, bp), "%s",
  821. shortenstring(CurHostName, MAXSHORTSTR));
  822. bp += strlen(buf);
  823. }
  824. if (SmtpPhase != NULL)
  825. {
  826. snprintf(bp, SPACELEFT(buf, bp), " during %s",
  827. SmtpPhase);
  828. }
  829. return buf;
  830.   case EHOSTDOWN:
  831. if (CurHostName == NULL)
  832. break;
  833. (void) snprintf(buf, sizeof buf, "Host %s is down",
  834. shortenstring(CurHostName, MAXSHORTSTR));
  835. return buf;
  836.   case ECONNREFUSED:
  837. if (CurHostName == NULL)
  838. break;
  839. (void) snprintf(buf, sizeof buf, "Connection refused by %s",
  840. shortenstring(CurHostName, MAXSHORTSTR));
  841. return buf;
  842. #endif /* defined(DAEMON) && defined(ETIMEDOUT) */
  843. #if NAMED_BIND
  844.   case HOST_NOT_FOUND + E_DNSBASE:
  845. dnsmsg = "host not found";
  846. break;
  847.   case TRY_AGAIN + E_DNSBASE:
  848. dnsmsg = "host name lookup failure";
  849. break;
  850.   case NO_RECOVERY + E_DNSBASE:
  851. dnsmsg = "non-recoverable error";
  852. break;
  853.   case NO_DATA + E_DNSBASE:
  854. dnsmsg = "no data known";
  855. break;
  856. #endif /* NAMED_BIND */
  857.   case EPERM:
  858. /* SunOS gives "Not owner" -- this is the POSIX message */
  859. return "Operation not permitted";
  860. /*
  861. **  Error messages used internally in sendmail.
  862. */
  863.   case E_SM_OPENTIMEOUT:
  864. return "Timeout on file open";
  865.   case E_SM_NOSLINK:
  866. return "Symbolic links not allowed";
  867.   case E_SM_NOHLINK:
  868. return "Hard links not allowed";
  869.   case E_SM_REGONLY:
  870. return "Regular files only";
  871.   case E_SM_ISEXEC:
  872. return "Executable files not allowed";
  873.   case E_SM_WWDIR:
  874. return "World writable directory";
  875.   case E_SM_GWDIR:
  876. return "Group writable directory";
  877.   case E_SM_FILECHANGE:
  878. return "File changed after open";
  879.   case E_SM_WWFILE:
  880. return "World writable file";
  881.   case E_SM_GWFILE:
  882. return "Group writable file";
  883.   case E_SM_RFILE:
  884. return "Group/other readable file";
  885. }
  886. if (dnsmsg != NULL)
  887. {
  888. bp = buf;
  889. bp += strlcpy(bp, "Name server: ", sizeof buf);
  890. if (CurHostName != NULL)
  891. {
  892. snprintf(bp, SPACELEFT(buf, bp), "%s: ",
  893. shortenstring(CurHostName, MAXSHORTSTR));
  894. bp += strlen(bp);
  895. }
  896. snprintf(bp, SPACELEFT(buf, bp), "%s", dnsmsg);
  897. return buf;
  898. }
  899. #ifdef LDAPMAP
  900. if (errnum >= E_LDAPBASE)
  901. return ldap_err2string(errnum - E_LDAPBASE);
  902. #endif /* LDAPMAP */
  903. #if HASSTRERROR
  904. return strerror(errnum);
  905. #else /* HASSTRERROR */
  906. if (errnum > 0 && errnum < sys_nerr)
  907. return sys_errlist[errnum];
  908. (void) snprintf(buf, sizeof buf, "Error %d", errnum);
  909. return buf;
  910. #endif /* HASSTRERROR */
  911. }