122712Sdist /* 2*33731Sbostic * Copyright (c) 1988 Regents of the University of California. 3*33731Sbostic * All rights reserved. 4*33731Sbostic * 5*33731Sbostic * Redistribution and use in source and binary forms are permitted 6*33731Sbostic * provided that this notice is preserved and that due credit is given 7*33731Sbostic * to the University of California at Berkeley. The name of the University 8*33731Sbostic * may not be used to endorse or promote products derived from this 9*33731Sbostic * software without specific prior written permission. This software 10*33731Sbostic * is provided ``as is'' without express or implied warranty. 11*33731Sbostic * 12*33731Sbostic * Sendmail 13*33731Sbostic * Copyright (c) 1983 Eric P. Allman 14*33731Sbostic * Berkeley, California 15*33731Sbostic */ 1622712Sdist 17*33731Sbostic # include "sendmail.h" 1822712Sdist 19*33731Sbostic #ifndef lint 20*33731Sbostic #ifdef SMTP 21*33731Sbostic static char sccsid[] = "@(#)srvrsmtp.c 5.21 (Berkeley) 03/13/88 (with SMTP)"; 22*33731Sbostic #else 23*33731Sbostic static char sccsid[] = "@(#)srvrsmtp.c 5.21 (Berkeley) 03/13/88 (without SMTP)"; 24*33731Sbostic #endif 25*33731Sbostic #endif /* not lint */ 26*33731Sbostic 279339Seric # include <errno.h> 2811728Seric # include <signal.h> 294549Seric 30*33731Sbostic # ifdef SMTP 314556Seric 324549Seric /* 334549Seric ** SMTP -- run the SMTP protocol. 344549Seric ** 354549Seric ** Parameters: 364549Seric ** none. 374549Seric ** 384549Seric ** Returns: 394549Seric ** never. 404549Seric ** 414549Seric ** Side Effects: 424549Seric ** Reads commands from the input channel and processes 434549Seric ** them. 444549Seric */ 454549Seric 464549Seric struct cmd 474549Seric { 484549Seric char *cmdname; /* command name */ 494549Seric int cmdcode; /* internal code, see below */ 504549Seric }; 514549Seric 524549Seric /* values for cmdcode */ 534549Seric # define CMDERROR 0 /* bad command */ 544549Seric # define CMDMAIL 1 /* mail -- designate sender */ 554976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 564549Seric # define CMDDATA 3 /* data -- send message text */ 579339Seric # define CMDRSET 4 /* rset -- reset state */ 589339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 599339Seric # define CMDHELP 6 /* help -- give usage info */ 609339Seric # define CMDNOOP 7 /* noop -- do nothing */ 619339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 629339Seric # define CMDHELO 9 /* helo -- be polite */ 639339Seric # define CMDDBGQSHOW 10 /* showq -- show send queue (DEBUG) */ 649339Seric # define CMDDBGDEBUG 11 /* debug -- set debug mode */ 659339Seric # define CMDVERB 12 /* verb -- go into verbose mode */ 669339Seric # define CMDDBGKILL 13 /* kill -- kill sendmail */ 679339Seric # define CMDDBGWIZ 14 /* wiz -- become a wizard */ 689339Seric # define CMDONEX 15 /* onex -- sending one transaction only */ 694549Seric 704549Seric static struct cmd CmdTab[] = 714549Seric { 724549Seric "mail", CMDMAIL, 734976Seric "rcpt", CMDRCPT, 744549Seric "data", CMDDATA, 754549Seric "rset", CMDRSET, 764549Seric "vrfy", CMDVRFY, 777762Seric "expn", CMDVRFY, 784549Seric "help", CMDHELP, 794549Seric "noop", CMDNOOP, 804549Seric "quit", CMDQUIT, 814976Seric "helo", CMDHELO, 828544Seric "verb", CMDVERB, 839314Seric "onex", CMDONEX, 845003Seric # ifdef DEBUG 859339Seric "showq", CMDDBGQSHOW, 868544Seric "debug", CMDDBGDEBUG, 8724945Seric # endif DEBUG 8824945Seric # ifdef WIZ 898544Seric "kill", CMDDBGKILL, 9024945Seric # endif WIZ 918544Seric "wiz", CMDDBGWIZ, 924549Seric NULL, CMDERROR, 934549Seric }; 944549Seric 9524955Seric # ifdef WIZ 968544Seric bool IsWiz = FALSE; /* set if we are a wizard */ 9724955Seric # endif WIZ 9815596Seric char *WizWord; /* the wizard word to compare against */ 999339Seric bool InChild = FALSE; /* true if running in a subprocess */ 1009378Seric bool OneXact = FALSE; /* one xaction only this run */ 10111146Seric 1029339Seric #define EX_QUIT 22 /* special code for QUIT command */ 1038544Seric 1044549Seric smtp() 1054549Seric { 1064549Seric register char *p; 1078544Seric register struct cmd *c; 1084549Seric char *cmd; 1094549Seric extern char *skipword(); 1104549Seric bool hasmail; /* mail command received */ 1115003Seric auto ADDRESS *vrfyqueue; 11212612Seric ADDRESS *a; 11330448Seric char *sendinghost; 1148544Seric char inp[MAXLINE]; 11524981Seric char cmdbuf[100]; 1167124Seric extern char Version[]; 1177356Seric extern tick(); 1188544Seric extern bool iswiz(); 1199349Seric extern char *arpadate(); 12011151Seric extern char *macvalue(); 12112612Seric extern ADDRESS *recipient(); 12224943Seric extern ENVELOPE BlankEnvelope; 12324943Seric extern ENVELOPE *newenvelope(); 1244549Seric 1255003Seric hasmail = FALSE; 1267363Seric if (OutChannel != stdout) 1277363Seric { 1287363Seric /* arrange for debugging output to go to remote host */ 1297363Seric (void) close(1); 1307363Seric (void) dup(fileno(OutChannel)); 1317363Seric } 13211931Seric settime(); 13324971Seric if (RealHostName != NULL) 13425050Seric { 13525050Seric CurHostName = RealHostName; 13625050Seric setproctitle("srvrsmtp %s", CurHostName); 13725050Seric } 13825050Seric else 13925050Seric { 14025050Seric /* this must be us!! */ 14125050Seric CurHostName = MyHostName; 14225050Seric } 14316153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 14410708Seric message("220", inp); 14524943Seric SmtpPhase = "startup"; 14630448Seric sendinghost = NULL; 1474549Seric for (;;) 1484549Seric { 14912612Seric /* arrange for backout */ 15012612Seric if (setjmp(TopFrame) > 0 && InChild) 15112612Seric finis(); 15212612Seric QuickAbort = FALSE; 15312612Seric HoldErrs = FALSE; 15412612Seric 1557356Seric /* setup for the read */ 1566907Seric CurEnv->e_to = NULL; 1574577Seric Errors = 0; 1587275Seric (void) fflush(stdout); 1597356Seric 1607356Seric /* read the input line */ 1617685Seric p = sfgets(inp, sizeof inp, InChannel); 1627356Seric 1637685Seric /* handle errors */ 1647356Seric if (p == NULL) 1657356Seric { 1664549Seric /* end of file, just die */ 16725050Seric message("421", "%s Lost input channel to %s", 16825050Seric MyHostName, CurHostName); 1694549Seric finis(); 1704549Seric } 1714549Seric 1724549Seric /* clean up end of line */ 1734558Seric fixcrlf(inp, TRUE); 1744549Seric 1754713Seric /* echo command to transcript */ 1769545Seric if (CurEnv->e_xfp != NULL) 1779545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1784713Seric 1794549Seric /* break off command */ 1804549Seric for (p = inp; isspace(*p); p++) 1814549Seric continue; 1824549Seric cmd = p; 18324981Seric for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) 18424981Seric *cmd++ = *p++; 18524981Seric *cmd = '\0'; 1864549Seric 18725691Seric /* throw away leading whitespace */ 18825691Seric while (isspace(*p)) 18925691Seric p++; 19025691Seric 1914549Seric /* decode command */ 1924549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1934549Seric { 19433725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1954549Seric break; 1964549Seric } 1974549Seric 1984549Seric /* process command */ 1994549Seric switch (c->cmdcode) 2004549Seric { 2014976Seric case CMDHELO: /* hello -- introduce yourself */ 20224943Seric SmtpPhase = "HELO"; 20325050Seric setproctitle("%s: %s", CurHostName, inp); 20433725Sbostic if (!strcasecmp(p, MyHostName)) 20514877Seric { 20614877Seric /* connected to an echo server */ 20714877Seric message("553", "%s I refuse to talk to myself", 20825050Seric MyHostName); 20914877Seric break; 21014877Seric } 21133725Sbostic if (RealHostName != NULL && strcasecmp(p, RealHostName)) 21211146Seric { 21324981Seric char hostbuf[MAXNAME]; 21411146Seric 21524981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 21630448Seric sendinghost = newstr(hostbuf); 21711146Seric } 21811146Seric else 21930448Seric sendinghost = newstr(p); 2204997Seric message("250", "%s Hello %s, pleased to meet you", 22125050Seric MyHostName, p); 2224976Seric break; 2234976Seric 2244549Seric case CMDMAIL: /* mail -- designate sender */ 22524943Seric SmtpPhase = "MAIL"; 22624943Seric 22711151Seric /* force a sending host even if no HELO given */ 22811151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 22930448Seric sendinghost = RealHostName; 23011151Seric 2319314Seric /* check for validity of this command */ 2324558Seric if (hasmail) 2334558Seric { 2344558Seric message("503", "Sender already specified"); 2354558Seric break; 2364558Seric } 2379339Seric if (InChild) 2389339Seric { 2399339Seric syserr("Nested MAIL command"); 2409339Seric exit(0); 2419339Seric } 2429339Seric 2439339Seric /* fork a subprocess to process this command */ 2449339Seric if (runinchild("SMTP-MAIL") > 0) 2459339Seric break; 24630448Seric define('s', sendinghost, CurEnv); 2479339Seric initsys(); 24825016Seric setproctitle("%s %s: %s", CurEnv->e_id, 24925050Seric CurHostName, inp); 2509339Seric 2519339Seric /* child -- go do the processing */ 2524549Seric p = skipword(p, "from"); 2534549Seric if (p == NULL) 2544549Seric break; 2554549Seric setsender(p); 2564577Seric if (Errors == 0) 2574549Seric { 2584549Seric message("250", "Sender ok"); 2594549Seric hasmail = TRUE; 2604549Seric } 2619339Seric else if (InChild) 2629339Seric finis(); 2634549Seric break; 2644549Seric 2654976Seric case CMDRCPT: /* rcpt -- designate recipient */ 26624943Seric SmtpPhase = "RCPT"; 26725016Seric setproctitle("%s %s: %s", CurEnv->e_id, 26825050Seric CurHostName, inp); 26912612Seric if (setjmp(TopFrame) > 0) 27014785Seric { 27114785Seric CurEnv->e_flags &= ~EF_FATALERRS; 27212612Seric break; 27314785Seric } 27412612Seric QuickAbort = TRUE; 2754549Seric p = skipword(p, "to"); 2764549Seric if (p == NULL) 2774549Seric break; 27816140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 27912612Seric if (a == NULL) 28012612Seric break; 28116886Seric a->q_flags |= QPRIMARY; 28212612Seric a = recipient(a, &CurEnv->e_sendqueue); 28312612Seric if (Errors != 0) 28412612Seric break; 28512612Seric 28612612Seric /* no errors during parsing, but might be a duplicate */ 28712612Seric CurEnv->e_to = p; 28812612Seric if (!bitset(QBADADDR, a->q_flags)) 28912612Seric message("250", "Recipient ok"); 29012612Seric else 2914549Seric { 29212612Seric /* punt -- should keep message in ADDRESS.... */ 29312612Seric message("550", "Addressee unknown"); 2944549Seric } 29512612Seric CurEnv->e_to = NULL; 2964549Seric break; 2974549Seric 2984549Seric case CMDDATA: /* data -- text of mail */ 29924943Seric SmtpPhase = "DATA"; 3004976Seric if (!hasmail) 3014549Seric { 3024976Seric message("503", "Need MAIL command"); 3034976Seric break; 3044549Seric } 30524943Seric else if (CurEnv->e_nrcpts <= 0) 3064549Seric { 3074976Seric message("503", "Need RCPT (recipient)"); 3084976Seric break; 3094549Seric } 3104976Seric 3114976Seric /* collect the text of the message */ 31224943Seric SmtpPhase = "collect"; 31325016Seric setproctitle("%s %s: %s", CurEnv->e_id, 31425050Seric CurHostName, inp); 3154976Seric collect(TRUE); 3164976Seric if (Errors != 0) 3174976Seric break; 3184976Seric 3198238Seric /* 3208238Seric ** Arrange to send to everyone. 3218238Seric ** If sending to multiple people, mail back 3228238Seric ** errors rather than reporting directly. 3238238Seric ** In any case, don't mail back errors for 3248238Seric ** anything that has happened up to 3258238Seric ** now (the other end will do this). 32610197Seric ** Truncate our transcript -- the mail has gotten 32710197Seric ** to us successfully, and if we have 32810197Seric ** to mail this back, it will be easier 32910197Seric ** on the reader. 3308238Seric ** Then send to everyone. 3318238Seric ** Finally give a reply code. If an error has 3328238Seric ** already been given, don't mail a 3338238Seric ** message back. 3349339Seric ** We goose error returns by clearing error bit. 3358238Seric */ 3368238Seric 33724943Seric SmtpPhase = "delivery"; 33824943Seric if (CurEnv->e_nrcpts != 1) 3399378Seric { 3409378Seric HoldErrs = TRUE; 34116886Seric ErrorMode = EM_MAIL; 3429378Seric } 3439339Seric CurEnv->e_flags &= ~EF_FATALERRS; 34410197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3454976Seric 3464976Seric /* send to all recipients */ 34714877Seric sendall(CurEnv, SM_DEFAULT); 3486907Seric CurEnv->e_to = NULL; 3494976Seric 35023516Seric /* save statistics */ 35123516Seric markstats(CurEnv, (ADDRESS *) NULL); 35223516Seric 3538238Seric /* issue success if appropriate and reset */ 3548238Seric if (Errors == 0 || HoldErrs) 3559283Seric message("250", "Ok"); 3568238Seric else 3579339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3589339Seric 3599339Seric /* if in a child, pop back to our parent */ 3609339Seric if (InChild) 3619339Seric finis(); 36224943Seric 36324943Seric /* clean up a bit */ 36424943Seric hasmail = 0; 36524943Seric dropenvelope(CurEnv); 36624943Seric CurEnv = newenvelope(CurEnv); 36724943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3684549Seric break; 3694549Seric 3704549Seric case CMDRSET: /* rset -- reset state */ 3714549Seric message("250", "Reset state"); 3729339Seric if (InChild) 3739339Seric finis(); 3749339Seric break; 3754549Seric 3764549Seric case CMDVRFY: /* vrfy -- verify address */ 3779339Seric if (runinchild("SMTP-VRFY") > 0) 3789339Seric break; 37925050Seric setproctitle("%s: %s", CurHostName, inp); 3805003Seric vrfyqueue = NULL; 3817762Seric QuickAbort = TRUE; 3829619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3837762Seric if (Errors != 0) 3849339Seric { 3859339Seric if (InChild) 3869339Seric finis(); 3877762Seric break; 3889339Seric } 3895003Seric while (vrfyqueue != NULL) 3905003Seric { 3915003Seric register ADDRESS *a = vrfyqueue->q_next; 3925003Seric char *code; 3935003Seric 3947685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 3955003Seric a = a->q_next; 3965003Seric 3977685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 3985003Seric { 3995003Seric if (a != NULL) 4005003Seric code = "250-"; 4015003Seric else 4025003Seric code = "250"; 4035003Seric if (vrfyqueue->q_fullname == NULL) 4045003Seric message(code, "<%s>", vrfyqueue->q_paddr); 4055003Seric else 4065003Seric message(code, "%s <%s>", 4075003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4085003Seric } 4095003Seric else if (a == NULL) 4105003Seric message("554", "Self destructive alias loop"); 4115003Seric vrfyqueue = a; 4125003Seric } 4139339Seric if (InChild) 4149339Seric finis(); 4154549Seric break; 4164549Seric 4174549Seric case CMDHELP: /* help -- give user info */ 4184577Seric if (*p == '\0') 4194577Seric p = "SMTP"; 4204577Seric help(p); 4214549Seric break; 4224549Seric 4234549Seric case CMDNOOP: /* noop -- do nothing */ 4244549Seric message("200", "OK"); 4254549Seric break; 4264549Seric 4274549Seric case CMDQUIT: /* quit -- leave mail */ 42825050Seric message("221", "%s closing connection", MyHostName); 4299339Seric if (InChild) 4309339Seric ExitStat = EX_QUIT; 4314549Seric finis(); 4324549Seric 4338544Seric case CMDVERB: /* set verbose mode */ 4348544Seric Verbose = TRUE; 43525025Seric SendMode = SM_DELIVER; 4368544Seric message("200", "Verbose mode"); 4378544Seric break; 4388544Seric 4399314Seric case CMDONEX: /* doing one transaction only */ 4409378Seric OneXact = TRUE; 4419314Seric message("200", "Only one transaction"); 4429314Seric break; 4439314Seric 4445003Seric # ifdef DEBUG 4459339Seric case CMDDBGQSHOW: /* show queues */ 4466907Seric printf("Send Queue="); 4476907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4485003Seric break; 4497275Seric 4507275Seric case CMDDBGDEBUG: /* set debug mode */ 4517676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4527676Seric tTflag(p); 4537676Seric message("200", "Debug set"); 4547275Seric break; 45524945Seric # endif DEBUG 4567275Seric 45724945Seric # ifdef WIZ 4587282Seric case CMDDBGKILL: /* kill the parent */ 4598544Seric if (!iswiz()) 4608544Seric break; 4617282Seric if (kill(MotherPid, SIGTERM) >= 0) 4627282Seric message("200", "Mother is dead"); 4637282Seric else 4647282Seric message("500", "Can't kill Mom"); 4657282Seric break; 4668544Seric 4678544Seric case CMDDBGWIZ: /* become a wizard */ 4688544Seric if (WizWord != NULL) 4698544Seric { 4708544Seric char seed[3]; 4718544Seric extern char *crypt(); 4728544Seric 47323106Seric (void) strncpy(seed, WizWord, 2); 47415596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4758544Seric { 47615596Seric IsWiz = TRUE; 47715596Seric message("200", "Please pass, oh mighty wizard"); 4788544Seric break; 4798544Seric } 4808544Seric } 48115596Seric message("500", "You are no wizard!"); 4828544Seric break; 4835003Seric 48424945Seric # else WIZ 48524945Seric case CMDDBGWIZ: /* try to become a wizard */ 48624945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 48724945Seric break; 48824945Seric # endif WIZ 48924945Seric 4904549Seric case CMDERROR: /* unknown command */ 4914549Seric message("500", "Command unrecognized"); 4924549Seric break; 4934549Seric 4944549Seric default: 4954549Seric syserr("smtp: unknown code %d", c->cmdcode); 4964549Seric break; 4974549Seric } 4984549Seric } 4994549Seric } 5004549Seric /* 5014549Seric ** SKIPWORD -- skip a fixed word. 5024549Seric ** 5034549Seric ** Parameters: 5044549Seric ** p -- place to start looking. 5054549Seric ** w -- word to skip. 5064549Seric ** 5074549Seric ** Returns: 5084549Seric ** p following w. 5094549Seric ** NULL on error. 5104549Seric ** 5114549Seric ** Side Effects: 5124549Seric ** clobbers the p data area. 5134549Seric */ 5144549Seric 5154549Seric static char * 5164549Seric skipword(p, w) 5174549Seric register char *p; 5184549Seric char *w; 5194549Seric { 5204549Seric register char *q; 5214549Seric 5224549Seric /* find beginning of word */ 5234549Seric while (isspace(*p)) 5244549Seric p++; 5254549Seric q = p; 5264549Seric 5274549Seric /* find end of word */ 5284549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5294549Seric p++; 5304549Seric while (isspace(*p)) 5314549Seric *p++ = '\0'; 5324549Seric if (*p != ':') 5334549Seric { 5344549Seric syntax: 5354549Seric message("501", "Syntax error"); 5364549Seric Errors++; 5374549Seric return (NULL); 5384549Seric } 5394549Seric *p++ = '\0'; 5404549Seric while (isspace(*p)) 5414549Seric p++; 5424549Seric 5434549Seric /* see if the input word matches desired word */ 54433725Sbostic if (strcasecmp(q, w)) 5454549Seric goto syntax; 5464549Seric 5474549Seric return (p); 5484549Seric } 5494577Seric /* 5504577Seric ** HELP -- implement the HELP command. 5514577Seric ** 5524577Seric ** Parameters: 5534577Seric ** topic -- the topic we want help for. 5544577Seric ** 5554577Seric ** Returns: 5564577Seric ** none. 5574577Seric ** 5584577Seric ** Side Effects: 5594577Seric ** outputs the help file to message output. 5604577Seric */ 5614577Seric 5624577Seric help(topic) 5634577Seric char *topic; 5644577Seric { 5654577Seric register FILE *hf; 5664577Seric int len; 5674577Seric char buf[MAXLINE]; 5684577Seric bool noinfo; 5694577Seric 5708269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5714577Seric { 5724577Seric /* no help */ 57311931Seric errno = 0; 5744577Seric message("502", "HELP not implemented"); 5754577Seric return; 5764577Seric } 5774577Seric 5784577Seric len = strlen(topic); 5794577Seric makelower(topic); 5804577Seric noinfo = TRUE; 5814577Seric 5824577Seric while (fgets(buf, sizeof buf, hf) != NULL) 5834577Seric { 5844577Seric if (strncmp(buf, topic, len) == 0) 5854577Seric { 5864577Seric register char *p; 5874577Seric 5884577Seric p = index(buf, '\t'); 5894577Seric if (p == NULL) 5904577Seric p = buf; 5914577Seric else 5924577Seric p++; 5934577Seric fixcrlf(p, TRUE); 5944577Seric message("214-", p); 5954577Seric noinfo = FALSE; 5964577Seric } 5974577Seric } 5984577Seric 5994577Seric if (noinfo) 6004577Seric message("504", "HELP topic unknown"); 6014577Seric else 6024577Seric message("214", "End of HELP info"); 6034628Seric (void) fclose(hf); 6044577Seric } 6058544Seric /* 6068544Seric ** ISWIZ -- tell us if we are a wizard 6078544Seric ** 6088544Seric ** If not, print a nasty message. 6098544Seric ** 6108544Seric ** Parameters: 6118544Seric ** none. 6128544Seric ** 6138544Seric ** Returns: 6148544Seric ** TRUE if we are a wizard. 6158544Seric ** FALSE if we are not a wizard. 6168544Seric ** 6178544Seric ** Side Effects: 6188544Seric ** Prints a 500 exit stat if we are not a wizard. 6198544Seric */ 6205181Seric 62124945Seric #ifdef WIZ 62219038Seric 6238544Seric bool 6248544Seric iswiz() 6258544Seric { 6268544Seric if (!IsWiz) 6278544Seric message("500", "Mere mortals musn't mutter that mantra"); 6288544Seric return (IsWiz); 6298544Seric } 63019038Seric 63124945Seric #endif WIZ 6329339Seric /* 6339339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6349339Seric ** 6359339Seric ** Parameters: 6369339Seric ** label -- a string used in error messages 6379339Seric ** 6389339Seric ** Returns: 6399339Seric ** zero in the child 6409339Seric ** one in the parent 6419339Seric ** 6429339Seric ** Side Effects: 6439339Seric ** none. 6449339Seric */ 6458544Seric 6469339Seric runinchild(label) 6479339Seric char *label; 6489339Seric { 6499339Seric int childpid; 6509339Seric 65116158Seric if (!OneXact) 6529339Seric { 65316158Seric childpid = dofork(); 65416158Seric if (childpid < 0) 65516158Seric { 65616158Seric syserr("%s: cannot fork", label); 65716158Seric return (1); 65816158Seric } 65916158Seric if (childpid > 0) 66016158Seric { 66116158Seric auto int st; 6629339Seric 66316158Seric /* parent -- wait for child to complete */ 66416158Seric st = waitfor(childpid); 66516158Seric if (st == -1) 66616158Seric syserr("%s: lost child", label); 6679339Seric 66816158Seric /* if we exited on a QUIT command, complete the process */ 66916158Seric if (st == (EX_QUIT << 8)) 67016158Seric finis(); 6719339Seric 67216158Seric return (1); 67316158Seric } 67416158Seric else 67516158Seric { 67616158Seric /* child */ 67716158Seric InChild = TRUE; 67825050Seric QuickAbort = FALSE; 67925614Seric clearenvelope(CurEnv, FALSE); 68016158Seric } 6819339Seric } 68215256Seric 68316158Seric /* open alias database */ 68416158Seric initaliases(AliasFile, FALSE); 68516158Seric 68616158Seric return (0); 6879339Seric } 6889339Seric 6895181Seric # endif SMTP 690