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