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