122712Sdist /* 222712Sdist ** Sendmail 322712Sdist ** Copyright (c) 1983 Eric P. Allman 422712Sdist ** Berkeley, California 522712Sdist ** 622712Sdist ** Copyright (c) 1983 Regents of the University of California. 722712Sdist ** All rights reserved. The Berkeley software License Agreement 822712Sdist ** specifies the terms and conditions for redistribution. 922712Sdist */ 1022712Sdist 1122712Sdist 129339Seric # include <errno.h> 134549Seric # include "sendmail.h" 1411728Seric # include <signal.h> 154549Seric 165181Seric # ifndef SMTP 1723122Seric # ifndef lint 18*25614Seric static char SccsId[] = "@(#)srvrsmtp.c 5.17 (Berkeley) 12/17/85 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*25614Seric static char SccsId[] = "@(#)srvrsmtp.c 5.17 (Berkeley) 12/17/85"; 2423122Seric # endif not lint 255181Seric 264549Seric /* 274549Seric ** SMTP -- run the SMTP protocol. 284549Seric ** 294549Seric ** Parameters: 304549Seric ** none. 314549Seric ** 324549Seric ** Returns: 334549Seric ** never. 344549Seric ** 354549Seric ** Side Effects: 364549Seric ** Reads commands from the input channel and processes 374549Seric ** them. 384549Seric */ 394549Seric 404549Seric struct cmd 414549Seric { 424549Seric char *cmdname; /* command name */ 434549Seric int cmdcode; /* internal code, see below */ 444549Seric }; 454549Seric 464549Seric /* values for cmdcode */ 474549Seric # define CMDERROR 0 /* bad command */ 484549Seric # define CMDMAIL 1 /* mail -- designate sender */ 494976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 504549Seric # define CMDDATA 3 /* data -- send message text */ 519339Seric # define CMDRSET 4 /* rset -- reset state */ 529339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 539339Seric # define CMDHELP 6 /* help -- give usage info */ 549339Seric # define CMDNOOP 7 /* noop -- do nothing */ 559339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 569339Seric # define CMDHELO 9 /* helo -- be polite */ 579339Seric # define CMDDBGQSHOW 10 /* showq -- show send queue (DEBUG) */ 589339Seric # define CMDDBGDEBUG 11 /* debug -- set debug mode */ 599339Seric # define CMDVERB 12 /* verb -- go into verbose mode */ 609339Seric # define CMDDBGKILL 13 /* kill -- kill sendmail */ 619339Seric # define CMDDBGWIZ 14 /* wiz -- become a wizard */ 629339Seric # define CMDONEX 15 /* onex -- sending one transaction only */ 634549Seric 644549Seric static struct cmd CmdTab[] = 654549Seric { 664549Seric "mail", CMDMAIL, 674976Seric "rcpt", CMDRCPT, 684549Seric "data", CMDDATA, 694549Seric "rset", CMDRSET, 704549Seric "vrfy", CMDVRFY, 717762Seric "expn", CMDVRFY, 724549Seric "help", CMDHELP, 734549Seric "noop", CMDNOOP, 744549Seric "quit", CMDQUIT, 754976Seric "helo", CMDHELO, 768544Seric "verb", CMDVERB, 779314Seric "onex", CMDONEX, 785003Seric # ifdef DEBUG 799339Seric "showq", CMDDBGQSHOW, 808544Seric "debug", CMDDBGDEBUG, 8124945Seric # endif DEBUG 8224945Seric # ifdef WIZ 838544Seric "kill", CMDDBGKILL, 8424945Seric # endif WIZ 858544Seric "wiz", CMDDBGWIZ, 864549Seric NULL, CMDERROR, 874549Seric }; 884549Seric 8924955Seric # ifdef WIZ 908544Seric bool IsWiz = FALSE; /* set if we are a wizard */ 9124955Seric # endif WIZ 9215596Seric char *WizWord; /* the wizard word to compare against */ 939339Seric bool InChild = FALSE; /* true if running in a subprocess */ 949378Seric bool OneXact = FALSE; /* one xaction only this run */ 9511146Seric 969339Seric #define EX_QUIT 22 /* special code for QUIT command */ 978544Seric 984549Seric smtp() 994549Seric { 1004549Seric register char *p; 1018544Seric register struct cmd *c; 1024549Seric char *cmd; 1034549Seric extern char *skipword(); 1044549Seric extern bool sameword(); 1054549Seric bool hasmail; /* mail command received */ 1065003Seric auto ADDRESS *vrfyqueue; 10712612Seric ADDRESS *a; 1088544Seric char inp[MAXLINE]; 10924981Seric char cmdbuf[100]; 1107124Seric extern char Version[]; 1117356Seric extern tick(); 1128544Seric extern bool iswiz(); 1139349Seric extern char *arpadate(); 11411151Seric extern char *macvalue(); 11512612Seric extern ADDRESS *recipient(); 11624943Seric extern ENVELOPE BlankEnvelope; 11724943Seric extern ENVELOPE *newenvelope(); 1184549Seric 1195003Seric hasmail = FALSE; 1207363Seric if (OutChannel != stdout) 1217363Seric { 1227363Seric /* arrange for debugging output to go to remote host */ 1237363Seric (void) close(1); 1247363Seric (void) dup(fileno(OutChannel)); 1257363Seric } 12611931Seric settime(); 12724971Seric if (RealHostName != NULL) 12825050Seric { 12925050Seric CurHostName = RealHostName; 13025050Seric setproctitle("srvrsmtp %s", CurHostName); 13125050Seric } 13225050Seric else 13325050Seric { 13425050Seric /* this must be us!! */ 13525050Seric CurHostName = MyHostName; 13625050Seric } 13716153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 13810708Seric message("220", inp); 13924943Seric SmtpPhase = "startup"; 1404549Seric for (;;) 1414549Seric { 14212612Seric /* arrange for backout */ 14312612Seric if (setjmp(TopFrame) > 0 && InChild) 14412612Seric finis(); 14512612Seric QuickAbort = FALSE; 14612612Seric HoldErrs = FALSE; 14712612Seric 1487356Seric /* setup for the read */ 1496907Seric CurEnv->e_to = NULL; 1504577Seric Errors = 0; 1517275Seric (void) fflush(stdout); 1527356Seric 1537356Seric /* read the input line */ 1547685Seric p = sfgets(inp, sizeof inp, InChannel); 1557356Seric 1567685Seric /* handle errors */ 1577356Seric if (p == NULL) 1587356Seric { 1594549Seric /* end of file, just die */ 16025050Seric message("421", "%s Lost input channel to %s", 16125050Seric MyHostName, CurHostName); 1624549Seric finis(); 1634549Seric } 1644549Seric 1654549Seric /* clean up end of line */ 1664558Seric fixcrlf(inp, TRUE); 1674549Seric 1684713Seric /* echo command to transcript */ 1699545Seric if (CurEnv->e_xfp != NULL) 1709545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1714713Seric 1724549Seric /* break off command */ 1734549Seric for (p = inp; isspace(*p); p++) 1744549Seric continue; 1754549Seric cmd = p; 17624981Seric for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) 17724981Seric *cmd++ = *p++; 17824981Seric *cmd = '\0'; 1794549Seric 1804549Seric /* decode command */ 1814549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1824549Seric { 18324984Seric if (sameword(c->cmdname, cmdbuf)) 1844549Seric break; 1854549Seric } 1864549Seric 1874549Seric /* process command */ 1884549Seric switch (c->cmdcode) 1894549Seric { 1904976Seric case CMDHELO: /* hello -- introduce yourself */ 19124943Seric SmtpPhase = "HELO"; 19225050Seric setproctitle("%s: %s", CurHostName, inp); 19325050Seric if (sameword(p, MyHostName)) 19414877Seric { 19514877Seric /* connected to an echo server */ 19614877Seric message("553", "%s I refuse to talk to myself", 19725050Seric MyHostName); 19814877Seric break; 19914877Seric } 20011146Seric if (RealHostName != NULL && !sameword(p, RealHostName)) 20111146Seric { 20224981Seric char hostbuf[MAXNAME]; 20311146Seric 20424981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 20524981Seric define('s', newstr(hostbuf), CurEnv); 20611146Seric } 20711146Seric else 20811146Seric define('s', newstr(p), CurEnv); 2094997Seric message("250", "%s Hello %s, pleased to meet you", 21025050Seric MyHostName, p); 2114976Seric break; 2124976Seric 2134549Seric case CMDMAIL: /* mail -- designate sender */ 21424943Seric SmtpPhase = "MAIL"; 21524943Seric 21611151Seric /* force a sending host even if no HELO given */ 21711151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 21811151Seric define('s', RealHostName, CurEnv); 21911151Seric 2209314Seric /* check for validity of this command */ 2214558Seric if (hasmail) 2224558Seric { 2234558Seric message("503", "Sender already specified"); 2244558Seric break; 2254558Seric } 2269339Seric if (InChild) 2279339Seric { 2289339Seric syserr("Nested MAIL command"); 2299339Seric exit(0); 2309339Seric } 2319339Seric 2329339Seric /* fork a subprocess to process this command */ 2339339Seric if (runinchild("SMTP-MAIL") > 0) 2349339Seric break; 2359339Seric initsys(); 23625016Seric setproctitle("%s %s: %s", CurEnv->e_id, 23725050Seric CurHostName, inp); 2389339Seric 2399339Seric /* child -- go do the processing */ 2404549Seric p = skipword(p, "from"); 2414549Seric if (p == NULL) 2424549Seric break; 2434549Seric setsender(p); 2444577Seric if (Errors == 0) 2454549Seric { 2464549Seric message("250", "Sender ok"); 2474549Seric hasmail = TRUE; 2484549Seric } 2499339Seric else if (InChild) 2509339Seric finis(); 2514549Seric break; 2524549Seric 2534976Seric case CMDRCPT: /* rcpt -- designate recipient */ 25424943Seric SmtpPhase = "RCPT"; 25525016Seric setproctitle("%s %s: %s", CurEnv->e_id, 25625050Seric CurHostName, inp); 25712612Seric if (setjmp(TopFrame) > 0) 25814785Seric { 25914785Seric CurEnv->e_flags &= ~EF_FATALERRS; 26012612Seric break; 26114785Seric } 26212612Seric QuickAbort = TRUE; 2634549Seric p = skipword(p, "to"); 2644549Seric if (p == NULL) 2654549Seric break; 26616140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 26712612Seric if (a == NULL) 26812612Seric break; 26916886Seric a->q_flags |= QPRIMARY; 27012612Seric a = recipient(a, &CurEnv->e_sendqueue); 27112612Seric if (Errors != 0) 27212612Seric break; 27312612Seric 27412612Seric /* no errors during parsing, but might be a duplicate */ 27512612Seric CurEnv->e_to = p; 27612612Seric if (!bitset(QBADADDR, a->q_flags)) 27712612Seric message("250", "Recipient ok"); 27812612Seric else 2794549Seric { 28012612Seric /* punt -- should keep message in ADDRESS.... */ 28112612Seric message("550", "Addressee unknown"); 2824549Seric } 28312612Seric CurEnv->e_to = NULL; 2844549Seric break; 2854549Seric 2864549Seric case CMDDATA: /* data -- text of mail */ 28724943Seric SmtpPhase = "DATA"; 2884976Seric if (!hasmail) 2894549Seric { 2904976Seric message("503", "Need MAIL command"); 2914976Seric break; 2924549Seric } 29324943Seric else if (CurEnv->e_nrcpts <= 0) 2944549Seric { 2954976Seric message("503", "Need RCPT (recipient)"); 2964976Seric break; 2974549Seric } 2984976Seric 2994976Seric /* collect the text of the message */ 30024943Seric SmtpPhase = "collect"; 30125016Seric setproctitle("%s %s: %s", CurEnv->e_id, 30225050Seric CurHostName, inp); 3034976Seric collect(TRUE); 3044976Seric if (Errors != 0) 3054976Seric break; 3064976Seric 3078238Seric /* 3088238Seric ** Arrange to send to everyone. 3098238Seric ** If sending to multiple people, mail back 3108238Seric ** errors rather than reporting directly. 3118238Seric ** In any case, don't mail back errors for 3128238Seric ** anything that has happened up to 3138238Seric ** now (the other end will do this). 31410197Seric ** Truncate our transcript -- the mail has gotten 31510197Seric ** to us successfully, and if we have 31610197Seric ** to mail this back, it will be easier 31710197Seric ** on the reader. 3188238Seric ** Then send to everyone. 3198238Seric ** Finally give a reply code. If an error has 3208238Seric ** already been given, don't mail a 3218238Seric ** message back. 3229339Seric ** We goose error returns by clearing error bit. 3238238Seric */ 3248238Seric 32524943Seric SmtpPhase = "delivery"; 32624943Seric if (CurEnv->e_nrcpts != 1) 3279378Seric { 3289378Seric HoldErrs = TRUE; 32916886Seric ErrorMode = EM_MAIL; 3309378Seric } 3319339Seric CurEnv->e_flags &= ~EF_FATALERRS; 33210197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3334976Seric 3344976Seric /* send to all recipients */ 33514877Seric sendall(CurEnv, SM_DEFAULT); 3366907Seric CurEnv->e_to = NULL; 3374976Seric 33823516Seric /* save statistics */ 33923516Seric markstats(CurEnv, (ADDRESS *) NULL); 34023516Seric 3418238Seric /* issue success if appropriate and reset */ 3428238Seric if (Errors == 0 || HoldErrs) 3439283Seric message("250", "Ok"); 3448238Seric else 3459339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3469339Seric 3479339Seric /* if in a child, pop back to our parent */ 3489339Seric if (InChild) 3499339Seric finis(); 35024943Seric 35124943Seric /* clean up a bit */ 35224943Seric hasmail = 0; 35324943Seric dropenvelope(CurEnv); 35424943Seric CurEnv = newenvelope(CurEnv); 35524943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3564549Seric break; 3574549Seric 3584549Seric case CMDRSET: /* rset -- reset state */ 3594549Seric message("250", "Reset state"); 3609339Seric if (InChild) 3619339Seric finis(); 3629339Seric break; 3634549Seric 3644549Seric case CMDVRFY: /* vrfy -- verify address */ 3659339Seric if (runinchild("SMTP-VRFY") > 0) 3669339Seric break; 36725050Seric setproctitle("%s: %s", CurHostName, inp); 3685003Seric vrfyqueue = NULL; 3697762Seric QuickAbort = TRUE; 3709619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3717762Seric if (Errors != 0) 3729339Seric { 3739339Seric if (InChild) 3749339Seric finis(); 3757762Seric break; 3769339Seric } 3775003Seric while (vrfyqueue != NULL) 3785003Seric { 3795003Seric register ADDRESS *a = vrfyqueue->q_next; 3805003Seric char *code; 3815003Seric 3827685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3835003Seric a = a->q_next; 3845003Seric 3857685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3865003Seric { 3875003Seric if (a != NULL) 3885003Seric code = "250-"; 3895003Seric else 3905003Seric code = "250"; 3915003Seric if (vrfyqueue->q_fullname == NULL) 3925003Seric message(code, "<%s>", vrfyqueue->q_paddr); 3935003Seric else 3945003Seric message(code, "%s <%s>", 3955003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 3965003Seric } 3975003Seric else if (a == NULL) 3985003Seric message("554", "Self destructive alias loop"); 3995003Seric vrfyqueue = a; 4005003Seric } 4019339Seric if (InChild) 4029339Seric finis(); 4034549Seric break; 4044549Seric 4054549Seric case CMDHELP: /* help -- give user info */ 4064577Seric if (*p == '\0') 4074577Seric p = "SMTP"; 4084577Seric help(p); 4094549Seric break; 4104549Seric 4114549Seric case CMDNOOP: /* noop -- do nothing */ 4124549Seric message("200", "OK"); 4134549Seric break; 4144549Seric 4154549Seric case CMDQUIT: /* quit -- leave mail */ 41625050Seric message("221", "%s closing connection", MyHostName); 4179339Seric if (InChild) 4189339Seric ExitStat = EX_QUIT; 4194549Seric finis(); 4204549Seric 4218544Seric case CMDVERB: /* set verbose mode */ 4228544Seric Verbose = TRUE; 42325025Seric SendMode = SM_DELIVER; 4248544Seric message("200", "Verbose mode"); 4258544Seric break; 4268544Seric 4279314Seric case CMDONEX: /* doing one transaction only */ 4289378Seric OneXact = TRUE; 4299314Seric message("200", "Only one transaction"); 4309314Seric break; 4319314Seric 4325003Seric # ifdef DEBUG 4339339Seric case CMDDBGQSHOW: /* show queues */ 4346907Seric printf("Send Queue="); 4356907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4365003Seric break; 4377275Seric 4387275Seric case CMDDBGDEBUG: /* set debug mode */ 4397676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4407676Seric tTflag(p); 4417676Seric message("200", "Debug set"); 4427275Seric break; 44324945Seric # endif DEBUG 4447275Seric 44524945Seric # ifdef WIZ 4467282Seric case CMDDBGKILL: /* kill the parent */ 4478544Seric if (!iswiz()) 4488544Seric break; 4497282Seric if (kill(MotherPid, SIGTERM) >= 0) 4507282Seric message("200", "Mother is dead"); 4517282Seric else 4527282Seric message("500", "Can't kill Mom"); 4537282Seric break; 4548544Seric 4558544Seric case CMDDBGWIZ: /* become a wizard */ 4568544Seric if (WizWord != NULL) 4578544Seric { 4588544Seric char seed[3]; 4598544Seric extern char *crypt(); 4608544Seric 46123106Seric (void) strncpy(seed, WizWord, 2); 46215596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4638544Seric { 46415596Seric IsWiz = TRUE; 46515596Seric message("200", "Please pass, oh mighty wizard"); 4668544Seric break; 4678544Seric } 4688544Seric } 46915596Seric message("500", "You are no wizard!"); 4708544Seric break; 4715003Seric 47224945Seric # else WIZ 47324945Seric case CMDDBGWIZ: /* try to become a wizard */ 47424945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 47524945Seric break; 47624945Seric # endif WIZ 47724945Seric 4784549Seric case CMDERROR: /* unknown command */ 4794549Seric message("500", "Command unrecognized"); 4804549Seric break; 4814549Seric 4824549Seric default: 4834549Seric syserr("smtp: unknown code %d", c->cmdcode); 4844549Seric break; 4854549Seric } 4864549Seric } 4874549Seric } 4884549Seric /* 4894549Seric ** SKIPWORD -- skip a fixed word. 4904549Seric ** 4914549Seric ** Parameters: 4924549Seric ** p -- place to start looking. 4934549Seric ** w -- word to skip. 4944549Seric ** 4954549Seric ** Returns: 4964549Seric ** p following w. 4974549Seric ** NULL on error. 4984549Seric ** 4994549Seric ** Side Effects: 5004549Seric ** clobbers the p data area. 5014549Seric */ 5024549Seric 5034549Seric static char * 5044549Seric skipword(p, w) 5054549Seric register char *p; 5064549Seric char *w; 5074549Seric { 5084549Seric register char *q; 5094549Seric extern bool sameword(); 5104549Seric 5114549Seric /* find beginning of word */ 5124549Seric while (isspace(*p)) 5134549Seric p++; 5144549Seric q = p; 5154549Seric 5164549Seric /* find end of word */ 5174549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5184549Seric p++; 5194549Seric while (isspace(*p)) 5204549Seric *p++ = '\0'; 5214549Seric if (*p != ':') 5224549Seric { 5234549Seric syntax: 5244549Seric message("501", "Syntax error"); 5254549Seric Errors++; 5264549Seric return (NULL); 5274549Seric } 5284549Seric *p++ = '\0'; 5294549Seric while (isspace(*p)) 5304549Seric p++; 5314549Seric 5324549Seric /* see if the input word matches desired word */ 5334549Seric if (!sameword(q, w)) 5344549Seric goto syntax; 5354549Seric 5364549Seric return (p); 5374549Seric } 5384577Seric /* 5394577Seric ** HELP -- implement the HELP command. 5404577Seric ** 5414577Seric ** Parameters: 5424577Seric ** topic -- the topic we want help for. 5434577Seric ** 5444577Seric ** Returns: 5454577Seric ** none. 5464577Seric ** 5474577Seric ** Side Effects: 5484577Seric ** outputs the help file to message output. 5494577Seric */ 5504577Seric 5514577Seric help(topic) 5524577Seric char *topic; 5534577Seric { 5544577Seric register FILE *hf; 5554577Seric int len; 5564577Seric char buf[MAXLINE]; 5574577Seric bool noinfo; 5584577Seric 5598269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5604577Seric { 5614577Seric /* no help */ 56211931Seric errno = 0; 5634577Seric message("502", "HELP not implemented"); 5644577Seric return; 5654577Seric } 5664577Seric 5674577Seric len = strlen(topic); 5684577Seric makelower(topic); 5694577Seric noinfo = TRUE; 5704577Seric 5714577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5724577Seric { 5734577Seric if (strncmp(buf, topic, len) == 0) 5744577Seric { 5754577Seric register char *p; 5764577Seric 5774577Seric p = index(buf, '\t'); 5784577Seric if (p == NULL) 5794577Seric p = buf; 5804577Seric else 5814577Seric p++; 5824577Seric fixcrlf(p, TRUE); 5834577Seric message("214-", p); 5844577Seric noinfo = FALSE; 5854577Seric } 5864577Seric } 5874577Seric 5884577Seric if (noinfo) 5894577Seric message("504", "HELP topic unknown"); 5904577Seric else 5914577Seric message("214", "End of HELP info"); 5924628Seric (void) fclose(hf); 5934577Seric } 5948544Seric /* 5958544Seric ** ISWIZ -- tell us if we are a wizard 5968544Seric ** 5978544Seric ** If not, print a nasty message. 5988544Seric ** 5998544Seric ** Parameters: 6008544Seric ** none. 6018544Seric ** 6028544Seric ** Returns: 6038544Seric ** TRUE if we are a wizard. 6048544Seric ** FALSE if we are not a wizard. 6058544Seric ** 6068544Seric ** Side Effects: 6078544Seric ** Prints a 500 exit stat if we are not a wizard. 6088544Seric */ 6095181Seric 61024945Seric #ifdef WIZ 61119038Seric 6128544Seric bool 6138544Seric iswiz() 6148544Seric { 6158544Seric if (!IsWiz) 6168544Seric message("500", "Mere mortals musn't mutter that mantra"); 6178544Seric return (IsWiz); 6188544Seric } 61919038Seric 62024945Seric #endif WIZ 6219339Seric /* 6229339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6239339Seric ** 6249339Seric ** Parameters: 6259339Seric ** label -- a string used in error messages 6269339Seric ** 6279339Seric ** Returns: 6289339Seric ** zero in the child 6299339Seric ** one in the parent 6309339Seric ** 6319339Seric ** Side Effects: 6329339Seric ** none. 6339339Seric */ 6348544Seric 6359339Seric runinchild(label) 6369339Seric char *label; 6379339Seric { 6389339Seric int childpid; 6399339Seric 64016158Seric if (!OneXact) 6419339Seric { 64216158Seric childpid = dofork(); 64316158Seric if (childpid < 0) 64416158Seric { 64516158Seric syserr("%s: cannot fork", label); 64616158Seric return (1); 64716158Seric } 64816158Seric if (childpid > 0) 64916158Seric { 65016158Seric auto int st; 6519339Seric 65216158Seric /* parent -- wait for child to complete */ 65316158Seric st = waitfor(childpid); 65416158Seric if (st == -1) 65516158Seric syserr("%s: lost child", label); 6569339Seric 65716158Seric /* if we exited on a QUIT command, complete the process */ 65816158Seric if (st == (EX_QUIT << 8)) 65916158Seric finis(); 6609339Seric 66116158Seric return (1); 66216158Seric } 66316158Seric else 66416158Seric { 66516158Seric /* child */ 66616158Seric InChild = TRUE; 66725050Seric QuickAbort = FALSE; 668*25614Seric clearenvelope(CurEnv, FALSE); 66916158Seric } 6709339Seric } 67115256Seric 67216158Seric /* open alias database */ 67316158Seric initaliases(AliasFile, FALSE); 67416158Seric 67516158Seric return (0); 6769339Seric } 6779339Seric 6785181Seric # endif SMTP 679