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*58064Seric static char sccsid[] = "@(#)srvrsmtp.c 6.9 (Berkeley) 02/19/93 (with SMTP)"; 1433731Sbostic #else 15*58064Seric static char sccsid[] = "@(#)srvrsmtp.c 6.9 (Berkeley) 02/19/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; 1008544Seric char inp[MAXLINE]; 10157232Seric char cmdbuf[MAXLINE]; 1027124Seric extern char Version[]; 10311151Seric extern char *macvalue(); 10412612Seric extern ADDRESS *recipient(); 10524943Seric extern ENVELOPE BlankEnvelope; 10624943Seric extern ENVELOPE *newenvelope(); 1074549Seric 1085003Seric hasmail = FALSE; 1097363Seric if (OutChannel != stdout) 1107363Seric { 1117363Seric /* arrange for debugging output to go to remote host */ 1127363Seric (void) close(1); 1137363Seric (void) dup(fileno(OutChannel)); 1147363Seric } 11555012Seric settime(e); 11657642Seric if (RealHostName == NULL) 11757642Seric RealHostName = MyHostName; 11857642Seric CurHostName = RealHostName; 11957642Seric setproctitle("srvrsmtp %s", CurHostName); 12058050Seric expand("\201e", inp, &inp[sizeof inp], e); 12155360Seric message("220", "%s", inp); 12224943Seric SmtpPhase = "startup"; 12330448Seric sendinghost = NULL; 1244549Seric for (;;) 1254549Seric { 12612612Seric /* arrange for backout */ 12712612Seric if (setjmp(TopFrame) > 0 && InChild) 12812612Seric finis(); 12912612Seric QuickAbort = FALSE; 13012612Seric HoldErrs = FALSE; 13151951Seric LogUsrErrs = FALSE; 13212612Seric 1337356Seric /* setup for the read */ 13455012Seric e->e_to = NULL; 1354577Seric Errors = 0; 1367275Seric (void) fflush(stdout); 1377356Seric 1387356Seric /* read the input line */ 13957389Seric p = sfgets(inp, sizeof inp, InChannel, ReadTimeout); 1407356Seric 1417685Seric /* handle errors */ 1427356Seric if (p == NULL) 1437356Seric { 1444549Seric /* end of file, just die */ 14536230Skarels message("421", "%s Lost input channel from %s", 14625050Seric MyHostName, CurHostName); 14755464Seric #ifdef LOG 14858020Seric if (LogLevel > 1) 14955464Seric syslog(LOG_NOTICE, "lost input channel from %s", 15055464Seric CurHostName); 15155464Seric #endif 1524549Seric finis(); 1534549Seric } 1544549Seric 1554549Seric /* clean up end of line */ 1564558Seric fixcrlf(inp, TRUE); 1574549Seric 1584713Seric /* echo command to transcript */ 15955012Seric if (e->e_xfp != NULL) 16055012Seric fprintf(e->e_xfp, "<<< %s\n", inp); 1614713Seric 1624549Seric /* break off command */ 16358050Seric for (p = inp; isascii(*p) && isspace(*p); p++) 1644549Seric continue; 16557232Seric cmd = cmdbuf; 16658050Seric while (*p != '\0' && 16758050Seric !(isascii(*p) && isspace(*p)) && 16858050Seric cmd < &cmdbuf[sizeof cmdbuf - 2]) 16924981Seric *cmd++ = *p++; 17024981Seric *cmd = '\0'; 1714549Seric 17225691Seric /* throw away leading whitespace */ 17358050Seric while (isascii(*p) && isspace(*p)) 17425691Seric p++; 17525691Seric 1764549Seric /* decode command */ 1774549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1784549Seric { 17933725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1804549Seric break; 1814549Seric } 1824549Seric 18351954Seric /* reset errors */ 18451954Seric errno = 0; 18551954Seric 1864549Seric /* process command */ 1874549Seric switch (c->cmdcode) 1884549Seric { 1894976Seric case CMDHELO: /* hello -- introduce yourself */ 19024943Seric SmtpPhase = "HELO"; 19125050Seric setproctitle("%s: %s", CurHostName, inp); 19233725Sbostic if (!strcasecmp(p, MyHostName)) 19314877Seric { 19436230Skarels /* 19536230Skarels * didn't know about alias, 19636230Skarels * or connected to an echo server 19736230Skarels */ 19847570Seric message("553", "%s config error: mail loops back to myself", 19947570Seric MyHostName); 20014877Seric break; 20114877Seric } 20233725Sbostic if (RealHostName != NULL && strcasecmp(p, RealHostName)) 20311146Seric { 20424981Seric char hostbuf[MAXNAME]; 20511146Seric 20624981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 20730448Seric sendinghost = newstr(hostbuf); 20811146Seric } 20911146Seric else 21030448Seric sendinghost = newstr(p); 2114997Seric message("250", "%s Hello %s, pleased to meet you", 21236230Skarels MyHostName, sendinghost); 2134976Seric break; 2144976Seric 2154549Seric case CMDMAIL: /* mail -- designate sender */ 21624943Seric SmtpPhase = "MAIL"; 21724943Seric 21811151Seric /* force a sending host even if no HELO given */ 219*58064Seric if (sendinghost == NULL && macvalue('s', e) == NULL) 22030448Seric sendinghost = RealHostName; 22111151Seric 2229314Seric /* check for validity of this command */ 2234558Seric if (hasmail) 2244558Seric { 2254558Seric message("503", "Sender already specified"); 2264558Seric break; 2274558Seric } 2289339Seric if (InChild) 2299339Seric { 23036230Skarels errno = 0; 23158008Seric syserr("Nested MAIL command: MAIL %s", p); 2329339Seric exit(0); 2339339Seric } 2349339Seric 2359339Seric /* fork a subprocess to process this command */ 23655012Seric if (runinchild("SMTP-MAIL", e) > 0) 2379339Seric break; 238*58064Seric if (sendinghost != NULL) 239*58064Seric define('s', sendinghost, e); 24055012Seric define('r', "SMTP", e); 24155012Seric initsys(e); 24257389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 2439339Seric 2449339Seric /* child -- go do the processing */ 2454549Seric p = skipword(p, "from"); 2464549Seric if (p == NULL) 2474549Seric break; 24857977Seric if (setjmp(TopFrame) > 0) 24957977Seric break; 25057977Seric QuickAbort = TRUE; 25155012Seric setsender(p, e); 2524577Seric if (Errors == 0) 2534549Seric { 2544549Seric message("250", "Sender ok"); 2554549Seric hasmail = TRUE; 2564549Seric } 2579339Seric else if (InChild) 2589339Seric finis(); 2594549Seric break; 2604549Seric 2614976Seric case CMDRCPT: /* rcpt -- designate recipient */ 26224943Seric SmtpPhase = "RCPT"; 26357389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 26412612Seric if (setjmp(TopFrame) > 0) 26514785Seric { 26655012Seric e->e_flags &= ~EF_FATALERRS; 26712612Seric break; 26814785Seric } 26912612Seric QuickAbort = TRUE; 27051951Seric LogUsrErrs = TRUE; 2714549Seric p = skipword(p, "to"); 2724549Seric if (p == NULL) 2734549Seric break; 27455012Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0', e); 27512612Seric if (a == NULL) 27612612Seric break; 27716886Seric a->q_flags |= QPRIMARY; 27855012Seric a = recipient(a, &e->e_sendqueue, e); 27912612Seric if (Errors != 0) 28012612Seric break; 28112612Seric 28212612Seric /* no errors during parsing, but might be a duplicate */ 28355012Seric e->e_to = p; 28412612Seric if (!bitset(QBADADDR, a->q_flags)) 28512612Seric message("250", "Recipient ok"); 28612612Seric else 2874549Seric { 28812612Seric /* punt -- should keep message in ADDRESS.... */ 28912612Seric message("550", "Addressee unknown"); 2904549Seric } 29155012Seric e->e_to = NULL; 2924549Seric break; 2934549Seric 2944549Seric case CMDDATA: /* data -- text of mail */ 29524943Seric SmtpPhase = "DATA"; 2964976Seric if (!hasmail) 2974549Seric { 2984976Seric message("503", "Need MAIL command"); 2994976Seric break; 3004549Seric } 30155012Seric else if (e->e_nrcpts <= 0) 3024549Seric { 3034976Seric message("503", "Need RCPT (recipient)"); 3044976Seric break; 3054549Seric } 3064976Seric 3074976Seric /* collect the text of the message */ 30824943Seric SmtpPhase = "collect"; 30957389Seric setproctitle("%s %s: %s", e->e_id, CurHostName, inp); 31055012Seric collect(TRUE, e); 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"; 33355012Seric if (e->e_nrcpts != 1) 3349378Seric { 3359378Seric HoldErrs = TRUE; 33616886Seric ErrorMode = EM_MAIL; 3379378Seric } 33855012Seric e->e_flags &= ~EF_FATALERRS; 33955012Seric e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); 3404976Seric 3414976Seric /* send to all recipients */ 34255012Seric sendall(e, SM_DEFAULT); 34355012Seric e->e_to = NULL; 3444976Seric 34523516Seric /* save statistics */ 34655012Seric markstats(e, (ADDRESS *) NULL); 34723516Seric 3488238Seric /* issue success if appropriate and reset */ 3498238Seric if (Errors == 0 || HoldErrs) 3509283Seric message("250", "Ok"); 3518238Seric else 35255012Seric e->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 */ 35958008Seric hasmail = FALSE; 36055012Seric dropenvelope(e); 36155012Seric CurEnv = e = newenvelope(e); 36255012Seric e->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 */ 37255012Seric if (runinchild("SMTP-VRFY", e) > 0) 3739339Seric break; 37425050Seric setproctitle("%s: %s", CurHostName, inp); 37555173Seric #ifdef LOG 37658020Seric if (LogLevel > 5) 37755173Seric syslog(LOG_INFO, "%s: %s", CurHostName, inp); 37855173Seric #endif 3795003Seric vrfyqueue = NULL; 3807762Seric QuickAbort = TRUE; 38155012Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e); 3827762Seric if (Errors != 0) 3839339Seric { 3849339Seric if (InChild) 3859339Seric finis(); 3867762Seric break; 3879339Seric } 3885003Seric while (vrfyqueue != NULL) 3895003Seric { 3905003Seric register ADDRESS *a = vrfyqueue->q_next; 3915003Seric char *code; 3925003Seric 3937685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3945003Seric a = a->q_next; 3955003Seric 3967685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3975003Seric { 3985003Seric if (a != NULL) 3995003Seric code = "250-"; 4005003Seric else 4015003Seric code = "250"; 40258010Seric if (strchr(vrfyqueue->q_paddr, '<') != NULL) 40358010Seric message(code, "%s", vrfyqueue->q_paddr); 40458010Seric else if (vrfyqueue->q_fullname == NULL) 4055003Seric message(code, "<%s>", vrfyqueue->q_paddr); 4065003Seric else 4075003Seric message(code, "%s <%s>", 4085003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4095003Seric } 4105003Seric else if (a == NULL) 4115003Seric message("554", "Self destructive alias loop"); 4125003Seric vrfyqueue = a; 4135003Seric } 4149339Seric if (InChild) 4159339Seric finis(); 4164549Seric break; 4174549Seric 4184549Seric case CMDHELP: /* help -- give user info */ 4194577Seric help(p); 4204549Seric break; 4214549Seric 4224549Seric case CMDNOOP: /* noop -- do nothing */ 4234549Seric message("200", "OK"); 4244549Seric break; 4254549Seric 4264549Seric case CMDQUIT: /* quit -- leave mail */ 42725050Seric message("221", "%s closing connection", MyHostName); 4289339Seric if (InChild) 4299339Seric ExitStat = EX_QUIT; 4304549Seric finis(); 4314549Seric 4328544Seric case CMDVERB: /* set verbose mode */ 4338544Seric Verbose = TRUE; 43425025Seric SendMode = SM_DELIVER; 4358544Seric message("200", "Verbose mode"); 4368544Seric break; 4378544Seric 4389314Seric case CMDONEX: /* doing one transaction only */ 4399378Seric OneXact = TRUE; 4409314Seric message("200", "Only one transaction"); 4419314Seric break; 4429314Seric 44336230Skarels # ifdef SMTPDEBUG 4449339Seric case CMDDBGQSHOW: /* show queues */ 4456907Seric printf("Send Queue="); 44655012Seric printaddr(e->e_sendqueue, TRUE); 4475003Seric break; 4487275Seric 4497275Seric case CMDDBGDEBUG: /* set debug mode */ 4507676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4517676Seric tTflag(p); 4527676Seric message("200", "Debug set"); 4537275Seric break; 4547275Seric 45536230Skarels # else /* not SMTPDEBUG */ 45624945Seric 45736230Skarels case CMDDBGQSHOW: /* show queues */ 45836230Skarels case CMDDBGDEBUG: /* set debug mode */ 45936233Skarels # ifdef LOG 46036233Skarels if (RealHostName != NULL && LogLevel > 0) 46136230Skarels syslog(LOG_NOTICE, 46258020Seric "\"%s\" command from %s (%s)", 46336230Skarels c->cmdname, RealHostName, 46436230Skarels inet_ntoa(RealHostAddr.sin_addr)); 46536233Skarels # endif 46636230Skarels /* FALL THROUGH */ 46736230Skarels # endif /* SMTPDEBUG */ 46836230Skarels 4694549Seric case CMDERROR: /* unknown command */ 4704549Seric message("500", "Command unrecognized"); 4714549Seric break; 4724549Seric 4734549Seric default: 47436230Skarels errno = 0; 4754549Seric syserr("smtp: unknown code %d", c->cmdcode); 4764549Seric break; 4774549Seric } 4784549Seric } 4794549Seric } 4804549Seric /* 4814549Seric ** SKIPWORD -- skip a fixed word. 4824549Seric ** 4834549Seric ** Parameters: 4844549Seric ** p -- place to start looking. 4854549Seric ** w -- word to skip. 4864549Seric ** 4874549Seric ** Returns: 4884549Seric ** p following w. 4894549Seric ** NULL on error. 4904549Seric ** 4914549Seric ** Side Effects: 4924549Seric ** clobbers the p data area. 4934549Seric */ 4944549Seric 4954549Seric static char * 4964549Seric skipword(p, w) 4974549Seric register char *p; 4984549Seric char *w; 4994549Seric { 5004549Seric register char *q; 5014549Seric 5024549Seric /* find beginning of word */ 50358050Seric while (isascii(*p) && isspace(*p)) 5044549Seric p++; 5054549Seric q = p; 5064549Seric 5074549Seric /* find end of word */ 50858050Seric while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 5094549Seric p++; 51058050Seric while (isascii(*p) && 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'; 52058050Seric while (isascii(*p) && isspace(*p)) 5214549Seric p++; 5224549Seric 5234549Seric /* see if the input word matches desired word */ 52433725Sbostic if (strcasecmp(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 55849669Seric if (topic == NULL || *topic == '\0') 55949669Seric topic = "smtp"; 56049669Seric else 56149669Seric makelower(topic); 56249669Seric 5634577Seric len = strlen(topic); 5644577Seric noinfo = TRUE; 5654577Seric 5664577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5674577Seric { 5684577Seric if (strncmp(buf, topic, len) == 0) 5694577Seric { 5704577Seric register char *p; 5714577Seric 57256795Seric p = strchr(buf, '\t'); 5734577Seric if (p == NULL) 5744577Seric p = buf; 5754577Seric else 5764577Seric p++; 5774577Seric fixcrlf(p, TRUE); 5784577Seric message("214-", p); 5794577Seric noinfo = FALSE; 5804577Seric } 5814577Seric } 5824577Seric 5834577Seric if (noinfo) 5844577Seric message("504", "HELP topic unknown"); 5854577Seric else 5864577Seric message("214", "End of HELP info"); 5874628Seric (void) fclose(hf); 5884577Seric } 5898544Seric /* 5909339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 5919339Seric ** 5929339Seric ** Parameters: 5939339Seric ** label -- a string used in error messages 5949339Seric ** 5959339Seric ** Returns: 5969339Seric ** zero in the child 5979339Seric ** one in the parent 5989339Seric ** 5999339Seric ** Side Effects: 6009339Seric ** none. 6019339Seric */ 6028544Seric 60355012Seric runinchild(label, e) 6049339Seric char *label; 60555012Seric register ENVELOPE *e; 6069339Seric { 6079339Seric int childpid; 6089339Seric 60916158Seric if (!OneXact) 6109339Seric { 61116158Seric childpid = dofork(); 61216158Seric if (childpid < 0) 61316158Seric { 61416158Seric syserr("%s: cannot fork", label); 61516158Seric return (1); 61616158Seric } 61716158Seric if (childpid > 0) 61816158Seric { 61916158Seric auto int st; 6209339Seric 62116158Seric /* parent -- wait for child to complete */ 62216158Seric st = waitfor(childpid); 62316158Seric if (st == -1) 62416158Seric syserr("%s: lost child", label); 6259339Seric 62616158Seric /* if we exited on a QUIT command, complete the process */ 62716158Seric if (st == (EX_QUIT << 8)) 62816158Seric finis(); 6299339Seric 63016158Seric return (1); 63116158Seric } 63216158Seric else 63316158Seric { 63416158Seric /* child */ 63516158Seric InChild = TRUE; 63625050Seric QuickAbort = FALSE; 63755012Seric clearenvelope(e, FALSE); 63816158Seric } 6399339Seric } 64015256Seric 64116158Seric /* open alias database */ 64255012Seric initaliases(AliasFile, FALSE, e); 64316158Seric 64416158Seric return (0); 6459339Seric } 6469339Seric 64756795Seric # endif /* SMTP */ 648