122712Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822712Sdist 933731Sbostic # include "sendmail.h" 1022712Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*58082Seric static char sccsid[] = "@(#)srvrsmtp.c 6.11 (Berkeley) 02/20/93 (with SMTP)"; 1433731Sbostic #else 15*58082Seric static char sccsid[] = "@(#)srvrsmtp.c 6.11 (Berkeley) 02/20/93 (without SMTP)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 199339Seric # include <errno.h> 2011728Seric # include <signal.h> 214549Seric 2233731Sbostic # ifdef SMTP 234556Seric 244549Seric /* 254549Seric ** SMTP -- run the SMTP protocol. 264549Seric ** 274549Seric ** Parameters: 284549Seric ** none. 294549Seric ** 304549Seric ** Returns: 314549Seric ** never. 324549Seric ** 334549Seric ** Side Effects: 344549Seric ** Reads commands from the input channel and processes 354549Seric ** them. 364549Seric */ 374549Seric 384549Seric struct cmd 394549Seric { 404549Seric char *cmdname; /* command name */ 414549Seric int cmdcode; /* internal code, see below */ 424549Seric }; 434549Seric 444549Seric /* values for cmdcode */ 454549Seric # define CMDERROR 0 /* bad command */ 464549Seric # define CMDMAIL 1 /* mail -- designate sender */ 474976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 484549Seric # define CMDDATA 3 /* data -- send message text */ 499339Seric # define CMDRSET 4 /* rset -- reset state */ 509339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 519339Seric # define CMDHELP 6 /* help -- give usage info */ 529339Seric # define CMDNOOP 7 /* noop -- do nothing */ 539339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 549339Seric # define CMDHELO 9 /* helo -- be polite */ 5536230Skarels # define CMDONEX 10 /* onex -- sending one transaction only */ 5636230Skarels # define CMDVERB 11 /* verb -- go into verbose mode */ 5736230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 5836230Skarels # define CMDDBGQSHOW 12 /* showq -- show send queue */ 5936230Skarels # define CMDDBGDEBUG 13 /* debug -- set debug mode */ 604549Seric 614549Seric static struct cmd CmdTab[] = 624549Seric { 634549Seric "mail", CMDMAIL, 644976Seric "rcpt", CMDRCPT, 654549Seric "data", CMDDATA, 664549Seric "rset", CMDRSET, 674549Seric "vrfy", CMDVRFY, 687762Seric "expn", CMDVRFY, 694549Seric "help", CMDHELP, 704549Seric "noop", CMDNOOP, 714549Seric "quit", CMDQUIT, 724976Seric "helo", CMDHELO, 738544Seric "verb", CMDVERB, 749314Seric "onex", CMDONEX, 7536230Skarels /* 7636230Skarels * remaining commands are here only 7736230Skarels * to trap and log attempts to use them 7836230Skarels */ 799339Seric "showq", CMDDBGQSHOW, 808544Seric "debug", CMDDBGDEBUG, 814549Seric NULL, CMDERROR, 824549Seric }; 834549Seric 849339Seric bool InChild = FALSE; /* true if running in a subprocess */ 859378Seric bool OneXact = FALSE; /* one xaction only this run */ 8611146Seric 879339Seric #define EX_QUIT 22 /* special code for QUIT command */ 888544Seric 8955012Seric smtp(e) 9055012Seric register ENVELOPE *e; 914549Seric { 924549Seric register char *p; 938544Seric register struct cmd *c; 944549Seric char *cmd; 9546928Sbostic static char *skipword(); 964549Seric bool hasmail; /* mail command received */ 975003Seric auto ADDRESS *vrfyqueue; 9812612Seric ADDRESS *a; 9930448Seric char *sendinghost; 100*58082Seric bool gothello; 1018544Seric char inp[MAXLINE]; 10257232Seric char cmdbuf[MAXLINE]; 1037124Seric extern char Version[]; 10411151Seric extern char *macvalue(); 10512612Seric extern ADDRESS *recipient(); 10624943Seric extern ENVELOPE BlankEnvelope; 10724943Seric extern ENVELOPE *newenvelope(); 1084549Seric 1095003Seric hasmail = FALSE; 1107363Seric if (OutChannel != stdout) 1117363Seric { 1127363Seric /* arrange for debugging output to go to remote host */ 1137363Seric (void) close(1); 1147363Seric (void) dup(fileno(OutChannel)); 1157363Seric } 11655012Seric settime(e); 11757642Seric if (RealHostName == NULL) 11857642Seric RealHostName = MyHostName; 11957642Seric CurHostName = RealHostName; 12057642Seric setproctitle("srvrsmtp %s", CurHostName); 12158050Seric expand("\201e", inp, &inp[sizeof inp], e); 12255360Seric message("220", "%s", inp); 12324943Seric SmtpPhase = "startup"; 12430448Seric sendinghost = NULL; 125*58082Seric gothello = FALSE; 1264549Seric for (;;) 1274549Seric { 12812612Seric /* arrange for backout */ 12912612Seric if (setjmp(TopFrame) > 0 && InChild) 13012612Seric finis(); 13112612Seric QuickAbort = FALSE; 13212612Seric HoldErrs = FALSE; 13351951Seric LogUsrErrs = FALSE; 13412612Seric 1357356Seric /* setup for the read */ 13655012Seric e->e_to = NULL; 1374577Seric Errors = 0; 1387275Seric (void) fflush(stdout); 1397356Seric 1407356Seric /* read the input line */ 14157389Seric p = sfgets(inp, sizeof inp, InChannel, ReadTimeout); 1427356Seric 1437685Seric /* handle errors */ 1447356Seric if (p == NULL) 1457356Seric { 1464549Seric /* end of file, just die */ 14736230Skarels message("421", "%s Lost input channel from %s", 14825050Seric MyHostName, CurHostName); 14955464Seric #ifdef LOG 15058020Seric if (LogLevel > 1) 15155464Seric syslog(LOG_NOTICE, "lost input channel from %s", 15255464Seric CurHostName); 15355464Seric #endif 15458069Seric if (InChild) 15558069Seric ExitStat = EX_QUIT; 1564549Seric finis(); 1574549Seric } 1584549Seric 1594549Seric /* clean up end of line */ 1604558Seric fixcrlf(inp, TRUE); 1614549Seric 1624713Seric /* echo command to transcript */ 16355012Seric if (e->e_xfp != NULL) 16455012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1654713Seric 1664549Seric /* break off command */ 16758050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1684549Seric continue; 16957232Seric cmd = cmdbuf; 17058050Seric while (*p != '\0' && 17158050Seric !(isascii(*p) && isspace(*p)) && 17258050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 17324981Seric *cmd++ = *p++; 17424981Seric *cmd = '\0'; 1754549Seric 17625691Seric /* throw away leading whitespace */ 17758050Seric while (isascii(*p) && isspace(*p)) 17825691Seric p++; 17925691Seric 1804549Seric /* decode command */ 1814549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1824549Seric { 18333725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1844549Seric break; 1854549Seric } 1864549Seric 18751954Seric /* reset errors */ 18851954Seric errno = 0; 18951954Seric 1904549Seric /* process command */ 1914549Seric switch (c->cmdcode) 1924549Seric { 1934976Seric case CMDHELO: /* hello -- introduce yourself */ 19424943Seric SmtpPhase = "HELO"; 19525050Seric setproctitle("%s: %s", CurHostName, inp); 19633725Sbostic if (!strcasecmp(p, MyHostName)) 19714877Seric { 19836230Skarels /* 19936230Skarels * didn't know about alias, 20036230Skarels * or connected to an echo server 20136230Skarels */ 20247570Seric message("553", "%s config error: mail loops back to myself", 20347570Seric MyHostName); 20414877Seric break; 20514877Seric } 20633725Sbostic if (RealHostName != NULL && strcasecmp(p, RealHostName)) 20711146Seric { 20824981Seric char hostbuf[MAXNAME]; 20911146Seric 21024981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 21130448Seric sendinghost = newstr(hostbuf); 21211146Seric } 21311146Seric else 21430448Seric sendinghost = newstr(p); 2154997Seric message("250", "%s Hello %s, pleased to meet you", 21636230Skarels MyHostName, sendinghost); 217*58082Seric gothello = TRUE; 2184976Seric break; 2194976Seric 2204549Seric case CMDMAIL: /* mail -- designate sender */ 22124943Seric SmtpPhase = "MAIL"; 22224943Seric 22311151Seric /* force a sending host even if no HELO given */ 22458064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 22530448Seric sendinghost = RealHostName; 22611151Seric 2279314Seric /* check for validity of this command */ 228*58082Seric if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 229*58082Seric { 230*58082Seric message("503", "Polite people say HELO first"); 231*58082Seric break; 232*58082Seric } 2334558Seric if (hasmail) 2344558Seric { 2354558Seric message("503", "Sender already specified"); 2364558Seric break; 2374558Seric } 2389339Seric if (InChild) 2399339Seric { 24036230Skarels errno = 0; 24158008Seric syserr("Nested MAIL command: MAIL %s", p); 24258069Seric finis(); 2439339Seric } 244*58082Seric if (!enoughspace()) 245*58082Seric { 246*58082Seric message("452", "Insufficient disk space; try again later"); 247*58082Seric break; 248*58082Seric } 2499339Seric 2509339Seric /* fork a subprocess to process this command */ 25155012Seric if (runinchild("SMTP-MAIL", e) > 0) 2529339Seric break; 25358064Seric if (sendinghost != NULL) 25458064Seric define('s', sendinghost, e); 25555012Seric define('r', "SMTP", e); 25655012Seric initsys(e); 25757389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2589339Seric 2599339Seric /* child -- go do the processing */ 2604549Seric p = skipword(p, "from"); 2614549Seric if (p == NULL) 2624549Seric break; 26357977Seric if (setjmp(TopFrame) > 0) 26457977Seric break; 26557977Seric QuickAbort = TRUE; 26655012Seric setsender(p, e); 2674577Seric if (Errors == 0) 2684549Seric { 2694549Seric message("250", "Sender ok"); 2704549Seric hasmail = TRUE; 2714549Seric } 2729339Seric else if (InChild) 2739339Seric finis(); 2744549Seric break; 2754549Seric 2764976Seric case CMDRCPT: /* rcpt -- designate recipient */ 27724943Seric SmtpPhase = "RCPT"; 27857389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 27912612Seric if (setjmp(TopFrame) > 0) 28014785Seric { 28155012Seric e->e_flags &= ~EF_FATALERRS; 28212612Seric break; 28314785Seric } 28412612Seric QuickAbort = TRUE; 28551951Seric LogUsrErrs = TRUE; 2864549Seric p = skipword(p, "to"); 2874549Seric if (p == NULL) 2884549Seric break; 28955012Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0', e); 29012612Seric if (a == NULL) 29112612Seric break; 29216886Seric a->q_flags |= QPRIMARY; 29355012Seric a = recipient(a, &e->e_sendqueue, e); 29412612Seric if (Errors != 0) 29512612Seric break; 29612612Seric 29712612Seric /* no errors during parsing, but might be a duplicate */ 29855012Seric e->e_to = p; 29912612Seric if (!bitset(QBADADDR, a->q_flags)) 30012612Seric message("250", "Recipient ok"); 30112612Seric else 3024549Seric { 30312612Seric /* punt -- should keep message in ADDRESS.... */ 30412612Seric message("550", "Addressee unknown"); 3054549Seric } 30655012Seric e->e_to = NULL; 3074549Seric break; 3084549Seric 3094549Seric case CMDDATA: /* data -- text of mail */ 31024943Seric SmtpPhase = "DATA"; 3114976Seric if (!hasmail) 3124549Seric { 3134976Seric message("503", "Need MAIL command"); 3144976Seric break; 3154549Seric } 31655012Seric else if (e->e_nrcpts <= 0) 3174549Seric { 3184976Seric message("503", "Need RCPT (recipient)"); 3194976Seric break; 3204549Seric } 3214976Seric 3224976Seric /* collect the text of the message */ 32324943Seric SmtpPhase = "collect"; 32457389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 32555012Seric collect(TRUE, e); 3264976Seric if (Errors != 0) 3274976Seric break; 3284976Seric 3298238Seric /* 3308238Seric ** Arrange to send to everyone. 3318238Seric ** If sending to multiple people, mail back 3328238Seric ** errors rather than reporting directly. 3338238Seric ** In any case, don't mail back errors for 3348238Seric ** anything that has happened up to 3358238Seric ** now (the other end will do this). 33610197Seric ** Truncate our transcript -- the mail has gotten 33710197Seric ** to us successfully, and if we have 33810197Seric ** to mail this back, it will be easier 33910197Seric ** on the reader. 3408238Seric ** Then send to everyone. 3418238Seric ** Finally give a reply code. If an error has 3428238Seric ** already been given, don't mail a 3438238Seric ** message back. 3449339Seric ** We goose error returns by clearing error bit. 3458238Seric */ 3468238Seric 34724943Seric SmtpPhase = "delivery"; 34855012Seric if (e->e_nrcpts != 1) 3499378Seric { 3509378Seric HoldErrs = TRUE; 35116886Seric ErrorMode = EM_MAIL; 3529378Seric } 35355012Seric e->e_flags &= ~EF_FATALERRS; 35455012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 3554976Seric 3564976Seric /* send to all recipients */ 35755012Seric sendall(e, SM_DEFAULT); 35855012Seric e->e_to = NULL; 3594976Seric 36023516Seric /* save statistics */ 36155012Seric markstats(e, (ADDRESS *) NULL); 36223516Seric 3638238Seric /* issue success if appropriate and reset */ 3648238Seric if (Errors == 0 || HoldErrs) 3659283Seric message("250", "Ok"); 3668238Seric else 36755012Seric e->e_flags &= ~EF_FATALERRS; 3689339Seric 3699339Seric /* if in a child, pop back to our parent */ 3709339Seric if (InChild) 3719339Seric finis(); 37224943Seric 37324943Seric /* clean up a bit */ 37458008Seric hasmail = FALSE; 37555012Seric dropenvelope(e); 37655012Seric CurEnv = e = newenvelope(e); 37755012Seric e->e_flags = BlankEnvelope.e_flags; 3784549Seric break; 3794549Seric 3804549Seric case CMDRSET: /* rset -- reset state */ 3814549Seric message("250", "Reset state"); 3829339Seric if (InChild) 3839339Seric finis(); 3849339Seric break; 3854549Seric 3864549Seric case CMDVRFY: /* vrfy -- verify address */ 387*58082Seric if (bitset(PRIV_NOVRFY|PRIV_NOEXPN, PrivacyFlags)) 388*58082Seric { 389*58082Seric message("502", "That's none of your business"); 390*58082Seric break; 391*58082Seric } 392*58082Seric else if (!gothello && 393*58082Seric bitset(PRIV_NEEDVRFYHELO|PRIV_NEEDEXPNHELO, PrivacyFlags)) 394*58082Seric { 395*58082Seric message("503", "I demand that you introduce yourself first"); 396*58082Seric break; 397*58082Seric } 39855012Seric if (runinchild("SMTP-VRFY", e) > 0) 3999339Seric break; 40025050Seric setproctitle("%s: %s", CurHostName, inp); 40155173Seric #ifdef LOG 40258020Seric if (LogLevel > 5) 40355173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 40455173Seric #endif 4055003Seric vrfyqueue = NULL; 4067762Seric QuickAbort = TRUE; 407*58082Seric (void) sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 4087762Seric if (Errors != 0) 4099339Seric { 4109339Seric if (InChild) 4119339Seric finis(); 4127762Seric break; 4139339Seric } 4145003Seric while (vrfyqueue != NULL) 4155003Seric { 4165003Seric register ADDRESS *a = vrfyqueue->q_next; 4175003Seric char *code; 4185003Seric 4197685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 4205003Seric a = a->q_next; 4215003Seric 4227685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 4235003Seric { 4245003Seric if (a != NULL) 4255003Seric code = "250-"; 4265003Seric else 4275003Seric code = "250"; 42858010Seric if (strchr(vrfyqueue->q_paddr, '<') != NULL) 42958010Seric message(code, "%s", vrfyqueue->q_paddr); 43058010Seric else if (vrfyqueue->q_fullname == NULL) 4315003Seric message(code, "<%s>", vrfyqueue->q_paddr); 4325003Seric else 4335003Seric message(code, "%s <%s>", 4345003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4355003Seric } 4365003Seric else if (a == NULL) 4375003Seric message("554", "Self destructive alias loop"); 4385003Seric vrfyqueue = a; 4395003Seric } 4409339Seric if (InChild) 4419339Seric finis(); 4424549Seric break; 4434549Seric 4444549Seric case CMDHELP: /* help -- give user info */ 4454577Seric help(p); 4464549Seric break; 4474549Seric 4484549Seric case CMDNOOP: /* noop -- do nothing */ 4494549Seric message("200", "OK"); 4504549Seric break; 4514549Seric 4524549Seric case CMDQUIT: /* quit -- leave mail */ 45325050Seric message("221", "%s closing connection", MyHostName); 4549339Seric if (InChild) 4559339Seric ExitStat = EX_QUIT; 4564549Seric finis(); 4574549Seric 4588544Seric case CMDVERB: /* set verbose mode */ 4598544Seric Verbose = TRUE; 46025025Seric SendMode = SM_DELIVER; 4618544Seric message("200", "Verbose mode"); 4628544Seric break; 4638544Seric 4649314Seric case CMDONEX: /* doing one transaction only */ 4659378Seric OneXact = TRUE; 4669314Seric message("200", "Only one transaction"); 4679314Seric break; 4689314Seric 46936230Skarels # ifdef SMTPDEBUG 4709339Seric case CMDDBGQSHOW: /* show queues */ 4716907Seric printf("Send Queue="); 47255012Seric printaddr(e->e_sendqueue, TRUE); 4735003Seric break; 4747275Seric 4757275Seric case CMDDBGDEBUG: /* set debug mode */ 4767676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4777676Seric tTflag(p); 4787676Seric message("200", "Debug set"); 4797275Seric break; 4807275Seric 48136230Skarels # else /* not SMTPDEBUG */ 48224945Seric 48336230Skarels case CMDDBGQSHOW: /* show queues */ 48436230Skarels case CMDDBGDEBUG: /* set debug mode */ 48536233Skarels # ifdef LOG 48636233Skarels if (RealHostName != NULL && LogLevel > 0) 48736230Skarels syslog(LOG_NOTICE, 48858020Seric "\"%s\" command from %s (%s)", 48936230Skarels c->cmdname, RealHostName, 49036230Skarels inet_ntoa(RealHostAddr.sin_addr)); 49136233Skarels # endif 49236230Skarels /* FALL THROUGH */ 49336230Skarels # endif /* SMTPDEBUG */ 49436230Skarels 4954549Seric case CMDERROR: /* unknown command */ 4964549Seric message("500", "Command unrecognized"); 4974549Seric break; 4984549Seric 4994549Seric default: 50036230Skarels errno = 0; 5014549Seric syserr("smtp: unknown code %d", c->cmdcode); 5024549Seric break; 5034549Seric } 5044549Seric } 5054549Seric } 5064549Seric /* 5074549Seric ** SKIPWORD -- skip a fixed word. 5084549Seric ** 5094549Seric ** Parameters: 5104549Seric ** p -- place to start looking. 5114549Seric ** w -- word to skip. 5124549Seric ** 5134549Seric ** Returns: 5144549Seric ** p following w. 5154549Seric ** NULL on error. 5164549Seric ** 5174549Seric ** Side Effects: 5184549Seric ** clobbers the p data area. 5194549Seric */ 5204549Seric 5214549Seric static char * 5224549Seric skipword(p, w) 5234549Seric register char *p; 5244549Seric char *w; 5254549Seric { 5264549Seric register char *q; 5274549Seric 5284549Seric /* find beginning of word */ 52958050Seric while (isascii(*p) && isspace(*p)) 5304549Seric p++; 5314549Seric q = p; 5324549Seric 5334549Seric /* find end of word */ 53458050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 5354549Seric p++; 53658050Seric while (isascii(*p) && isspace(*p)) 5374549Seric *p++ = '\0'; 5384549Seric if (*p != ':') 5394549Seric { 5404549Seric syntax: 5414549Seric message("501", "Syntax error"); 5424549Seric Errors++; 5434549Seric return (NULL); 5444549Seric } 5454549Seric *p++ = '\0'; 54658050Seric while (isascii(*p) && isspace(*p)) 5474549Seric p++; 5484549Seric 5494549Seric /* see if the input word matches desired word */ 55033725Sbostic if (strcasecmp(q, w)) 5514549Seric goto syntax; 5524549Seric 5534549Seric return (p); 5544549Seric } 5554577Seric /* 5564577Seric ** HELP -- implement the HELP command. 5574577Seric ** 5584577Seric ** Parameters: 5594577Seric ** topic -- the topic we want help for. 5604577Seric ** 5614577Seric ** Returns: 5624577Seric ** none. 5634577Seric ** 5644577Seric ** Side Effects: 5654577Seric ** outputs the help file to message output. 5664577Seric */ 5674577Seric 5684577Seric help(topic) 5694577Seric char *topic; 5704577Seric { 5714577Seric register FILE *hf; 5724577Seric int len; 5734577Seric char buf[MAXLINE]; 5744577Seric bool noinfo; 5754577Seric 5768269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5774577Seric { 5784577Seric /* no help */ 57911931Seric errno = 0; 5804577Seric message("502", "HELP not implemented"); 5814577Seric return; 5824577Seric } 5834577Seric 58449669Seric if (topic == NULL || *topic == '\0') 58549669Seric topic = "smtp"; 58649669Seric else 58749669Seric makelower(topic); 58849669Seric 5894577Seric len = strlen(topic); 5904577Seric noinfo = TRUE; 5914577Seric 5924577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5934577Seric { 5944577Seric if (strncmp(buf, topic, len) == 0) 5954577Seric { 5964577Seric register char *p; 5974577Seric 59856795Seric p = strchr(buf, '\t'); 5994577Seric if (p == NULL) 6004577Seric p = buf; 6014577Seric else 6024577Seric p++; 6034577Seric fixcrlf(p, TRUE); 6044577Seric message("214-", p); 6054577Seric noinfo = FALSE; 6064577Seric } 6074577Seric } 6084577Seric 6094577Seric if (noinfo) 6104577Seric message("504", "HELP topic unknown"); 6114577Seric else 6124577Seric message("214", "End of HELP info"); 6134628Seric (void) fclose(hf); 6144577Seric } 6158544Seric /* 6169339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6179339Seric ** 6189339Seric ** Parameters: 6199339Seric ** label -- a string used in error messages 6209339Seric ** 6219339Seric ** Returns: 6229339Seric ** zero in the child 6239339Seric ** one in the parent 6249339Seric ** 6259339Seric ** Side Effects: 6269339Seric ** none. 6279339Seric */ 6288544Seric 62955012Seric runinchild(label, e) 6309339Seric char *label; 63155012Seric register ENVELOPE *e; 6329339Seric { 6339339Seric int childpid; 6349339Seric 63516158Seric if (!OneXact) 6369339Seric { 63716158Seric childpid = dofork(); 63816158Seric if (childpid < 0) 63916158Seric { 64016158Seric syserr("%s: cannot fork", label); 64116158Seric return (1); 64216158Seric } 64316158Seric if (childpid > 0) 64416158Seric { 64516158Seric auto int st; 6469339Seric 64716158Seric /* parent -- wait for child to complete */ 64816158Seric st = waitfor(childpid); 64916158Seric if (st == -1) 65016158Seric syserr("%s: lost child", label); 6519339Seric 65216158Seric /* if we exited on a QUIT command, complete the process */ 65316158Seric if (st == (EX_QUIT << 8)) 65416158Seric finis(); 6559339Seric 65616158Seric return (1); 65716158Seric } 65816158Seric else 65916158Seric { 66016158Seric /* child */ 66116158Seric InChild = TRUE; 66225050Seric QuickAbort = FALSE; 66355012Seric clearenvelope(e, FALSE); 66416158Seric } 6659339Seric } 66615256Seric 66716158Seric /* open alias database */ 66855012Seric initaliases(AliasFile, FALSE, e); 66916158Seric 67016158Seric return (0); 6719339Seric } 6729339Seric 67356795Seric # endif /* SMTP */ 674