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*30448Seric static char SccsId[] = "@(#)srvrsmtp.c 5.19 (Berkeley) 02/03/87 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*30448Seric static char SccsId[] = "@(#)srvrsmtp.c 5.19 (Berkeley) 02/03/87"; 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; 108*30448Seric char *sendinghost; 1098544Seric char inp[MAXLINE]; 11024981Seric char cmdbuf[100]; 1117124Seric extern char Version[]; 1127356Seric extern tick(); 1138544Seric extern bool iswiz(); 1149349Seric extern char *arpadate(); 11511151Seric extern char *macvalue(); 11612612Seric extern ADDRESS *recipient(); 11724943Seric extern ENVELOPE BlankEnvelope; 11824943Seric extern ENVELOPE *newenvelope(); 1194549Seric 1205003Seric hasmail = FALSE; 1217363Seric if (OutChannel != stdout) 1227363Seric { 1237363Seric /* arrange for debugging output to go to remote host */ 1247363Seric (void) close(1); 1257363Seric (void) dup(fileno(OutChannel)); 1267363Seric } 12711931Seric settime(); 12824971Seric if (RealHostName != NULL) 12925050Seric { 13025050Seric CurHostName = RealHostName; 13125050Seric setproctitle("srvrsmtp %s", CurHostName); 13225050Seric } 13325050Seric else 13425050Seric { 13525050Seric /* this must be us!! */ 13625050Seric CurHostName = MyHostName; 13725050Seric } 13816153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 13910708Seric message("220", inp); 14024943Seric SmtpPhase = "startup"; 141*30448Seric sendinghost = NULL; 1424549Seric for (;;) 1434549Seric { 14412612Seric /* arrange for backout */ 14512612Seric if (setjmp(TopFrame) > 0 && InChild) 14612612Seric finis(); 14712612Seric QuickAbort = FALSE; 14812612Seric HoldErrs = FALSE; 14912612Seric 1507356Seric /* setup for the read */ 1516907Seric CurEnv->e_to = NULL; 1524577Seric Errors = 0; 1537275Seric (void) fflush(stdout); 1547356Seric 1557356Seric /* read the input line */ 1567685Seric p = sfgets(inp, sizeof inp, InChannel); 1577356Seric 1587685Seric /* handle errors */ 1597356Seric if (p == NULL) 1607356Seric { 1614549Seric /* end of file, just die */ 16225050Seric message("421", "%s Lost input channel to %s", 16325050Seric MyHostName, CurHostName); 1644549Seric finis(); 1654549Seric } 1664549Seric 1674549Seric /* clean up end of line */ 1684558Seric fixcrlf(inp, TRUE); 1694549Seric 1704713Seric /* echo command to transcript */ 1719545Seric if (CurEnv->e_xfp != NULL) 1729545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1734713Seric 1744549Seric /* break off command */ 1754549Seric for (p = inp; isspace(*p); p++) 1764549Seric continue; 1774549Seric cmd = p; 17824981Seric for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) 17924981Seric *cmd++ = *p++; 18024981Seric *cmd = '\0'; 1814549Seric 18225691Seric /* throw away leading whitespace */ 18325691Seric while (isspace(*p)) 18425691Seric p++; 18525691Seric 1864549Seric /* decode command */ 1874549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1884549Seric { 18924984Seric if (sameword(c->cmdname, cmdbuf)) 1904549Seric break; 1914549Seric } 1924549Seric 1934549Seric /* process command */ 1944549Seric switch (c->cmdcode) 1954549Seric { 1964976Seric case CMDHELO: /* hello -- introduce yourself */ 19724943Seric SmtpPhase = "HELO"; 19825050Seric setproctitle("%s: %s", CurHostName, inp); 19925050Seric if (sameword(p, MyHostName)) 20014877Seric { 20114877Seric /* connected to an echo server */ 20214877Seric message("553", "%s I refuse to talk to myself", 20325050Seric MyHostName); 20414877Seric break; 20514877Seric } 20611146Seric if (RealHostName != NULL && !sameword(p, RealHostName)) 20711146Seric { 20824981Seric char hostbuf[MAXNAME]; 20911146Seric 21024981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 211*30448Seric sendinghost = newstr(hostbuf); 21211146Seric } 21311146Seric else 214*30448Seric sendinghost = newstr(p); 2154997Seric message("250", "%s Hello %s, pleased to meet you", 21625050Seric MyHostName, p); 2174976Seric break; 2184976Seric 2194549Seric case CMDMAIL: /* mail -- designate sender */ 22024943Seric SmtpPhase = "MAIL"; 22124943Seric 22211151Seric /* force a sending host even if no HELO given */ 22311151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 224*30448Seric sendinghost = RealHostName; 22511151Seric 2269314Seric /* check for validity of this command */ 2274558Seric if (hasmail) 2284558Seric { 2294558Seric message("503", "Sender already specified"); 2304558Seric break; 2314558Seric } 2329339Seric if (InChild) 2339339Seric { 2349339Seric syserr("Nested MAIL command"); 2359339Seric exit(0); 2369339Seric } 2379339Seric 2389339Seric /* fork a subprocess to process this command */ 2399339Seric if (runinchild("SMTP-MAIL") > 0) 2409339Seric break; 241*30448Seric define('s', sendinghost, CurEnv); 2429339Seric initsys(); 24325016Seric setproctitle("%s %s: %s", CurEnv->e_id, 24425050Seric CurHostName, inp); 2459339Seric 2469339Seric /* child -- go do the processing */ 2474549Seric p = skipword(p, "from"); 2484549Seric if (p == NULL) 2494549Seric break; 2504549Seric setsender(p); 2514577Seric if (Errors == 0) 2524549Seric { 2534549Seric message("250", "Sender ok"); 2544549Seric hasmail = TRUE; 2554549Seric } 2569339Seric else if (InChild) 2579339Seric finis(); 2584549Seric break; 2594549Seric 2604976Seric case CMDRCPT: /* rcpt -- designate recipient */ 26124943Seric SmtpPhase = "RCPT"; 26225016Seric setproctitle("%s %s: %s", CurEnv->e_id, 26325050Seric CurHostName, inp); 26412612Seric if (setjmp(TopFrame) > 0) 26514785Seric { 26614785Seric CurEnv->e_flags &= ~EF_FATALERRS; 26712612Seric break; 26814785Seric } 26912612Seric QuickAbort = TRUE; 2704549Seric p = skipword(p, "to"); 2714549Seric if (p == NULL) 2724549Seric break; 27316140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 27412612Seric if (a == NULL) 27512612Seric break; 27616886Seric a->q_flags |= QPRIMARY; 27712612Seric a = recipient(a, &CurEnv->e_sendqueue); 27812612Seric if (Errors != 0) 27912612Seric break; 28012612Seric 28112612Seric /* no errors during parsing, but might be a duplicate */ 28212612Seric CurEnv->e_to = p; 28312612Seric if (!bitset(QBADADDR, a->q_flags)) 28412612Seric message("250", "Recipient ok"); 28512612Seric else 2864549Seric { 28712612Seric /* punt -- should keep message in ADDRESS.... */ 28812612Seric message("550", "Addressee unknown"); 2894549Seric } 29012612Seric CurEnv->e_to = NULL; 2914549Seric break; 2924549Seric 2934549Seric case CMDDATA: /* data -- text of mail */ 29424943Seric SmtpPhase = "DATA"; 2954976Seric if (!hasmail) 2964549Seric { 2974976Seric message("503", "Need MAIL command"); 2984976Seric break; 2994549Seric } 30024943Seric else if (CurEnv->e_nrcpts <= 0) 3014549Seric { 3024976Seric message("503", "Need RCPT (recipient)"); 3034976Seric break; 3044549Seric } 3054976Seric 3064976Seric /* collect the text of the message */ 30724943Seric SmtpPhase = "collect"; 30825016Seric setproctitle("%s %s: %s", CurEnv->e_id, 30925050Seric CurHostName, inp); 3104976Seric collect(TRUE); 3114976Seric if (Errors != 0) 3124976Seric break; 3134976Seric 3148238Seric /* 3158238Seric ** Arrange to send to everyone. 3168238Seric ** If sending to multiple people, mail back 3178238Seric ** errors rather than reporting directly. 3188238Seric ** In any case, don't mail back errors for 3198238Seric ** anything that has happened up to 3208238Seric ** now (the other end will do this). 32110197Seric ** Truncate our transcript -- the mail has gotten 32210197Seric ** to us successfully, and if we have 32310197Seric ** to mail this back, it will be easier 32410197Seric ** on the reader. 3258238Seric ** Then send to everyone. 3268238Seric ** Finally give a reply code. If an error has 3278238Seric ** already been given, don't mail a 3288238Seric ** message back. 3299339Seric ** We goose error returns by clearing error bit. 3308238Seric */ 3318238Seric 33224943Seric SmtpPhase = "delivery"; 33324943Seric if (CurEnv->e_nrcpts != 1) 3349378Seric { 3359378Seric HoldErrs = TRUE; 33616886Seric ErrorMode = EM_MAIL; 3379378Seric } 3389339Seric CurEnv->e_flags &= ~EF_FATALERRS; 33910197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3404976Seric 3414976Seric /* send to all recipients */ 34214877Seric sendall(CurEnv, SM_DEFAULT); 3436907Seric CurEnv->e_to = NULL; 3444976Seric 34523516Seric /* save statistics */ 34623516Seric markstats(CurEnv, (ADDRESS *) NULL); 34723516Seric 3488238Seric /* issue success if appropriate and reset */ 3498238Seric if (Errors == 0 || HoldErrs) 3509283Seric message("250", "Ok"); 3518238Seric else 3529339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3539339Seric 3549339Seric /* if in a child, pop back to our parent */ 3559339Seric if (InChild) 3569339Seric finis(); 35724943Seric 35824943Seric /* clean up a bit */ 35924943Seric hasmail = 0; 36024943Seric dropenvelope(CurEnv); 36124943Seric CurEnv = newenvelope(CurEnv); 36224943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3634549Seric break; 3644549Seric 3654549Seric case CMDRSET: /* rset -- reset state */ 3664549Seric message("250", "Reset state"); 3679339Seric if (InChild) 3689339Seric finis(); 3699339Seric break; 3704549Seric 3714549Seric case CMDVRFY: /* vrfy -- verify address */ 3729339Seric if (runinchild("SMTP-VRFY") > 0) 3739339Seric break; 37425050Seric setproctitle("%s: %s", CurHostName, inp); 3755003Seric vrfyqueue = NULL; 3767762Seric QuickAbort = TRUE; 3779619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3787762Seric if (Errors != 0) 3799339Seric { 3809339Seric if (InChild) 3819339Seric finis(); 3827762Seric break; 3839339Seric } 3845003Seric while (vrfyqueue != NULL) 3855003Seric { 3865003Seric register ADDRESS *a = vrfyqueue->q_next; 3875003Seric char *code; 3885003Seric 3897685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3905003Seric a = a->q_next; 3915003Seric 3927685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3935003Seric { 3945003Seric if (a != NULL) 3955003Seric code = "250-"; 3965003Seric else 3975003Seric code = "250"; 3985003Seric if (vrfyqueue->q_fullname == NULL) 3995003Seric message(code, "<%s>", vrfyqueue->q_paddr); 4005003Seric else 4015003Seric message(code, "%s <%s>", 4025003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4035003Seric } 4045003Seric else if (a == NULL) 4055003Seric message("554", "Self destructive alias loop"); 4065003Seric vrfyqueue = a; 4075003Seric } 4089339Seric if (InChild) 4099339Seric finis(); 4104549Seric break; 4114549Seric 4124549Seric case CMDHELP: /* help -- give user info */ 4134577Seric if (*p == '\0') 4144577Seric p = "SMTP"; 4154577Seric help(p); 4164549Seric break; 4174549Seric 4184549Seric case CMDNOOP: /* noop -- do nothing */ 4194549Seric message("200", "OK"); 4204549Seric break; 4214549Seric 4224549Seric case CMDQUIT: /* quit -- leave mail */ 42325050Seric message("221", "%s closing connection", MyHostName); 4249339Seric if (InChild) 4259339Seric ExitStat = EX_QUIT; 4264549Seric finis(); 4274549Seric 4288544Seric case CMDVERB: /* set verbose mode */ 4298544Seric Verbose = TRUE; 43025025Seric SendMode = SM_DELIVER; 4318544Seric message("200", "Verbose mode"); 4328544Seric break; 4338544Seric 4349314Seric case CMDONEX: /* doing one transaction only */ 4359378Seric OneXact = TRUE; 4369314Seric message("200", "Only one transaction"); 4379314Seric break; 4389314Seric 4395003Seric # ifdef DEBUG 4409339Seric case CMDDBGQSHOW: /* show queues */ 4416907Seric printf("Send Queue="); 4426907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4435003Seric break; 4447275Seric 4457275Seric case CMDDBGDEBUG: /* set debug mode */ 4467676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4477676Seric tTflag(p); 4487676Seric message("200", "Debug set"); 4497275Seric break; 45024945Seric # endif DEBUG 4517275Seric 45224945Seric # ifdef WIZ 4537282Seric case CMDDBGKILL: /* kill the parent */ 4548544Seric if (!iswiz()) 4558544Seric break; 4567282Seric if (kill(MotherPid, SIGTERM) >= 0) 4577282Seric message("200", "Mother is dead"); 4587282Seric else 4597282Seric message("500", "Can't kill Mom"); 4607282Seric break; 4618544Seric 4628544Seric case CMDDBGWIZ: /* become a wizard */ 4638544Seric if (WizWord != NULL) 4648544Seric { 4658544Seric char seed[3]; 4668544Seric extern char *crypt(); 4678544Seric 46823106Seric (void) strncpy(seed, WizWord, 2); 46915596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4708544Seric { 47115596Seric IsWiz = TRUE; 47215596Seric message("200", "Please pass, oh mighty wizard"); 4738544Seric break; 4748544Seric } 4758544Seric } 47615596Seric message("500", "You are no wizard!"); 4778544Seric break; 4785003Seric 47924945Seric # else WIZ 48024945Seric case CMDDBGWIZ: /* try to become a wizard */ 48124945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 48224945Seric break; 48324945Seric # endif WIZ 48424945Seric 4854549Seric case CMDERROR: /* unknown command */ 4864549Seric message("500", "Command unrecognized"); 4874549Seric break; 4884549Seric 4894549Seric default: 4904549Seric syserr("smtp: unknown code %d", c->cmdcode); 4914549Seric break; 4924549Seric } 4934549Seric } 4944549Seric } 4954549Seric /* 4964549Seric ** SKIPWORD -- skip a fixed word. 4974549Seric ** 4984549Seric ** Parameters: 4994549Seric ** p -- place to start looking. 5004549Seric ** w -- word to skip. 5014549Seric ** 5024549Seric ** Returns: 5034549Seric ** p following w. 5044549Seric ** NULL on error. 5054549Seric ** 5064549Seric ** Side Effects: 5074549Seric ** clobbers the p data area. 5084549Seric */ 5094549Seric 5104549Seric static char * 5114549Seric skipword(p, w) 5124549Seric register char *p; 5134549Seric char *w; 5144549Seric { 5154549Seric register char *q; 5164549Seric extern bool sameword(); 5174549Seric 5184549Seric /* find beginning of word */ 5194549Seric while (isspace(*p)) 5204549Seric p++; 5214549Seric q = p; 5224549Seric 5234549Seric /* find end of word */ 5244549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5254549Seric p++; 5264549Seric while (isspace(*p)) 5274549Seric *p++ = '\0'; 5284549Seric if (*p != ':') 5294549Seric { 5304549Seric syntax: 5314549Seric message("501", "Syntax error"); 5324549Seric Errors++; 5334549Seric return (NULL); 5344549Seric } 5354549Seric *p++ = '\0'; 5364549Seric while (isspace(*p)) 5374549Seric p++; 5384549Seric 5394549Seric /* see if the input word matches desired word */ 5404549Seric if (!sameword(q, w)) 5414549Seric goto syntax; 5424549Seric 5434549Seric return (p); 5444549Seric } 5454577Seric /* 5464577Seric ** HELP -- implement the HELP command. 5474577Seric ** 5484577Seric ** Parameters: 5494577Seric ** topic -- the topic we want help for. 5504577Seric ** 5514577Seric ** Returns: 5524577Seric ** none. 5534577Seric ** 5544577Seric ** Side Effects: 5554577Seric ** outputs the help file to message output. 5564577Seric */ 5574577Seric 5584577Seric help(topic) 5594577Seric char *topic; 5604577Seric { 5614577Seric register FILE *hf; 5624577Seric int len; 5634577Seric char buf[MAXLINE]; 5644577Seric bool noinfo; 5654577Seric 5668269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5674577Seric { 5684577Seric /* no help */ 56911931Seric errno = 0; 5704577Seric message("502", "HELP not implemented"); 5714577Seric return; 5724577Seric } 5734577Seric 5744577Seric len = strlen(topic); 5754577Seric makelower(topic); 5764577Seric noinfo = TRUE; 5774577Seric 5784577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5794577Seric { 5804577Seric if (strncmp(buf, topic, len) == 0) 5814577Seric { 5824577Seric register char *p; 5834577Seric 5844577Seric p = index(buf, '\t'); 5854577Seric if (p == NULL) 5864577Seric p = buf; 5874577Seric else 5884577Seric p++; 5894577Seric fixcrlf(p, TRUE); 5904577Seric message("214-", p); 5914577Seric noinfo = FALSE; 5924577Seric } 5934577Seric } 5944577Seric 5954577Seric if (noinfo) 5964577Seric message("504", "HELP topic unknown"); 5974577Seric else 5984577Seric message("214", "End of HELP info"); 5994628Seric (void) fclose(hf); 6004577Seric } 6018544Seric /* 6028544Seric ** ISWIZ -- tell us if we are a wizard 6038544Seric ** 6048544Seric ** If not, print a nasty message. 6058544Seric ** 6068544Seric ** Parameters: 6078544Seric ** none. 6088544Seric ** 6098544Seric ** Returns: 6108544Seric ** TRUE if we are a wizard. 6118544Seric ** FALSE if we are not a wizard. 6128544Seric ** 6138544Seric ** Side Effects: 6148544Seric ** Prints a 500 exit stat if we are not a wizard. 6158544Seric */ 6165181Seric 61724945Seric #ifdef WIZ 61819038Seric 6198544Seric bool 6208544Seric iswiz() 6218544Seric { 6228544Seric if (!IsWiz) 6238544Seric message("500", "Mere mortals musn't mutter that mantra"); 6248544Seric return (IsWiz); 6258544Seric } 62619038Seric 62724945Seric #endif WIZ 6289339Seric /* 6299339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6309339Seric ** 6319339Seric ** Parameters: 6329339Seric ** label -- a string used in error messages 6339339Seric ** 6349339Seric ** Returns: 6359339Seric ** zero in the child 6369339Seric ** one in the parent 6379339Seric ** 6389339Seric ** Side Effects: 6399339Seric ** none. 6409339Seric */ 6418544Seric 6429339Seric runinchild(label) 6439339Seric char *label; 6449339Seric { 6459339Seric int childpid; 6469339Seric 64716158Seric if (!OneXact) 6489339Seric { 64916158Seric childpid = dofork(); 65016158Seric if (childpid < 0) 65116158Seric { 65216158Seric syserr("%s: cannot fork", label); 65316158Seric return (1); 65416158Seric } 65516158Seric if (childpid > 0) 65616158Seric { 65716158Seric auto int st; 6589339Seric 65916158Seric /* parent -- wait for child to complete */ 66016158Seric st = waitfor(childpid); 66116158Seric if (st == -1) 66216158Seric syserr("%s: lost child", label); 6639339Seric 66416158Seric /* if we exited on a QUIT command, complete the process */ 66516158Seric if (st == (EX_QUIT << 8)) 66616158Seric finis(); 6679339Seric 66816158Seric return (1); 66916158Seric } 67016158Seric else 67116158Seric { 67216158Seric /* child */ 67316158Seric InChild = TRUE; 67425050Seric QuickAbort = FALSE; 67525614Seric clearenvelope(CurEnv, FALSE); 67616158Seric } 6779339Seric } 67815256Seric 67916158Seric /* open alias database */ 68016158Seric initaliases(AliasFile, FALSE); 68116158Seric 68216158Seric return (0); 6839339Seric } 6849339Seric 6855181Seric # endif SMTP 686