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*33725Sbostic static char SccsId[] = "@(#)srvrsmtp.c 5.20 (Berkeley) 03/13/88 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*33725Sbostic static char SccsId[] = "@(#)srvrsmtp.c 5.20 (Berkeley) 03/13/88"; 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 bool hasmail; /* mail command received */ 1055003Seric auto ADDRESS *vrfyqueue; 10612612Seric ADDRESS *a; 10730448Seric char *sendinghost; 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"; 14030448Seric sendinghost = NULL; 1414549Seric for (;;) 1424549Seric { 14312612Seric /* arrange for backout */ 14412612Seric if (setjmp(TopFrame) > 0 && InChild) 14512612Seric finis(); 14612612Seric QuickAbort = FALSE; 14712612Seric HoldErrs = FALSE; 14812612Seric 1497356Seric /* setup for the read */ 1506907Seric CurEnv->e_to = NULL; 1514577Seric Errors = 0; 1527275Seric (void) fflush(stdout); 1537356Seric 1547356Seric /* read the input line */ 1557685Seric p = sfgets(inp, sizeof inp, InChannel); 1567356Seric 1577685Seric /* handle errors */ 1587356Seric if (p == NULL) 1597356Seric { 1604549Seric /* end of file, just die */ 16125050Seric message("421", "%s Lost input channel to %s", 16225050Seric MyHostName, CurHostName); 1634549Seric finis(); 1644549Seric } 1654549Seric 1664549Seric /* clean up end of line */ 1674558Seric fixcrlf(inp, TRUE); 1684549Seric 1694713Seric /* echo command to transcript */ 1709545Seric if (CurEnv->e_xfp != NULL) 1719545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1724713Seric 1734549Seric /* break off command */ 1744549Seric for (p = inp; isspace(*p); p++) 1754549Seric continue; 1764549Seric cmd = p; 17724981Seric for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) 17824981Seric *cmd++ = *p++; 17924981Seric *cmd = '\0'; 1804549Seric 18125691Seric /* throw away leading whitespace */ 18225691Seric while (isspace(*p)) 18325691Seric p++; 18425691Seric 1854549Seric /* decode command */ 1864549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1874549Seric { 188*33725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1894549Seric break; 1904549Seric } 1914549Seric 1924549Seric /* process command */ 1934549Seric switch (c->cmdcode) 1944549Seric { 1954976Seric case CMDHELO: /* hello -- introduce yourself */ 19624943Seric SmtpPhase = "HELO"; 19725050Seric setproctitle("%s: %s", CurHostName, inp); 198*33725Sbostic if (!strcasecmp(p, MyHostName)) 19914877Seric { 20014877Seric /* connected to an echo server */ 20114877Seric message("553", "%s I refuse to talk to myself", 20225050Seric MyHostName); 20314877Seric break; 20414877Seric } 205*33725Sbostic if (RealHostName != NULL && strcasecmp(p, RealHostName)) 20611146Seric { 20724981Seric char hostbuf[MAXNAME]; 20811146Seric 20924981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 21030448Seric sendinghost = newstr(hostbuf); 21111146Seric } 21211146Seric else 21330448Seric sendinghost = newstr(p); 2144997Seric message("250", "%s Hello %s, pleased to meet you", 21525050Seric MyHostName, p); 2164976Seric break; 2174976Seric 2184549Seric case CMDMAIL: /* mail -- designate sender */ 21924943Seric SmtpPhase = "MAIL"; 22024943Seric 22111151Seric /* force a sending host even if no HELO given */ 22211151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 22330448Seric sendinghost = RealHostName; 22411151Seric 2259314Seric /* check for validity of this command */ 2264558Seric if (hasmail) 2274558Seric { 2284558Seric message("503", "Sender already specified"); 2294558Seric break; 2304558Seric } 2319339Seric if (InChild) 2329339Seric { 2339339Seric syserr("Nested MAIL command"); 2349339Seric exit(0); 2359339Seric } 2369339Seric 2379339Seric /* fork a subprocess to process this command */ 2389339Seric if (runinchild("SMTP-MAIL") > 0) 2399339Seric break; 24030448Seric define('s', sendinghost, CurEnv); 2419339Seric initsys(); 24225016Seric setproctitle("%s %s: %s", CurEnv->e_id, 24325050Seric CurHostName, inp); 2449339Seric 2459339Seric /* child -- go do the processing */ 2464549Seric p = skipword(p, "from"); 2474549Seric if (p == NULL) 2484549Seric break; 2494549Seric setsender(p); 2504577Seric if (Errors == 0) 2514549Seric { 2524549Seric message("250", "Sender ok"); 2534549Seric hasmail = TRUE; 2544549Seric } 2559339Seric else if (InChild) 2569339Seric finis(); 2574549Seric break; 2584549Seric 2594976Seric case CMDRCPT: /* rcpt -- designate recipient */ 26024943Seric SmtpPhase = "RCPT"; 26125016Seric setproctitle("%s %s: %s", CurEnv->e_id, 26225050Seric CurHostName, inp); 26312612Seric if (setjmp(TopFrame) > 0) 26414785Seric { 26514785Seric CurEnv->e_flags &= ~EF_FATALERRS; 26612612Seric break; 26714785Seric } 26812612Seric QuickAbort = TRUE; 2694549Seric p = skipword(p, "to"); 2704549Seric if (p == NULL) 2714549Seric break; 27216140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 27312612Seric if (a == NULL) 27412612Seric break; 27516886Seric a->q_flags |= QPRIMARY; 27612612Seric a = recipient(a, &CurEnv->e_sendqueue); 27712612Seric if (Errors != 0) 27812612Seric break; 27912612Seric 28012612Seric /* no errors during parsing, but might be a duplicate */ 28112612Seric CurEnv->e_to = p; 28212612Seric if (!bitset(QBADADDR, a->q_flags)) 28312612Seric message("250", "Recipient ok"); 28412612Seric else 2854549Seric { 28612612Seric /* punt -- should keep message in ADDRESS.... */ 28712612Seric message("550", "Addressee unknown"); 2884549Seric } 28912612Seric CurEnv->e_to = NULL; 2904549Seric break; 2914549Seric 2924549Seric case CMDDATA: /* data -- text of mail */ 29324943Seric SmtpPhase = "DATA"; 2944976Seric if (!hasmail) 2954549Seric { 2964976Seric message("503", "Need MAIL command"); 2974976Seric break; 2984549Seric } 29924943Seric else if (CurEnv->e_nrcpts <= 0) 3004549Seric { 3014976Seric message("503", "Need RCPT (recipient)"); 3024976Seric break; 3034549Seric } 3044976Seric 3054976Seric /* collect the text of the message */ 30624943Seric SmtpPhase = "collect"; 30725016Seric setproctitle("%s %s: %s", CurEnv->e_id, 30825050Seric CurHostName, inp); 3094976Seric collect(TRUE); 3104976Seric if (Errors != 0) 3114976Seric break; 3124976Seric 3138238Seric /* 3148238Seric ** Arrange to send to everyone. 3158238Seric ** If sending to multiple people, mail back 3168238Seric ** errors rather than reporting directly. 3178238Seric ** In any case, don't mail back errors for 3188238Seric ** anything that has happened up to 3198238Seric ** now (the other end will do this). 32010197Seric ** Truncate our transcript -- the mail has gotten 32110197Seric ** to us successfully, and if we have 32210197Seric ** to mail this back, it will be easier 32310197Seric ** on the reader. 3248238Seric ** Then send to everyone. 3258238Seric ** Finally give a reply code. If an error has 3268238Seric ** already been given, don't mail a 3278238Seric ** message back. 3289339Seric ** We goose error returns by clearing error bit. 3298238Seric */ 3308238Seric 33124943Seric SmtpPhase = "delivery"; 33224943Seric if (CurEnv->e_nrcpts != 1) 3339378Seric { 3349378Seric HoldErrs = TRUE; 33516886Seric ErrorMode = EM_MAIL; 3369378Seric } 3379339Seric CurEnv->e_flags &= ~EF_FATALERRS; 33810197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3394976Seric 3404976Seric /* send to all recipients */ 34114877Seric sendall(CurEnv, SM_DEFAULT); 3426907Seric CurEnv->e_to = NULL; 3434976Seric 34423516Seric /* save statistics */ 34523516Seric markstats(CurEnv, (ADDRESS *) NULL); 34623516Seric 3478238Seric /* issue success if appropriate and reset */ 3488238Seric if (Errors == 0 || HoldErrs) 3499283Seric message("250", "Ok"); 3508238Seric else 3519339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3529339Seric 3539339Seric /* if in a child, pop back to our parent */ 3549339Seric if (InChild) 3559339Seric finis(); 35624943Seric 35724943Seric /* clean up a bit */ 35824943Seric hasmail = 0; 35924943Seric dropenvelope(CurEnv); 36024943Seric CurEnv = newenvelope(CurEnv); 36124943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3624549Seric break; 3634549Seric 3644549Seric case CMDRSET: /* rset -- reset state */ 3654549Seric message("250", "Reset state"); 3669339Seric if (InChild) 3679339Seric finis(); 3689339Seric break; 3694549Seric 3704549Seric case CMDVRFY: /* vrfy -- verify address */ 3719339Seric if (runinchild("SMTP-VRFY") > 0) 3729339Seric break; 37325050Seric setproctitle("%s: %s", CurHostName, inp); 3745003Seric vrfyqueue = NULL; 3757762Seric QuickAbort = TRUE; 3769619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3777762Seric if (Errors != 0) 3789339Seric { 3799339Seric if (InChild) 3809339Seric finis(); 3817762Seric break; 3829339Seric } 3835003Seric while (vrfyqueue != NULL) 3845003Seric { 3855003Seric register ADDRESS *a = vrfyqueue->q_next; 3865003Seric char *code; 3875003Seric 3887685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3895003Seric a = a->q_next; 3905003Seric 3917685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3925003Seric { 3935003Seric if (a != NULL) 3945003Seric code = "250-"; 3955003Seric else 3965003Seric code = "250"; 3975003Seric if (vrfyqueue->q_fullname == NULL) 3985003Seric message(code, "<%s>", vrfyqueue->q_paddr); 3995003Seric else 4005003Seric message(code, "%s <%s>", 4015003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4025003Seric } 4035003Seric else if (a == NULL) 4045003Seric message("554", "Self destructive alias loop"); 4055003Seric vrfyqueue = a; 4065003Seric } 4079339Seric if (InChild) 4089339Seric finis(); 4094549Seric break; 4104549Seric 4114549Seric case CMDHELP: /* help -- give user info */ 4124577Seric if (*p == '\0') 4134577Seric p = "SMTP"; 4144577Seric help(p); 4154549Seric break; 4164549Seric 4174549Seric case CMDNOOP: /* noop -- do nothing */ 4184549Seric message("200", "OK"); 4194549Seric break; 4204549Seric 4214549Seric case CMDQUIT: /* quit -- leave mail */ 42225050Seric message("221", "%s closing connection", MyHostName); 4239339Seric if (InChild) 4249339Seric ExitStat = EX_QUIT; 4254549Seric finis(); 4264549Seric 4278544Seric case CMDVERB: /* set verbose mode */ 4288544Seric Verbose = TRUE; 42925025Seric SendMode = SM_DELIVER; 4308544Seric message("200", "Verbose mode"); 4318544Seric break; 4328544Seric 4339314Seric case CMDONEX: /* doing one transaction only */ 4349378Seric OneXact = TRUE; 4359314Seric message("200", "Only one transaction"); 4369314Seric break; 4379314Seric 4385003Seric # ifdef DEBUG 4399339Seric case CMDDBGQSHOW: /* show queues */ 4406907Seric printf("Send Queue="); 4416907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4425003Seric break; 4437275Seric 4447275Seric case CMDDBGDEBUG: /* set debug mode */ 4457676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4467676Seric tTflag(p); 4477676Seric message("200", "Debug set"); 4487275Seric break; 44924945Seric # endif DEBUG 4507275Seric 45124945Seric # ifdef WIZ 4527282Seric case CMDDBGKILL: /* kill the parent */ 4538544Seric if (!iswiz()) 4548544Seric break; 4557282Seric if (kill(MotherPid, SIGTERM) >= 0) 4567282Seric message("200", "Mother is dead"); 4577282Seric else 4587282Seric message("500", "Can't kill Mom"); 4597282Seric break; 4608544Seric 4618544Seric case CMDDBGWIZ: /* become a wizard */ 4628544Seric if (WizWord != NULL) 4638544Seric { 4648544Seric char seed[3]; 4658544Seric extern char *crypt(); 4668544Seric 46723106Seric (void) strncpy(seed, WizWord, 2); 46815596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4698544Seric { 47015596Seric IsWiz = TRUE; 47115596Seric message("200", "Please pass, oh mighty wizard"); 4728544Seric break; 4738544Seric } 4748544Seric } 47515596Seric message("500", "You are no wizard!"); 4768544Seric break; 4775003Seric 47824945Seric # else WIZ 47924945Seric case CMDDBGWIZ: /* try to become a wizard */ 48024945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 48124945Seric break; 48224945Seric # endif WIZ 48324945Seric 4844549Seric case CMDERROR: /* unknown command */ 4854549Seric message("500", "Command unrecognized"); 4864549Seric break; 4874549Seric 4884549Seric default: 4894549Seric syserr("smtp: unknown code %d", c->cmdcode); 4904549Seric break; 4914549Seric } 4924549Seric } 4934549Seric } 4944549Seric /* 4954549Seric ** SKIPWORD -- skip a fixed word. 4964549Seric ** 4974549Seric ** Parameters: 4984549Seric ** p -- place to start looking. 4994549Seric ** w -- word to skip. 5004549Seric ** 5014549Seric ** Returns: 5024549Seric ** p following w. 5034549Seric ** NULL on error. 5044549Seric ** 5054549Seric ** Side Effects: 5064549Seric ** clobbers the p data area. 5074549Seric */ 5084549Seric 5094549Seric static char * 5104549Seric skipword(p, w) 5114549Seric register char *p; 5124549Seric char *w; 5134549Seric { 5144549Seric register char *q; 5154549Seric 5164549Seric /* find beginning of word */ 5174549Seric while (isspace(*p)) 5184549Seric p++; 5194549Seric q = p; 5204549Seric 5214549Seric /* find end of word */ 5224549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5234549Seric p++; 5244549Seric while (isspace(*p)) 5254549Seric *p++ = '\0'; 5264549Seric if (*p != ':') 5274549Seric { 5284549Seric syntax: 5294549Seric message("501", "Syntax error"); 5304549Seric Errors++; 5314549Seric return (NULL); 5324549Seric } 5334549Seric *p++ = '\0'; 5344549Seric while (isspace(*p)) 5354549Seric p++; 5364549Seric 5374549Seric /* see if the input word matches desired word */ 538*33725Sbostic if (strcasecmp(q, w)) 5394549Seric goto syntax; 5404549Seric 5414549Seric return (p); 5424549Seric } 5434577Seric /* 5444577Seric ** HELP -- implement the HELP command. 5454577Seric ** 5464577Seric ** Parameters: 5474577Seric ** topic -- the topic we want help for. 5484577Seric ** 5494577Seric ** Returns: 5504577Seric ** none. 5514577Seric ** 5524577Seric ** Side Effects: 5534577Seric ** outputs the help file to message output. 5544577Seric */ 5554577Seric 5564577Seric help(topic) 5574577Seric char *topic; 5584577Seric { 5594577Seric register FILE *hf; 5604577Seric int len; 5614577Seric char buf[MAXLINE]; 5624577Seric bool noinfo; 5634577Seric 5648269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5654577Seric { 5664577Seric /* no help */ 56711931Seric errno = 0; 5684577Seric message("502", "HELP not implemented"); 5694577Seric return; 5704577Seric } 5714577Seric 5724577Seric len = strlen(topic); 5734577Seric makelower(topic); 5744577Seric noinfo = TRUE; 5754577Seric 5764577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5774577Seric { 5784577Seric if (strncmp(buf, topic, len) == 0) 5794577Seric { 5804577Seric register char *p; 5814577Seric 5824577Seric p = index(buf, '\t'); 5834577Seric if (p == NULL) 5844577Seric p = buf; 5854577Seric else 5864577Seric p++; 5874577Seric fixcrlf(p, TRUE); 5884577Seric message("214-", p); 5894577Seric noinfo = FALSE; 5904577Seric } 5914577Seric } 5924577Seric 5934577Seric if (noinfo) 5944577Seric message("504", "HELP topic unknown"); 5954577Seric else 5964577Seric message("214", "End of HELP info"); 5974628Seric (void) fclose(hf); 5984577Seric } 5998544Seric /* 6008544Seric ** ISWIZ -- tell us if we are a wizard 6018544Seric ** 6028544Seric ** If not, print a nasty message. 6038544Seric ** 6048544Seric ** Parameters: 6058544Seric ** none. 6068544Seric ** 6078544Seric ** Returns: 6088544Seric ** TRUE if we are a wizard. 6098544Seric ** FALSE if we are not a wizard. 6108544Seric ** 6118544Seric ** Side Effects: 6128544Seric ** Prints a 500 exit stat if we are not a wizard. 6138544Seric */ 6145181Seric 61524945Seric #ifdef WIZ 61619038Seric 6178544Seric bool 6188544Seric iswiz() 6198544Seric { 6208544Seric if (!IsWiz) 6218544Seric message("500", "Mere mortals musn't mutter that mantra"); 6228544Seric return (IsWiz); 6238544Seric } 62419038Seric 62524945Seric #endif WIZ 6269339Seric /* 6279339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6289339Seric ** 6299339Seric ** Parameters: 6309339Seric ** label -- a string used in error messages 6319339Seric ** 6329339Seric ** Returns: 6339339Seric ** zero in the child 6349339Seric ** one in the parent 6359339Seric ** 6369339Seric ** Side Effects: 6379339Seric ** none. 6389339Seric */ 6398544Seric 6409339Seric runinchild(label) 6419339Seric char *label; 6429339Seric { 6439339Seric int childpid; 6449339Seric 64516158Seric if (!OneXact) 6469339Seric { 64716158Seric childpid = dofork(); 64816158Seric if (childpid < 0) 64916158Seric { 65016158Seric syserr("%s: cannot fork", label); 65116158Seric return (1); 65216158Seric } 65316158Seric if (childpid > 0) 65416158Seric { 65516158Seric auto int st; 6569339Seric 65716158Seric /* parent -- wait for child to complete */ 65816158Seric st = waitfor(childpid); 65916158Seric if (st == -1) 66016158Seric syserr("%s: lost child", label); 6619339Seric 66216158Seric /* if we exited on a QUIT command, complete the process */ 66316158Seric if (st == (EX_QUIT << 8)) 66416158Seric finis(); 6659339Seric 66616158Seric return (1); 66716158Seric } 66816158Seric else 66916158Seric { 67016158Seric /* child */ 67116158Seric InChild = TRUE; 67225050Seric QuickAbort = FALSE; 67325614Seric clearenvelope(CurEnv, FALSE); 67416158Seric } 6759339Seric } 67615256Seric 67716158Seric /* open alias database */ 67816158Seric initaliases(AliasFile, FALSE); 67916158Seric 68016158Seric return (0); 6819339Seric } 6829339Seric 6835181Seric # endif SMTP 684