122712Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 633731Sbostic * Redistribution and use in source and binary forms are permitted 734921Sbostic * provided that the above copyright notice and this paragraph are 834921Sbostic * duplicated in all such forms and that any documentation, 934921Sbostic * advertising materials, and other materials related to such 1034921Sbostic * distribution and use acknowledge that the software was developed 1134921Sbostic * by the University of California, Berkeley. The name of the 1234921Sbostic * University may not be used to endorse or promote products derived 1334921Sbostic * from this software without specific prior written permission. 1434921Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1534921Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1634921Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1733731Sbostic */ 1822712Sdist 1933731Sbostic # include "sendmail.h" 2022712Sdist 2133731Sbostic #ifndef lint 2233731Sbostic #ifdef SMTP 23*36233Skarels static char sccsid[] = "@(#)srvrsmtp.c 5.25 (Berkeley) 11/17/88 (with SMTP)"; 2433731Sbostic #else 25*36233Skarels static char sccsid[] = "@(#)srvrsmtp.c 5.25 (Berkeley) 11/17/88 (without SMTP)"; 2633731Sbostic #endif 2733731Sbostic #endif /* not lint */ 2833731Sbostic 299339Seric # include <errno.h> 3011728Seric # include <signal.h> 314549Seric 3233731Sbostic # ifdef SMTP 334556Seric 344549Seric /* 354549Seric ** SMTP -- run the SMTP protocol. 364549Seric ** 374549Seric ** Parameters: 384549Seric ** none. 394549Seric ** 404549Seric ** Returns: 414549Seric ** never. 424549Seric ** 434549Seric ** Side Effects: 444549Seric ** Reads commands from the input channel and processes 454549Seric ** them. 464549Seric */ 474549Seric 484549Seric struct cmd 494549Seric { 504549Seric char *cmdname; /* command name */ 514549Seric int cmdcode; /* internal code, see below */ 524549Seric }; 534549Seric 544549Seric /* values for cmdcode */ 554549Seric # define CMDERROR 0 /* bad command */ 564549Seric # define CMDMAIL 1 /* mail -- designate sender */ 574976Seric # define CMDRCPT 2 /* rcpt -- designate recipient */ 584549Seric # define CMDDATA 3 /* data -- send message text */ 599339Seric # define CMDRSET 4 /* rset -- reset state */ 609339Seric # define CMDVRFY 5 /* vrfy -- verify address */ 619339Seric # define CMDHELP 6 /* help -- give usage info */ 629339Seric # define CMDNOOP 7 /* noop -- do nothing */ 639339Seric # define CMDQUIT 8 /* quit -- close connection and die */ 649339Seric # define CMDHELO 9 /* helo -- be polite */ 6536230Skarels # define CMDONEX 10 /* onex -- sending one transaction only */ 6636230Skarels # define CMDVERB 11 /* verb -- go into verbose mode */ 6736230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 6836230Skarels # define CMDDBGQSHOW 12 /* showq -- show send queue */ 6936230Skarels # define CMDDBGDEBUG 13 /* debug -- set debug mode */ 7036230Skarels # define CMDDBGKILL 14 /* kill -- kill sendmail */ 7136230Skarels # define CMDDBGWIZ 15 /* wiz -- become a wizard */ 724549Seric 734549Seric static struct cmd CmdTab[] = 744549Seric { 754549Seric "mail", CMDMAIL, 764976Seric "rcpt", CMDRCPT, 774549Seric "data", CMDDATA, 784549Seric "rset", CMDRSET, 794549Seric "vrfy", CMDVRFY, 807762Seric "expn", CMDVRFY, 814549Seric "help", CMDHELP, 824549Seric "noop", CMDNOOP, 834549Seric "quit", CMDQUIT, 844976Seric "helo", CMDHELO, 858544Seric "verb", CMDVERB, 869314Seric "onex", CMDONEX, 8736230Skarels /* 8836230Skarels * remaining commands are here only 8936230Skarels * to trap and log attempts to use them 9036230Skarels */ 919339Seric "showq", CMDDBGQSHOW, 928544Seric "debug", CMDDBGDEBUG, 938544Seric "kill", CMDDBGKILL, 948544Seric "wiz", CMDDBGWIZ, 954549Seric NULL, CMDERROR, 964549Seric }; 974549Seric 9824955Seric # ifdef WIZ 998544Seric bool IsWiz = FALSE; /* set if we are a wizard */ 10036230Skarels char *WizWord; /* the wizard word to compare against */ 10124955Seric # endif WIZ 1029339Seric bool InChild = FALSE; /* true if running in a subprocess */ 1039378Seric bool OneXact = FALSE; /* one xaction only this run */ 10411146Seric 1059339Seric #define EX_QUIT 22 /* special code for QUIT command */ 1068544Seric 1074549Seric smtp() 1084549Seric { 1094549Seric register char *p; 1108544Seric register struct cmd *c; 1114549Seric char *cmd; 1124549Seric extern char *skipword(); 1134549Seric bool hasmail; /* mail command received */ 1145003Seric auto ADDRESS *vrfyqueue; 11512612Seric ADDRESS *a; 11630448Seric char *sendinghost; 1178544Seric char inp[MAXLINE]; 11824981Seric char cmdbuf[100]; 1197124Seric extern char Version[]; 1207356Seric extern tick(); 1218544Seric extern bool iswiz(); 1229349Seric extern char *arpadate(); 12311151Seric extern char *macvalue(); 12412612Seric extern ADDRESS *recipient(); 12524943Seric extern ENVELOPE BlankEnvelope; 12624943Seric extern ENVELOPE *newenvelope(); 1274549Seric 1285003Seric hasmail = FALSE; 1297363Seric if (OutChannel != stdout) 1307363Seric { 1317363Seric /* arrange for debugging output to go to remote host */ 1327363Seric (void) close(1); 1337363Seric (void) dup(fileno(OutChannel)); 1347363Seric } 13511931Seric settime(); 13624971Seric if (RealHostName != NULL) 13725050Seric { 13825050Seric CurHostName = RealHostName; 13925050Seric setproctitle("srvrsmtp %s", CurHostName); 14025050Seric } 14125050Seric else 14225050Seric { 14325050Seric /* this must be us!! */ 14425050Seric CurHostName = MyHostName; 14525050Seric } 14616153Seric expand("\001e", inp, &inp[sizeof inp], CurEnv); 14710708Seric message("220", inp); 14824943Seric SmtpPhase = "startup"; 14930448Seric sendinghost = NULL; 1504549Seric for (;;) 1514549Seric { 15212612Seric /* arrange for backout */ 15312612Seric if (setjmp(TopFrame) > 0 && InChild) 15412612Seric finis(); 15512612Seric QuickAbort = FALSE; 15612612Seric HoldErrs = FALSE; 15712612Seric 1587356Seric /* setup for the read */ 1596907Seric CurEnv->e_to = NULL; 1604577Seric Errors = 0; 1617275Seric (void) fflush(stdout); 1627356Seric 1637356Seric /* read the input line */ 1647685Seric p = sfgets(inp, sizeof inp, InChannel); 1657356Seric 1667685Seric /* handle errors */ 1677356Seric if (p == NULL) 1687356Seric { 1694549Seric /* end of file, just die */ 17036230Skarels message("421", "%s Lost input channel from %s", 17125050Seric MyHostName, CurHostName); 1724549Seric finis(); 1734549Seric } 1744549Seric 1754549Seric /* clean up end of line */ 1764558Seric fixcrlf(inp, TRUE); 1774549Seric 1784713Seric /* echo command to transcript */ 1799545Seric if (CurEnv->e_xfp != NULL) 1809545Seric fprintf(CurEnv->e_xfp, "<<< %s\n", inp); 1814713Seric 1824549Seric /* break off command */ 1834549Seric for (p = inp; isspace(*p); p++) 1844549Seric continue; 1854549Seric cmd = p; 18624981Seric for (cmd = cmdbuf; *p != '\0' && !isspace(*p); ) 18724981Seric *cmd++ = *p++; 18824981Seric *cmd = '\0'; 1894549Seric 19025691Seric /* throw away leading whitespace */ 19125691Seric while (isspace(*p)) 19225691Seric p++; 19325691Seric 1944549Seric /* decode command */ 1954549Seric for (c = CmdTab; c->cmdname != NULL; c++) 1964549Seric { 19733725Sbostic if (!strcasecmp(c->cmdname, cmdbuf)) 1984549Seric break; 1994549Seric } 2004549Seric 2014549Seric /* process command */ 2024549Seric switch (c->cmdcode) 2034549Seric { 2044976Seric case CMDHELO: /* hello -- introduce yourself */ 20524943Seric SmtpPhase = "HELO"; 20625050Seric setproctitle("%s: %s", CurHostName, inp); 20733725Sbostic if (!strcasecmp(p, MyHostName)) 20814877Seric { 20936230Skarels /* 21036230Skarels * didn't know about alias, 21136230Skarels * or connected to an echo server 21236230Skarels */ 21336230Skarels message("553", "Local configuration error, hostname not recognized as local"); 21414877Seric break; 21514877Seric } 21633725Sbostic if (RealHostName != NULL && strcasecmp(p, RealHostName)) 21711146Seric { 21824981Seric char hostbuf[MAXNAME]; 21911146Seric 22024981Seric (void) sprintf(hostbuf, "%s (%s)", p, RealHostName); 22130448Seric sendinghost = newstr(hostbuf); 22211146Seric } 22311146Seric else 22430448Seric sendinghost = newstr(p); 2254997Seric message("250", "%s Hello %s, pleased to meet you", 22636230Skarels MyHostName, sendinghost); 2274976Seric break; 2284976Seric 2294549Seric case CMDMAIL: /* mail -- designate sender */ 23024943Seric SmtpPhase = "MAIL"; 23124943Seric 23211151Seric /* force a sending host even if no HELO given */ 23311151Seric if (RealHostName != NULL && macvalue('s', CurEnv) == NULL) 23430448Seric sendinghost = RealHostName; 23511151Seric 2369314Seric /* check for validity of this command */ 2374558Seric if (hasmail) 2384558Seric { 2394558Seric message("503", "Sender already specified"); 2404558Seric break; 2414558Seric } 2429339Seric if (InChild) 2439339Seric { 24436230Skarels errno = 0; 2459339Seric syserr("Nested MAIL command"); 2469339Seric exit(0); 2479339Seric } 2489339Seric 2499339Seric /* fork a subprocess to process this command */ 2509339Seric if (runinchild("SMTP-MAIL") > 0) 2519339Seric break; 25230448Seric define('s', sendinghost, CurEnv); 2539339Seric initsys(); 25425016Seric setproctitle("%s %s: %s", CurEnv->e_id, 25525050Seric CurHostName, inp); 2569339Seric 2579339Seric /* child -- go do the processing */ 2584549Seric p = skipword(p, "from"); 2594549Seric if (p == NULL) 2604549Seric break; 2614549Seric setsender(p); 2624577Seric if (Errors == 0) 2634549Seric { 2644549Seric message("250", "Sender ok"); 2654549Seric hasmail = TRUE; 2664549Seric } 2679339Seric else if (InChild) 2689339Seric finis(); 2694549Seric break; 2704549Seric 2714976Seric case CMDRCPT: /* rcpt -- designate recipient */ 27224943Seric SmtpPhase = "RCPT"; 27325016Seric setproctitle("%s %s: %s", CurEnv->e_id, 27425050Seric CurHostName, inp); 27512612Seric if (setjmp(TopFrame) > 0) 27614785Seric { 27714785Seric CurEnv->e_flags &= ~EF_FATALERRS; 27812612Seric break; 27914785Seric } 28012612Seric QuickAbort = TRUE; 2814549Seric p = skipword(p, "to"); 2824549Seric if (p == NULL) 2834549Seric break; 28416140Seric a = parseaddr(p, (ADDRESS *) NULL, 1, '\0'); 28512612Seric if (a == NULL) 28612612Seric break; 28716886Seric a->q_flags |= QPRIMARY; 28812612Seric a = recipient(a, &CurEnv->e_sendqueue); 28912612Seric if (Errors != 0) 29012612Seric break; 29112612Seric 29212612Seric /* no errors during parsing, but might be a duplicate */ 29312612Seric CurEnv->e_to = p; 29412612Seric if (!bitset(QBADADDR, a->q_flags)) 29512612Seric message("250", "Recipient ok"); 29612612Seric else 2974549Seric { 29812612Seric /* punt -- should keep message in ADDRESS.... */ 29912612Seric message("550", "Addressee unknown"); 3004549Seric } 30112612Seric CurEnv->e_to = NULL; 3024549Seric break; 3034549Seric 3044549Seric case CMDDATA: /* data -- text of mail */ 30524943Seric SmtpPhase = "DATA"; 3064976Seric if (!hasmail) 3074549Seric { 3084976Seric message("503", "Need MAIL command"); 3094976Seric break; 3104549Seric } 31124943Seric else if (CurEnv->e_nrcpts <= 0) 3124549Seric { 3134976Seric message("503", "Need RCPT (recipient)"); 3144976Seric break; 3154549Seric } 3164976Seric 3174976Seric /* collect the text of the message */ 31824943Seric SmtpPhase = "collect"; 31925016Seric setproctitle("%s %s: %s", CurEnv->e_id, 32025050Seric CurHostName, inp); 3214976Seric collect(TRUE); 3224976Seric if (Errors != 0) 3234976Seric break; 3244976Seric 3258238Seric /* 3268238Seric ** Arrange to send to everyone. 3278238Seric ** If sending to multiple people, mail back 3288238Seric ** errors rather than reporting directly. 3298238Seric ** In any case, don't mail back errors for 3308238Seric ** anything that has happened up to 3318238Seric ** now (the other end will do this). 33210197Seric ** Truncate our transcript -- the mail has gotten 33310197Seric ** to us successfully, and if we have 33410197Seric ** to mail this back, it will be easier 33510197Seric ** on the reader. 3368238Seric ** Then send to everyone. 3378238Seric ** Finally give a reply code. If an error has 3388238Seric ** already been given, don't mail a 3398238Seric ** message back. 3409339Seric ** We goose error returns by clearing error bit. 3418238Seric */ 3428238Seric 34324943Seric SmtpPhase = "delivery"; 34424943Seric if (CurEnv->e_nrcpts != 1) 3459378Seric { 3469378Seric HoldErrs = TRUE; 34716886Seric ErrorMode = EM_MAIL; 3489378Seric } 3499339Seric CurEnv->e_flags &= ~EF_FATALERRS; 35010197Seric CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp); 3514976Seric 3524976Seric /* send to all recipients */ 35314877Seric sendall(CurEnv, SM_DEFAULT); 3546907Seric CurEnv->e_to = NULL; 3554976Seric 35623516Seric /* save statistics */ 35723516Seric markstats(CurEnv, (ADDRESS *) NULL); 35823516Seric 3598238Seric /* issue success if appropriate and reset */ 3608238Seric if (Errors == 0 || HoldErrs) 3619283Seric message("250", "Ok"); 3628238Seric else 3639339Seric CurEnv->e_flags &= ~EF_FATALERRS; 3649339Seric 3659339Seric /* if in a child, pop back to our parent */ 3669339Seric if (InChild) 3679339Seric finis(); 36824943Seric 36924943Seric /* clean up a bit */ 37024943Seric hasmail = 0; 37124943Seric dropenvelope(CurEnv); 37224943Seric CurEnv = newenvelope(CurEnv); 37324943Seric CurEnv->e_flags = BlankEnvelope.e_flags; 3744549Seric break; 3754549Seric 3764549Seric case CMDRSET: /* rset -- reset state */ 3774549Seric message("250", "Reset state"); 3789339Seric if (InChild) 3799339Seric finis(); 3809339Seric break; 3814549Seric 3824549Seric case CMDVRFY: /* vrfy -- verify address */ 3839339Seric if (runinchild("SMTP-VRFY") > 0) 3849339Seric break; 38525050Seric setproctitle("%s: %s", CurHostName, inp); 3865003Seric vrfyqueue = NULL; 3877762Seric QuickAbort = TRUE; 3889619Seric sendtolist(p, (ADDRESS *) NULL, &vrfyqueue); 3897762Seric if (Errors != 0) 3909339Seric { 3919339Seric if (InChild) 3929339Seric finis(); 3937762Seric break; 3949339Seric } 3955003Seric while (vrfyqueue != NULL) 3965003Seric { 3975003Seric register ADDRESS *a = vrfyqueue->q_next; 3985003Seric char *code; 3995003Seric 4007685Seric while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) 4015003Seric a = a->q_next; 4025003Seric 4037685Seric if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags)) 4045003Seric { 4055003Seric if (a != NULL) 4065003Seric code = "250-"; 4075003Seric else 4085003Seric code = "250"; 4095003Seric if (vrfyqueue->q_fullname == NULL) 4105003Seric message(code, "<%s>", vrfyqueue->q_paddr); 4115003Seric else 4125003Seric message(code, "%s <%s>", 4135003Seric vrfyqueue->q_fullname, vrfyqueue->q_paddr); 4145003Seric } 4155003Seric else if (a == NULL) 4165003Seric message("554", "Self destructive alias loop"); 4175003Seric vrfyqueue = a; 4185003Seric } 4199339Seric if (InChild) 4209339Seric finis(); 4214549Seric break; 4224549Seric 4234549Seric case CMDHELP: /* help -- give user info */ 4244577Seric if (*p == '\0') 4254577Seric p = "SMTP"; 4264577Seric help(p); 4274549Seric break; 4284549Seric 4294549Seric case CMDNOOP: /* noop -- do nothing */ 4304549Seric message("200", "OK"); 4314549Seric break; 4324549Seric 4334549Seric case CMDQUIT: /* quit -- leave mail */ 43425050Seric message("221", "%s closing connection", MyHostName); 4359339Seric if (InChild) 4369339Seric ExitStat = EX_QUIT; 4374549Seric finis(); 4384549Seric 4398544Seric case CMDVERB: /* set verbose mode */ 4408544Seric Verbose = TRUE; 44125025Seric SendMode = SM_DELIVER; 4428544Seric message("200", "Verbose mode"); 4438544Seric break; 4448544Seric 4459314Seric case CMDONEX: /* doing one transaction only */ 4469378Seric OneXact = TRUE; 4479314Seric message("200", "Only one transaction"); 4489314Seric break; 4499314Seric 45036230Skarels # ifdef SMTPDEBUG 4519339Seric case CMDDBGQSHOW: /* show queues */ 4526907Seric printf("Send Queue="); 4536907Seric printaddr(CurEnv->e_sendqueue, TRUE); 4545003Seric break; 4557275Seric 4567275Seric case CMDDBGDEBUG: /* set debug mode */ 4577676Seric tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 4587676Seric tTflag(p); 4597676Seric message("200", "Debug set"); 4607275Seric break; 4617275Seric 46224945Seric # ifdef WIZ 4637282Seric case CMDDBGKILL: /* kill the parent */ 4648544Seric if (!iswiz()) 4658544Seric break; 4667282Seric if (kill(MotherPid, SIGTERM) >= 0) 4677282Seric message("200", "Mother is dead"); 4687282Seric else 4697282Seric message("500", "Can't kill Mom"); 4707282Seric break; 4718544Seric 4728544Seric case CMDDBGWIZ: /* become a wizard */ 4738544Seric if (WizWord != NULL) 4748544Seric { 4758544Seric char seed[3]; 4768544Seric extern char *crypt(); 4778544Seric 47823106Seric (void) strncpy(seed, WizWord, 2); 47915596Seric if (strcmp(WizWord, crypt(p, seed)) == 0) 4808544Seric { 48115596Seric IsWiz = TRUE; 48215596Seric message("200", "Please pass, oh mighty wizard"); 4838544Seric break; 4848544Seric } 4858544Seric } 48615596Seric message("500", "You are no wizard!"); 4878544Seric break; 4885003Seric 48924945Seric # else WIZ 49024945Seric case CMDDBGWIZ: /* try to become a wizard */ 49124945Seric message("500", "You wascal wabbit! Wandering wizards won't win!"); 49224945Seric break; 49324945Seric # endif WIZ 49436230Skarels # else /* not SMTPDEBUG */ 49524945Seric 49636230Skarels case CMDDBGQSHOW: /* show queues */ 49736230Skarels case CMDDBGDEBUG: /* set debug mode */ 49836230Skarels case CMDDBGKILL: /* kill the parent */ 49936230Skarels case CMDDBGWIZ: /* become a wizard */ 500*36233Skarels # ifdef LOG 501*36233Skarels if (RealHostName != NULL && LogLevel > 0) 50236230Skarels syslog(LOG_NOTICE, 50336230Skarels "\"%s\" command from %s (%s)\n", 50436230Skarels c->cmdname, RealHostName, 50536230Skarels inet_ntoa(RealHostAddr.sin_addr)); 506*36233Skarels # endif 50736230Skarels /* FALL THROUGH */ 50836230Skarels # endif /* SMTPDEBUG */ 50936230Skarels 5104549Seric case CMDERROR: /* unknown command */ 5114549Seric message("500", "Command unrecognized"); 5124549Seric break; 5134549Seric 5144549Seric default: 51536230Skarels errno = 0; 5164549Seric syserr("smtp: unknown code %d", c->cmdcode); 5174549Seric break; 5184549Seric } 5194549Seric } 5204549Seric } 5214549Seric /* 5224549Seric ** SKIPWORD -- skip a fixed word. 5234549Seric ** 5244549Seric ** Parameters: 5254549Seric ** p -- place to start looking. 5264549Seric ** w -- word to skip. 5274549Seric ** 5284549Seric ** Returns: 5294549Seric ** p following w. 5304549Seric ** NULL on error. 5314549Seric ** 5324549Seric ** Side Effects: 5334549Seric ** clobbers the p data area. 5344549Seric */ 5354549Seric 5364549Seric static char * 5374549Seric skipword(p, w) 5384549Seric register char *p; 5394549Seric char *w; 5404549Seric { 5414549Seric register char *q; 5424549Seric 5434549Seric /* find beginning of word */ 5444549Seric while (isspace(*p)) 5454549Seric p++; 5464549Seric q = p; 5474549Seric 5484549Seric /* find end of word */ 5494549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5504549Seric p++; 5514549Seric while (isspace(*p)) 5524549Seric *p++ = '\0'; 5534549Seric if (*p != ':') 5544549Seric { 5554549Seric syntax: 5564549Seric message("501", "Syntax error"); 5574549Seric Errors++; 5584549Seric return (NULL); 5594549Seric } 5604549Seric *p++ = '\0'; 5614549Seric while (isspace(*p)) 5624549Seric p++; 5634549Seric 5644549Seric /* see if the input word matches desired word */ 56533725Sbostic if (strcasecmp(q, w)) 5664549Seric goto syntax; 5674549Seric 5684549Seric return (p); 5694549Seric } 5704577Seric /* 5714577Seric ** HELP -- implement the HELP command. 5724577Seric ** 5734577Seric ** Parameters: 5744577Seric ** topic -- the topic we want help for. 5754577Seric ** 5764577Seric ** Returns: 5774577Seric ** none. 5784577Seric ** 5794577Seric ** Side Effects: 5804577Seric ** outputs the help file to message output. 5814577Seric */ 5824577Seric 5834577Seric help(topic) 5844577Seric char *topic; 5854577Seric { 5864577Seric register FILE *hf; 5874577Seric int len; 5884577Seric char buf[MAXLINE]; 5894577Seric bool noinfo; 5904577Seric 5918269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5924577Seric { 5934577Seric /* no help */ 59411931Seric errno = 0; 5954577Seric message("502", "HELP not implemented"); 5964577Seric return; 5974577Seric } 5984577Seric 5994577Seric len = strlen(topic); 6004577Seric makelower(topic); 6014577Seric noinfo = TRUE; 6024577Seric 6034577Seric while (fgets(buf, sizeof buf, hf) != NULL) 6044577Seric { 6054577Seric if (strncmp(buf, topic, len) == 0) 6064577Seric { 6074577Seric register char *p; 6084577Seric 6094577Seric p = index(buf, '\t'); 6104577Seric if (p == NULL) 6114577Seric p = buf; 6124577Seric else 6134577Seric p++; 6144577Seric fixcrlf(p, TRUE); 6154577Seric message("214-", p); 6164577Seric noinfo = FALSE; 6174577Seric } 6184577Seric } 6194577Seric 6204577Seric if (noinfo) 6214577Seric message("504", "HELP topic unknown"); 6224577Seric else 6234577Seric message("214", "End of HELP info"); 6244628Seric (void) fclose(hf); 6254577Seric } 6268544Seric /* 6278544Seric ** ISWIZ -- tell us if we are a wizard 6288544Seric ** 6298544Seric ** If not, print a nasty message. 6308544Seric ** 6318544Seric ** Parameters: 6328544Seric ** none. 6338544Seric ** 6348544Seric ** Returns: 6358544Seric ** TRUE if we are a wizard. 6368544Seric ** FALSE if we are not a wizard. 6378544Seric ** 6388544Seric ** Side Effects: 6398544Seric ** Prints a 500 exit stat if we are not a wizard. 6408544Seric */ 6415181Seric 64224945Seric #ifdef WIZ 64319038Seric 6448544Seric bool 6458544Seric iswiz() 6468544Seric { 6478544Seric if (!IsWiz) 6488544Seric message("500", "Mere mortals musn't mutter that mantra"); 6498544Seric return (IsWiz); 6508544Seric } 65119038Seric 65224945Seric #endif WIZ 6539339Seric /* 6549339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6559339Seric ** 6569339Seric ** Parameters: 6579339Seric ** label -- a string used in error messages 6589339Seric ** 6599339Seric ** Returns: 6609339Seric ** zero in the child 6619339Seric ** one in the parent 6629339Seric ** 6639339Seric ** Side Effects: 6649339Seric ** none. 6659339Seric */ 6668544Seric 6679339Seric runinchild(label) 6689339Seric char *label; 6699339Seric { 6709339Seric int childpid; 6719339Seric 67216158Seric if (!OneXact) 6739339Seric { 67416158Seric childpid = dofork(); 67516158Seric if (childpid < 0) 67616158Seric { 67716158Seric syserr("%s: cannot fork", label); 67816158Seric return (1); 67916158Seric } 68016158Seric if (childpid > 0) 68116158Seric { 68216158Seric auto int st; 6839339Seric 68416158Seric /* parent -- wait for child to complete */ 68516158Seric st = waitfor(childpid); 68616158Seric if (st == -1) 68716158Seric syserr("%s: lost child", label); 6889339Seric 68916158Seric /* if we exited on a QUIT command, complete the process */ 69016158Seric if (st == (EX_QUIT << 8)) 69116158Seric finis(); 6929339Seric 69316158Seric return (1); 69416158Seric } 69516158Seric else 69616158Seric { 69716158Seric /* child */ 69816158Seric InChild = TRUE; 69925050Seric QuickAbort = FALSE; 70025614Seric clearenvelope(CurEnv, FALSE); 70116158Seric } 7029339Seric } 70315256Seric 70416158Seric /* open alias database */ 70516158Seric initaliases(AliasFile, FALSE); 70616158Seric 70716158Seric return (0); 7089339Seric } 7099339Seric 7105181Seric # endif SMTP 711