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*24971Seric static char SccsId[] = "@(#)srvrsmtp.c 5.11 (Berkeley) 09/20/85 (no SMTP)"; 1923122Seric # endif not lint 205181Seric # else SMTP 214556Seric 2223122Seric # ifndef lint 23*24971Seric static char SccsId[] = "@(#)srvrsmtp.c 5.11 (Berkeley) 09/20/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; 10824969Seric char state[100]; 1098544Seric char inp[MAXLINE]; 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(); 127*24971Seric if (RealHostName != NULL) 128*24971Seric { 129*24971Seric static char status[100]; 130*24971Seric 131*24971Seric (void) sprintf(status, "talking to %s", RealHostName); 132*24971Seric setproctitle(status); 133*24971Seric } 13416153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 13510708Seric message("220", inp); 13624943Seric SmtpPhase = "startup"; 1374549Seric for (;;) 1384549Seric { 13912612Seric /* arrange for backout */ 14012612Seric if (setjmp(TopFrame) > 0 && InChild) 14112612Seric finis(); 14212612Seric QuickAbort = FALSE; 14312612Seric HoldErrs = FALSE; 14412612Seric 1457356Seric /* setup for the read */ 1466907Seric CurEnv->e_to = NULL; 1474577Seric Errors = 0; 1487275Seric (void) fflush(stdout); 1497356Seric 1507356Seric /* read the input line */ 1517685Seric p = sfgets(inp, sizeof inp, InChannel); 1527356Seric 1537685Seric /* handle errors */ 1547356Seric if (p == NULL) 1557356Seric { 1564549Seric /* end of file, just die */ 1574558Seric message("421", "%s Lost input channel", HostName); 1584549Seric finis(); 1594549Seric } 1604549Seric 1614549Seric /* clean up end of line */ 1624558Seric fixcrlf(inp, TRUE); 1634549Seric 1644713Seric /* echo command to transcript */ 1659545Seric if (CurEnv->e_xfp != NULL) 1669545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1674713Seric 1684549Seric /* break off command */ 1694549Seric for (p = inp; isspace(*p); p++) 1704549Seric continue; 1714549Seric cmd = p; 1724549Seric while (*++p != '\0' && !isspace(*p)) 1734549Seric continue; 1744549Seric if (*p != '\0') 1754549Seric *p++ = '\0'; 1764549Seric 1774549Seric /* decode command */ 1784549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1794549Seric { 1804549Seric if (sameword(c->cmdname, cmd)) 1814549Seric break; 1824549Seric } 1834549Seric 1844549Seric /* process command */ 1854549Seric switch (c->cmdcode) 1864549Seric { 1874976Seric case CMDHELO: /* hello -- introduce yourself */ 18824943Seric SmtpPhase = "HELO"; 18914877Seric if (sameword(p, HostName)) 19014877Seric { 19114877Seric /* connected to an echo server */ 19214877Seric message("553", "%s I refuse to talk to myself", 19314877Seric HostName); 19414877Seric break; 19514877Seric } 19611146Seric if (RealHostName != NULL && !sameword(p, RealHostName)) 19711146Seric { 19811146Seric char buf[MAXNAME]; 19911146Seric 20011146Seric (void) sprintf(buf, "%s (%s)", p, RealHostName); 20111146Seric define('s', newstr(buf), CurEnv); 20211146Seric } 20311146Seric else 20411146Seric define('s', newstr(p), CurEnv); 2054997Seric message("250", "%s Hello %s, pleased to meet you", 2064997Seric HostName, p); 2074976Seric break; 2084976Seric 2094549Seric case CMDMAIL: /* mail -- designate sender */ 21024943Seric SmtpPhase = "MAIL"; 21124943Seric 21211151Seric /* force a sending host even if no HELO given */ 21311151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 21411151Seric define('s', RealHostName, CurEnv); 21511151Seric 2169314Seric /* check for validity of this command */ 2174558Seric if (hasmail) 2184558Seric { 2194558Seric message("503", "Sender already specified"); 2204558Seric break; 2214558Seric } 2229339Seric if (InChild) 2239339Seric { 2249339Seric syserr("Nested MAIL command"); 2259339Seric exit(0); 2269339Seric } 2279339Seric 2289339Seric /* fork a subprocess to process this command */ 2299339Seric if (runinchild("SMTP-MAIL") > 0) 2309339Seric break; 2319339Seric initsys(); 23224969Seric (void) sprintf(state, "srvrsmtp %s", CurEnv->e_id); 23324969Seric setproctitle(state); 2349339Seric 2359339Seric /* child -- go do the processing */ 2364549Seric p = skipword(p, "from"); 2374549Seric if (p == NULL) 2384549Seric break; 2394549Seric setsender(p); 2404577Seric if (Errors == 0) 2414549Seric { 2424549Seric message("250", "Sender ok"); 2434549Seric hasmail = TRUE; 2444549Seric } 2459339Seric else if (InChild) 2469339Seric finis(); 2474549Seric break; 2484549Seric 2494976Seric case CMDRCPT: /* rcpt -- designate recipient */ 25024943Seric SmtpPhase = "RCPT"; 25112612Seric if (setjmp(TopFrame) > 0) 25214785Seric { 25314785Seric CurEnv->e_flags &= ~EF_FATALERRS; 25412612Seric break; 25514785Seric } 25612612Seric QuickAbort = TRUE; 2574549Seric p = skipword(p, "to"); 2584549Seric if (p == NULL) 2594549Seric break; 26016140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 26112612Seric if (a == NULL) 26212612Seric break; 26316886Seric a->q_flags |= QPRIMARY; 26412612Seric a = recipient(a, &CurEnv->e_sendqueue); 26512612Seric if (Errors != 0) 26612612Seric break; 26712612Seric 26812612Seric /* no errors during parsing, but might be a duplicate */ 26912612Seric CurEnv->e_to = p; 27012612Seric if (!bitset(QBADADDR, a->q_flags)) 27112612Seric message("250", "Recipient ok"); 27212612Seric else 2734549Seric { 27412612Seric /* punt -- should keep message in ADDRESS.... */ 27512612Seric message("550", "Addressee unknown"); 2764549Seric } 27712612Seric CurEnv->e_to = NULL; 2784549Seric break; 2794549Seric 2804549Seric case CMDDATA: /* data -- text of mail */ 28124943Seric SmtpPhase = "DATA"; 2824976Seric if (!hasmail) 2834549Seric { 2844976Seric message("503", "Need MAIL command"); 2854976Seric break; 2864549Seric } 28724943Seric else if (CurEnv->e_nrcpts <= 0) 2884549Seric { 2894976Seric message("503", "Need RCPT (recipient)"); 2904976Seric break; 2914549Seric } 2924976Seric 2934976Seric /* collect the text of the message */ 29424943Seric SmtpPhase = "collect"; 2954976Seric collect(TRUE); 2964976Seric if (Errors != 0) 2974976Seric break; 2984976Seric 2998238Seric /* 3008238Seric ** Arrange to send to everyone. 3018238Seric ** If sending to multiple people, mail back 3028238Seric ** errors rather than reporting directly. 3038238Seric ** In any case, don't mail back errors for 3048238Seric ** anything that has happened up to 3058238Seric ** now (the other end will do this). 30610197Seric ** Truncate our transcript -- the mail has gotten 30710197Seric ** to us successfully, and if we have 30810197Seric ** to mail this back, it will be easier 30910197Seric ** on the reader. 3108238Seric ** Then send to everyone. 3118238Seric ** Finally give a reply code. If an error has 3128238Seric ** already been given, don't mail a 3138238Seric ** message back. 3149339Seric ** We goose error returns by clearing error bit. 3158238Seric */ 3168238Seric 31724943Seric SmtpPhase = "delivery"; 31824943Seric if (CurEnv->e_nrcpts != 1) 3199378Seric { 3209378Seric HoldErrs = TRUE; 32116886Seric ErrorMode = EM_MAIL; 3229378Seric } 3239339Seric CurEnv->e_flags &= ~EF_FATALERRS; 32410197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3254976Seric 3264976Seric /* send to all recipients */ 32714877Seric sendall(CurEnv, SM_DEFAULT); 3286907Seric CurEnv->e_to = NULL; 3294976Seric 33023516Seric /* save statistics */ 33123516Seric markstats(CurEnv, (ADDRESS *) NULL); 33223516Seric 3338238Seric /* issue success if appropriate and reset */ 3348238Seric if (Errors == 0 || HoldErrs) 3359283Seric message("250", "Ok"); 3368238Seric else 3379339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3389339Seric 3399339Seric /* if in a child, pop back to our parent */ 3409339Seric if (InChild) 3419339Seric finis(); 34224943Seric 34324943Seric /* clean up a bit */ 34424943Seric hasmail = 0; 34524943Seric dropenvelope(CurEnv); 34624943Seric CurEnv = newenvelope(CurEnv); 34724943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3484549Seric break; 3494549Seric 3504549Seric case CMDRSET: /* rset -- reset state */ 3514549Seric message("250", "Reset state"); 3529339Seric if (InChild) 3539339Seric finis(); 3549339Seric break; 3554549Seric 3564549Seric case CMDVRFY: /* vrfy -- verify address */ 3579339Seric if (runinchild("SMTP-VRFY") > 0) 3589339Seric break; 35924969Seric setproctitle("SMTP-VRFY"); 3605003Seric vrfyqueue = NULL; 3617762Seric QuickAbort = TRUE; 3629619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3637762Seric if (Errors != 0) 3649339Seric { 3659339Seric if (InChild) 3669339Seric finis(); 3677762Seric break; 3689339Seric } 3695003Seric while (vrfyqueue != NULL) 3705003Seric { 3715003Seric register ADDRESS *a = vrfyqueue->q_next; 3725003Seric char *code; 3735003Seric 3747685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3755003Seric a = a->q_next; 3765003Seric 3777685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3785003Seric { 3795003Seric if (a != NULL) 3805003Seric code = "250-"; 3815003Seric else 3825003Seric code = "250"; 3835003Seric if (vrfyqueue->q_fullname == NULL) 3845003Seric message(code, "<%s>", vrfyqueue->q_paddr); 3855003Seric else 3865003Seric message(code, "%s <%s>", 3875003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 3885003Seric } 3895003Seric else if (a == NULL) 3905003Seric message("554", "Self destructive alias loop"); 3915003Seric vrfyqueue = a; 3925003Seric } 3939339Seric if (InChild) 3949339Seric finis(); 3954549Seric break; 3964549Seric 3974549Seric case CMDHELP: /* help -- give user info */ 3984577Seric if (*p == '\0') 3994577Seric p = "SMTP"; 4004577Seric help(p); 4014549Seric break; 4024549Seric 4034549Seric case CMDNOOP: /* noop -- do nothing */ 4044549Seric message("200", "OK"); 4054549Seric break; 4064549Seric 4074549Seric case CMDQUIT: /* quit -- leave mail */ 4084549Seric message("221", "%s closing connection", HostName); 4099339Seric if (InChild) 4109339Seric ExitStat = EX_QUIT; 4114549Seric finis(); 4124549Seric 4138544Seric case CMDVERB: /* set verbose mode */ 4148544Seric Verbose = TRUE; 4158544Seric message("200", "Verbose mode"); 4168544Seric break; 4178544Seric 4189314Seric case CMDONEX: /* doing one transaction only */ 4199378Seric OneXact = TRUE; 4209314Seric message("200", "Only one transaction"); 4219314Seric break; 4229314Seric 4235003Seric # ifdef DEBUG 4249339Seric case CMDDBGQSHOW: /* show queues */ 4256907Seric printf("Send Queue="); 4266907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4275003Seric break; 4287275Seric 4297275Seric case CMDDBGDEBUG: /* set debug mode */ 4307676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4317676Seric tTflag(p); 4327676Seric message("200", "Debug set"); 4337275Seric break; 43424945Seric # endif DEBUG 4357275Seric 43624945Seric # ifdef WIZ 4377282Seric case CMDDBGKILL: /* kill the parent */ 4388544Seric if (!iswiz()) 4398544Seric break; 4407282Seric if (kill(MotherPid, SIGTERM) >= 0) 4417282Seric message("200", "Mother is dead"); 4427282Seric else 4437282Seric message("500", "Can't kill Mom"); 4447282Seric break; 4458544Seric 4468544Seric case CMDDBGWIZ: /* become a wizard */ 4478544Seric if (WizWord != NULL) 4488544Seric { 4498544Seric char seed[3]; 4508544Seric extern char *crypt(); 4518544Seric 45223106Seric (void) strncpy(seed, WizWord, 2); 45315596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4548544Seric { 45515596Seric IsWiz = TRUE; 45615596Seric message("200", "Please pass, oh mighty wizard"); 4578544Seric break; 4588544Seric } 4598544Seric } 46015596Seric message("500", "You are no wizard!"); 4618544Seric break; 4625003Seric 46324945Seric # else WIZ 46424945Seric case CMDDBGWIZ: /* try to become a wizard */ 46524945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 46624945Seric break; 46724945Seric # endif WIZ 46824945Seric 4694549Seric case CMDERROR: /* unknown command */ 4704549Seric message("500", "Command unrecognized"); 4714549Seric break; 4724549Seric 4734549Seric default: 4744549Seric syserr("smtp: unknown code %d", c->cmdcode); 4754549Seric break; 4764549Seric } 4774549Seric } 4784549Seric } 4794549Seric /* 4804549Seric ** SKIPWORD -- skip a fixed word. 4814549Seric ** 4824549Seric ** Parameters: 4834549Seric ** p -- place to start looking. 4844549Seric ** w -- word to skip. 4854549Seric ** 4864549Seric ** Returns: 4874549Seric ** p following w. 4884549Seric ** NULL on error. 4894549Seric ** 4904549Seric ** Side Effects: 4914549Seric ** clobbers the p data area. 4924549Seric */ 4934549Seric 4944549Seric static char * 4954549Seric skipword(p, w) 4964549Seric register char *p; 4974549Seric char *w; 4984549Seric { 4994549Seric register char *q; 5004549Seric extern bool sameword(); 5014549Seric 5024549Seric /* find beginning of word */ 5034549Seric while (isspace(*p)) 5044549Seric p++; 5054549Seric q = p; 5064549Seric 5074549Seric /* find end of word */ 5084549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5094549Seric p++; 5104549Seric while (isspace(*p)) 5114549Seric *p++ = '\0'; 5124549Seric if (*p != ':') 5134549Seric { 5144549Seric syntax: 5154549Seric message("501", "Syntax error"); 5164549Seric Errors++; 5174549Seric return (NULL); 5184549Seric } 5194549Seric *p++ = '\0'; 5204549Seric while (isspace(*p)) 5214549Seric p++; 5224549Seric 5234549Seric /* see if the input word matches desired word */ 5244549Seric if (!sameword(q, w)) 5254549Seric goto syntax; 5264549Seric 5274549Seric return (p); 5284549Seric } 5294577Seric /* 5304577Seric ** HELP -- implement the HELP command. 5314577Seric ** 5324577Seric ** Parameters: 5334577Seric ** topic -- the topic we want help for. 5344577Seric ** 5354577Seric ** Returns: 5364577Seric ** none. 5374577Seric ** 5384577Seric ** Side Effects: 5394577Seric ** outputs the help file to message output. 5404577Seric */ 5414577Seric 5424577Seric help(topic) 5434577Seric char *topic; 5444577Seric { 5454577Seric register FILE *hf; 5464577Seric int len; 5474577Seric char buf[MAXLINE]; 5484577Seric bool noinfo; 5494577Seric 5508269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5514577Seric { 5524577Seric /* no help */ 55311931Seric errno = 0; 5544577Seric message("502", "HELP not implemented"); 5554577Seric return; 5564577Seric } 5574577Seric 5584577Seric len = strlen(topic); 5594577Seric makelower(topic); 5604577Seric noinfo = TRUE; 5614577Seric 5624577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5634577Seric { 5644577Seric if (strncmp(buf, topic, len) == 0) 5654577Seric { 5664577Seric register char *p; 5674577Seric 5684577Seric p = index(buf, '\t'); 5694577Seric if (p == NULL) 5704577Seric p = buf; 5714577Seric else 5724577Seric p++; 5734577Seric fixcrlf(p, TRUE); 5744577Seric message("214-", p); 5754577Seric noinfo = FALSE; 5764577Seric } 5774577Seric } 5784577Seric 5794577Seric if (noinfo) 5804577Seric message("504", "HELP topic unknown"); 5814577Seric else 5824577Seric message("214", "End of HELP info"); 5834628Seric (void) fclose(hf); 5844577Seric } 5858544Seric /* 5868544Seric ** ISWIZ -- tell us if we are a wizard 5878544Seric ** 5888544Seric ** If not, print a nasty message. 5898544Seric ** 5908544Seric ** Parameters: 5918544Seric ** none. 5928544Seric ** 5938544Seric ** Returns: 5948544Seric ** TRUE if we are a wizard. 5958544Seric ** FALSE if we are not a wizard. 5968544Seric ** 5978544Seric ** Side Effects: 5988544Seric ** Prints a 500 exit stat if we are not a wizard. 5998544Seric */ 6005181Seric 60124945Seric #ifdef WIZ 60219038Seric 6038544Seric bool 6048544Seric iswiz() 6058544Seric { 6068544Seric if (!IsWiz) 6078544Seric message("500", "Mere mortals musn't mutter that mantra"); 6088544Seric return (IsWiz); 6098544Seric } 61019038Seric 61124945Seric #endif WIZ 6129339Seric /* 6139339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6149339Seric ** 6159339Seric ** Parameters: 6169339Seric ** label -- a string used in error messages 6179339Seric ** 6189339Seric ** Returns: 6199339Seric ** zero in the child 6209339Seric ** one in the parent 6219339Seric ** 6229339Seric ** Side Effects: 6239339Seric ** none. 6249339Seric */ 6258544Seric 6269339Seric runinchild(label) 6279339Seric char *label; 6289339Seric { 6299339Seric int childpid; 6309339Seric 63116158Seric if (!OneXact) 6329339Seric { 63316158Seric childpid = dofork(); 63416158Seric if (childpid < 0) 63516158Seric { 63616158Seric syserr("%s: cannot fork", label); 63716158Seric return (1); 63816158Seric } 63916158Seric if (childpid > 0) 64016158Seric { 64116158Seric auto int st; 6429339Seric 64316158Seric /* parent -- wait for child to complete */ 64416158Seric st = waitfor(childpid); 64516158Seric if (st == -1) 64616158Seric syserr("%s: lost child", label); 6479339Seric 64816158Seric /* if we exited on a QUIT command, complete the process */ 64916158Seric if (st == (EX_QUIT << 8)) 65016158Seric finis(); 6519339Seric 65216158Seric return (1); 65316158Seric } 65416158Seric else 65516158Seric { 65616158Seric /* child */ 65716158Seric InChild = TRUE; 65824945Seric clearenvelope(CurEnv); 65916158Seric } 6609339Seric } 66115256Seric 66216158Seric /* open alias database */ 66316158Seric initaliases(AliasFile, FALSE); 66416158Seric 66516158Seric return (0); 6669339Seric } 6679339Seric 6685181Seric # endif SMTP 669