122711Sdist /* 268839Seric * Copyright (c) 1983, 1995 Eric P. Allman 362531Sbostic * Copyright (c) 1988, 1993 462531Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822711Sdist 922711Sdist #ifndef lint 10*69888Seric static char sccsid[] = "@(#)savemail.c 8.75 (Berkeley) 06/14/95"; 1133731Sbostic #endif /* not lint */ 1222711Sdist 1363937Seric # include "sendmail.h" 14297Seric 15297Seric /* 16297Seric ** SAVEMAIL -- Save mail on error 17297Seric ** 189375Seric ** If mailing back errors, mail it back to the originator 19297Seric ** together with an error message; otherwise, just put it in 20297Seric ** dead.letter in the user's home directory (if he exists on 21297Seric ** this machine). 22297Seric ** 23297Seric ** Parameters: 249337Seric ** e -- the envelope containing the message in error. 2567981Seric ** sendbody -- if TRUE, also send back the body of the 2667981Seric ** message; otherwise just send the header. 27297Seric ** 28297Seric ** Returns: 29297Seric ** none 30297Seric ** 31297Seric ** Side Effects: 32297Seric ** Saves the letter, by writing or mailing it back to the 33297Seric ** sender, or by putting it in dead.letter in her home 34297Seric ** directory. 35297Seric */ 36297Seric 3724942Seric /* defines for state machine */ 3824942Seric # define ESM_REPORT 0 /* report to sender's terminal */ 3924942Seric # define ESM_MAIL 1 /* mail back to sender */ 4024942Seric # define ESM_QUIET 2 /* messages have already been returned */ 4124942Seric # define ESM_DEADLETTER 3 /* save in ~/dead.letter */ 4224942Seric # define ESM_POSTMASTER 4 /* return to postmaster */ 4324942Seric # define ESM_USRTMP 5 /* save in /usr/tmp/dead.letter */ 4424942Seric # define ESM_PANIC 6 /* leave the locked queue/transcript files */ 4524942Seric # define ESM_DONE 7 /* the message is successfully delivered */ 4624942Seric 4765174Seric # ifndef _PATH_VARTMP 4865174Seric # define _PATH_VARTMP "/usr/tmp/" 4965174Seric # endif 5024942Seric 5165174Seric 5269748Seric void 5367981Seric savemail(e, sendbody) 549337Seric register ENVELOPE *e; 5567981Seric bool sendbody; 56297Seric { 57297Seric register struct passwd *pw; 5824942Seric register FILE *fp; 5924942Seric int state; 6059290Seric auto ADDRESS *q = NULL; 6165870Seric register char *p; 6265870Seric MCI mcibuf; 6368802Seric int sfflags; 64297Seric char buf[MAXLINE+1]; 65297Seric extern char *ttypath(); 665846Seric typedef int (*fnptr)(); 6764945Seric extern bool writable(); 68297Seric 697676Seric if (tTd(6, 1)) 7058680Seric { 7166317Seric printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n e_from=", 7266317Seric e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id, 7366317Seric ExitStat); 7458680Seric printaddr(&e->e_from, FALSE); 7558680Seric } 767361Seric 7759101Seric if (e->e_id == NULL) 7859101Seric { 7959101Seric /* can't return a message with no id */ 8059101Seric return; 8159101Seric } 8259101Seric 83297Seric /* 84297Seric ** In the unhappy event we don't know who to return the mail 85297Seric ** to, make someone up. 86297Seric */ 87297Seric 889337Seric if (e->e_from.q_paddr == NULL) 89297Seric { 9058733Seric e->e_sender = "Postmaster"; 9164284Seric if (parseaddr(e->e_sender, &e->e_from, 9264284Seric RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL) 93297Seric { 9458733Seric syserr("553 Cannot parse Postmaster!"); 95297Seric ExitStat = EX_SOFTWARE; 96297Seric finis(); 97297Seric } 98297Seric } 999337Seric e->e_to = NULL; 100297Seric 101297Seric /* 10224942Seric ** Basic state machine. 10324942Seric ** 10424942Seric ** This machine runs through the following states: 10524942Seric ** 10624942Seric ** ESM_QUIET Errors have already been printed iff the 10724942Seric ** sender is local. 10824942Seric ** ESM_REPORT Report directly to the sender's terminal. 10924942Seric ** ESM_MAIL Mail response to the sender. 11024942Seric ** ESM_DEADLETTER Save response in ~/dead.letter. 11124942Seric ** ESM_POSTMASTER Mail response to the postmaster. 11224942Seric ** ESM_PANIC Save response anywhere possible. 113297Seric */ 114297Seric 11524942Seric /* determine starting state */ 11658734Seric switch (e->e_errormode) 117297Seric { 11824942Seric case EM_WRITE: 11924942Seric state = ESM_REPORT; 12024942Seric break; 12124942Seric 12224942Seric case EM_BERKNET: 12324942Seric case EM_MAIL: 12424942Seric state = ESM_MAIL; 12524942Seric break; 12624942Seric 12724942Seric case EM_PRINT: 12824979Seric case '\0': 12924942Seric state = ESM_QUIET; 13024942Seric break; 13124942Seric 13224942Seric case EM_QUIET: 13324942Seric /* no need to return anything at all */ 13424942Seric return; 13524979Seric 13624979Seric default: 13758734Seric syserr("554 savemail: bogus errormode x%x\n", e->e_errormode); 13824979Seric state = ESM_MAIL; 13924979Seric break; 140297Seric } 141297Seric 14259094Seric /* if this is already an error response, send to postmaster */ 14359094Seric if (bitset(EF_RESPONSE, e->e_flags)) 14459094Seric { 14559094Seric if (e->e_parent != NULL && 14659094Seric bitset(EF_RESPONSE, e->e_parent->e_flags)) 14759094Seric { 14859094Seric /* got an error sending a response -- can it */ 14959094Seric return; 15059094Seric } 15159094Seric state = ESM_POSTMASTER; 15259094Seric } 15359094Seric 15424942Seric while (state != ESM_DONE) 155297Seric { 15624979Seric if (tTd(6, 5)) 15724979Seric printf(" state %d\n", state); 15824979Seric 15924942Seric switch (state) 160297Seric { 16124979Seric case ESM_QUIET: 16267473Seric if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags)) 16324979Seric state = ESM_DEADLETTER; 16424979Seric else 16524979Seric state = ESM_MAIL; 16624979Seric break; 16724979Seric 16824942Seric case ESM_REPORT: 16924942Seric 17024942Seric /* 17124942Seric ** If the user is still logged in on the same terminal, 17224942Seric ** then write the error messages back to hir (sic). 17324942Seric */ 17424942Seric 17524942Seric p = ttypath(); 17624942Seric if (p == NULL || freopen(p, "w", stdout) == NULL) 17724942Seric { 17824942Seric state = ESM_MAIL; 17924942Seric break; 18024942Seric } 18124942Seric 18268529Seric expand("\201n", buf, sizeof buf, e); 1839375Seric printf("\r\nMessage from %s...\r\n", buf); 1849375Seric printf("Errors occurred while sending mail.\r\n"); 1859542Seric if (e->e_xfp != NULL) 1869375Seric { 1879542Seric (void) fflush(e->e_xfp); 18824942Seric fp = fopen(queuename(e, 'x'), "r"); 1899375Seric } 1909375Seric else 19124942Seric fp = NULL; 19224942Seric if (fp == NULL) 1939375Seric { 1949337Seric syserr("Cannot open %s", queuename(e, 'x')); 1959375Seric printf("Transcript of session is unavailable.\r\n"); 1969375Seric } 1979375Seric else 1989375Seric { 1999375Seric printf("Transcript follows:\r\n"); 20024942Seric while (fgets(buf, sizeof buf, fp) != NULL && 2019375Seric !ferror(stdout)) 2029375Seric fputs(buf, stdout); 20358680Seric (void) xfclose(fp, "savemail transcript", e->e_id); 2049375Seric } 20524942Seric printf("Original message will be saved in dead.letter.\r\n"); 20624942Seric state = ESM_DEADLETTER; 20724942Seric break; 208297Seric 20924942Seric case ESM_MAIL: 21024942Seric /* 21124942Seric ** If mailing back, do it. 21224942Seric ** Throw away all further output. Don't alias, 21324942Seric ** since this could cause loops, e.g., if joe 21424942Seric ** mails to joe@x, and for some reason the network 21524942Seric ** for @x is down, then the response gets sent to 21624942Seric ** joe@x, which gives a response, etc. Also force 21724942Seric ** the mail to be delivered even if a version of 21824942Seric ** it has already been sent to the sender. 21963841Seric ** 22063841Seric ** If this is a configuration or local software 22163841Seric ** error, send to the local postmaster as well, 22263841Seric ** since the originator can't do anything 22363841Seric ** about it anyway. Note that this is a full 22463841Seric ** copy of the message (intentionally) so that 22563841Seric ** the Postmaster can forward things along. 22624942Seric */ 227297Seric 22863841Seric if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE) 22963841Seric { 23063841Seric (void) sendtolist("postmaster", 23167982Seric NULLADDR, &e->e_errorqueue, 0, e); 23263841Seric } 23367939Seric if (!emptyaddr(&e->e_from)) 23463841Seric { 23558680Seric (void) sendtolist(e->e_from.q_paddr, 23667982Seric NULLADDR, &e->e_errorqueue, 0, e); 23763841Seric } 23858680Seric 23963841Seric /* 24063841Seric ** Deliver a non-delivery report to the 24163841Seric ** Postmaster-designate (not necessarily 24263841Seric ** Postmaster). This does not include the 24363841Seric ** body of the message, for privacy reasons. 24463841Seric ** You really shouldn't need this. 24563841Seric */ 24663841Seric 24763849Seric e->e_flags |= EF_PM_NOTIFY; 24858178Seric 24964792Seric /* check to see if there are any good addresses */ 25064792Seric for (q = e->e_errorqueue; q != NULL; q = q->q_next) 25164792Seric if (!bitset(QBADADDR|QDONTSEND, q->q_flags)) 25264792Seric break; 25358680Seric if (q == NULL) 25458680Seric { 25558680Seric /* this is an error-error */ 25658680Seric state = ESM_POSTMASTER; 25758680Seric break; 25858680Seric } 25966303Seric if (returntosender(e->e_message, e->e_errorqueue, 26067981Seric sendbody, e) == 0) 26158680Seric { 26258680Seric state = ESM_DONE; 26358680Seric break; 26458680Seric } 26524981Seric 26658680Seric /* didn't work -- return to postmaster */ 26758680Seric state = ESM_POSTMASTER; 26858680Seric break; 26958306Seric 27058680Seric case ESM_POSTMASTER: 27158680Seric /* 27258680Seric ** Similar to previous case, but to system postmaster. 27358680Seric */ 27458680Seric 27559432Seric q = NULL; 27667982Seric if (sendtolist("postmaster", NULL, &q, 0, e) <= 0) 27724942Seric { 27858680Seric syserr("553 cannot parse postmaster!"); 27958680Seric ExitStat = EX_SOFTWARE; 28058680Seric state = ESM_USRTMP; 28158680Seric break; 28224942Seric } 28367981Seric if (returntosender(e->e_message, q, sendbody, e) == 0) 28424942Seric { 28524942Seric state = ESM_DONE; 28624942Seric break; 28724942Seric } 288297Seric 28958680Seric /* didn't work -- last resort */ 29058680Seric state = ESM_USRTMP; 29124942Seric break; 292297Seric 29324942Seric case ESM_DEADLETTER: 29424942Seric /* 29524942Seric ** Save the message in dead.letter. 29624942Seric ** If we weren't mailing back, and the user is 29724942Seric ** local, we should save the message in 29824942Seric ** ~/dead.letter so that the poor person doesn't 29924942Seric ** have to type it over again -- and we all know 30024942Seric ** what poor typists UNIX users are. 30124942Seric */ 3025315Seric 30324942Seric p = NULL; 30467473Seric if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags)) 30524942Seric { 30624942Seric if (e->e_from.q_home != NULL) 30724942Seric p = e->e_from.q_home; 30868693Seric else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL) 30924942Seric p = pw->pw_dir; 31024942Seric } 31168802Seric if (p == NULL || e->e_dfp == NULL) 31224942Seric { 31368802Seric /* no local directory or no data file */ 31424942Seric state = ESM_MAIL; 31524942Seric break; 31624942Seric } 31724942Seric 31869787Seric /* we have a home directory; write dead.letter */ 31968802Seric define('z', p, e); 32068802Seric expand("\201z/dead.letter", buf, sizeof buf, e); 32168802Seric sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID; 32268802Seric e->e_to = buf; 32369787Seric if (mailfile(buf, NULL, sfflags, e) == EX_OK) 32469787Seric { 32569787Seric bool oldverb = Verbose; 32624942Seric 32769787Seric Verbose = TRUE; 32869787Seric message("Saved message in %s", buf); 32969787Seric Verbose = oldverb; 33069787Seric state = ESM_DONE; 33169787Seric break; 33269787Seric } 33369787Seric state = ESM_MAIL; 33469787Seric break; 33569787Seric 33624942Seric case ESM_USRTMP: 33724942Seric /* 33824942Seric ** Log the mail in /usr/tmp/dead.letter. 33924942Seric */ 34024942Seric 34157438Seric if (e->e_class < 0) 34257438Seric { 34357438Seric state = ESM_DONE; 34457438Seric break; 34557438Seric } 34657438Seric 34768490Seric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 34868490Seric { 34968490Seric state = ESM_PANIC; 35068490Seric break; 35168490Seric } 35268490Seric 35365174Seric strcpy(buf, _PATH_VARTMP); 35465174Seric strcat(buf, "dead.letter"); 35568802Seric sfflags = SFF_NOSLINK|SFF_CREAT|SFF_REGONLY; 35668802Seric 35769787Seric if (!writable(buf, NULL, sfflags) || 35868802Seric (fp = safefopen(buf, O_WRONLY|O_CREAT|O_APPEND, 35968802Seric FileMode, sfflags)) == NULL) 36064945Seric { 36169787Seric state = ESM_PANIC; 36264945Seric break; 36364945Seric } 36424942Seric 36565870Seric bzero(&mcibuf, sizeof mcibuf); 36665870Seric mcibuf.mci_out = fp; 36765870Seric mcibuf.mci_mailer = FileMailer; 36865870Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 36965870Seric mcibuf.mci_flags |= MCIF_7BIT; 37065870Seric 37165870Seric putfromline(&mcibuf, e); 37268228Seric (*e->e_puthdr)(&mcibuf, e->e_header, e); 37368228Seric (*e->e_putbody)(&mcibuf, e, NULL); 37465870Seric putline("\n", &mcibuf); 37524942Seric (void) fflush(fp); 37668802Seric if (!ferror(fp)) 37768802Seric { 37868802Seric bool oldverb = Verbose; 37968802Seric 38068802Seric Verbose = TRUE; 38168802Seric message("Saved message in %s", buf); 38268802Seric Verbose = oldverb; 38368802Seric state = ESM_DONE; 38468802Seric } 38569787Seric state = ESM_PANIC; 38667809Seric (void) xfclose(fp, "savemail", buf); 38724942Seric break; 38824942Seric 38924942Seric default: 39058151Seric syserr("554 savemail: unknown state %d", state); 39124942Seric 39224942Seric /* fall through ... */ 39324942Seric 39424942Seric case ESM_PANIC: 39524942Seric /* leave the locked queue & transcript files around */ 39668490Seric loseqfile(e, "savemail panic"); 39764949Seric syserr("!554 savemail: cannot save rejected email anywhere"); 39824942Seric } 399297Seric } 400297Seric } 401297Seric /* 4024633Seric ** RETURNTOSENDER -- return a message to the sender with an error. 4034633Seric ** 4044633Seric ** Parameters: 4054633Seric ** msg -- the explanatory message. 40616479Seric ** returnq -- the queue of people to send the message to. 4075984Seric ** sendbody -- if TRUE, also send back the body of the 4085984Seric ** message; otherwise just send the header. 40955012Seric ** e -- the current envelope. 4104633Seric ** 4114633Seric ** Returns: 4124633Seric ** zero -- if everything went ok. 4134633Seric ** else -- some error. 4144633Seric ** 4154633Seric ** Side Effects: 4164633Seric ** Returns the current message to the sender via 4174633Seric ** mail. 4184633Seric */ 4194633Seric 4207045Seric #define MAXRETURNS 6 /* max depth of returning messages */ 42158559Seric #define ERRORFUDGE 100 /* nominal size of error message text */ 4227045Seric 42369748Seric int 42455012Seric returntosender(msg, returnq, sendbody, e) 4254633Seric char *msg; 42616479Seric ADDRESS *returnq; 4275984Seric bool sendbody; 42855012Seric register ENVELOPE *e; 4294633Seric { 4306978Seric register ENVELOPE *ee; 43158680Seric ENVELOPE *oldcur = CurEnv; 4326978Seric ENVELOPE errenvelope; 4337045Seric static int returndepth; 4349375Seric register ADDRESS *q; 43568228Seric char *p; 43669748Seric char buf[MAXNAME + 1]; 43769748Seric extern void errbody __P((MCI *, ENVELOPE *, char *)); 4384633Seric 43960010Seric if (returnq == NULL) 44060010Seric return (-1); 44160010Seric 44258966Seric if (msg == NULL) 44358966Seric msg = "Unable to deliver mail"; 44458966Seric 4457676Seric if (tTd(6, 1)) 4467287Seric { 44767987Seric printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%x, returnq=", 44855012Seric msg, returndepth, e); 44916479Seric printaddr(returnq, TRUE); 45067987Seric if (tTd(6, 20)) 45167987Seric { 45267987Seric printf("Sendq="); 45367987Seric printaddr(e->e_sendqueue, TRUE); 45467987Seric } 4557287Seric } 4567287Seric 4577045Seric if (++returndepth >= MAXRETURNS) 4587045Seric { 4597045Seric if (returndepth != MAXRETURNS) 46058151Seric syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr); 4617045Seric /* don't "unrecurse" and fake a clean exit */ 4627045Seric /* returndepth--; */ 4637045Seric return (0); 4647045Seric } 4657045Seric 46658680Seric define('g', e->e_from.q_paddr, e); 46764940Seric define('u', NULL, e); 46867880Seric 46967880Seric /* initialize error envelope */ 47058179Seric ee = newenvelope(&errenvelope, e); 47158050Seric define('a', "\201b", ee); 47259057Seric define('r', "internal", ee); 47359057Seric define('s', "localhost", ee); 47459057Seric define('_', "localhost", ee); 4756978Seric ee->e_puthdr = putheader; 4766978Seric ee->e_putbody = errbody; 47764120Seric ee->e_flags |= EF_RESPONSE|EF_METOO; 47855012Seric if (!bitset(EF_OLDSTYLE, e->e_flags)) 47945155Seric ee->e_flags &= ~EF_OLDSTYLE; 48016479Seric ee->e_sendqueue = returnq; 48164655Seric ee->e_msgsize = ERRORFUDGE; 48268559Seric if (sendbody) 48364655Seric ee->e_msgsize += e->e_msgsize; 48468802Seric else 48568802Seric ee->e_flags |= EF_NO_BODY_RETN; 48664737Seric initsys(ee); 48716479Seric for (q = returnq; q != NULL; q = q->q_next) 4889375Seric { 48959989Seric if (bitset(QBADADDR, q->q_flags)) 49058559Seric continue; 49158559Seric 49268141Seric if (!DontPruneRoutes && pruneroute(q->q_paddr)) 49368141Seric { 49468141Seric register ADDRESS *p; 49568141Seric 49668141Seric parseaddr(q->q_paddr, q, RF_COPYPARSE, '\0', NULL, e); 49768141Seric for (p = returnq; p != NULL; p = p->q_next) 49868141Seric { 49968141Seric if (p != q && sameaddr(p, q)) 50068141Seric q->q_flags |= QDONTSEND; 50168141Seric } 50268141Seric } 50368141Seric 50459989Seric if (!bitset(QDONTSEND, q->q_flags)) 50559989Seric ee->e_nrcpts++; 50658559Seric 5079375Seric if (q->q_alias == NULL) 50867546Seric addheader("To", q->q_paddr, &ee->e_header); 5099375Seric } 51024942Seric 51157642Seric # ifdef LOG 51258020Seric if (LogLevel > 5) 51365054Seric syslog(LOG_INFO, "%s: %s: return to sender: %s", 51457642Seric e->e_id, ee->e_id, msg); 51557642Seric # endif 51657642Seric 51768003Seric if (SendMIMEErrors) 51867261Seric { 51968003Seric addheader("MIME-Version", "1.0", &ee->e_header); 52068003Seric (void) sprintf(buf, "%s.%ld/%s", 52168003Seric ee->e_id, curtime(), MyHostName); 52268003Seric ee->e_msgboundary = newstr(buf); 52368003Seric (void) sprintf(buf, 52468848Seric #if DSN 52569858Seric "multipart/report; report-type=X-delivery-status-03 (Draft of May 5, 1995);\n\tboundary=\"%s\"", 52668028Seric #else 52768028Seric "multipart/mixed; boundary=\"%s\"", 52868028Seric #endif 52968003Seric ee->e_msgboundary); 53068003Seric addheader("Content-Type", buf, &ee->e_header); 53168003Seric } 53268228Seric if (strncmp(msg, "Warning:", 8) == 0) 53368003Seric { 53468879Seric addheader("Subject", msg, &ee->e_header); 53568228Seric p = "warning-timeout"; 53667261Seric } 53767429Seric else if (strcmp(msg, "Return receipt") == 0) 53867429Seric { 53968879Seric addheader("Subject", msg, &ee->e_header); 54068228Seric p = "return-receipt"; 54167429Seric } 54267261Seric else 54367261Seric { 54467261Seric sprintf(buf, "Returned mail: %.*s", sizeof buf - 20, msg); 54567546Seric addheader("Subject", buf, &ee->e_header); 54668228Seric p = "failure"; 54767261Seric } 54868228Seric (void) sprintf(buf, "auto-generated (%s)", p); 54968228Seric addheader("Auto-Submitted", buf, &ee->e_header); 5504633Seric 5514633Seric /* fake up an address header for the from person */ 55268529Seric expand("\201n", buf, sizeof buf, e); 55364284Seric if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL) 5544633Seric { 55558151Seric syserr("553 Can't parse myself!"); 5564633Seric ExitStat = EX_SOFTWARE; 5577045Seric returndepth--; 5584633Seric return (-1); 5594633Seric } 56058704Seric ee->e_sender = ee->e_from.q_paddr; 5615984Seric 5626978Seric /* push state into submessage */ 5636978Seric CurEnv = ee; 56458050Seric define('f', "\201n", ee); 5659375Seric define('x', "Mail Delivery Subsystem", ee); 56658929Seric eatheader(ee, TRUE); 5675984Seric 56863753Seric /* mark statistics */ 56964284Seric markstats(ee, NULLADDR); 57063753Seric 5716978Seric /* actually deliver the error message */ 57214876Seric sendall(ee, SM_DEFAULT); 5736978Seric 5746978Seric /* restore state */ 5757811Seric dropenvelope(ee); 57658680Seric CurEnv = oldcur; 5777045Seric returndepth--; 5786978Seric 5797045Seric /* should check for delivery errors here */ 5804633Seric return (0); 5814633Seric } 5824633Seric /* 5836978Seric ** ERRBODY -- output the body of an error message. 5846978Seric ** 5856978Seric ** Typically this is a copy of the transcript plus a copy of the 5866978Seric ** original offending message. 5876978Seric ** 588297Seric ** Parameters: 58965870Seric ** mci -- the mailer connection information. 5909542Seric ** e -- the envelope we are working in. 59167546Seric ** separator -- any possible MIME separator. 59267936Seric ** flags -- to modify the behaviour. 593297Seric ** 594297Seric ** Returns: 595297Seric ** none 596297Seric ** 597297Seric ** Side Effects: 5986978Seric ** Outputs the body of an error message. 599297Seric */ 600297Seric 60169748Seric void 60268228Seric errbody(mci, e, separator) 60365870Seric register MCI *mci; 6049542Seric register ENVELOPE *e; 60567546Seric char *separator; 606297Seric { 6076978Seric register FILE *xfile; 60859082Seric char *p; 60959082Seric register ADDRESS *q; 61059082Seric bool printheader; 61168559Seric bool sendbody; 6123189Seric char buf[MAXLINE]; 61369858Seric extern char *xuntextify(); 614297Seric 61567546Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 61667546Seric { 61767546Seric putline("", mci); 61867546Seric mci->mci_flags &= ~MCIF_INHEADER; 61967546Seric } 62058680Seric if (e->e_parent == NULL) 62158680Seric { 62258680Seric syserr("errbody: null parent"); 62365870Seric putline(" ----- Original message lost -----\n", mci); 62458680Seric return; 62558680Seric } 62658680Seric 6279057Seric /* 62859730Seric ** Output MIME header. 62959730Seric */ 63059730Seric 63159730Seric if (e->e_msgboundary != NULL) 63259730Seric { 63365870Seric putline("This is a MIME-encapsulated message", mci); 63465870Seric putline("", mci); 63559730Seric (void) sprintf(buf, "--%s", e->e_msgboundary); 63665870Seric putline(buf, mci); 63765870Seric putline("", mci); 63859730Seric } 63959730Seric 64059730Seric /* 64163852Seric ** Output introductory information. 64263852Seric */ 64363852Seric 64464718Seric for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 64564718Seric if (bitset(QBADADDR, q->q_flags)) 64664718Seric break; 64765054Seric if (q == NULL && 64865054Seric !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags)) 64964718Seric { 65064718Seric putline(" **********************************************", 65165870Seric mci); 65264718Seric putline(" ** THIS IS A WARNING MESSAGE ONLY **", 65365870Seric mci); 65464718Seric putline(" ** YOU DO NOT NEED TO RESEND YOUR MESSAGE **", 65565870Seric mci); 65664718Seric putline(" **********************************************", 65765870Seric mci); 65865870Seric putline("", mci); 65964718Seric } 66064718Seric sprintf(buf, "The original message was received at %s", 66164718Seric arpadate(ctime(&e->e_parent->e_ctime))); 66265870Seric putline(buf, mci); 66368529Seric expand("from \201_", buf, sizeof buf, e->e_parent); 66465870Seric putline(buf, mci); 66565870Seric putline("", mci); 66663852Seric 66763852Seric /* 66855372Seric ** Output error message header (if specified and available). 66955372Seric */ 67055372Seric 67167682Seric if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags)) 67255372Seric { 67355372Seric if (*ErrMsgFile == '/') 67455372Seric { 67555372Seric xfile = fopen(ErrMsgFile, "r"); 67655372Seric if (xfile != NULL) 67755372Seric { 67855372Seric while (fgets(buf, sizeof buf, xfile) != NULL) 67955425Seric { 68068529Seric expand(buf, buf, sizeof buf, e); 68165870Seric putline(buf, mci); 68255425Seric } 68355372Seric (void) fclose(xfile); 68465870Seric putline("\n", mci); 68555372Seric } 68655372Seric } 68755372Seric else 68855372Seric { 68968529Seric expand(ErrMsgFile, buf, sizeof buf, e); 69065870Seric putline(buf, mci); 69165870Seric putline("", mci); 69255372Seric } 69355372Seric } 69455372Seric 69555372Seric /* 69659082Seric ** Output message introduction 69759082Seric */ 69859082Seric 69959082Seric printheader = TRUE; 70059082Seric for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 70159082Seric { 70268868Seric if (bitset(QBADADDR, q->q_flags)) 70359082Seric { 70468868Seric if (!bitset(QPINGONFAILURE, q->q_flags)) 70568603Seric continue; 70668868Seric p = "unrecoverable error"; 70768868Seric } 70868868Seric else if (!bitset(QPRIMARY, q->q_flags)) 70968868Seric continue; 71068868Seric else if (bitset(QRELAYED, q->q_flags)) 71168868Seric p = "relayed to non-DSN-aware mailer"; 71268868Seric else if (bitset(QDELIVERED, q->q_flags)) 71368868Seric { 71468868Seric if (bitset(QEXPANDED, q->q_flags)) 71568868Seric p = "successfully delivered to mailing list"; 71663787Seric else 71768868Seric p = "successfully delivered to mailbox"; 71868868Seric } 71968868Seric else if (bitset(QEXPANDED, q->q_flags)) 72068868Seric p = "expanded by alias"; 72168868Seric else if (bitset(QDELAYED, q->q_flags)) 72268868Seric p = "transient failure"; 72368868Seric else 72468868Seric continue; 72568868Seric 72668868Seric if (printheader) 72768868Seric { 72868868Seric putline(" ----- The following addresses have delivery notifications -----", 72968868Seric mci); 73068868Seric printheader = FALSE; 73168868Seric } 73268868Seric 73368868Seric sprintf(buf, "%s (%s)", q->q_paddr, p); 73468868Seric putline(buf, mci); 73568868Seric if (q->q_alias != NULL) 73668868Seric { 73768868Seric strcpy(buf, " (expanded from: "); 73868868Seric strcat(buf, q->q_alias->q_paddr); 73968868Seric strcat(buf, ")"); 74065870Seric putline(buf, mci); 74159082Seric } 74259082Seric } 74359082Seric if (!printheader) 74465870Seric putline("\n", mci); 74559082Seric 74659082Seric /* 7479057Seric ** Output transcript of errors 7489057Seric */ 7499057Seric 7504086Seric (void) fflush(stdout); 7519542Seric p = queuename(e->e_parent, 'x'); 7529337Seric if ((xfile = fopen(p, "r")) == NULL) 7539057Seric { 7549337Seric syserr("Cannot open %s", p); 75565870Seric putline(" ----- Transcript of session is unavailable -----\n", mci); 7569057Seric } 7579057Seric else 7589057Seric { 75968868Seric printheader = TRUE; 7609542Seric if (e->e_xfp != NULL) 7619542Seric (void) fflush(e->e_xfp); 7629057Seric while (fgets(buf, sizeof buf, xfile) != NULL) 76368868Seric { 76468868Seric if (printheader) 76568868Seric putline(" ----- Transcript of session follows -----\n", mci); 76668868Seric printheader = FALSE; 76765870Seric putline(buf, mci); 76868868Seric } 76958680Seric (void) xfclose(xfile, "errbody xscript", p); 7709057Seric } 771297Seric errno = 0; 7724318Seric 77368848Seric #if DSN 7744318Seric /* 77567880Seric ** Output machine-readable version. 77667880Seric */ 77767880Seric 77867880Seric if (e->e_msgboundary != NULL) 77967880Seric { 78067880Seric putline("", mci); 78167880Seric (void) sprintf(buf, "--%s", e->e_msgboundary); 78267880Seric putline(buf, mci); 78369858Seric putline("Content-Type: message/X-delivery-status-05 (Draft of May 29, 1995)", mci); 78467880Seric putline("", mci); 78567880Seric 78667880Seric /* 78767880Seric ** Output per-message information. 78867880Seric */ 78967880Seric 79067880Seric /* original envelope id from MAIL FROM: line */ 79167880Seric if (e->e_parent->e_envid != NULL) 79267880Seric { 79367880Seric (void) sprintf(buf, "Original-Envelope-Id: %s", 79469858Seric xuntextify(e->e_parent->e_envid)); 79567880Seric putline(buf, mci); 79667880Seric } 79767880Seric 79868228Seric /* Reporting-MTA: is us (required) */ 79969858Seric (void) sprintf(buf, "Reporting-MTA: dns; %s", MyHostName); 80067880Seric putline(buf, mci); 80167880Seric 80268868Seric /* DSN-Gateway: not relevant since we are not translating */ 80368868Seric 80468228Seric /* Received-From-MTA: shows where we got this message from */ 80567990Seric if (RealHostName != NULL) 80667990Seric { 80768228Seric /* XXX use $s for type? */ 80868228Seric p = e->e_parent->e_from.q_mailer->m_mtatype; 80968228Seric if (p == NULL) 81068228Seric p = "dns"; 81168228Seric (void) sprintf(buf, "Received-From-MTA: %s; %s", 81269858Seric p, RealHostName); 81367990Seric putline(buf, mci); 81467990Seric } 81567963Seric 81667963Seric /* Arrival-Date: -- when it arrived here */ 81767963Seric (void) sprintf(buf, "Arrival-Date: %s", 81867963Seric arpadate(ctime(&e->e_parent->e_ctime))); 81967963Seric putline(buf, mci); 82067963Seric 82167880Seric /* 82267880Seric ** Output per-address information. 82367880Seric */ 82467880Seric 82567880Seric for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next) 82667880Seric { 82767880Seric register ADDRESS *r; 82868603Seric char *action; 82967880Seric 83068603Seric if (bitset(QBADADDR, q->q_flags)) 83168868Seric action = "failed"; 83268603Seric else if (!bitset(QPRIMARY, q->q_flags)) 83367880Seric continue; 83468868Seric else if (bitset(QDELIVERED, q->q_flags)) 83568868Seric { 83668868Seric if (bitset(QEXPANDED, q->q_flags)) 83768868Seric action = "delivered (to mailing list)"; 83868868Seric else 83968868Seric action = "delivered (to mailbox)"; 84068868Seric } 84168603Seric else if (bitset(QRELAYED, q->q_flags)) 84268868Seric action = "relayed (to non-DSN-aware mailer)"; 84368868Seric else if (bitset(QEXPANDED, q->q_flags)) 84468868Seric action = "expanded (to multi-recipient alias)"; 84568868Seric else if (bitset(QDELAYED, q->q_flags)) 84668603Seric action = "delayed"; 84768603Seric else 84868603Seric continue; 84968603Seric 85067880Seric putline("", mci); 85167880Seric 85268228Seric /* Original-Recipient: -- passed from on high */ 85368228Seric if (q->q_orcpt != NULL) 85468228Seric { 85568228Seric (void) sprintf(buf, "Original-Recipient: %s", 85669858Seric q->q_orcpt); 85768228Seric putline(buf, mci); 85868228Seric } 85968228Seric 86068228Seric /* Final-Recipient: -- the name from the RCPT command */ 86168228Seric p = e->e_parent->e_from.q_mailer->m_addrtype; 86268228Seric if (p == NULL) 86368228Seric p = "rfc822"; 86468228Seric for (r = q; r->q_alias != NULL; r = r->q_alias) 86568228Seric continue; 86668228Seric if (strchr(r->q_user, '@') == NULL) 86768583Seric { 86868583Seric (void) sprintf(buf, "Final-Recipient: %s; %s@", 86969858Seric p, r->q_user); 87069858Seric strcat(buf, MyHostName); 87168583Seric } 87267998Seric else 87368583Seric { 87468228Seric (void) sprintf(buf, "Final-Recipient: %s; %s", 87569858Seric p, r->q_user); 87668583Seric } 87767880Seric putline(buf, mci); 87867880Seric 87968603Seric /* X-Actual-Recipient: -- the real problem address */ 88068603Seric if (r != q) 88168603Seric { 88268603Seric if (strchr(q->q_user, '@') == NULL) 88368603Seric { 88468603Seric (void) sprintf(buf, "X-Actual-Recipient: %s; %s@", 88569858Seric p, q->q_user); 88669858Seric strcat(buf, MyHostName); 88768603Seric } 88868603Seric else 88968603Seric { 89068603Seric (void) sprintf(buf, "X-Actual-Recipient: %s; %s", 89169858Seric p, q->q_user); 89268603Seric } 89368603Seric putline(buf, mci); 89468603Seric } 89568603Seric 89667880Seric /* Action: -- what happened? */ 89768603Seric sprintf(buf, "Action: %s", action); 89868603Seric putline(buf, mci); 89967880Seric 90067880Seric /* Status: -- what _really_ happened? */ 90167880Seric strcpy(buf, "Status: "); 90267880Seric if (q->q_status != NULL) 90367880Seric strcat(buf, q->q_status); 90467880Seric else if (bitset(QBADADDR, q->q_flags)) 90568228Seric strcat(buf, "5.0.0"); 90667880Seric else if (bitset(QQUEUEUP, q->q_flags)) 90768228Seric strcat(buf, "4.0.0"); 90867880Seric else 90968228Seric strcat(buf, "2.0.0"); 91067880Seric putline(buf, mci); 91167880Seric 91268228Seric /* Remote-MTA: -- who was I talking to? */ 91368228Seric p = q->q_mailer->m_mtatype; 91468228Seric if (p == NULL) 91568228Seric p = "dns"; 91668228Seric (void) sprintf(buf, "Remote-MTA: %s; ", p); 91768228Seric if (q->q_statmta != NULL) 91868228Seric p = q->q_statmta; 91968603Seric else if (q->q_host != NULL && q->q_host[0] != '\0') 92068228Seric p = q->q_host; 92168228Seric else 92268228Seric p = NULL; 92368228Seric if (p != NULL) 92468228Seric { 92568228Seric strcat(buf, p); 92668228Seric p = &buf[strlen(buf) - 1]; 92768228Seric if (*p == '.') 92868228Seric *p = '\0'; 92968228Seric putline(buf, mci); 93068228Seric } 93168228Seric 93268228Seric /* Diagnostic-Code: -- actual result from other end */ 93368228Seric if (q->q_rstatus != NULL) 93468228Seric { 93568228Seric p = q->q_mailer->m_diagtype; 93668228Seric if (p == NULL) 93768228Seric p = "smtp"; 93868228Seric (void) sprintf(buf, "Diagnostic-Code: %s; %s", 93969858Seric p, q->q_rstatus); 94068228Seric putline(buf, mci); 94168228Seric } 94268228Seric 94368228Seric /* Last-Attempt-Date: -- fine granularity */ 94467880Seric if (q->q_statdate == (time_t) 0L) 94567880Seric q->q_statdate = curtime(); 94668228Seric (void) sprintf(buf, "Last-Attempt-Date: %s", 94767880Seric arpadate(ctime(&q->q_statdate))); 94867880Seric putline(buf, mci); 94967880Seric 95068868Seric /* Will-Retry-Until: -- for delayed messages only */ 95167963Seric if (bitset(QQUEUEUP, q->q_flags) && 95267963Seric !bitset(QBADADDR, q->q_flags)) 95367963Seric { 95467963Seric time_t xdate; 95567963Seric 95667963Seric xdate = e->e_ctime + TimeOuts.to_q_return[e->e_timeoutclass]; 95768868Seric sprintf(buf, "Will-Retry-Until: %s", 95867963Seric arpadate(ctime(&xdate))); 95967963Seric putline(buf, mci); 96067963Seric } 96167880Seric } 96267880Seric } 96368028Seric #endif 96467880Seric 96567880Seric /* 9664318Seric ** Output text of original message 9674318Seric */ 9684318Seric 96965870Seric putline("", mci); 97068564Seric if (bitset(EF_HAS_DF, e->e_parent->e_flags)) 9714199Seric { 97268802Seric sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) && 97368802Seric !bitset(EF_NO_BODY_RETN, e->e_flags); 97468559Seric 97567880Seric if (e->e_msgboundary == NULL) 97667880Seric { 97768559Seric if (sendbody) 97867880Seric putline(" ----- Original message follows -----\n", mci); 97967880Seric else 98067880Seric putline(" ----- Message header follows -----\n", mci); 98167880Seric (void) fflush(mci->mci_out); 98267880Seric } 9835984Seric else 9845984Seric { 98559730Seric (void) sprintf(buf, "--%s", e->e_msgboundary); 98665870Seric putline(buf, mci); 98768859Seric (void) sprintf(buf, "Content-Type: %s", 98868859Seric sendbody ? "message/rfc822" 98968859Seric : "text/rfc822-headers"); 99068228Seric putline(buf, mci); 9915984Seric } 99267981Seric putline("", mci); 99368228Seric putheader(mci, e->e_parent->e_header, e->e_parent); 99468559Seric if (sendbody) 99568228Seric putbody(mci, e->e_parent, e->e_msgboundary); 99668228Seric else if (e->e_msgboundary == NULL) 99767546Seric { 99867546Seric putline("", mci); 99965870Seric putline(" ----- Message body suppressed -----", mci); 100067546Seric } 10014199Seric } 100268228Seric else if (e->e_msgboundary == NULL) 100310170Seric { 100465870Seric putline(" ----- No message was collected -----\n", mci); 100510170Seric } 10064318Seric 100760010Seric if (e->e_msgboundary != NULL) 100860010Seric { 100965870Seric putline("", mci); 101060010Seric (void) sprintf(buf, "--%s--", e->e_msgboundary); 101165870Seric putline(buf, mci); 101260010Seric } 101365870Seric putline("", mci); 101459730Seric 10154318Seric /* 10164318Seric ** Cleanup and exit 10174318Seric */ 10184318Seric 1019297Seric if (errno != 0) 10206978Seric syserr("errbody: I/O error"); 1021297Seric } 102258144Seric /* 102368228Seric ** SMTPTODSN -- convert SMTP to DSN status code 102468228Seric ** 102568228Seric ** Parameters: 102668228Seric ** smtpstat -- the smtp status code (e.g., 550). 102768228Seric ** 102868228Seric ** Returns: 102968228Seric ** The DSN version of the status code. 103068228Seric */ 103168228Seric 103268228Seric char * 103368228Seric smtptodsn(smtpstat) 103468228Seric int smtpstat; 103568228Seric { 103668857Seric if (smtpstat < 0) 103768857Seric return "4.4.2"; 103868857Seric 103968228Seric switch (smtpstat) 104068228Seric { 104168228Seric case 450: /* Req mail action not taken: mailbox unavailable */ 104268228Seric return "4.2.0"; 104368228Seric 104468228Seric case 451: /* Req action aborted: local error in processing */ 104568228Seric return "4.3.0"; 104668228Seric 104768228Seric case 452: /* Req action not taken: insufficient sys storage */ 104868228Seric return "4.3.1"; 104968228Seric 105068228Seric case 500: /* Syntax error, command unrecognized */ 105168228Seric return "5.5.2"; 105268228Seric 105368228Seric case 501: /* Syntax error in parameters or arguments */ 105468228Seric return "5.5.4"; 105568228Seric 105668228Seric case 502: /* Command not implemented */ 105768228Seric return "5.5.1"; 105868228Seric 105968228Seric case 503: /* Bad sequence of commands */ 106068228Seric return "5.5.1"; 106168228Seric 106268228Seric case 504: /* Command parameter not implemented */ 106368228Seric return "5.5.4"; 106468228Seric 106568228Seric case 550: /* Req mail action not taken: mailbox unavailable */ 106668228Seric return "5.2.0"; 106768228Seric 106868228Seric case 551: /* User not local; please try <...> */ 106968228Seric return "5.1.6"; 107068228Seric 107168228Seric case 552: /* Req mail action aborted: exceeded storage alloc */ 107268228Seric return "5.2.2"; 107368228Seric 107468228Seric case 553: /* Req action not taken: mailbox name not allowed */ 107568228Seric return "5.1.3"; 107668228Seric 107768228Seric case 554: /* Transaction failed */ 107868228Seric return "5.0.0"; 107968228Seric } 108068228Seric 108168228Seric if ((smtpstat / 100) == 2) 108268228Seric return "2.0.0"; 108368228Seric if ((smtpstat / 100) == 4) 108468228Seric return "4.0.0"; 108568228Seric return "5.0.0"; 108668228Seric } 108768228Seric /* 108868228Seric ** XTEXTIFY -- take regular text and turn it into DSN-style xtext 108968228Seric ** 109068228Seric ** Parameters: 109168228Seric ** t -- the text to convert. 109268228Seric ** 109368228Seric ** Returns: 109468228Seric ** The xtext-ified version of the same string. 109568228Seric */ 109668228Seric 109768228Seric char * 109868228Seric xtextify(t) 109968228Seric register char *t; 110068228Seric { 110168228Seric register char *p; 110268228Seric int l; 110368228Seric int nbogus; 110468228Seric static char *bp = NULL; 110568228Seric static int bplen = 0; 110668228Seric 110768228Seric /* figure out how long this xtext will have to be */ 110868228Seric nbogus = l = 0; 110968228Seric for (p = t; *p != '\0'; p++) 111068228Seric { 111168228Seric register int c = (*p & 0xff); 111268228Seric 111368228Seric /* ASCII dependence here -- this is the way the spec words it */ 111468868Seric if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') 111568228Seric nbogus++; 111668228Seric l++; 111768228Seric } 111868228Seric if (nbogus == 0) 111968228Seric return t; 112068228Seric l += nbogus * 2 + 1; 112168228Seric 112268228Seric /* now allocate space if necessary for the new string */ 112368228Seric if (l > bplen) 112468228Seric { 112568228Seric if (bp != NULL) 112668228Seric free(bp); 112768228Seric bp = xalloc(l); 112868228Seric bplen = l; 112968228Seric } 113068228Seric 113168228Seric /* ok, copy the text with byte expansion */ 113268228Seric for (p = bp; *t != '\0'; ) 113368228Seric { 113468228Seric register int c = (*t++ & 0xff); 113568228Seric 113668228Seric /* ASCII dependence here -- this is the way the spec words it */ 113768228Seric if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(') 113868228Seric { 113968228Seric *p++ = '+'; 114068228Seric *p++ = "0123456789abcdef"[c >> 4]; 114168228Seric *p++ = "0123456789abcdef"[c & 0xf]; 114268228Seric } 114368228Seric else 114468228Seric *p++ = c; 114568228Seric } 114668228Seric *p = '\0'; 114768228Seric return bp; 114868228Seric } 114968228Seric /* 115069858Seric ** XUNTEXTIFY -- take xtext and turn it into plain text 115169858Seric ** 115269858Seric ** Parameters: 115369858Seric ** t -- the xtextified text. 115469858Seric ** 115569858Seric ** Returns: 115669858Seric ** The decoded text. No attempt is made to deal with 115769858Seric ** null strings in the resulting text. 115869858Seric */ 115969858Seric 116069858Seric char * 116169858Seric xuntextify(t) 116269858Seric register char *t; 116369858Seric { 116469858Seric register char *p; 116569858Seric int l; 116669858Seric static char *bp = NULL; 116769858Seric static int bplen = 0; 116869858Seric 116969858Seric /* heuristic -- if no plus sign, just return the input */ 117069858Seric if (strchr(t, '+') == NULL) 117169858Seric return t; 117269858Seric 117369858Seric /* xtext is always longer than decoded text */ 117469858Seric l = strlen(t); 117569858Seric if (l > bplen) 117669858Seric { 117769858Seric if (bp != NULL) 117869858Seric free(bp); 117969858Seric bp = xalloc(l); 118069858Seric bplen = l; 118169858Seric } 118269858Seric 118369858Seric /* ok, copy the text with byte compression */ 118469858Seric for (p = bp; *t != '\0'; t++) 118569858Seric { 118669858Seric register int c = *t & 0xff; 118769858Seric 118869858Seric if (c != '+') 118969858Seric { 119069858Seric *p++ = c; 119169858Seric continue; 119269858Seric } 119369858Seric 119469858Seric c = *++t & 0xff; 119569858Seric if (!isascii(c) || !isxdigit(c)) 119669858Seric { 119769858Seric /* error -- first digit is not hex */ 119869858Seric usrerr("bogus xtext: +%c", c); 119969858Seric t--; 120069858Seric continue; 120169858Seric } 120269858Seric if (isdigit(c)) 120369858Seric c -= '0'; 120469858Seric else if (isupper(c)) 120569858Seric c -= 'A' - 10; 120669858Seric else 120769858Seric c -= 'a' - 10; 120869858Seric *p = c << 4; 120969858Seric 121069858Seric c = *++t & 0xff; 121169858Seric if (!isascii(c) || !isxdigit(c)) 121269858Seric { 121369858Seric /* error -- second digit is not hex */ 121469858Seric usrerr("bogus xtext: +%x%c", *p >> 4, c); 121569858Seric t--; 121669858Seric continue; 121769858Seric } 121869858Seric if (isdigit(c)) 121969858Seric c -= '0'; 122069858Seric else if (isupper(c)) 122169858Seric c -= 'A' - 10; 122269858Seric else 122369858Seric c -= 'a' - 10; 122469858Seric *p++ |= c; 122569858Seric } 122669858Seric return bp; 122769858Seric } 122869858Seric /* 122968583Seric ** XTEXTOK -- check if a string is legal xtext 123068583Seric ** 123168583Seric ** Xtext is used in Delivery Status Notifications. The spec was 123268583Seric ** taken from draft-ietf-notary-mime-delivery-04.txt. 123368583Seric ** 123468583Seric ** Parameters: 123568583Seric ** s -- the string to check. 123668583Seric ** 123768583Seric ** Returns: 123868583Seric ** TRUE -- if 's' is legal xtext. 123968583Seric ** FALSE -- if it has any illegal characters in it. 124068583Seric */ 124168583Seric 124268583Seric bool 124368583Seric xtextok(s) 124468583Seric char *s; 124568583Seric { 124668583Seric int c; 124768583Seric 124868583Seric while ((c = *s++) != '\0') 124968583Seric { 125068583Seric if (c == '+') 125168583Seric { 125268583Seric c = *s++; 125368583Seric if (!isascii(c) || !isxdigit(c)) 125468583Seric return FALSE; 125568583Seric c = *s++; 125668583Seric if (!isascii(c) || !isxdigit(c)) 125768583Seric return FALSE; 125868583Seric } 1259*69888Seric else if (c < '!' || c > '~' || c == '=') 126068583Seric return FALSE; 126168583Seric } 126268583Seric return TRUE; 126368583Seric } 126468583Seric /* 126558144Seric ** PRUNEROUTE -- prune an RFC-822 source route 126658144Seric ** 126758144Seric ** Trims down a source route to the last internet-registered hop. 126858144Seric ** This is encouraged by RFC 1123 section 5.3.3. 126958144Seric ** 127058144Seric ** Parameters: 127158144Seric ** addr -- the address 127258144Seric ** 127358144Seric ** Returns: 127458144Seric ** TRUE -- address was modified 127558144Seric ** FALSE -- address could not be pruned 127658144Seric ** 127758144Seric ** Side Effects: 127858144Seric ** modifies addr in-place 127958144Seric */ 128058144Seric 128169748Seric bool 128258144Seric pruneroute(addr) 128358144Seric char *addr; 128458144Seric { 128566334Seric #if NAMED_BIND 128658144Seric char *start, *at, *comma; 128758144Seric char c; 128858144Seric int rcode; 128958144Seric char hostbuf[BUFSIZ]; 129058144Seric char *mxhosts[MAXMXHOSTS + 1]; 129158144Seric 129258144Seric /* check to see if this is really a route-addr */ 129358144Seric if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>') 129458144Seric return FALSE; 129558144Seric start = strchr(addr, ':'); 129658144Seric at = strrchr(addr, '@'); 129758144Seric if (start == NULL || at == NULL || at < start) 129858144Seric return FALSE; 129958144Seric 130058144Seric /* slice off the angle brackets */ 130158144Seric strcpy(hostbuf, at + 1); 130258144Seric hostbuf[strlen(hostbuf) - 1] = '\0'; 130358144Seric 130458144Seric while (start) 130558144Seric { 130659273Seric if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0) 130758144Seric { 130858144Seric strcpy(addr + 1, start + 1); 130958144Seric return TRUE; 131058144Seric } 131158144Seric c = *start; 131258144Seric *start = '\0'; 131358144Seric comma = strrchr(addr, ','); 131458144Seric if (comma && comma[1] == '@') 131558144Seric strcpy(hostbuf, comma + 2); 131658144Seric else 131758144Seric comma = 0; 131858144Seric *start = c; 131958144Seric start = comma; 132058144Seric } 132158144Seric #endif 132258144Seric return FALSE; 132358144Seric } 1324