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*25691Seric static char SccsId[] = "@(#)srvrsmtp.c 5.18 (Berkeley) 01/05/86 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*25691Seric static char SccsId[] = "@(#)srvrsmtp.c 5.18 (Berkeley) 01/05/86"; 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 180*25691Seric /* throw away leading whitespace */ 181*25691Seric while (isspace(*p)) 182*25691Seric p++; 183*25691Seric 1844549Seric /* decode command */ 1854549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1864549Seric { 18724984Seric if (sameword(c->cmdname, cmdbuf)) 1884549Seric break; 1894549Seric } 1904549Seric 1914549Seric /* process command */ 1924549Seric switch (c->cmdcode) 1934549Seric { 1944976Seric case CMDHELO: /* hello -- introduce yourself */ 19524943Seric SmtpPhase = "HELO"; 19625050Seric setproctitle("%s: %s", CurHostName, inp); 19725050Seric if (sameword(p, MyHostName)) 19814877Seric { 19914877Seric /* connected to an echo server */ 20014877Seric message("553", "%s I refuse to talk to myself", 20125050Seric MyHostName); 20214877Seric break; 20314877Seric } 20411146Seric if (RealHostName != NULL && !sameword(p, RealHostName)) 20511146Seric { 20624981Seric char hostbuf[MAXNAME]; 20711146Seric 20824981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 20924981Seric define('s', newstr(hostbuf), CurEnv); 21011146Seric } 21111146Seric else 21211146Seric define('s', newstr(p), CurEnv); 2134997Seric message("250", "%s Hello %s, pleased to meet you", 21425050Seric MyHostName, p); 2154976Seric break; 2164976Seric 2174549Seric case CMDMAIL: /* mail -- designate sender */ 21824943Seric SmtpPhase = "MAIL"; 21924943Seric 22011151Seric /* force a sending host even if no HELO given */ 22111151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 22211151Seric define('s', RealHostName, CurEnv); 22311151Seric 2249314Seric /* check for validity of this command */ 2254558Seric if (hasmail) 2264558Seric { 2274558Seric message("503", "Sender already specified"); 2284558Seric break; 2294558Seric } 2309339Seric if (InChild) 2319339Seric { 2329339Seric syserr("Nested MAIL command"); 2339339Seric exit(0); 2349339Seric } 2359339Seric 2369339Seric /* fork a subprocess to process this command */ 2379339Seric if (runinchild("SMTP-MAIL") > 0) 2389339Seric break; 2399339Seric initsys(); 24025016Seric setproctitle("%s %s: %s", CurEnv->e_id, 24125050Seric CurHostName, inp); 2429339Seric 2439339Seric /* child -- go do the processing */ 2444549Seric p = skipword(p, "from"); 2454549Seric if (p == NULL) 2464549Seric break; 2474549Seric setsender(p); 2484577Seric if (Errors == 0) 2494549Seric { 2504549Seric message("250", "Sender ok"); 2514549Seric hasmail = TRUE; 2524549Seric } 2539339Seric else if (InChild) 2549339Seric finis(); 2554549Seric break; 2564549Seric 2574976Seric case CMDRCPT: /* rcpt -- designate recipient */ 25824943Seric SmtpPhase = "RCPT"; 25925016Seric setproctitle("%s %s: %s", CurEnv->e_id, 26025050Seric CurHostName, inp); 26112612Seric if (setjmp(TopFrame) > 0) 26214785Seric { 26314785Seric CurEnv->e_flags &= ~EF_FATALERRS; 26412612Seric break; 26514785Seric } 26612612Seric QuickAbort = TRUE; 2674549Seric p = skipword(p, "to"); 2684549Seric if (p == NULL) 2694549Seric break; 27016140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 27112612Seric if (a == NULL) 27212612Seric break; 27316886Seric a->q_flags |= QPRIMARY; 27412612Seric a = recipient(a, &CurEnv->e_sendqueue); 27512612Seric if (Errors != 0) 27612612Seric break; 27712612Seric 27812612Seric /* no errors during parsing, but might be a duplicate */ 27912612Seric CurEnv->e_to = p; 28012612Seric if (!bitset(QBADADDR, a->q_flags)) 28112612Seric message("250", "Recipient ok"); 28212612Seric else 2834549Seric { 28412612Seric /* punt -- should keep message in ADDRESS.... */ 28512612Seric message("550", "Addressee unknown"); 2864549Seric } 28712612Seric CurEnv->e_to = NULL; 2884549Seric break; 2894549Seric 2904549Seric case CMDDATA: /* data -- text of mail */ 29124943Seric SmtpPhase = "DATA"; 2924976Seric if (!hasmail) 2934549Seric { 2944976Seric message("503", "Need MAIL command"); 2954976Seric break; 2964549Seric } 29724943Seric else if (CurEnv->e_nrcpts <= 0) 2984549Seric { 2994976Seric message("503", "Need RCPT (recipient)"); 3004976Seric break; 3014549Seric } 3024976Seric 3034976Seric /* collect the text of the message */ 30424943Seric SmtpPhase = "collect"; 30525016Seric setproctitle("%s %s: %s", CurEnv->e_id, 30625050Seric CurHostName, inp); 3074976Seric collect(TRUE); 3084976Seric if (Errors != 0) 3094976Seric break; 3104976Seric 3118238Seric /* 3128238Seric ** Arrange to send to everyone. 3138238Seric ** If sending to multiple people, mail back 3148238Seric ** errors rather than reporting directly. 3158238Seric ** In any case, don't mail back errors for 3168238Seric ** anything that has happened up to 3178238Seric ** now (the other end will do this). 31810197Seric ** Truncate our transcript -- the mail has gotten 31910197Seric ** to us successfully, and if we have 32010197Seric ** to mail this back, it will be easier 32110197Seric ** on the reader. 3228238Seric ** Then send to everyone. 3238238Seric ** Finally give a reply code. If an error has 3248238Seric ** already been given, don't mail a 3258238Seric ** message back. 3269339Seric ** We goose error returns by clearing error bit. 3278238Seric */ 3288238Seric 32924943Seric SmtpPhase = "delivery"; 33024943Seric if (CurEnv->e_nrcpts != 1) 3319378Seric { 3329378Seric HoldErrs = TRUE; 33316886Seric ErrorMode = EM_MAIL; 3349378Seric } 3359339Seric CurEnv->e_flags &= ~EF_FATALERRS; 33610197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3374976Seric 3384976Seric /* send to all recipients */ 33914877Seric sendall(CurEnv, SM_DEFAULT); 3406907Seric CurEnv->e_to = NULL; 3414976Seric 34223516Seric /* save statistics */ 34323516Seric markstats(CurEnv, (ADDRESS *) NULL); 34423516Seric 3458238Seric /* issue success if appropriate and reset */ 3468238Seric if (Errors == 0 || HoldErrs) 3479283Seric message("250", "Ok"); 3488238Seric else 3499339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3509339Seric 3519339Seric /* if in a child, pop back to our parent */ 3529339Seric if (InChild) 3539339Seric finis(); 35424943Seric 35524943Seric /* clean up a bit */ 35624943Seric hasmail = 0; 35724943Seric dropenvelope(CurEnv); 35824943Seric CurEnv = newenvelope(CurEnv); 35924943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3604549Seric break; 3614549Seric 3624549Seric case CMDRSET: /* rset -- reset state */ 3634549Seric message("250", "Reset state"); 3649339Seric if (InChild) 3659339Seric finis(); 3669339Seric break; 3674549Seric 3684549Seric case CMDVRFY: /* vrfy -- verify address */ 3699339Seric if (runinchild("SMTP-VRFY") > 0) 3709339Seric break; 37125050Seric setproctitle("%s: %s", CurHostName, inp); 3725003Seric vrfyqueue = NULL; 3737762Seric QuickAbort = TRUE; 3749619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3757762Seric if (Errors != 0) 3769339Seric { 3779339Seric if (InChild) 3789339Seric finis(); 3797762Seric break; 3809339Seric } 3815003Seric while (vrfyqueue != NULL) 3825003Seric { 3835003Seric register ADDRESS *a = vrfyqueue->q_next; 3845003Seric char *code; 3855003Seric 3867685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3875003Seric a = a->q_next; 3885003Seric 3897685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3905003Seric { 3915003Seric if (a != NULL) 3925003Seric code = "250-"; 3935003Seric else 3945003Seric code = "250"; 3955003Seric if (vrfyqueue->q_fullname == NULL) 3965003Seric message(code, "<%s>", vrfyqueue->q_paddr); 3975003Seric else 3985003Seric message(code, "%s <%s>", 3995003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4005003Seric } 4015003Seric else if (a == NULL) 4025003Seric message("554", "Self destructive alias loop"); 4035003Seric vrfyqueue = a; 4045003Seric } 4059339Seric if (InChild) 4069339Seric finis(); 4074549Seric break; 4084549Seric 4094549Seric case CMDHELP: /* help -- give user info */ 4104577Seric if (*p == '\0') 4114577Seric p = "SMTP"; 4124577Seric help(p); 4134549Seric break; 4144549Seric 4154549Seric case CMDNOOP: /* noop -- do nothing */ 4164549Seric message("200", "OK"); 4174549Seric break; 4184549Seric 4194549Seric case CMDQUIT: /* quit -- leave mail */ 42025050Seric message("221", "%s closing connection", MyHostName); 4219339Seric if (InChild) 4229339Seric ExitStat = EX_QUIT; 4234549Seric finis(); 4244549Seric 4258544Seric case CMDVERB: /* set verbose mode */ 4268544Seric Verbose = TRUE; 42725025Seric SendMode = SM_DELIVER; 4288544Seric message("200", "Verbose mode"); 4298544Seric break; 4308544Seric 4319314Seric case CMDONEX: /* doing one transaction only */ 4329378Seric OneXact = TRUE; 4339314Seric message("200", "Only one transaction"); 4349314Seric break; 4359314Seric 4365003Seric # ifdef DEBUG 4379339Seric case CMDDBGQSHOW: /* show queues */ 4386907Seric printf("Send Queue="); 4396907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4405003Seric break; 4417275Seric 4427275Seric case CMDDBGDEBUG: /* set debug mode */ 4437676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4447676Seric tTflag(p); 4457676Seric message("200", "Debug set"); 4467275Seric break; 44724945Seric # endif DEBUG 4487275Seric 44924945Seric # ifdef WIZ 4507282Seric case CMDDBGKILL: /* kill the parent */ 4518544Seric if (!iswiz()) 4528544Seric break; 4537282Seric if (kill(MotherPid, SIGTERM) >= 0) 4547282Seric message("200", "Mother is dead"); 4557282Seric else 4567282Seric message("500", "Can't kill Mom"); 4577282Seric break; 4588544Seric 4598544Seric case CMDDBGWIZ: /* become a wizard */ 4608544Seric if (WizWord != NULL) 4618544Seric { 4628544Seric char seed[3]; 4638544Seric extern char *crypt(); 4648544Seric 46523106Seric (void) strncpy(seed, WizWord, 2); 46615596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4678544Seric { 46815596Seric IsWiz = TRUE; 46915596Seric message("200", "Please pass, oh mighty wizard"); 4708544Seric break; 4718544Seric } 4728544Seric } 47315596Seric message("500", "You are no wizard!"); 4748544Seric break; 4755003Seric 47624945Seric # else WIZ 47724945Seric case CMDDBGWIZ: /* try to become a wizard */ 47824945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 47924945Seric break; 48024945Seric # endif WIZ 48124945Seric 4824549Seric case CMDERROR: /* unknown command */ 4834549Seric message("500", "Command unrecognized"); 4844549Seric break; 4854549Seric 4864549Seric default: 4874549Seric syserr("smtp: unknown code %d", c->cmdcode); 4884549Seric break; 4894549Seric } 4904549Seric } 4914549Seric } 4924549Seric /* 4934549Seric ** SKIPWORD -- skip a fixed word. 4944549Seric ** 4954549Seric ** Parameters: 4964549Seric ** p -- place to start looking. 4974549Seric ** w -- word to skip. 4984549Seric ** 4994549Seric ** Returns: 5004549Seric ** p following w. 5014549Seric ** NULL on error. 5024549Seric ** 5034549Seric ** Side Effects: 5044549Seric ** clobbers the p data area. 5054549Seric */ 5064549Seric 5074549Seric static char * 5084549Seric skipword(p, w) 5094549Seric register char *p; 5104549Seric char *w; 5114549Seric { 5124549Seric register char *q; 5134549Seric extern bool sameword(); 5144549Seric 5154549Seric /* find beginning of word */ 5164549Seric while (isspace(*p)) 5174549Seric p++; 5184549Seric q = p; 5194549Seric 5204549Seric /* find end of word */ 5214549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5224549Seric p++; 5234549Seric while (isspace(*p)) 5244549Seric *p++ = '\0'; 5254549Seric if (*p != ':') 5264549Seric { 5274549Seric syntax: 5284549Seric message("501", "Syntax error"); 5294549Seric Errors++; 5304549Seric return (NULL); 5314549Seric } 5324549Seric *p++ = '\0'; 5334549Seric while (isspace(*p)) 5344549Seric p++; 5354549Seric 5364549Seric /* see if the input word matches desired word */ 5374549Seric if (!sameword(q, w)) 5384549Seric goto syntax; 5394549Seric 5404549Seric return (p); 5414549Seric } 5424577Seric /* 5434577Seric ** HELP -- implement the HELP command. 5444577Seric ** 5454577Seric ** Parameters: 5464577Seric ** topic -- the topic we want help for. 5474577Seric ** 5484577Seric ** Returns: 5494577Seric ** none. 5504577Seric ** 5514577Seric ** Side Effects: 5524577Seric ** outputs the help file to message output. 5534577Seric */ 5544577Seric 5554577Seric help(topic) 5564577Seric char *topic; 5574577Seric { 5584577Seric register FILE *hf; 5594577Seric int len; 5604577Seric char buf[MAXLINE]; 5614577Seric bool noinfo; 5624577Seric 5638269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5644577Seric { 5654577Seric /* no help */ 56611931Seric errno = 0; 5674577Seric message("502", "HELP not implemented"); 5684577Seric return; 5694577Seric } 5704577Seric 5714577Seric len = strlen(topic); 5724577Seric makelower(topic); 5734577Seric noinfo = TRUE; 5744577Seric 5754577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5764577Seric { 5774577Seric if (strncmp(buf, topic, len) == 0) 5784577Seric { 5794577Seric register char *p; 5804577Seric 5814577Seric p = index(buf, '\t'); 5824577Seric if (p == NULL) 5834577Seric p = buf; 5844577Seric else 5854577Seric p++; 5864577Seric fixcrlf(p, TRUE); 5874577Seric message("214-", p); 5884577Seric noinfo = FALSE; 5894577Seric } 5904577Seric } 5914577Seric 5924577Seric if (noinfo) 5934577Seric message("504", "HELP topic unknown"); 5944577Seric else 5954577Seric message("214", "End of HELP info"); 5964628Seric (void) fclose(hf); 5974577Seric } 5988544Seric /* 5998544Seric ** ISWIZ -- tell us if we are a wizard 6008544Seric ** 6018544Seric ** If not, print a nasty message. 6028544Seric ** 6038544Seric ** Parameters: 6048544Seric ** none. 6058544Seric ** 6068544Seric ** Returns: 6078544Seric ** TRUE if we are a wizard. 6088544Seric ** FALSE if we are not a wizard. 6098544Seric ** 6108544Seric ** Side Effects: 6118544Seric ** Prints a 500 exit stat if we are not a wizard. 6128544Seric */ 6135181Seric 61424945Seric #ifdef WIZ 61519038Seric 6168544Seric bool 6178544Seric iswiz() 6188544Seric { 6198544Seric if (!IsWiz) 6208544Seric message("500", "Mere mortals musn't mutter that mantra"); 6218544Seric return (IsWiz); 6228544Seric } 62319038Seric 62424945Seric #endif WIZ 6259339Seric /* 6269339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6279339Seric ** 6289339Seric ** Parameters: 6299339Seric ** label -- a string used in error messages 6309339Seric ** 6319339Seric ** Returns: 6329339Seric ** zero in the child 6339339Seric ** one in the parent 6349339Seric ** 6359339Seric ** Side Effects: 6369339Seric ** none. 6379339Seric */ 6388544Seric 6399339Seric runinchild(label) 6409339Seric char *label; 6419339Seric { 6429339Seric int childpid; 6439339Seric 64416158Seric if (!OneXact) 6459339Seric { 64616158Seric childpid = dofork(); 64716158Seric if (childpid < 0) 64816158Seric { 64916158Seric syserr("%s: cannot fork", label); 65016158Seric return (1); 65116158Seric } 65216158Seric if (childpid > 0) 65316158Seric { 65416158Seric auto int st; 6559339Seric 65616158Seric /* parent -- wait for child to complete */ 65716158Seric st = waitfor(childpid); 65816158Seric if (st == -1) 65916158Seric syserr("%s: lost child", label); 6609339Seric 66116158Seric /* if we exited on a QUIT command, complete the process */ 66216158Seric if (st == (EX_QUIT << 8)) 66316158Seric finis(); 6649339Seric 66516158Seric return (1); 66616158Seric } 66716158Seric else 66816158Seric { 66916158Seric /* child */ 67016158Seric InChild = TRUE; 67125050Seric QuickAbort = FALSE; 67225614Seric clearenvelope(CurEnv, FALSE); 67316158Seric } 6749339Seric } 67515256Seric 67616158Seric /* open alias database */ 67716158Seric initaliases(AliasFile, FALSE); 67816158Seric 67916158Seric return (0); 6809339Seric } 6819339Seric 6825181Seric # endif SMTP 683