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*36230Skarels static char sccsid[] = "@(#)srvrsmtp.c 5.24 (Berkeley) 11/17/88 (with SMTP)"; 2433731Sbostic #else 25*36230Skarels static char sccsid[] = "@(#)srvrsmtp.c 5.24 (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 */ 65*36230Skarels # define CMDONEX 10 /* onex -- sending one transaction only */ 66*36230Skarels # define CMDVERB 11 /* verb -- go into verbose mode */ 67*36230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 68*36230Skarels # define CMDDBGQSHOW 12 /* showq -- show send queue */ 69*36230Skarels # define CMDDBGDEBUG 13 /* debug -- set debug mode */ 70*36230Skarels # define CMDDBGKILL 14 /* kill -- kill sendmail */ 71*36230Skarels # 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, 87*36230Skarels /* 88*36230Skarels * remaining commands are here only 89*36230Skarels * to trap and log attempts to use them 90*36230Skarels */ 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 */ 100*36230Skarels 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 */ 170*36230Skarels 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 { 209*36230Skarels /* 210*36230Skarels * didn't know about alias, 211*36230Skarels * or connected to an echo server 212*36230Skarels */ 213*36230Skarels 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", 226*36230Skarels 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 { 244*36230Skarels 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 450*36230Skarels # 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 494*36230Skarels # else /* not SMTPDEBUG */ 49524945Seric 496*36230Skarels case CMDDBGQSHOW: /* show queues */ 497*36230Skarels case CMDDBGDEBUG: /* set debug mode */ 498*36230Skarels case CMDDBGKILL: /* kill the parent */ 499*36230Skarels case CMDDBGWIZ: /* become a wizard */ 500*36230Skarels if (RealHostName) 501*36230Skarels syslog(LOG_NOTICE, 502*36230Skarels "\"%s\" command from %s (%s)\n", 503*36230Skarels c->cmdname, RealHostName, 504*36230Skarels inet_ntoa(RealHostAddr.sin_addr)); 505*36230Skarels /* FALL THROUGH */ 506*36230Skarels # endif /* SMTPDEBUG */ 507*36230Skarels 5084549Seric case CMDERROR: /* unknown command */ 5094549Seric message("500", "Command unrecognized"); 5104549Seric break; 5114549Seric 5124549Seric default: 513*36230Skarels errno = 0; 5144549Seric syserr("smtp: unknown code %d", c->cmdcode); 5154549Seric break; 5164549Seric } 5174549Seric } 5184549Seric } 5194549Seric /* 5204549Seric ** SKIPWORD -- skip a fixed word. 5214549Seric ** 5224549Seric ** Parameters: 5234549Seric ** p -- place to start looking. 5244549Seric ** w -- word to skip. 5254549Seric ** 5264549Seric ** Returns: 5274549Seric ** p following w. 5284549Seric ** NULL on error. 5294549Seric ** 5304549Seric ** Side Effects: 5314549Seric ** clobbers the p data area. 5324549Seric */ 5334549Seric 5344549Seric static char * 5354549Seric skipword(p, w) 5364549Seric register char *p; 5374549Seric char *w; 5384549Seric { 5394549Seric register char *q; 5404549Seric 5414549Seric /* find beginning of word */ 5424549Seric while (isspace(*p)) 5434549Seric p++; 5444549Seric q = p; 5454549Seric 5464549Seric /* find end of word */ 5474549Seric while (*p != '\0' && *p != ':' && !isspace(*p)) 5484549Seric p++; 5494549Seric while (isspace(*p)) 5504549Seric *p++ = '\0'; 5514549Seric if (*p != ':') 5524549Seric { 5534549Seric syntax: 5544549Seric message("501", "Syntax error"); 5554549Seric Errors++; 5564549Seric return (NULL); 5574549Seric } 5584549Seric *p++ = '\0'; 5594549Seric while (isspace(*p)) 5604549Seric p++; 5614549Seric 5624549Seric /* see if the input word matches desired word */ 56333725Sbostic if (strcasecmp(q, w)) 5644549Seric goto syntax; 5654549Seric 5664549Seric return (p); 5674549Seric } 5684577Seric /* 5694577Seric ** HELP -- implement the HELP command. 5704577Seric ** 5714577Seric ** Parameters: 5724577Seric ** topic -- the topic we want help for. 5734577Seric ** 5744577Seric ** Returns: 5754577Seric ** none. 5764577Seric ** 5774577Seric ** Side Effects: 5784577Seric ** outputs the help file to message output. 5794577Seric */ 5804577Seric 5814577Seric help(topic) 5824577Seric char *topic; 5834577Seric { 5844577Seric register FILE *hf; 5854577Seric int len; 5864577Seric char buf[MAXLINE]; 5874577Seric bool noinfo; 5884577Seric 5898269Seric if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) 5904577Seric { 5914577Seric /* no help */ 59211931Seric errno = 0; 5934577Seric message("502", "HELP not implemented"); 5944577Seric return; 5954577Seric } 5964577Seric 5974577Seric len = strlen(topic); 5984577Seric makelower(topic); 5994577Seric noinfo = TRUE; 6004577Seric 6014577Seric while (fgets(buf, sizeof buf, hf) != NULL) 6024577Seric { 6034577Seric if (strncmp(buf, topic, len) == 0) 6044577Seric { 6054577Seric register char *p; 6064577Seric 6074577Seric p = index(buf, '\t'); 6084577Seric if (p == NULL) 6094577Seric p = buf; 6104577Seric else 6114577Seric p++; 6124577Seric fixcrlf(p, TRUE); 6134577Seric message("214-", p); 6144577Seric noinfo = FALSE; 6154577Seric } 6164577Seric } 6174577Seric 6184577Seric if (noinfo) 6194577Seric message("504", "HELP topic unknown"); 6204577Seric else 6214577Seric message("214", "End of HELP info"); 6224628Seric (void) fclose(hf); 6234577Seric } 6248544Seric /* 6258544Seric ** ISWIZ -- tell us if we are a wizard 6268544Seric ** 6278544Seric ** If not, print a nasty message. 6288544Seric ** 6298544Seric ** Parameters: 6308544Seric ** none. 6318544Seric ** 6328544Seric ** Returns: 6338544Seric ** TRUE if we are a wizard. 6348544Seric ** FALSE if we are not a wizard. 6358544Seric ** 6368544Seric ** Side Effects: 6378544Seric ** Prints a 500 exit stat if we are not a wizard. 6388544Seric */ 6395181Seric 64024945Seric #ifdef WIZ 64119038Seric 6428544Seric bool 6438544Seric iswiz() 6448544Seric { 6458544Seric if (!IsWiz) 6468544Seric message("500", "Mere mortals musn't mutter that mantra"); 6478544Seric return (IsWiz); 6488544Seric } 64919038Seric 65024945Seric #endif WIZ 6519339Seric /* 6529339Seric ** RUNINCHILD -- return twice -- once in the child, then in the parent again 6539339Seric ** 6549339Seric ** Parameters: 6559339Seric ** label -- a string used in error messages 6569339Seric ** 6579339Seric ** Returns: 6589339Seric ** zero in the child 6599339Seric ** one in the parent 6609339Seric ** 6619339Seric ** Side Effects: 6629339Seric ** none. 6639339Seric */ 6648544Seric 6659339Seric runinchild(label) 6669339Seric char *label; 6679339Seric { 6689339Seric int childpid; 6699339Seric 67016158Seric if (!OneXact) 6719339Seric { 67216158Seric childpid = dofork(); 67316158Seric if (childpid < 0) 67416158Seric { 67516158Seric syserr("%s: cannot fork", label); 67616158Seric return (1); 67716158Seric } 67816158Seric if (childpid > 0) 67916158Seric { 68016158Seric auto int st; 6819339Seric 68216158Seric /* parent -- wait for child to complete */ 68316158Seric st = waitfor(childpid); 68416158Seric if (st == -1) 68516158Seric syserr("%s: lost child", label); 6869339Seric 68716158Seric /* if we exited on a QUIT command, complete the process */ 68816158Seric if (st == (EX_QUIT << 8)) 68916158Seric finis(); 6909339Seric 69116158Seric return (1); 69216158Seric } 69316158Seric else 69416158Seric { 69516158Seric /* child */ 69616158Seric InChild = TRUE; 69725050Seric QuickAbort = FALSE; 69825614Seric clearenvelope(CurEnv, FALSE); 69916158Seric } 7009339Seric } 70115256Seric 70216158Seric /* open alias database */ 70316158Seric initaliases(AliasFile, FALSE); 70416158Seric 70516158Seric return (0); 7069339Seric } 7079339Seric 7085181Seric # endif SMTP 709